/*===========================================================================*/
/*                                                                           */
/* Mesa-3.0 Makefile for DirectX 6                                           */
/*                                                                           */
/* By Leigh McRae                                                            */
/*                                                                           */
/* http://www.altsoftware.com/                                               */
/*                                                                           */
/* Copyright (c) 1998-1997  alt.software inc.  All Rights Reserved           */
/*===========================================================================*/
#include "D3DMesa.h"
/*===========================================================================*/
/* Window managment.                                                         */
/*===========================================================================*/
static BOOL    InitOpenGL( HINSTANCE hInst );
static BOOL    TermOpenGL( HINSTANCE hInst );
static BOOL     ResizeContext( GLcontext *ctx );
static BOOL    MakeCurrent( D3DMESACONTEXT *pContext );
static void    DestroyContext( D3DMESACONTEXT *pContext );
static BOOL    UnBindWindow( D3DMESACONTEXT *pContext );
LONG APIENTRY  wglMonitorProc( HWND hwnd, UINT message, UINT wParam, LONG lParam );
/*===========================================================================*/
/* Mesa hooks.                                                               */
/*===========================================================================*/
static void SetupDDPointers( GLcontext *ctx );
static void SetupSWDDPointers( GLcontext *ctx );
static void SetupHWDDPointers( GLcontext *ctx );
static void SetupNULLDDPointers( GLcontext *ctx );
static const char *RendererString( void );

/* State Management hooks. */
static void       SetColor( GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a );
static void       ClearColor( GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a );
static GLboolean SetBuffer( GLcontext *ctx, GLenum buffer );

/* Window Management hooks. */
static void GetBufferSize( GLcontext *ctx, GLuint *width, GLuint *height );
static void SetViewport( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h );
static void Flush( GLcontext *ctx );

/* Span rendering hooks. */
void WSpanRGB( const GLcontext* ctx, GLuint n, GLint x, GLint y, const GLubyte rgb[][3], const GLubyte mask[] );
void WSpanRGBA( const GLcontext* ctx, GLuint n, GLint x, GLint y, const GLubyte rgba[][4], const GLubyte mask[] );
void WSpanRGBAMono( const GLcontext* ctx, GLuint n, GLint x, GLint y, const GLubyte mask[] );
void WPixelsRGBA( const GLcontext* ctx, GLuint n, const GLint x[], const GLint y[], const GLubyte rgba[][4], const GLubyte mask[] );
void WPixelsRGBAMono( const GLcontext* ctx, GLuint n, const GLint x[], const GLint y[], const GLubyte mask[] );
void RSpanRGBA( const GLcontext* ctx, GLuint n, GLint x, GLint y, GLubyte rgba[][4] );
void RPixelsRGBA( const GLcontext* ctx, GLuint n, const GLint x[], const GLint y[], GLubyte rgba[][4], const GLubyte mask[] );
GLbitfield ClearBuffers( GLcontext *ctx, GLbitfield mask, GLboolean all, GLint x, GLint y, GLint width, GLint height );

/* Primitve rendering hooks. */
GLboolean  RenderVertexBuffer( GLcontext *ctx, GLboolean allDone );
void             RenderOneTriangle( GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint pv );
void     RenderOneLine( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv );
GLbitfield ClearBuffersD3D( GLcontext *ctx, GLbitfield mask, GLboolean all, GLint x, GLint y, GLint width, GLint height );

/* Texture Management hooks. */
static void TextureBind( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj );
static void TextureLoad( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLint level, GLint internalFormat, const struct gl_texture_image *image );
static void TextureSubImage( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint internalFormat, const struct gl_texture_image *image );
/*===========================================================================*/
/* Global variables.                                                         */
/*===========================================================================*/
D3DMESACONTEXT *pD3DCurrent,     
	       *pD3DDefault;     /* Thin support context. */

struct __extensions__   ext[] = {

    { (PROC)glPolygonOffsetEXT,        "glPolygonOffsetEXT"       },
    { (PROC)glBlendEquationEXT,        "glBlendEquationEXT"       },
    { (PROC)glBlendColorEXT,           "glBlendColorExt"          },
    { (PROC)glVertexPointerEXT,        "glVertexPointerEXT"       },
    { (PROC)glNormalPointerEXT,        "glNormalPointerEXT"       },
    { (PROC)glColorPointerEXT,         "glColorPointerEXT"        },
    { (PROC)glIndexPointerEXT,         "glIndexPointerEXT"        },
    { (PROC)glTexCoordPointerEXT,      "glTexCoordPointer"        },
    { (PROC)glEdgeFlagPointerEXT,      "glEdgeFlagPointerEXT"     },
    { (PROC)glGetPointervEXT,          "glGetPointervEXT"         },
    { (PROC)glArrayElementEXT,         "glArrayElementEXT"        },
    { (PROC)glDrawArraysEXT,           "glDrawArrayEXT"           },
    { (PROC)glAreTexturesResidentEXT,  "glAreTexturesResidentEXT" },
    { (PROC)glBindTextureEXT,          "glBindTextureEXT"         },
    { (PROC)glDeleteTexturesEXT,       "glDeleteTexturesEXT"      },
    { (PROC)glGenTexturesEXT,          "glGenTexturesEXT"         },
    { (PROC)glIsTextureEXT,            "glIsTextureEXT"           },
    { (PROC)glPrioritizeTexturesEXT,   "glPrioritizeTexturesEXT"  },
    { (PROC)glCopyTexSubImage3DEXT,    "glCopyTexSubImage3DEXT"   },
    { (PROC)glTexImage3DEXT,           "glTexImage3DEXT"          },
    { (PROC)glTexSubImage3DEXT,        "glTexSubImage3DEXT"       },
};

