
/*
 * Windows (Win32) device driver for Mesa 3.4
 *
 * Original author:
 *
 *  Copyright (C) 1996-  Li Wei
 *  Address      :       Institute of Artificial Intelligence
 *               :           & Robotics
 *               :       Xi'an Jiaotong University
 *  Email        :       liwei@aiar.xjtu.edu.cn
 *  Web page :       http://sun.aiar.xjtu.edu.cn
 *
 *  This file and its associations are partially borrowed from the
 *  Windows NT driver for Mesa 1.8 , written by Mark Leaming
 *  (mark@rsinc.com).
 *
 * Updated for Mesa 4.0 by Karl Schultz (kschultz@sourceforge.net)
 */

#ifdef NDEBUG
#pragma auto_inline(on)
#pragma inline_depth(255)
#pragma inline_recursion(on)
#endif

#include "wmesadef.h"
#include <GL/wmesa.h>
#include "mesa_extend.h"

#include "glheader.h"
#include "colors.h"
#include "context.h"
#include "colormac.h"
#include "dd.h"
#include "depth.h"
#include "extensions.h"
#include "imports.h"
#include "macros.h"
#include "matrix.h"
#include "mmath.h"
#include "mtypes.h"
#include "texformat.h"
#include "texstore.h"
#include "array_cache/acache.h"
#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
#include "swrast/s_context.h"
#include "swrast/s_depth.h"
#include "swrast/s_lines.h"
#include "swrast/s_triangle.h"
#include "swrast/s_trispan.h"
#include "tnl/tnl.h"
#include "tnl/t_context.h"
#include "tnl/t_pipeline.h"

/* Dither not tested for Mesa 4.0 */ 
#ifdef DITHER
#ifdef USE_WING
#include <wing.h>
#endif // USE_WING
#endif

#ifdef __CYGWIN32__
#include "macros.h"
#include <string.h>
#define CopyMemory memcpy
#endif

/* Stereo and parallel not tested for Mesa 4.0. */
#if !defined(NO_STEREO)
#include "gl\glu.h"
#include "stereo.h"
#endif

#if !defined(NO_PARALLEL)
#include "parallel.h"
#endif


/* File global varaibles */
struct DISPLAY_OPTIONS displayOptions = 
{
	0,		// stereo
	0,		// fullScreen
	0,		// full screen mode (1,2,3,4)
	0		// bpp (8,16,24,32)
};
GLenum stereoCompile = GL_FALSE ;
GLenum stereoShowing  = GL_FALSE ;
GLenum stereoBuffer = GL_FALSE;
#if !defined(NO_STEREO)
GLint displayList = MAXIMUM_DISPLAY_LIST ;
#endif
GLint stereo_flag = 0 ;

static PWMC Current = NULL;
WMesaContext WC = NULL;

#ifdef COMPILE_SETPIXEL

#if defined(_MSC_VER) && _MSC_VER >= 1200
#define FORCEINLINE __forceinline
#else
#define FORCEINLINE __inline
#endif

FORCEINLINE void wmSetPixel(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	pwc->wmSetPixel(pwc,iScanLine,iPixel,r,g,b);
}

void ChooseSetPixel(PWMC pwc);

#endif // COMPILE_SETPIXEL

/* If we are double-buffering, we want to get the DC for the
 * off-screen DIB, otherwise the DC for the window.
 */
#define DD_GETDC ((Current->db_flag) ? Current->dib.hDC : Current->hDC )
#define DD_RELEASEDC

#define FLIP(Y)  (Current->height-(Y)-1)

#define DITHER_RGB_TO_8BIT_SETUP            \
GLubyte pixelDithered;

#define DITHER_RGB_TO_8BIT(red, green, blue, pixel, scanline)        \
{                                                                    \
    char unsigned redtemp, greentemp, bluetemp, paletteindex;        \
    redtemp = aDividedBy51[red]                                      \
    + (aModulo51[red] > aHalftone8x8[(pixel%8)*8                     \
    + scanline%8]);                                                  \
    greentemp = aDividedBy51[(char unsigned)green]                   \
    + (aModulo51[green] > aHalftone8x8[                              \
    (pixel%8)*8 + scanline%8]);                                      \
    bluetemp = aDividedBy51[(char unsigned)blue]                     \
    + (aModulo51[blue] > aHalftone8x8[                               \
    (pixel%8)*8 +scanline%8]);                                       \
    paletteindex = redtemp + aTimes6[greentemp] + aTimes36[bluetemp];\
    pixelDithered = aWinGHalftoneTranslation[paletteindex];          \
}

#ifdef DDRAW
static BOOL DDInit( WMesaContext wc, HWND hwnd);
static void DDFree( WMesaContext wc);
static HRESULT DDRestoreAll( WMesaContext wc );
static void DDDeleteOffScreen(WMesaContext wc);
static BOOL DDCreateOffScreen(WMesaContext wc);

// define this to use the GDI Rectangle call to
// clear the back buffer. Otherwise will manually
// set the pixels. On an NVidia GEForce 2MX under Windows XP
// and DirectX 8 , defining this makes apps run much much faster
#define USE_GDI_TO_CLEAR 1
#endif

static void FlushToFile(PWMC pwc, PSTR  szFile);
BOOL wmCreateBackingStore(PWMC pwc, long lxSize, long lySize);
BOOL wmDeleteBackingStore(PWMC pwc);
void wmCreatePalette( PWMC pwdc );
BOOL wmSetDibColors(PWMC pwc);
void wmSetPixel(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b);
BOOL wmFlush(PWMC pwc);
void wmCreateDIBSection(
    HDC  hDC,
    PWMC pwc,   // handle of device context
    CONST BITMAPINFO *pbmi, // bitmap size, format, and color data
    UINT iUsage // color data type indicator: RGB values or palette indices
    );
void WMesaViewport( GLcontext *ctx,
                    GLint x, GLint y, GLsizei width, GLsizei height );


static void wmSetPixelFormat( PWMC wc, HDC hDC)
{
  if(wc->rgb_flag)
    wc->cColorBits = GetDeviceCaps(hDC, BITSPIXEL);
  else
    wc->cColorBits = 8;
  switch(wc->cColorBits){
  case 8:
    if(wc->dither_flag != GL_TRUE)
      wc->pixelformat = PF_INDEX8;
    else
      wc->pixelformat = PF_DITHER8;
    break;
  case 16:
    wc->pixelformat = PF_5R6G5B;
    break;
  case 32:
    wc->pixelformat = PF_8R8G8B;
    break;
  default:
    wc->pixelformat = PF_BADFORMAT;
  }
}


/* This function sets the color table of a DIB section
 * to match that of the destination DC
 */
BOOL wmSetDibColors(PWMC pwc)
{
  RGBQUAD         *pColTab, *pRGB;
  PALETTEENTRY    *pPal, *pPE;
  int             i, nColors;
  BOOL            bRet=TRUE;
  DWORD           dwErr=0;
  
  /* Build a color table in the DIB that maps to the
   *  selected palette in the DC.
   */
  nColors = 1 << pwc->cColorBits;
  pPal = (PALETTEENTRY *)malloc( nColors * sizeof(PALETTEENTRY));
  memset( pPal, 0, nColors * sizeof(PALETTEENTRY) );
  GetPaletteEntries( pwc->hGLPalette, 0, nColors, pPal );
  pColTab = (RGBQUAD *)malloc( nColors * sizeof(RGBQUAD));
  for (i = 0, pRGB = pColTab, pPE = pPal; i < nColors; i++, pRGB++, pPE++) {
    pRGB->rgbRed = pPE->peRed;
    pRGB->rgbGreen = pPE->peGreen;
    pRGB->rgbBlue = pPE->peBlue;
  }
  if(pwc->db_flag)
    bRet = SetDIBColorTable(pwc->dib.hDC, 0, nColors, pColTab );
  
  if(!bRet)
    dwErr = GetLastError();
  
  free( pColTab );
  free( pPal );
  
  return bRet;
}


/*
 * Free up the dib section that was created
 */
BOOL wmDeleteBackingStore(PWMC pwc)
{
  SelectObject(pwc->dib.hDC, pwc->hOldBitmap);
  DeleteDC(pwc->dib.hDC);
  DeleteObject(pwc->hbmDIB);
#ifdef USE_MAPPED_FILE
  UnmapViewOfFile(pwc->dib.base);
  CloseHandle(pwc->dib.hFileMap);
#endif
  return TRUE;
}


/*
 * This function creates the DIB section that is used for combined
 * GL and GDI calls
 */
BOOL wmCreateBackingStore(PWMC pwc, long lxSize, long lySize)
{
  HDC hdc = pwc->hDC;
  LPBITMAPINFO pbmi = &(pwc->bmi);
  int     iUsage;
  
  pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  pbmi->bmiHeader.biWidth = lxSize;
  pbmi->bmiHeader.biHeight= -lySize;
  pbmi->bmiHeader.biPlanes = 1;
  if(pwc->rgb_flag)
    pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwc->hDC, BITSPIXEL);
  else
    pbmi->bmiHeader.biBitCount = 8;
  pbmi->bmiHeader.biCompression = BI_RGB;
  pbmi->bmiHeader.biSizeImage = 0;
  pbmi->bmiHeader.biXPelsPerMeter = 0;
  pbmi->bmiHeader.biYPelsPerMeter = 0;
  pbmi->bmiHeader.biClrUsed = 0;
  pbmi->bmiHeader.biClrImportant = 0;
  
  iUsage = (pbmi->bmiHeader.biBitCount <= 8) ? DIB_PAL_COLORS : DIB_RGB_COLORS;

  pwc->cColorBits = pbmi->bmiHeader.biBitCount;
  pwc->ScanWidth = pwc->pitch = lxSize;
  
  wmCreateDIBSection(hdc, pwc, pbmi, iUsage);
  
  if ((iUsage == DIB_PAL_COLORS) && !(pwc->hGLPalette)) {
    wmCreatePalette( pwc );
    wmSetDibColors( pwc );
  }
  wmSetPixelFormat(pwc, pwc->hDC);
  return TRUE;
}

#if 0
// D.R.S. 10/30/01 - this function is never referenced
/*
 * This function copies one scan line in a DIB section to another
 */
BOOL wmSetDIBits(PWMC pwc, UINT uiScanWidth, UINT uiNumScans, 
			UINT nBypp, UINT uiNewWidth, LPBYTE pBits)
{
  UINT    uiScans = 0;
  LPBYTE  pDest = pwc->pbPixels;
  DWORD   dwNextScan = uiScanWidth;
  DWORD   dwNewScan = uiNewWidth;
  DWORD   dwScanWidth = (uiScanWidth * nBypp);
  
  /*
   * We need to round up to the nearest DWORD
   * and multiply by the number of bytes per
   * pixel
   */
  dwNextScan = (((dwNextScan * nBypp)+ 3) & ~3);
  dwNewScan = (((dwNewScan * nBypp)+ 3) & ~3);
  
  for(uiScans = 0; uiScans < uiNumScans; uiScans++){
    CopyMemory(pDest, pBits, dwScanWidth);
    pBits += dwNextScan;
    pDest += dwNewScan;
  }
  return TRUE;
}
#endif // 0

#if defined(FAST_RASTERIZERS)

#define PIXELADDR(X,Y)  \
  ((GLubyte *)Current->pbPixels + (Current->height-Y-1)* \
  Current->ScanWidth + (X)*nBypp)
#define PIXELADDR1( X, Y )  \
((GLubyte *)wmesa->pbPixels + (wmesa->height-Y-1)* wmesa->ScanWidth + (X))
#define PIXELADDR2( X, Y )  \
((GLubyte *)wmesa->pbPixels + (wmesa->height-Y-1)* wmesa->ScanWidth + (X)*2)
#define PIXELADDR4( X, Y )  \
((GLubyte *)wmesa->pbPixels + (wmesa->height-Y-1)* wmesa->ScanWidth + (X)*4)

#endif // 0

BYTE DITHER_RGB_2_8BIT( int r, int g, int b, int x, int y);

/* Finish all pending operations and synchronize. */
static void finish(GLcontext* ctx)
{
  /* No op */
}


