1 /*
2  * Copyright (C) 1997-2005, R3vis Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18  *
19  * Original Contributor:
20  *   Wes Bethel, R3vis Corporation, Marin County, California
21  * Additional Contributor(s):
22  *
23  * The OpenRM project is located at http://openrm.sourceforge.net/.
24  */
25 /*
26  * $Id: rmwin.c,v 1.12 2005/09/12 04:03:51 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.12 $
29  * $Log: rmwin.c,v $
30  * Revision 1.12  2005/09/12 04:03:51  wes
31  * Minor documentation updates.
32  *
33  * Revision 1.11  2005/06/09 00:45:29  wes
34  * More compiler warning fixes turned up by Windows build.
35  *
36  * Revision 1.10  2005/02/19 16:40:20  wes
37  * Distro sync and consolidation.
38  * Repairs to fix memory leak associated with repeated calls to rmPipeNew,
39  * rmPipeMakeCurrent, rmPipeClose.
40  *
41  * Revision 1.9  2005/01/23 17:00:22  wes
42  * Copyright updated to 2005.
43  *
44  * Revision 1.8  2004/01/16 16:49:50  wes
45  * Updated copyright line for 2004.
46  *
47  * Revision 1.7  2003/10/03 19:19:07  wes
48  * Migrate away from platform-specific interfaces to the OpenGL context,
49  * and use a single interface: rmPipeSet/GetContext.
50  *
51  * Revision 1.6  2003/07/23 13:32:28  wes
52  * Win32: problems with offscreen rendering appeared with new context
53  * initialization code sequence (1.5.0). Minor repairs needed to fix the bug.
54  *
55  * Revision 1.5  2003/03/16 21:56:16  wes
56  * Documentation updates.
57  *
58  * Revision 1.4  2003/02/17 17:36:02  wes
59  * Mods to fix Win32 compile problems.
60  *
61  * Revision 1.3  2003/02/02 02:07:16  wes
62  * Updated copyright to 2003.
63  *
64  * Revision 1.2  2003/02/01 17:56:15  wes
65  * Win32 code work to reflect new RMpipe initialization sequence.
66  *
67  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
68  * Manual rebuild of rm150 repository.
69  *
70  * Revision 1.11  2003/01/16 22:21:17  wes
71  * Updated all source files to reflect new organization of header files:
72  * all header files formerly located in include/rmaux, include/rmi, include/rmv
73  * are now located in include/rm.
74  *
75  * Revision 1.10  2002/12/31 00:55:22  wes
76  *
77  * Various enhancements to support Chromium - achitecture-specific sections
78  * of RMpipe were cleaned up, etc.
79  *
80  * Revision 1.9  2002/04/30 19:37:09  wes
81  * Updated copyright dates.
82  *
83  * Revision 1.8  2001/10/15 00:14:28  wes
84  * New routine: rmPipeSetOffscreenWindow() added to ensure consistency
85  * between Win32 and X11 APIs.
86  *
87  * Revision 1.7  2001/03/31 17:12:39  wes
88  * v1.4.0-alpha-2 checkin.
89  *
90  * Revision 1.6  2000/12/03 22:33:55  wes
91  * Mods for thread-safety.
92  *
93  * Revision 1.5  2000/08/23 23:33:14  wes
94  * Moved private_rmInitQuadrics to rmPipeSetWindow. Context-specific
95  * display lists are built when a window is assigned to a pipe, and
96  * there's no already-initialized OpenGL rendering context.
97  *
98  * Revision 1.4  2000/05/14 23:37:11  wes
99  * Added control via RMpipe attribute to how OpenGL matrix stack
100  * is initialized or used during rendering.
101  *
102  * Revision 1.3  2000/04/20 16:29:47  wes
103  * Documentation additions/enhancements, some code rearragement.
104  *
105  * Revision 1.2  2000/03/02 23:46:05  wes
106  * rmPipeSetWindow (win32), fix for hRC not assigned.
107  *
108  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
109  * OpenRM 1.2 Checkin
110  *
111  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
112  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
113  *
114  */
115 
116 #include <rm/rm.h>
117 #include "rmprivat.h"
118 
119 
120 
121 #ifdef RM_WIN
122 
123 static RMpipe *win_current_pipe=NULL;
124 
125 /* temp until we get uniform event handling working */
126 static float q1[4],q2[4];
127 static float x1,yy1,x2,y2;
128 static float xscale_delta,yscale_delta;
129 
130 static RMnode *save_obj=NULL;
131 static RMmatrix save_matrix;
132 
pixeltovp(int ipixel,int idim)133 static float pixeltovp(int ipixel, int idim)
134 {
135     float t;
136     t = (float)(ipixel - (idim>>1)) / (float)(idim >> 1);
137     return(t);
138 }
139 
140 RMenum
rmPipeSwapBuffersWin32(const RMpipe * p)141 rmPipeSwapBuffersWin32(const RMpipe *p)
142 {
143    glFlush();
144    glFinish();
145    SwapBuffers(p->hdc);
146    return RM_CHILL;
147 }
148 
149 HWND
rmPipeGetWindow(RMpipe * p)150 rmPipeGetWindow(RMpipe *p)
151 {
152    return(p->hwnd);
153 }
154 
155 /*
156  * ----------------------------------------------------
157  * @Name rmPipeSetContext (Win32)
158  @pstart
159  RMenum rmPipeSetContext (RMpipe *toUse,
160 		          HGLRC theContext)
161  @pend
162 
163  @astart
164  RMpipe *toUse - a handle to an RMpipe object (input, but not const).
165 
166  HGLRC theContext - a valid to a Windows OpenGL context (created by
167  wglCreateContext, or obtained by some other nefarious means).
168 
169  @aend
170 
171  @dstart
172 
173  Returns the current Windows OpenGL associated with an RMpipe object upon
174  success.  A return value of NULL is returned if there is a problem.
175 
176  Note that the OpenGL returned by this routine is not necessarily
177  "active" unless this call is made after the RMpipe is "made current"
178  by using rmPipeMakeCurrent.
179 
180  @dend
181  * ----------------------------------------------------
182  */
183 HGLRC
rmPipeGetContext(const RMpipe * p)184 rmPipeGetContext(const RMpipe *p)
185 {
186     if (RM_ASSERT(p, "rmPipeGetContext [Win32 version] error: the input RMpipe is NULL") == RM_WHACKED)
187 	return NULL;
188     return p->hRC;
189 }
190 
191 /*
192  * ----------------------------------------------------
193  * @Name rmPipeSetContext (Win32)
194  @pstart
195  RMenum rmPipeSetContext (RMpipe *toUse,
196 		          HGLRC theContext)
197  @pend
198 
199  @astart
200  RMpipe *toUse - a handle to an RMpipe object (input, but not const).
201 
202  HGLRC theContext - a valid to a Windows OpenGL context (created by
203  wglCreateContext, or obtained by some other nefarious means).
204 
205  @aend
206 
207  @dstart
208 
209  Use this routine to assign a Windows OpenGL rendering context to an
210  RMpipe. Inside this routine, the input context "theContext" is copied
211  into a field internal to the RMpipe object. This routine would be used,
212  for example, to obtain an OpenGL context from your application (e.g., some
213  FLTK infrastructure) and to tell OpenRM to use it for subsequent rendering.
214 
215  Since this routine only makes a copy of the context, you need to "make
216  it current" with a call to rmPipeMakeCurrent *after* you call
217  rmPipeSetContext.
218 
219  This routine will return RM_WHACKED if the input RMpipe is NULL. Otherwise,
220  it returns RM_CHILL. No error checking is performed on the input
221  Windows OpenGL context.
222 
223  @dend
224  * ----------------------------------------------------
225  */
226 RMenum
rmPipeSetContext(RMpipe * p,HGLRC theContext)227 rmPipeSetContext(RMpipe *p,
228 		 HGLRC theContext)
229 {
230     if (RM_ASSERT(p, "rmPipeSetContext [Win32 version] error: the input RMpipe is NULL") == RM_WHACKED)
231 	return(RM_WHACKED);
232    p->hRC = theContext;
233    return RM_CHILL;
234 }
235 
236 /*
237  * ----------------------------------------------------
238  * @Name rmPipeSetWindow (Win32)
239  @pstart
240  RMenum rmPipeSetWindow (RMpipe *toUse,
241 		         HWND window,
242 			 int windowWidth,
243 			 int windowHeight)
244  @pend
245 
246  @astart
247  RMpipe *toUse - a handle to an RMpipe object (input, but not const).
248 
249  HWND window - a valid Win32 window handle (input).
250 
251  int windowWidth, int windowHeight - integer values specifying the
252     pixel width & height of the window "w".
253  @aend
254 
255  @dstart
256 
257  Use this routine to "bind" an X11 Window to an RMpipe. When this
258  routine is called, the RMpipe's window attribute is set to the value
259  specified by theWindow parameter, and the RMpipe's window pixel dimension
260  attributes are set.
261 
262  Note that there are no event callbacks associated with the RMpipe: when the
263  window geometry changes (size, etc) it is the responsibility of the
264  application to inform RM that the window geometry has changed
265  (rmPipeSetWindowSize). There are separate versions of this routine
266  for Win32 and X.
267 
268  To assign an offscreen rendering area to the RMpipe, use the routine
269  rmPipeSetOffscreenWindow() rather than rmPipeSetWindow().
270 
271  Win32 notes: in addition to setting the window handle and size attributes,
272  this routine also grabs the DC associated with the window, and stores the
273  DC in a field in the RMpipe structure.
274 
275  This routine returns RM_CHILL upon success, or RM_WHACKED upon failure.
276 
277  @dend
278  * ----------------------------------------------------
279  */
280 RMenum
rmPipeSetWindow(RMpipe * p,HWND hWnd,int width,int height)281 rmPipeSetWindow(RMpipe *p,
282 		HWND hWnd,
283 		int width,
284 		int height)
285 {
286     if (RM_ASSERT(p, "rmPipeSetWindow [Win32 version] error: the input RMpipe is NULL") == RM_WHACKED)
287 	return(RM_WHACKED);
288 
289     if (hWnd == 0)
290     {
291 	if ((p->hwnd != NULL) && (p->hdc != NULL))
292 	    ReleaseDC(p->hwnd, p->hdc);
293 	p->hdc = 0;
294 	p->hwnd = 0;
295     }
296     else
297     {
298 	p->hwnd = hWnd;
299 
300 	if (p->offscreen != RM_TRUE)
301 	    p->hdc = GetDC(hWnd);
302     }
303 
304     if (p->offscreen != RM_TRUE)
305 	p->hdc = GetDC(hWnd);
306     rmPipeSetWindowSize(p,width,height);
307     return RM_CHILL;
308 }
309 
310 /*
311  * ----------------------------------------------------
312  * @Name rmPipeSetOffscreenWindow (Win32)
313  @pstart
314  int rmPipeSetOffscreenWindow (RMpipe *toUse,
315 		               HWND window,
316 		               int windowWidth,
317 		               int windowHeight)
318  @pend
319 
320  @astart
321  RMpipe *toUse - a handle to an RMpipe object (input, but not const).
322 
323  HWND window - a valid Win32 window handle (input).
324 
325  int windowWidth, int windowHeight - integer values specifying the
326     pixel width & height of the window "w".
327  @aend
328 
329  @dstart
330 
331  Use this routine to "bind" a Win32 HWND window to an RMpipe. When this
332  routine is called, a number of things happen:
333 
334  1. The RMpipe's notion of the window size is set
335  (rmPipeSetWindowSize).
336 
337  2. The OpenGL context contained within the RMpipe is made current.
338 
339  3. Final internal initialization within RM on the RMpipe's OpenGL context
340  is performed, readying both RM and OpenGL for use.
341 
342  After this call succeeds, on X11 systems is is safe to begin making
343  raw OpenGL calls. Note that things work a bit differently in Win32.
344  See rmauxSetInitFunc().
345 
346  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
347 
348  This routine should be used by all applications to activate an OpenGL
349  context and to bind a window to the RMpipe.
350 
351  Note that there are no event callbacks associated with the RMpipe: when the
352  window geometry changes (size, etc) it is the responsibility of the
353  application to inform RM that the window geometry has changed
354  (rmPipeSetWindowSize). There are separate versions of this routine
355  for Win32 and X.
356 
357  On Win32, there is no distinction between an onscreen and offscreen
358  window. The routine rmPipeSetOffscreenWindow() is present to provide
359  API compatibility between X and Win32. Internally, this routine simply
360  makes a call to rmPipeSetWindow().
361 
362  @dend
363  * ----------------------------------------------------
364  */
365 void
rmPipeSetOffscreenWindow(RMpipe * p,HWND hWnd,int width,int height)366 rmPipeSetOffscreenWindow(RMpipe *p,
367 			 HWND hWnd,
368 			 int width,
369 			 int height)
370 {
371     rmPipeSetWindow(p, hWnd, width, height);
372 }
373 
374 /* PRIVATE */
375 RMenum
rmwPipeCreateContext(RMpipe * p)376 rmwPipeCreateContext(RMpipe *p)
377 {
378     HGLRC theContext;
379     HDC deviceContext;
380     RMenum rstat;
381     RMenum stereoFormatBool;
382 
383     if (p->hwnd == NULL)
384     {
385 	rmError("rmwPipeCreateContext() error: creation of an OpenGL context on windows requires that you first create a window and assign it to the RMpipe using rmPipeSetWindow. This is different from how it works on X systems where you need to create the context prior to creating the window.");
386 	return RM_WHACKED;
387     }
388 
389     deviceContext = GetDC(p->hwnd);
390 
391     if (deviceContext == NULL)
392     {
393 	rmError("rmwPipeCreateContext() error: the deviceContext for the RMpipe's window is NULL. This is bad.");
394 	return RM_WHACKED;
395     }
396 
397     /* if the format is offscreen, create a DIB */
398     if (private_rmPipeIsOffscreenFormat(p))
399     {
400 	int w, h;
401 	p->hdc = deviceContext = CreateCompatibleDC(deviceContext);
402 	rmPipeGetWindowSize(p, &w, &h);
403 	private_rmwSetupDIB(deviceContext, w, h, 16);
404     }
405 
406     if (rmPipeGetChannelFormat(p) == RM_MBUF_STEREO_CHANNEL)
407 	stereoFormatBool = RM_TRUE;
408     else
409 	stereoFormatBool = RM_FALSE;
410 
411     /* win32 stereo code not tested. 1/31/03 - wes */
412     private_rmwSetupPixelFormat(deviceContext, 16,
413 				private_rmPipeIsOffscreenFormat(p),
414 				stereoFormatBool);
415     /* 16 bit zbuffer? */
416 
417     private_rmwSetupPalette(deviceContext);
418 
419     theContext = wglCreateContext(deviceContext);
420     p->hRC = theContext;
421     if (theContext != NULL)
422 	rstat = RM_CHILL;
423     else
424 	rstat = RM_WHACKED;
425 
426     return rstat;
427 }
428 
429 /* PRIVATE */
430 void
private_rmwSetupDIB(HDC hDC,int width,int height,int depth)431 private_rmwSetupDIB(HDC hDC,
432 		    int width,
433 		    int height,
434 		    int depth)
435 {
436     BITMAPINFO *bmInfo;
437     BITMAPINFOHEADER *bmHeader;
438     UINT usage;
439     VOID *base;
440     int bmiSize;
441     int bitsPerPixel;
442     HBITMAP hBitmap, hOldBitmap;
443 
444     bmiSize = sizeof(*bmInfo);
445     bitsPerPixel = GetDeviceCaps(hDC, BITSPIXEL);
446 
447     switch (bitsPerPixel) {
448     case 8:
449 	/* bmiColors is 256 WORD palette indices */
450 	bmiSize += (256 * sizeof(WORD)) - sizeof(RGBQUAD);
451 	break;
452     case 16:
453 	/* bmiColors is 3 WORD component masks */
454 	bmiSize += (3 * sizeof(DWORD)) - sizeof(RGBQUAD);
455 	break;
456     case 24:
457     case 32:
458     default:
459 	/* bmiColors not used */
460 	break;
461     }
462 
463     bmInfo = (BITMAPINFO *) calloc(1, bmiSize);
464     bmHeader = &bmInfo->bmiHeader;
465 
466     bmHeader->biSize = sizeof(*bmHeader);
467     bmHeader->biWidth = width,
468     bmHeader->biHeight = height,
469     bmHeader->biPlanes = 1;			/* must be 1 */
470     bmHeader->biBitCount = bitsPerPixel;
471     bmHeader->biXPelsPerMeter = 0;
472     bmHeader->biYPelsPerMeter = 0;
473     bmHeader->biClrUsed = 0;			/* all are used */
474     bmHeader->biClrImportant = 0;		/* all are important */
475 
476     switch (bitsPerPixel) {
477     case 8:
478 	bmHeader->biCompression = BI_RGB;
479 	bmHeader->biSizeImage = 0;
480 	usage = DIB_PAL_COLORS;
481 	/* bmiColors is 256 WORD palette indices */
482 	{
483 	    WORD *palIndex = (WORD *) &bmInfo->bmiColors[0];
484 	    int i;
485 
486 	    for (i=0; i<256; i++) {
487 		palIndex[i] = i;
488 	    }
489 	}
490 	break;
491     case 16:
492 	bmHeader->biCompression = BI_RGB;
493 	bmHeader->biSizeImage = 0;
494 	usage = DIB_RGB_COLORS;
495 	/* bmiColors is 3 WORD component masks */
496 	{
497 	    DWORD *compMask = (DWORD *) &bmInfo->bmiColors[0];
498 
499 	    compMask[0] = 0xF800;
500 	    compMask[1] = 0x07E0;
501 	    compMask[2] = 0x001F;
502 	}
503 	break;
504     case 24:
505     case 32:
506     default:
507 	bmHeader->biCompression = BI_RGB;
508 	bmHeader->biSizeImage = 0;
509 	usage = DIB_RGB_COLORS;
510 	/* bmiColors not used */
511 	break;
512     }
513 
514     hBitmap = CreateDIBSection(hDC, bmInfo, usage, &base, NULL, 0);
515     if (hBitmap == NULL) {
516 	(void) MessageBox(WindowFromDC(hDC),
517 		"Failed to create DIBSection.",
518 		"OpenGL application error",
519 		MB_ICONERROR | MB_OK);
520 	exit(1);
521     }
522 
523     hOldBitmap = SelectObject(hDC, hBitmap);
524 
525     free(bmInfo);
526 }
527 
528 /* PRIVATE */
529 void
private_rmwSetupPixelFormat(HDC hDC,int depth,int offscreenBool,RMenum stereoFormatBool)530 private_rmwSetupPixelFormat(HDC hDC,
531 			    int depth,
532 			    int offscreenBool,
533 			    RMenum stereoFormatBool)
534 {
535     PIXELFORMATDESCRIPTOR pfd = {
536 	sizeof(PIXELFORMATDESCRIPTOR),	/* size of this pfd */
537 	1,				/* version num */
538 	PFD_SUPPORT_OPENGL,		/* support OpenGL */
539 	0,				/* pixel type */
540 	0,				/* 8-bit color depth */
541 	0, 0, 0, 0, 0, 0,		/* color bits (ignored) */
542 	0,				/* no alpha buffer */
543 	0,				/* alpha bits (ignored) */
544 	0,				/* no accumulation buffer */
545 	0, 0, 0, 0,			/* accum bits (ignored) */
546 	16,				/* depth buffer */
547 	0,				/* no stencil buffer */
548 	0,				/* no auxiliary buffers */
549 	PFD_MAIN_PLANE,			/* main layer */
550 	0,				/* reserved */
551 	0, 0, 0,			/* no layer, visible, damage masks */
552     };
553     int SelectedPixelFormat;
554     BOOL retVal;
555 
556     pfd.cDepthBits = depth;
557 
558     /* which of the following two lines of code is correct? */
559     pfd.cColorBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
560 /*    pfd.cColorBits = GetDeviceCaps(hDC, BITSPIXEL); */
561     pfd.cDepthBits = pfd.cColorBits;
562     pfd.iPixelType = PFD_TYPE_RGBA;
563 
564 #if 0
565     {
566 	char buf[128];
567 	sprintf(buf," bits/pixel=%d, planes=%d, cColorBits=%d \n",GetDeviceCaps(hDC,BITSPIXEL), GetDeviceCaps(hDC,PLANES), pfd.cColorBits);
568 	rmWarning(buf);
569     }
570 #endif
571 
572     if (offscreenBool)
573     {
574 	pfd.dwFlags |= PFD_DRAW_TO_BITMAP;
575     }
576     else
577     {
578 	pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
579         pfd.dwFlags |= PFD_DOUBLEBUFFER;
580         pfd.dwFlags |= PFD_GENERIC_ACCELERATED;
581 
582 	if (stereoFormatBool == RM_TRUE)
583 	    pfd.dwFlags |= PFD_STEREO;
584 
585     }
586 
587     SelectedPixelFormat = ChoosePixelFormat(hDC, &pfd);
588     if (SelectedPixelFormat == 0) {
589 	(void) MessageBox(WindowFromDC(hDC),
590 		"Failed to find acceptable pixel format.",
591 		"OpenGL application error",
592 		MB_ICONERROR | MB_OK);
593 	exit(1);
594     }
595 
596     retVal = SetPixelFormat(hDC, SelectedPixelFormat, &pfd);
597     if (retVal != TRUE) {
598 	(void) MessageBox(WindowFromDC(hDC),
599 		"Failed to set pixel format.",
600 		"OpenGL application error",
601 		MB_ICONERROR | MB_OK);
602 	exit(1);
603     }
604 }
605 
606 /* PRIVATE */
607 void
private_rmwSetupPalette(HDC hDC)608 private_rmwSetupPalette(HDC hDC)
609 {
610     PIXELFORMATDESCRIPTOR pfd;
611     LOGPALETTE* pPal;
612     int pixelFormat = GetPixelFormat(hDC);
613     int paletteSize;
614     HPALETTE hPalette;
615 
616     DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
617 
618     /*
619     ** Determine if a palette is needed and if so what size.
620     */
621     if (pfd.dwFlags & PFD_NEED_PALETTE) {
622 	paletteSize = 1 << pfd.cColorBits;
623     } else if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
624 	paletteSize = 4096;
625     } else {
626 	return;
627     }
628 
629     pPal = (LOGPALETTE*)
630 	malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
631     pPal->palVersion = 0x300;
632     pPal->palNumEntries = paletteSize;
633 
634     if (pfd.iPixelType == PFD_TYPE_RGBA) {
635 	/*
636 	** Fill the logical paletee with RGB color ramps
637 	*/
638 	int redMask = (1 << pfd.cRedBits) - 1;
639 	int greenMask = (1 << pfd.cGreenBits) - 1;
640 	int blueMask = (1 << pfd.cBlueBits) - 1;
641 	int i;
642 
643 	for (i=0; i<paletteSize; ++i) {
644 	    pPal->palPalEntry[i].peRed =
645 		    (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
646 	    pPal->palPalEntry[i].peGreen =
647 		    (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
648 	    pPal->palPalEntry[i].peBlue =
649 		    (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
650 	    pPal->palPalEntry[i].peFlags = 0;
651 	}
652     } else {
653 #if 0
654 	/* color index mode not supported at this time. 2/8/2001 - wes */
655 	/*
656 	** Fill the logical palette with color ramps.
657 	**
658 	** Set up the logical palette so that it can be realized
659 	** into the system palette as an identity palette.
660 	**
661 	** 1) The default static entries should be present and at the right
662 	**    location.  The easiest way to do this is to grab them from
663 	**    the current system palette.
664 	**
665 	** 2) All non-static entries should be initialized to unique values.
666 	**    The easiest way to do this is to ensure that all of the non-static
667 	**    entries have the PC_NOCOLLAPSE flag bit set.
668 	*/
669 	int numRamps = NUM_COLORS;
670 	int rampSize = (paletteSize - 20) / numRamps;
671 	int extra = (paletteSize - 20) - (numRamps * rampSize);
672 	int i, r;
673 
674 	/*
675 	** Initialize static entries by copying them from the
676 	** current system palette.
677 	*/
678 	GetSystemPaletteEntries(hDC, 0, paletteSize, &pPal->palPalEntry[0]);
679 
680 	/*
681 	** Fill in non-static entries with desired colors.
682 	*/
683 	for (r=0; r<numRamps; ++r) {
684 	    int rampBase = r * rampSize + 10;
685 	    PALETTEENTRY *pe = &pPal->palPalEntry[rampBase];
686 	    int diffSize = (int) (rampSize * colors[r].ratio);
687 	    int specSize = rampSize - diffSize;
688 
689 	    for (i=0; i<rampSize; ++i) {
690 		GLfloat *c0, *c1;
691 		GLint a;
692 
693 		if (i < diffSize) {
694 		    c0 = colors[r].amb;
695 		    c1 = colors[r].diff;
696 		    a = (i * 255) / (diffSize - 1);
697 		} else {
698 		    c0 = colors[r].diff;
699 		    c1 = colors[r].spec;
700 		    a = ((i - diffSize) * 255) / (specSize - 1);
701 		}
702 
703 		pe[i].peRed = (BYTE) (a * (c1[0] - c0[0]) + 255 * c0[0]);
704 		pe[i].peGreen = (BYTE) (a * (c1[1] - c0[1]) + 255 * c0[1]);
705 		pe[i].peBlue = (BYTE) (a * (c1[2] - c0[2]) + 255 * c0[2]);
706 		pe[i].peFlags = PC_NOCOLLAPSE;
707 	    }
708 
709 	    colors[r].indexes[0] = rampBase;
710 	    colors[r].indexes[1] = rampBase + (diffSize-1);
711 	    colors[r].indexes[2] = rampBase + (rampSize-1);
712 	}
713 
714 	/*
715 	** Initialize any remaining non-static entries.
716 	*/
717 	for (i=0; i<extra; ++i) {
718 	    int index = numRamps*rampSize+10+i;
719 	    PALETTEENTRY *pe = &pPal->palPalEntry[index];
720 
721 	    pe->peRed = (BYTE) 0;
722 	    pe->peGreen = (BYTE) 0;
723 	    pe->peBlue = (BYTE) 0;
724 	    pe->peFlags = PC_NOCOLLAPSE;
725 	}
726 #endif
727     }
728 
729     hPalette = CreatePalette(pPal);
730     free(pPal);
731 
732     if (hPalette) {
733 	SelectPalette(hDC, hPalette, FALSE);
734 	RealizePalette(hDC);
735     }
736 }
737 
738 /* PRIVATE */
739 void
private_rmPipeCloseContextW32(RMpipe * toClose)740 private_rmPipeCloseContextW32(RMpipe *toClose)
741 {
742     if ((toClose != NULL) && (toClose->hRC != NULL))
743 	wglDeleteContext(toClose->hRC);
744 }
745 
746 /* PRIVATE */
747 RMenum
private_rmwCheckAndDisplayLastError(const char * callerMsg)748 private_rmwCheckAndDisplayLastError(const char *callerMsg)
749 {
750     DWORD errorStatus;
751 
752     /*
753      * checks for Win32 errors. If an error is detected, a message box
754      * is displayed that contains (hopefully) useful information.
755      * This routine returns zero if there is no error, or a non-zero value if
756      * there is an error of some type.
757      */
758 
759     errorStatus = GetLastError();
760 
761     if (errorStatus != 0)
762     {
763 	LPVOID lpMsgBuf;
764 	FormatMessage(
765 		      FORMAT_MESSAGE_ALLOCATE_BUFFER |
766 		      FORMAT_MESSAGE_FROM_SYSTEM |
767 		      FORMAT_MESSAGE_IGNORE_INSERTS,
768 		      NULL,
769 		      errorStatus,
770 		      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
771 		      (LPTSTR) &lpMsgBuf,
772 		      0,
773 		      NULL
774 		      );
775 	MessageBox( NULL, (LPCTSTR)lpMsgBuf, callerMsg, MB_ICONERROR | MB_ICONINFORMATION );
776 	LocalFree( lpMsgBuf );
777     }
778     return errorStatus;
779 }
780 #endif /* RM_WIN */
781 /* EOF */
782