Drawing

Hello,

once again I need your help. I have a checkerboard and I’d like to draw a semi-transparent green arrow from one square to another using a click on the source square and a drop on the destination square. Here is what I did so far :
My squares can be accessed with (i,j) their coordinates, and my pixels can be accessed with their (x,y) coordinates as well :

Code:
typedef struct {int x; int y;} Coord;
typedef struct {int i; int j;} Square;

I have a global variable

Code:
int square_size;

which stores the current size of every square.
I created 2 functions to switch between square coordinates and pixel coordinates (only multiplies or divides by the square size, basically) :

Code:
Square CoordToSquare (Coord MousePosition);
Coord SquareToCoord (Square square);

I have also included the following librairies to make it easier to implement :

Code:
#include <SDL_rotozoom.h>
#include <math.h>

In order not to try everything at once, to begin with I’m just trying to draw a simple segment from the center of the source square to the center of the destination square. Here is my function :

Code:
int draw_arrow(Square sq1, Square sq2)
{
int i1 = sq1.i, i2 = sq2.i, j1 = sq1.j, j2 = sq2.j;
if ( i1 < 0 || i1 > 7 || j1 < 0 || j1 > 7 || i2 < 0 || i2 > 7 || j2 < 0 || j2 > 7) //not chessboard squares.
return 1;
//start calculating the distance between the 2 squares and their angle with the x-axis.
Coord square_coord1 = SquareToCoord (sq1);
int x1 = square_coord1.x;
int y1 = square_coord1.y;
Coord square_coord2 = SquareToCoord (sq2);
int x2 = square_coord2.x;
int y2 = square_coord2.y;
double x = x2 - x1, y = y2 - y1;
double distance = sqrt ( x * x + y * y);
double theta = 180 / PI;
if ( x > 0 && y >= 0 )
theta *= atan (y / x);
else if (x > 0 && y < 0)
theta *= atan (y / x) + 2 * PI;
else if (x < 0)
theta *= atan (y / x) + PI;
else if (x == 0 && y > 0)
theta *= PI / 2;
else if (x == 0 && y < 0)
theta *= 3 * PI / 2;
else //undef angle : (x,y)=(0,0).
return 1;
//end calculating.

SDL_Surface * screen = SDL_GetVideoSurface();
SDL_Surface* layer = SDL_CreateRGBSurface (SDL_HWSURFACE, distance, square_size/4, 32, 0, 0, 0, 0);
SDL_FillRect (layer, NULL, SDL_MapRGB (layer->format, 0, 255, 0));

SDL_Rect position;
position.x = x1 + square_size / 2;
position.y = y1 + square_size / 2 - layer->h / 2;

layer = rotozoomSurface(layer,-theta,1,SMOOTH);
SDL_SetColorKey (layer, SDL_SRCCOLORKEY, SDL_MapRGB (layer->format, 0, 0, 0));
SDL_SetAlpha(layer, SDL_SRCALPHA, 64);
SDL_BlitSurface(layer,NULL,screen,&position);
SDL_FreeSurface(layer);
return 0;

}

In order to try it, I wrote

Code:
Square sq1 = {4,4};
Square sq2 = {5,6};
draw_arrow(sq1,sq2);

in my function “draw_everything”, and I was careful to insert this portion of code after the squares have been drawn.

Here are my questions (finally !) :

  • I tried to do it on my own, but maybe there’s a better/faster way to draw an arrow. Do you have any ideas ?
  • I have a memory leak with that function, though I don’t see why because I used SDL_FreeSurface. Do you see where it is ?
  • How can I locate memory leaks with codeblocks (and wingw) ?
  • I need to rotate with -theta to make it work, but I don’t understand why it’s not just +theta.
  • Is there any other way to draw a line than to create a rectangle of tickness 1 ?
  • The only way to draw a slanted line is to create a SDL_surface * and to rotate it as I did, right ? (it’s not possible to use a SDL_rect, or is it?).
  • I’d like to add a black frame to the “arrow” (which is currently only a rectangle), but how can I do it since the rotation adds many black pixels that I then need to remove with SDL_SetColorKey (and since it would be difficult to draw a frame after the rotation) ?
  • Finally, I will need to draw a black triangle and fill it with semi-transparent green. How can I do that ?

(I might edit these questions to find answers to my lattest problems so please keep checking for updates).

If you would be kind enough to answer at least some of them, I’d be really greatful.
Thanks.

Hi.

  • I tried to do it on my own, but maybe there’s a better/faster way to draw
    an arrow. Do you have any ideas ?

You could build an arrow surface during initialisation, and selectively
stretch part of it when drawing. Or you might only draw the arrow head once
and save that to a surface, because it is easy to draw the arrow body using
SDL_FillRect(). Finally, you could load a pre-made arrow image from the hard
drive. This would allow you the most flexibility in terms of the colours and
shape of the arrow (it would be easy to replace the straight line arrow with
something with softer edges if you wanted).

  • I have a memory leak with that function, though I don’t see why because I
    used SDL_FreeSurface. Do you see where it is ?

layer = rotozoomSurface(layer,-theta,1,SMOOTH);

This line loses the pointer to the original layer, and allocates memory
itself. You need to have two calls to SDL_FreeSurface().

  • How can I locate memory leaks with codeblocks (and wingw) ?

Your runtime might give you the option of hooking into allocations.

  • I need to rotate with -theta to make it work, but I don’t understand why
    it’s not just +theta.

Your angle computations look complex. I don’t have time to check them by
hand, but I would suggest you look at atan2() as a possible alternative.

  • Is there any other way to draw a line than to create a rectangle of
    tickness 1 ?

You can use pixel manipulation, like here:
http://www.libsdl.org/cgi/docwiki.cgi/Pixel_Access
Filling a rect is likely to be faster, but if you are only building the
arrow at initialisation time then the cost isn’t going to matter much.

  • The only way to draw a slanted line is to create a SDL_surface * and to
    rotate it as I did, right ? (it’s not possible to use a SDL_rect, or is
    it?).

If you use direct pixel access, you could use Bresham’s algorithm
http://www.google.com/search?q=breshams+line+drawing+algorithm

  • I’d like to add a black frame to the “arrow” (which is currently only a
    rectangle), but how can I do it since the rotation adds many black pixels
    that I then need to remove with SDL_SetColorKey (and since it would be
    difficult to draw a frame after the rotation) ?

Again, not rotating would be the most flexible approach here I think.

  • Finally, I will need to draw a black triangle and fill it with
    semi-transparent green. How can I do that ?

Using the above algorithms, perhaps combined with a flood-fill.

(I might edit these questions to find answers to my lattest problems so
please keep checking for updates).

I’m on the mailing list (as are the majority of users I would guess), I
don’t believe we can see edits.On 19 March 2010 01:03, Lilly wrote:

If you would be kind enough to answer at least some of them, I’d be really
greatful.
Thanks.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org