static void flush(GLcontext* ctx)
{
  if((Current->rgb_flag &&!(Current->db_flag))
     ||(!Current->rgb_flag))
    {
      wmFlush(Current);
    }
  
}



/*
 * Set the color index used to clear the color buffer.
 */
static void clear_index(GLcontext* ctx, GLuint index)
{
  Current->clearpixel = index;
}



/*
 * Set the color used to clear the color buffer.
 */
static void clear_color( GLcontext* ctx, const GLfloat color[4] )
{
  GLubyte col[4];
  CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]);
  CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]);
  CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]);
  Current->clearpixel = RGB(col[0], col[1], col[2]);
}


/* 
 * Clear the specified region of the color buffer using the clear color 
 * or index as specified by one of the two functions above. 
 * 
 * This procedure clears either the front and/or the back COLOR buffers. 
 * Only the "left" buffer is cleared since we are not stereo. 
 * Clearing of the other non-color buffers is left to the swrast. 
 * We also only clear the color buffers if the color masks are all 1's. 
 * Otherwise, we let swrast do it. 
 */ 

static clear(GLcontext* ctx, GLbitfield mask, 
      GLboolean all, GLint x, GLint y, GLint width, GLint height) 
{ 
  const   GLuint *colorMask = (GLuint *) &ctx->Color.ColorMask; 
  
  if (all){ 
    x=y=0; 
    width=Current->width; 
    height=Current->height; 
  } 
  
  
  /* sanity check - can't have right(stereo) buffers */ 
  assert((mask & (DD_FRONT_RIGHT_BIT | DD_BACK_RIGHT_BIT)) == 0); 
  
  /* clear alpha */
  if ((mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT)) &&
      ctx->DrawBuffer->UseSoftwareAlphaBuffers &&
      ctx->Color.ColorMask[ACOMP]) {
      _mesa_clear_alpha_buffers( ctx );
  }

  if (*colorMask == 0xffffffff && ctx->Color.IndexMask == 0xffffffff) { 
      if (mask & DD_BACK_LEFT_BIT) { 
#if defined(USE_GDI_TO_CLEAR) 
#if defined(DDRAW) 
 // D.R.S. 10/29/01 on my system (Pentium 4 with nvidia GeForce2 MX card, 
 // this is almose 100 times faster that the code below 
 HDC DC=NULL; 
 HPEN Pen=CreatePen(PS_SOLID,1,Current->clearpixel); 
 HBRUSH Brush=CreateSolidBrush(Current->clearpixel); 
 HPEN Old_Pen=NULL; 
 HBRUSH Old_Brush=NULL; 
 Current->lpDDSOffScreen->lpVtbl->Unlock(Current->lpDDSOffScreen,NULL); 
 Current->lpDDSOffScreen->lpVtbl->GetDC(Current->lpDDSOffScreen,&DC); 
 Old_Pen=SelectObject(DC,Pen); 
 Old_Brush=SelectObject(DC,Brush); 
 Rectangle(DC,x,y,x+width,y+height); 
 SelectObject(DC,Old_Pen); 
 SelectObject(DC,Old_Brush); 
 DeleteObject(Pen); 
 DeleteObject(Brush); 
 Current->lpDDSOffScreen->lpVtbl->ReleaseDC(Current->lpDDSOffScreen,DC); 
 while (Current->lpDDSOffScreen->lpVtbl->Lock(Current->lpDDSOffScreen,NULL, &(Current->ddsd), 0, NULL) == DDERR_WASSTILLDRAWING);

   mask &= ~DD_BACK_LEFT_BIT; 
#else 
   /* single-buffer */ 
   HDC DC=DD_GETDC; 
   HPEN Pen=CreatePen(PS_SOLID,1,Current->clearpixel); 
   HBRUSH Brush=CreateSolidBrush(Current->clearpixel); 
   HPEN Old_Pen=SelectObject(DC,Pen); 
   HBRUSH Old_Brush=SelectObject(DC,Brush); 
   Rectangle(DC,x+Current->rectSurface.left,Current->rectSurface.top+y,x+width+Current->rectSurface.left,y+height+Current->rectSurface.top);

   SelectObject(DC,Old_Pen); 
   SelectObject(DC,Old_Brush); 
   DeleteObject(Pen); 
   DeleteObject(Brush); 
   DD_RELEASEDC; 
   mask &= ~DD_BACK_LEFT_BIT; 
#endif // DDRAW 
#else 
   DWORD   dwColor; 
   WORD    wColor; 
   BYTE    bColor; 
   LPDWORD lpdw = (LPDWORD)Current->pbPixels; 
   LPWORD  lpw = (LPWORD)Current->pbPixels; 
   LPBYTE  lpb = Current->pbPixels; 
   int     lines; 
   /* Double-buffering - clear back buffer */ 
   UINT    nBypp = Current->cColorBits / 8; 
   int     i = 0; 
   int     iSize = 0; 
   int   mult = 4; 

   
   assert(Current->db_flag==GL_TRUE); /* we'd better be double buffer */ 
   if(nBypp ==1 ){ 
       iSize = Current->width/4; 
       bColor  = BGR8(GetRValue(Current->clearpixel), 
        GetGValue(Current->clearpixel), 
        GetBValue(Current->clearpixel)); 
       wColor  = MAKEWORD(bColor,bColor); 
       dwColor = MAKELONG(wColor, wColor); 
   } 
   else if(nBypp == 2){ 
       iSize = Current->width / 2; 
       wColor = BGR16(GetRValue(Current->clearpixel), 
        GetGValue(Current->clearpixel), 
        GetBValue(Current->clearpixel)); 
       dwColor = MAKELONG(wColor, wColor); 
   } 
   else if(nBypp == 3){ 
      BYTE r, g, b; 
      r = GetRValue(Current->clearpixel); 
      g = GetGValue(Current->clearpixel); 
      b = GetBValue(Current->clearpixel); 
      iSize = Current->width; 
      while (i < iSize) { 
        *lpb++ = b; 
        *lpb++ = g; 
        *lpb++ = r; 
        i++; 
      } 
      lpb = Current->pbPixels + Current->ScanWidth; 
      mult = 3; 
   }   
   else if(nBypp == 4){ 
       iSize = Current->width; 
       dwColor = BGR32(GetRValue(Current->clearpixel), 
         GetGValue(Current->clearpixel), 
         GetBValue(Current->clearpixel)); 
   } 

   if (nBypp != 3) 
   { 
      /* clear a line */ 
    while(i < iSize){ 
        *lpdw = dwColor; 
     lpdw++; 
        i++; 
    } 
   } 
   
   i = 0; 
   if (stereo_flag) 
       lines = height /2; 
   else 
       lines = height; 
   /* copy cleared line to other lines in buffer */ 
   do { 
       memcpy(lpb, Current->pbPixels, iSize*mult); 
       lpb += Current->ScanWidth; 
       i++; 
   } 
   while (i<lines-1); 
   mask &= ~DD_BACK_LEFT_BIT; 
#endif // defined(USE_GDI_TO_CLEAR) 
      } /* double-buffer */ 
      
      if (mask & DD_FRONT_LEFT_BIT) { 
   /* single-buffer */ 
   HDC DC=DD_GETDC; 
   HPEN Pen=CreatePen(PS_SOLID,1,Current->clearpixel); 
   HBRUSH Brush=CreateSolidBrush(Current->clearpixel); 
   HPEN Old_Pen=SelectObject(DC,Pen); 
   HBRUSH Old_Brush=SelectObject(DC,Brush); 
   Rectangle(DC,x+Current->rectSurface.left,Current->rectSurface.top+y,x+width+Current->rectSurface.left,y+height+Current->rectSurface.top);

   SelectObject(DC,Old_Pen); 
   SelectObject(DC,Old_Brush); 
   DeleteObject(Pen); 
   DeleteObject(Brush); 
   DD_RELEASEDC; 
   mask &= ~DD_FRONT_LEFT_BIT; 
      } /* single-buffer */ 
  } /* if masks are all 1's */ 
    
  /* Call swrast if there is anything left to clear (like DEPTH) */ 
  if (mask) 
      _swrast_Clear( ctx, mask, all, x, y, width, height ); 
} 


static void enable( GLcontext* ctx, GLenum pname, GLboolean enable )
{
  if (!Current)
    return;
  
  if (pname == GL_DITHER) {
    if(enable == GL_FALSE){
      Current->dither_flag = GL_FALSE;
      if(Current->cColorBits == 8)
	Current->pixelformat = PF_INDEX8;
    }
    else{
      if (Current->rgb_flag && Current->cColorBits == 8){
	Current->pixelformat = PF_DITHER8;
	Current->dither_flag = GL_TRUE;
      }
      else
	Current->dither_flag = GL_FALSE;
    }
  }
}



static void set_buffer(GLcontext *ctx, GLframebuffer *colorBuffer,
                       GLuint bufferBit )
{
  /* XXX todo - examine bufferBit and set read/write pointers */
  return;
}



/* Return characteristics of the output buffer. */
static void buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
{
  GET_CURRENT_CONTEXT(ctx);
  int New_Size;
  RECT CR;
  
  GetClientRect(Current->Window,&CR);
  
   *width=CR.right;
   *height=CR.bottom;
   
   New_Size=((*width)!=Current->width) || ((*height)!=Current->height);
   
   if (New_Size){
     Current->width=*width;
     Current->height=*height;
     Current->ScanWidth=Current->width;
     if ((Current->ScanWidth%sizeof(long))!=0)
       Current->ScanWidth+=(sizeof(long)-(Current->ScanWidth%sizeof(long)));
     
     if (Current->db_flag){
#ifdef DDRAW
       DDDeleteOffScreen(Current);
       DDCreateOffScreen(Current);
#else
       if (Current->rgb_flag==GL_TRUE && Current->dither_flag!=GL_TRUE){
	 wmDeleteBackingStore(Current);
	 wmCreateBackingStore(Current, Current->width, Current->height);
       }
#endif
     }
     
     /*  Resize OsmesaBuffer if in Parallel mode */
#if !defined(NO_PARALLEL)
     if(parallelFlag)
       PRSizeRenderBuffer(Current->width, Current->height,Current->ScanWidth,
			  Current->rgb_flag == GL_TRUE ? Current->pbPixels: 
			  Current->ScreenMem);
#endif
   }
}



/**********************************************************************/
/*****           Accelerated point, line, polygon rendering       *****/
/**********************************************************************/

/* Accelerated routines are not implemented in 4.0. See OSMesa for ideas. */

static void fast_rgb_points( GLcontext* ctx, GLuint first, GLuint last )
{
}

/* Return pointer to accelerated points function */
extern points_func choose_points_function( GLcontext* ctx )
{
  return NULL;
}

static void fast_flat_rgb_line( GLcontext* ctx, GLuint v0, 
				GLuint v1, GLuint pv )
{
}

static line_func choose_line_function( GLcontext* ctx )
{
}


/**********************************************************************/
/*****                 Span-based pixel drawing                   *****/
/**********************************************************************/


/* Write a horizontal span of 32-bit color-index pixels with a boolean mask. */
static void write_ci32_span( const GLcontext* ctx,
                             GLuint n, GLint x, GLint y,
                             const GLuint index[],
                             const GLubyte mask[] )
{
  GLuint i;
  PBYTE Mem=Current->ScreenMem+FLIP(y)*Current->ScanWidth+x;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++)
    if (mask[i])
      Mem[i]=index[i];
}


/* Write a horizontal span of 8-bit color-index pixels with a boolean mask. */
static void write_ci8_span( const GLcontext* ctx,
                            GLuint n, GLint x, GLint y,
                            const GLubyte index[],
                            const GLubyte mask[] )
{
  GLuint i;
  PBYTE Mem=Current->ScreenMem+FLIP(y)*Current->ScanWidth+x;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++)
    if (mask[i])
      Mem[i]=index[i];
}



/*
 * Write a horizontal span of pixels with a boolean mask.  The current
 * color index is used for all pixels.
 */
static void write_mono_ci_span(const GLcontext* ctx,
                               GLuint n,GLint x,GLint y,
                               GLuint colorIndex, const GLubyte mask[])
{
  GLuint i;
  BYTE *Mem=Current->ScreenMem+FLIP(y)*Current->ScanWidth+x;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++)
    if (mask[i])
      Mem[i]=colorIndex;
}