int             qt_ext = sizeof(ext) / sizeof(ext[0]);
float   g_DepthScale,
	  g_MaxDepth;
/*===========================================================================*/
/*  When a process loads this DLL we will setup the linked list for context  */
/* management and create a default context that will support the API until   */
/* the user creates and binds thier own.  This THIN default context is useful*/
/* to have around.                                                           */
/*  When the process terminates we will clean up all resources here.         */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
BOOL APIENTRY   DllMain( HINSTANCE hInst, DWORD reason, LPVOID reserved )
{
  switch( reason ) 
  {
    case DLL_PROCESS_ATTACH:
	 return InitOpenGL( hInst );

    case DLL_PROCESS_DETACH:
	 return TermOpenGL( hInst );
  }     

  return TRUE;
}
/*===========================================================================*/
/*  The first thing we do when this dll is hit is connect to the dll that has*/
/* handles all the DirectX 6 rendering.  I decided to use another dll as DX6 */
/* is all C++ and Mesa-3.0 is C (thats a good thing).  This way I can write  */
/* the DX6 in C++ and Mesa-3.0 in C without having to worry about linkage.   */
/* I feel this is easy and better then using static wrappers as it is likely */
/* faster and it allows me to just develope the one without compiling the    */
/* other.                                                                    */
/*  NOTE that at this point we don't have much other than a very thin context*/
/* that will support the API calls only to the point of not causing the app  */
/* to crash from the API table being empty.                                  */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
static BOOL  InitOpenGL( HINSTANCE hInst )
{
  /* Allocate and clear the default context. */
  pD3DDefault = (PD3DMESACONTEXT)ALLOC( sizeof(D3DMESACONTEXT) );
  if ( pD3DDefault == NULL )
    return FALSE;
  memset( pD3DDefault, 0, sizeof(D3DMESACONTEXT) );

  /*  Clear the D3D vertex buffer so that values not used will be zero.  This */
  /* save me from some redundant work.                                        */
  memset( &D3DTLVertices, 0, sizeof(D3DTLVertices) );

  /*  Update the link.  We uses a circular list so that it is easy to  */
  /* add and search.  This context will also be used for head and tail.*/
  pD3DDefault->next = pD3DDefault;

  /*========================================================================*/
  /* Do all core Mesa stuff.                                                */
  /*========================================================================*/
  pD3DDefault->gl_visual = gl_create_visual( TRUE,
									GL_FALSE,   /* software alpha */
									FALSE,      /* db_flag */
									GL_FALSE,   /* stereo */
									16,         /* depth_bits */
									8,          /* stencil_bits */
									8,          /* accum_bits */
									0,          /* index bits */
									8,8,8,8 );  /* r, g, b, a bits */

  if ( pD3DDefault->gl_visual == NULL)  
  {
    FREE( pD3DDefault );
    return FALSE;
  }

  /* Allocate a new Mesa context */
  pD3DDefault->gl_ctx = gl_create_context( pD3DDefault->gl_visual, NULL, pD3DDefault, GL_TRUE );
  if ( pD3DDefault->gl_ctx == NULL ) 
  {
    gl_destroy_visual( pD3DDefault->gl_visual );
    FREE( pD3DDefault );
    return FALSE;
  }

  /* Allocate a new Mesa frame buffer */
  pD3DDefault->gl_buffer = gl_create_framebuffer( pD3DDefault->gl_visual );
  if ( pD3DDefault->gl_buffer == NULL )
  {
    gl_destroy_visual( pD3DDefault->gl_visual );
    gl_destroy_context( pD3DDefault->gl_ctx );
    FREE( pD3DDefault );
    return FALSE;
  }
  SetupDDPointers( pD3DDefault->gl_ctx );
  gl_make_current( pD3DDefault->gl_ctx, pD3DDefault->gl_buffer );

  return TRUE;
}
/*===========================================================================*/
/*  This function will create a new D3D context but will not create the D3D  */
/* surfaces or even an instance of D3D (see at GetBufferSize). The only stuff*/
/* done here is the internal Mesa stuff and some Win32 handles.              */
/*===========================================================================*/
/* RETURN: casted pointer to the context, NULL.                              */
/*===========================================================================*/
HGLRC APIENTRY wglCreateContext( HDC hdc )
{
  D3DMESACONTEXT        *pNewContext;
  DWORD                 dwCoopFlags = DDSCL_NORMAL;
  RECT                  rectClient;
  POINT                 pt;

  /* ALLOC and clear the new context. */
  pNewContext = (PD3DMESACONTEXT)ALLOC( sizeof(D3DMESACONTEXT) );
  if ( pNewContext == NULL )
  {
    SetLastError( 0 );
    return (HGLRC)NULL;
  }
  memset( pNewContext, 0, sizeof(D3DMESACONTEXT) );

  /*========================================================================*/
  /* Do all core Mesa stuff.                                                */
  /*========================================================================*/

  /* TODO: support more then one visual. */
  pNewContext->gl_visual = gl_create_visual( TRUE,
									GL_TRUE,   /* software alpha */
									TRUE,       /* db_flag */
									GL_FALSE,   /* stereo */
									16,         /* depth_bits */
									8,          /* stencil_bits */
									8,          /* accum_bits */
									0,          /* index bits */
									8,8,8,8 );  /* r, g, b, a bits */
  if ( pNewContext->gl_visual == NULL) 
  {
    FREE( pNewContext );
    SetLastError( 0 );
    return (HGLRC)NULL;
  }

  /* Allocate a new Mesa context */
  pNewContext->gl_ctx = gl_create_context( pNewContext->gl_visual, NULL, pNewContext, GL_TRUE );
  if ( pNewContext->gl_ctx == NULL ) 
  {
    gl_destroy_visual( pNewContext->gl_visual );
    FREE( pNewContext );
    SetLastError( 0 );
    return (HGLRC)NULL;
  }

  /* Allocate a new Mesa frame buffer */
  pNewContext->gl_buffer = gl_create_framebuffer( pNewContext->gl_visual );
  if ( pNewContext->gl_buffer == NULL )
  {
    gl_destroy_visual( pNewContext->gl_visual );
    gl_destroy_context( pNewContext->gl_ctx );
    FREE( pNewContext );
    SetLastError( 0 );
    return (HGLRC)NULL;
  }

  /*========================================================================*/
  /* Do all the driver stuff.                                               */
  /*========================================================================*/
  pNewContext->hdc  = hdc;
  pNewContext->next = pD3DDefault->next;
  pD3DDefault->next = pNewContext; /* Add to circular list. */

  /* Create the HAL for the new context. */
  pNewContext->pShared = InitHAL( WindowFromDC(hdc) );

  return (HGLRC)pNewContext;
}
/*===========================================================================*/
/*  This is a wrapper function that is supported by MakeCurrent.             */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
BOOL APIENTRY  wglMakeCurrent( HDC hdc, HGLRC hglrc )
{
   return MakeCurrent((D3DMESACONTEXT *)hglrc);
}
/*===========================================================================*/
/*  MakeCurrent will unbind whatever context is current (if any) & then bind */
/* the supplied context.  A context that is bound has it's window proc hooked*/
/* with the wglMonitorProc and the context pointer is saved in pD3DCurrent.    */
/* Once the context is bound we update the Mesa-3.0 hooks (SetDDPointers) and*/
/* the viewport (Mesa-.30 and DX6).                                          */
/*                                                                           */
/* TODO: this function can't fail.                                           */
/*===========================================================================*/
/* RETURN: TRUE                                                              */
/*===========================================================================*/
static BOOL MakeCurrent( D3DMESACONTEXT *pContext )
{
   D3DMESACONTEXT *pNext;

   /*====================================================================*/
   /* This is a special case that is a request to have no context bound. */
   /*====================================================================*/
   if ( pContext == NULL )
   {
	/* Walk the whole list. We start and end at the Default context. */
	for( pNext = pD3DDefault->next; pNext != pD3DDefault; pNext = pNext->next )
	  UnBindWindow( pNext );
      
	return TRUE;
   }

   /*=================================================*/
   /* Make for a fast redundant use of this function. */
   /*=================================================*/
   if ( pD3DCurrent == pContext )
      return TRUE;

   /*=============================*/
   /* Unbind the current context. */
   /*=============================*/
   UnBindWindow( pD3DCurrent );

   /*=====================================*/
   /* Let Mesa-3.0 we have a new context. */
   /*=====================================*/
   SetupDDPointers( pContext->gl_ctx );
   gl_make_current( pContext->gl_ctx, pContext->gl_buffer );

   /*  We are done so set the internal current context. */
   if ( pContext != pD3DDefault )
   {
	ResizeContext( pContext->gl_ctx );
	pContext->hOldProc = (WNDPROC)GetWindowLong( pContext->pShared->hwnd, GWL_WNDPROC );
	SetWindowLong( pContext->pShared->hwnd, GWL_WNDPROC, (LONG)wglMonitorProc );
   }
   pD3DCurrent = pContext;

   return TRUE;
}
/*===========================================================================*/
/*  This function will only return the current window size.  I have re-done  */   
/* this function so that it doesn't check the current size and react to it as*/   
/* I should be able to have all the react code in the WM_SIZE message.  The  */   
/* old version would check the current window size and create/resize the HAL */   
/* surfaces if they have changed.  I needed to delay the creation if the     */   
/* surfaces because sometimes I wouldn't have a window size so this is where */   
/* I delayed it.  If you are reading this then all went ok!                  */   
/*  The default context will return a zero sized window and I'm not sure if  */
/* this is ok at this point (TODO).                                          */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void GetBufferSize( GLcontext *ctx, GLuint *width, GLuint *height )
{
  D3DMESACONTEXT        *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

  /* Fall through for the default because that is one of the uses for it. */
  if ( pContext == pD3DDefault )
  {
    *width  = 0;
    *height = 0;
  }
  else
  {
    *width  = pContext->pShared->dwWidth;
    *height = pContext->pShared->dwHeight;
  }
}
/*===========================================================================*/
/*                                                                           */
/*                                                                           */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static BOOL ResizeContext( GLcontext *ctx )
{
  D3DMESACONTEXT        *pContext = (D3DMESACONTEXT *)ctx->DriverCtx,
		    *pCurrentTemp;
  RECT                  rectClient;
  POINT                 pt;
  DWORD                 dwWidth,
		    dwHeight;
  static BOOL           bDDrawLock = FALSE;

  /* Make sure we have some values. */
  if ( (pContext->hdc == NULL ) || 
	  (pContext->pShared->hwnd != WindowFromDC(pContext->hdc)) ||
       (pContext == pD3DDefault) )
    return FALSE;

  /* Having problems with DDraw sending resize messages before I was done. */
  if( bDDrawLock == TRUE )
    return FALSE;

  // TODO: don't think I need this anymore.
  pCurrentTemp = pD3DCurrent;
  pD3DCurrent = pD3DDefault;
  bDDrawLock = TRUE;

  /* Get the current window dimentions. */
  UpdateScreenPosHAL( pContext->pShared );
  dwWidth  = pContext->pShared->rectW.right - pContext->pShared->rectW.left;
  dwHeight = pContext->pShared->rectW.bottom - pContext->pShared->rectW.top;

  /* Is the size of the OffScreen Render different? */
  if ( (dwWidth != pContext->pShared->dwWidth) || (dwHeight != pContext->pShared->dwHeight) )
  {
    /* Create all the D3D surfaces and device. */
    CreateHAL( pContext->pShared );

    /*  I did this so that software rendering would still work as */
    /* I don't need to scale the z values twice.                  */
    g_DepthScale        = (pContext->pShared->bHardware) ? 1.0 : ((float)0x00FFFFFF);
    g_MaxDepth          = (pContext->pShared->bHardware) ? 1.0 : ((float)0x00FFFFFF);
    gl_DepthRange( pContext->gl_ctx, ctx->Viewport.Near, ctx->Viewport.Far );

    /* Make sure we have a viewport. */
    gl_Viewport( pContext->gl_ctx, 0, 0, dwWidth, dwHeight );

    /* Update Mesa as we might have changed from SW <-> HW. */
    SetupDDPointers( pContext->gl_ctx );
    gl_make_current( pContext->gl_ctx, pContext->gl_buffer );

    /*  If we are in HW we need to load the current texture if there is one already. */
    //    if ( (ctx->Texture.Set[ctx->Texture.CurrentSet].Current != NULL) &&
    //      (pContext->pShared->bHardware == TRUE) )
    //    {
    //   CreateTMgrHAL( pContext->pShared,
    //                           ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Name,
    //                           0,     
    //                           ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Format,
    //                           (RECT *)NULL,
    //                           ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Width,
    //                           ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Height,
    //                           TM_ACTION_BIND,
    //                           (void *)ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Data );
    //    }
  }

  // TODO: don't think I need this anymore.
  pD3DCurrent = pCurrentTemp;
  bDDrawLock = FALSE;

  return TRUE;
}

