1/*
2 * Windows (Win32/Win64) device driver for Mesa
3 *
4 */
5
6#include "wmesadef.h"
7#include "colors.h"
8#include "GL/wmesa.h"
9#include <winuser.h>
10#include "main/context.h"
11#include "main/extensions.h"
12#include "main/framebuffer.h"
13#include "main/renderbuffer.h"
14#include "main/macros.h"
15#include "drivers/common/driverfuncs.h"
16#include "drivers/common/meta.h"
17#include "vbo/vbo.h"
18#include "swrast/swrast.h"
19#include "swrast/s_renderbuffer.h"
20#include "swrast_setup/swrast_setup.h"
21#include "tnl/tnl.h"
22#include "tnl/t_context.h"
23#include "tnl/t_pipeline.h"
24
25
26/* linked list of our Framebuffers (windows) */
27static WMesaFramebuffer FirstFramebuffer = NULL;
28
29
30/**
31 * Create a new WMesaFramebuffer object which will correspond to the
32 * given HDC (Window handle).
33 */
34static WMesaFramebuffer
35wmesa_new_framebuffer(HDC hdc, struct gl_config *visual)
36{
37    WMesaFramebuffer pwfb
38        = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer));
39    if (pwfb) {
40        _mesa_initialize_window_framebuffer(&pwfb->Base, visual);
41        pwfb->hDC = hdc;
42        /* insert at head of list */
43        pwfb->next = FirstFramebuffer;
44        FirstFramebuffer = pwfb;
45    }
46    return pwfb;
47}
48
49/**
50 * Given an hdc, free the corresponding WMesaFramebuffer
51 */
52static void
53wmesa_free_framebuffer(HDC hdc)
54{
55    WMesaFramebuffer pwfb, prev;
56    for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) {
57        if (pwfb->hDC == hdc)
58            break;
59	prev = pwfb;
60    }
61    if (pwfb) {
62        struct gl_framebuffer *fb;
63	if (pwfb == FirstFramebuffer)
64	    FirstFramebuffer = pwfb->next;
65	else
66	    prev->next = pwfb->next;
67        fb = &pwfb->Base;
68        _mesa_reference_framebuffer(&fb, NULL);
69    }
70}
71
72/**
73 * Given an hdc, return the corresponding WMesaFramebuffer
74 */
75static WMesaFramebuffer
76wmesa_lookup_framebuffer(HDC hdc)
77{
78    WMesaFramebuffer pwfb;
79    for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) {
80        if (pwfb->hDC == hdc)
81            return pwfb;
82    }
83    return NULL;
84}
85
86
87/**
88 * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer.
89 */
90static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb)
91{
92    return (WMesaFramebuffer) fb;
93}
94
95
96/**
97 * Given a struct gl_context, return the corresponding WMesaContext.
98 */
99static WMesaContext wmesa_context(const struct gl_context *ctx)
100{
101    return (WMesaContext) ctx;
102}
103
104
105/*
106 * Every driver should implement a GetString function in order to
107 * return a meaningful GL_RENDERER string.
108 */
109static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name)
110{
111    return (name == GL_RENDERER) ?
112	(GLubyte *) "Mesa Windows GDI Driver" : NULL;
113}
114
115
116/*
117 * Determine the pixel format based on the pixel size.
118 */
119static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC)
120{
121    pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL);
122
123    /* Only 16 and 32 bit targets are supported now */
124    assert(pwfb->cColorBits == 0 ||
125	   pwfb->cColorBits == 16 ||
126	   pwfb->cColorBits == 24 ||
127	   pwfb->cColorBits == 32);
128
129    switch(pwfb->cColorBits){
130    case 8:
131	pwfb->pixelformat = PF_INDEX8;
132	break;
133    case 16:
134	pwfb->pixelformat = PF_5R6G5B;
135	break;
136    case 24:
137    case 32:
138	pwfb->pixelformat = PF_8R8G8B;
139	break;
140    default:
141	pwfb->pixelformat = PF_BADFORMAT;
142    }
143}
144
145
146/**
147 * Create DIB for back buffer.
148 * We write into this memory with the span routines and then blit it
149 * to the window on a buffer swap.
150 */
151static BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize)
152{
153    LPBITMAPINFO pbmi = &(pwfb->bmi);
154    HDC          hic;
155
156    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
157    pbmi->bmiHeader.biWidth = lxSize;
158    pbmi->bmiHeader.biHeight= -lySize;
159    pbmi->bmiHeader.biPlanes = 1;
160    pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL);
161    pbmi->bmiHeader.biCompression = BI_RGB;
162    pbmi->bmiHeader.biSizeImage = 0;
163    pbmi->bmiHeader.biXPelsPerMeter = 0;
164    pbmi->bmiHeader.biYPelsPerMeter = 0;
165    pbmi->bmiHeader.biClrUsed = 0;
166    pbmi->bmiHeader.biClrImportant = 0;
167
168    pwfb->cColorBits = pbmi->bmiHeader.biBitCount;
169    pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3;
170
171    hic = CreateIC("display", NULL, NULL, NULL);
172    pwfb->dib_hDC = CreateCompatibleDC(hic);
173
174    pwfb->hbmDIB = CreateDIBSection(hic,
175				   &pwfb->bmi,
176				   DIB_RGB_COLORS,
177				   (void **)&(pwfb->pbPixels),
178				   0,
179				   0);
180    pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB);
181
182    DeleteDC(hic);
183
184    wmSetPixelFormat(pwfb, pwfb->hDC);
185    return TRUE;
186}
187
188
189static void wmDeleteBackingStore(WMesaFramebuffer pwfb)
190{
191    if (pwfb->hbmDIB) {
192	SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap);
193	DeleteDC(pwfb->dib_hDC);
194	DeleteObject(pwfb->hbmDIB);
195    }
196}
197
198
199/**
200 * Find the width and height of the window named by hdc.
201 */
202static void
203get_window_size(HDC hdc, GLuint *width, GLuint *height)
204{
205    if (WindowFromDC(hdc)) {
206        RECT rect;
207        GetClientRect(WindowFromDC(hdc), &rect);
208        *width = rect.right - rect.left;
209        *height = rect.bottom - rect.top;
210    }
211    else { /* Memory context */
212        /* From contributed code - use the size of the desktop
213         * for the size of a memory context (?) */
214        *width = GetDeviceCaps(hdc, HORZRES);
215        *height = GetDeviceCaps(hdc, VERTRES);
216    }
217}
218
219
220static void
221wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height)
222{
223    WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
224    get_window_size(pwfb->hDC, width, height);
225}
226
227
228static void wmesa_flush(struct gl_context *ctx)
229{
230    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer);
231
232    if (ctx->Visual.doubleBufferMode == 1) {
233	BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
234	       pwfb->dib_hDC, 0, 0, SRCCOPY);
235    }
236    else {
237	/* Do nothing for single buffer */
238    }
239}
240
241
242/**********************************************************************/
243/*****                   CLEAR Functions                          *****/
244/**********************************************************************/
245
246/*
247 * Clear the color/depth/stencil buffers.
248 */
249static void clear(struct gl_context *ctx, GLbitfield mask)
250{
251#define FLIP(Y)  (ctx->DrawBuffer->Height - (Y) - 1)
252    const GLint x = ctx->DrawBuffer->_Xmin;
253    const GLint y = ctx->DrawBuffer->_Ymin;
254    const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
255    const GLint width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
256
257    WMesaContext pwc = wmesa_context(ctx);
258    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
259    int done = 0;
260
261    /* Let swrast do all the work if the masks are not set to
262     * clear all channels. */
263    if (!ctx->Color.ColorMask[0][0] ||
264	!ctx->Color.ColorMask[0][1] ||
265	!ctx->Color.ColorMask[0][2] ||
266	!ctx->Color.ColorMask[0][3]) {
267	_swrast_Clear(ctx, mask);
268	return;
269    }
270
271    if (mask & BUFFER_BITS_COLOR) {
272       /* setup the clearing color */
273       const union gl_color_union color = ctx->Color.ClearColor;
274       GLubyte col[3];
275       UNCLAMPED_FLOAT_TO_UBYTE(col[0], color.f[0]);
276       UNCLAMPED_FLOAT_TO_UBYTE(col[1], color.f[1]);
277       UNCLAMPED_FLOAT_TO_UBYTE(col[2], color.f[2]);
278       pwc->clearColorRef = RGB(col[0], col[1], col[2]);
279       DeleteObject(pwc->clearPen);
280       DeleteObject(pwc->clearBrush);
281       pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef);
282       pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef);
283    }
284
285    /* Back buffer */
286    if (mask & BUFFER_BIT_BACK_LEFT) {
287
288	int     i, rowSize;
289	UINT    bytesPerPixel = pwfb->cColorBits / 8;
290	LPBYTE  lpb, clearRow;
291	LPWORD  lpw;
292	BYTE    bColor;
293	WORD    wColor;
294	BYTE    r, g, b;
295	DWORD   dwColor;
296	LPDWORD lpdw;
297
298	/* Try for a fast clear - clearing entire buffer with a single
299	 * byte value. */
300	if (width == ctx->DrawBuffer->Width &&
301            height == ctx->DrawBuffer->Height) { /* entire buffer */
302	    /* Now check for an easy clear value */
303	    switch (bytesPerPixel) {
304	    case 1:
305		bColor = BGR8(GetRValue(pwc->clearColorRef),
306			      GetGValue(pwc->clearColorRef),
307			      GetBValue(pwc->clearColorRef));
308		memset(pwfb->pbPixels, bColor,
309		       pwfb->ScanWidth * height);
310		done = 1;
311		break;
312	    case 2:
313		wColor = BGR16(GetRValue(pwc->clearColorRef),
314			       GetGValue(pwc->clearColorRef),
315			       GetBValue(pwc->clearColorRef));
316		if (((wColor >> 8) & 0xff) == (wColor & 0xff)) {
317		    memset(pwfb->pbPixels, wColor & 0xff,
318			   pwfb->ScanWidth * height);
319		    done = 1;
320		}
321		break;
322	    case 3:
323		/* fall through */
324	    case 4:
325		if (GetRValue(pwc->clearColorRef) ==
326		    GetGValue(pwc->clearColorRef) &&
327		    GetRValue(pwc->clearColorRef) ==
328		    GetBValue(pwc->clearColorRef)) {
329		    memset(pwfb->pbPixels,
330			   GetRValue(pwc->clearColorRef),
331			   pwfb->ScanWidth * height);
332		    done = 1;
333		}
334		break;
335	    default:
336		break;
337	    }
338	} /* all */
339
340	if (!done) {
341	    /* Need to clear a row at a time.  Begin by setting the first
342	     * row in the area to be cleared to the clear color. */
343
344	    clearRow = pwfb->pbPixels +
345		pwfb->ScanWidth * FLIP(y) +
346		bytesPerPixel * x;
347	    switch (bytesPerPixel) {
348	    case 1:
349		lpb = clearRow;
350		bColor = BGR8(GetRValue(pwc->clearColorRef),
351			      GetGValue(pwc->clearColorRef),
352			      GetBValue(pwc->clearColorRef));
353		memset(lpb, bColor, width);
354		break;
355	    case 2:
356		lpw = (LPWORD)clearRow;
357		wColor = BGR16(GetRValue(pwc->clearColorRef),
358			       GetGValue(pwc->clearColorRef),
359			       GetBValue(pwc->clearColorRef));
360		for (i=0; i<width; i++)
361		    *lpw++ = wColor;
362		break;
363	    case 3:
364		lpb = clearRow;
365		r = GetRValue(pwc->clearColorRef);
366		g = GetGValue(pwc->clearColorRef);
367		b = GetBValue(pwc->clearColorRef);
368		for (i=0; i<width; i++) {
369		    *lpb++ = b;
370		    *lpb++ = g;
371		    *lpb++ = r;
372		}
373		break;
374	    case 4:
375		lpdw = (LPDWORD)clearRow;
376		dwColor = BGR32(GetRValue(pwc->clearColorRef),
377				GetGValue(pwc->clearColorRef),
378				GetBValue(pwc->clearColorRef));
379		for (i=0; i<width; i++)
380		    *lpdw++ = dwColor;
381		break;
382	    default:
383		break;
384	    } /* switch */
385
386	    /* copy cleared row to other rows in buffer */
387	    lpb = clearRow - pwfb->ScanWidth;
388	    rowSize = width * bytesPerPixel;
389	    for (i=1; i<height; i++) {
390		memcpy(lpb, clearRow, rowSize);
391		lpb -= pwfb->ScanWidth;
392	    }
393	} /* not done */
394	mask &= ~BUFFER_BIT_BACK_LEFT;
395    } /* back buffer */
396
397    /* front buffer */
398    if (mask & BUFFER_BIT_FRONT_LEFT) {
399	HDC DC = pwc->hDC;
400	HPEN Old_Pen = SelectObject(DC, pwc->clearPen);
401	HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush);
402	Rectangle(DC,
403		  x,
404		  FLIP(y) + 1,
405		  x + width + 1,
406		  FLIP(y) - height + 1);
407	SelectObject(DC, Old_Pen);
408	SelectObject(DC, Old_Brush);
409	mask &= ~BUFFER_BIT_FRONT_LEFT;
410    } /* front buffer */
411
412    /* Call swrast if there is anything left to clear (like DEPTH) */
413    if (mask)
414	_swrast_Clear(ctx, mask);
415
416#undef FLIP
417}
418
419
420/**********************************************************************/
421/*****                   PIXEL Functions                          *****/
422/**********************************************************************/
423
424#define FLIP(Y)  (rb->Height - (Y) - 1)
425
426
427/**
428 ** Front Buffer reading/writing
429 ** These are slow, but work with all non-indexed visual types.
430 **/
431
432/* Write a horizontal span of RGBA color pixels with a boolean mask. */
433static void write_rgba_span_front(struct gl_context *ctx,
434				  struct gl_renderbuffer *rb,
435				  GLuint n, GLint x, GLint y,
436				  const void *values,
437				  const GLubyte *mask)
438{
439   const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
440   WMesaContext pwc = wmesa_context(ctx);
441   WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(pwc->hDC);
442   HBITMAP bmp=0;
443   HDC mdc=0;
444   typedef union
445   {
446      unsigned i;
447      struct {
448         unsigned b:8, g:8, r:8, a:8;
449      };
450   } BGRA;
451   BGRA *bgra, c;
452   GLuint i;
453
454   if (n < 16) {   // the value 16 is just guessed
455      y=FLIP(y);
456      if (mask) {
457         for (i=0; i<n; i++)
458            if (mask[i])
459               SetPixel(pwc->hDC, x+i, y,
460                        RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]));
461      }
462      else {
463         for (i=0; i<n; i++)
464            SetPixel(pwc->hDC, x+i, y,
465                     RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]));
466      }
467   }
468   else {
469      if (!pwfb) {
470         _mesa_problem(NULL, "wmesa: write_rgba_span_front on unknown hdc");
471         return;
472      }
473      bgra=malloc(n*sizeof(BGRA));
474      if (!bgra) {
475         _mesa_problem(NULL, "wmesa: write_rgba_span_front: out of memory");
476         return;
477      }
478      c.a=0;
479      if (mask) {
480         for (i=0; i<n; i++) {
481            if (mask[i]) {
482               c.r=rgba[i][RCOMP];
483               c.g=rgba[i][GCOMP];
484               c.b=rgba[i][BCOMP];
485               c.a=rgba[i][ACOMP];
486               bgra[i]=c;
487            }
488            else
489               bgra[i].i=0;
490         }
491      }
492      else {
493         for (i=0; i<n; i++) {
494            c.r=rgba[i][RCOMP];
495            c.g=rgba[i][GCOMP];
496            c.b=rgba[i][BCOMP];
497            c.a=rgba[i][ACOMP];
498            bgra[i]=c;
499         }
500      }
501      bmp=CreateBitmap(n, 1,  1, 32, bgra);
502      mdc=CreateCompatibleDC(pwfb->hDC);
503      SelectObject(mdc, bmp);
504      y=FLIP(y);
505      BitBlt(pwfb->hDC, x, y, n, 1, mdc, 0, 0, SRCCOPY);
506      SelectObject(mdc, 0);
507      DeleteObject(bmp);
508      DeleteDC(mdc);
509      free(bgra);
510   }
511}
512
513
514/* Write an array of RGBA pixels with a boolean mask. */
515static void write_rgba_pixels_front(struct gl_context *ctx,
516                                    struct gl_renderbuffer *rb,
517                                    GLuint n,
518                                    const GLint x[], const GLint y[],
519                                    const void *values,
520                                    const GLubyte *mask)
521{
522    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
523    GLuint i;
524    WMesaContext pwc = wmesa_context(ctx);
525    (void) ctx;
526    for (i=0; i<n; i++)
527	if (mask[i])
528	    SetPixel(pwc->hDC, x[i], FLIP(y[i]),
529		     RGB(rgba[i][RCOMP], rgba[i][GCOMP],
530			 rgba[i][BCOMP]));
531}
532
533
534
535/* Read a horizontal span of color pixels. */
536static void read_rgba_span_front(struct gl_context *ctx,
537                                 struct gl_renderbuffer *rb,
538                                 GLuint n, GLint x, GLint y,
539                                 void *values)
540{
541    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
542    WMesaContext pwc = wmesa_context(ctx);
543    GLuint i;
544    COLORREF Color;
545    y = FLIP(y);
546    for (i=0; i<n; i++) {
547	Color = GetPixel(pwc->hDC, x+i, y);
548	rgba[i][RCOMP] = GetRValue(Color);
549	rgba[i][GCOMP] = GetGValue(Color);
550	rgba[i][BCOMP] = GetBValue(Color);
551	rgba[i][ACOMP] = 255;
552    }
553}
554
555
556/* Read an array of color pixels. */
557static void read_rgba_pixels_front(struct gl_context *ctx,
558                                   struct gl_renderbuffer *rb,
559                                   GLuint n, const GLint x[], const GLint y[],
560                                   void *values)
561{
562    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
563    WMesaContext pwc = wmesa_context(ctx);
564    GLuint i;
565    COLORREF Color;
566    for (i=0; i<n; i++) {
567        GLint y2 = FLIP(y[i]);
568        Color = GetPixel(pwc->hDC, x[i], y2);
569        rgba[i][RCOMP] = GetRValue(Color);
570        rgba[i][GCOMP] = GetGValue(Color);
571        rgba[i][BCOMP] = GetBValue(Color);
572        rgba[i][ACOMP] = 255;
573    }
574}
575
576/*********************************************************************/
577
578/* DOUBLE BUFFER 32-bit */
579
580#define WMSETPIXEL32(pwc, y, x, r, g, b) { \
581LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \
582*lpdw = BGR32((r),(g),(b)); }
583
584
585
586/* Write a horizontal span of RGBA color pixels with a boolean mask. */
587static void write_rgba_span_32(struct gl_context *ctx,
588			       struct gl_renderbuffer *rb,
589			       GLuint n, GLint x, GLint y,
590			       const void *values,
591			       const GLubyte *mask)
592{
593    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
594    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
595    GLuint i;
596    LPDWORD lpdw;
597
598    (void) ctx;
599
600    y=FLIP(y);
601    lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
602    if (mask) {
603	for (i=0; i<n; i++)
604	    if (mask[i])
605                lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
606				rgba[i][BCOMP]);
607    }
608    else {
609	for (i=0; i<n; i++)
610                *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
611				rgba[i][BCOMP]);
612    }
613}
614
615
616/* Write an array of RGBA pixels with a boolean mask. */
617static void write_rgba_pixels_32(struct gl_context *ctx,
618				 struct gl_renderbuffer *rb,
619				 GLuint n, const GLint x[], const GLint y[],
620				 const void *values,
621				 const GLubyte *mask)
622{
623    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
624    GLuint i;
625    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
626    for (i=0; i<n; i++)
627	if (mask[i])
628	    WMSETPIXEL32(pwfb, FLIP(y[i]), x[i],
629			 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
630}
631
632
633/* Read a horizontal span of color pixels. */
634static void read_rgba_span_32(struct gl_context *ctx,
635			      struct gl_renderbuffer *rb,
636			      GLuint n, GLint x, GLint y,
637			      void *values)
638{
639    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
640    GLuint i;
641    DWORD pixel;
642    LPDWORD lpdw;
643    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
644
645    y = FLIP(y);
646    lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
647    for (i=0; i<n; i++) {
648	pixel = lpdw[i];
649	rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16);
650	rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8);
651	rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff);
652	rgba[i][ACOMP] = 255;
653    }
654}
655
656
657/* Read an array of color pixels. */
658static void read_rgba_pixels_32(struct gl_context *ctx,
659				struct gl_renderbuffer *rb,
660				GLuint n, const GLint x[], const GLint y[],
661				void *values)
662{
663    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
664    GLuint i;
665    DWORD pixel;
666    LPDWORD lpdw;
667    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
668
669    for (i=0; i<n; i++) {
670	GLint y2 = FLIP(y[i]);
671	lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + x[i];
672	pixel = *lpdw;
673	rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16);
674	rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8);
675	rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff);
676	rgba[i][ACOMP] = 255;
677  }
678}
679
680
681/*********************************************************************/
682
683/* DOUBLE BUFFER 24-bit */
684
685#define WMSETPIXEL24(pwc, y, x, r, g, b) { \
686LPBYTE lpb = ((LPBYTE)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (3 * x)); \
687lpb[0] = (b); \
688lpb[1] = (g); \
689lpb[2] = (r); }
690
691/* Write a horizontal span of RGBA color pixels with a boolean mask. */
692static void write_rgba_span_24(struct gl_context *ctx,
693			       struct gl_renderbuffer *rb,
694			       GLuint n, GLint x, GLint y,
695			       const void *values,
696			       const GLubyte *mask)
697{
698    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
699    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
700    GLuint i;
701    LPBYTE lpb;
702
703    (void) ctx;
704
705    y=FLIP(y);
706    lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
707    if (mask) {
708	for (i=0; i<n; i++)
709	    if (mask[i]) {
710                lpb[3*i] = rgba[i][BCOMP];
711                lpb[3*i+1] = rgba[i][GCOMP];
712                lpb[3*i+2] = rgba[i][RCOMP];
713	    }
714    }
715    else {
716	    for (i=0; i<n; i++) {
717            *lpb++ = rgba[i][BCOMP];
718            *lpb++ = rgba[i][GCOMP];
719            *lpb++ = rgba[i][RCOMP];
720	    }
721    }
722}
723
724
725/* Write an array of RGBA pixels with a boolean mask. */
726static void write_rgba_pixels_24(struct gl_context *ctx,
727				 struct gl_renderbuffer *rb,
728				 GLuint n, const GLint x[], const GLint y[],
729				 const void *values,
730				 const GLubyte *mask)
731{
732    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
733    GLuint i;
734    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
735    for (i=0; i<n; i++)
736	if (mask[i])
737	    WMSETPIXEL24(pwfb, FLIP(y[i]), x[i],
738			 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
739}
740
741
742/* Read a horizontal span of color pixels. */
743static void read_rgba_span_24(struct gl_context *ctx,
744			      struct gl_renderbuffer *rb,
745			      GLuint n, GLint x, GLint y,
746			      void *values)
747{
748    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
749    GLuint i;
750    LPBYTE lpb;
751    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
752
753    y = FLIP(y);
754    lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x);
755    for (i=0; i<n; i++) {
756	rgba[i][RCOMP] = lpb[3*i+2];
757	rgba[i][GCOMP] = lpb[3*i+1];
758	rgba[i][BCOMP] = lpb[3*i];
759	rgba[i][ACOMP] = 255;
760    }
761}
762
763
764/* Read an array of color pixels. */
765static void read_rgba_pixels_24(struct gl_context *ctx,
766				struct gl_renderbuffer *rb,
767				GLuint n, const GLint x[], const GLint y[],
768				void *values)
769{
770    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
771    GLuint i;
772    LPBYTE lpb;
773    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
774
775    for (i=0; i<n; i++) {
776	GLint y2 = FLIP(y[i]);
777	lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + (3 * x[i]);
778	rgba[i][RCOMP] = lpb[3*i+2];
779	rgba[i][GCOMP] = lpb[3*i+1];
780	rgba[i][BCOMP] = lpb[3*i];
781	rgba[i][ACOMP] = 255;
782  }
783}
784
785
786/*********************************************************************/
787
788/* DOUBLE BUFFER 16-bit */
789
790#define WMSETPIXEL16(pwc, y, x, r, g, b) { \
791LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \
792*lpw = BGR16((r),(g),(b)); }
793
794
795
796/* Write a horizontal span of RGBA color pixels with a boolean mask. */
797static void write_rgba_span_16(struct gl_context *ctx,
798			       struct gl_renderbuffer *rb,
799			       GLuint n, GLint x, GLint y,
800			       const void *values,
801			       const GLubyte *mask)
802{
803    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
804    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
805    GLuint i;
806    LPWORD lpw;
807
808    (void) ctx;
809
810    y=FLIP(y);
811    lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
812    if (mask) {
813	for (i=0; i<n; i++)
814	    if (mask[i])
815                lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
816			       rgba[i][BCOMP]);
817    }
818    else {
819	for (i=0; i<n; i++)
820                *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
821			       rgba[i][BCOMP]);
822    }
823}
824
825
826
827/* Write an array of RGBA pixels with a boolean mask. */
828static void write_rgba_pixels_16(struct gl_context *ctx,
829				 struct gl_renderbuffer *rb,
830				 GLuint n, const GLint x[], const GLint y[],
831				 const void *values,
832				 const GLubyte *mask)
833{
834    const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values;
835    GLuint i;
836    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
837    (void) ctx;
838    for (i=0; i<n; i++)
839	if (mask[i])
840	    WMSETPIXEL16(pwfb, FLIP(y[i]), x[i],
841			 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
842}
843
844
845/* Read a horizontal span of color pixels. */
846static void read_rgba_span_16(struct gl_context *ctx,
847			      struct gl_renderbuffer *rb,
848			      GLuint n, GLint x, GLint y,
849			      void *values)
850{
851    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
852    GLuint i, pixel;
853    LPWORD lpw;
854    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
855
856    y = FLIP(y);
857    lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x;
858    for (i=0; i<n; i++) {
859	pixel = lpw[i];
860	/* Windows uses 5,5,5 for 16-bit */
861	rgba[i][RCOMP] = (pixel & 0x7c00) >> 7;
862	rgba[i][GCOMP] = (pixel & 0x03e0) >> 2;
863	rgba[i][BCOMP] = (pixel & 0x001f) << 3;
864	rgba[i][ACOMP] = 255;
865    }
866}
867
868
869/* Read an array of color pixels. */
870static void read_rgba_pixels_16(struct gl_context *ctx,
871				struct gl_renderbuffer *rb,
872				GLuint n, const GLint x[], const GLint y[],
873				void *values)
874{
875    GLubyte (*rgba)[4] = (GLubyte (*)[4])values;
876    GLuint i, pixel;
877    LPWORD lpw;
878    WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
879
880    for (i=0; i<n; i++) {
881	GLint y2 = FLIP(y[i]);
882	lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y2)) + x[i];
883	pixel = *lpw;
884	/* Windows uses 5,5,5 for 16-bit */
885	rgba[i][RCOMP] = (pixel & 0x7c00) >> 7;
886	rgba[i][GCOMP] = (pixel & 0x03e0) >> 2;
887	rgba[i][BCOMP] = (pixel & 0x001f) << 3;
888	rgba[i][ACOMP] = 255;
889  }
890}
891
892
893
894
895/**********************************************************************/
896/*****                   BUFFER Functions                         *****/
897/**********************************************************************/
898
899
900
901
902static void
903wmesa_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
904{
905    _mesa_delete_renderbuffer(ctx, rb);
906}
907
908
909/**
910 * This is called by Mesa whenever it determines that the window size
911 * has changed.  Do whatever's needed to cope with that.
912 */
913static GLboolean
914wmesa_renderbuffer_storage(struct gl_context *ctx,
915			   struct gl_renderbuffer *rb,
916			   GLenum internalFormat,
917			   GLuint width,
918			   GLuint height)
919{
920    rb->Width = width;
921    rb->Height = height;
922    return GL_TRUE;
923}
924
925
926/**
927 * Called by ctx->Driver.ResizeBuffers()
928 * Resize the front/back colorbuffers to match the latest window size.
929 */
930static void
931wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer,
932                     GLuint width, GLuint height)
933{
934    WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
935
936    if (pwfb->Base.Width != width || pwfb->Base.Height != height) {
937	/* Realloc back buffer */
938	if (ctx->Visual.doubleBufferMode == 1) {
939	    wmDeleteBackingStore(pwfb);
940	    wmCreateBackingStore(pwfb, width, height);
941	}
942    }
943    _mesa_resize_framebuffer(ctx, buffer, width, height);
944}
945
946
947/**
948 * Called by glViewport.
949 * This is a good time for us to poll the current window size and adjust
950 * our renderbuffers to match the current window size.
951 * Remember, we have no opportunity to respond to conventional
952 * resize events since the driver has no event loop.
953 * Thus, we poll.
954 * MakeCurrent also ends up making a call here, so that ensures
955 * we get the viewport set correctly, even if the app does not call
956 * glViewport and relies on the defaults.
957 */
958static void wmesa_viewport(struct gl_context *ctx,
959			   GLint x, GLint y,
960			   GLsizei width, GLsizei height)
961{
962    GLuint new_width, new_height;
963
964    wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height);
965
966    /**
967     * Resize buffers if the window size changed.
968     */
969    wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height);
970    ctx->NewState |= _NEW_BUFFERS;  /* to update scissor / window bounds */
971}
972
973
974
975
976/**
977 * Called when the driver should update it's state, based on the new_state
978 * flags.
979 */
980static void wmesa_update_state(struct gl_context *ctx, GLuint new_state)
981{
982    _swrast_InvalidateState(ctx, new_state);
983    _swsetup_InvalidateState(ctx, new_state);
984    _vbo_InvalidateState(ctx, new_state);
985    _tnl_InvalidateState(ctx, new_state);
986
987    /* TODO - This code is not complete yet because I
988     * don't know what to do for all state updates.
989     */
990
991    if (new_state & _NEW_BUFFERS) {
992    }
993}
994
995
996
997
998
999/**********************************************************************/
1000/*****                   WMESA Functions                          *****/
1001/**********************************************************************/
1002
1003WMesaContext WMesaCreateContext(HDC hDC,
1004				HPALETTE* Pal,
1005				GLboolean rgb_flag,
1006				GLboolean db_flag,
1007				GLboolean alpha_flag)
1008{
1009    WMesaContext c;
1010    struct dd_function_table functions;
1011    GLint red_bits, green_bits, blue_bits, alpha_bits;
1012    struct gl_context *ctx;
1013    struct gl_config *visual;
1014
1015    (void) Pal;
1016
1017    /* Indexed mode not supported */
1018    if (!rgb_flag)
1019	return NULL;
1020
1021    /* Allocate wmesa context */
1022    c = CALLOC_STRUCT(wmesa_context);
1023    if (!c)
1024	return NULL;
1025
1026#if 0
1027    /* I do not understand this contributed code */
1028    /* Support memory and device contexts */
1029    if(WindowFromDC(hDC) != NULL) {
1030	c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */
1031    }
1032    else {
1033	c->hDC = hDC;
1034    }
1035#else
1036    c->hDC = hDC;
1037#endif
1038
1039    /* Get data for visual */
1040    /* Dealing with this is actually a bit of overkill because Mesa will end
1041     * up treating all color component size requests less than 8 by using
1042     * a single byte per channel.  In addition, the interface to the span
1043     * routines passes colors as an entire byte per channel anyway, so there
1044     * is nothing to be saved by telling the visual to be 16 bits if the device
1045     * is 16 bits.  That is, Mesa is going to compute colors down to 8 bits per
1046     * channel anyway.
1047     * But we go through the motions here anyway.
1048     */
1049    switch (GetDeviceCaps(c->hDC, BITSPIXEL)) {
1050    case 16:
1051	red_bits = green_bits = blue_bits = 5;
1052	alpha_bits = 0;
1053	break;
1054    default:
1055	red_bits = green_bits = blue_bits = 8;
1056	alpha_bits = 8;
1057	break;
1058    }
1059    /* Create visual based on flags */
1060    visual = _mesa_create_visual(db_flag,    /* db_flag */
1061                                 GL_FALSE,   /* stereo */
1062                                 red_bits, green_bits, blue_bits, /* color RGB */
1063                                 alpha_flag ? alpha_bits : 0, /* color A */
1064                                 DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */
1065                                 8,          /* stencil_bits */
1066                                 16,16,16,   /* accum RGB */
1067                                 alpha_flag ? 16 : 0, /* accum A */
1068                                 1);         /* num samples */
1069
1070    if (!visual) {
1071	free(c);
1072	return NULL;
1073    }
1074
1075    /* Set up driver functions */
1076    _mesa_init_driver_functions(&functions);
1077    functions.GetString = wmesa_get_string;
1078    functions.UpdateState = wmesa_update_state;
1079    functions.GetBufferSize = wmesa_get_buffer_size;
1080    functions.Flush = wmesa_flush;
1081    functions.Clear = clear;
1082    functions.ResizeBuffers = wmesa_resize_buffers;
1083    functions.Viewport = wmesa_viewport;
1084
1085    /* initialize the Mesa context data */
1086    ctx = &c->gl_ctx;
1087    _mesa_initialize_context(ctx, API_OPENGL, visual,
1088                             NULL, &functions, (void *)c);
1089
1090    /* visual no longer needed - it was copied by _mesa_initialize_context() */
1091    _mesa_destroy_visual(visual);
1092
1093    _mesa_enable_sw_extensions(ctx);
1094    _mesa_enable_1_3_extensions(ctx);
1095    _mesa_enable_1_4_extensions(ctx);
1096    _mesa_enable_1_5_extensions(ctx);
1097    _mesa_enable_2_0_extensions(ctx);
1098    _mesa_enable_2_1_extensions(ctx);
1099
1100    _mesa_meta_init(ctx);
1101
1102    /* Initialize the software rasterizer and helper modules. */
1103    if (!_swrast_CreateContext(ctx) ||
1104        !_vbo_CreateContext(ctx) ||
1105        !_tnl_CreateContext(ctx) ||
1106	!_swsetup_CreateContext(ctx)) {
1107	_mesa_free_context_data(ctx);
1108	free(c);
1109	return NULL;
1110    }
1111    _swsetup_Wakeup(ctx);
1112    TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
1113
1114    return c;
1115}
1116
1117
1118void WMesaDestroyContext( WMesaContext pwc )
1119{
1120    struct gl_context *ctx = &pwc->gl_ctx;
1121    WMesaFramebuffer pwfb;
1122    GET_CURRENT_CONTEXT(cur_ctx);
1123
1124    if (cur_ctx == ctx) {
1125        /* unbind current if deleting current context */
1126        WMesaMakeCurrent(NULL, NULL);
1127    }
1128
1129    /* clean up frame buffer resources */
1130    pwfb = wmesa_lookup_framebuffer(pwc->hDC);
1131    if (pwfb) {
1132	if (ctx->Visual.doubleBufferMode == 1)
1133	    wmDeleteBackingStore(pwfb);
1134	wmesa_free_framebuffer(pwc->hDC);
1135    }
1136
1137    /* Release for device, not memory contexts */
1138    if (WindowFromDC(pwc->hDC) != NULL)
1139    {
1140      ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC);
1141    }
1142    DeleteObject(pwc->clearPen);
1143    DeleteObject(pwc->clearBrush);
1144
1145    _mesa_meta_free(ctx);
1146
1147    _swsetup_DestroyContext(ctx);
1148    _tnl_DestroyContext(ctx);
1149    _vbo_DestroyContext(ctx);
1150    _swrast_DestroyContext(ctx);
1151
1152    _mesa_free_context_data(ctx);
1153    free(pwc);
1154}
1155
1156
1157/**
1158 * Create a new color renderbuffer.
1159 */
1160static struct gl_renderbuffer *
1161wmesa_new_renderbuffer(void)
1162{
1163    struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer);
1164    if (!rb)
1165        return NULL;
1166
1167    _mesa_init_renderbuffer(rb, (GLuint)0);
1168
1169    rb->_BaseFormat = GL_RGBA;
1170    rb->InternalFormat = GL_RGBA;
1171    rb->Delete = wmesa_delete_renderbuffer;
1172    rb->AllocStorage = wmesa_renderbuffer_storage;
1173    return rb;
1174}
1175
1176
1177void WMesaMakeCurrent(WMesaContext c, HDC hdc)
1178{
1179    WMesaFramebuffer pwfb;
1180
1181    {
1182        /* return if already current */
1183        GET_CURRENT_CONTEXT(ctx);
1184        WMesaContext pwc = wmesa_context(ctx);
1185        if (pwc && c == pwc && pwc->hDC == hdc)
1186            return;
1187    }
1188
1189    pwfb = wmesa_lookup_framebuffer(hdc);
1190
1191    /* Lazy creation of framebuffers */
1192    if (c && !pwfb && hdc) {
1193        struct gl_renderbuffer *rb;
1194        struct gl_config *visual = &c->gl_ctx.Visual;
1195        GLuint width, height;
1196
1197        get_window_size(hdc, &width, &height);
1198
1199	c->clearPen = CreatePen(PS_SOLID, 1, 0);
1200	c->clearBrush = CreateSolidBrush(0);
1201
1202        pwfb = wmesa_new_framebuffer(hdc, visual);
1203
1204	/* Create back buffer if double buffered */
1205	if (visual->doubleBufferMode == 1) {
1206	    wmCreateBackingStore(pwfb, width, height);
1207	}
1208
1209        /* make render buffers */
1210        if (visual->doubleBufferMode == 1) {
1211            rb = wmesa_new_renderbuffer();
1212            _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb);
1213	}
1214        rb = wmesa_new_renderbuffer();
1215        _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb);
1216
1217	/* Let Mesa own the Depth, Stencil, and Accum buffers */
1218        _swrast_add_soft_renderbuffers(&pwfb->Base,
1219                                       GL_FALSE, /* color */
1220                                       visual->depthBits > 0,
1221                                       visual->stencilBits > 0,
1222                                       visual->accumRedBits > 0,
1223                                       visual->alphaBits >0,
1224                                       GL_FALSE);
1225    }
1226
1227    if (c && pwfb)
1228	_mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base);
1229    else
1230        _mesa_make_current(NULL, NULL, NULL);
1231}
1232
1233
1234void WMesaSwapBuffers( HDC hdc )
1235{
1236    GET_CURRENT_CONTEXT(ctx);
1237    WMesaContext pwc = wmesa_context(ctx);
1238    WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc);
1239
1240    if (!pwfb) {
1241        _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc");
1242        return;
1243    }
1244
1245    /* If we're swapping the buffer associated with the current context
1246     * we have to flush any pending rendering commands first.
1247     */
1248    if (pwc->hDC == hdc) {
1249	_mesa_notifySwapBuffers(ctx);
1250
1251	BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
1252	       pwfb->dib_hDC, 0, 0, SRCCOPY);
1253    }
1254    else {
1255        /* XXX for now only allow swapping current window */
1256        _mesa_problem(NULL, "wmesa: can't swap non-current window");
1257    }
1258}
1259
1260void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx)
1261{
1262	_mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx);
1263}
1264
1265