/*
 * To improve the performance of this routine, frob the data into an actual
 * scanline and call bitblt on the complete scan line instead of SetPixel.
 */

/* Write a horizontal span of RGBA color pixels with a boolean mask. */
static void write_rgba_span( const GLcontext* ctx, GLuint n, GLint x, GLint y,
                             const GLubyte rgba[][4], const GLubyte mask[] )
{
  PWMC    pwc = Current;
  
  if (pwc->rgb_flag==GL_TRUE)
    {
      GLuint i;
      HDC DC=DD_GETDC;
      y=FLIP(y);
      if (mask) {
	for (i=0; i<n; i++)
	  if (mask[i])
	    wmSetPixel(pwc, y, x + i, 
		       rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
      }
      else {
	for (i=0; i<n; i++)
	  wmSetPixel(pwc, y, x + i, 
		     rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP] );
      }
      DD_RELEASEDC;
    }
  else
    {
      GLuint i;
      BYTE *Mem=Current->ScreenMem+y*Current->ScanWidth+x;
      y = FLIP(y);
      if (mask) {
	for (i=0; i<n; i++)
	  if (mask[i])
	    Mem[i] = GetNearestPaletteIndex(Current->hPal, 
					    RGB(rgba[i][RCOMP], 
						rgba[i][GCOMP], 
						rgba[i][BCOMP]));
      }
      else {
	for (i=0; i<n; i++)
	  Mem[i] = GetNearestPaletteIndex(Current->hPal,
					  RGB(rgba[i][RCOMP], 
					      rgba[i][GCOMP], 
					      rgba[i][BCOMP]));
      }
    }
}

/* Write a horizontal span of RGB color pixels with a boolean mask. */
static void write_rgb_span( const GLcontext* ctx,
                            GLuint n, GLint x, GLint y,
                            const GLubyte rgb[][3], const GLubyte mask[] )
{
  PWMC    pwc = Current;
  
  if (pwc->rgb_flag==GL_TRUE)
    {
      GLuint i;
      HDC DC=DD_GETDC;
      y=FLIP(y);
      if (mask) {
	for (i=0; i<n; i++)
	  if (mask[i])
	    wmSetPixel(pwc, y, x + i, 
		       rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP]);
      }
      else {
	for (i=0; i<n; i++)
	  wmSetPixel(pwc, y, x + i, 
		     rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP] );
      }
      DD_RELEASEDC;
    }
  else
    {
      GLuint i;
      BYTE *Mem=Current->ScreenMem+y*Current->ScanWidth+x;
      y = FLIP(y);
      if (mask) {
	for (i=0; i<n; i++)
	  if (mask[i])
	    Mem[i] = GetNearestPaletteIndex(Current->hPal,
					    RGB(rgb[i][RCOMP], 
						rgb[i][GCOMP], 
						rgb[i][BCOMP]));
      }
      else {
	for (i=0; i<n; i++)
	  Mem[i] = GetNearestPaletteIndex(Current->hPal,
					  RGB(rgb[i][RCOMP], 
					      rgb[i][GCOMP], 
					      rgb[i][BCOMP]));
      }
    }
}

/*
 * Write a horizontal span of pixels with a boolean mask.  The current color
 * is used for all pixels.
 */
static void write_mono_rgba_span( const GLcontext* ctx,
                                  GLuint n, GLint x, GLint y,
                                  const GLchan color[4], const GLubyte mask[])
{
  GLuint i;
  PWMC pwc = Current;
  assert(Current->rgb_flag==GL_TRUE);
  y=FLIP(y);
  if(Current->rgb_flag==GL_TRUE)
  {
	for (i=0; i<n; i++)
		if (mask[i])
			wmSetPixel(pwc,y,x+i,color[RCOMP], color[GCOMP], color[BCOMP]);
  }
  else
  {
	HDC DC=DD_GETDC;
    ULONG pixel =  RGB( color[RCOMP], color[GCOMP], color[BCOMP] );
    for (i=0; i<n; i++)
      if (mask[i])
		SetPixel(DC, y, x+i, pixel);
	  DD_RELEASEDC;
  }
}



/**********************************************************************/
/*****                   Array-based pixel drawing                *****/
/**********************************************************************/


/* Write an array of 32-bit index pixels with a boolean mask. */
static void write_ci32_pixels( const GLcontext* ctx,
                               GLuint n, const GLint x[], const GLint y[],
                               const GLuint index[], const GLubyte mask[] )
{
  GLuint i;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++) {
    if (mask[i]) {
      BYTE *Mem=Current->ScreenMem+FLIP(y[i])*Current->ScanWidth+x[i];
      *Mem = index[i];
    }
  }
}



/*
 * Write an array of pixels with a boolean mask.  The current color
 * index is used for all pixels.
 */
static void write_mono_ci_pixels( const GLcontext* ctx,
                                  GLuint n,
                                  const GLint x[], const GLint y[],
                                  GLuint colorIndex, const GLubyte mask[] )
{
  GLuint i;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++) {
    if (mask[i]) {
      BYTE *Mem=Current->ScreenMem+FLIP(y[i])*Current->ScanWidth+x[i];
      *Mem = colorIndex;
    }
  }
}



/* Write an array of RGBA pixels with a boolean mask. */
static void write_rgba_pixels( const GLcontext* ctx,
                               GLuint n, const GLint x[], const GLint y[],
                               const GLubyte rgba[][4], const GLubyte mask[] )
{
  GLuint i;
  PWMC    pwc = Current;
  HDC DC=DD_GETDC;
  assert(Current->rgb_flag==GL_TRUE);
  for (i=0; i<n; i++)
    if (mask[i])
      wmSetPixel(pwc, FLIP(y[i]), x[i],
		 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
  DD_RELEASEDC;
}



/*
 * Write an array of pixels with a boolean mask.  The current color
 * is used for all pixels.
 */
static void write_mono_rgba_pixels( const GLcontext* ctx,
                                    GLuint n,
                                    const GLint x[], const GLint y[],
                                    const GLchan color[4],
                                    const GLubyte mask[] )
{
  GLuint i;
  PWMC    pwc = Current;
  HDC DC=DD_GETDC;
  assert(Current->rgb_flag==GL_TRUE);
  for (i=0; i<n; i++)
    if (mask[i])
      wmSetPixel(pwc, FLIP(y[i]),x[i],color[RCOMP],
		 color[GCOMP], color[BCOMP]);
  DD_RELEASEDC;
}



/**********************************************************************/
/*****            Read spans/arrays of pixels                     *****/
/**********************************************************************/


/* Read a horizontal span of color-index pixels. */
static void read_ci32_span( const GLcontext* ctx, GLuint n, GLint x, GLint y,
                            GLuint index[])
{
  GLuint i;
  BYTE *Mem=Current->ScreenMem+FLIP(y)*Current->ScanWidth+x;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++)
    index[i]=Mem[i];
}




/* Read an array of color index pixels. */
static void read_ci32_pixels( const GLcontext* ctx,
                              GLuint n, const GLint x[], const GLint y[],
                              GLuint indx[], const GLubyte mask[] )
{
  GLuint i;
  assert(Current->rgb_flag==GL_FALSE);
  for (i=0; i<n; i++) {
    if (mask[i]) {
      indx[i]=*(Current->ScreenMem+FLIP(y[i])*Current->ScanWidth+x[i]);
    }
  }
}



/* Read a horizontal span of color pixels. */
static void read_rgba_span( const GLcontext* ctx,
                            GLuint n, GLint x, GLint y,
                            GLubyte rgba[][4] )
{
  UINT i;
  COLORREF Color;
  HDC DC=DD_GETDC;
  assert(Current->rgb_flag==GL_TRUE);
  y = Current->height - y - 1;
  for (i=0; i<n; i++) {
    Color=GetPixel(DC,x+i,y);
    rgba[i][RCOMP] = GetRValue(Color);
    rgba[i][GCOMP] = GetGValue(Color);
    rgba[i][BCOMP] = GetBValue(Color);
    rgba[i][ACOMP] = 255;
  }
  DD_RELEASEDC;
}


/* Read an array of color pixels. */
static void read_rgba_pixels( const GLcontext* ctx,
                              GLuint n, const GLint x[], const GLint y[],
                              GLubyte rgba[][4], const GLubyte mask[] )
{
  GLuint i;
  COLORREF Color;
  HDC DC=DD_GETDC;
  assert(Current->rgb_flag==GL_TRUE);
  for (i=0; i<n; i++) {
    if (mask[i]) {
      GLint y2 = Current->height - y[i] - 1;
      Color=GetPixel(DC,x[i],y2);
      rgba[i][RCOMP] = GetRValue(Color);
      rgba[i][GCOMP] = GetGValue(Color);
      rgba[i][BCOMP] = GetBValue(Color);
      rgba[i][ACOMP] = 255;
    }
  }
  DD_RELEASEDC;
}



/**********************************************************************/
/**********************************************************************/


static const GLubyte *get_string(GLcontext *ctx, GLenum name)
{
  if (name == GL_RENDERER) {
    return (GLubyte *) "Mesa Windows";
  }
  else {
    return NULL;
  }
}

static void wmesa_update_state( GLcontext *ctx, GLuint new_state );

static void SetFunctionPointers(GLcontext *ctx)
{
  struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference( ctx );
  ctx->Driver.GetString = get_string;
  ctx->Driver.UpdateState = wmesa_update_state;
  ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
  ctx->Driver.GetBufferSize = buffer_size;
  
  ctx->Driver.Accum = _swrast_Accum;
  ctx->Driver.Bitmap = _swrast_Bitmap;
  ctx->Driver.Clear = clear;
  
  ctx->Driver.Flush = flush;
  ctx->Driver.ClearIndex = clear_index;
  ctx->Driver.ClearColor = clear_color;
  ctx->Driver.Enable = enable;
  
  ctx->Driver.CopyPixels = _swrast_CopyPixels;
  ctx->Driver.DrawPixels = _swrast_DrawPixels;
  ctx->Driver.ReadPixels = _swrast_ReadPixels;
  ctx->Driver.DrawBuffer = _swrast_DrawBuffer;
  
  ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format;
  ctx->Driver.TexImage1D = _mesa_store_teximage1d;
  ctx->Driver.TexImage2D = _mesa_store_teximage2d;
  ctx->Driver.TexImage3D = _mesa_store_teximage3d;
  ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
  ctx->Driver.TexSubImage2D = _mesa_store_texsubimage2d;
  ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
  ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
  
  ctx->Driver.CompressedTexImage1D = _mesa_store_compressed_teximage1d;
  ctx->Driver.CompressedTexImage2D = _mesa_store_compressed_teximage2d;
  ctx->Driver.CompressedTexImage3D = _mesa_store_compressed_teximage3d;
  ctx->Driver.CompressedTexSubImage1D = _mesa_store_compressed_texsubimage1d;
  ctx->Driver.CompressedTexSubImage2D = _mesa_store_compressed_texsubimage2d;
  ctx->Driver.CompressedTexSubImage3D = _mesa_store_compressed_texsubimage3d;

  ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
  ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
  ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
  ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
  ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
  ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
  ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
  ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
  ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;

  swdd->SetBuffer = set_buffer;

  /* Pixel/span writing functions: */
  swdd->WriteRGBASpan        = write_rgba_span;
  swdd->WriteRGBSpan         = write_rgb_span;
  swdd->WriteMonoRGBASpan    = write_mono_rgba_span;
  swdd->WriteRGBAPixels      = write_rgba_pixels;
  swdd->WriteMonoRGBAPixels  = write_mono_rgba_pixels;
  swdd->WriteCI32Span        = write_ci32_span;
  swdd->WriteCI8Span         = write_ci8_span;
  swdd->WriteMonoCISpan      = write_mono_ci_span;
  swdd->WriteCI32Pixels      = write_ci32_pixels;
  swdd->WriteMonoCIPixels    = write_mono_ci_pixels;
  
  swdd->ReadCI32Span        = read_ci32_span;
  swdd->ReadRGBASpan        = read_rgba_span;
  swdd->ReadCI32Pixels      = read_ci32_pixels;
  swdd->ReadRGBAPixels      = read_rgba_pixels;
 
}

