#define INCL_PM
#define INCL_DOS
#include <os2.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>

static int bmpcount = 0;
static int done = 0;
static HAB hab = NULL;

static HBITMAP bitmap = NULL;
static HPS hpsBitmap = NULL;
static HDC hdcBitmap = NULL;


void draw(HPS hps, int offset)
{
    POINTL pt = {5,5};
    POINTL pt2 = {190,190};
    pt.x += offset;
    pt2.x += offset;

    GpiSavePS(hps);

    // flip into RGB mode.  Colors are easier then.
    GpiCreateLogColorTable(hps,0,LCOLF_RGB,0,0,NULL);


    GpiSetColor(hps,0x000000);

    GpiMove(hps,&pt);

    // draw a rect
    // with only DRO_OUTLINE, the Matrox drivers miss a spot
    // in the lower left
    GpiBox(hps,DRO_OUTLINE,&pt2,0,0);


    GpiSetBackMix(hps,BM_LEAVEALONE);
    GpiSetPattern(hps,PATSYM_NOSHADE);
    
    pt.x = 15 + offset;
    pt.y = 15;
    GpiMove(hps,&pt);
    pt.x = 180 + offset;
    pt.y = 180;

    // with OUTLINEFILL, it misses a pixel in all the corners 
    // EXCEPT the lower left
    GpiBox(hps,DRO_OUTLINEFILL,&pt,0,0);

    pt.x = 100 + offset;
    pt.y = 100;
    GpiMove(hps,&pt);

    ARCPARAMS arcp = {50,50,0,0};
    GpiSetArcParams(hps,&arcp);

    // a full circel
    // with OUTLINE, the Matrox drivers miss 4 pixels, the ones
    // on the exact x and y axis from the center
    GpiFullArc(hps,DRO_OUTLINE,0x18000);


    ARCPARAMS arcp2 = {50,50,25,0};
    GpiSetArcParams(hps,&arcp2);
    // rotated elipses have the same problem
    GpiFullArc(hps,DRO_OUTLINE,0x10000);
    
    ARCPARAMS arcp3 = {50,25,0,0};
    GpiSetArcParams(hps,&arcp3);

    GpiSetColor(hps,0x000000);
    GpiSetBackColor(hps,0x00FFFF);
    GpiSetBackMix(hps,BM_OVERPAINT);
    GpiSetPattern(hps,PATSYM_NOSHADE);
    // with OUTLINEFILL, elipses have a big problem
    // many pixels are missing
    GpiFullArc(hps,DRO_OUTLINEFILL,0x8000);


    //Lines are completely off too
    pt.x = 20+offset;
    pt.y = 20;
    GpiMove(hps,&pt);
    pt.y += 20;
    GpiLine(hps,&pt);
    pt.x += 20;
    GpiLine(hps,&pt);
    pt.y -= 20;
    GpiLine(hps,&pt);
    pt.x -= 20;
    GpiLine(hps,&pt);

    
    // doing a MOVE after the Line corrects the above problem.
    pt.x = 150+offset;
    pt.y = 20;
    GpiMove(hps,&pt);
    pt.y += 20;
    GpiLine(hps,&pt);
    GpiMove(hps,&pt);
    pt.x += 21;
    GpiLine(hps,&pt);
    GpiMove(hps,&pt);
    pt.y -= 20;
    GpiLine(hps,&pt);
    GpiMove(hps,&pt);
    pt.x -= 20;
    GpiLine(hps,&pt);
    GpiMove(hps,&pt);

    pt.x = 160+offset;
    pt.y = 30;
    GpiMove(hps,&pt);
    GpiSetColor(hps,0x0000FF);
    GpiSetBackColor(hps,0x0000FF);

    // we're going to query the color instead of using 0xFFFFFF
    // cause on a 16bit display, white is 0xF8FCF8, not 0xFFFFFF
    // querying the pel gets the correct value to use
    // we could also use GpiQueryNearestColor(hps,0,0xFFFFFF)
    int color = GpiQueryPel(hps,&pt);

    // Fill the white rectangle created with the "corrected" lines
    // with a blue background
    GpiFloodFill(hps,FF_SURFACE,color);

    GpiSetColor(hps,0x00FF00);
    GpiSetBackColor(hps,0x00FF00);
    color = GpiQueryPel(hps,&pt);

    // oops.  We didn't really want blue, we wanted green.  Fill over
    // the blue with green.  Matrox cannot do this on-screen or 
    // off screen
    GpiFloodFill(hps,FF_SURFACE,color);


    GpiRestorePS(hps,-1);
}