/*===========================================================================*
/*  This function will Blt the render buffer to the PRIMARY surface. I repeat*/
/* this code for the other SwapBuffer like functions and the flush (didn't   */
/* want the function calling overhead).  Thsi could have been a macro...     */
/*                                                                           */
/* TODO: there are some problems with viewport/scissoring.                   */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
BOOL APIENTRY  wglSwapBuffers( HDC hdc )
{
  /* Fall through for the default because that is one of the uses for it. */
  if ( pD3DCurrent == pD3DDefault )
    return FALSE;

  SwapBuffersHAL( pD3DCurrent->pShared );

  return TRUE;
}
/*===========================================================================*/
/*  Same as wglSwapBuffers.                                                  */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
BOOL APIENTRY  SwapBuffers( HDC hdc )
{
  /* Fall through for the default because that is one of the uses for it. */
  if ( pD3DCurrent == pD3DDefault )
    return FALSE;

  SwapBuffersHAL( pD3DCurrent->pShared );

  return TRUE;
}
/*===========================================================================*/
/*  This should be ok as none of the SwapBuffers will cause a redundant Blt  */
/* as none of my Swap functions will call flush.  This should also allow     */
/* sinlge buffered applications to work (not really worried though).  Some   */
/* applications may flush then swap but then this is there fault IMHO.       */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void Flush( GLcontext *ctx )
{
  /* Fall through for the default because that is one of the uses for it. */
  if ( pD3DCurrent == pD3DDefault )
    return;

  SwapBuffersHAL( pD3DCurrent->pShared );
}
/*===========================================================================*/
/*  For now this function will ignore the supplied PF. If I'm going to allow */
/* the user to choice the mode and device at startup I'm going to have to do */
/* something different.                                                      */
/*                                                                           */
/* TODO: use the linked list of modes to build a pixel format to be returned */
/*      to the caller.                                                       */
/*===========================================================================*/
/* RETURN: 1.                                                                */
/*===========================================================================*/
int APIENTRY   wglChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd )
{
   return 1;
}
/*===========================================================================*/
/*  See wglChoosePixelFormat.                                                */
/*===========================================================================*/
/* RETURN: 1.                                                                */
/*===========================================================================*/
int APIENTRY   ChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd )
{
  return wglChoosePixelFormat(hdc,ppfd);
}
/*===========================================================================*/
/*  This function (for now) returns a static PF everytime.  This is just to  */
/* allow things to continue.                                                 */
/*===========================================================================*/
/* RETURN: 1.                                                                */
/*===========================================================================*/
int APIENTRY   wglDescribePixelFormat( HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd )
{
   static PIXELFORMATDESCRIPTOR  pfd = 
   {
      sizeof(PIXELFORMATDESCRIPTOR),   /* size */
      1,                               /* version */
      PFD_SUPPORT_OPENGL |
      PFD_DRAW_TO_WINDOW |
      PFD_DOUBLEBUFFER,                /* support double-buffering */
      PFD_TYPE_RGBA,                   /* color type */
      16,                              /* prefered color depth */
      0, 0, 0, 0, 0, 0,                /* color bits (ignored) */
      0,                               /* no alpha buffer */
      0,                               /* alpha bits (ignored) */
      0,                               /* no accumulation buffer */
      0, 0, 0, 0,                      /* accum bits (ignored) */
      16,                              /* depth buffer */
      0,                               /* no stencil buffer */
      0,                               /* no auxiliary buffers */
      PFD_MAIN_PLANE,                  /* main layer */
      0,                               /* reserved */
      0, 0, 0,                         /* no layer, visible, damage masks */
   };

   /* Return the address of this static PF if one was requested. */
   if ( ppfd != NULL )
      memcpy( ppfd, &pfd, sizeof(PIXELFORMATDESCRIPTOR) );

  return 1;
}
/*===========================================================================*/
/*  See wglDescribePixelFormat.                                              */
/*===========================================================================*/
/* RETURN: 1.                                                                */
/*===========================================================================*/
int APIENTRY   DescribePixelFormat( HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd )
{
  return wglDescribePixelFormat(hdc,iPixelFormat,nBytes,ppfd);
}
/*===========================================================================*/
/*  This function will always return 1 for now.  Just to allow for support.  */
/*===========================================================================*/
/* RETURN: 1.                                                                */
/*===========================================================================*/
int APIENTRY   wglGetPixelFormat( HDC hdc )
{
   return 1;
}
/*===========================================================================*/
/*  See wglGetPixelFormat.                                                   */
/*===========================================================================*/
/* RETURN: 1.                                                                */
/*===========================================================================*/
int APIENTRY   GetPixelFormat( HDC hdc )
{
   return wglGetPixelFormat(hdc);
}
/*===========================================================================*/
/*  This will aways work for now.                                            */
/*===========================================================================*/
/* RETURN: TRUE.                                                             */
/*===========================================================================*/
BOOL APIENTRY  wglSetPixelFormat( HDC hdc, int iPixelFormat, CONST PIXELFORMATDESCRIPTOR *ppfd )
{
   return TRUE;
}
/*===========================================================================*/
/*  See wglSetPixelFormat.                                                   */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
BOOL APIENTRY  SetPixelFormat( HDC hdc, int iPixelFormat, CONST PIXELFORMATDESCRIPTOR *ppfd )
{
   return wglSetPixelFormat(hdc,iPixelFormat,ppfd);
}
/*===========================================================================*/
/*  This is a wrapper function that is supported by my own internal function.*/
/* that takes my own D3D Mesa context structure.  This so I can reuse the    */
/* function (no need for speed).                                             */
/*===========================================================================*/
/* RETURN: TRUE.                                                             */
/*===========================================================================*/
BOOL APIENTRY  wglDeleteContext( HGLRC hglrc )
{
   DestroyContext( (D3DMESACONTEXT *)hglrc );

   return TRUE;
}
/*===========================================================================*/
/*  Simple getter function that uses a cast.                                 */
/*===========================================================================*/
/* RETURN: casted pointer to the context, NULL.                              */
/*===========================================================================*/
HGLRC APIENTRY wglGetCurrentContext( VOID )
{
   return (pD3DCurrent) ? (HGLRC)pD3DCurrent : (HGLRC)NULL;
}
/*===========================================================================*/
/* No support.                                                               */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglCopyContext( HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask )
{
   SetLastError( 0 );
   return FALSE;
}
/*===========================================================================*/
/* No support.                                                               */
/*===========================================================================*/
/* RETURN: NULL.                                                             */
/*===========================================================================*/
HGLRC APIENTRY wglCreateLayerContext( HDC hdc,int iLayerPlane )
{
   SetLastError( 0 );
   return (HGLRC)NULL;
}
/*===========================================================================*/
/*  Simple getter function.                                                  */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
HDC APIENTRY   wglGetCurrentDC( VOID )
{
   return (pD3DCurrent) ? pD3DCurrent->hdc : (HDC)NULL;
}
/*===========================================================================*/
/*  Simply call that searches the supported extensions for a match & returns */
/* the pointer to the function that lends support.                           */
/*===========================================================================*/
/* RETURN: pointer to API call, NULL.                                        */
/*===========================================================================*/
PROC APIENTRY  wglGetProcAddress( LPCSTR lpszProc )
{
   int   index;

   for( index = 0; index < qt_ext; index++ )
      if( !strcmp(lpszProc,ext[index].name) )
	 return ext[index].proc;

   SetLastError( 0 );
   return NULL;
}
/*===========================================================================*/
/*  No support.                                                              */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglShareLists( HGLRC hglrc1, HGLRC hglrc2 )
{
   SetLastError( 0 );
   return FALSE;
}
/*===========================================================================*/
/*  No support.                                                              */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglUseFontBitmaps( HDC fontDevice, DWORD firstChar, DWORD numChars, DWORD listBase )
{
   SetLastError( 0 );
   return FALSE;
}
/*===========================================================================*/
/*  No support.                                                              */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglUseFontBitmapsW( HDC hdc,DWORD first,DWORD count,DWORD listBase )
{
   SetLastError( 0 );
   return FALSE;
}
/*===========================================================================*/
/*  No support.                                                              */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglUseFontOutlinesA( HDC hdc, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf )
{
   SetLastError( 0 );
   return FALSE;
}
/*===========================================================================*/
/*  No support.                                                              */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglUseFontOutlinesW( HDC hdc,DWORD first,DWORD count, DWORD listBase,FLOAT deviation, FLOAT extrusion,int format, LPGLYPHMETRICSFLOAT lpgmf )
{
   SetLastError( 0 );
   return FALSE ;
}
/*===========================================================================*/
/*  No support.                                                              */
/*===========================================================================*/
/* RETURN: FALSE.                                                            */
/*===========================================================================*/
BOOL APIENTRY  wglSwapLayerBuffers( HDC hdc, UINT fuPlanes )
{
   SetLastError( 0 );
   return FALSE;
}
/*===========================================================================*/
/*  This function will be hooked into the window that has been bound.  Right */
/* now it is used to track the window size and position.  Also the we clean  */
/* up the currrent context when the window is close/destroyed.               */
/*                                                                           */
/* TODO: there might be something wrong here as some games (Heretic II) don't*/
/*      track the window quit right.                                         */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
LONG APIENTRY  wglMonitorProc( HWND hwnd, UINT message, UINT wParam, LONG lParam )
{
  WNDPROC       hOldProc;
  GLint width,
	  height;

  switch( message ) 
  {
//      case WM_PAINT:
//        break;
//      case WM_ACTIVATE:
//         break;
//      case WM_SHOWWINDOW:
//         break;

    case UM_FATALSHUTDOWN:
	 /* Support the API until we die... */
	 MakeCurrent( pD3DDefault );
	 break;

    case WM_MOVE:
    case WM_DISPLAYCHANGE:
    case WM_SIZE:
	 ResizeContext( pD3DCurrent->gl_ctx );
	 break;

    case WM_CLOSE:
    case WM_DESTROY:
	 /* Support the API until we die... */
	 hOldProc = pD3DCurrent->hOldProc;
	 DestroyContext( pD3DCurrent );
	 return (hOldProc)(hwnd,message,wParam,lParam);
  }

  return (pD3DCurrent->hOldProc)(hwnd,message,wParam,lParam);
}