static void wmesa_update_state( GLcontext *ctx, GLuint new_state )
{
  struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference( ctx );
  TNLcontext *tnl = TNL_CONTEXT(ctx);
  
  /*
   * XXX these function pointers could be initialized just once during
   * context creation since they don't depend on any state changes.
   * kws - This is true - this function gets called a lot and it
   * would be good to minimize setting all this when not needed.
   */
#ifndef SET_FPOINTERS_ONCE  
  SetFunctionPointers(ctx);
#if 0
  ctx->Driver.GetString = get_string;
  ctx->Driver.UpdateState = wmesa_update_state;
  ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
  ctx->Driver.GetBufferSize = buffer_size;
  
  ctx->Driver.Accum = _swrast_Accum;
  ctx->Driver.Bitmap = _swrast_Bitmap;
  ctx->Driver.Clear = clear;
  
  ctx->Driver.Flush = flush;
  ctx->Driver.ClearIndex = clear_index;
  ctx->Driver.ClearColor = clear_color;
  ctx->Driver.Enable = enable;
  
  ctx->Driver.CopyPixels = _swrast_CopyPixels;
  ctx->Driver.DrawPixels = _swrast_DrawPixels;
  ctx->Driver.ReadPixels = _swrast_ReadPixels;
  
  ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format;
  ctx->Driver.TexImage1D = _mesa_store_teximage1d;
  ctx->Driver.TexImage2D = _mesa_store_teximage2d;
  ctx->Driver.TexImage3D = _mesa_store_teximage3d;
  ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
  ctx->Driver.TexSubImage2D = _mesa_store_texsubimage2d;
  ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
  ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
  
  ctx->Driver.CompressedTexImage1D = _mesa_store_compressed_teximage1d;
  ctx->Driver.CompressedTexImage2D = _mesa_store_compressed_teximage2d;
  ctx->Driver.CompressedTexImage3D = _mesa_store_compressed_teximage3d;
  ctx->Driver.CompressedTexSubImage1D = _mesa_store_compressed_texsubimage1d;
  ctx->Driver.CompressedTexSubImage2D = _mesa_store_compressed_texsubimage2d;
  ctx->Driver.CompressedTexSubImage3D = _mesa_store_compressed_texsubimage3d;

  ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
  ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
  ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
  ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
  ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
  ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
  ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
  ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
  ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
  
  swdd->SetBuffer = set_buffer;
  
  /* Pixel/span writing functions: */
  swdd->WriteRGBASpan        = write_rgba_span;
  swdd->WriteRGBSpan         = write_rgb_span;
  swdd->WriteMonoRGBASpan    = write_mono_rgba_span;
  swdd->WriteRGBAPixels      = write_rgba_pixels;
  swdd->WriteMonoRGBAPixels  = write_mono_rgba_pixels;
  swdd->WriteCI32Span        = write_ci32_span;
  swdd->WriteCI8Span         = write_ci8_span;
  swdd->WriteMonoCISpan      = write_mono_ci_span;
  swdd->WriteCI32Pixels      = write_ci32_pixels;
  swdd->WriteMonoCIPixels    = write_mono_ci_pixels;
  
  swdd->ReadCI32Span        = read_ci32_span;
  swdd->ReadRGBASpan        = read_rgba_span;
  swdd->ReadCI32Pixels      = read_ci32_pixels;
  swdd->ReadRGBAPixels      = read_rgba_pixels;
#endif // 0  
#endif //  !SET_FPOINTERS_ONCE  
  tnl->Driver.RunPipeline = _tnl_run_pipeline;
  
  _swrast_InvalidateState( ctx, new_state );
  _swsetup_InvalidateState( ctx, new_state );
  _ac_InvalidateState( ctx, new_state );
  _tnl_InvalidateState( ctx, new_state );
}




/**********************************************************************/
/*****                  WMesa API Functions                       *****/
/**********************************************************************/



#define PAL_SIZE 256
static void GetPalette(HPALETTE Pal,RGBQUAD *aRGB)
{
  int i;
  HDC hdc;
  struct
  {
    WORD Version;
    WORD NumberOfEntries;
    PALETTEENTRY aEntries[PAL_SIZE];
  } Palette =
    {
      0x300,
      PAL_SIZE
    };
  hdc=GetDC(NULL);
  if (Pal!=NULL)
    GetPaletteEntries(Pal,0,PAL_SIZE,Palette.aEntries);
  else
    GetSystemPaletteEntries(hdc,0,PAL_SIZE,Palette.aEntries);
  if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC)
    {
      for(i = 0; i <PAL_SIZE; i++)
	Palette.aEntries[i].peFlags = PC_RESERVED;
      Palette.aEntries[255].peRed = 255;
      Palette.aEntries[255].peGreen = 255;
      Palette.aEntries[255].peBlue = 255;
      Palette.aEntries[255].peFlags = 0;
      Palette.aEntries[0].peRed = 0;
      Palette.aEntries[0].peGreen = 0;
      Palette.aEntries[0].peBlue = 0;
      Palette.aEntries[0].peFlags = 0;
    }
  else
    {
      int nStaticColors;
      int nUsableColors;
      nStaticColors = GetDeviceCaps(hdc, NUMCOLORS)/2;
      for (i=0; i<nStaticColors; i++)
	Palette.aEntries[i].peFlags = 0;
      nUsableColors = PAL_SIZE-nStaticColors;
      for (; i<nUsableColors; i++)
	Palette.aEntries[i].peFlags = PC_RESERVED;
      for (; i<PAL_SIZE-nStaticColors; i++)
	Palette.aEntries[i].peFlags = PC_RESERVED;
      for (i=PAL_SIZE-nStaticColors; i<PAL_SIZE; i++)
	Palette.aEntries[i].peFlags = 0;
    }
  ReleaseDC(NULL,hdc);
  for (i=0; i<PAL_SIZE; i++)
    {
      aRGB[i].rgbRed=Palette.aEntries[i].peRed;
      aRGB[i].rgbGreen=Palette.aEntries[i].peGreen;
      aRGB[i].rgbBlue=Palette.aEntries[i].peBlue;
      aRGB[i].rgbReserved=Palette.aEntries[i].peFlags;
    }
}


WMesaContext WMesaCreateContext( HWND hWnd, HPALETTE* Pal,
				 GLboolean rgb_flag,
				 GLboolean db_flag,
                                 GLboolean alpha_flag )
{
  RECT CR;
  WMesaContext c;
  GLboolean true_color_flag;

  c = (struct wmesa_context * ) calloc(1,sizeof(struct wmesa_context));
  if (!c)
    return NULL;
  
  c->Window=hWnd;
  c->hDC = GetDC(hWnd);
  true_color_flag = GetDeviceCaps(c->hDC, BITSPIXEL) > 8;
#ifdef DDRAW
  if(true_color_flag) c->rgb_flag = rgb_flag = GL_TRUE;
#endif
  
  
#ifdef DITHER
  if ((true_color_flag==GL_FALSE) && (rgb_flag == GL_TRUE)){
    c->dither_flag = GL_TRUE;
#ifdef USE_WING
    c->hPalHalfTone = WinGCreateHalftonePalette();
#else
	c->hPalHalfTone = CreateHalftonePalette(c->hDC);
#endif
  }
  else
    c->dither_flag = GL_FALSE;
#else
  c->dither_flag = GL_FALSE;
#endif
  
  
  if (rgb_flag==GL_FALSE)
    {
      c->rgb_flag = GL_FALSE;
#if 0
      /* Old WinG stuff???? */
      c->db_flag = db_flag =GL_TRUE; /* WinG requires double buffering */
      printf("Single buffer is not supported in color index mode, ",
	     "setting to double buffer.\n");
#endif
    }
  else
    {
      c->rgb_flag = GL_TRUE;
    }
  GetClientRect(c->Window,&CR);
  c->width=CR.right;
  c->height=CR.bottom;
  if (db_flag)
    {
      c->db_flag = 1;
      /* Double buffered */
#ifndef DDRAW
      {
	wmCreateBackingStore(c, c->width, c->height);
	
      }
#endif
    }
  else
    {
      /* Single Buffered */
      if (c->rgb_flag)
	c->db_flag = 0;
    }
#ifdef DDRAW
  if (DDInit(c,hWnd) == GL_FALSE) {
    free( (void *) c );
    exit(1);
  }
#endif
  
  
  c->gl_visual = _mesa_create_visual(rgb_flag,
				     db_flag,    /* db_flag */
				     GL_FALSE,   /* stereo */
				     8,8,8,      /* r, g, b bits */
                                     alpha_flag ? 8 : 0, /* alpha bits */
				     0,          /* index bits */
				     16,         /* depth_bits */
				     8,          /* stencil_bits */
				     16,16,16,/* accum_bits */
                                     alpha_flag ? 16 : 0, /* alpha accum */
				     1);
  
  if (!c->gl_visual) {
    return NULL;
  }
  
  /* allocate a new Mesa context */
  c->gl_ctx = _mesa_create_context( c->gl_visual, NULL, (void *) c, GL_FALSE );
  
  if (!c->gl_ctx) {
    _mesa_destroy_visual( c->gl_visual );
    free(c);
    return NULL;
  }
  
  _mesa_enable_sw_extensions(c->gl_ctx);
  _mesa_enable_1_3_extensions(c->gl_ctx);
  _mesa_enable_1_4_extensions(c->gl_ctx);

  c->gl_buffer = _mesa_create_framebuffer( c->gl_visual,
					   c->gl_visual->depthBits > 0,
					   c->gl_visual->stencilBits > 0,
					   c->gl_visual->accumRedBits > 0,
					   alpha_flag /* s/w alpha */ );
  if (!c->gl_buffer) {
    _mesa_destroy_visual( c->gl_visual );
    _mesa_free_context_data( c->gl_ctx );
    free(c);
    return NULL;
  }
  
  /* Initialize the software rasterizer and helper modules.
   */
  {
    GLcontext *ctx = c->gl_ctx;
    _swrast_CreateContext( ctx );
    _ac_CreateContext( ctx );
    _tnl_CreateContext( ctx );
    _swsetup_CreateContext( ctx );
    
#ifdef SET_FPOINTERS_ONCE
    SetFunctionPointers(ctx);
#endif // SET_FPOINTERS_ONCE
    _swsetup_Wakeup( ctx );
  }
#ifdef COMPILE_SETPIXEL
  ChooseSetPixel(c);
#endif
  return c;
}

void WMesaDestroyContext( void )
{
  WMesaContext c = Current;
  ReleaseDC(c->Window,c->hDC);
  WC = c;
  if(c->hPalHalfTone != NULL)
    DeleteObject(c->hPalHalfTone);

  _swsetup_DestroyContext( c->gl_ctx );
  _tnl_DestroyContext( c->gl_ctx );
  _ac_DestroyContext( c->gl_ctx );
  _swrast_DestroyContext( c->gl_ctx );
  
  _mesa_destroy_visual( c->gl_visual );
  _mesa_destroy_framebuffer( c->gl_buffer );
  _mesa_free_context_data( c->gl_ctx );
  free( (void *) c->gl_ctx);
    
  if (c->db_flag)
#ifdef DDRAW
    DDFree(c);
#else
  wmDeleteBackingStore(c);
#endif
  free( (void *) c );
#if !defined(NO_PARALLEL)
  if(parallelMachine)
    PRDestroyRenderBuffer();
#endif

  // Destroyed context no longer valid
  WMesaMakeCurrent( NULL );
}


void WMesaMakeCurrent( WMesaContext c )
{
  if(!c){
    Current = c;
    return;
  }
  
  if(Current == c)
    return;
  
  Current = c;
  wmesa_update_state(c->gl_ctx, 0);
  _mesa_make_current(c->gl_ctx, c->gl_buffer);
  if (Current->gl_ctx->Viewport.Width==0) {
    /* initialize viewport to window size */
    _mesa_Viewport( 0, 0, Current->width, Current->height );
    Current->gl_ctx->Scissor.Width = Current->width;
    Current->gl_ctx->Scissor.Height = Current->height;
  }
  if ((c->cColorBits <= 8 ) && (c->rgb_flag == GL_TRUE)){
    WMesaPaletteChange(c->hPalHalfTone);
  }
}



