View mode: basic / threaded / horizontal-split · Log in · Help
April 09, 2011
Re: simple display (from: GUI library for D)
On 2011-04-08 22:31:11 -0400, Matthias Pleh <jens@konrad.net> said:

> For the drawingt part. I'm currently working on a rednerer with 
> scanline algorithm. This will be completly OS-independent. It's in a 
> single file with 2kLOC, and rather low level drawing. I just render on 
> a simple ubyte-array, but it already support polygon-rendering, 
> antialiasing and different color-structs.

Oh! really nice.


> This is how it looks like for now:
> http://img683.imageshack.us/i/testawa.jpg/
> this takes currently 62ms to render, don't know if this is fast enough,
> but can definitley improved.

The important thing is to have an API. Once it works we can concern 
ourselves with speed. What's the API like?


-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
April 09, 2011
Re: simple display (from: GUI library for D)
Am 09.04.2011 13:11, schrieb Michel Fortin:
> On 2011-04-08 22:31:11 -0400, Matthias Pleh <jens@konrad.net> said:
>
>> For the drawingt part. I'm currently working on a rednerer with
>> scanline algorithm. This will be completly OS-independent. It's in a
>> single file with 2kLOC, and rather low level drawing. I just render on
>> a simple ubyte-array, but it already support polygon-rendering,
>> antialiasing and different color-structs.
>
> Oh! really nice.
>
>
>> This is how it looks like for now:
>> http://img683.imageshack.us/i/testawa.jpg/
>> this takes currently 62ms to render, don't know if this is fast enough,
>> but can definitley improved.
>
> The important thing is to have an API. Once it works we can concern
> ourselves with speed. What's the API like?
>
>


Currntly, it's rather low level API.
It looks like this:

void draw()
{
    buf = new ubyte[width * height * 3];
    // create render buffer, just a ubyte-arrray (no color info)
    PixelBuffer pixBuff = new PixelBuffer(buf, width, height, width*3);

    auto ren= new Renderer!(Rgb24)(pixBuff);  // -> Rgb24
 	                              // manages the correct Color
    Rasterizer ras = new Rasterizer;

    // create the path
    // per primitive min. 3 vertexes needed
    ras.movTo(20,40);  // -> moves the point without drawing
    ras.lineTo(30,80); // -> moves the point with drawing
    [...snip...]

    // finally render it to the PixelBuffer
    ras.render(ren, Color(255,0,0));
}

on this we could add more abstraction to directly render lines, 
rectangles and circles ... (the posted image is completly renderd
whit the API above)

I hope, I will find time this weekend, clean it up and post it here.
Maybe Adam then could add it to his source.


