/***********************************************************************
 * GDI.C
 *  
 *    API for GDI
 *
 *
 * Toby Opferman Copyright (c) 2003
 *
 ***********************************************************************/
 

                                                                     
#include <windows.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <gdi.h>


 /***********************************************************************
  * Macros
  ***********************************************************************/
#define COLOR_GOTO_COLOR(x, y, z) if(x > y) { x--; z = FALSE; } else if(x < y) { x++; z = FALSE; } 


 /***********************************************************************
  * Internal Structures
  ***********************************************************************/
  typedef struct {

      HWND hWnd;
      HDC hDoubleBuffer;
      HDC hDoubleBufferWorker;
      BITMAPINFO BitmapInfo;
      HBITMAP hCompatBitmap;
      HBITMAP hOldCompatBitmap;
      HGDIOBJ hOldBitMap;
      HBITMAP hDBBitMap;
      UCHAR *pBuffer;
      DWORD dwScreenX;
      DWORD dwScreenY;
      PALETTEENTRY VirtualPalette[256];
      DWORD dwOptimizedPaletteLookUp[256];
      //CRITICAL_SECTION csRepaintBlock;

  } GDI, *PGDI;




 /***********************************************************************
  * GDI_Init
  *  
  *    Initialize Full Screen
  *
  * Parameters
  *     Window  Handle
  * 
  * Return Value
  *     Handle To Cubix
  *
  ***********************************************************************/
HGDI WINAPI GDI_Init(HWND hWnd, UINT dwScreenX, UINT dwScreenY)
{
    PGDI pGDI = NULL;
    HDC hDC;
    int iScreenY = dwScreenY;

    /* Bitmaps Are Upside Down, Need To Negate */
    iScreenY = -iScreenY;

    if(pGDI = (PGDI)LocalAlloc(LMEM_ZEROINIT, sizeof(GDI)))
    {
        
        //InitializeCriticalSection(&pGDI->csRepaintBlock);

        pGDI->dwScreenX = dwScreenX;
        pGDI->dwScreenY = dwScreenY;

        pGDI->BitmapInfo.bmiHeader.biSize     = sizeof(BITMAPINFOHEADER);
        pGDI->BitmapInfo.bmiHeader.biBitCount = 32;
        pGDI->BitmapInfo.bmiHeader.biWidth    = dwScreenX;
        pGDI->BitmapInfo.bmiHeader.biHeight   = iScreenY;
        pGDI->BitmapInfo.bmiHeader.biPlanes   = 1;
        pGDI->BitmapInfo.bmiHeader.biCompression = BI_RGB;

        hDC = GetDC(hWnd);

        pGDI->hDoubleBuffer = CreateCompatibleDC(hDC);
        pGDI->hDoubleBufferWorker = CreateCompatibleDC(hDC);
        pGDI->hDBBitMap  = CreateDIBSection(pGDI->hDoubleBufferWorker, &pGDI->BitmapInfo, DIB_RGB_COLORS, (VOID **)&pGDI->pBuffer, NULL, 0);
        pGDI->hCompatBitmap = CreateCompatibleBitmap(hDC, dwScreenX, dwScreenY);
        pGDI->hOldCompatBitmap = SelectObject(pGDI->hDoubleBuffer, pGDI->hCompatBitmap);
        pGDI->hOldBitMap = SelectObject(pGDI->hDoubleBufferWorker, pGDI->hDBBitMap);

        ReleaseDC(hWnd, hDC);
        
    }

    return (HGDI)pGDI;
}



 /***********************************************************************
  * GDI_UnInit
  *  
  *    UnInitialize Test Graphics
  *
  * Parameters
  *     Handle to Test
  * 
  * Return Value
  *     Nothing
  *
  ***********************************************************************/