void WMesaSwapBuffers( void )
{
  HDC DC = Current->hDC;
  GET_CURRENT_CONTEXT(ctx);
  
  /* If we're swapping the buffer associated with the current context
   * we have to flush any pending rendering commands first.
   */
  if (Current && Current->gl_ctx == ctx)
    _mesa_notifySwapBuffers(ctx);
  
  if (Current->db_flag)
    wmFlush(Current);
}



void WMesaPaletteChange(HPALETTE Pal)
{
#ifndef DDRAW
  int vRet;
#endif
  LPPALETTEENTRY pPal;
  if (Current && (Current->rgb_flag==GL_FALSE || 
		  Current->dither_flag == GL_TRUE))
    {
      pPal = (PALETTEENTRY *)malloc( 256 * sizeof(PALETTEENTRY));
      Current->hPal=Pal;
      GetPaletteEntries( Pal, 0, 256, pPal );
#ifdef DDRAW
      Current->lpDD->lpVtbl->CreatePalette(Current->lpDD,DDPCAPS_8BIT,
					   pPal, &(Current->lpDDPal), NULL);
      if (Current->lpDDPal)
	Current->lpDDSPrimary->lpVtbl->SetPalette(Current->lpDDSPrimary,
						  Current->lpDDPal);
#else
      vRet = SetDIBColorTable(Current->dib.hDC, 0, 256, (RGBQUAD*)pPal);
#endif
      free( pPal );
    }
}




static unsigned char threeto8[8] = {
  0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};

static unsigned char twoto8[4] = {
  0, 0x55, 0xaa, 0xff
};

static unsigned char oneto8[2] = {
  0, 255
};

static unsigned char componentFromIndex(UCHAR i, UINT nbits, UINT shift)
{
  unsigned char val;
  
  val = i >> shift;
  switch (nbits) {
    
  case 1:
    val &= 0x1;
    return oneto8[val];
    
  case 2:
    val &= 0x3;
    return twoto8[val];
    
  case 3:
    val &= 0x7;
    return threeto8[val];
    
  default:
    return 0;
  }
}

void wmCreatePalette( PWMC pwdc )
{
  /* Create a compressed and re-expanded 3:3:2 palette */
  int            i;
  LOGPALETTE     *pPal;
  BYTE           rb, rs, gb, gs, bb, bs;
  
  pwdc->nColors = 0x100;
  
  pPal = (PLOGPALETTE)malloc(sizeof(LOGPALETTE) + 
			     pwdc->nColors * sizeof(PALETTEENTRY));
  memset( pPal, 0, sizeof(LOGPALETTE) + pwdc->nColors * sizeof(PALETTEENTRY) );
  
  pPal->palVersion = 0x300;
  
  rb = REDBITS;
  rs = REDSHIFT;
  gb = GREENBITS;
  gs = GREENSHIFT;
  bb = BLUEBITS;
  bs = BLUESHIFT;
  
  if (pwdc->db_flag) {
    
    /* Need to make two palettes: one for the screen DC and one for the DIB. */
    pPal->palNumEntries = pwdc->nColors;
    for (i = 0; i < pwdc->nColors; i++) {
      pPal->palPalEntry[i].peRed = componentFromIndex( i, rb, rs );
      pPal->palPalEntry[i].peGreen = componentFromIndex( i, gb, gs );
      pPal->palPalEntry[i].peBlue = componentFromIndex( i, bb, bs );
      pPal->palPalEntry[i].peFlags = 0;
    }
    pwdc->hGLPalette = CreatePalette( pPal );
    pwdc->hPalette = CreatePalette( pPal );
  }
  
  else {
    pPal->palNumEntries = pwdc->nColors;
    for (i = 0; i < pwdc->nColors; i++) {
      pPal->palPalEntry[i].peRed = componentFromIndex( i, rb, rs );
      pPal->palPalEntry[i].peGreen = componentFromIndex( i, gb, gs );
      pPal->palPalEntry[i].peBlue = componentFromIndex( i, bb, bs );
      pPal->palPalEntry[i].peFlags = 0;
    }
    pwdc->hGLPalette = CreatePalette( pPal );
  }
  
  free(pPal);
  
}


void 
#ifdef COMPILE_SETPIXEL

wmSetPixelDefault(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	if (Current->db_flag)
	{
#ifdef DDRAW
		HDC hdc = NULL;
		Current->lpDDSOffScreen->lpVtbl->Unlock(Current->lpDDSOffScreen,NULL);
		Current->lpDDSOffScreen->lpVtbl->GetDC(Current->lpDDSOffScreen,&hdc);
		SetPixelV(hdc,iPixel, iScanLine, RGB(r,g,b));
		Current->lpDDSOffScreen->lpVtbl->ReleaseDC(Current->lpDDSOffScreen,hdc);
		while (Current->lpDDSOffScreen->lpVtbl->Lock(Current->lpDDSOffScreen,NULL, &(Current->ddsd), 0, NULL) == DDERR_WASSTILLDRAWING);
#else
		SetPixelV(Current->hDC, iPixel, iScanLine, RGB(r,g,b));
#endif
	}
	else
	{
		SetPixelV(Current->hDC, iPixel+pwc->rectSurface.left, pwc->rectSurface.top+iScanLine, RGB(r,g,b));
	}
}
#else
wmSetPixel(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	if (Current->db_flag)
	{
		LPBYTE  lpb = pwc->pbPixels;
		UINT    nBypp = pwc->cColorBits >> 3;
    
		lpb += pwc->ScanWidth * iScanLine;
		lpb += iPixel * nBypp;
    
		if(nBypp == 1)
		{
			if(pwc->dither_flag)
				*lpb = DITHER_RGB_2_8BIT(r,g,b,iScanLine,iPixel);
			else
				*lpb = BGR8(r,g,b);
		}
		else if(nBypp == 2)
			*((LPWORD)lpb) = BGR16(r,g,b);
		else if (nBypp == 3)
			{
			*lpb++ = b;
			*lpb++ = g;
			*lpb   = r;
			}
		else if (nBypp == 4)
			*((LPDWORD)lpb) = BGR32(r,g,b);
	}
	else
	{
		SetPixel(Current->hDC, iPixel, iScanLine, RGB(r,g,b));
	}
}
#endif
#ifdef COMPILE_SETPIXEL
void wmSetPixel4(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	LPDWORD lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * iScanLine)) + iPixel;
	*lpdw = BGR32(r,g,b);
//	LPBYTE  lpb = pwc->pbPixels + pwc->ScanWidth * iScanLine + iPixel + iPixel + iPixel + iPixel;
//	*((LPDWORD)lpb) = BGR32(r,g,b);
}

void wmSetPixel3(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	LPBYTE  lpb = pwc->pbPixels + pwc->ScanWidth * iScanLine + iPixel + iPixel + iPixel;
	*lpb++ = b;
	*lpb++ = g;
	*lpb   = r;
}

void wmSetPixel2(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	LPWORD lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * iScanLine)) + iPixel;
	*lpw = BGR16(r,g,b);
//	LPBYTE  lpb = pwc->pbPixels + pwc->ScanWidth * iScanLine + iPixel + iPixel;
//	*((LPWORD)lpb) = BGR16(r,g,b);
}

void wmSetPixel1(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	LPBYTE  lpb = pwc->pbPixels + pwc->ScanWidth * iScanLine + iPixel;
	*lpb = BGR8(r,g,b);
}

void wmSetPixel1Dither(PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b)
{
	LPBYTE  lpb = pwc->pbPixels + pwc->ScanWidth * iScanLine + iPixel;
	*lpb = DITHER_RGB_2_8BIT(r,g,b,iScanLine,iPixel);
}


void ChooseSetPixel(PWMC pwc)
{
	UINT nBypp = (pwc ) ? pwc->cColorBits >> 3 : 0;
	switch(nBypp)
	{
		case 1:
			pwc->wmSetPixel = pwc->dither_flag ? &wmSetPixel1Dither : &wmSetPixel1;
			break;
		case 2:
			pwc->wmSetPixel = &wmSetPixel2;
			break;
		case 3:
			pwc->wmSetPixel = &wmSetPixel3;
			break;
		case 4:
			pwc->wmSetPixel = &wmSetPixel4;
			break;
		default:
			pwc->wmSetPixel = &wmSetPixelDefault;
			break;
	}
}

#endif

void  wmCreateDIBSection(
  HDC   hDC,
  PWMC pwc,    // handle of device context
  CONST BITMAPINFO *pbmi,  // bitmap size, format, and color data
  UINT iUsage  // color data type indicator: RGB values or palette indices
  )
{
  DWORD   dwSize = 0;
  DWORD   dwScanWidth;
  UINT    nBypp = pwc->cColorBits / 8;
  HDC     hic;
  
  dwScanWidth = (((pwc->ScanWidth * nBypp)+ 3) & ~3);
  
  pwc->ScanWidth =pwc->pitch = dwScanWidth;
  
  if (stereo_flag)
    pwc->ScanWidth = 2* pwc->pitch;
  
  dwSize = sizeof(BITMAPINFO) + (dwScanWidth * pwc->height);
#ifdef USE_MAPPED_FILE  
  pwc->dib.hFileMap = CreateFileMapping((HANDLE)PAGE_FILE,
					NULL,
					PAGE_READWRITE | SEC_COMMIT,
					0,
					dwSize,
					NULL);
  
  if (!pwc->dib.hFileMap)
    return;
  
  pwc->dib.base = MapViewOfFile(pwc->dib.hFileMap,
				FILE_MAP_ALL_ACCESS,
				0,
				0,
				0);
  
  if(!pwc->dib.base){
    CloseHandle(pwc->dib.hFileMap);
    return;
  }


  CopyMemory(pwc->dib.base, pbmi, sizeof(BITMAPINFO));
#endif // USE_MAPPED_FILE
  
  hic = CreateIC("display", NULL, NULL, NULL);
  pwc->dib.hDC = CreateCompatibleDC(hic);
  
#ifdef USE_MAPPED_FILE  

  pwc->hbmDIB = CreateDIBSection(hic,
				 &(pwc->bmi),
				 (iUsage ? DIB_PAL_COLORS : DIB_RGB_COLORS),
				 &(pwc->pbPixels),
				 pwc->dib.hFileMap,
				 0);
#else
  pwc->hbmDIB = CreateDIBSection(hic,
				 &(pwc->bmi),
				 (iUsage ? DIB_PAL_COLORS : DIB_RGB_COLORS),
				 &(pwc->pbPixels),
				 0,
				 0);
#endif // USE_MAPPED_FILE
  pwc->ScreenMem = pwc->addrOffScreen = pwc->pbPixels;
  pwc->hOldBitmap = SelectObject(pwc->dib.hDC, pwc->hbmDIB);
  
  DeleteDC(hic);
  
  return;
  
}

/*
 * Blit memory DC to screen DC
 */
BOOL wmFlush(PWMC pwc)
{
  BOOL    bRet = 0;
  DWORD   dwErr = 0;
#ifdef DDRAW
  HRESULT             ddrval;
#endif
  
  if(pwc->db_flag){
#ifdef DDRAW
    if (pwc->lpDDSOffScreen == NULL)
      if(DDCreateOffScreen(pwc) == GL_FALSE)
	return FALSE;
    
    pwc->lpDDSOffScreen->lpVtbl->Unlock(pwc->lpDDSOffScreen, NULL);
    
    while( 1 )
      {
	ddrval = pwc->lpDDSPrimary->lpVtbl->Blt( pwc->lpDDSPrimary,
						 &(pwc->rectSurface), 
						 pwc->lpDDSOffScreen, 
						 &(pwc->rectOffScreen), 
						 0, NULL );
	
	if( ddrval == DD_OK )
	  {
	    break;
	  }
	if( ddrval == DDERR_SURFACELOST )
	  {
	    if(!DDRestoreAll(pwc))
	      {
		break;
	      }
	  }
	if( ddrval != DDERR_WASSTILLDRAWING )
	  {
	    break;
	  }
      }
    
    while (pwc->lpDDSOffScreen->lpVtbl->Lock(pwc->lpDDSOffScreen,
					     NULL, &(pwc->ddsd), 0, NULL) == 
	   DDERR_WASSTILLDRAWING)
      ;
    
    if(ddrval != DD_OK)
      dwErr = GetLastError();
#else
    bRet = BitBlt(pwc->hDC, 0, 0, pwc->width, pwc->height,
		  pwc->dib.hDC, 0, 0, SRCCOPY);
#endif
  }
  
  return(TRUE);
  
}