/**********************************************************************/
/*****              Miscellaneous device driver funcs             *****/
/**********************************************************************/

/*===========================================================================*/
/*  Not reacting to this as I'm only supporting drawing to the back buffer   */
/* right now.                                                                */
/*===========================================================================*/
/* RETURN: TRUE.                                                             */
/*===========================================================================*/
static GLboolean SetBuffer( GLcontext *ctx, GLenum buffer )
{
   if (buffer == GL_BACK_LEFT)
      return GL_TRUE;
   else
      return GL_FALSE;
}
/*===========================================================================*/
/*  This proc will be called by Mesa when the viewport has been set.  So if  */
/* we have a context and it isn't the default then we should let D3D know of */
/* the change.                                                               */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void SetViewport( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
   RECT           rect;

   /* Make sure we can set a viewport. */
   if ( pContext->pShared && (pContext != pD3DDefault) )
   {
	 // TODO: might be needed.
     UpdateScreenPosHAL( pContext->pShared );
	rect.left   = x;
	rect.right  = x + w;
	rect.top    = y;
	rect.bottom = y + h;

	// TODO: shared struct should make this call smaller
     SetViewportHAL( pContext->pShared, &rect, 0.0F, 1.0F );
   }
}
/*===========================================================================*/
/*  This function could be better I guess but I decided just to grab the four*/
/* components and store then seperately.  Makes it easier to use IMHO.       */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void ClearColor( GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

   pContext->aClear = a;
   pContext->bClear = b;
   pContext->gClear = g;
   pContext->rClear = r;
}
/*===========================================================================*/
/*  This function could be better I guess but I decided just to grab the four*/
/* components and store then seperately.  Makes it easier to use IMHO.       */
/* (is there an echo in here?)                                               */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void SetColor( GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

   pContext->aCurrent = a;
   pContext->bCurrent = b;
   pContext->gCurrent = g;
   pContext->rCurrent = r;
}
/*===========================================================================*/
/*                                                                           */
/*                                                                           */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static const char *RendererString( void )
{
  static char pszRender[64];

  strcpy( pszRender, "altD3D " );

  if ( pD3DCurrent->pShared->bHardware )
    strcat( pszRender, "(HW)");
  else
    strcat( pszRender, "(SW)");

  return (const char *)pszRender;
}
/*===========================================================================*/
/*  This function will choose which set of pointers Mesa will use based on   */
/* whether we hard using hardware or software.  I have added another set of  */
/* pointers that will do nothing but stop the API from crashing.             */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void SetupDDPointers( GLcontext *ctx )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

   // TODO: write a generic NULL support for the span render. 
   if ( pContext->pShared && pContext->pShared->bHardware )
   {
	ctx->Driver.UpdateState = SetupHWDDPointers;
   }
   else if ( pContext == pD3DDefault )
   {
	ctx->Driver.UpdateState = SetupNULLDDPointers;
   }
   else
   {
	ctx->Driver.UpdateState = SetupSWDDPointers;
   }
}
/*===========================================================================*/
/*  This function will populate all the Mesa driver hooks. This version of   */
/* hooks will do nothing but support the API when we don't have a valid      */
/* context bound.  This is mostly for applications that don't behave right   */
/* and also to help exit as clean as possable when we have a FatalError.     */
/*===========================================================================*/
/* RETURN: pointer to the specific function.                                 */
/*===========================================================================*/
static void SetupNULLDDPointers( GLcontext *ctx )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

   /* Initialize all the pointers in the DD struct.  Do this whenever */
   /* a new context is made current or we change buffers via set_buffer! */
   ctx->Driver.UpdateState          = SetupNULLDDPointers;

   /* State management hooks. */
   ctx->Driver.Color                = NULLSetColor;
   ctx->Driver.ClearColor           = NULLClearColor;
   ctx->Driver.Clear                = NULLClearBuffers;
   ctx->Driver.SetBuffer            = NULLSetBuffer;

   /* Window management hooks. */
   ctx->Driver.GetBufferSize        = NULLGetBufferSize;

   /* Primitive rendering hooks. */
   ctx->Driver.TriangleFunc         = NULL;
   ctx->Driver.RenderVB             = NULL;

   /* Pixel/span writing functions: */
   ctx->Driver.WriteRGBASpan        = NULLWrSpRGBA;
   ctx->Driver.WriteRGBSpan         = NULLWrSpRGB;
   ctx->Driver.WriteMonoRGBASpan    = NULLWrSpRGBAMono;
   ctx->Driver.WriteRGBAPixels      = NULLWrPiRGBA;
   ctx->Driver.WriteMonoRGBAPixels  = NULLWrPiRGBAMono;

   /* Pixel/span reading functions: */
   ctx->Driver.ReadRGBASpan         = NULLReSpRGBA;
   ctx->Driver.ReadRGBAPixels       = NULLRePiRGBA;

   /* Misc. hooks. */
   ctx->Driver.RendererString    = RendererString;
}
/*===========================================================================*/
/*  This function will populate all the Mesa driver hooks. There are two of  */
/* these functions.  One if we have hardware support and one is there is only*/
/* software.  These functions will be called by Mesa and by the wgl.c when we*/
/* have resized (or created) the buffers.  The thing is that if a window gets*/
/* resized we may loose hardware support or gain it...                       */
/*===========================================================================*/
/* RETURN: pointer to the specific function.                                 */
/*===========================================================================*/
static void SetupSWDDPointers( GLcontext *ctx )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

   /* Initialize all the pointers in the DD struct.  Do this whenever */
   /* a new context is made current or we change buffers via set_buffer! */
   ctx->Driver.UpdateState          = SetupSWDDPointers;

   /* State management hooks. */
   ctx->Driver.Color                = SetColor;
   ctx->Driver.ClearColor           = ClearColor;
   ctx->Driver.Clear                = ClearBuffers;
   ctx->Driver.SetBuffer            = SetBuffer;

   /* Window management hooks. */
   ctx->Driver.GetBufferSize        = GetBufferSize;
   ctx->Driver.Viewport             = SetViewport;

   /* Primitive rendering hooks. */
   ctx->Driver.TriangleFunc         = NULL;
   ctx->Driver.RenderVB             = NULL;

   /* Texture management hooks. */

   /* Pixel/span writing functions: */
   ctx->Driver.WriteRGBASpan        = WSpanRGBA;
   ctx->Driver.WriteRGBSpan         = WSpanRGB;
   ctx->Driver.WriteMonoRGBASpan    = WSpanRGBAMono;
   ctx->Driver.WriteRGBAPixels      = WPixelsRGBA;
   ctx->Driver.WriteMonoRGBAPixels  = WPixelsRGBAMono;

   /* Pixel/span reading functions: */
   ctx->Driver.ReadRGBASpan         = RSpanRGBA;
   ctx->Driver.ReadRGBAPixels       = RPixelsRGBA;

   /* Misc. hooks. */
   ctx->Driver.Flush                = Flush;
   ctx->Driver.RendererString    = RendererString;
}
/*===========================================================================*/
/*  This function will populate all the Mesa driver hooks. There are two of  */
/* these functions.  One if we have hardware support and one is there is only*/
/* software.  These functions will be called by Mesa and by the wgl.c when we*/
/* have resized (or created) the buffers.  The thing is that if a window gets*/
/* resized we may loose hardware support or gain it...                       */
/*===========================================================================*/
/* RETURN: pointer to the specific function.                                 */
/*===========================================================================*/
static void SetupHWDDPointers( GLcontext *ctx )
{
   D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

   /* Initialize all the pointers in the DD struct.  Do this whenever */
   /* a new context is made current or we change buffers via set_buffer! */
   ctx->Driver.UpdateState          = SetupHWDDPointers;

   /* State management hooks. */
   ctx->Driver.Color                = SetColor;
   ctx->Driver.ClearColor           = ClearColor;
   ctx->Driver.Clear                = ClearBuffersD3D;
   ctx->Driver.SetBuffer            = SetBuffer;

   /* Window management hooks. */
   ctx->Driver.GetBufferSize        = GetBufferSize;
   ctx->Driver.Viewport             = SetViewport;

   /* Primitive rendering hooks. */
   ctx->Driver.TriangleFunc         = RenderOneTriangle;
   ctx->Driver.LineFunc                          = RenderOneLine;
   ctx->Driver.RenderVB             = RenderVertexBuffer;

   /* Pixel/span writing functions: */
   ctx->Driver.WriteRGBASpan        = WSpanRGBA;
   ctx->Driver.WriteRGBSpan         = WSpanRGB;
   ctx->Driver.WriteMonoRGBASpan    = WSpanRGBAMono;
   ctx->Driver.WriteRGBAPixels      = WPixelsRGBA;
   ctx->Driver.WriteMonoRGBAPixels  = WPixelsRGBAMono;

   /* Pixel/span reading functions: */
   ctx->Driver.ReadRGBASpan         = RSpanRGBA;
   ctx->Driver.ReadRGBAPixels       = RPixelsRGBA;

   /* Texture management hooks. */
   //   ctx->Driver.BindTexture          = TextureBind;
   ctx->Driver.TexImage             = TextureLoad;
   ctx->Driver.TexSubImage          = TextureSubImage;

   /* Misc. hooks. */
   ctx->Driver.Flush                = Flush;
   ctx->Driver.RendererString    = RendererString;
}
/*===========================================================================*/
/*  This function will release all resources used by the DLL.  Every context */
/* will be clobbered by releaseing all driver desources and then freeing the */
/* context memory.  Most all the work is done in DestroyContext.             */
/*===========================================================================*/
/* RETURN: TRUE.                                                             */
/*===========================================================================*/
static BOOL  TermOpenGL( HINSTANCE hInst )
{
  D3DMESACONTEXT *pTmp,
		 *pNext;

  /* Just incase we are still getting paint msg. */
  MakeCurrent( pD3DDefault );

  /* Walk the list until we get back to the default context. */
  for( pTmp = pD3DDefault->next; pTmp != pD3DDefault; pTmp = pNext )
  {
    pNext = pTmp->next;
    DestroyContext( pTmp );
  }
  DestroyContext( pD3DDefault );

  return TRUE;
}
/*===========================================================================*/
/*  This function is an internal function that will clean up all the Mesa    */
/* context bound to this D3D context.  Also any D3D stuff that this context  */
/* uses will be unloaded.                                                    */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
static void DestroyContext( D3DMESACONTEXT *pContext )
{
  D3DMESACONTEXT        *pTmp;

  /* Walk the list until we find the context before this one. */
  for( pTmp = pD3DDefault; pTmp && (pTmp->next != pContext); pTmp = pTmp->next )
    if ( pTmp == pTmp->next )
	 break;

  /* If we never found it it must already be deleted. */
  if ( pTmp->next != pContext )
    return;

  /* Make sure we are not using this context. */
  if ( pContext == pD3DCurrent )
    MakeCurrent( pD3DDefault );

   /* Free the Mesa stuff. */
   if ( pContext->gl_visual ) 
   {
      gl_destroy_visual( pContext->gl_visual );
      pContext->gl_visual = NULL;
   }
   if ( pContext->gl_buffer ) 
   {
      gl_destroy_framebuffer( pContext->gl_buffer );
      pContext->gl_buffer = NULL;
   }
   if ( pContext->gl_ctx )    
   {
      gl_destroy_context( pContext->gl_ctx );
      pContext->gl_ctx = NULL;
   }

   /* Now dump the D3D. */
   if ( pContext->pShared )
	TermHAL( pContext->pShared );

   /* Update the previous context's link. */
   pTmp->next = pContext->next;

   /* Gonzo. */
   FREE( pContext );
}
/*===========================================================================*/
/*  This function will pull the supplied context away from Win32.  Basicly it*/
/* will remove the hook from the window Proc.                                */
/*                                                                           */
/* TODO: might want to serialize this stuff...                               */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
static BOOL UnBindWindow( D3DMESACONTEXT *pContext )
{
  if ( pContext == NULL )
    return FALSE;

  if ( pContext == pD3DDefault )
    return TRUE;

  /* Make sure we always have a context bound. */
  if ( pContext == pD3DCurrent )
    pD3DCurrent = pD3DDefault;

  SetWindowLong( pContext->pShared->hwnd, GWL_WNDPROC, (LONG)pContext->hOldProc );
  pContext->hOldProc   = NULL;

  return TRUE;
}
/*===========================================================================*/
/*  There are two cases that allow for a faster clear when we know that the  */
/* whole buffer is cleared and that there is no clipping.                    */
/*===========================================================================*/
/* RETURN: the original mask with the bits cleared that represents the buffer*
/* or buffers we just cleared.                                               */
/*===========================================================================*/
GLbitfield ClearBuffersD3D( GLcontext *ctx, GLbitfield mask, GLboolean all, GLint x, GLint y, GLint width, GLint height )
{
  D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  DWORD          dwFlags = 0;

  if ( mask & GL_COLOR_BUFFER_BIT )
  {
    dwFlags |= D3DCLEAR_TARGET;
    mask &= ~GL_COLOR_BUFFER_BIT;
  }
  if ( mask & GL_DEPTH_BUFFER_BIT )
  {
    dwFlags |= D3DCLEAR_ZBUFFER;
    mask &= ~GL_DEPTH_BUFFER_BIT;
  }
  if ( dwFlags == 0 )
    return mask;

  ClearHAL( pContext->pShared, 
		  dwFlags, 
		  all, 
		  x, y, 
		  width, height, 
		  ((pContext->aClear<<24) | (pContext->rClear<<16) | (pContext->gClear<<8) | (pContext->bClear)), 
		  ctx->Depth.Clear, 
		  0 );

  return mask;
}



