GP32 Gp32 Tutorial 03 "structure, Prototyping"


synkro

0xdeadbeef
Joined
Aug 26, 2003
Messages
823
Location
Germany
Website
Visit site
Code:
/*
 * GP32 Tutorial 03 "Structure, Prototyping"
 *
 * Intro
 * -----
 * You are still there? I guess the last two tutos were to easy, huh? This
 * time we have a big and difficult tuto but at its end you will have
 * something to impress your mommy. If you are still willing to learn C/C++
 * for GP32 or in general I advise you to get a C/C++ textbook for beginners.
 * This tuto is really hard, I don't knwo what I was think while writing this
 * one. Feel free to skip this!
 *
 * I can take it!
 * -------------
 * 1. typedef struct
 *    Sometimes we need more than the standard types or arraye of them. We can
 *    compose a complex structure from different types/arrays. Here we define
 *    a type structure named tPARTICLES (the 't' stands for type). Every
 *    structure has different members, this one has four members, all of them
 *    are from the type int. We try to sombine data types that are logically
 *    connected. We can use this structure nearly like the other types.
 *
 * 2. void DrawParticles (void);
 *    Now we have arrived at a stage where our programs become so complex we
 *    should split our code into functions/procedures. Before you can
 *    implement and use them you have to prototype them. In this case we
 *    use two functions one to move and one to draw the particles on screen.
 *    The implementations of these functions are after the main function.
 *
 * 3. particles[i].x = rand() % WIDTH;
 *    We want to set every particle on a random position. To set the x
 *    position we take the specific particle 'particles[i]' and directly set
 *    the member '.x'. Note that the member of the structer is preceded by
 *    a '.'. The function rand() returns a random number, to make sure that
 *    that number is not bigger than the screen width, we use the '%' also
 *    known as modulo (I guess you heard about it at school). With '% WIDTH'
 *    we can assure that the random number is between 0 and WIDTH-1.
 *
 * 4.  gp_SetPixel16(x, y, color, framebuffer);
 *     This SDK function sets a 16bit pixel at (x,y) on a framebuffer.
 *     We get the coordinates from every particle, draw them in the current
 *     framebuffer.
 *
 * So, you think learned enough to make your own particle animations? we
 * will see. First try following exercises after re-typing the code:
 * A) Change the color of the particles
 * B) Add more particles
 * C) Put the particles init in its own function called 'InitParticles'
 *
 * I want to thank everybody who helped in findig bugs and proofreading
 * my bad English!
 *
 * Disclaimer
 * ----------
 * This Tutorial is based on Mr. Mirko's SDK (mirko@mirkoroller.de)
 * download it at: http://home.t-online.de/home/mirkoroller/gp32/
 * THIS TUTORIAL IS NOT WRITTEN BY MR. MIRKO! Parts of this Tutorial
 * are from the SDK's examples or manual.
 *
 *                                 SDK by Mr. Mirko mirko@mirkoroller.de
 *                            Tutorial by synkro    synkro@gmx.net
 *                                                  26.04.2004 14:26:39
 */


#include <gp32.h>
#include <stdlib.h>
// This is the C Standard Lib. We will need this for random numbers
// later on. We use the function rand() that returns a random number.
// Before we can use that function we have to "plant" a random seed.

#define MAX_PARTICLES 100       // Maximum count of particles
#define WIDTH         320
#define HEIGHT        240

#define	FLIP_BUFFER      \
       gp_SetView(framebuffer[nflip++]);	\
       nflip &= 0x01;

// You alread know how to use #define for often used values but
// here we defined a whole macro. The compiler will expand FLIP_BUFFER
// with the following two commands. We use that macro to flip between
// the two framebuffers. '&' is the bitwise AND operator so we assure that
// nflip is 0 or 1 after we increased it.

int nflip = 0;                  // This variable determines the current buffer
unsigned short *framebuffer[2]; // Instead of two pointers we declare
                                // an array of them.

typedef struct
{
  int x, y;                     // Position of the particel (x,y)
  int velocity_x, velocity_y;   // Particle velocity on x- and y-axis
}tPARTICLE;                     // the name of the struct, you don't have to set a preceding 't'

tPARTICLE particles[MAX_PARTICLES];
// This allocates an array of 100 tPARTICLES named particles.

void DrawParticles (void);
void MoveParticles (void);
// Here are the needed prototypes of the functions we want to use later.

/*
 * This is the main function
 */
int main(void)
{
  int i;
  framebuffer[0] = (unsigned short*) FRAMEBUFFER;
  framebuffer[1] = (unsigned short*) (FRAMEBUFFER + (WIDTH*HEIGHT*2));

  gp_SetScreen(framebuffer[1], 16);

  // Clear both buffer white
  for (i=0; i<WIDTH*HEIGHT; i++)
  {
    framebuffer[0][i] = 0xFFFF;
    framebuffer[1][i] = 0xFFFF;
  }

  gp_SetCpuSpeed(66);

  srand(1337);
  // You can take any number as seed, but keep in mind
  // that these are still pseudo random numbers.

  for (i=0; i<MAX_PARTICLES; i++)
  {
     // The particles get a random positrion on the screen
     particles[i].x = rand() % WIDTH;
     particles[i].y = rand() % HEIGHT;

     if ((rand() % 2) == 0)            // (rand() % 2) will be 1 or 0
        particles[i].velocity_x = -(rand() % 3) + 1;
        // if the condition is true the x velocity will be negative
     else
        particles[i].velocity_x = (rand() % 3) + 1;
        // else x velocity will be positive

     if ((rand() % 2) == 0)
        particles[i].velocity_y = -(rand() % 3) + 1;
     else
        particles[i].velocity_y = (rand() % 3) + 1;
     // Here we do the same for the y velocity.

  }
  // This inits all particles with a random position and velocity

  while (1)
  {
  	for (i=0; i<WIDTH*HEIGHT; i++)
       framebuffer[nflip][i] = 0x0000;
  	// Clear the screen black before we draw the particles.

  	MoveParticles();
  	DrawParticles();

  	FLIP_BUFFER
  	for (i=0; i<500000; i++) i=i;
  	// No flip the working framebuffer with the current framebuffer
  	// on screen. This creates the animation of the particles moving
  	// around on the screen.
  }

}