/* The following code is added by Li Wei to enable stereo display */

#if !defined(NO_STEREO)

static void __gluMakeIdentityf(GLfloat m[16])
{
    m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
    m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
    m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
    m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
}

static void normalize(float v[3])
{
    float r;

    r = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );
    if (r == 0.0) return;

    v[0] /= r;
    v[1] /= r;
    v[2] /= r;
}

static void cross(float v1[3], float v2[3], float result[3])
{
    result[0] = v1[1]*v2[2] - v1[2]*v2[1];
    result[1] = v1[2]*v2[0] - v1[0]*v2[2];
    result[2] = v1[0]*v2[1] - v1[1]*v2[0];
}


static void 
__gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
	  GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
	  GLdouble upz)
{
    int i;
    float forward[3], side[3], up[3];
    GLfloat m[4][4];

    forward[0] = centerx - eyex;
    forward[1] = centery - eyey;
    forward[2] = centerz - eyez;

    up[0] = upx;
    up[1] = upy;
    up[2] = upz;

    normalize(forward);

    /* Side = forward x up */
    cross(forward, up, side);
    normalize(side);

    /* Recompute up as: up = side x forward */
    cross(side, forward, up);

    __gluMakeIdentityf(&m[0][0]);
    m[0][0] = side[0];
    m[1][0] = side[1];
    m[2][0] = side[2];

    m[0][1] = up[0];
    m[1][1] = up[1];
    m[2][1] = up[2];

    m[0][2] = -forward[0];
    m[1][2] = -forward[1];
    m[2][2] = -forward[2];

    glMultMatrixf(&m[0][0]);
    glTranslated(-eyex, -eyey, -eyez);
}

GLfloat viewDistance = 1.0;

void WMesaShowStereo(GLuint list)
{
  
  GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
  GLfloat cm[16];
  GLint matrix_mode;
  /* Must use double Buffer */
  if( ! Current-> db_flag )
    return;
  
  
  glGetIntegerv(GL_MATRIX_MODE,&matrix_mode);
  
  WMesaViewport(Current->gl_ctx,0,Current->height/2,
		Current->width,Current->height/2);
  if(matrix_mode!=GL_MODELVIEW)
    glMatrixMode(GL_MODELVIEW);
  
  glGetFloatv(GL_MODELVIEW_MATRIX,cm);
  glLoadIdentity();
  __gluLookAt(viewDistance/2,0.0,0.0 ,
	    viewDistance/2,0.0,-1.0,
	    0.0,1.0,0.0 );
  glMultMatrixf( cm );
  
  Current->ScreenMem = Current->pbPixels = Current->addrOffScreen;
  glCallList( list );
  
  glGetFloatv(GL_MODELVIEW_MATRIX,cm);
  glLoadIdentity();
  __gluLookAt(-viewDistance/2,0.0,0.0 ,
	    -viewDistance/2,0.0,-1.0,
	    0.0,1.0,0.0 );
  glMultMatrixf(cm);
  
  Current->ScreenMem = Current->pbPixels = Current->addrOffScreen + Current->pitch;
  glCallList(list);
  if(matrix_mode!=GL_MODELVIEW)
    glMatrixMode(matrix_mode);
  
  glFlush();
  
  WMesaViewport(Current->gl_ctx,0,0,Current->width,Current->height);
  WMesaSwapBuffers();
}

void toggleStereoMode()
{
  if(!Current->db_flag)
    return;
  if(!stereo_flag){
    stereo_flag = 1;
    if(stereoBuffer==GL_FALSE)
#if !defined(NO_PARALLEL)
      if(!parallelFlag)
#endif
	{
	  Current->ScanWidth = Current->pitch*2;
	}
  }
  else {
    stereo_flag = 0;
#if !defined(NO_PARALLEL)
    if(!parallelFlag)
#endif
      Current->ScanWidth = Current->pitch;
    Current->pbPixels = Current->addrOffScreen;
  }
}

/* if in stereo mode, the following function is called */
void glShowStereo(GLuint list)
{
  WMesaShowStereo(list);
}

#endif /* NO_STEREO */

#if !defined(NO_PARALLEL)

void toggleParallelMode(void)
{
  if(!parallelFlag){
    parallelFlag = GL_TRUE;
    if(parallelMachine==GL_FALSE){
      PRCreateRenderBuffer( Current->rgb_flag? GL_RGBA :GL_COLOR_INDEX,
			    Current->cColorBits/8,
			    Current->width ,Current->height,
			    Current->ScanWidth,
			    Current->rgb_flag? Current->pbPixels: 
			    Current->ScreenMem);
      parallelMachine = GL_TRUE;
    }
  }
  else {
    parallelFlag = GL_FALSE;
    if(parallelMachine==GL_TRUE){
      PRDestroyRenderBuffer();
      parallelMachine=GL_FALSE;
      ReadyForNextFrame = GL_TRUE;
    }
    
    /***********************************************
     * Seems something wrong!!!!
     ************************************************/
    
    WMesaMakeCurrent(Current);
#if !defined(NO_STEREO)
    stereo_flag = GL_FALSE ;
#endif
  }
}

void PRShowRenderResult(void)
{
  int flag = 0;
  if(!glImageRendered())
    return;
  
  if (parallelFlag)
    {
      WMesaSwapBuffers();
    }
  
}
#endif /* NO_PARALLEL */

BYTE DITHER_RGB_2_8BIT( int red, int green, int blue, int pixel, int scanline)
{
  char unsigned redtemp, greentemp, bluetemp, paletteindex;
  
  //*** now, look up each value in the halftone matrix
  //*** using an 8x8 ordered dither.
  redtemp = aDividedBy51[red]
    + (aModulo51[red] > aHalftone8x8[(pixel%8)*8
				    + scanline%8]);
  greentemp = aDividedBy51[(char unsigned)green]
    + (aModulo51[green] > aHalftone8x8[
      (pixel%8)*8 + scanline%8]);
  bluetemp = aDividedBy51[(char unsigned)blue]
    + (aModulo51[blue] > aHalftone8x8[
      (pixel%8)*8 +scanline%8]);
  
  //*** recombine the halftoned rgb values into a palette index
  paletteindex =
    redtemp + aTimes6[greentemp] + aTimes36[bluetemp];
  
  //*** and translate through the wing halftone palette
  //*** translation vector to give the correct value.
  return aWinGHalftoneTranslation[paletteindex];
}

#ifdef DDRAW
/*
 * restoreAll
 *
 * restore all lost objects
 */
HRESULT DDRestoreAll( WMesaContext wc )
{
  HRESULT     ddrval;
  
  ddrval = wc->lpDDSPrimary->lpVtbl->Restore(wc->lpDDSPrimary);
  if( ddrval == DD_OK )
    {
      ddrval = wc->lpDDSOffScreen->lpVtbl->Restore(wc->lpDDSOffScreen);
    }
  return ddrval;
  
} /* restoreAll */


/*
 * This function is called if the initialization function fails
 */
BOOL initFail( HWND hwnd, WMesaContext wc )
{
  DDFree(wc);
  MessageBox( hwnd, "DirectDraw Init FAILED", "", MB_OK );
  return FALSE;
  
} /* initFail */


static void DDDeleteOffScreen(WMesaContext wc)
{
  if( wc->lpDDSOffScreen != NULL )
    {
      wc->lpDDSOffScreen->lpVtbl->Unlock(wc->lpDDSOffScreen,NULL);
      wc->lpDDSOffScreen->lpVtbl->Release(wc->lpDDSOffScreen);
      wc->lpDDSOffScreen = NULL;
    }
  
}

static void DDFreePrimarySurface(WMesaContext wc)
{
  if( wc->lpDDSPrimary != NULL )
    {
      if(wc->db_flag == GL_FALSE)
	wc->lpDDSPrimary->lpVtbl->ReleaseDC(wc->lpDDSPrimary, wc->hDC);
      wc->lpDDSPrimary->lpVtbl->Release(wc->lpDDSPrimary);
      wc->lpDDSPrimary = NULL;
    }
}

static BOOL DDCreatePrimarySurface(WMesaContext wc)
{
  HRESULT ddrval;
//  DDSCAPS             ddscaps;
  wc->ddsd.dwSize = sizeof( wc->ddsd );
  wc->ddsd.dwFlags = DDSD_CAPS;
  wc->ddsd.ddsCaps.dwCaps =   DDSCAPS_PRIMARYSURFACE;
  
  ddrval = wc->lpDD->lpVtbl->CreateSurface( wc->lpDD,&(wc->ddsd), 
					    &(wc->lpDDSPrimary), NULL );
  if( ddrval != DD_OK )
    {
      return initFail(wc->hwnd , wc);
    }
  if(wc->db_flag == GL_FALSE)
    wc->lpDDSPrimary->lpVtbl->GetDC(wc->lpDDSPrimary, &(wc->hDC));
  return TRUE;
}

static BOOL DDCreateOffScreen(WMesaContext wc)
{
  POINT   pt;
  HRESULT     ddrval;
  if(wc->lpDD == NULL)
    return FALSE;
  GetClientRect( wc->hwnd, &(wc->rectOffScreen) );
  wc->ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  wc->ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  wc->ddsd.dwHeight = wc->rectOffScreen.bottom - wc->rectOffScreen.top;
  wc->ddsd.dwWidth = wc->rectOffScreen.right - wc->rectOffScreen.left;
  
  ddrval = wc->lpDD->lpVtbl->CreateSurface( wc->lpDD, &(wc->ddsd), 
					    &(wc->lpDDSOffScreen), NULL );
  if( ddrval != DD_OK )
    {
      return FALSE;
    }
  
  while (wc->lpDDSOffScreen->lpVtbl->Lock(wc->lpDDSOffScreen,NULL, 
					  &(wc->ddsd), 0, NULL) == 
	 DDERR_WASSTILLDRAWING)
    ;
  
  if(wc->ddsd.lpSurface==NULL)
    return initFail(wc->hwnd, wc);
  
  wc->ScreenMem = wc->pbPixels = wc->addrOffScreen = 
    (PBYTE)(wc->ddsd.lpSurface);
  wc->ScanWidth = wc->pitch = wc->ddsd.lPitch;
  if (stereo_flag)
    wc->ScanWidth = wc->ddsd.lPitch*2;
  
  GetClientRect( wc->hwnd, &(wc->rectSurface) );
  pt.x = pt.y = 0;
  ClientToScreen( wc->hwnd, &pt );
  OffsetRect(&(wc->rectSurface), pt.x, pt.y);
  wmSetPixelFormat(wc, wc->hDC);
  return TRUE;
}

typedef
struct tagWMesaContextList
{
	WMesaContext wc;
	struct tagWMesaContextList *next;
}WMesaContextList;

WMesaContextList *head = 0;

void AddContext(WMesaContext wc)
{
	WMesaContextList *lst = (WMesaContextList *)malloc(sizeof(WMesaContextList));
	lst->wc = wc;
	if( head )
		lst->next = head;
	head = lst;
}

WMesaContext FindContext(HWND hWnd)
{
	WMesaContextList *tmp = head;
	while(tmp)
	{
		if( tmp->wc->hwnd == hWnd )
			return tmp->wc;
		tmp = tmp->next;
	}
	return NULL;
}

void RemoveContext(HWND hWnd)
{
	WMesaContextList *tmp = head;
	if(tmp )
	{
		if( tmp->wc->hwnd == hWnd )
		{
			WMesaContextList *lst = tmp;

			head = tmp->next;
			free((void *)lst);
		}
		else
			while(tmp->next)
			{
				if( tmp->next->wc->hwnd == hWnd )
				{
					WMesaContextList *lst = tmp->next;
					tmp->next = tmp->next->next;
					free((void *)lst);
				}
				tmp = tmp->next;
			}
	}
}

