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