1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 /*
21 ** RW_DIB.C
22 **
23 ** This handles DIB section management under Windows.
24 **
25 */
26 #include "..\ref_soft\r_local.h"
27 #include "rw_win.h"
28 
29 #ifndef _WIN32
30 #  error You should not be trying to compile this file on this platform
31 #endif
32 
33 static qboolean s_systemcolors_saved;
34 
35 static HGDIOBJ previously_selected_GDI_obj;
36 
37 static int s_syspalindices[] =
38 {
39   COLOR_ACTIVEBORDER,
40   COLOR_ACTIVECAPTION,
41   COLOR_APPWORKSPACE,
42   COLOR_BACKGROUND,
43   COLOR_BTNFACE,
44   COLOR_BTNSHADOW,
45   COLOR_BTNTEXT,
46   COLOR_CAPTIONTEXT,
47   COLOR_GRAYTEXT,
48   COLOR_HIGHLIGHT,
49   COLOR_HIGHLIGHTTEXT,
50   COLOR_INACTIVEBORDER,
51 
52   COLOR_INACTIVECAPTION,
53   COLOR_MENU,
54   COLOR_MENUTEXT,
55   COLOR_SCROLLBAR,
56   COLOR_WINDOW,
57   COLOR_WINDOWFRAME,
58   COLOR_WINDOWTEXT
59 };
60 
61 #define NUM_SYS_COLORS ( sizeof( s_syspalindices ) / sizeof( int ) )
62 
63 static int s_oldsyscolors[NUM_SYS_COLORS];
64 
65 typedef struct dibinfo
66 {
67 	BITMAPINFOHEADER	header;
68 	RGBQUAD				acolors[256];
69 } dibinfo_t;
70 
71 typedef struct
72 {
73 	WORD palVersion;
74 	WORD palNumEntries;
75 	PALETTEENTRY palEntries[256];
76 } identitypalette_t;
77 
78 static identitypalette_t s_ipal;
79 
80 static void DIB_SaveSystemColors( void );
81 static void DIB_RestoreSystemColors( void );
82 
83 /*
84 ** DIB_Init
85 **
86 ** Builds our DIB section
87 */
DIB_Init(unsigned char ** ppbuffer,int * ppitch)88 qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch )
89 {
90 	dibinfo_t   dibheader;
91 	BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader;
92 	int i;
93 
94 	memset( &dibheader, 0, sizeof( dibheader ) );
95 
96 	/*
97 	** grab a DC
98 	*/
99 	if ( !sww_state.hDC )
100 	{
101 		if ( ( sww_state.hDC = GetDC( sww_state.hWnd ) ) == NULL )
102 			return false;
103 	}
104 
105 	/*
106 	** figure out if we're running in an 8-bit display mode
107 	*/
108  	if ( GetDeviceCaps( sww_state.hDC, RASTERCAPS ) & RC_PALETTE )
109 	{
110 		sww_state.palettized = true;
111 
112 		// save system colors
113 		if ( !s_systemcolors_saved )
114 		{
115 			DIB_SaveSystemColors();
116 			s_systemcolors_saved = true;
117 		}
118 	}
119 	else
120 	{
121 		sww_state.palettized = false;
122 	}
123 
124 	/*
125 	** fill in the BITMAPINFO struct
126 	*/
127 	pbmiDIB->bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
128 	pbmiDIB->bmiHeader.biWidth         = vid.width;
129 	pbmiDIB->bmiHeader.biHeight        = vid.height;
130 	pbmiDIB->bmiHeader.biPlanes        = 1;
131 	pbmiDIB->bmiHeader.biBitCount      = 8;
132 	pbmiDIB->bmiHeader.biCompression   = BI_RGB;
133 	pbmiDIB->bmiHeader.biSizeImage     = 0;
134 	pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
135 	pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
136 	pbmiDIB->bmiHeader.biClrUsed       = 256;
137 	pbmiDIB->bmiHeader.biClrImportant  = 256;
138 
139 	/*
140 	** fill in the palette
141 	*/
142 	for ( i = 0; i < 256; i++ )
143 	{
144 		dibheader.acolors[i].rgbRed   = ( d_8to24table[i] >> 0 )  & 0xff;
145 		dibheader.acolors[i].rgbGreen = ( d_8to24table[i] >> 8 )  & 0xff;
146 		dibheader.acolors[i].rgbBlue  = ( d_8to24table[i] >> 16 ) & 0xff;
147 	}
148 
149 	/*
150 	** create the DIB section
151 	*/
152 	sww_state.hDIBSection = CreateDIBSection( sww_state.hDC,
153 		                                     pbmiDIB,
154 											 DIB_RGB_COLORS,
155 											 &sww_state.pDIBBase,
156 											 NULL,
157 											 0 );
158 
159 	if ( sww_state.hDIBSection == NULL )
160 	{
161 		ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateDIBSection failed\n" );
162 		goto fail;
163 	}
164 
165 	if ( pbmiDIB->bmiHeader.biHeight > 0 )
166     {
167 		// bottom up
168 		*ppbuffer	= sww_state.pDIBBase + ( vid.height - 1 ) * vid.width;
169 		*ppitch		= -vid.width;
170     }
171     else
172     {
173 		// top down
174 		*ppbuffer	= sww_state.pDIBBase;
175 		*ppitch		= vid.width;
176     }
177 
178 	/*
179 	** clear the DIB memory buffer
180 	*/
181 	memset( sww_state.pDIBBase, 0xff, vid.width * vid.height );
182 
183 	if ( ( sww_state.hdcDIBSection = CreateCompatibleDC( sww_state.hDC ) ) == NULL )
184 	{
185 		ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateCompatibleDC failed\n" );
186 		goto fail;
187 	}
188 	if ( ( previously_selected_GDI_obj = SelectObject( sww_state.hdcDIBSection, sww_state.hDIBSection ) ) == NULL )
189 	{
190 		ri.Con_Printf( PRINT_ALL, "DIB_Init() - SelectObject failed\n" );
191 		goto fail;
192 	}
193 
194 	return true;
195 
196 fail:
197 	DIB_Shutdown();
198 	return false;
199 
200 }
201 
202 /*
203 ** DIB_SetPalette
204 **
205 ** Sets the color table in our DIB section, and also sets the system palette
206 ** into an identity mode if we're running in an 8-bit palettized display mode.
207 **
208 ** The palette is expected to be 1024 bytes, in the format:
209 **
210 ** R = offset 0
211 ** G = offset 1
212 ** B = offset 2
213 ** A = offset 3
214 */
DIB_SetPalette(const unsigned char * _pal)215 void DIB_SetPalette( const unsigned char *_pal )
216 {
217 	const unsigned char *pal = _pal;
218   	LOGPALETTE		*pLogPal = ( LOGPALETTE * ) &s_ipal;
219 	RGBQUAD			colors[256];
220 	int				i;
221 	int				ret;
222 	HDC				hDC = sww_state.hDC;
223 
224 	/*
225 	** set the DIB color table
226 	*/
227 	if ( sww_state.hdcDIBSection )
228 	{
229 		for ( i = 0; i < 256; i++, pal += 4 )
230 		{
231 			colors[i].rgbRed   = pal[0];
232 			colors[i].rgbGreen = pal[1];
233 			colors[i].rgbBlue  = pal[2];
234 			colors[i].rgbReserved = 0;
235 		}
236 
237 		colors[0].rgbRed = 0;
238 		colors[0].rgbGreen = 0;
239 		colors[0].rgbBlue = 0;
240 
241 		colors[255].rgbRed = 0xff;
242 		colors[255].rgbGreen = 0xff;
243 		colors[255].rgbBlue = 0xff;
244 
245 		if ( SetDIBColorTable( sww_state.hdcDIBSection, 0, 256, colors ) == 0 )
246 		{
247 			ri.Con_Printf( PRINT_ALL, "DIB_SetPalette() - SetDIBColorTable failed\n" );
248 		}
249 	}
250 
251 	/*
252 	** for 8-bit color desktop modes we set up the palette for maximum
253 	** speed by going into an identity palette mode.
254 	*/
255 	if ( sww_state.palettized )
256 	{
257 		int i;
258 		HPALETTE hpalOld;
259 
260 		if ( SetSystemPaletteUse( hDC, SYSPAL_NOSTATIC ) == SYSPAL_ERROR )
261 		{
262 			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SetSystemPaletteUse() failed\n" );
263 		}
264 
265 		/*
266 		** destroy our old palette
267 		*/
268 		if ( sww_state.hPal )
269 		{
270 			DeleteObject( sww_state.hPal );
271 			sww_state.hPal = 0;
272 		}
273 
274 		/*
275 		** take up all physical palette entries to flush out anything that's currently
276 		** in the palette
277 		*/
278 		pLogPal->palVersion		= 0x300;
279 		pLogPal->palNumEntries	= 256;
280 
281 		for ( i = 0, pal = _pal; i < 256; i++, pal += 4 )
282 		{
283 			pLogPal->palPalEntry[i].peRed	= pal[0];
284 			pLogPal->palPalEntry[i].peGreen	= pal[1];
285 			pLogPal->palPalEntry[i].peBlue	= pal[2];
286 			pLogPal->palPalEntry[i].peFlags	= PC_RESERVED | PC_NOCOLLAPSE;
287 		}
288 		pLogPal->palPalEntry[0].peRed		= 0;
289 		pLogPal->palPalEntry[0].peGreen		= 0;
290 		pLogPal->palPalEntry[0].peBlue		= 0;
291 		pLogPal->palPalEntry[0].peFlags		= 0;
292 		pLogPal->palPalEntry[255].peRed		= 0xff;
293 		pLogPal->palPalEntry[255].peGreen	= 0xff;
294 		pLogPal->palPalEntry[255].peBlue	= 0xff;
295 		pLogPal->palPalEntry[255].peFlags	= 0;
296 
297 		if ( ( sww_state.hPal = CreatePalette( pLogPal ) ) == NULL )
298 		{
299 			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - CreatePalette failed(%x)\n", GetLastError() );
300 		}
301 
302 		if ( ( hpalOld = SelectPalette( hDC, sww_state.hPal, FALSE ) ) == NULL )
303 		{
304 			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SelectPalette failed(%x)\n",GetLastError() );
305 		}
306 
307 		if ( sww_state.hpalOld == NULL )
308 			sww_state.hpalOld = hpalOld;
309 
310 		if ( ( ret = RealizePalette( hDC ) ) != pLogPal->palNumEntries )
311 		{
312 			ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - RealizePalette set %d entries\n", ret );
313 		}
314 	}
315 }
316 
317 /*
318 ** DIB_Shutdown
319 */
DIB_Shutdown(void)320 void DIB_Shutdown( void )
321 {
322 	if ( sww_state.palettized && s_systemcolors_saved )
323 		DIB_RestoreSystemColors();
324 
325 	if ( sww_state.hPal )
326 	{
327 		DeleteObject( sww_state.hPal );
328 		sww_state.hPal = 0;
329 	}
330 
331 	if ( sww_state.hpalOld )
332 	{
333 		SelectPalette( sww_state.hDC, sww_state.hpalOld, FALSE );
334 		RealizePalette( sww_state.hDC );
335 		sww_state.hpalOld = NULL;
336 	}
337 
338 	if ( sww_state.hdcDIBSection )
339 	{
340 		SelectObject( sww_state.hdcDIBSection, previously_selected_GDI_obj );
341 		DeleteDC( sww_state.hdcDIBSection );
342 		sww_state.hdcDIBSection = NULL;
343 	}
344 
345 	if ( sww_state.hDIBSection )
346 	{
347 		DeleteObject( sww_state.hDIBSection );
348 		sww_state.hDIBSection = NULL;
349 		sww_state.pDIBBase = NULL;
350 	}
351 
352 	if ( sww_state.hDC )
353 	{
354 		ReleaseDC( sww_state.hWnd, sww_state.hDC );
355 		sww_state.hDC = 0;
356 	}
357 }
358 
359 
360 /*
361 ** DIB_Save/RestoreSystemColors
362 */
DIB_RestoreSystemColors(void)363 static void DIB_RestoreSystemColors( void )
364 {
365     SetSystemPaletteUse( sww_state.hDC, SYSPAL_STATIC );
366     SetSysColors( NUM_SYS_COLORS, s_syspalindices, s_oldsyscolors );
367 }
368 
DIB_SaveSystemColors(void)369 static void DIB_SaveSystemColors( void )
370 {
371 	int i;
372 
373 	for ( i = 0; i < NUM_SYS_COLORS; i++ )
374 		s_oldsyscolors[i] = GetSysColor( s_syspalindices[i] );
375 }
376