test/threadwin.c
author Patrice Mandin <patmandin@gmail.com>
Thu, 19 Jan 2006 21:28:52 +0000
changeset 1257 448a9a64537b
parent 1151 be9c9c8f6d53
child 1659 14717b52abc0
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
slouken@0
     2
/* Test out the multi-threaded event handling functions */
slouken@0
     3
slouken@0
     4
#include <stdlib.h>
slouken@0
     5
#include <stdio.h>
slouken@0
     6
#include <string.h>
slouken@0
     7
slouken@0
     8
#include "SDL.h"
slouken@0
     9
#include "SDL_thread.h"
slouken@0
    10
slouken@0
    11
/* Are we done yet? */
slouken@0
    12
static int done = 0;
slouken@0
    13
slouken@0
    14
/* Is the cursor visible? */
slouken@0
    15
static int visible = 1;
slouken@0
    16
icculus@1151
    17
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
icculus@1151
    18
static void quit(int rc)
icculus@1151
    19
{
icculus@1151
    20
	SDL_Quit();
icculus@1151
    21
	exit(rc);
icculus@1151
    22
}
icculus@1151
    23
slouken@0
    24
SDL_Surface *LoadIconSurface(char *file, Uint8 **maskp)
slouken@0
    25
{
slouken@0
    26
	SDL_Surface *icon;
slouken@0
    27
	Uint8       *pixels;
slouken@0
    28
	Uint8       *mask;
slouken@0
    29
	int          mlen, i;
slouken@0
    30
slouken@0
    31
	*maskp = NULL;
slouken@0
    32
slouken@0
    33
	/* Load the icon surface */
slouken@0
    34
	icon = SDL_LoadBMP(file);
slouken@0
    35
	if ( icon == NULL ) {
slouken@0
    36
		fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());
slouken@0
    37
		return(NULL);
slouken@0
    38
	}
slouken@0
    39
slouken@0
    40
	/* Check width and height */
slouken@0
    41
	if ( (icon->w%8) != 0 ) {
slouken@0
    42
		fprintf(stderr, "Icon width must be a multiple of 8!\n");
slouken@0
    43
		SDL_FreeSurface(icon);
slouken@0
    44
		return(NULL);
slouken@0
    45
	}
slouken@0
    46
	if ( icon->format->palette == NULL ) {
slouken@0
    47
		fprintf(stderr, "Icon must have a palette!\n");
slouken@0
    48
		SDL_FreeSurface(icon);
slouken@0
    49
		return(NULL);
slouken@0
    50
	}
slouken@0
    51
slouken@0
    52
	/* Set the colorkey */
slouken@0
    53
	SDL_SetColorKey(icon, SDL_SRCCOLORKEY, *((Uint8 *)icon->pixels));
slouken@0
    54
slouken@0
    55
	/* Create the mask */
slouken@0
    56
	pixels = (Uint8 *)icon->pixels;
slouken@0
    57
	printf("Transparent pixel: (%d,%d,%d)\n",
slouken@0
    58
				icon->format->palette->colors[*pixels].r,
slouken@0
    59
				icon->format->palette->colors[*pixels].g,
slouken@0
    60
				icon->format->palette->colors[*pixels].b);
slouken@0
    61
	mlen = icon->w*icon->h;
slouken@0
    62
	mask = (Uint8 *)malloc(mlen/8);
slouken@0
    63
	if ( mask == NULL ) {
slouken@0
    64
		fprintf(stderr, "Out of memory!\n");
slouken@0
    65
		SDL_FreeSurface(icon);
slouken@0
    66
		return(NULL);
slouken@0
    67
	}
slouken@0
    68
	memset(mask, 0, mlen/8);
slouken@0
    69
	for ( i=0; i<mlen; ) {
slouken@0
    70
		if ( pixels[i] != *pixels )
slouken@0
    71
			mask[i/8] |= 0x01;
slouken@0
    72
		++i;
slouken@0
    73
		if ( (i%8) != 0 )
slouken@0
    74
			mask[i/8] <<= 1;
slouken@0
    75
	}
slouken@0
    76
	*maskp = mask;
slouken@0
    77
	return(icon);
slouken@0
    78
}
slouken@0
    79
slouken@0
    80
