singe/thirdparty/manymouse/example/manymousepong.c
2023-10-23 19:38:18 -05:00

993 lines
28 KiB
C

/*
* This is a more robust "pong" than mmpong.c ... it handles more than
* two people and puts paddles on all four sides of the screen, assuming
* you have that many mice plugged in.
*
* Player 1 is on the left, Player 2 on the right, 3 on the top, 4 on the
* bottom, and then 5 to n continue this pattern.
*
* This was written to show a robust use of the library with arbitrary
* numbers of players. mmpong.c is better if you want a small example
* to get you started on your own program.
*
* You need Simple Directmedia Layer (http://libsdl.org/) to use this code.
*
* Controls:
* Plus to add more balls to the game, minus to remove some. Escape to quit.
* Whatever mice you have will control the paddles.
*
* Written by Ryan C. Gordon (icculus@icculus.org).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "SDL.h"
#include "manymouse.h"
#ifdef _MSC_VER
#define inline __inline
#endif
/*
* paddles and balls. Things. They're all basically rectangles that move.
*/
typedef struct
{
Uint32 color;
float x; /* location is top left pixel. */
float y;
int w; /* size is in pixels. */
int h;
float xvelocity; /* velocity is in pixels per second. */
float yvelocity;
float delayUpdate; /* seconds to delay before updating. */
int exists;
int blanked; /* already blanked this frame. */
} PongThing;
typedef struct
{
Uint8 r;
Uint8 g;
Uint8 b;
} RGB;
#define MAX_PADDLES 32
#define MAX_BALLS 32
#define MAX_UPDATERECTS 100
/* Paddle speed for keyboard input (in seconds to cross the screen). */
#define PADDLE_SPEED 1.0
/* default ball speeds (in seconds to cross the screen). */
#define BALL_VSPEED 5.0
#define BALL_HSPEED 1.7
/* time to wait between setting video mode and balls start moving. */
#define VIDEOINIT_DELAY 3.0f
typedef enum
{
PADDLESIDE_LEFT=0,
PADDLESIDE_RIGHT,
PADDLESIDE_TOP,
PADDLESIDE_BOTTOM,
PADDLESIDE_MAX
} PaddleSide;
static PongThing paddles[MAX_PADDLES];
static PongThing balls[MAX_BALLS];
static int sideExists[PADDLESIDE_MAX];
static int sideScore[PADDLESIDE_MAX];
static SDL_Rect rects[MAX_UPDATERECTS];
static int rectCount = 0;
static SDL_Surface *screen = NULL;
static int available_mice = 0;
static Uint32 sdlvideoflags = SDL_FULLSCREEN;
static int sdlgrab = 1;
static int showfps = 0;
static int screenwidth = 640;
static int screenheight = 480;
static float screenWidthScale = 1.0f;
static float screenHeightScale = 1.0f;
static void renderOneThing(PongThing *thing, int blanking);
static int initVideo(void)
{
int i;
if (!SDL_WasInit(SDL_INIT_VIDEO))
{
if (SDL_Init(SDL_INIT_VIDEO) == -1)
return 0;
} /* if */
SDL_WM_GrabInput(sdlgrab ? SDL_GRAB_ON : SDL_GRAB_OFF);
SDL_ShowCursor(0);
SDL_WM_SetCaption("ManyMouse PONG!", "ManyMousePong");
screen = SDL_SetVideoMode(screenwidth, screenheight, 0, sdlvideoflags);
if (screen == NULL)
{
SDL_Quit();
return 0;
} /* if */
/*
* We consider 640x480 to be the "native" resolution of the game.
* Everything here scales to any arbitrary resolution, but relative
* mouse motion is presumably the same no matter what the resolution.
*
* Therefore, we modulate relative motion to make it match what it would
* we in 640x480...this way, mice don't move slower or faster at
* different resolutions...
*/
screenWidthScale = ((float) screen->w) / 640.0f;
screenHeightScale = ((float) screen->h) / 480.0f;
SDL_FillRect(screen, NULL, 0); /* blank surface */
SDL_Flip(screen); /* move it to the screen. */
for (i = 0; i < MAX_PADDLES; i++)
paddles[i].blanked = 1;
for (i = 0; i < MAX_BALLS; i++)
balls[i].blanked = 1;
return 1; /* we're good to go. */
} /* initVideo */
static inline PaddleSide getPaddleSide(int paddleidx)
{
return (PaddleSide) (paddleidx % 4);
} /* getPaddleSide */
static void setSidesExists(void)
{
int i;
sideExists[PADDLESIDE_LEFT] = 0;
sideExists[PADDLESIDE_RIGHT] = 0;
sideExists[PADDLESIDE_TOP] = 0;
sideExists[PADDLESIDE_BOTTOM] = 0;
for (i = 0; i < available_mice; i++)
{
PaddleSide side = getPaddleSide(i);
if (paddles[i].exists)
sideExists[side] = 1;
} /* for */
} /* setSidesExists */
static int initMice(void)
{
int i;
available_mice = ManyMouse_Init();
if (available_mice < 0)
{
printf("Error initializing ManyMouse!\n");
return 0;
}
printf("ManyMouse driver: %s\n", ManyMouse_DriverName());
if (available_mice == 0)
printf("No mice detected!\n");
else
{
for (i = 0; i < available_mice; i++)
{
const char *name = ManyMouse_DeviceName(i);
printf("#%d: %s\n", i, name);
}
if (available_mice > MAX_PADDLES)
{
printf("Clamping to first %d mice.\n", available_mice);
available_mice = MAX_PADDLES;
}
for (i = 0; i < available_mice; i++)
paddles[i].exists = 1;
}
setSidesExists();
return 1;
} /* initMice */
static Uint32 standardizedColor(void)
{
/*
* How I got these numbers:
* These color choices are ripped directly from QuickBasic's
* COLOR command in text mode. So, (1) is dark blue, (2) is
* dark green, etc...Then I used the GIMP color tool
* (http://www.gimp.org/), to find the equivalents in RGB format.
*/
static RGB colorArray[] =
{
#if 0 /* these don't stand out well, just use the bright ones. */
{ 0, 0, 0 }, /* black */
{ 0, 26, 196 }, /* dark blue */
{ 0, 153, 45 }, /* dark green */
{ 0, 144, 138 }, /* dark cyan */
{ 160, 0, 0 }, /* dark red */
{ 197, 0, 202 }, /* dark magenta */
{ 129, 90, 16 }, /* brown */
{ 200, 200, 200 }, /* gray */
{ 90, 90, 90 }, /* dark gray */
#endif
{ 0, 200, 255 }, /* bright blue */
{ 0, 90, 38 }, /* bright green */
{ 91, 110, 255 }, /* bright cyan */
{ 255, 0, 0 }, /* bright red */
{ 255, 0, 255 }, /* bright pink */
{ 255, 255, 0 }, /* bright yellow */
{ 255, 255, 255 }, /* bright white */
};
static int nextcolor = 0;
const RGB *color = &colorArray[nextcolor++];
nextcolor %= (sizeof (colorArray) / sizeof (colorArray[0]));
return SDL_MapRGB(screen->format, color->r, color->g, color->b);
} /* standardizedColor */
#if 0
static inline Uint32 randomizedColor(void)
{
Uint8 r = (Uint8) (255.0f*rand()/(RAND_MAX+1.0f));
Uint8 g = (Uint8) (255.0f*rand()/(RAND_MAX+1.0f));
Uint8 b = (Uint8) (255.0f*rand()/(RAND_MAX+1.0f));
return SDL_MapRGB(screen->format, r, g, b);
} /* randomizedColor */
#endif
static inline void resetBallVelocity(PongThing *ball)
{
/* divided by 3.0 would == 3 seconds from one side of screen to other. */
float origx = ball->xvelocity < 0.0f ? -1.0f : 1.0f;
float origy = ball->yvelocity < 0.0f ? -1.0f : 1.0f;
ball->xvelocity = (((float) screen->w) / BALL_HSPEED) * origx;
ball->yvelocity = (((float) screen->h) / BALL_VSPEED) * origy;
} /* resetBallVelocity */
static void initThings(void)
{
int i = 0;
int ball_width = (int) (screen->w * 0.017);
int ball_height = ball_width; /* eh. */
int vert_paddle_width = (int) (screen->w * 0.02);
int vert_paddle_height = (int) (screen->h * 0.10);
int centerx = ((screen->w - ball_width) / 2);
int centery = ((screen->h - ball_height) / 2);
srand(time(NULL));
memset(sideExists, '\0', sizeof (sideExists));
memset(sideScore, '\0', sizeof (sideScore));
memset(paddles, '\0', sizeof (paddles));
memset(balls, '\0', sizeof (balls));
for (i = 0; i < MAX_PADDLES; i++)
{
PongThing *thing = &paddles[i];
PaddleSide side = getPaddleSide(i);
thing->color = standardizedColor();
thing->blanked = 1;
if ((side == PADDLESIDE_LEFT) || (side == PADDLESIDE_RIGHT))
{
thing->w = vert_paddle_width;
thing->h = vert_paddle_height;
thing->x = ((i % 2) ? screen->w - vert_paddle_width : 0);
thing->y = (screen->h - vert_paddle_height) / 2;
} /* if */
else /* top or bottom */
{
thing->h = vert_paddle_width;
thing->w = vert_paddle_height;
thing->x = (screen->w - vert_paddle_height) / 2;
thing->y = ((i % 2) ? screen->h - vert_paddle_width : 0);
} /* else */
} /* for */
for (i = 0; i < MAX_BALLS; i++)
{
PongThing *thing = &balls[i];
thing->color = standardizedColor();
thing->w = ball_width;
thing->h = ball_height;
thing->x = centerx;
thing->y = centery;
thing->blanked = 1;
thing->xvelocity = 1.0f;
thing->yvelocity = 1.0f;
resetBallVelocity(thing);
} /* for */
/*
* Just put one ball into play to start, and don't kick it off
* for three seconds, so going to fullscreen mode doesn't
* cause a score before the monitor catches up.
*/
balls[0].exists = 1;
balls[0].delayUpdate = VIDEOINIT_DELAY;
} /* initThings */
static void updateMice(int screen_w, int screen_h)
{
ManyMouseEvent event;
while (ManyMouse_PollEvent(&event))
{
PongThing *paddle = NULL;
PaddleSide side = 0;
if (event.device >= (unsigned int) available_mice)
continue;
paddle = &paddles[event.device];
side = getPaddleSide(event.device);
if (event.type == MANYMOUSE_EVENT_RELMOTION)
{
if (event.item == 0)
{
if ((side == PADDLESIDE_TOP) || (side == PADDLESIDE_BOTTOM))
{
renderOneThing(paddle, 1); /* blank in framebuffer. */
paddle->x += ((float) event.value) * screenWidthScale;
} /* if */
} /* if */
else if (event.item == 1)
{
if ((side == PADDLESIDE_LEFT) || (side == PADDLESIDE_RIGHT))
{
renderOneThing(paddle, 1); /* blank in framebuffer. */
paddle->y += ((float) event.value) * screenHeightScale;
} /* if */
} /* else if */
} /* if */
else if (event.type == MANYMOUSE_EVENT_ABSMOTION)
{
if (event.item == 0)
{
if ((side == PADDLESIDE_TOP) || (side == PADDLESIDE_BOTTOM))
{
float val = (float) (event.value - event.minval);
float maxval = (float) (event.maxval - event.minval);
renderOneThing(paddle, 1); /* blank in framebuffer. */
paddle->x = (float) ((val / maxval) * screen_w);
} /* if */
} /* if */
else if (event.item == 1)
{
if ((side == PADDLESIDE_LEFT) || (side == PADDLESIDE_RIGHT))
{
float val = (float) (event.value - event.minval);
float maxval = (float) (event.maxval - event.minval);
renderOneThing(paddle, 1); /* blank in framebuffer. */
paddle->y = (float) ((val / maxval) * screen_h);
} /* if */
} /* else if */
} /* else if */
else if (event.type == MANYMOUSE_EVENT_BUTTON)
{
if (event.value == 1) /* pressed */
paddle->color = standardizedColor();
} /* else if */
else if (event.type == MANYMOUSE_EVENT_DISCONNECT)
{
renderOneThing(paddle, 1); /* blank in framebuffer. */
paddle->exists = 0;
setSidesExists();
} /* else if */
} /* while */
} /* updateMice */
static int updateInput(void)
{
SDL_Event event;
updateMice(screen->w, screen->h);
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT: /* window was closed, etc. */
return 0;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE)
return 0; /* quit. */
else if (event.key.keysym.sym == SDLK_KP_PLUS)
{
/* put a new ball into play */
int i;
for (i = 0; i < MAX_BALLS; i++)
{
PongThing *ball = &balls[i];
if (ball->exists)
continue;
/* !!! FIXME: subroutine this. */
ball->x = ((screen->w - ball->w) / 2);
ball->y = ((screen->h - ball->h) / 2);
ball->color = standardizedColor();
ball->delayUpdate = 0.25f;
ball->exists = 1;
ball->blanked = 1;
ball->xvelocity = ball->yvelocity = 1.0f;
resetBallVelocity(ball);
break;
} /* for */
} /* else if */
else if (event.key.keysym.sym == SDLK_KP_MINUS)
{
/* remove a ball from play */
int i;
for (i = MAX_BALLS - 1; i >= 0; i--)
{
PongThing *ball = &balls[i];
if (!ball->exists)
continue;
renderOneThing(ball, 1);
ball->exists = 0;
break;
} /* for */
} /* else if */
else if (event.key.keysym.sym == SDLK_g)
{
if (event.key.keysym.mod & KMOD_CTRL)
{
sdlgrab = sdlgrab ? 0 : 1;
SDL_WM_GrabInput(sdlgrab ? SDL_GRAB_ON : SDL_GRAB_OFF);
} /* if */
} /* else if */
else if (event.key.keysym.sym == SDLK_RETURN)
{
if (event.key.keysym.mod & KMOD_ALT)
{
int i;
if (sdlvideoflags & SDL_FULLSCREEN)
sdlvideoflags &= ~SDL_FULLSCREEN;
else
sdlvideoflags |= SDL_FULLSCREEN;
if (!initVideo())
{
printf("window/fullscreen toggle failed!\n");
return 0; /* quit */
} /* if */
/*
* Render all balls then freeze them so the monitor
* has time to catch up and players can get oriented.
*/
for (i = 0; i < MAX_BALLS; i++)
{
PongThing *ball = &balls[i];
if (ball->exists)
{
resetBallVelocity(ball);
ball->delayUpdate = VIDEOINIT_DELAY;
} /* if */
} /* for */
} /* if */
} /* else if */
break;
} /* switch */
} /* while */
return 1; /* no quit events this time. */
} /* updateInput */
static void renderOneThing(PongThing *thing, int blanking)
{
SDL_Rect *rect;
if ((!thing->exists) || (blanking && thing->blanked))
return;
if (rectCount < MAX_UPDATERECTS)
rect = &rects[rectCount++];
else
rect = &rects[0]; /* oh well. */
/* !!! FIXME: need clipping. */
rect->x = thing->x;
rect->y = thing->y;
rect->w = thing->w;
rect->h = thing->h;
SDL_FillRect(screen, rect, blanking ? 0x00000000 : thing->color);
thing->blanked = blanking;
/* note that this isn't on the screen until we call SDL_UpdateRects(). */
} /* renderOneThing */
static void renderThings(void)
{
int i;
for (i = 0; i < available_mice; i++)
renderOneThing(&paddles[i], 0);
for (i = 0; i < MAX_BALLS; i++)
renderOneThing(&balls[i], 0);
if (rectCount < MAX_UPDATERECTS)
SDL_UpdateRects(screen, rectCount, rects);
else
{
printf("Developer warning! overflowed updaterects!\n");
SDL_Flip(screen); /* just do the whole screen. */
} /* else */
rectCount = 0;
} /* renderThings */
static void triggerScore(PongThing *ball, PaddleSide scoreAgainst)
{
#define INCR_SCORE(side) if (scoreAgainst != side) { sideScore[side]++; }
INCR_SCORE(PADDLESIDE_LEFT);
INCR_SCORE(PADDLESIDE_RIGHT);
INCR_SCORE(PADDLESIDE_TOP);
INCR_SCORE(PADDLESIDE_BOTTOM);
#undef INCR_SCORE
#define PRINT_SCORE(side) { \
if (sideExists[PADDLESIDE_##side]) \
printf(" %s side: %d.\n", #side, sideScore[PADDLESIDE_##side]); \
}
printf("SCORE!\n");
PRINT_SCORE(LEFT);
PRINT_SCORE(RIGHT);
PRINT_SCORE(TOP);
PRINT_SCORE(BOTTOM);
printf("\n");
#undef PRINT_SCORE
/* center it again. */
ball->x = ((screen->w - ball->w) / 2);
ball->y = ((screen->h - ball->h) / 2);
/* pick a new color for the next ball. */
ball->color = standardizedColor();
/* wait two seconds before ball is back in play. */
ball->delayUpdate = 2.0f;
/* point next ball at opposing side. */
if ((scoreAgainst==PADDLESIDE_LEFT) || (scoreAgainst==PADDLESIDE_RIGHT))
ball->xvelocity *= -1.0f;
else
ball->yvelocity *= -1.0f;
resetBallVelocity(ball);
} /* triggerScore */
static void updatePaddle(PongThing *thing, float fractionalTime)
{
if (!thing->exists)
return;
renderOneThing(thing, 1); /* blank existing thing in framebuffer. */
/* this is for keyboard input, mostly...mice don't move here... */
thing->x += thing->xvelocity * fractionalTime;
thing->y += thing->yvelocity * fractionalTime;
/* collided with left wall. */
if (thing->x < 0.0f)
{
thing->x = 0.0f;
} /* if */
/* collided with right wall. */
else if (thing->x > ((float) screen->w) - ((float) thing->w))
{
thing->x = ((float) screen->w) - ((float) thing->w);
} /* if */
/* collided with top wall. */
if (thing->y < 0.0f)
{
thing->y = 0.0f;
} /* if */
/* collided with bottom wall. */
else if (thing->y > ((float) screen->h) - ((float) thing->h))
{
thing->y = ((float) screen->h) - ((float) thing->h);
} /* if */
} /* updatePaddle */
static inline int inRect(int x, int y, int bx1, int by1, int bx2, int by2)
{
/* bounding box must be normalized. */
if ((x < bx1) || (x > bx2))
return 0;
if ((y < by1) || (y > by2))
return 0;
return 1;
} /* inRect */
static inline int intersection(int px1, int py1, int px2, int py2,
int bx1, int by1, int bx2, int by2)
{
/* if any corner of a rect is in the other, it's a collision. */
return ( (inRect(px1, py1, bx1, by1, bx2, by2)) ||
(inRect(px2, py1, bx1, by1, bx2, by2)) ||
(inRect(px1, py2, bx1, by1, bx2, by2)) ||
(inRect(px2, py2, bx1, by1, bx2, by2)) ||
(inRect(bx1, by1, px1, py1, px2, py2)) ||
(inRect(bx2, by1, px1, py1, px2, py2)) ||
(inRect(bx1, by2, px1, py1, px2, py2)) ||
(inRect(bx2, by2, px1, py1, px2, py2)) );
} /* intersection */
/* returns non-zero if bounced, zero if score against existing team. */
static inline int scoreOrBounce(PongThing *ball, PaddleSide side)
{
if (sideExists[side])
{
triggerScore(ball, side);
return 0;
} /* if */
return 1;
} /* scoreOrBounce */
static void updateBall(PongThing *ball, float fractionalTime)
{
/* !!! FIXME: be nice if bounces randomized direction */
int i;
float xorig, yorig;
int bx1, bx2, by1, by2;
int bounced = 0;
if (!ball->exists)
return;
ball->delayUpdate -= fractionalTime;
if (ball->delayUpdate > 0.0f)
return;
renderOneThing(ball, 1); /* blank existing ball in framebuffer. */
xorig = ball->x;
yorig = ball->y;
ball->x += ball->xvelocity * fractionalTime;
ball->y += ball->yvelocity * fractionalTime;
if (xorig < ball->x)
{
bx1 = xorig;
bx2 = ball->x + ball->w;
} /* if */
else
{
bx1 = ball->x;
bx2 = xorig + ball->w;
} /* else */
if (yorig < ball->y)
{
by1 = yorig;
by2 = ball->y + ball->h;
} /* if */
else
{
by1 = ball->y;
by2 = yorig + ball->h;
} /* else */
/* check paddle collisions. */
for (i = 0; i < available_mice; i++)
{
int px1, px2, py1, py2;
PongThing *paddle = &paddles[i];
if (!paddle->exists)
continue;
/* !!! FIXME: should round to nearest, not truncate! */
/* cast to int only once. */
px1 = (int) paddle->x;
px2 = px1 + paddle->w;
py1 = (int) paddle->y;
py2 = py1 + paddle->h;
/*
* The trick here is to not care where the ball is currently, but
* rather whether it would overlap or pass through a given paddle
* on this frame.
*
* We go for cheap, not accurate, erring on the side of the player
* (the bigger the lag spike, the more likely they are to trigger
* a collision, even when there shouldn't be one, but in Pong,
* there'd have to be a BIG lag spike to screw this up).
*
* We construct a bounding rectangle of the entire surface area
* the ball could have touched when going from point A to point B
* on this frame, and then see if the paddle's rectangle touches
* it. If so, it's a collision, even though the paddle might have
* scraped a corner of the bounding box where the ball never
* actually touched. When you're getting hundreds of frames per
* second however, the likelihood of this ever failing, let alone
* failing noticably, is basically null.
*
* My devbox currently renders this game at over 15,000 fps.
*/
if (intersection(px1, py1, px2, py2, bx1, by1, bx2, by2))
{
/* It's a hit, bounce the ball. */
/* Push it to the edge of the paddle and reverse velocity. */
PaddleSide side = getPaddleSide(i);
if (side == PADDLESIDE_LEFT)
{
ball->x = (px2 + ball->w) + 1;
ball->xvelocity *= -1.0f;
} /* else if */
else if (side == PADDLESIDE_RIGHT)
{
ball->x = (px1 - ball->w) - 1;
ball->xvelocity *= -1.0f;
} /* if */
else if (side == PADDLESIDE_TOP)
{
ball->y = (py2 + ball->h) + 1;
ball->yvelocity *= -1.0f;
} /* else if */
else if (side == PADDLESIDE_BOTTOM)
{
ball->y = (py1 - ball->h) - 1;
ball->yvelocity *= -1.0f;
} /* else if */
bounced = 1;
break; /* detected a collision; stop checking paddles. */
} /* if */
} /* for */
/* no collisions with paddles this frame? See about wall collisions... */
/* Multiply velocity by -1.0 so it reverses. */
if (i == available_mice)
{
/*
* If we hit a wall, we need to see if there's at least one paddle
* guarding that side. If so, it's a score. If not, just bounce off
* the wall.
*/
/* collided with left wall. */
if (ball->x < 0.0f)
{
if ((bounced = scoreOrBounce(ball, PADDLESIDE_LEFT)) != 0)
{
ball->x = 0.0f;
ball->xvelocity *= -1.0f;
} /* else */
} /* if */
/* collided with right wall. */
else if (ball->x > ((float) screen->w) - ((float) ball->w))
{
if ((bounced = scoreOrBounce(ball, PADDLESIDE_RIGHT)) != 0)
{
ball->x = ((float) screen->w) - ((float) ball->w);
ball->xvelocity *= -1.0f;
} /* else */
} /* if */
/* collided with top wall. */
if (ball->y < 0.0f)
{
if ((bounced = scoreOrBounce(ball, PADDLESIDE_TOP)) != 0)
{
ball->y = 0.0f;
ball->yvelocity *= -1.0f;
} /* else */
} /* if */
/* collided with bottom wall. */
else if (ball->y > ((float) screen->h) - ((float) ball->h))
{
if ((bounced = scoreOrBounce(ball, PADDLESIDE_BOTTOM)) != 0)
{
ball->y = ((float) screen->h) - ((float) ball->h);
ball->yvelocity *= -1.0f;
} /* else */
} /* if */
} /* if */
if (bounced)
{
/* increase velocities from 0% to 5% if we bounced off something. */
ball->xvelocity *= 1.0f + ((10.0f*rand()/(RAND_MAX+1.0f)) / 200.0f);
ball->yvelocity *= 1.0f + ((10.0f*rand()/(RAND_MAX+1.0f)) / 200.0f);
} /* if */
} /* updateBall */
static void updateThings(void)
{
int i;
static int firstRun = 1;
static Uint32 lastTicks = 0;
Uint32 ticks = SDL_GetTicks();
float fractionalTime;
if (firstRun) /* since setting fullscreen can take several seconds... */
{
lastTicks = ticks;
firstRun = 0;
} /* if */
fractionalTime = ((ticks - lastTicks) / 1000.0f);
for (i = 0; i < available_mice; i++)
updatePaddle(&paddles[i], fractionalTime);
for (i = 0; i < MAX_BALLS; i++)
updateBall(&balls[i], fractionalTime);
lastTicks = ticks;
} /* updateThings */
static int processCmdLines(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
char *arg = argv[i];
if (strcmp(arg, "--windowed") == 0)
sdlvideoflags &= ~SDL_FULLSCREEN;
else if (strcmp(arg, "--fullscreen") == 0)
sdlvideoflags |= SDL_FULLSCREEN;
else if (strcmp(arg, "--grabinput") == 0)
sdlgrab = 1;
else if (strcmp(arg, "--nograbinput") == 0)
sdlgrab = 0;
else if (strcmp(arg, "--showfps") == 0)
showfps = 1;
else if (strcmp(arg, "--noshowfps") == 0)
showfps = 0;
#define SCREENRESOPT(w,h) \
else if (strcmp(arg, "--" #w "x" #h) == 0) { \
screenwidth = w; \
screenheight = h; \
}
SCREENRESOPT(320, 240)
SCREENRESOPT(512, 384)
SCREENRESOPT(640, 480)
SCREENRESOPT(800, 500)
SCREENRESOPT(800, 600)
SCREENRESOPT(1024, 640)
SCREENRESOPT(1024, 768)
SCREENRESOPT(1152, 768)
SCREENRESOPT(1152, 864)
SCREENRESOPT(1280, 800)
SCREENRESOPT(1280, 854)
SCREENRESOPT(1280, 960)
SCREENRESOPT(1280, 1024)
SCREENRESOPT(1600, 1024)
SCREENRESOPT(1600, 1200)
SCREENRESOPT(1680, 1050)
SCREENRESOPT(1920, 1200)
#undef SCREENRESOPT
else
{
printf("Unknown command line '%s'\n", arg);
return 0;
} /* else */
} /* for */
return 1;
} /* processCmdLines */
static void updateFPS(int reinit)
{
/* quick and dirty frame counter. */
static Uint32 fpsticks = 0;
static Uint32 frames = 0;
if (reinit)
{
frames = 0;
fpsticks = SDL_GetTicks() + 5000;
} /* if */
else
{
frames++;
if (SDL_GetTicks() >= fpsticks)
{
if (showfps)
printf("fps == %d\n", (int) (frames / 5));
fpsticks += 5000;
frames = 0;
} /* if */
} /* else */
} /* updateFPS */
int main(int argc, char **argv)
{
if (!processCmdLines(argc, argv))
return 42;
if (!initVideo())
return 42;
initThings();
if (!initMice())
{
SDL_Quit();
return 42;
} /* if */
updateFPS(1);
while (updateInput()) /* go until quit event of some sort. */
{
updateThings(); /* move things to new locations. */
renderThings(); /* draw moved things to screen. */
updateFPS(0);
} /* while */
ManyMouse_Quit();
SDL_Quit(); /* clean up video mode, etc. */
return 0;
} /* main */
/* end of manymousepong.c ... */