/*
 * This function draws the particles on the screen
 */
void DrawParticles (void)
{
  int i;

  for (i=0; i<MAX_PARTICLES; i++)
      gp_SetPixel16(particles[i].x, particles[i].y, 0xFFFF, framebuffer[nflip]);
  // We draw all particles in white on the current working framebuffer.
}

/*
 * This function moves the particles and deletes them
 * if they are leaving the screen.
 */
void MoveParticles (void)
{
  int i;
  for (i=0; i<MAX_PARTICLES; i++)
  {
    particles[i].x += particles[i].velocity_x;
    if (particles[i].x >= WIDTH)        // Leaving the screen left
        particles[i].x -= WIDTH;        // Reset x coordinate
    if (particles[i].x <= 0)            // Leaving the screen right
        particles[i].x += WIDTH;        // Reset y coordinate

    particles[i].y += particles[i].velocity_y;
    if (particles[i].y >= HEIGHT)       // Leaving the screen top
        particles[i].y -= HEIGHT;       // Reset y coordinate
    if (particles[i].y <= 0)            // Leaving the screen bottom
        particles[i].y += HEIGHT;       // Reset y coordinate

  }

}
 
Code:
#define FLIP_BUFFER      \
      gp_SetView(framebuffer[nflip++]); \
      nflip &= 0x00;

Should be changed to: nflip &= 0x01
 
bobintrees posted on Mar 18 2004 at 02:18 AM said:
Code:
#define FLIP_BUFFER      \
      gp_SetView(framebuffer[nflip++]); \
      nflip &= 0x00;

Should be changed to: nflip &= 0x01
yeah right! thank you!
 
Last edited by a moderator:
actually I think your ideas for this third tutorial are not bad at all, it just might be too much new stuff for one tut, so it might be better to split it into 2 or 3 small ones that connect to a big one in the end.
Like starting off with just one particle and no typedef and just having it move around the screen and make sure that it doesn't leave the screen.
Then make one with more particles but no typedef to show why typedef is useful here.
And in the last one introduce the typefdef.
Something like that, at least that's my 2 cents on this one.
If you do more and need more proofreading, let me know.
 
Hi,

I haven't got a GP32 (yet) but I have developed applications on win32 etc, though mostly in Delphi. This means I can't really experiment yet, but...

I see that every time before the particles are drawn, the screen is cleared by looping through every single pixel.
Code:
for (i=0; i<WIDTH*HEIGHT; i++)
      framebuffer[nflip][i] = 0x0000;

Obviously this loops through 76800 times and sets one pixel each time.

My question is, would it be beneficial to remember the colour of the pixel before drawing the particle (in this case probably always black) and then once the particle has moved, fill the pixel in that colour again?

What this would do is increase the memory requirements for the struct, but would speed up the loop for clearing the screen.

Which is a better trade-off?

Sorry, I have not (can not) tested the code below, but it would be something like this:
Code:
...
typedef struct
{
 int last_x, last_y;       // Last position of the particle
 int last_col;               // Last colour of the particle
 int x, y;                     // Position of the particel (x,y)
 int velocity_x, velocity_y;   // Particle velocity on x- and y-axis
}tPARTICLE;                     // the name of the struct, you don't have to set a preceding 't'
...

 while (1)
 {

  MoveParticles();
  ClearParticles();
  DrawParticles();
  }
...
void ClearParticles (void)
{
 int i;

 for (i=0; i<MAX_PARTICLES; i++)
     gp_SetPixel16(particles[i].last_x, particles[i].last_y, particles[i].last_col, framebuffer[nflip]);
 // We draw all particles in white on the current working framebuffer.
}
...
void MoveParticles (void)
{
 int i;
 for (i=0; i<MAX_PARTICLES; i++)
 {
  // Remember last particle position
  particles[i].last_x = particles[i].x;
  particles[i].last_y = particles[i].y;

   particles[i].x += particles[i].velocity_x;
   if (particles[i].x >= WIDTH)        // Leaving the screen left
       particles[i].x -= WIDTH;        // Reset x coordinate
   if (particles[i].x <= 0)            // Leaving the screen right
       particles[i].x += WIDTH;        // Reset y coordinate

   particles[i].y += particles[i].velocity_y;
   if (particles[i].y >= HEIGHT)       // Leaving the screen top
       particles[i].y -= HEIGHT;       // Reset y coordinate
   if (particles[i].y <= 0)            // Leaving the screen bottom
       particles[i].y += HEIGHT;       // Reset y coordinate

 }

}
...
void DrawParticles (void)
{
  int i;

  for (i=0; i<MAX_PARTICLES; i++)
  {
  particles[i].last_col = framebuffer[nflip][particles[i].last_y*320 + particles[i].last_x];
  // Remember last particle colour for clear
  gp_SetPixel16(particles[i].x, particles[i].y, 0xFFFF, framebuffer[nflip]);
  // We draw all particles in white on the current working framebuffer.
  }
}
 
Back
Top