int FilterEvents(const SDL_Event *event)
slouken@0
    81
{
slouken@0
    82
	static int reallyquit = 0;
slouken@0
    83
slouken@0
    84
	switch (event->type) {
slouken@0
    85
slouken@0
    86
		case SDL_ACTIVEEVENT:
slouken@0
    87
			/* See what happened */
slouken@0
    88
			printf("App %s ",
slouken@0
    89
				event->active.gain ? "gained" : "lost");
slouken@0
    90
			if ( event->active.state & SDL_APPACTIVE )
slouken@0
    91
				printf("active ");
slouken@0
    92
			if ( event->active.state & SDL_APPMOUSEFOCUS )
slouken@0
    93
				printf("mouse ");
slouken@0
    94
			if ( event->active.state & SDL_APPINPUTFOCUS )
slouken@0
    95
				printf("input ");
slouken@0
    96
			printf("focus\n");
slouken@0
    97
slouken@0
    98
			/* See if we are iconified or restored */
slouken@0
    99
			if ( event->active.state & SDL_APPACTIVE ) {
slouken@0
   100
				printf("App has been %s\n",
slouken@0
   101
					event->active.gain ?
slouken@0
   102
						 "restored" : "iconified");
slouken@0
   103
			}
slouken@0
   104
			return(0);
slouken@0
   105
slouken@0
   106
		/* This is important!  Queue it if we want to quit. */
slouken@0
   107
		case SDL_QUIT:
slouken@0
   108
			if ( ! reallyquit ) {
slouken@0
   109
				reallyquit = 1;
slouken@0
   110
				printf("Quit requested\n");
slouken@0
   111
				return(0);
slouken@0
   112
			}
slouken@0
   113
			printf("Quit demanded\n");
slouken@0
   114
			return(1);
slouken@0
   115
slouken@0
   116
		/* Mouse and keyboard events go to threads */
slouken@0
   117
		case SDL_MOUSEMOTION:
slouken@0
   118
		case SDL_MOUSEBUTTONDOWN:
slouken@0
   119
		case SDL_MOUSEBUTTONUP:
slouken@0
   120
		case SDL_KEYDOWN:
slouken@0
   121
		case SDL_KEYUP:
slouken@0
   122
			return(1);
slouken@0
   123
slouken@0
   124
		/* Drop all other events */
slouken@0
   125
		default:
slouken@0
   126
			return(0);
slouken@0
   127
	}
slouken@0
   128
}
slouken@0
   129
slouken@0
   130
int HandleMouse(void *unused)
slouken@0
   131
{
slouken@0
   132
	SDL_Event events[10];
slouken@0
   133
	int i, found;
slouken@0
   134
	Uint32 mask;
slouken@0
   135
slouken@0
   136
	/* Handle mouse events here */
slouken@0
   137
	mask = (SDL_MOUSEMOTIONMASK|SDL_MOUSEBUTTONDOWNMASK|SDL_MOUSEBUTTONUPMASK);
slouken@0
   138
	while ( ! done ) {
slouken@0
   139
		found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask);
slouken@0
   140
		for ( i=0; i<found; ++i ) {
slouken@0
   141
			switch(events[i].type) {
slouken@0
   142
				/* We want to toggle visibility on buttonpress */
slouken@0
   143
				case SDL_MOUSEBUTTONDOWN:
slouken@0
   144
				case SDL_MOUSEBUTTONUP:
slouken@0
   145
					if ( events[i].button.state == SDL_PRESSED ) {
slouken@0
   146
						visible = !visible;
slouken@0
   147
						SDL_ShowCursor(visible);
slouken@0
   148
					}
slouken@0
   149
					printf("Mouse button %d has been %s\n",
slouken@0
   150
						events[i].button.button,
slouken@0
   151
						(events[i].button.state == SDL_PRESSED) ?
slouken@0
   152
						"pressed" : "released");
slouken@0
   153
					break;
slouken@0
   154
				/* Show relative mouse motion */
slouken@0
   155
				case SDL_MOUSEMOTION:
slouken@0
   156
					printf("Mouse relative motion: {%d,%d}\n",
slouken@0
   157
							events[i].motion.xrel, events[i].motion.yrel);
slouken@0
   158
					break;
slouken@0
   159
			}
slouken@0
   160
		}
slouken@0
   161
		/* Give up some CPU to allow events to arrive */
slouken@0
   162
		SDL_Delay(20);
slouken@0
   163
	}
slouken@0
   164
	return(0);
slouken@0
   165
}
slouken@0
   166
slouken@0
   167
