diff src/video/windib/SDL_dibvideo.c @ 3992:c75679dce60c SDL-1.2

Fixed bug #335 Use SetSystemPaletteUse() to get better access to the system palette. We can still do better palette matching in the case where we aren't using fullscreen mode or a hardware palette, but that can wait for another day. :)
author Sam Lantinga <slouken@libsdl.org>
date Tue, 03 Jul 2007 09:05:51 +0000
parents b0d021cf41b6
children 0207ca19fd8f
line wrap: on
line diff
--- a/src/video/windib/SDL_dibvideo.c	Mon Jul 02 02:45:52 2007 +0000
+++ b/src/video/windib/SDL_dibvideo.c	Tue Jul 03 09:05:51 2007 +0000
@@ -87,6 +87,9 @@
 static void DIB_FreeHWSurface(_THIS, SDL_Surface *surface);
 
 /* Windows message handling functions */
+static void DIB_GrabStaticColors(HWND window);
+static void DIB_ReleaseStaticColors(HWND window);
+static void DIB_Activate(_THIS, BOOL active, BOOL minimized);
 static void DIB_RealizePalette(_THIS);
 static void DIB_PaletteChanged(_THIS, HWND window);
 static void DIB_WinPAINT(_THIS, HDC hdc);
@@ -176,6 +179,7 @@
 	device->PumpEvents = DIB_PumpEvents;
 
 	/* Set up the windows message handling functions */
+	WIN_Activate = DIB_Activate;
 	WIN_RealizePalette = DIB_RealizePalette;
 	WIN_PaletteChanged = DIB_PaletteChanged;
 	WIN_WinPAINT = DIB_WinPAINT;
@@ -248,36 +252,25 @@
 	return(0);
 }
 
-static HPALETTE DIB_CreatePalette(int bpp)
+static void DIB_CreatePalette(_THIS, int bpp)
 {
 /*	RJR: March 28, 2000
 	moved palette creation here from "DIB_VideoInit" */
 
-	HPALETTE handle = NULL;
-	
-	if ( bpp <= 8 )
-	{
-		LOGPALETTE *palette;
-		HDC hdc;
-		int ncolors;
-		int i;
+	LOGPALETTE *palette;
+	HDC hdc;
+	int ncolors;
 
-		ncolors = 1;
-		for ( i=0; i<bpp; ++i ) {
-			ncolors *= 2;
-		}
-		palette = (LOGPALETTE *)SDL_malloc(sizeof(*palette)+
-					ncolors*sizeof(PALETTEENTRY));
-		palette->palVersion = 0x300;
-		palette->palNumEntries = ncolors;
-		hdc = GetDC(SDL_Window);
-		GetSystemPaletteEntries(hdc, 0, ncolors, palette->palPalEntry);
-		ReleaseDC(SDL_Window, hdc);
-		handle = CreatePalette(palette);
-		SDL_free(palette);
-	}
-	
-	return handle;
+	ncolors = (1 << bpp);
+	palette = (LOGPALETTE *)SDL_malloc(sizeof(*palette)+
+				ncolors*sizeof(PALETTEENTRY));
+	palette->palVersion = 0x300;
+	palette->palNumEntries = ncolors;
+	hdc = GetDC(SDL_Window);
+	GetSystemPaletteEntries(hdc, 0, ncolors, palette->palPalEntry);
+	ReleaseDC(SDL_Window, hdc);
+	screen_pal = CreatePalette(palette);
+	screen_logpal = palette;
 }
 
 int DIB_VideoInit(_THIS, SDL_PixelFormat *vformat)
@@ -371,7 +364,7 @@
 	if ( vformat->BitsPerPixel <= 8 ) {
 	/*	RJR: March 28, 2000
 		moved palette creation to "DIB_CreatePalette" */
-		screen_pal = DIB_CreatePalette(vformat->BitsPerPixel);
+		DIB_CreatePalette(this, vformat->BitsPerPixel);
 	}
 
 	/* Fill in some window manager capabilities */
