test/testsprite.c
author Patrice Mandin <patmandin@gmail.com>
Thu, 19 Jan 2006 21:28:52 +0000
changeset 1257 448a9a64537b
parent 1214 31103dbf1c26
child 1516 4d241ea8a1cd
permissions -rw-r--r--
[PATCH] SDL_GetVideoMode() does not find best mode, part 2

Following commit 1.51, I come accross a problem when SDL must choose between
several video modes that could suit the one asked.

If I ask 320x240 with this list:
768x480 768x240 640x400 640x200 384x480 384x240 320x400 320x200

The smallest selectables modes are 384x240 and 320x400. And SDL choose the later
in this list, but 384x240 is more suitable. So I added a check to compare
the pixel count (surface) of modes, and select the one which has the smallest
pixel count.

In my example, 384x240 has 92160 pixels, and 320x400 has 128000 pixels. So now
SDL will choose 384x240 for the asked 320x240 mode.
slouken@0
     1
/* Simple program:  Move N sprites around on the screen as fast as possible */
slouken@0
     2
slouken@0
     3
#include <stdio.h>
slouken@0
     4
#include <stdlib.h>
slouken@0
     5
#include <string.h>
slouken@0
     6
#include <ctype.h>
slouken@753
     7
#include <math.h>
slouken@0
     8
#include <time.h>
slouken@0
     9
slouken@0
    10
#include "SDL.h"
slouken@0
    11
slouken@0
    12
#define NUM_SPRITES	100
slouken@0
    13
#define MAX_SPEED 	1
slouken@0
    14
slouken@0
    15
SDL_Surface *sprite;
slouken@0
    16
int numsprites;
slouken@0
    17
SDL_Rect *sprite_rects;
slouken@0
    18
SDL_Rect *positions;
slouken@0
    19
SDL_Rect *velocities;
slouken@0
    20
int sprites_visible;
icculus@1214
    21
int debug_flip;
slouken@288
    22
Uint16 sprite_w, sprite_h;
slouken@0
    23
icculus@1151
    24
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
icculus@1151
    25
static void quit(int rc)
icculus@1151
    26
{
icculus@1151
    27
	SDL_Quit();
icculus@1151
    28
	exit(rc);
icculus@1151
    29
}
icculus@1151
    30
slouken@0
    31
int LoadSprite(SDL_Surface *screen, char *file)
slouken@0
    32
{
slouken@0
    33
	SDL_Surface *temp;
slouken@0
    34
slouken@0
    35
	/* Load the sprite image */
slouken@0
    36
	sprite = SDL_LoadBMP(file);
slouken@0
    37
	if ( sprite == NULL ) {
slouken@0
    38
		fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError());
slouken@0
    39
		return(-1);
slouken@0
    40
	}
slouken@0
    41
slouken@0
    42
	/* Set transparent pixel as the pixel at (0,0) */
slouken@0
    43
	if ( sprite->format->palette ) {
slouken@0
    44
		SDL_SetColorKey(sprite, (SDL_SRCCOLORKEY|SDL_RLEACCEL),
slouken@0
    45
						*(Uint8 *)sprite->pixels);
slouken@0
    46
	}
slouken@0
    47
slouken@0
    48
	/* Convert sprite to video format */
slouken@0
    49
	temp = SDL_DisplayFormat(sprite);
slouken@0
    50
	SDL_FreeSurface(sprite);
slouken@0
    51
	if ( temp == NULL ) {
slouken@0
    52
		fprintf(stderr, "Couldn't convert background: %s\n",
slouken@0
    53
							SDL_GetError());
slouken@0
    54
		return(-1);
slouken@0
    55
	}
slouken@0
    56
	sprite = temp;
slouken@0
    57
slouken@0
    58
	/* We're ready to roll. :) */
slouken@0
    59
	return(0);
slouken@0
    60
}
slouken@0
    61
slouken@0
    62
