/* $Id: mesadive.c,v 1.3 2000-12-30 13:55:43 sandervl Exp $ */ /*****************************************************************************/ /* */ /* DIVE code for OpenGL */ /* */ /*****************************************************************************/ #ifdef DIVE #define INCL_BASE #define INCL_WIN #define INCL_GPI #include #include "../../ddraw/divewrap.h" #include #include #include #include #include #define mmioFOURCC( ch0, ch1, ch2, ch3 ) \ ( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \ ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) ) /* Some extra typedefs to be able to import some of the underneath headers */ typedef ULONG HPALETTE; typedef ULONG HPEN; typedef ULONG COLORREF; #include "gl.h" #include "config.h" #include "context.h" #include "wmesadef.h" #include "colors.h" #include "mesadive.h" extern BYTE DITHER_RGB_2_8BIT( int red, int green, int blue, int pixel, int scanline); extern void WMesaUpdateScreenPos(PWMC c,HWND hWnd); extern INT WINAPI MessageBoxA(HWND,LPCSTR,LPCSTR,UINT); extern PWMC Current; DIVE_CAPS DiveCaps; typedef struct tagFN { HWND hwnd; PFNWP f; struct tagFN *Next; }FN; FN *WndFuncs; void StoreFn(HWND hwnd,PFNWP f) { FN *p=WndFuncs; while(p) { if(p->hwnd==hwnd) { p->f=f; return; } p=p->Next; } p=(FN *)calloc(sizeof(FN),1); p->hwnd=hwnd; p->f=f; p->Next=WndFuncs; WndFuncs=p; } PFNWP QueryFn(HWND hwnd) { FN *p=WndFuncs; while(p) { if(p->hwnd==hwnd) return p->f; p=p->Next; } return 0; } FOURCC GetFOURCC(int pf) { switch(pf) { case PF_8A8B8G8R: return FOURCC_BGR4; case PF_8R8G8B: return FOURCC_RGB3; case PF_5R6G5B: return FOURCC_R565; case PF_DITHER8: break; case PF_LOOKUP: return FOURCC_LUT8; case PF_GRAYSCALE: return FOURCC_GREY; case PF_BADFORMAT: return FOURCC_RGB3; case PF_INDEX8: return FOURCC_LUT8; default: break; } return 0; } void DiveWriteBackbuffer( PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b) { PBYTE lpb = pwc->pbPixels; PDWORD lpdw; PWORD lpw; ULONG nBypp = pwc->cColorBits >> 3; ULONG nOffset = iPixel % nBypp; lpb += pwc->ScanWidth * iScanLine; lpb += iPixel * nBypp; lpdw = (LPDWORD)lpb; lpw = (LPWORD)lpb; 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) *lpw = BGR16(r,g,b); else if (nBypp == 3) *lpdw = BGR24(r,g,b); else if (nBypp == 4) *lpdw = BGR32(r,g,b); } void DiveWriteFrontbuffer( PWMC pwc, int iScanLine, int iPixel, BYTE r, BYTE g, BYTE b) { /* Check whether the point is clipped - if so don't draw it! */ POINTL pt; ULONG rc; pt.x=iPixel; pt.y=iScanLine; rc=GpiPtInRegion(pwc->hps,pwc->hrgn,&pt); if(rc!=PRGN_INSIDE) return; if(DiveCaps.fBankSwitched) { MessageBoxA( NULL, "Bank-Switched DIVE access currently not supported", "", MB_OK ); } else { PBYTE lpb = (PBYTE)pwc->ppFrameBuffer; PDWORD lpdw; PWORD lpw; ULONG nBypp = DiveCaps.ulDepth >> 3; /* ULONG nOffset = iPixel % nBypp;*/ iScanLine+=pwc->WinPos.y; iPixel+=pwc->WinPos.x; lpb += iScanLine * DiveCaps.ulScanLineBytes; lpb += iPixel * nBypp; lpdw = (LPDWORD)lpb; lpw = (LPWORD)lpb; 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) *lpw = BGR16(r,g,b); else if (nBypp == 3){ *lpdw = BGR24(r,g,b); } else if (nBypp == 4) *lpdw = BGR32(r,g,b); } } void DiveFlush( PWMC pwc ) { ULONG rc; if(!pwc->hDiveInstance) { dprintf(("DIVE ERROR : no instance!")); return; } if(pwc->DiveSoftwareBlit) { /* Perform software blitting if DiveSetupBlitter failed! */ /* The source and target format will always be identical */ /* This is accomplished by wmesa.c's wmSetPixelFormat */ /* routine that uses the native output-format... */ PBYTE lpb = (PBYTE)pwc->ppFrameBuffer; PBYTE lpbb = pwc->pbPixels; ULONG nBypp = pwc->cColorBits >> 3; ULONG bpl = nBypp*pwc->awidth; lpb += pwc->WinPos.y*DiveCaps.ulScanLineBytes; lpb += pwc->WinPos.x*nBypp; lpbb += (pwc->height-1) * pwc->ScanWidth; for(int y=0; yheight; y++) { memcpy(lpb,lpbb,bpl); lpb+=DiveCaps.ulScanLineBytes; lpbb-=pwc->ScanWidth; } } else { rc=DiveEndImageBufferAccess(pwc->hDiveInstance, pwc->BackBufferNumber); rc=DiveBlitImage(pwc->hDiveInstance, pwc->BackBufferNumber, DIVE_BUFFER_SCREEN); ULONG bsl; rc=DiveBeginImageBufferAccess(pwc->hDiveInstance, pwc->BackBufferNumber, &pwc->pbPixels, &pwc->ScanWidth, &bsl); } } void DiveDefineRegion(PWMC wc,HWND hWnd) { RGNRECT rgnCtl; HWND hwnd=Win32ToOS2Handle(hWnd); ULONG rc; rgnCtl.ircStart=0; rgnCtl.crc=50; rgnCtl.ulDirection=RECTDIR_LFRT_TOPBOT; if(wc->hrgn) GpiDestroyRegion(wc->hps,wc->hrgn); if(wc->hps) WinReleasePS(wc->hps); wc->hps=WinGetPS(hwnd); wc->hrgn=(ULONG)GpiCreateRegion(wc->hps,0,NULL); rc=WinQueryVisibleRegion(hwnd,wc->hrgn); rc=GpiQueryRegionRects(wc->hps,wc->hrgn,NULL,&rgnCtl,(RECTL *)wc->rctls); wc->NumClipRects=rgnCtl.crcReturned; } ULONG DiveBlitSetup(PWMC wc,BOOL fActivate) { SETUP_BLITTER setup; POINTL pointl; SWP swp; ULONG rc; if(!wc) return 0; if(!fActivate) return DiveSetupBlitter(wc->hDiveInstance,0); DiveDefineRegion(wc,wc->hwnd); /* If not double-buffered we don't actually need to setup the blitter! */ /* Also, if setting up the blitter failed once, it will probably fail */ /* again, so no need to pursue this piece of logic... */ if(!wc->db_flag || wc->DiveSoftwareBlit) return 0; memset(&setup,0,sizeof(SETUP_BLITTER)); setup.ulStructLen=sizeof(SETUP_BLITTER); setup.fInvert=1; setup.fccSrcColorFormat=GetFOURCC(wc->pixelformat); setup.fccDstColorFormat=FOURCC_SCRN; setup.ulSrcWidth=wc->awidth; setup.ulDstWidth=wc->awidth; setup.ulSrcHeight=wc->aheight; setup.ulDstHeight=wc->aheight; WinQueryWindowPos(Win32ToOS2Handle(wc->hwnd),&swp); pointl.x=swp.x; pointl.y=swp.y; WinMapWindowPoints(WinQueryWindow(Win32ToOS2Handle(wc->hwnd),QW_PARENT), HWND_DESKTOP, &pointl, 1); setup.lScreenPosX=pointl.x; setup.lScreenPosY=pointl.y; setup.ulNumDstRects=wc->NumClipRects; setup.pVisDstRects=(RECTL *)wc->rctls; rc=DiveSetupBlitter(wc->hDiveInstance,&setup); if(rc==DIVE_ERR_INVALID_CONVERSION) { /* Hmmm, my Matrox does this all the time in 24-bit depth mode */ /* It works in lower color-depths, but in order to use Dive even */ /* if the conversion-code in DIVE is somehow malfunctioning use */ /* a software blitter to blit the image. Do however change the */ /* backbuffer's pixelformat to that of the screen. */ wc->DiveSoftwareBlit=TRUE; rc=0; } return rc; } MRESULT EXPENTRY os2DiveWndProc(HWND hwnd,ULONG msg,MPARAM mp1,MPARAM mp2) { PFNWP f=QueryFn(hwnd); ULONG rc; switch(msg) { case WM_VRNENABLED: if(Current) { DiveBlitSetup(Current,TRUE); WMesaUpdateScreenPos(Current,Current->hwnd); } break; case WM_VRNDISABLED: if(Current) DiveBlitSetup(Current,FALSE); break; case WM_SETFOCUS: if(Current) DiveDefineRegion(Current,Current->hwnd); break; case WM_SIZE: if(Current) { WMesaUpdateScreenPos(Current,Current->hwnd); /* DiveResizeBuffers(Current->width,Current->Height);*/ } break; case WM_DESTROY: WinSetVisibleRegionNotify(hwnd,FALSE); break; } return (*f)(hwnd,msg,mp1,mp2); } PBYTE AllocateBuffer(int width,int height,int pf,ULONG *s) { *s=width*4; return (PBYTE)malloc(width*height*4); } /* * doInit - do work required for every instance of the application: * create the window, initialize data */ BOOL DiveInit( PWMC wc, HWND hwnd) { ULONG rc; RECT rect; /* wc->fullScreen = displayOptions.fullScreen; wc->gMode = displayOptions.mode;*/ wc->hwnd = hwnd; /* Register Region change Notifications for our window */ /* This allows us to set the correct clipping rects and window position */ /* We must subclass the OS/2 hwnd in order to accomplish this, since the*/ /* WM_VRNxxxxx messages are not relayed to the WIN hwnd. */ PFNWP f=WinSubclassWindow(Win32ToOS2Handle(hwnd),(PFNWP)os2DiveWndProc); StoreFn(Win32ToOS2Handle(hwnd),f); WinSetVisibleRegionNotify(Win32ToOS2Handle(hwnd),TRUE); /* stereo_flag = displayOptions.stereo; if(wc->db_flag!= TRUE) stereo_flag = FALSE; */ rc=DiveOpen(&wc->hDiveInstance, FALSE, &wc->ppFrameBuffer); dprintf(("OPENGL32: Created a new dive-instance (%08X) - pfb %08X - rc was %d", wc->hDiveInstance, wc->ppFrameBuffer, rc)); if(rc) return FALSE; /* For later? Switch to FullScreen mode ... switch( wc->gMode ) { case 1: ddrval = DiveSetDisplayMode( wc->lpDD, 640, 480, displayOptions.bpp); break; case 2: ddrval = DiveSetDisplayMode( wc->lpDD, 800, 600, displayOptions.bpp); break; case 3: ddrval = DiveSetDisplayMode( wc->lpDD, 1024, 768, displayOptions.bpp); break; case 4: ddrval = DiveSetDisplayMode( wc->lpDD, 1152, 864, displayOptions.bpp); break; case 5: ddrval = DiveSetDisplayMode( wc->lpDD, 1280, 1024, displayOptions.bpp); break; } */ /* If in double-buffer mode allocate an offscreen rendering buffer! */ if(wc->db_flag) { wc->BackBufferNumber=0; wc->awidth=wc->width; wc->aheight=wc->height; rc=DiveAllocImageBuffer(wc->hDiveInstance, &wc->BackBufferNumber, GetFOURCC(wc->pixelformat), wc->awidth, wc->aheight, 0, 0); dprintf(("Allocated imagebuffer %d (double-buffered screen). rc is %d",wc->BackBufferNumber,rc)); if(rc==DIVE_ERR_SOURCE_FORMAT) { /* Darn - the driver doesn't support the format we want! */ /* Well, just allocate it ourselves then!! */ wc->BackBufferOwnAllocation=TRUE; wc->pbPixels=AllocateBuffer(wc->awidth, wc->aheight, wc->pixelformat, &wc->ScanWidth); wc->BackBufferNumber=0; rc=DiveAllocImageBuffer(wc->hDiveInstance, &wc->BackBufferNumber, GetFOURCC(wc->pixelformat), wc->awidth, wc->aheight, wc->ScanWidth, wc->pbPixels); dprintf(("Allocated imagebuffer @%08X. rc is %d",wc->pbPixels,rc)); } else { if(rc) { DiveClose(wc->hDiveInstance); wc->hDiveInstance=0; return FALSE; } } ULONG bsl; rc=DiveBeginImageBufferAccess(wc->hDiveInstance, wc->BackBufferNumber, &wc->pbPixels, &wc->ScanWidth, &bsl); if(rc) { DiveFree(wc); return FALSE; } rc=DiveBlitSetup(wc,TRUE); if(rc) { DiveFree(wc); return FALSE; } } return TRUE; } void DiveFree(PWMC wc) { ULONG rc; if(wc->hDiveInstance!=0) { if(wc->BackBufferNumber) /* A backbuffer allocated??*/ { rc=DiveEndImageBufferAccess(wc->hDiveInstance, wc->BackBufferNumber); rc=DiveFreeImageBuffer(wc->hDiveInstance, wc->BackBufferNumber); } wc->BackBufferNumber=0; rc=DiveClose(wc->hDiveInstance); wc->hDiveInstance=0; } } void _System DiveGlobalInitialize(void)/* Called by INITTERM */ { DiveQueryCaps(&DiveCaps,DIVE_BUFFER_SCREEN); /* WriteLog("OPENGL32: Dive Capabilities\n"); WriteLog("OPENGL32: ulPlaneCount %d\n",DiveCaps.ulPlaneCount); WriteLog("OPENGL32: fScreenDirect %d\n",DiveCaps.fScreenDirect); WriteLog("OPENGL32: fBankSwitched %d\n",DiveCaps.fBankSwitched); WriteLog("OPENGL32: ulDepth %d\n",DiveCaps.ulDepth); WriteLog("OPENGL32: ulHorizontalResolution %d\n",DiveCaps.ulHorizontalResolution); WriteLog("OPENGL32: ulVerticalResolution %d\n",DiveCaps.ulVerticalResolution); WriteLog("OPENGL32: ulScanLineBytes %d\n",DiveCaps.ulScanLineBytes); WriteLog("OPENGL32: fccColorEncoding %08X\n",DiveCaps.fccColorEncoding); WriteLog("OPENGL32: ulApertureSize %d\n",DiveCaps.ulApertureSize); WriteLog("OPENGL32: ulInputFormats %d\n",DiveCaps.ulInputFormats); WriteLog("OPENGL32: ulOutputFormats %d\n",DiveCaps.ulOutputFormats); WriteLog("OPENGL32: ulFormatLength %d\n",DiveCaps.ulFormatLength); WriteLog("OPENGL32: pFormatData %08X\n",DiveCaps.pFormatData); */ } void _System DiveGlobalTerminate(void) { if(Current) { PWMC c=Current; Current=0; if(c->BackBufferNumber) { ULONG ulb=c->BackBufferNumber; c->BackBufferNumber=0; DiveEndImageBufferAccess(Current->hDiveInstance,ulb); } } } BOOL _System DiveDirectAccess(void) { return DiveCaps.fScreenDirect; } ULONG _System DiveQueryDepth(void) { return DiveCaps.ulDepth; } ULONG _System DiveQueryNativePixelFormat(void) { switch(DiveCaps.fccColorEncoding) { case FOURCC_LUT8: return PF_INDEX8; case FOURCC_BGR4: return PF_8A8B8G8R; case FOURCC_RGB3: return PF_8R8G8B; case FOURCC_R565: return PF_5R6G5B; case FOURCC_GREY: return PF_GRAYSCALE; default: break; } return 0; } void _System DiveResizeBuffers(GLint width,GLint height) { ULONG rc; if(!Current) return; if(Current->awidth==width && Current->aheight==height) return; DiveBlitSetup(Current,FALSE); Current->awidth=width; Current->aheight=height; if(Current->db_flag) { rc=DiveEndImageBufferAccess(Current->hDiveInstance, Current->BackBufferNumber); rc=DiveFreeImageBuffer(Current->hDiveInstance, Current->BackBufferNumber); if(Current->BackBufferOwnAllocation) { free(Current->pbPixels); Current->pbPixels=AllocateBuffer(Current->awidth, Current->aheight, Current->pixelformat, &Current->ScanWidth); Current->BackBufferNumber=0; rc=DiveAllocImageBuffer(Current->hDiveInstance, &Current->BackBufferNumber, GetFOURCC(Current->pixelformat), Current->awidth, Current->aheight, Current->ScanWidth, Current->pbPixels); ULONG bsl; rc=DiveBeginImageBufferAccess(Current->hDiveInstance, Current->BackBufferNumber, &Current->pbPixels, &Current->ScanWidth, &bsl); } else { Current->BackBufferNumber=0; rc=DiveAllocImageBuffer(Current->hDiveInstance, &Current->BackBufferNumber, GetFOURCC(Current->pixelformat), Current->awidth, Current->aheight, 0, 0); ULONG bsl; rc=DiveBeginImageBufferAccess(Current->hDiveInstance, Current->BackBufferNumber, &Current->pbPixels, &Current->ScanWidth, &bsl); } } DiveBlitSetup(Current,TRUE); } #endif