┬░Matthias
April 09, 2011
Re: simple display (from: GUI library for D)
On 04/09/2011 02:42 AM, Adam D. Ruppe wrote:
>> OK. (But for this module I think usage simplicity is more
>> >  important than raw speed.
> The struct is at least equal in simplicity:
>
> image[x, y] = Color(r, g, b);
>
> vs
>
> image[x, y] = tuple(r, g, b);

Indeed; and then:
    image[x, y].g
versus
    image[x, y][1]

Denis
-- 
_________________
vita es estrany
spir.wikidot.com
April 09, 2011
Re: simple display (from: GUI library for D)
On 04/09/2011 06:50 AM, Cliff Hudson wrote:
> So is the objective to create a windowing library, or a drawing library for
> (for example) games?  The two are rather different - though you can build a
> windowing library on top of a drawing library, doing so is pointless given
> the plethora of GUI libraries already out there, several with D bindings.
>   If the bindings are hard to use, I'd address that directly rather than
> creating a whole new one.
>
> If you are building a drawing library, I'd definitely co-opt an existing one
> (SDL would be a good place, in particular since its license seems favorable
> and the API is well known.)  In fact, a good game-oriented library for D I
> think would be a fabulous idea.  D has a lot to offer game developers, a
> great mix of the high level and the low.  I don't know if it is popular with
> this crowd, but Microsoft DirectX or the XNA Framework might be a good place
> to go for pattern ideas as well.
>
> But generally I'd strive to not create new APIs, just new implementations
> (as necessary.)

I guess you are simply missing the point. You should re-read start-of-thread 
messages.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com
April 09, 2011
Re: simple display (from: GUI library for D)
Matthias Pleh:
> I hope, I will find time this weekend, clean it up and post it here.
> Maybe Adam then could add it to his source.

Cool!
April 09, 2011
Re: simple display (from: GUI library for D)
Yeah, I'm certainly not suggesting you necessarily rip off implementation,
just possibly API design.  But to be fair it has been a while since I used
that API - maybe the design is crap by comparison to others these days.
OpenGL or DirectX for quick rendering is definitely the way to go under the
covers.

On Sat, Apr 9, 2011 at 8:05 AM, Adam D. Ruppe <destructionator@gmail.com>wrote:

> On Fri, Apr 08, 2011 at 09:50:11PM -0700, Cliff Hudson wrote:
> > So is the objective to create a windowing library, or a drawing library
> for
> > (for example) games?
>
> Drawing. I have a windowing library in the works too, but it's much much
> more effort (even building off existing ones!) so it won't be ready to
> share
> for a long time still.
>
> > If you are building a drawing library, I'd definitely co-opt an existing
> one
> > (SDL would be a good place, in particular since its license seems
> favorable
> > and the API is well known.)
>
> I actually find SDL's drawing facilities to be almost useless... in my D1
> game lib, even doing NES type games, I found it was simply too slow and
> redid the graphics with OpenGL.
>
> It's image loaders and sound/music parts are good though.
>
> > I don't know if it is popular with
> > this crowd, but Microsoft DirectX or the XNA Framework might be a good
> place
> > to go for pattern ideas as well.
>
> I've heard good things about XNA, but I've never used it...
>
>
April 09, 2011
Re: simple display (from: GUI library for D)
bearophile wrote:
> http://rosettacode.org/wiki/Animate_a_pendulum

Here's the D version using the direct to screen functions. I
ported the C# version, since the APIs were most alike. (Not
really surprising... C# and I both thinly wrapped GDI.)

===

import std.math;
import simpledisplay;

void main() {
   auto win = new SimpleWindow(512, 512);

   real angle = PI / 2;
   real angleVelocity = 0;
   immutable real dt = 0.1;
   int length = 150;

   win.eventLoop(50,
       () {
           auto anchorX = win.width / 2 - 12;
           auto anchorY = win.height / 4;
           auto ballX = anchorX + cast(int) (sin(angle) * length);
           auto ballY = anchorY + cast(int) (cos(angle) * length);

           auto angleAcceleration = -9.81 / length * sin(angle);
           angleVelocity += angleAcceleration * dt;
           angle += angleVelocity * dt;

           auto painter = win.draw();

           painter.fillColor = Color(255, 255, 255);
           painter.drawRectangle(0, 0, win.width, win.height);

           painter.outlineColor = Color(0, 0, 0);
           painter.drawLine(anchorX, anchorY, ballX, ballY);
           painter.fillColor = Color(0, 0, 0);
           painter.drawEllipse(anchorX - 3, anchorY - 4, anchorX + 3, anchorY + 4);

           painter.fillColor = fromHsl(30, 0.8, 0.4);
           painter.drawEllipse(ballX - 7, ballY - 7, ballX + 7, ballY + 7);
       }
   );
}

===

Exit the program by closing the window.

Some comments. First, you'll see that the pulse timer is
implemented, allowing the animation to easily happen.

Then, there's a dozen lines to actually do the drawing, starting
with

auto painter = win.draw();

win.draw (name might change) returns a ScreenPainter struct, which
gives access to the drawing directly in the window, via a handful
of native api calls. This struct is necessary to handle some state
and cleanup that the native APIs require. (It's destructor does
it all for you though, so no need to think about it here.)

You can draw images, text, pixels (slowly), lines, rectangles,
arcs, and polygons with solid colors for filling and outline. It's
the lowest common denominator between Windows GDI and Xlib.

I agree with what Michel said earlier about it being a lot of
fairly pointless effort to go further than this. Instead, we'll
offer a rich set of cross-platform functions to draw to an image,
and simply copy those images to the windows when we want to get
fancy. (That's easy to do here: painter.drawImage(x, y, image); )

Moving on, I first clear the screen by drawing a large, white
rectangle over the window.

fillColor and outlineColor are settable properties that are
implicitly used in the drawing functions. (This reflects how
pens and brushes are tied to the HDC on Windows and foreground
and background colors are tied to the GC on X - you don't pass
colors to the individual functions on either native API either.)

Following Windows' lead, all the functions use the two separate
colors, one for the outline of the shape and one for filling it in,
hence their names. Note that only outline is used for drawline lines
and pixels.

If you want to draw a shape without filling it in, first set the
fill color to transparent:

painter.fillColor = Color.transparent;

(Color.transparent is a static method to conveniently return a
color with alpha = 0.)


Also in there, you can see me using the fromHsl helper function
to return a Color specifying HSL values instead of RGB.


Finally, I said this draws directly to the screen, but it actually
doesn't... it double buffers underneath. No need to call a
buffer.flip function though. ScreenPainter's destructor does it for
you. You don't have to think about it.

The buffer is preserved across calls and used to automatically
handle WM_PAINT/Expose messages.



======

There's still a handful of little things and a lot of error checking
needed, but I'm pretty happy with this as the screen drawing base.
It covers all the easy stuff. The hard stuff will be in platform
independent images.

Anyway, here's the updated simpledisplay.d:

http://arsdnet.net/dcode/simpledisplay.d
April 09, 2011
Re: simple display (from: GUI library for D)
Adam D. Ruppe:

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

On Windows Vista the window often doesn't close when I hit the close window click at the top right.

Probably quite more people will have to comment and think about this module and its API before adopting it.

The length=150 too is better to be set as immutable. Most of the auto variables (but "painter") are better set to immutable.

The delegate inside eventLoop doesn't need the ().

Color(255, 255, 255) ==> Color.white
Color(0, 0, 0) ==> Color.black

painter.drawRectangle(0, 0, win.width, win.height) painter.clearAll(), or painter.clearAll(Color.white) or something similar.

auto win = new SimpleWindow(512, 512);
==>
auto win = new SimpleWindow(512, 512, "Pendulum");

win.eventLoop(10, {...})  does this semantics work with more than one window too?

       auto painter = win.draw();
       painter.fillColor = Color(255, 255, 255);
==> sometimes a bit better:
       auto painter = win.draw();
       with (painter) {
           fillColor = ...
           ...

drawRectangle => rectangle or even "box"
drawLine ==> line
drawEllipse ==> ellipse
circle
fillColor ==> filling?
outline => pen?


> This struct is necessary to handle some state
> and cleanup that the native APIs require.

This is not so nice...


> I agree with what Michel said earlier about it being a lot of
> fairly pointless effort to go further than this.

Reading keyboard chars, and mouse clicks & movements is very useful.
Another useful thing is to plot a matrix of rgb or int or ubyte in grey shades, to speed up some basic usage. In PyGame/Numpy there is surfarray for this.

Bye,
bearophile
April 10, 2011
Re: simple display (from: GUI library for D)
bearophile wrote:
> The length=150 too is better to be set as immutable.

Yeah, I made that change after copy/pasting the code into my
newsgroup post. win, painter, angle, and angular velocity were
the only things left mutable in the end.

> The delegate inside eventLoop doesn't need the ().

I put it there for consistency with other events. While there
are no other handlers in this example, there can be, and all the
other ones take arguments.

> Color(255, 255, 255) ==> Color.white
> painter.clearAll(Color.white)
> auto win = new SimpleWindow(512, 512, "Pendulum");

Yeah, those are reasonable.

> win.eventLoop(10, {...})  does this semantics work with more than
> one window too?

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.

> drawRectangle => rectangle or even "box"

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.

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.

> outline => pen?

Pens do more than just color. I guess the real question is how
complex should it be able to get?

In the underlying APIs, you can make a pen with a color, a
width, and a style (solid, dashed, etc). Since they both can
do it, I think I will add it.

(Some more advanced APIs can even do things like gradient pens. I
hope the image manipulation functions we write will eventually
be able to do this too, but since plain old X can't, it won't
happen for the display painter.)

Perhaps:

painter.pen = Pen(Color(r, g, b), 1, Pen.Style.solid);

(Or maybe new Pen()... have to think about that.)

And offer an overload for the simple case where you only care
about color. (or keep the current fillColor property.)

Then, of course, something similar for Brush, which is used
to fill the background.

But, here, the idea was to keep it simple, so I went with just
color. I guess that might be too simple.

> This is not so nice...

I'm sympathetic, but I don't agree losing the struct would be good.

Even if the struct proves to be unnecessary (which it might be - I
think you can hold on to a window HDC as long as you like, but it's
not something I see often so I think it's discouraged), I'd still
keep it.

Having an automatic constructor and destructor available gives
some flexibility on the implementation side without inconveniencing
the user beyond a single function.

For example, the implicit double buffering done here. You don't
have to think about flipping it. It just works. Better yet, the
implementation can disable it at will. BitBlt is slow over Remote
Desktop on Windows, making double buffering laggy. But, you, the
user, don't really need to know that, since it wasn't your problem
in the first place. The ScreenPainter can make it's own decision
about it.

> Reading keyboard chars, and mouse clicks & movements is very
> useful.

For that, you can pass other handlers to eventLoop. I still intend
to define a few more you can use.

> Another useful thing is to plot a matrix of rgb or int or ubyte
> in grey shades, to speed up some basic usage. In PyGame/Numpy
> there is surfarray for this.

Sounds like what you'd use the Image class for, so I think we're
good on that too.


====

A note: since I posted last, I changed my mind on something, and
bearophile, I rather doubt you'll like it...

Before, it was drawRectangle(int x1, int y2, int width, int height);

Now, it is drawRectangle(Point upperLeft, Size size);

So, at the usage, you now need to put in some more parenthesis
and say what you mean:

painter.drawRectangle(Point(0, 0), Size(win.width, win.height));


Why did I do this? Well, consider the following:

drawRectangle(int x1, int y1, int x2, int y2);

(This is, in fact, the signature in Windows GDI, whereas Xlib
user width/height.)


The types there are no different than the above, but meaning has
changed. I'd be ok with saying "RTFM" to avoid having to use
the structs.

But, RTFM doesn't let you overload it, whereas the types do. Now,
it can offer both

drawRectangle(Point upperLeft, Size size);

*and*

drawRectangle(Point upperLeft, Point lowerRight);

I'm sure you were thinking about named arguments for a moment
there about width/height vs x2/y2. I did too. But, named arguments
don't really exist in D (you can do them via library magic but not
without) so it's moot, and I don't believe named arguments would
offer the overloading possibilities, which I like. It can save
some math while being quite natural.

The Point struct also makes drawPolygon look a lot better, so
it's of general use.
April 10, 2011
Re: simple display (from: GUI library for D)
One thing to consider, since I was impacted by this when writing a WPF app a
while back, is the difference between a 2-Vector and a Point.  In
particular, Vectors typically have some very useful methods on them, like
addition, rotation, transformations, etc. which frequently are not
associated with the Point type.  I don't know if you have or plan to support
this data type, but at least having simple transforms to/from Vector would
be nice.

- Cliff

On Sat, Apr 9, 2011 at 5:58 PM, Adam D. Ruppe <destructionator@gmail.com>wrote:

> bearophile wrote:
> > The length=150 too is better to be set as immutable.
>
> Yeah, I made that change after copy/pasting the code into my
> newsgroup post. win, painter, angle, and angular velocity were
> the only things left mutable in the end.
>
> > The delegate inside eventLoop doesn't need the ().
>
> I put it there for consistency with other events. While there
> are no other handlers in this example, there can be, and all the
> other ones take arguments.
>
> > Color(255, 255, 255) ==> Color.white
> > painter.clearAll(Color.white)
> > auto win = new SimpleWindow(512, 512, "Pendulum");
>
> Yeah, those are reasonable.
>
> > win.eventLoop(10, {...})  does this semantics work with more than
> > one window too?
>
> 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.
>
> > drawRectangle => rectangle or even "box"
>
> 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.
>
> 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.
>
> > outline => pen?
>
> Pens do more than just color. I guess the real question is how
> complex should it be able to get?
>
> In the underlying APIs, you can make a pen with a color, a
> width, and a style (solid, dashed, etc). Since they both can
> do it, I think I will add it.
>
> (Some more advanced APIs can even do things like gradient pens. I
> hope the image manipulation functions we write will eventually
> be able to do this too, but since plain old X can't, it won't
> happen for the display painter.)
>
> Perhaps:
>
> painter.pen = Pen(Color(r, g, b), 1, Pen.Style.solid);
>
> (Or maybe new Pen()... have to think about that.)
>
> And offer an overload for the simple case where you only care
> about color. (or keep the current fillColor property.)
>
> Then, of course, something similar for Brush, which is used
> to fill the background.
>
> But, here, the idea was to keep it simple, so I went with just
> color. I guess that might be too simple.
>
> > This is not so nice...
>
> I'm sympathetic, but I don't agree losing the struct would be good.
>
> Even if the struct proves to be unnecessary (which it might be - I
> think you can hold on to a window HDC as long as you like, but it's
> not something I see often so I think it's discouraged), I'd still
> keep it.
>
> Having an automatic constructor and destructor available gives
> some flexibility on the implementation side without inconveniencing
> the user beyond a single function.
>
> For example, the implicit double buffering done here. You don't
> have to think about flipping it. It just works. Better yet, the
> implementation can disable it at will. BitBlt is slow over Remote
> Desktop on Windows, making double buffering laggy. But, you, the
> user, don't really need to know that, since it wasn't your problem
> in the first place. The ScreenPainter can make it's own decision
> about it.
>
> > Reading keyboard chars, and mouse clicks & movements is very
> > useful.
>
> For that, you can pass other handlers to eventLoop. I still intend
> to define a few more you can use.
>
> > Another useful thing is to plot a matrix of rgb or int or ubyte
> > in grey shades, to speed up some basic usage. In PyGame/Numpy
> > there is surfarray for this.
>
> Sounds like what you'd use the Image class for, so I think we're
> good on that too.
>
>
> ====
>
> A note: since I posted last, I changed my mind on something, and
> bearophile, I rather doubt you'll like it...
>
> Before, it was drawRectangle(int x1, int y2, int width, int height);
>
> Now, it is drawRectangle(Point upperLeft, Size size);
>
> So, at the usage, you now need to put in some more parenthesis
> and say what you mean:
>
> painter.drawRectangle(Point(0, 0), Size(win.width, win.height));
>
>
> Why did I do this? Well, consider the following:
>
> drawRectangle(int x1, int y1, int x2, int y2);
>
> (This is, in fact, the signature in Windows GDI, whereas Xlib
>  user width/height.)
>
>
> The types there are no different than the above, but meaning has
> changed. I'd be ok with saying "RTFM" to avoid having to use
> the structs.
>
> But, RTFM doesn't let you overload it, whereas the types do. Now,
> it can offer both
>
> drawRectangle(Point upperLeft, Size size);
>
> *and*
>
> drawRectangle(Point upperLeft, Point lowerRight);
>
> I'm sure you were thinking about named arguments for a moment
> there about width/height vs x2/y2. I did too. But, named arguments
> don't really exist in D (you can do them via library magic but not
> without) so it's moot, and I don't believe named arguments would
> offer the overloading possibilities, which I like. It can save
> some math while being quite natural.
>
> The Point struct also makes drawPolygon look a lot better, so
> it's of general use.
>
1 2 3 4 5 6 7
Top | Discussion index | About this forum | D home