@@ -645,16 +638,23 @@
 
 	/* Reset the palette and create a new one if necessary */
 	if ( screen_pal != NULL ) {
+		if ( video->flags & SDL_HWPALETTE ) {
+			DIB_ReleaseStaticColors(SDL_Window);
+		}
 	/*	RJR: March 28, 2000
 		delete identity palette if switching from a palettized mode */
 		DeleteObject(screen_pal);
 		screen_pal = NULL;
 	}
+	if ( screen_logpal != NULL ) {
+		SDL_free(screen_logpal);
+		screen_logpal = NULL;
+	}
 	if ( bpp <= 8 )
 	{
 	/*	RJR: March 28, 2000
 		create identity palette switching to a palettized mode */
-		screen_pal = DIB_CreatePalette(bpp);
+		DIB_CreatePalette(this, bpp);
 	}
 
 	style = GetWindowLong(SDL_Window, GWL_STYLE);
@@ -755,12 +755,7 @@
 		this->UpdateRects = DIB_NormalUpdate;
 
 		/* Set video surface flags */
-		if ( bpp <= 8 ) {
-			if ( (video->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
-				hdc = GetDC(SDL_Window);
-				SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
-				ReleaseDC(SDL_Window, hdc);
-			}
+		if ( (flags & (SDL_FULLSCREEN|SDL_HWPALETTE)) != 0 ) {
 			/* BitBlt() maps colors for us */
 			video->flags |= SDL_HWPALETTE;
 		}
@@ -885,6 +880,41 @@
 	ReleaseDC(SDL_Window, hdc);
 }
 
+static int FindPaletteIndex(LOGPALETTE *pal, BYTE r, BYTE g, BYTE b)
+{
+	PALETTEENTRY *entry;
+	int i;
+	int nentries = pal->palNumEntries;
+
+	for ( i = 0; i < nentries; ++i ) {
+		entry = &pal->palPalEntry[i];
+		if ( entry->peRed == r && entry->peGreen == g && entry->peBlue == b ) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+static BOOL CheckPaletteEntry(LOGPALETTE *pal, int index, BYTE r, BYTE g, BYTE b)
+{
+	PALETTEENTRY *entry;
+	BOOL moved = 0;
+
+	entry = &pal->palPalEntry[index];
+	if ( entry->peRed != r || entry->peGreen != g || entry->peBlue != b ) {
+		int found = FindPaletteIndex(pal, r, g, b);
+		if ( found >= 0 ) {
+			pal->palPalEntry[found] = *entry;
+		}
+		entry->peRed = r;
+		entry->peGreen = g;
+		entry->peBlue = b;
+		moved = 1;
+	}
+	entry->peFlags = 0;
+
+	return moved;
+}
 
 int DIB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
 {
@@ -895,23 +925,37 @@
 	HDC hdc;
 #endif
 	int i;
+	int moved_entries = 0;
 
 	/* Update the display palette */
 	hdc = GetDC(SDL_Window);
 	if ( screen_pal ) {
-		PALETTEENTRY *entries;
+		PALETTEENTRY *entry;
 
-		entries = SDL_stack_alloc(PALETTEENTRY, ncolors);
 		for ( i=0; i<ncolors; ++i ) {
-			entries[i].peRed   = colors[i].r;
-			entries[i].peGreen = colors[i].g;
-			entries[i].peBlue  = colors[i].b;
-			entries[i].peFlags = PC_NOCOLLAPSE;
+			entry = &screen_logpal->palPalEntry[firstcolor+i];
+			entry->peRed   = colors[i].r;
+			entry->peGreen = colors[i].g;
+			entry->peBlue  = colors[i].b;
+			entry->peFlags = PC_NOCOLLAPSE;
+		}
+		/* Check to make sure black and white are in position */
+		if ( GetSystemPaletteUse(hdc) != SYSPAL_NOSTATIC256 ) {
+			moved_entries += CheckPaletteEntry(screen_logpal, 0, 0x00, 0x00, 0x00);
+			moved_entries += CheckPaletteEntry(screen_logpal, screen_logpal->palNumEntries-1, 0xff, 0xff, 0xff);
 		}
-		SetPaletteEntries(screen_pal, firstcolor, ncolors, entries);
+		/* FIXME:
+		   If we don't have full access to the palette, what we
+		   really want to do is find the 236 most diverse colors
+		   in the desired palette, set those entries (10-245) and
+		   then map everything into the new system palette.
+		 */
+
+		/* Copy the entries into the system palette */
+		UnrealizeObject(screen_pal);
+		SetPaletteEntries(screen_pal, 0, screen_logpal->palNumEntries, screen_logpal->palPalEntry);
 		SelectPalette(hdc, screen_pal, FALSE);
 		RealizePalette(hdc);
-		SDL_stack_free(entries);
 	}
 
 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
@@ -928,8 +972,10 @@
 	mdc = CreateCompatibleDC(hdc);
 	SelectObject(mdc, screen_bmp);
 	SetDIBColorTable(mdc, firstcolor, ncolors, pal);
-	BitBlt(hdc, 0, 0, this->screen->w, this->screen->h,
-	       mdc, 0, 0, SRCCOPY);
+	if ( moved_entries || !(this->screen->flags & SDL_HWPALETTE) ) {
+		BitBlt(hdc, 0, 0, this->screen->w, this->screen->h,
+		       mdc, 0, 0, SRCCOPY);
+	}
 	DeleteDC(mdc);
 	SDL_stack_free(pal);
 #endif
@@ -1048,6 +1094,9 @@
 	if ( SDL_Window ) {
 		/* Delete the screen bitmap (also frees screen->pixels) */
 		if ( this->screen ) {
+			if ( this->screen->flags & SDL_HWPALETTE ) {
+				DIB_ReleaseStaticColors(SDL_Window);
+			}
 #ifndef NO_CHANGEDISPLAYSETTINGS
 			if ( this->screen->flags & SDL_FULLSCREEN ) {
 				ChangeDisplaySettings(NULL, 0);
@@ -1059,6 +1108,14 @@
 			}
 			this->screen->pixels = NULL;
 		}
+		if ( screen_pal != NULL ) {
+			DeleteObject(screen_pal);
+			screen_pal = NULL;
+		}
+		if ( screen_logpal != NULL ) {
+			SDL_free(screen_logpal);
+			screen_logpal = NULL;
+		}
 		if ( screen_bmp ) {
 			DeleteObject(screen_bmp);
 			screen_bmp = NULL;
@@ -1097,26 +1154,55 @@
 }
 
 /* Exported for the windows message loop only */
-static void DIB_FocusPalette(_THIS, int foreground)
+static void DIB_GrabStaticColors(HWND window)
+{
+	HDC hdc;
+
+	hdc = GetDC(window);
+	SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC256);
+	if ( GetSystemPaletteUse(hdc) != SYSPAL_NOSTATIC256 ) {
+		SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
+	}
+	ReleaseDC(window, hdc);
+}
+static void DIB_ReleaseStaticColors(HWND window)
+{
+	HDC hdc;
+
+	hdc = GetDC(window);
+	SetSystemPaletteUse(hdc, SYSPAL_STATIC);
+	ReleaseDC(window, hdc);
+}
+static void DIB_Activate(_THIS, BOOL active, BOOL minimized)
+{
+	if ( screen_pal && (this->screen->flags & SDL_HWPALETTE) ) {
+		if ( !active ) {
+			DIB_ReleaseStaticColors(SDL_Window);
+			DIB_RealizePalette(this);
+		} else if ( !minimized ) {
+			DIB_GrabStaticColors(SDL_Window);
+			DIB_RealizePalette(this);
+		}
+	}
+}
+static void DIB_RealizePalette(_THIS)
 {
 	if ( screen_pal != NULL ) {
 		HDC hdc;
 
 		hdc = GetDC(SDL_Window);
+		UnrealizeObject(screen_pal);
 		SelectPalette(hdc, screen_pal, FALSE);
-		if ( RealizePalette(hdc) )
+		if ( RealizePalette(hdc) ) {
 			InvalidateRect(SDL_Window, NULL, FALSE);
+		}
 		ReleaseDC(SDL_Window, hdc);
 	}
 }
-static void DIB_RealizePalette(_THIS)
-{
-	DIB_FocusPalette(this, 1);
-}
 static void DIB_PaletteChanged(_THIS, HWND window)
 {
 	if ( window != SDL_Window ) {
-		DIB_FocusPalette(this, 0);
+		DIB_RealizePalette(this);
 	}
 }