void MoveSprites(SDL_Surface *screen, Uint32 background)
slouken@0
    63
{
slouken@0
    64
	int i, nupdates;
slouken@0
    65
	SDL_Rect area, *position, *velocity;
slouken@0
    66
slouken@0
    67
	nupdates = 0;
slouken@0
    68
	/* Erase all the sprites if necessary */
slouken@0
    69
	if ( sprites_visible ) {
slouken@0
    70
		SDL_FillRect(screen, NULL, background);
slouken@0
    71
	}
slouken@0
    72
slouken@0
    73
	/* Move the sprite, bounce at the wall, and draw */
slouken@0
    74
	for ( i=0; i<numsprites; ++i ) {
slouken@0
    75
		position = &positions[i];
slouken@0
    76
		velocity = &velocities[i];
slouken@0
    77
		position->x += velocity->x;
slouken@288
    78
		if ( (position->x < 0) || (position->x >= (screen->w - sprite_w)) ) {
slouken@0
    79
			velocity->x = -velocity->x;
slouken@0
    80
			position->x += velocity->x;
slouken@0
    81
		}
slouken@0
    82
		position->y += velocity->y;
slouken@288
    83
		if ( (position->y < 0) || (position->y >= (screen->h - sprite_w)) ) {
slouken@0
    84
			velocity->y = -velocity->y;
slouken@0
    85
			position->y += velocity->y;
slouken@0
    86
		}
slouken@0
    87
slouken@0
    88
		/* Blit the sprite onto the screen */
slouken@0
    89
		area = *position;
slouken@0
    90
		SDL_BlitSurface(sprite, NULL, screen, &area);
slouken@0
    91
		sprite_rects[nupdates++] = area;
slouken@0
    92
	}
slouken@0
    93
icculus@1214
    94
	if (debug_flip) {
icculus@1214
    95
		if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
icculus@1214
    96
			static int t = 0;
slouken@663
    97
icculus@1214
    98
			Uint32 color = SDL_MapRGB (screen->format, 255, 0, 0);
icculus@1214
    99
			SDL_Rect r;
icculus@1214
   100
			r.x = (sin((float)t * 2 * 3.1459) + 1.0) / 2.0 * (screen->w-20);
icculus@1214
   101
			r.y = 0;
icculus@1214
   102
			r.w = 20;
icculus@1214
   103
			r.h = screen->h;
icculus@1214
   104
icculus@1214
   105
			SDL_FillRect (screen, &r, color);
icculus@1214
   106
			t+=2;
icculus@1214
   107
		}
icculus@1214
   108
	}
icculus@1214
   109
slouken@0
   110
	/* Update the screen! */
slouken@0
   111
	if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
slouken@0
   112
		SDL_Flip(screen);
slouken@0
   113
	} else {
slouken@0
   114
		SDL_UpdateRects(screen, nupdates, sprite_rects);
slouken@0
   115
	}
slouken@0
   116
	sprites_visible = 1;
slouken@0
   117
}
slouken@0
   118
slouken@0
   119
/* This is a way of telling whether or not to use hardware surfaces */
slouken@107
   120
Uint32 FastestFlags(Uint32 flags, int width, int height, int bpp)
slouken@0
   121
{
slouken@0
   122
	const SDL_VideoInfo *info;
slouken@0
   123
slouken@0
   124
	/* Hardware acceleration is only used in fullscreen mode */
slouken@0
   125
	flags |= SDL_FULLSCREEN;
slouken@0
   126
slouken@0
   127
	/* Check for various video capabilities */
slouken@0
   128
	info = SDL_GetVideoInfo();
slouken@0
   129
	if ( info->blit_hw_CC && info->blit_fill ) {
slouken@0
   130
		/* We use accelerated colorkeying and color filling */
slouken@0
   131
		flags |= SDL_HWSURFACE;
slouken@0
   132
	}
slouken@0
   133
	/* If we have enough video memory, and will use accelerated
slouken@0
   134
	   blits directly to it, then use page flipping.
slouken@0
   135
	 */
slouken@0
   136
	if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
slouken@0
   137
		/* Direct hardware blitting without double-buffering
slouken@0
   138
		   causes really bad flickering.
slouken@0
   139
		 */
slouken@107
   140
		if ( info->video_mem*1024 > (height*width*bpp/8) ) {
slouken@0
   141
			flags |= SDL_DOUBLEBUF;
slouken@0
   142
		} else {
slouken@0
   143
			flags &= ~SDL_HWSURFACE;
slouken@0
   144
		}
slouken@0
   145
	}
slouken@0
   146
slouken@0
   147
	/* Return the flags */
slouken@0
   148
	return(flags);
slouken@0
   149
}
slouken@0
   150
slouken@0
   151
int main(int argc, char *argv[])
slouken@0
   152
{
slouken@0
   153
	SDL_Surface *screen;
slouken@0
   154
	Uint8 *mem;
slouken@0
   155
	int width, height;
slouken@0
   156
	Uint8  video_bpp;
slouken@0
   157
	Uint32 videoflags;
slouken@0
   158
	Uint32 background;
slouken@0
   159
	int    i, done;
slouken@0
   160
	SDL_Event event;
slouken@0
   161
	Uint32 then, now, frames;
slouken@0
   162
slouken@0
   163
	/* Initialize SDL */
slouken@0
   164
	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
slouken@0
   165
		fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
icculus@1151
   166
		return(1);
slouken@0
   167
	}
