www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: simple display (from: GUI library for D)

reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 Here's the D version using the direct to screen functions.

More little tasks for your module: http://rosettacode.org/wiki/Fractal_tree#Python http://rosettacode.org/wiki/Brownian_tree The JavaScript processing port site has some more examples in the Demos section: http://processingjs.org/exhibition Bye, bearophile
Apr 09 2011
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
bearophile wrote:
 More little tasks for your module:
 http://rosettacode.org/wiki/Fractal_tree#Python

This one's use of recursion caused me to hit what I think is a compiler bug. Not in the recursion itself, but in a struct's copy constructor when it had a significant mixin. I worked around it by declaring a private struct and using a pointer to it rather than mixing in the implementation directly. I believe this will be a net-positive too, since ScreenPainter is now referenced counted. Here's the implementation: ==== import simpledisplay; import std.math; void main() { // auto image = new Image(600, 600); auto window = new SimpleWindow(600, 600, "Fractal Tree"); void drawTree(ScreenPainter p, in int x1, in int y1, in real angle, in int depth) { if(depth == 0) return; immutable x2 = x1 + cast(int) (cos(angle) * depth * 10); immutable y2 = y1 + cast(int) (sin(angle) * depth * 10); p.drawLine(Point(x1, y1), Point(x2, y2)); drawTree(p, x2, y2, angle - 0.35, depth - 1); drawTree(p, x2, y2, angle + 0.35, depth - 1); } drawTree(window.draw, 300, 550, -PI / 2, 9); window.eventLoop(0, (dchar) { window.close(); }); // displayImage(image); } === The reason Image is there, but commented out, is that such things might be better done as images, then displayed once finished. But, since we don't have drawing lines to images yet*, I went direct to screen instead. (well, I do have my implementation of Bresenham's algorithm, but I want to see Mathias' code before falling back on mine. Mine worked well for DOS, but better anti-aliasing is expected nowadays.) DrawTree takes an existing ScreenPainter so I can limit it's scope to only where it's used. The new reference counting under the hood means that while the struct is copied several times here, it isn't wasteful. The eventLoop inline delegate allows you to close the window by pressing any key as well as using the button in the corner. I don't think the Python version on rosetta code would allow this. Comparing to the Python version, mine is a little shorter, primarily due to the much simpler initialization. The Python one took three lines to do what SimpleWindow's constructor does in one. I also put the "get_surface" kind of thing that allows drawing inline to the drawTree line. Like I said above, this was for reasons of scope, but it coincidentally shaves a line too. As does the struct destructor doing the job of display.flip(). The last place where I save a couple lines is the event loop, doing all that in one place instead of a separate function, loop, and fetcher. (Note: the delegate in there is not strictly necessary! It handles quit events sanely by default.) All in all, I'm very happy with this approach so far. It's simple, it's short, it's readable, it's reasonably efficient, and the implementation is moderately lean. Everything I was hoping for!
Apr 09 2011
next sibling parent Matthias Pleh <jens konrad.net> writes:
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit

Am 10.04.2011 04:30, schrieb Adam D. Ruppe:
 bearophile wrote:
 More little tasks for your module:
 http://rosettacode.org/wiki/Fractal_tree#Python