int HandleKeyboard(void *unused)
slouken@0
   168
{
slouken@0
   169
	SDL_Event events[10];
slouken@0
   170
	int i, found;
slouken@0
   171
	Uint32 mask;
slouken@0
   172
slouken@0
   173
	/* Handle mouse events here */
slouken@0
   174
	mask = (SDL_KEYDOWNMASK|SDL_KEYUPMASK);
slouken@0
   175
	while ( ! done ) {
slouken@0
   176
		found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask);
slouken@0
   177
		for ( i=0; i<found; ++i ) {
slouken@0
   178
			switch(events[i].type) {
slouken@0
   179
			    /* We want to toggle visibility on buttonpress */
slouken@0
   180
			    case SDL_KEYDOWN:
slouken@0
   181
			    case SDL_KEYUP:
icculus@562
   182
			    	printf("Key '%c' has been %s\n",
icculus@562
   183
						events[i].key.keysym.unicode,
icculus@562
   184
					(events[i].key.state == SDL_PRESSED) ?
icculus@562
   185
						"pressed" : "released");
icculus@562
   186
slouken@0
   187
			    	/* Allow hitting <ESC> to quit the app */
slouken@0
   188
			    	if ( events[i].key.keysym.sym == SDLK_ESCAPE ) {
slouken@0
   189
			    		done = 1;
slouken@0
   190
			    	}
icculus@562
   191
icculus@562
   192
					/* skip events now that aren't KEYUPs... */
icculus@562
   193
					if (events[i].key.state == SDL_PRESSED)
icculus@562
   194
						break;
icculus@562
   195
icculus@562
   196
			    	if ( events[i].key.keysym.sym == SDLK_f ) {
icculus@562
   197
						int rc = 0;
icculus@562
   198
						printf("attempting to toggle fullscreen...\n");
icculus@562
   199
						rc = SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
icculus@562
   200
                        printf("SDL_WM_ToggleFullScreen returned %d.\n", rc);
icculus@562
   201
			    	}
icculus@562
   202
icculus@562
   203
			    	if ( events[i].key.keysym.sym == SDLK_g ) {
icculus@562
   204
						SDL_GrabMode m;
icculus@562
   205
						m = SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON ?
icculus@562
   206
								SDL_GRAB_OFF : SDL_GRAB_ON;
icculus@562
   207
						printf("attempting to toggle input grab to %s...\n",
icculus@562
   208
                                m == SDL_GRAB_ON ? "ON" : "OFF");
icculus@562
   209
                        SDL_WM_GrabInput(m);
icculus@562
   210
						printf("attempt finished.\n");
icculus@562
   211
			    	}
icculus@562
   212
slouken@0
   213
			    	break;
slouken@0
   214
			}
slouken@0
   215
		}
slouken@0
   216
		/* Give up some CPU to allow events to arrive */
slouken@0
   217
		SDL_Delay(20);
slouken@0
   218
	}
slouken@0
   219
	return(0);
slouken@0
   220
}
slouken@0
   221
slouken@0
   222
int main(int argc, char *argv[])
slouken@0
   223
{
slouken@0
   224
	SDL_Surface *screen;
slouken@0
   225
	SDL_Surface *icon;
slouken@0
   226
	Uint8 *icon_mask;
slouken@0
   227
	int i, parsed;
slouken@0
   228
	Uint8 *buffer;
slouken@0
   229
	SDL_Color palette[256];
slouken@0
   230
	Uint32 init_flags;
slouken@0
   231
	Uint8  video_bpp;
slouken@0
   232
	Uint32 video_flags;
slouken@0
   233
	SDL_Thread *mouse_thread;
slouken@0
   234
	SDL_Thread *keybd_thread;
slouken@0
   235
slouken@0
   236
	/* Set the options, based on command line arguments */
slouken@0
   237
	init_flags = SDL_INIT_VIDEO;
slouken@0
   238
	video_bpp = 8;
slouken@0
   239
	video_flags = SDL_SWSURFACE;
slouken@0
   240
	parsed = 1;
slouken@0
   241
	while ( parsed ) {
slouken@0
   242
		/* If the threaded option is enabled, and the SDL library hasn't
slouken@0
   243
		   been compiled with threaded events enabled, then the mouse and
slouken@0
   244
		   keyboard won't respond.
slouken@0
   245
		 */
slouken@0
   246
		if ( (argc >= 2) && (strcmp(argv[1], "-threaded") == 0) ) {
slouken@0
   247
			init_flags |= SDL_INIT_EVENTTHREAD;
slouken@0
   248
			argc -= 1;
slouken@0
   249
			argv += 1;
slouken@0
   250
			printf("Running with threaded events\n");
slouken@0
   251
		} else
slouken@0
   252
		if ( (argc >= 2) && (strcmp(argv[1], "-fullscreen") == 0) ) {
slouken@0
   253
			video_flags |= SDL_FULLSCREEN;
slouken@0
   254
			argc -= 1;
slouken@0
   255
			argv += 1;
slouken@0
   256
		} else
slouken@0
   257
		if ( (argc >= 3) && (strcmp(argv[1], "-bpp") == 0) ) {
slouken@0
   258
			video_bpp = atoi(argv[2]);
slouken@0
   259
			argc -= 2;
slouken@0
   260
			argv += 2;
slouken@0
   261
		} else {
slouken@0
   262
			parsed = 0;
slouken@0
   263
		}
slouken@0
   264
	}
slouken@0
   265
slouken@0
   266
	/* Initialize SDL with the requested flags */
slouken@0
   267
	if ( SDL_Init(init_flags) < 0 ) {
slouken@0
   268
		fprintf(stderr,
slouken@0
   269
			"Couldn't initialize SDL: %s\n", SDL_GetError());
icculus@1151
   270
		return(1);
slouken@0
   271
	}
slouken@0
   272
slouken@0
   273
	/* Set the icon -- this must be done before the first mode set */
slouken@0
   274
	icon = LoadIconSurface("icon.bmp", &icon_mask);
slouken@0
   275
	if ( icon != NULL ) {
slouken@0
   276
		SDL_WM_SetIcon(icon, icon_mask);
slouken@0
   277
	}
slouken@0
   278
	if ( icon_mask != NULL )
slouken@0
   279
		free(icon_mask);
slouken@0
   280
slouken@0
   281
	/* Initialize the display */
slouken@0
   282
	screen = SDL_SetVideoMode(640, 480, video_bpp, video_flags);
slouken@0
   283
	if (  screen == NULL ) {
slouken@0
   284
		fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n",
slouken@0
   285
						video_bpp, SDL_GetError());
icculus@1151
   286
		quit(1);
slouken@0
   287
	}
