Tille - I can see you, read those man pages!   Tille's Site

The Maths library

In the following example, we will include the math.h file for drawing circles. The functions sin and cos are included in this file.

We also include the DrawPixel fuction in this program. Note that we added two conditions in that function, so as the program wouldn't crash when we start doing strange things with x and y coordinates.

/* Program Name: circle.c */
/* SDL screen test */
                                                                                
# include <SDL.h>
# include <stdlib.h>
# include <unistd.h>
# include <math.h>
                                                                                
/* Begin DrawPixel. */
void DrawPixel(SDL_Surface *screen, int x, int y,
Uint8 R, Uint8 G,
Uint8 B)
{
/* Don't fail on attempts to draw outside the screen. */
if ((x>=640) || (x<0)) return;
if ((y>=480) || (y<0)) return;

    Uint32 color = SDL_MapRGB(screen->format, R, G, B);

    if ( SDL_MUSTLOCK(screen) ) {
        if ( SDL_LockSurface(screen) < 0 ) {
            return;
        }
    }
    switch (screen->format->BytesPerPixel) {
        case 1: { /* Assuming 8-bpp */
            Uint8 *bufp;

            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
            *bufp = color;
        }
        break;

        case 2: { /* Probably 15-bpp or 16-bpp */
            Uint16 *bufp;

            bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
            *bufp = color;
        }
        break;

        case 3: { /* Slow 24-bpp mode, usually not used */
            Uint8 *bufp;

            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
            if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {
                bufp[0] = color;
                bufp[1] = color >> 8;
                bufp[2] = color >> 16;
            } else {
                bufp[2] = color;
                bufp[1] = color >> 8;
                bufp[0] = color >> 16;
            }
        }
        break;
                                                                                
        case 4: { /* Probably 32-bpp */
            Uint32 *bufp;
                                                                                
            bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
            *bufp = color;
        }
        break;
    }
    if ( SDL_MUSTLOCK(screen) ) {
        SDL_UnlockSurface(screen);
    }
    SDL_UpdateRect(screen, x, y, 1, 1);
}
/* End DrawPixel. */
                                                                                
int main()
{
  SDL_Surface *screen;
  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
  }
  atexit(SDL_Quit);
                                                                                
  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
    if ( screen == NULL ) {
        fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
        exit(1);
    }
                                                                                
  printf("Set window of 640x480 at %d bits per pixel mode\n",
        screen->format->BitsPerPixel);

  
/* draw a circle.  The constant M_PI is defined from math.h. */
  float i;
                                                                                
  for (i=0; i<2*M_PI; i+=0.01) {
    int x = 120 + 100*cos(i);
    int y = 120 + 100*sin(i);
    DrawPixel(screen, x, y, 0, 255, 0 );
  }
/* end draw circle. */
               
  sleep(5);
                                                                                
  printf("Quitting SDL.\n");
                                                                                
  return(0);
}

On older systems or on systems not using gcc, it might be necessary to add the following in the Makefile:

LDFLAGS=-lm `sdl-config --libs`

The -lm option instructs the linker explicitly to link against the math library. You can find out what libraries your binary uses isuuing the ldd command with the executable as argument, like this:

[tille@octarine ~/C/SDL/screen/circle] ldd circle
        libSDL-1.2.so.0 => /usr/lib/libSDL-1.2.so.0 (0x40017000)
        libpthread.so.0 => /lib/tls/libpthread.so.0 (0x400a3000)
        libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
        libm.so.6 => /lib/tls/libm.so.6 (0x400b2000)
        libdl.so.2 => /lib/libdl.so.2 (0x400d4000)
        libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x400d8000)
        libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x401b7000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

There are a couple of libraries that the linker finds out automatically, like this libm.so.6 and the X libraries. The C library, libc, is included by default.

Home-brewed functions

In the following example, we'll make our own function, DrawCircle, which draws circles to the screen specified. The arguments for the DrawPixel have to be given, and also the RGB values, so that this will be a more flexible function:

/* Program Name: circle.c */
/* SDL screen test */
                                                                                
# include <SDL.h>
# include <stdlib.h>
# include <unistd.h>
# include <math.h>
                                                                                