/*===========================================================================*/
/*  TEXTURE MANAGER: ok here is how I did textures.  Mesa-3.0 will keep track*/
/* of all the textures for us.  So this means that at anytime we can go to   */
/* the Mesa context and get the current texture.  With this in mind this is  */
/* what I did.  I really don't care about what textures get or are loaded    */
/* until I actually have to draw a tri that is textured.  At this point I    */
/* must have the texture so I demand the texture by destorying all other     */
/* texture surfaces if need be and load the current one.  This allows for the*/
/* best preformance on low memory cards as time is not wasted loading and    */
/* unload textures.                                                          */
/*===========================================================================*/





/*===========================================================================*/
/*  TextureLoad will try and create a D3D surface from the supplied texture  */
/* object if its level 0 (first).  The surface will be fully filled with the */
/* texture.                                                                  */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void TextureLoad( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLint level, GLint internalFormat, const struct gl_texture_image *image )
{
  D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

  /* TODO: only doing first LOD. */
  if ( (ctx->DriverCtx == NULL) || (level != 0) )
    return;

  CreateTMgrHAL( pContext->pShared, 
			  tObj->Name, 
			  level,
			  tObj->Image[level]->Format,
			  (RECT *)NULL,
			  tObj->Image[level]->Width, 
			  tObj->Image[level]->Height,
			  TM_ACTION_LOAD,
			  (void *)tObj->Image[level]->Data );
}
/*===========================================================================*/
/*  TextureBind make sure that the texture is on the card.  Thats it.        */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void TextureBind( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj )
{
  D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;

  /* TODO: only doing first LOD. */
  if ( (tObj->Image[0] == NULL) || (ctx->DriverCtx == NULL) )
    return;

  CreateTMgrHAL( pContext->pShared, 
			  tObj->Name, 
			  0,
			  tObj->Image[0]->Format,
			  (RECT *)NULL,
			  tObj->Image[0]->Width, 
			  tObj->Image[0]->Height,
			  TM_ACTION_BIND,
			  (void *)tObj->Image[0]->Data );
}
/*===========================================================================*/
/*  TextureSubImage will make sure that the texture being updated is updated */
/* if its on the card.                                                       */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void TextureSubImage( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint internalFormat, const struct gl_texture_image *image )
{
  D3DMESACONTEXT *pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  RECT           rect;

  /* TODO: only doing first LOD. */
  if ( (ctx->DriverCtx == NULL) || (level > 0) )
    return;

  /* Create a dirty rectangle structure. */
  rect.left   = xoffset;
  rect.right  = xoffset + width;
  rect.top    = yoffset;
  rect.bottom = yoffset + height;
  
  CreateTMgrHAL( pContext->pShared, 
			  tObj->Name, 
			  0,
			  tObj->Image[0]->Format, 
			  &rect,
			  tObj->Image[0]->Width, 
			  tObj->Image[0]->Height,
			  TM_ACTION_UPDATE,
			  (void *)tObj->Image[0]->Data );
}