void WINAPI GDI_UnInit(HGDI hGDI)
{
    PGDI pGDI = (PGDI)hGDI;

    if(pGDI)
    {
        LocalFree(pGDI);
    }
}


 /***********************************************************************
  * GDI_GetSize
  *  
  *    Get The Video DC
  *
  * Parameters
  *     Handle to Test
  * 
  * Return Value
  *     Nothing
  *
  ***********************************************************************/
void WINAPI GDI_GetSize(HGDI hGDI, UINT *ScreenX, UINT *ScreenY)
{
   PGDI pGDI = (PGDI)hGDI;
   
   *ScreenX = pGDI->dwScreenX;
   *ScreenY = pGDI->dwScreenY;
}


 /***********************************************************************
  * GDI_GetDC
  *  
  *    Get The Video DC
  *
  * Parameters
  *     Handle to Test
  * 
  * Return Value
  *     Nothing
  *
  ***********************************************************************/
HDC GDI_GetDC(HGDI hGDI)
{
    PGDI pGDI = (PGDI)hGDI;

    //EnterCriticalSection(&pGDI->csRepaintBlock);
    return pGDI->hDoubleBuffer;
}


 /***********************************************************************
  * GDI_GetDC
  *  
  *    Get The Video DC
  *
  * Parameters
  *     Handle to Test
  * 
  * Return Value
  *     Nothing
  *
  ***********************************************************************/
void GDI_ReleaseDC(HGDI hGDI)
{
    PGDI pGDI = (PGDI)hGDI;

    //LeaveCriticalSection(&pGDI->csRepaintBlock);
}

 /***********************************************************************
  * GDI_BeginPaint
  *  
  *    Get The Video Buffer
  *
  * Parameters
  *     Handle to Test
  * 
  * Return Value
  *     Nothing
  *
  ***********************************************************************/
PUCHAR WINAPI GDI_BeginPaint(HGDI hGDI)
{
   PGDI pGDI = (PGDI)hGDI;

   return pGDI->pBuffer;
}



 /***********************************************************************
  * GDI_EndPaint
  *  
  *    End Painting
  *
  * Parameters
  *     Handle to Test
  * 
  * Return Value
  *     Nothing
  *
  ***********************************************************************/
void WINAPI GDI_EndPaint(HGDI hGDI)
{
    PGDI pGDI = (PGDI)hGDI;

    //EnterCriticalSection(&pGDI->csRepaintBlock);
    BitBlt(pGDI->hDoubleBuffer, 0, 0, pGDI->dwScreenX, pGDI->dwScreenY, pGDI->hDoubleBufferWorker, 0, 0, SRCCOPY);
    //LeaveCriticalSection(&pGDI->csRepaintBlock);
    
}