/* Begin DrawPixel. */
void DrawPixel(SDL_Surface *screen, int x, int y,
Uint8 R, Uint8 G,
Uint8 B)
{
/* Don't fail on attempts to draw outside the screen. */
if ((x>=640) || (x<0)) return;
if ((y>=480) || (y<0)) return;
                                                                                
    Uint32 color = SDL_MapRGB(screen->format, R, G, B);
                                                                                
    if ( SDL_MUSTLOCK(screen) ) {
        if ( SDL_LockSurface(screen) < 0 ) {
            return;
        }
    }
    switch (screen-format->BytesPerPixel) {
        case 1: { /* Assuming 8-bpp */
            Uint8 *bufp;
                                                                                
            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
            *bufp = color;
        }
        break;
                                                                                
        case 2: { /* Probably 15-bpp or 16-bpp */
            Uint16 *bufp;
                                                                                
            bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
            *bufp = color;
        }
        break;
                                                                                
        case 3: { /* Slow 24-bpp mode, usually not used */
            Uint8 *bufp;
                                                                                
            bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
            if(SDL_BYTEORDER == SDL_LIL_ENDIAN) {
                bufp[0] = color;
                bufp[1] = color >> 8;
                bufp[2] = color >> 16;
            } else {
                bufp[2] = color;
                bufp[1] = color >> 8;
                bufp[0] = color >> 16;
            }
        }
        break;
                                                                                
        case 4: { /* Probably 32-bpp */
            Uint32 *bufp;
                                                                                
            bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
            *bufp = color;
        }
        break;
    }
    if ( SDL_MUSTLOCK(screen) ) {
        SDL_UnlockSurface(screen);
    }
    SDL_UpdateRect(screen, x, y, 1, 1);
}
/* End DrawPixel. */

/* Begin DrawCircle. */
void DrawCircle(SDL_Surface *screen, int rrr, int ggg, int bbb) {
  float i;
  for (i=0; i<2*M_PI; i+=0.01) {
    int x = 120 + 100*cos(i);
    int y = 120 + 100*sin(i);
    DrawPixel(screen, x, y, rrr, ggg, bbb );
  }
}
/* End DrawCircle. */

                                                                                
int main()
{
  SDL_Surface *screen;
  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
  }
  atexit(SDL_Quit);
                                                                                
  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
    if ( screen == NULL ) {
        fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
        exit(1);
    }
                                                                                
  printf("Set window of 640x480 at %d bits per pixel mode\n",
        screen->format->BitsPerPixel);

/* test DrawCircle */
  DrawCircle(screen, 255, 255, 255);
/* end test DrawCircle */
                                                                                
  sleep(5);
                                                                                
  printf("Quitting SDL.\n");
                                                                                
  return(0);
}

Edit the make file and see if this works. If it does, you can start playing around a bit. Here is another example, that demonstrates how to fade a color. Insert this bit of code in between the test comments:

/* test DrawCircle */
  int y;
  for (y=0; y<255; y++) {
  DrawCircle(screen, 0, y, 0);
  }
/* end test DrawCircle */

In this example, we make the DrawCircle function more fancy, so that we can draw circles with different radius.

--omitted begin of program--
/* Begin DrawCircle. */
                                                                                
void DrawCircle(SDL_Surface *screen, int rrr, int ggg, int bbb, int radius) {
  float i;
  for (i=0; i<2*M_PI; i+=0.01) {
    int x = 220 + radius*cos(i);
    int y = 220 + radius*sin(i);
    DrawPixel(screen, x, y, rrr, ggg, bbb );
  }
}
                                                                                
/* End DrawCircle. */

--omitted first part of main()--

/* test DrawCircle */
  int blue;
  int myradius = 1;
  for (blue=0; blue<255; blue++) {
  DrawCircle(screen, 255, 100, blue, myradius);
  myradius++;
  }
/* end test DrawCircle */
--omitted last part of program--

If you play around a bit with the values of i for calculating sinuses and cosinuses, you can do the strangest things. This will make a fish - but it is generally named a Lisajou curve:

/* Begin DrawCircle. */
                                                                                
void DrawCircle(SDL_Surface *screen, int rrr, int ggg, int bbb, int radius) {
  float i;
  for (i=0; i<2*M_PI; i+=0.01) {
    int x = 220 + radius*cos(2*i);
    int y = 220 + radius*sin(3*i);
    DrawPixel(screen, x, y, rrr, ggg, bbb );
  }
}
                                                                                
/* End DrawCircle. */
--cut--
/* test DrawCircle */
  int blue;
  int myradius = 1;
  for (blue=0; blue<255; blue++) {
  DrawCircle(screen, 255, 100, blue, myradius);
  myradius++;
  }
/* end test DrawCircle */

Working on the functions

This would be sort of the ideal circle function, in which all parameters are variable:

/* Begin DrawCircle. */
                                                                                
void DrawCircle(SDL_Surface *screen, int rrr, int ggg, int bbb, int radius, int
offsetx, int offsety) {
  float i;
  for (i=0; i<2*M_PI; i+=0.01) {
    int x = offsetx + radius*cos(i);
    int y = offsety + radius*sin(i);
    DrawPixel(screen, x, y, rrr, ggg, bbb );
  }
}
                                                                                
/* End DrawCircle. */

Now we have some basic fun stuff to play with. Go ahead, write a couple of programs that play with this.

In the next chapter, we explain how to include some random effects.

Home
© 1995-2010 Machtelt Garrels - tille - Powered by vIm - Best viewed with your eyes - Validated by W3C - Last update 20100511