void makeBitmap()
{
    DEVOPENSTRUC dopData;
    dopData.pszLogAddress=NULL;
    dopData.pszDriverName="DISPLAY";
    dopData.pdriv=NULL;
    dopData.pszDataType=NULL;
    dopData.pszComment="Testing";
    dopData.pszQueueProcName=NULL;
    dopData.pszQueueProcParams=NULL;
    dopData.pszSpoolerParams=NULL;
    dopData.pszNetworkParams=NULL;
    SIZEL sizlPage = {200,200};
    hdcBitmap=DevOpenDC(hab,OD_MEMORY,"*",9L,(PDEVOPENDATA)&dopData,0L);

    hpsBitmap = NULL;
    if (hdcBitmap) {
        hpsBitmap = GpiCreatePS(hab, hdcBitmap, &sizlPage,PU_PELS|GPIA_ASSOC|GPIT_NORMAL);
    }

    if (!hpsBitmap) {
        if (hdcBitmap) {
            DevCloseDC(hdcBitmap);
            hdcBitmap = NULL;
        } // endif
    } else {
        BITMAPINFOHEADER2 bmih;  /* bit map info structure               */
        LONG alArray[10];

        GpiQueryDeviceBitmapFormats(hpsBitmap,10, alArray);

        memset(&bmih,0, sizeof(BITMAPINFOHEADER2));
        bmih.cbFix = 16;
        bmih.cx = 200;
        bmih.cy = 200;
        bmih.cPlanes = alArray[0];
        bmih.cBitCount = alArray[1];

        bitmap =GpiCreateBitmap(hpsBitmap, &bmih, 0L, NULL, NULL);
        GpiSetBitmap(hpsBitmap,bitmap);
        if (bitmap) {
            GpiSetColor(hpsBitmap,CLR_WHITE);
            GpiErase(hpsBitmap);
            GpiSetColor(hpsBitmap,CLR_BLACK);
            draw(hpsBitmap,0);
        } // endif
    } // endif
}


void destroyBitmap() 
{
    GpiAssociate(hpsBitmap,0L);
    GpiDeleteBitmap(bitmap);
    GpiDestroyPS(hpsBitmap);
    DevCloseDC(hdcBitmap);
}

MRESULT EXPENTRY BitmapBugWinProc(HWND hw,ULONG msg,MPARAM mp1,MPARAM mp2)
{
    MRESULT ret = 0;
    switch (msg) {
    case WM_CREATE:
        makeBitmap();
        break;
    case WM_DESTROY:
        destroyBitmap();
        break;
    case WM_PAINT:
        {
            HPS hps = WinBeginPaint(hw,NULL,NULL);
            POINTL points[3] = {0,0,200,200,0,0};
            GpiSetColor(hps,CLR_WHITE);
            GpiErase(hps);
            GpiSetColor(hps,CLR_BLACK);

            GpiBitBlt(hps,hpsBitmap,3,points,ROP_SRCCOPY,BBO_IGNORE);

            draw(hps,210);
            
            WinEndPaint(hps);
        }
        break;
    default:
        ret = WinDefWindowProc(hw,msg,mp1,mp2);
    } // endswitch
    return ret;
}

void main (int argc, char *argv[])
{
    hab = WinInitialize(0);
    HMQ hmq = WinCreateMsgQueue(hab,0);
    QMSG msg;
    WinRegisterClass(hab,"BitmapBugTestClass",BitmapBugWinProc,CS_SIZEREDRAW,0);
    HWND hwndClient;
    ULONG flags = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | FCF_TASKLIST;
    HWND hwFrm = WinCreateStdWindow(HWND_DESKTOP,WS_VISIBLE,
                  &flags,"BitmapBugTestClass",
                  "Test Bitmap",0,NULL,24,&hwndClient);
    WinSetWindowPos(hwFrm,NULL,5,5,450,300,SWP_SIZE |SWP_MOVE | SWP_SHOW);

    while (WinGetMsg(hab,&msg,NULL,0,0)) {
        WinDispatchMsg(hab,&msg);
    } // endwhile
    WinDestroyWindow(hwFrm);
    WinDestroyMsgQueue(hmq);

    WinTerminate(hab);
}