/***********************************************************************
 * GDI_BlastBuffer
 *  
 *    Clear Video Buffer
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void WINAPI GDI_BlastBuffer(HGDI hGDI, PUCHAR pBuffer)
{
   PGDI pGDI = (PGDI)hGDI;

   memcpy(pGDI->pBuffer, pBuffer, pGDI->dwScreenX*pGDI->dwScreenY*4);
}



/***********************************************************************
 * GDI_ClearVideoBuffer
 *  
 *    Clear Video Buffer
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void WINAPI GDI_ClearVideoBuffer(HGDI hGDI)
{
   PGDI pGDI = (PGDI)hGDI;

   memset(pGDI->pBuffer, 0, pGDI->dwScreenX*pGDI->dwScreenY*4);
}

/***********************************************************************
 * GDI_SetPalette
 *  
 *    
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void WINAPI GDI_SetPalette(HGDI hGDI, PALETTEENTRY *pPaletteEntries)
{
   PGDI pGDI = (PGDI)hGDI;
   DWORD dwIndex;

   for(dwIndex = 0; dwIndex < 256; dwIndex++)
   {
      pGDI->VirtualPalette[dwIndex].peBlue  = pPaletteEntries[dwIndex].peBlue;
      pGDI->VirtualPalette[dwIndex].peGreen = pPaletteEntries[dwIndex].peGreen;
      pGDI->VirtualPalette[dwIndex].peRed   = pPaletteEntries[dwIndex].peRed;

      pGDI->dwOptimizedPaletteLookUp[dwIndex] = pGDI->VirtualPalette[dwIndex].peBlue | (pGDI->VirtualPalette[dwIndex].peGreen<<8) | (pGDI->VirtualPalette[dwIndex].peRed<<16);
   }
}


/***********************************************************************
 * GDI_FadePalette
 *  
 *    
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL WINAPI GDI_FadePalette(HGDI hGDI)
{
   PGDI pGDI = (PGDI)hGDI;
   BOOL bFaded = TRUE;
   DWORD dwIndex;

   for(dwIndex = 0; dwIndex < 256; dwIndex++)
   {
      COLOR_GOTO_COLOR(pGDI->VirtualPalette[dwIndex].peBlue, 0, bFaded);
      COLOR_GOTO_COLOR(pGDI->VirtualPalette[dwIndex].peGreen, 0, bFaded);
      COLOR_GOTO_COLOR(pGDI->VirtualPalette[dwIndex].peRed, 0, bFaded);

      pGDI->dwOptimizedPaletteLookUp[dwIndex] = pGDI->VirtualPalette[dwIndex].peBlue | (pGDI->VirtualPalette[dwIndex].peGreen<<8) | (pGDI->VirtualPalette[dwIndex].peRed<<16);
   }

   return bFaded;
}


/***********************************************************************
 * GDI_GetVPalEntry
 *  
 *    
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
DWORD WINAPI GDI_GetVPalEntry(HGDI hGDI, DWORD dwIndex)
{
   PGDI pGDI = (PGDI)hGDI;

   return pGDI->dwOptimizedPaletteLookUp[dwIndex];
}

/***********************************************************************
 * GDI_SetPixelUsingVPal
 *  
 *    
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void WINAPI GDI_SetPixelUsingVPal(HGDI hGDI, DWORD dwIndexX, DWORD dwIndexY, DWORD dwIndex)
{
   PGDI pGDI = (PGDI)hGDI;

   memcpy(&pGDI->pBuffer[(dwIndexX*4) + (dwIndexY*pGDI->dwScreenX*4)], &pGDI->dwOptimizedPaletteLookUp[dwIndex], 4);

}



/***********************************************************************
 * DirectX_FadeToPalette
 *  
 *    
 *
 * Parameters
 *     Video Buffer
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL WINAPI GDI_FadeToPalette(HGDI hGDI, PALETTEENTRY *pPaletteEntries)
{
   PGDI pGDI = (PGDI)hGDI;
   BOOL bFaded = TRUE;
   DWORD dwIndex;

   for(dwIndex = 0; dwIndex < 256; dwIndex++)
   {
      COLOR_GOTO_COLOR(pGDI->VirtualPalette[dwIndex].peBlue, pPaletteEntries[dwIndex].peBlue, bFaded);
      COLOR_GOTO_COLOR(pGDI->VirtualPalette[dwIndex].peGreen, pPaletteEntries[dwIndex].peGreen, bFaded);
      COLOR_GOTO_COLOR(pGDI->VirtualPalette[dwIndex].peRed, pPaletteEntries[dwIndex].peRed, bFaded);

      pGDI->dwOptimizedPaletteLookUp[dwIndex] = pGDI->VirtualPalette[dwIndex].peBlue | (pGDI->VirtualPalette[dwIndex].peGreen<<8) | (pGDI->VirtualPalette[dwIndex].peRed<<16);
   }

   return bFaded;
}







/***********************************************************************
 * GDI_Debug
 *  
 *    Debug Shit
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
 void GDI_Debug(char *pszFormatString, ...)
 {
     char DebugString[256];
     va_list vl;

     va_start(vl, pszFormatString);
     vsprintf(DebugString, pszFormatString, vl);
     va_end(vl);

     OutputDebugStringA(DebugString);
 }