slouken@0
   288
	printf("Running in %s mode\n", screen->flags & SDL_FULLSCREEN ?
slouken@0
   289
						"fullscreen" : "windowed");
slouken@0
   290
slouken@0
   291
	/* Enable printable characters */
slouken@0
   292
	SDL_EnableUNICODE(1);
slouken@0
   293
slouken@0
   294
	/* Set an event filter that discards everything but QUIT */
slouken@0
   295
	SDL_SetEventFilter(FilterEvents);
slouken@0
   296
slouken@0
   297
	/* Create the event handling threads */
slouken@0
   298
	mouse_thread = SDL_CreateThread(HandleMouse, NULL);
slouken@0
   299
	keybd_thread = SDL_CreateThread(HandleKeyboard, NULL);
slouken@0
   300
slouken@0
   301
	/* Set the surface pixels and refresh! */
slouken@0
   302
	for ( i=0; i<256; ++i ) {
slouken@0
   303
		palette[i].r = 255-i;
slouken@0
   304
		palette[i].g = 255-i;
slouken@0
   305
		palette[i].b = 255-i;
slouken@0
   306
	}
slouken@0
   307
	SDL_SetColors(screen, palette, 0, 256);
slouken@0
   308
	if ( SDL_LockSurface(screen) < 0 ) {
slouken@0
   309
		fprintf(stderr, "Couldn't lock display surface: %s\n",
slouken@0
   310
							SDL_GetError());
icculus@1151
   311
		quit(2);
slouken@0
   312
	}
slouken@0
   313
	buffer = (Uint8 *)screen->pixels;
slouken@0
   314
	for ( i=0; i<screen->h; ++i ) {
slouken@0
   315
		memset(buffer,(i*255)/screen->h,
slouken@0
   316
				screen->w*screen->format->BytesPerPixel);
slouken@0
   317
		buffer += screen->pitch;
slouken@0
   318
	}
slouken@0
   319
	SDL_UnlockSurface(screen);
slouken@0
   320
	SDL_UpdateRect(screen, 0, 0, 0, 0);
slouken@0
   321
slouken@0
   322
	/* Loop, waiting for QUIT */
slouken@0
   323
	while ( ! done ) {
slouken@0
   324
		if ( ! (init_flags & SDL_INIT_EVENTTHREAD) ) {
slouken@0
   325
			SDL_PumpEvents(); /* Needed when event thread is off */
slouken@0
   326
		}
slouken@0
   327
		if ( SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_QUITMASK) ) {
slouken@0
   328
			done = 1;
slouken@0
   329
		}
slouken@0
   330
		/* Give up some CPU so the events can accumulate */
slouken@0
   331
		SDL_Delay(20);
slouken@0
   332
	}
slouken@0
   333
	SDL_WaitThread(mouse_thread, NULL);
slouken@0
   334
	SDL_WaitThread(keybd_thread, NULL);
icculus@1151
   335
	SDL_Quit();
slouken@0
   336
	return(0);
slouken@0
   337
}