/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #pragma off (unreferenced) static char rcsid[] = "$Id: ddgr.c,v 1.1.1.1 2006/03/17 20:00:42 zicodxx Exp $"; #pragma on (unreferenced) #define WIN95 #define _WIN32 #define WIN32_LEAN_AND_MEAN #include #include "ddraw.h" #include #include #include "winapp.h" #include "mem.h" #include "error.h" #include "gr.h" #include "dd.h" #include "mono.h" // Canvas Globals // ---------------------------------------------------------------------------- int dd_gr_initialized = 0; dd_grs_canvas *dd_grd_screencanv = NULL; dd_grs_canvas *dd_grd_backcanv = NULL; dd_grs_canvas *dd_grd_curcanv = NULL; static int ddgr_atexit_called = 0; extern int _DDLockCounter; extern BOOL _DDSysMemSurfacing; extern int W95OldDisplayMode; extern RECT ViewportRect; // Superhack! (from descentw.c. Too much trouble // to move!) // dd_gr_create_canvas // ---------------------------------------------------------------------------- dd_grs_canvas *dd_gr_create_canvas(int w, int h) { dd_grs_canvas *ddnew; grs_canvas *new; DDSCAPS ddsc; ddnew = (dd_grs_canvas *)malloc( sizeof(dd_grs_canvas) ); ddnew->xoff = ddnew->yoff = 0; new = &ddnew->canvas; new->cv_bitmap.bm_x = 0; new->cv_bitmap.bm_y = 0; new->cv_bitmap.bm_w = w; new->cv_bitmap.bm_h = h; new->cv_bitmap.bm_flags = 0; new->cv_bitmap.bm_type = BM_LINEAR; new->cv_bitmap.bm_rowsize = 0; new->cv_bitmap.bm_data = NULL; new->cv_color = 0; new->cv_drawmode = 0; new->cv_font = NULL; new->cv_font_fg_color = 0; new->cv_font_bg_color = 0; ddnew->lpdds = DDCreateSurface(w, h, 0); if (!ddnew->lpdds) Error("dd_gr_create_canvas: Unable to create DD Surface"); ddnew->lock_count = 0; IDirectDrawSurface_GetCaps(ddnew->lpdds, &ddsc); if (ddDriverCaps.offscreen.sysmem) ddnew->sram = 1; else ddnew->sram = 0; return ddnew; } void dd_gr_init_canvas(dd_grs_canvas *canv, int pixtype, int w, int h) { grs_canvas *new; DDSCAPS ddsc; canv->xoff = canv->yoff = 0; new = &canv->canvas; new->cv_bitmap.bm_x = 0; new->cv_bitmap.bm_y = 0; new->cv_bitmap.bm_w = w; new->cv_bitmap.bm_h = h; new->cv_bitmap.bm_flags = 0; new->cv_bitmap.bm_type = BM_LINEAR; new->cv_bitmap.bm_rowsize = 0; new->cv_bitmap.bm_data = NULL; new->cv_color = 0; new->cv_drawmode = 0; new->cv_font = NULL; new->cv_font_fg_color = 0; new->cv_font_bg_color = 0; canv->lpdds = DDCreateSurface(w,h,0); if (!canv->lpdds) Error("dd_gr_create_canvas: Unable to create DD Surface"); canv->lock_count = 0; IDirectDrawSurface_GetCaps(canv->lpdds, &ddsc); if (ddsc.dwCaps & DDSCAPS_VIDEOMEMORY) canv->sram = 0; else if (ddDriverCaps.offscreen.sysmem) canv->sram = 1; else canv->sram = 0; } void dd_gr_reinit_canvas(dd_grs_canvas *canv) { grs_canvas *new; DDSURFACEDESC ddsd; LPDIRECTDRAWSURFACE lpdds; ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; IDirectDrawSurface_GetSurfaceDesc(canv->lpdds, &ddsd); lpdds = canv->lpdds; memset(canv, 0, sizeof(dd_grs_canvas)); canv->lpdds = lpdds; canv->lock_count = 0; canv->xoff = canv->yoff = 0; new = &canv->canvas; new->cv_bitmap.bm_x = 0; new->cv_bitmap.bm_y = 0; new->cv_bitmap.bm_w = ddsd.dwWidth; new->cv_bitmap.bm_h = ddsd.dwHeight; new->cv_bitmap.bm_flags = 0; new->cv_bitmap.bm_type = BM_LINEAR; new->cv_bitmap.bm_rowsize = 0; new->cv_bitmap.bm_data = NULL; new->cv_color = 0; new->cv_drawmode = 0; new->cv_font = NULL; new->cv_font_fg_color = 0; new->cv_font_bg_color = 0; } // dd_gr_free_canvas // ---------------------------------------------------------------------------- void dd_gr_free_canvas(dd_grs_canvas *canvas) { if (canvas == dd_grd_curcanv) { //bad!! freeing current canvas! DebugBreak(); gr_set_current_canvas(NULL); } DDFreeSurface(canvas->lpdds); free(canvas); } // dd_gr_create_sub_canvas // ---------------------------------------------------------------------------- dd_grs_canvas *dd_gr_create_sub_canvas(dd_grs_canvas *cvs, int x, int y, int w, int h) { dd_grs_canvas *ddnew; grs_canvas *canv; grs_canvas *new; canv = &cvs->canvas; if (x+w > canv->cv_bitmap.bm_w) {Int3(); w=canv->cv_bitmap.bm_w-x;} if (y+h > canv->cv_bitmap.bm_h) {Int3(); h=canv->cv_bitmap.bm_h-y;} ddnew = (dd_grs_canvas *)malloc( sizeof(dd_grs_canvas) ); ddnew->xoff = cvs->xoff; ddnew->yoff = cvs->yoff; ddnew->lock_count = 0; ddnew->lpdds = cvs->lpdds; new = &ddnew->canvas; new->cv_bitmap.bm_x = x+canv->cv_bitmap.bm_x; new->cv_bitmap.bm_y = y+canv->cv_bitmap.bm_y; new->cv_bitmap.bm_w = w; new->cv_bitmap.bm_h = h; new->cv_bitmap.bm_flags = 0; new->cv_bitmap.bm_type = canv->cv_bitmap.bm_type; new->cv_bitmap.bm_rowsize = 0; new->cv_bitmap.bm_data = 0; new->cv_color = canv->cv_color; new->cv_drawmode = canv->cv_drawmode; new->cv_font = canv->cv_font; new->cv_font_fg_color = canv->cv_font_fg_color; new->cv_font_bg_color = canv->cv_font_bg_color; ddnew->sram = cvs->sram; return ddnew; } // dd_gr_free_sub_canvas // ---------------------------------------------------------------------------- void dd_gr_free_sub_canvas(dd_grs_canvas *cvs) { free(cvs); } // dd_gr_hacks // ---------------------------------------------------------------------------- void dd_gr_dup_hack(dd_grs_canvas *hacked, dd_grs_canvas *src) { hacked->canvas.cv_bitmap.bm_data = src->canvas.cv_bitmap.bm_data; hacked->canvas.cv_bitmap.bm_rowsize = src->canvas.cv_bitmap.bm_rowsize; } void dd_gr_dup_unhack(dd_grs_canvas *hacked) { hacked->canvas.cv_bitmap.bm_data = 0; hacked->canvas.cv_bitmap.bm_rowsize = 0; } // dd_gr_init // ---------------------------------------------------------------------------- void dd_gr_init() { Assert(!dd_gr_initialized); if (!dd_grd_screencanv) dd_grd_screencanv = (dd_grs_canvas *)malloc(sizeof(dd_grs_canvas)); if (!dd_grd_backcanv) dd_grd_backcanv = (dd_grs_canvas *)malloc(sizeof(dd_grs_canvas)); dd_grd_screencanv->lpdds = NULL; dd_grd_backcanv->lpdds = NULL; if (!ddgr_atexit_called) { atexit(dd_gr_close); ddgr_atexit_called = 1; } dd_gr_initialized = 1; } // dd_gr_close // ---------------------------------------------------------------------------- void dd_gr_close() { Assert(dd_gr_initialized); if (dd_grd_screencanv) free(dd_grd_screencanv); if (dd_grd_backcanv) free(dd_grd_backcanv); dd_grd_screencanv = dd_grd_backcanv = NULL; dd_gr_initialized = 0; } // dd_gr_init_screen // ---------------------------------------------------------------------------- void dd_gr_init_screen() { grs_canvas *new; // Define screen canvas if (dd_grd_screencanv->lpdds != NULL && !IDirectDrawSurface_IsLost(dd_grd_screencanv->lpdds)) { gr_palette_clear(); dd_gr_set_current_canvas(NULL); dd_gr_clear_canvas(BM_XRGB(0,0,0)); if (_DDModeList[W95OldDisplayMode].modex) { dd_gr_flip(); dd_gr_clear_canvas(BM_XRGB(0,0,0)); dd_gr_flip(); } } // Capture the surface's palette. DDSetDisplayMode(W95DisplayMode, 0); grwin_set_winpalette(_lpDD, _lpDDPalette); gr_palette_clear(); gr_init_screen(BM_LINEAR, GRMODEINFO(rw), GRMODEINFO(rh), 0, 0, 0, NULL); dd_grd_screencanv->lock_count = 0; memcpy(&dd_grd_screencanv->canvas, &grd_curscreen->sc_canvas, sizeof(grs_canvas)); // NEW!!! // Scheme 1: // The 'Emulated' Method. // We will define the screen canvas as the Windows equiv to // DOS display memory. This will be our Direct Draw Back canvas. if (GRMODEINFO(emul) || GRMODEINFO(modex)) { dd_grd_screencanv->lpdds = _lpDDSBack; dd_grd_backcanv->lpdds = NULL; dd_grd_curcanv = NULL; } // Scheme 2: // The Page Flipping Full Screen Method // The screen canvas is the actual display // The back canvas is our scratch page // This does not apply to Mode X modes else if (GRMODEINFO(paged) && !GRMODEINFO(modex)) { dd_grd_screencanv->lpdds = _lpDDSPrimary; new = &dd_grd_backcanv->canvas; new->cv_bitmap.bm_x = 0; new->cv_bitmap.bm_y = 0; new->cv_bitmap.bm_w = _DDModeList[W95DisplayMode].rw; new->cv_bitmap.bm_h = _DDModeList[W95DisplayMode].rh; new->cv_bitmap.bm_flags = 0; new->cv_bitmap.bm_type = BM_LINEAR; new->cv_bitmap.bm_rowsize = 0; new->cv_bitmap.bm_data = NULL; new->cv_color = 0; new->cv_drawmode = 0; new->cv_font = NULL; new->cv_font_fg_color = 0; new->cv_font_bg_color = 0; dd_grd_backcanv->lpdds = _lpDDSBack; dd_grd_backcanv->lock_count = 0; dd_grd_curcanv = NULL; } // Scheme 3: // No page flipping (just 1 page), and no use for back surface. else if (GRMODEINFO(dbuf) && !GRMODEINFO(paged)) { dd_grd_screencanv->lpdds = _lpDDSPrimary; dd_grd_backcanv->lpdds = NULL; dd_grd_curcanv = NULL; } // Bad Scheme else { Int3(); // An illegal hacked graphic mode } dd_gr_set_current_canvas(NULL); dd_gr_clear_canvas(BM_XRGB(0,0,0)); // if (GRMODEINFO(modex)) { // dd_gr_flip(); // dd_gr_clear_canvas(BM_XRGB(0,0,0)); // dd_gr_flip(); // } } int dd_gr_restore_canvas(dd_grs_canvas *canvas) { if (!DDRestoreSurface(canvas->lpdds)) { // Recreate surface DDFreeSurface(canvas->lpdds); if (canvas->sram) { canvas->lpdds = DDCreateSysMemSurface(canvas->canvas.cv_bitmap.bm_w, canvas->canvas.cv_bitmap.bm_h); } else { canvas->lpdds = DDCreateSurface(canvas->canvas.cv_bitmap.bm_w, canvas->canvas.cv_bitmap.bm_h, TRUE); } if (!canvas->lpdds) return 0; } return 1; } // dd_gr_screen_lock // copies dd_gr_screencanv to grd_curscreen->sc_canvas // ---------------------------------------------------------------------------- void dd_gr_screen_lock() { if (dd_grd_screencanv->lpdds == _lpDDSPrimary && GRMODEINFO(modex)) Int3(); // Can't do this in ModeX!! dd_gr_lock(dd_grd_screencanv); memcpy(&grd_curscreen->sc_canvas, &dd_grd_screencanv->canvas, sizeof(grs_canvas)); } // dd_gr_screen_unlock // copies grd_curscreen->sc_canvas to dd_gr_screencanv // ---------------------------------------------------------------------------- void dd_gr_screen_unlock() { memcpy(&dd_grd_screencanv->canvas, &grd_curscreen->sc_canvas, sizeof(grs_canvas)); dd_gr_unlock(dd_grd_screencanv); } void dd_gr_lock(dd_grs_canvas *canv) { RECT rect; ubyte *data; grs_bitmap *bmp; int rowsize; if (canv->lock_count == 0) { bmp = &canv->canvas.cv_bitmap; SetRect(&rect,bmp->bm_x,bmp->bm_y,bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h); if (!dd_gr_restore_canvas(canv)) Error("Failed to lock canvas (restore err)!\n"); data = DDLockSurface(canv->lpdds, &rect, &rowsize); canv->canvas.cv_bitmap.bm_rowsize = (short)rowsize; if (!data) Error("Failed to lock canvas! You may need to use the -emul option.\n"); canv->canvas.cv_bitmap.bm_data = data; if (canv == dd_grd_curcanv) { gr_set_current_canvas(&canv->canvas); } } canv->lock_count++; } void dd_gr_lock_d(dd_grs_canvas *canv, char *filename, int line) { RECT rect; ubyte *data; grs_bitmap *bmp; int rowsize; if (canv->lock_count == 0) { bmp = &canv->canvas.cv_bitmap; SetRect(&rect,bmp->bm_x,bmp->bm_y,bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h); if (!dd_gr_restore_canvas(canv)) #ifndef NDEBUG Error("Failed to lock canvas (restore err) (%s line %d)\n", filename, line); #else Error("Failed to lock canvas (restore err)!\n"); #endif data = DDLockSurface(canv->lpdds, &rect, &rowsize); canv->canvas.cv_bitmap.bm_rowsize = (short)rowsize; if (!data) #ifndef NDEBUG Error("Failed to lock canvas (%s line %d)\n", filename, line); #else Error("Failed to lock canvas! You may ned to use the -emul option.\n"); #endif canv->canvas.cv_bitmap.bm_data = data; if (canv == dd_grd_curcanv) { gr_set_current_canvas(&canv->canvas); } } canv->lock_count++; } void dd_gr_unlock(dd_grs_canvas *canv) { if (canv->lock_count == 1) { DDUnlockSurface(canv->lpdds, canv->canvas.cv_bitmap.bm_data); } canv->lock_count--; } // dd_gr_set_current_canvas // This function should do this: // set desired canvas to dd_grd_curcanv // call gr_set_current_canvas // // If desired canvas is NULL, then set current canvas to screen // set grd_curscreen->sc_canvas.cv_bitmap, etc to dd_grd_screencanv info // call gr_set_current_canvas(NULL) // this will use what is in grd_curscreen->etc to do the proper thing // // Note: Must lock desired canvas before calling this. // This causes an address to be delivered to the canvas. // Else address is invalid and will crash. void dd_gr_set_current_canvas(dd_grs_canvas *canvas) { if (canvas == NULL) { dd_grd_curcanv = dd_grd_screencanv; gr_set_current_canvas(&dd_grd_screencanv->canvas); } else { dd_grd_curcanv = canvas; gr_set_current_canvas(&dd_grd_curcanv->canvas); } } // dd_gr_init_sub_canvas // perform gr_init_sub_canvas. // same surface but reset lock count. void dd_gr_init_sub_canvas(dd_grs_canvas *new, dd_grs_canvas *src, int x, int y, int w, int h) { gr_init_sub_canvas(&new->canvas, &src->canvas, x, y, w, h); new->xoff = src->xoff; new->yoff = src->yoff; new->lpdds = src->lpdds; new->lock_count = 0; new->sram = src->sram; } // dd_gr_flip() // performs a general 'flip' of canvases. // If we are in a slow display mode, we will copy the screen canvas // to the display // If we are in a FullScreen mode, then we will just perform a // Direct Draw Flip. void dd_gr_flip() { if (GRMODEINFO(emul)) { dd_gr_blt_display(dd_grd_screencanv, 0,0,0,0, ViewportRect.left, ViewportRect.top, ViewportRect.right-ViewportRect.left, ViewportRect.bottom-ViewportRect.top); } else if (_DDFullScreen) { DDFlip(); } else { Int3(); // Illegal display mode! } } // dd_gr_restore_display // blts the screen canvas to the display // (for Slow modes which emulate a DOS display) void dd_gr_restore_display() { if (GRMODEINFO(emul)) { // We use a offscreen buffer as grd_screencanv, so just // blt this to the display IDirectDrawSurface_Blt(_lpDDSPrimary, NULL, dd_grd_screencanv->lpdds, NULL, DDBLT_WAIT, NULL); } else if (GRMODEINFO(modex)) { // dd_gr_flip(); } } // DD Blt Functions // // dd_gr_blt_notrans // blts one canvas region to another canvas with scaling and // no color keying void dd_gr_blt_notrans(dd_grs_canvas *srccanv, int sx, int sy, int swidth, int sheight, dd_grs_canvas *destcanv, int dx, int dy, int dwidth, int dheight) { RECT srect, drect; RECT *psrect, *pdrect; grs_bitmap *sbmp, *dbmp; psrect = &srect; pdrect = &drect; sbmp = &srccanv->canvas.cv_bitmap; dbmp = &destcanv->canvas.cv_bitmap; if (swidth || sheight) { SetRect(psrect, sx+sbmp->bm_x, sy+sbmp->bm_y, sx+sbmp->bm_x+swidth, sy+sbmp->bm_y+sheight); } else { SetRect(psrect, sbmp->bm_x, sbmp->bm_y, sbmp->bm_w+sbmp->bm_x, sbmp->bm_h+sbmp->bm_y); } if (dwidth || dheight) { SetRect(pdrect, dx+dbmp->bm_x, dy+dbmp->bm_y, dx+dbmp->bm_x+dwidth, dy+dbmp->bm_y+dheight); } else { SetRect(pdrect, dbmp->bm_x, dbmp->bm_y, dbmp->bm_x+dbmp->bm_w, dbmp->bm_y+dbmp->bm_h); } if (_DDFullScreen && !GRMODEINFO(emul)) { IDirectDrawSurface_BltFast(destcanv->lpdds, dx+dbmp->bm_x, dy+dbmp->bm_y, srccanv->lpdds, psrect, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT); } else { IDirectDrawSurface_Blt(destcanv->lpdds, pdrect, srccanv->lpdds, psrect, DDBLT_WAIT, NULL); } } // dd_gr_blt_display (no keying) // blts a canvas region to the display. // for windowed modes, this is the only way to blt // a canvas to the display. void dd_gr_blt_display(dd_grs_canvas *srccanv, int sx, int sy, int swidth, int sheight, int dx, int dy, int dwidth, int dheight) { RECT srect, drect; RECT *psrect, *pdrect; HRESULT result; grs_bitmap *sbmp; if (srccanv->lpdds == _lpDDSPrimary) { Int3(); // This will crash the system } psrect = &srect; pdrect = &drect; sbmp = &srccanv->canvas.cv_bitmap; if (swidth || sheight) { SetRect(psrect, sx+sbmp->bm_x, sy+sbmp->bm_y, sx+sbmp->bm_x+swidth-1, sy+sbmp->bm_y+sheight-1); } else { SetRect(psrect, sbmp->bm_x, sbmp->bm_y, sbmp->bm_w+sbmp->bm_x-1, sbmp->bm_h+sbmp->bm_y-1); } if (dwidth || dheight) { SetRect(pdrect, dx, dy, dx+dwidth-1, dy+dheight-1); } else pdrect = NULL; // We are blting to the display which is _lpDDSPrimary. result = IDirectDrawSurface_Blt(_lpDDSPrimary, pdrect, srccanv->lpdds, psrect, DDBLT_WAIT, NULL); if (result != DD_OK) Error("DDERR: Blt: (%d)\n", (result & 0x0000ffff)); } // dd_gr_blt_screen (no keying) // blts canvas to screen canvas void dd_gr_blt_screen(dd_grs_canvas *srccanv, int sx, int sy, int swidth, int sheight, int dx, int dy, int dwidth, int dheight) { dd_gr_blt_notrans(srccanv, sx, sy, swidth, sheight, dd_grd_screencanv, dx, dy, dwidth, dheight); } // dd_gr_clear_canvas // clears a canvas the 'fast' way. void dd_gr_clear_canvas(int color) { DDBLTFX ddbltfx; HRESULT ddresult; RECT drect; grs_bitmap *bmp; bmp = &dd_grd_curcanv->canvas.cv_bitmap; UpdateWindow(GetLibraryWindow()); ddbltfx.dwSize = sizeof( ddbltfx ); ddbltfx.dwFillColor = (DWORD)color; Assert(_DDLockCounter == 0); SetRect(&drect, bmp->bm_x, bmp->bm_y, bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h); ddresult = IDirectDrawSurface_Blt( dd_grd_curcanv->lpdds, // dest surface &drect, // dest rect NULL, // src surface NULL, // src rect DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); if (ddresult != DD_OK) { if (ddresult == DDERR_SURFACELOST) { if (!dd_gr_restore_canvas(dd_grd_curcanv)) Error("Direct Draw GR library Blt Clear Restore error."); } else Error("Direct Draw GR library Blt Clear error: %x", ddresult); } if (!_DDFullScreen) { Assert(_DDLockCounter == 0); DDGRRESTORE; } }