This one's use of recursion caused me to hit what I think is a compiler bug. Not in the recursion itself, but in a struct's copy constructor when it had a significant mixin. I worked around it by declaring a private struct and using a pointer to it rather than mixing in the implementation directly. I believe this will be a net-positive too, since ScreenPainter is now referenced counted. Here's the implementation: ==== import simpledisplay; import std.math; void main() { // auto image = new Image(600, 600); auto window = new SimpleWindow(600, 600, "Fractal Tree"); void drawTree(ScreenPainter p, in int x1, in int y1, in real angle, in int depth) { if(depth == 0) return; immutable x2 = x1 + cast(int) (cos(angle) * depth * 10); immutable y2 = y1 + cast(int) (sin(angle) * depth * 10); p.drawLine(Point(x1, y1), Point(x2, y2)); drawTree(p, x2, y2, angle - 0.35, depth - 1); drawTree(p, x2, y2, angle + 0.35, depth - 1); } drawTree(window.draw, 300, 550, -PI / 2, 9); window.eventLoop(0, (dchar) { window.close(); }); // displayImage(image); } === The reason Image is there, but commented out, is that such things might be better done as images, then displayed once finished. But, since we don't have drawing lines to images yet*, I went direct to screen instead. (well, I do have my implementation of Bresenham's algorithm, but I want to see Mathias' code before falling back on mine. Mine worked well for DOS, but better anti-aliasing is expected nowadays.) DrawTree takes an existing ScreenPainter so I can limit it's scope to only where it's used. The new reference counting under the hood means that while the struct is copied several times here, it isn't wasteful. The eventLoop inline delegate allows you to close the window by pressing any key as well as using the button in the corner. I don't think the Python version on rosetta code would allow this. Comparing to the Python version, mine is a little shorter, primarily due to the much simpler initialization. The Python one took three lines to do what SimpleWindow's constructor does in one. I also put the "get_surface" kind of thing that allows drawing inline to the drawTree line. Like I said above, this was for reasons of scope, but it coincidentally shaves a line too. As does the struct destructor doing the job of display.flip(). The last place where I save a couple lines is the event loop, doing all that in one place instead of a separate function, loop, and fetcher. (Note: the delegate in there is not strictly necessary! It handles quit events sanely by default.) All in all, I'm very happy with this approach so far. It's simple, it's short, it's readable, it's reasonably efficient, and the implementation is moderately lean. Everything I was hoping for!