slouken@0
   168
slouken@0
   169
	numsprites = NUM_SPRITES;
slouken@0
   170
	videoflags = SDL_SWSURFACE|SDL_ANYFORMAT;
slouken@0
   171
	width = 640;
slouken@0
   172
	height = 480;
slouken@0
   173
	video_bpp = 8;
icculus@1214
   174
	debug_flip = 0;
slouken@0
   175
	while ( argc > 1 ) {
slouken@0
   176
		--argc;
slouken@0
   177
		if ( strcmp(argv[argc-1], "-width") == 0 ) {
slouken@0
   178
			width = atoi(argv[argc]);
slouken@0
   179
			--argc;
slouken@0
   180
		} else
slouken@0
   181
		if ( strcmp(argv[argc-1], "-height") == 0 ) {
slouken@0
   182
			height = atoi(argv[argc]);
slouken@0
   183
			--argc;
slouken@0
   184
		} else
slouken@0
   185
		if ( strcmp(argv[argc-1], "-bpp") == 0 ) {
slouken@0
   186
			video_bpp = atoi(argv[argc]);
slouken@0
   187
			videoflags &= ~SDL_ANYFORMAT;
slouken@0
   188
			--argc;
slouken@0
   189
		} else
slouken@0
   190
		if ( strcmp(argv[argc], "-fast") == 0 ) {
slouken@107
   191
			videoflags = FastestFlags(videoflags, width, height, video_bpp);
slouken@0
   192
		} else
slouken@0
   193
		if ( strcmp(argv[argc], "-hw") == 0 ) {
slouken@0
   194
			videoflags ^= SDL_HWSURFACE;
slouken@0
   195
		} else
slouken@0
   196
		if ( strcmp(argv[argc], "-flip") == 0 ) {
slouken@0
   197
			videoflags ^= SDL_DOUBLEBUF;
slouken@0
   198
		} else
icculus@1214
   199
		if ( strcmp(argv[argc], "-debugflip") == 0 ) {
icculus@1214
   200
			debug_flip ^= 1;
icculus@1214
   201
		} else
slouken@0
   202
		if ( strcmp(argv[argc], "-fullscreen") == 0 ) {
slouken@0
   203
			videoflags ^= SDL_FULLSCREEN;
slouken@0
   204
		} else
slouken@0
   205
		if ( isdigit(argv[argc][0]) ) {
slouken@0
   206
			numsprites = atoi(argv[argc]);
slouken@0
   207
		} else {
slouken@0
   208
			fprintf(stderr, 
slouken@0
   209
	"Usage: %s [-bpp N] [-hw] [-flip] [-fast] [-fullscreen] [numsprites]\n",
slouken@0
   210
								argv[0]);
icculus@1151
   211
			quit(1);
slouken@0
   212
		}
slouken@0
   213
	}
slouken@0
   214
slouken@0
   215
	/* Set video mode */
slouken@0
   216
	screen = SDL_SetVideoMode(width, height, video_bpp, videoflags);
slouken@0
   217
	if ( ! screen ) {
slouken@0
   218
		fprintf(stderr, "Couldn't set %dx%d video mode: %s\n",
slouken@0
   219
					width, height, SDL_GetError());
icculus@1151
   220
		quit(2);
slouken@0
   221
	}
slouken@0
   222
slouken@0
   223
	/* Load the sprite */
slouken@0
   224
	if ( LoadSprite(screen, "icon.bmp") < 0 ) {
icculus@1151
   225
		quit(1);
slouken@0
   226
	}
slouken@0
   227
slouken@0
   228
	/* Allocate memory for the sprite info */
slouken@0
   229
	mem = (Uint8 *)malloc(4*sizeof(SDL_Rect)*numsprites);
slouken@0
   230
	if ( mem == NULL ) {
slouken@0
   231
		SDL_FreeSurface(sprite);
slouken@0
   232
		fprintf(stderr, "Out of memory!\n");
icculus@1151
   233
		quit(2);
slouken@0
   234
	}
slouken@0
   235
	sprite_rects = (SDL_Rect *)mem;
slouken@0
   236
	positions = sprite_rects;
slouken@0
   237
	sprite_rects += numsprites;
slouken@0
   238
	velocities = sprite_rects;
slouken@0
   239
	sprite_rects += numsprites;
