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