Ok, this is what I have so far. It's code, I have written one year ago and is based on AntiGrain , which is based on freetype2, which is based on libart? AntiGrain is under the modified BSD-license. To prevent license-issues(if it should go into phobos) and to get a faster version, I'v started form scratch, but this is not finished yet. But you can get an idea, how it should work.
 (well, I do have my implementation of Bresenham's algorithm, but ..

simple lines, I think Bresenham's algorithm (also anti-aliased) will maybe faster (fewer overhead), but for thicker lines with different caps, you need polygons anyway, so ... In the test.d file is an example, which produce the image (.ppm) I have posted. (note, you need the Color struct form simpledisplay.d) have fun, °Matthias
Apr 09 2011
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 I believe so, yes, but I haven't tried it and wouldn't mind if
 it didn't. If you need to use multiple windows at the same time,
 it'd probably be better to use DFL, DWT, GTK, Qt, etc. etc.

It's better to support multiple windows, otherwise you have to split the single window "manually" if you want a window with a simulation and a window with a graph about the simulation.
 Heh, I used to call it box in my DOS programs. But, the functions
 it forwards to are called Rectangle() and XDrawRectangle(), so
 I want to be consistent with them so it's not a surprise to
 someone already familiar with with the other APIs.

I don't agree. line(), box(), circle(), etc are so easy to remember and common that I don't see the need to keep the names of the functions under them.
 The reason I went with drawShape instead of just Shape is that
 functions are verbs, so generally, I like their names to be
 verbs too. There's exceptions, of course, but I don't these
 fit.

I don't agree. It's _very_ easy to understand that p.line() is to add a line, there is no chance of confusion here, the verb of p.drawLine() is implied.
 But, here, the idea was to keep it simple, so I went with just
 color. I guess that might be too simple.

In this module shaded pens are less important than usage simplicity. I suggest to keep things simple here.
 A note: since I posted last, I changed my mind on something, and
 bearophile, I rather doubt you'll like it...

I think it's acceptable :-) ----------------------------
 This one's use of recursion caused me to hit what I think is a
 compiler bug. Not in the recursion itself, but in a struct's
 copy constructor when it had a significant mixin.

Where is the updated display module? This doesn't seem to be updated yet: http://arsdnet.net/dcode/simpledisplay.d In your little program drawTree() is better "static" (or better, moved out of the main). window.eventLoop(0, (dchar){ window.close(); }); ==> Default arguments? window.eventLoop();
 Comparing to the Python version, mine is a little shorter,

PyGame is also quite more powerful than your simpledisplay module, you can write small video games with it. So its API is a little more complex.
 All in all, I'm very happy with this approach so far. It's simple,
 it's short, it's readable, it's reasonably efficient, and the
 implementation is moderately lean. Everything I was hoping for!

Before freezing the API design I suggest to implement many more quite different examples. Designing APIs is something that can't be done in a hurry :-) Two features are quite important: Mouse position, mouse clicks, keys pressed: http://processingjs.org/learning/topic/pattern Text: http://processingjs.org/learning/topic/tickle --------------- Few more useful features for later: Transparency: http://processingjs.org/learning/topic/follow2 Antialiasing: http://processing.org/learning/topics/penrosetile.html Polygons, curves: http://processing.org/learning/topics/softbody.html Image loading: http://processingjs.org/learning/topic/blur Save screen: http://processing.org/learning/topics/saveoneimage.html Sprites: http://processing.org/learning/topics/unlimitedsprites.html Bye, bearophile
Apr 10 2011
prev sibling parent Cliff Hudson <cliff.s.hudson gmail.com> writes:
--00032555f6c6d5149504a093aa63
Content-Type: text/plain; charset=ISO-8859-1

 Heh, I used to call it box in my DOS programs. But, the functions
 it forwards to are called Rectangle() and XDrawRectangle(), so
 I want to be consistent with them so it's not a surprise to
 someone already familiar with with the other APIs.

I don't agree. line(), box(), circle(), etc are so easy to remember and common that I don't see the need to keep the names of the functions under them.
 The reason I went with drawShape instead of just Shape is that
 functions are verbs, so generally, I like their names to be
 verbs too. There's exceptions, of course, but I don't these
 fit.

I don't agree. It's _very_ easy to understand that p.line() is to add a line, there is no chance of confusion here, the verb of p.drawLine() is implied.

design (it just strikes me as weird all around actually.) If this were retained mode, something like p.Add(Line(...)) would make sense. But if the action is to draw a line, and the target of that action is object p, then p.drawLine is the most sensible. The objective here is not to relieve the user of typing, but to ensure the code is unambiguously clear. Imagine p.box. What does that mean? Draw a box? Or are we boxing p into some portable format? I agree with Adam's original thought that methods should be verbs. At least to my mind is reads easier. YMMV. - Cliff --00032555f6c6d5149504a093aa63 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"m= argin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class= =3D"im"> &gt; Heh, I used to call it box in my DOS programs. But, the functions<br> &gt; it forwards to are called Rectangle() and XDrawRectangle(), so<br> &gt; I want to be consistent with them so it&#39;s not a surprise to<br> &gt; someone already familiar with with the other APIs.<br> <br> </div>I don&#39;t agree. line(), box(), circle(), etc are so easy to rememb= er and common that I don&#39;t see the need to keep the names of the functi= ons under them.<br> <div class=3D"im"><br> <br> &gt; The reason I went with drawShape instead of just Shape is that<br> &gt; functions are verbs, so generally, I like their names to be<br> &gt; verbs too. There&#39;s exceptions, of course, but I don&#39;t these<br=

<br> </div>I don&#39;t agree. It&#39;s _very_ easy to understand that p.line() i= s to add a line, there is no chance of confusion here, the verb of p.drawLi= ne() is implied.<br> <div class=3D"im"><br></div></blockquote><div>=A0</div><div>I would argue t= hat p.line is inconsistent with an immediate-mode drawing API design (it ju= st strikes me as weird all around actually.) =A0If this were retained mode,= something like p.Add(Line(...)) would make sense. =A0But if the action is = to draw a line, and the target of that action is object p, then p.drawLine = is the most sensible. =A0The objective here is not to relieve the user of t= yping, but to ensure the code is unambiguously clear. =A0Imagine p.box. Wha= t does that mean? =A0Draw a box? =A0Or are we boxing p into some portable f= ormat? =A0I agree with Adam&#39;s original thought that methods should be v= erbs. =A0At least to my mind is reads easier. =A0YMMV.</div> <div><br></div><div>- Cliff</div></div> --00032555f6c6d5149504a093aa63--
Apr 10 2011