slouken@288
   240
	sprite_w = sprite->w;
slouken@288
   241
	sprite_h = sprite->h;
slouken@0
   242
	srand(time(NULL));
slouken@0
   243
	for ( i=0; i<numsprites; ++i ) {
slouken@288
   244
		positions[i].x = rand()%(screen->w - sprite_w);
slouken@288
   245
		positions[i].y = rand()%(screen->h - sprite_h);
slouken@0
   246
		positions[i].w = sprite->w;
slouken@0
   247
		positions[i].h = sprite->h;
slouken@0
   248
		velocities[i].x = 0;
slouken@0
   249
		velocities[i].y = 0;
slouken@0
   250
		while ( ! velocities[i].x && ! velocities[i].y ) {
slouken@0
   251
			velocities[i].x = (rand()%(MAX_SPEED*2+1))-MAX_SPEED;
slouken@0
   252
			velocities[i].y = (rand()%(MAX_SPEED*2+1))-MAX_SPEED;
slouken@0
   253
		}
slouken@0
   254
	}
slouken@0
   255
	background = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
slouken@0
   256
slouken@0
   257
	/* Print out information about our surfaces */
slouken@0
   258
	printf("Screen is at %d bits per pixel\n",screen->format->BitsPerPixel);
slouken@0
   259
	if ( (screen->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
slouken@0
   260
		printf("Screen is in video memory\n");
slouken@0
   261
	} else {
slouken@0
   262
		printf("Screen is in system memory\n");
slouken@0
   263
	}
slouken@0
   264
	if ( (screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
slouken@0
   265
		printf("Screen has double-buffering enabled\n");
slouken@0
   266
	}
slouken@0
   267
	if ( (sprite->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
slouken@0
   268
		printf("Sprite is in video memory\n");
slouken@0
   269
	} else {
slouken@0
   270
		printf("Sprite is in system memory\n");
slouken@0
   271
	}
slouken@0
   272
	/* Run a sample blit to trigger blit acceleration */
slouken@0
   273
	{ SDL_Rect dst;
slouken@0
   274
		dst.x = 0;
slouken@0
   275
		dst.y = 0;
slouken@0
   276
		dst.w = sprite->w;
slouken@0
   277
		dst.h = sprite->h;
slouken@0
   278
		SDL_BlitSurface(sprite, NULL, screen, &dst);
slouken@0
   279
		SDL_FillRect(screen, &dst, background);
slouken@0
   280
	}
slouken@0
   281
	if ( (sprite->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
slouken@0
   282
		printf("Sprite blit uses hardware acceleration\n");
slouken@0
   283
	}
slouken@0
   284
	if ( (sprite->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
slouken@0
   285
		printf("Sprite blit uses RLE acceleration\n");
slouken@0
   286
	}
slouken@0
   287
slouken@0
   288
	/* Loop, blitting sprites and waiting for a keystroke */
slouken@0
   289
	frames = 0;
slouken@0
   290
	then = SDL_GetTicks();
slouken@0
   291
	done = 0;
slouken@0
   292
	sprites_visible = 0;
slouken@0
   293
	while ( !done ) {
slouken@0
   294
		/* Check for events */
slouken@0
   295
		++frames;
slouken@0
   296
		while ( SDL_PollEvent(&event) ) {
slouken@0
   297
			switch (event.type) {
slouken@529
   298
				case SDL_MOUSEBUTTONDOWN:
slouken@529
   299
					SDL_WarpMouse(screen->w/2, screen->h/2);
slouken@529
   300
					break;
slouken@0
   301
				case SDL_KEYDOWN:
slouken@0
   302
					/* Any keypress quits the app... */
slouken@0
   303
				case SDL_QUIT:
slouken@0
   304
					done = 1;
slouken@0
   305
					break;
slouken@0
   306
				default:
slouken@0
   307
					break;
slouken@0
   308
			}
slouken@0
   309
		}
slouken@0
   310
		MoveSprites(screen, background);
slouken@0
   311
	}
slouken@0
   312
	SDL_FreeSurface(sprite);
slouken@0
   313
	free(mem);
slouken@0
   314
slouken@0
   315
	/* Print out some timing information */
slouken@0
   316
	now = SDL_GetTicks();
slouken@0
   317
	if ( now > then ) {
slouken@0
   318
		printf("%2.2f frames per second\n",
slouken@0
   319
					((double)frames*1000)/(now-then));
slouken@0
   320
	}
slouken@288
   321
	SDL_Quit();
slouken@0
   322
	return(0);
slouken@0
   323
}