static LRESULT CALLBACK MyWndProc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam)
{
	WMesaContext wc = Current->hwnd == hwnd ? Current : FindContext(hwnd);
	 if( wc )
	 {
		LRESULT lret = CallWindowProc((WNDPROC)(wc->oldWndProc),hwnd,message,wParam,lParam);
		if( message = WM_MOVE )
		{
			 POINT pt = {0};
			GetClientRect( wc->hwnd, &(wc->rectSurface) );
			ClientToScreen( hwnd, &pt );
			OffsetRect(&(wc->rectSurface), pt.x, pt.y);
		 }
		return lret;
	}
	 return 0L;
}

/*
 * doInit - do work required for every instance of the application:
 *                create the window, initialize data
 */
static BOOL DDInit( WMesaContext wc, HWND hwnd)
{
  HRESULT             ddrval;
//  DWORD dwFrequency;
  
//  LPDIRECTDRAW            lpDD;           // DirectDraw object
//  LPDIRECTDRAW2            lpDD2;
  LPDIRECTDRAWCLIPPER pcClipper = NULL;
  
  wc->fullScreen = displayOptions.fullScreen;
  wc->gMode = displayOptions.mode;
  wc->hwnd = hwnd;
  stereo_flag = displayOptions.stereo;
  if(wc->db_flag!= GL_TRUE)
    stereo_flag = GL_FALSE;
  /*
   * create the main DirectDraw object
   */
  ddrval = DirectDrawCreate( NULL, &(wc->lpDD), NULL );
  if( ddrval != DD_OK )
    {
      return initFail(hwnd,wc);
    }
  
  // Get exclusive mode if requested
  if(wc->fullScreen)
    {
      ddrval = wc->lpDD->lpVtbl->SetCooperativeLevel( wc->lpDD, hwnd, 
						      DDSCL_EXCLUSIVE | 
						      DDSCL_FULLSCREEN );
    }
  else
    {
      ddrval = wc->lpDD->lpVtbl->SetCooperativeLevel( wc->lpDD, hwnd, 
						      DDSCL_NORMAL );
    }
  if( ddrval != DD_OK )
    {
      return initFail(hwnd , wc);
    }
  
  
  if(ddrval != DD_OK)
    return initFail(hwnd , wc);
  
  
  switch( wc->gMode )
    {
    case 1:  
      ddrval = wc->lpDD->lpVtbl->SetDisplayMode( wc->lpDD, 640, 480, 
						 displayOptions.bpp); 
      break;
    case 2:  
      ddrval = wc->lpDD->lpVtbl->SetDisplayMode( wc->lpDD, 800, 600, 
						 displayOptions.bpp); 
      break;
    case 3:  
      ddrval = wc->lpDD->lpVtbl->SetDisplayMode( wc->lpDD, 1024, 768, 
						 displayOptions.bpp); 
      break;
    case 4:  
      ddrval = wc->lpDD->lpVtbl->SetDisplayMode( wc->lpDD, 1152, 864, 
						 displayOptions.bpp); 
      break;
    case 5:  
      ddrval = wc->lpDD->lpVtbl->SetDisplayMode( wc->lpDD, 1280, 1024, 
						 displayOptions.bpp); 
      break;
    }

  if( ddrval != DD_OK )
    {
      printf("Can't modify display mode, current mode used\n");
    }
  switch(ddrval){
  case DDERR_INVALIDOBJECT:
    break;
  case DDERR_INVALIDPARAMS:
    break;
  case DDERR_UNSUPPORTEDMODE:
    ;
  }
  
  if(DDCreatePrimarySurface(wc) == GL_FALSE)
    return initFail(hwnd, wc);
  
  if(wc->db_flag)
    DDCreateOffScreen(wc);

    if( FAILED( ddrval = wc->lpDD->lpVtbl->CreateClipper(wc->lpDD, 0, &pcClipper, NULL ) ) )
        return E_FAIL;

    if( FAILED( ddrval = pcClipper->lpVtbl->SetHWnd(pcClipper,  0, wc->hwnd ) ) )
    {
        pcClipper->lpVtbl->Release(pcClipper);
        return E_FAIL;
    }

    if( FAILED( ddrval = wc->lpDDSPrimary->lpVtbl->SetClipper(wc->lpDDSPrimary,  pcClipper ) ) )
    {
        pcClipper->lpVtbl->Release(pcClipper);
        return E_FAIL;
    }

    // Done with clipper
    pcClipper->lpVtbl->Release(pcClipper);
	AddContext(wc);
	// Hook the window so we can update the drawing rectangle when the window moves
	wc->oldWndProc = SetWindowLong(wc->hwnd,GWL_WNDPROC,(LONG)MyWndProc);

	return TRUE;

} /* DDInit */

static void DDFree( WMesaContext wc)
{
  RemoveContext(wc->hwnd);
  SetWindowLong(wc->hwnd,GWL_WNDPROC,(LONG)(wc->oldWndProc));
  wc->oldWndProc = 0;
  if( wc->lpDD != NULL )
    {
      DDFreePrimarySurface(wc);
      DDDeleteOffScreen(wc);
      wc->lpDD->lpVtbl->Release(wc->lpDD);
      wc->lpDD = NULL;
    }
  // Clean up the screen on exit
  RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
		RDW_ALLCHILDREN );
  
}
#endif

void WMesaMove(void)
{
  WMesaContext wc = Current;
  POINT   pt;
  if (Current != NULL){
    GetClientRect( wc->hwnd, &(wc->rectSurface) );
    pt.x = pt.y = 0;
    ClientToScreen( wc->hwnd, &pt );
    OffsetRect(&(wc->rectSurface), pt.x, pt.y);
  }
}


/************************************************
 * Mesa 4.0 - These triangle rasterizers are not
 * implemented in this version of the Windows
 * driver.  They could be implemented for a
 * potential performance improvement.
 * See OSMesa for an example of the approach
 * to use.
 * This old code is left in this file in case
 * it is useful.  However, it may end up looking
 * a lot more like the OSMesa code.
 ************************************************/


#if defined(FAST_RASTERIZERS)


/*
 * Like PACK_8A8B8G8R() but don't use alpha.  This is usually an acceptable
 * shortcut.
 */
#define PACK_8B8G8R( R, G, B )   ( ((B) << 16) | ((G) << 8) | (R) )

/**********************************************************************/
/***                   Triangle rendering                            ***/
/**********************************************************************/

/*
 * XImage, smooth, depth-buffered, PF_8A8B8G8R triangle.
 */
static void smooth_8A8B8G8R_z_triangle( GLcontext *ctx,
                                       GLuint v0, GLuint v1, GLuint v2,
                                       GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint i, len = RIGHT-LEFT;                      \
    for (i=0;i<len;i++) {                       \
    GLdepth z = FixedToDepth(ffz);                  \
    if (z < zRow[i]) {                      \
    pRow[i] = PACK_8B8G8R( FixedToInt(ffr), FixedToInt(ffg),    \
    FixedToInt(ffb) );          \
    zRow[i] = z;                            \
    }                                   \
    ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;         \
    ffz += fdzdx;                           \
    }                                   \
    }

