I don't do much gdi programming, but I'm trying.... :)

Anyways, I'm trying to code an app that will let you draw a bezier curve. I'm guessing that it's something along the lines of the following:

1) In WM_LBUTTONDOWN
-- set draw flag
-- get current x and y
-- draw the line

2) in WM_MOUSEMOVE
-- if draw flag is set continue on
-- get current x and y
-- continue drawing line

3) in WM_LBUTTONUP
-- if draw flag is set, unset it and continue on
-- get current x and y
-- draw current line and then stop

I'm not exactly sure which gdi api's I'll need. Also, I'm not sure how to have a dynamic buffer of all of the x/y info. I did a little test where I set a buffer in the .data as 'dd 64 dup(0)' which gave me 32 POINT structs worth of space. It was just a really really basic test. I set the flag in the WM_LBUTTONDOWN section and moved the current x and y (GetCursorPos api) into the 64 dword buffer. Then in the WM_LBUTTONUP section, I moved the current x and y into the buffer. So I was just saving the starting x/y and the ending x/y. Then I called the PolyLine gdi api, setting 2 for the # points in array param. Even though I set that to 2, the buffer was still big enough for 32 POINT structs, initialized to 0's. It ignored the 2, and drew the whole buffer. When I lowered the buffer from 64 dwords to 4 dwords, which was all my simple little test was using, it drew the line only from the start x/y to the end x/y.

So, what is the best method of setting up a dynamic buffer that would grow as x/y info was added. Also, what gdi functions will I need to use to draw the line, starting from a left button press and ending with a left button release.

thanks,
will
Posted on 2003-10-07 18:29:49 by Will
Well, you would use MoveToEx to place the anchor point where the curve will start then create an array of 3 (or more) reference points, 2 are control points and the last reference point is the endpoint of the curve. Once you have set the point into the array you can call PolyBezierTo to draw the curve.
Posted on 2003-10-07 22:25:40 by donkey
What is the best method to dynamically allocate a buffer of undetermined size to accomodate for an unknown number of points? In my earlier tests (which I'm not sure how clear I explained it), if I allocated a buffer of 64 dwords (32 POINT structs), but only filled 4 dwords (2 POINT structs), it still drew the rest of the POINTs which were intialized to 0. This happened even if I set the cPoints param to the correct number of points in the PolyLineTo api call. The PolyBezierTo api has a similar param (cCount). So if I pre-allocate a huge buffer for the POINT array, and correctly set this count to the actual number of POINTs that I've set, it still draws all of them. So that idea is out, and I'd have to somehow allow the buffer to dynamically grow as I add the POINTs, so it would be the exact size.

....on to the actual drawing routine:
How would I set this up? Presumably I'd put the MoveToEx and PolyBezierTo calls in the WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP sections of my wndproc. Could you show me a general outline of the steps in psuedo-code?


thanks for your help donkey!

cheers,
will
Posted on 2003-10-08 11:34:50 by Will
Well, as it is only point structures (8bytes) I wouldn't bother with a dynamic buffer, the overhead in creating the buffer would probably slow down your drawing. You might allocate enough memory to hold the maximum number of points expected and always use that. You can always free the block and allocate a larger one if necessary.
ie

MAXPOINTS equ 64

invoke GetCurrentProcess
mov hProcess,eax
invoke VirtualAllocEx, hProcess, 0, MAXPOINTS*8, MEM_COMMIT,PAGE_READWRITE
mov pPOINTS, EAX

For the outline of steps I would have to think about it but generally I would say on LBUTTONDOWN you execute MoveToEx, then prompt for an endpoint. At that point display two control points on a straight line between the start and end points and allow the user to move them or add more.
Posted on 2003-10-08 12:25:23 by donkey
Posted on 2003-10-08 12:44:16 by NOP-erator
Thanks for the info and link guys!

I'm thinking that maybe I used the wrong term out of ignorance though. I'm not looking to draw a bezier cuve per se. I want to be able to draw a curved line on a window. I thought that it could be done by starting to draw the line when the left mouse button was pressed, continuing to draw it as the mouse moves, and stopping the line when the left mouse button was released. Or maybe it could be done like drawing a straight line, then 'clicking' on the line (in the middle of a vertical line for example), and then 'dragging' it out changing it from a straight line into a curved line. I don't really know how to word that as I'm not very experienced in gdi programming.

The only other program that I can think of that does what I'm trying to do is Visio. In Visio, you can draw a couple of shapes onto the worksheet, and draw a line (straight or curved) between them.

Maybe there's another method of doing it? The more that I read about the bezier api's it doesn't seem like that's exactly what I'm looking for. Maybe if i explain what I'd like to do, maybe someone can give me some advice on how to accomplish this. :)

I have several buttons on a window. What I'm trying to do is draw lines between them. There are also static text controls around each button. So rather then draw straight lines between the buttons, I'd like to draw curved lines so as not to draw the line over the text.

thanks,
will
Posted on 2003-10-08 17:46:51 by Will
Hi Will,

You might want to take a look at the ArcTo function, it will allow your to define a "box" and the arc will be drawn to the limits of the box. I have not used these functions however so I can't be of much help. Not much use for beziers and arcs in toolbar paint when your canvas is normally 16x16 :)
Posted on 2003-10-08 17:59:37 by donkey
Perfect donkey!

thanks again,
will
Posted on 2003-10-09 09:31:59 by Will
donkey,

I've got the arc api working alright, but I found that mspaint has a 'curve' drawing tool which does it a little better. You click and drag w/ the left mouse buttom to draw the line, and then click one or two (max of two it seems) more points to curve the line to that point(s). That seems ideal, but how would they do that? My guess is that when you draw the line between 2 points, you would just save those two POINTs. Then when you press the left mouse button again, you get the cursor position, and use that POINT along with the previous two POINTs to draw a curve. Do you know exactly how that would work though?

thanks a lot,
will
Posted on 2003-10-10 11:59:23 by Will

donkey,

I've got the arc api working alright, but I found that mspaint has a 'curve' drawing tool which does it a little better. You click and drag w/ the left mouse buttom to draw the line, and then click one or two (max of two it seems) more points to curve the line to that point(s). That seems ideal, but how would they do that? My guess is that when you draw the line between 2 points, you would just save those two POINTs. Then when you press the left mouse button again, you get the cursor position, and use that POINT along with the previous two POINTs to draw a curve. Do you know exactly how that would work though?

thanks a lot,
will

Hi Will, that is the bezier curve functions, see my post about how I would go about using a bezier curve, it explains the process of how MSPaint does it. There are a maximum of 2 points because they only support a simple curve (no poly curve) and all gdi bezier curves use only two control points, they are an anchor, 2 control points and an endpoint, the structure you pass to the function consists of the 2 controls and the endpoint.
Posted on 2003-10-10 12:45:43 by donkey
Ahhhh..... Now I feel dumb! ;)

Thanks a lot donkey,
will
Posted on 2003-10-10 12:55:48 by Will