#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, smooth, depth-buffered, PF_8R8G8B triangle.
*/
static void smooth_8R8G8B_z_triangle( GLcontext *ctx,
                                     GLuint v0, GLuint v1, GLuint v2,
                                     GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint i, len = RIGHT-LEFT;                      \
    for (i=0;i<len;i++) {                       \
    GLdepth z = FixedToDepth(ffz);                  \
    if (z < zRow[i]) {                      \
    pRow[i] = PACK_8R8G8B( FixedToInt(ffr), FixedToInt(ffg),    \
    FixedToInt(ffb) );          \
    zRow[i] = z;                            \
    }                                   \
    ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;         \
    ffz += fdzdx;                           \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}



/*
* XImage, smooth, depth-buffered, PF_5R6G5B triangle.
*/
static void smooth_5R6G5B_z_triangle( GLcontext *ctx,
                                     GLuint v0, GLuint v1, GLuint v2,
                                     GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR2(X,Y)
#define PIXEL_TYPE GLushort
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint i, len = RIGHT-LEFT;                      \
    for (i=0;i<len;i++) {                       \
    GLdepth z = FixedToDepth(ffz);                  \
    if (z < zRow[i]) {                      \
    pRow[i] = PACK_5R6G5B( FixedToInt(ffr), FixedToInt(ffg),    \
    FixedToInt(ffb) );          \
    zRow[i] = z;                            \
    }                                   \
    ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;         \
    ffz += fdzdx;                           \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}

/*
* XImage, flat, depth-buffered, PF_8A8B8G8R triangle.
*/
static void flat_8A8B8G8R_z_triangle( GLcontext *ctx, GLuint v0,
                                     GLuint v1, GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE                  \
    unsigned long p = PACK_8B8G8R( VB->ColorPtr->data[pv][0],    \
    VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2] );
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint i, len = RIGHT-LEFT;                      \
    for (i=0;i<len;i++) {                       \
    GLdepth z = FixedToDepth(ffz);                  \
    if (z < zRow[i]) {                      \
    pRow[i] = p;                            \
    zRow[i] = z;                            \
    }                                   \
    ffz += fdzdx;                           \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, flat, depth-buffered, PF_8R8G8B triangle.
*/
static void flat_8R8G8B_z_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                   GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE                  \
    unsigned long p = PACK_8R8G8B( VB->ColorPtr->data[pv][0],    \
    VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2] );
#define INNER_LOOP( LEFT, RIGHT, Y )            \
    {                           \
    GLint i, len = RIGHT-LEFT;              \
    for (i=0;i<len;i++) {               \
    GLdepth z = FixedToDepth(ffz);          \
    if (z < zRow[i]) {              \
    pRow[i] = p;                    \
    zRow[i] = z;                    \
    }                           \
    ffz += fdzdx;                   \
    }                           \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, flat, depth-buffered, PF_5R6G5B triangle.
*/
static void flat_5R6G5B_z_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                   GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR2(X,Y)
#define PIXEL_TYPE GLushort
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE                  \
    unsigned long p = PACK_5R6G5B( VB->ColorPtr->data[pv][0],    \
    VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2] );
#define INNER_LOOP( LEFT, RIGHT, Y )            \
    {                           \
    GLint i, len = RIGHT-LEFT;              \
    for (i=0;i<len;i++) {               \
    GLdepth z = FixedToDepth(ffz);          \
    if (z < zRow[i]) {              \
    pRow[i] = p;                    \
    zRow[i] = z;                    \
    }                           \
    ffz += fdzdx;                   \
    }                           \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, smooth, NON-depth-buffered, PF_8A8B8G8R triangle.
*/
static void smooth_8A8B8G8R_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                     GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint xx;                               \
    PIXEL_TYPE *pixel = pRow;                       \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {               \
    *pixel = PACK_8B8G8R( FixedToInt(ffr), FixedToInt(ffg),     \
                FixedToInt(ffb) );          \
                ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;         \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, smooth, NON-depth-buffered, PF_8R8G8B triangle.
*/
static void smooth_8R8G8B_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                   GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint xx;                               \
    PIXEL_TYPE *pixel = pRow;                       \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {               \
    *pixel = PACK_8R8G8B( FixedToInt(ffr), FixedToInt(ffg),     \
                FixedToInt(ffb) );          \
                ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;         \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, smooth, NON-depth-buffered, PF_5R6G5B triangle.
*/
static void smooth_5R6G5B_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                   GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR2(X,Y)
#define PIXEL_TYPE GLushort
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint xx;                               \
    PIXEL_TYPE *pixel = pRow;                       \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {               \
    *pixel = PACK_5R6G5B( FixedToInt(ffr), FixedToInt(ffg),     \
                FixedToInt(ffb) );          \
                ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;         \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}



/*
* XImage, flat, NON-depth-buffered, PF_8A8B8G8R triangle.
*/
static void flat_8A8B8G8R_triangle( GLcontext *ctx, GLuint v0,
                                   GLuint v1, GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE                  \
    unsigned long p = PACK_8B8G8R( VB->ColorPtr->data[pv][0],    \
    VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2] );
#define INNER_LOOP( LEFT, RIGHT, Y )            \
    {                           \
    GLint xx;                       \
    PIXEL_TYPE *pixel = pRow;               \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {       \
    *pixel = p;                 \
    }                           \
    }

#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, flat, NON-depth-buffered, PF_8R8G8B triangle.
*/
static void flat_8R8G8B_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                 GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define PIXEL_ADDRESS(X,Y) PIXELADDR4(X,Y)
#define PIXEL_TYPE GLuint
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE                  \
    unsigned long p = PACK_8R8G8B( VB->ColorPtr->data[pv][0],    \
    VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2] );
#define INNER_LOOP( LEFT, RIGHT, Y )            \
    {                           \
    GLint xx;                       \
    PIXEL_TYPE *pixel = pRow;               \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {       \
    *pixel = p;                 \
    }                           \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, flat, NON-depth-buffered, PF_5R6G5B triangle.
*/
static void flat_5R6G5B_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                 GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define PIXEL_ADDRESS(X,Y) PIXELADDR2(X,Y)
#define PIXEL_TYPE GLushort
    //#define BYTES_PER_ROW (wmesa->xm_buffer->backimage->bytes_per_line)
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE                  \
    unsigned long p = PACK_5R6G5B( VB->ColorPtr->data[pv][0],    \
    VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2] );
#define INNER_LOOP( LEFT, RIGHT, Y )            \
    {                           \
    GLint xx;                       \
    PIXEL_TYPE *pixel = pRow;               \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {       \
    *pixel = p;                 \
    }                           \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, smooth, depth-buffered, 8-bit PF_LOOKUP triangle.
*/

static void smooth_ci_z_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                 GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define INTERP_INDEX 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                                \
    {                                                                   \
    GLint i, len = RIGHT-LEFT;                                      \
    for (i=0;i<len;i++) {                                           \
    GLdepth z = FixedToDepth(ffz);                              \
    if (z < zRow[i]) {                                          \
    pRow[i] = FixedToInt(ffi);                                  \
    zRow[i] = z;                                                \
    }                                                               \
    ffi += fdidx;                                                   \
    ffz += fdzdx;                                                   \
    }                                                               \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, flat, depth-buffered, 8-bit PF_LOOKUP triangle.
*/

static void flat_ci_z_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                               GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE			\
   GLuint index = VB->IndexPtr->data[pv];	\
   (*ctx->Driver.Index)( ctx, index );
#define INNER_LOOP( LEFT, RIGHT, Y )	\
   {					\
      GLint i, len = RIGHT-LEFT;	\
      for (i=0;i<len;i++) {		\
         GLdepth z = FixedToDepth(ffz);	\
         if (z < zRow[i]) {		\
            pRow[i] = index;		\
            zRow[i] = z;		\
         }				\
         ffz += fdzdx;			\
      }					\
   }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}



/*
* XImage, smooth, NON-depth-buffered, 8-bit PF_LOOKUP triangle.
*/

static void smooth_ci_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                               GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define INTERP_INDEX 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                    \
    {                                   \
    GLint xx;                               \
    PIXEL_TYPE *pixel = pRow;                       \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {               \
    *pixel = FixedToInt(ffi);           \
    ffi += fdidx;           \
    }                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}


/*
* XImage, flat, NON-depth-buffered, 8-bit PF_LOOKUP triangle.
*/
static void flat_ci_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                             GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
#define INTERP_Z 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define SETUP_CODE			\
   GLuint index = VB->IndexPtr->data[pv];	\
   (*ctx->Driver.Index)( ctx, index );
#define INNER_LOOP( LEFT, RIGHT, Y )		\
   {						\
      GLint xx;					\
      PIXEL_TYPE *pixel = pRow;			\
      for (xx=LEFT;xx<RIGHT;xx++,pixel++) {	\
         *pixel = index;			\
      }						\
   }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}

/*
* XImage, smooth, depth-buffered, 8-bit, PF_DITHER8 triangle.
*/
static void smooth_DITHER8_z_triangle( GLcontext *ctx,
                                      GLuint v0, GLuint v1, GLuint v2,
                                      GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
    DITHER_RGB_TO_8BIT_SETUP
#define INTERP_Z 1
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                                    \
    {                                                                       \
    GLint i, xx = LEFT, yy = FLIP(Y), len = RIGHT-LEFT;                 \
    for (i=0;i<len;i++,xx++) {                                          \
    GLdepth z = FixedToDepth(ffz);                                  \
    if (z < zRow[i]) {                                              \
    DITHER_RGB_TO_8BIT( FixedToInt(ffr), FixedToInt(ffg),           \
    FixedToInt(ffb), xx, yy);               \
    pRow[i] = pixelDithered;                                        \
    zRow[i] = z;                                                    \
    }                                                                   \
    ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;                     \
    ffz += fdzdx;                                                       \
    }                                                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}

/*
* XImage, flat, depth-buffered, 8-bit PF_DITHER triangle.
*/
static void flat_DITHER8_z_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                    GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
    DITHER_RGB_TO_8BIT_SETUP
#define INTERP_Z 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)

#define INNER_LOOP( LEFT, RIGHT, Y )                                    \
    {                                                                       \
    GLint i, xx = LEFT, yy = FLIP(Y), len = RIGHT-LEFT;                 \
    for (i=0;i<len;i++,xx++) {                                          \
    GLdepth z = FixedToDepth(ffz);                                  \
    if (z < zRow[i]) {                                              \
    DITHER_RGB_TO_8BIT( VB->ColorPtr->data[pv][0],                           \
             VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2], xx, yy);               \
             pRow[i] = pixelDithered;                                       \
             zRow[i] = z;                                                   \
    }                                                                   \
    ffz += fdzdx;                                                       \
    }                                                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}

/*
* XImage, smooth, NON-depth-buffered, 8-bit PF_DITHER triangle.
*/
static void smooth_DITHER8_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                    GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
    DITHER_RGB_TO_8BIT_SETUP
#define INTERP_RGB 1
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)
#define INNER_LOOP( LEFT, RIGHT, Y )                                    \
    {                                                                       \
    GLint xx, yy = FLIP(Y);                                             \
    PIXEL_TYPE *pixel = pRow;                                           \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {                               \
    DITHER_RGB_TO_8BIT( VB->ColorPtr->data[pv][0],   VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2], xx, yy);\
    *pixel = pixelDithered;                                         \
    ffr += fdrdx;  ffg += fdgdx;  ffb += fdbdx;                     \
    }                                                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}

/*
* XImage, flat, NON-depth-buffered, 8-bit PF_DITHER triangle.
*/

static void flat_DITHER8_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
                                  GLuint v2, GLuint pv )
{
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
    DITHER_RGB_TO_8BIT_SETUP
#define PIXEL_ADDRESS(X,Y) PIXELADDR1(X,Y)
#define PIXEL_TYPE GLubyte
#define BYTES_PER_ROW (wmesa->ScanWidth)

#define INNER_LOOP( LEFT, RIGHT, Y )                                    \
    {                                                                       \
    GLint xx, yy = FLIP(Y);                                             \
    PIXEL_TYPE *pixel = pRow;                                           \
    for (xx=LEFT;xx<RIGHT;xx++,pixel++) {                               \
    DITHER_RGB_TO_8BIT( VB->ColorPtr->data[pv][0],                               \
             VB->ColorPtr->data[pv][1], VB->ColorPtr->data[pv][2], xx, yy);               \
             *pixel = pixelDithered;                                            \
    }                                                                   \
    }
#ifdef __MINGW32__
	#include "tritemp.h"
#else

	#ifdef WIN32
//		#include "..\tritemp.h"
	#else
		#include "tritemp.h"
	#endif
#endif
}

#endif
/************** END DEAD TRIANGLE CODE ***********************/

static triangle_func choose_triangle_function( GLcontext *ctx )
{
#if 0
    WMesaContext wmesa = (WMesaContext) ctx->DriverCtx;
    int depth = wmesa->cColorBits;

    if (ctx->Polygon.SmoothFlag)     return NULL;
    if (ctx->Texture._EnabledUnits)  return NULL;
    if (!wmesa->db_flag) return NULL;
    if (ctx->swrast->_RasterMask & MULTI_DRAW_BIT) return NULL;

    /*if (wmesa->xm_buffer->buffer==XIMAGE)*/ {
    if (   ctx->Light.ShadeModel==GL_SMOOTH
        && ctx->_RasterMask==DEPTH_BIT
        && ctx->Depth.Func==GL_LESS
        && ctx->Depth.Mask==GL_TRUE
        && ctx->Polygon.StippleFlag==GL_FALSE) {
        switch (wmesa->pixelformat) {
        case PF_8A8B8G8R:
            return smooth_8A8B8G8R_z_triangle;
        case PF_8R8G8B:
            return smooth_8R8G8B_z_triangle;
        case PF_5R6G5B:
            return smooth_5R6G5B_z_triangle;
        case PF_DITHER8:
            return  smooth_DITHER8_z_triangle;
        case PF_INDEX8:
            return smooth_ci_z_triangle;
        default:
            return NULL;
        }
    }
    if (   ctx->Light.ShadeModel==GL_FLAT
        && ctx->_RasterMask==DEPTH_BIT
        && ctx->Depth.Func==GL_LESS
        && ctx->Depth.Mask==GL_TRUE
        && ctx->Polygon.StippleFlag==GL_FALSE) {
        switch (wmesa->pixelformat) {
        case PF_8A8B8G8R:
            return flat_8A8B8G8R_z_triangle;
        case PF_8R8G8B:
            return flat_8R8G8B_z_triangle;
        case PF_5R6G5B:
            return flat_5R6G5B_z_triangle;
        case PF_DITHER8:
            return flat_DITHER8_z_triangle;
        case PF_INDEX8:
            return flat_ci_z_triangle;
        default:
            return NULL;
        }
    }
    if (   ctx->_RasterMask==0   /* no depth test */
        && ctx->Light.ShadeModel==GL_SMOOTH
        && ctx->Polygon.StippleFlag==GL_FALSE) {
        switch (wmesa->pixelformat) {
        case PF_8A8B8G8R:
            return smooth_8A8B8G8R_triangle;
        case PF_8R8G8B:
            return smooth_8R8G8B_triangle;
        case PF_5R6G5B:
            return smooth_5R6G5B_triangle;
        case PF_DITHER8:
            return smooth_DITHER8_triangle;
        case PF_INDEX8:
            return smooth_ci_triangle;
        default:
            return NULL;
        }
    }

    if (   ctx->_RasterMask==0   /* no depth test */
        && ctx->Light.ShadeModel==GL_FLAT
        && ctx->Polygon.StippleFlag==GL_FALSE) {
        switch (wmesa->pixelformat) {
        case PF_8A8B8G8R:
            return flat_8A8B8G8R_triangle;
        case PF_8R8G8B:
            return flat_8R8G8B_triangle;
        case PF_5R6G5B:
            return flat_5R6G5B_triangle;
        case PF_DITHER8:
            return flat_DITHER8_triangle;
        case PF_INDEX8:
            return flat_ci_triangle;
        default:
            return NULL;
        }
    }

    return NULL;
    }
#endif
}

/*
 * Define a new viewport and reallocate auxillary buffers if the size of
 * the window (color buffer) has changed.
 */
void WMesaViewport( GLcontext *ctx,
		    GLint x, GLint y, GLsizei width, GLsizei height )
{
  assert(0);  /* I don't think that this is being used. */
#if 0
  /* Save viewport */
  ctx->Viewport.X = x;
  ctx->Viewport.Width = width;
  ctx->Viewport.Y = y;
  ctx->Viewport.Height = height;
  
  /* compute scale and bias values */
/* Pre-Keith 3.1 changes
   ctx->Viewport.Map.m[Sx] = (GLfloat) width / 2.0F;
   ctx->Viewport.Map.m[Tx] = ctx->Viewport.Sx + x;
   ctx->Viewport.Map.m[Sy] = (GLfloat) height / 2.0F;
   ctx->Viewport.Map.m[Ty] = ctx->Viewport.Sy + y;
*/
  ctx->Viewport.WindowMap.m[MAT_SX] = (GLfloat) width / 2.0F;
  ctx->Viewport.WindowMap.m[MAT_TX] = ctx->Viewport.WindowMap.m[MAT_SX] + x;
  ctx->Viewport.WindowMap.m[MAT_SY] = (GLfloat) height / 2.0F;
  ctx->Viewport.WindowMap.m[MAT_TY] = ctx->Viewport.WindowMap.m[MAT_SY] + y;
#endif
}
