/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ /* * $Logfile: /Freespace2/code/Graphics/GrSoft.cpp $ * $Revision: 2.5 $ * $Date: 2003-07-04 02:27:48 $ * $Author: phreak $ * * Code for our software renderer using standard Win32 functions. (Dibsections, etc) * * $Log: not supported by cvs2svn $ * Revision 2.4 2003/03/18 10:07:02 unknownplayer * The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can. * * Revision 2.3 2003/03/02 05:43:49 penguin * ANSI C++ - fixed non-compliant casts to unsigned short and unsigned char * - penguin * * Revision 2.2.2.2 2002/11/04 16:04:21 randomtiger * * Tided up some bumpman stuff and added a few function points to gr_screen. - RT * * Revision 2.2.2.1 2002/11/04 03:02:29 randomtiger * * I have made some fairly drastic changes to the bumpman system. Now functionality can be engine dependant. * This is so D3D8 can call its own loading code that will allow good efficient loading and use of textures that it desparately needs without * turning bumpman.cpp into a total hook infested nightmare. Note the new bumpman code is still relying on a few of the of the old functions and all of the old bumpman arrays. * * I have done this by adding to the gr_screen list of function pointers that are set up by the engines init functions. * I have named the define calls the same name as the original 'bm_' functions so that I havent had to change names all through the code. * * Rolled back to an old version of bumpman and made a few changes. * Added new files: grd3dbumpman.cpp and .h * Moved the bitmap init function to after the 3D engine is initialised * Added includes where needed * Disabled (for now) the D3D8 TGA loading - RT * * Revision 2.2 2002/08/01 01:41:05 penguin * The big include file move * * Revision 2.1 2002/07/07 19:55:59 penguin * Back-port to MSVC * * Revision 2.0 2002/06/03 04:02:23 penguin * Warpcore CVS sync * * Revision 1.2 2002/05/17 02:52:38 mharris * More porting hacks * * Revision 1.1 2002/05/02 18:03:07 mharris * Initial checkin - converted filenames and includes to lower case * * * 12 7/14/99 9:42a Dave * Put in clear_color debug function. Put in base for 3dnow stuff / P3 * stuff * * 11 7/09/99 9:51a Dave * Added thick polyline code. * * 10 6/29/99 10:35a Dave * Interface polygon bitmaps! Whee! * * 9 2/03/99 11:44a Dave * Fixed d3d transparent textures. * * 8 1/24/99 11:37p Dave * First full rev of beam weapons. Very customizable. Removed some bogus * Int3()'s in low level net code. * * 7 12/18/98 1:13a Dave * Rough 1024x768 support for Direct3D. Proper detection and usage through * the launcher. * * 6 12/06/98 2:36p Dave * Drastically improved nebula fogging. * * 5 11/30/98 5:31p Dave * Fixed up Fred support for software mode. * * 4 11/30/98 1:07p Dave * 16 bit conversion, first run. * * 3 11/11/98 5:37p Dave * Checkin for multiplayer testing. * * 2 10/07/98 10:53a Dave * Initial checkin. * * 1 10/07/98 10:49a Dave * * 84 5/20/98 9:46p John * added code so the places in code that change half the palette don't * have to clear the screen. * * 83 5/18/98 11:17a John * Fixed some bugs with software window and output window. * * 82 5/17/98 5:03p John * Fixed some bugs that make the taskbar interfere with the DEBUG-only * mouse cursor. * * 81 5/15/98 2:44p John * Made windowed mode not touch the window if no handle to window found. * * 80 5/14/98 5:42p John * Revamped the whole window position/mouse code for the graphics windows. * * 79 5/07/98 6:58p Hoffoss * Made changes to mouse code to fix a number of problems. * * 78 5/06/98 5:30p John * Removed unused cfilearchiver. Removed/replaced some unused/little used * graphics functions, namely gradient_h and _v and pixel_sp. Put in new * DirectX header files and libs that fixed the Direct3D alpha blending * problems. * * 77 4/23/98 8:24a John * Changed the way palette effect works so that: * 1. If gr_flash isn't called this frame, screen shows no flash. * 2. With hardware, only 3d portion of screen gets flashed. * * 76 4/21/98 5:22p John * Fixed all the &^#@$ cursor bugs with popups. For Glide, had problem * with mouse restoring assuming back buffer was same buffer last frame, * for software, problems with half drawn new frames, then mouse got * restored on top of that with old data. * * 75 4/14/98 12:15p John * Made 16-bpp movies work. * * 74 4/11/98 12:48p John * Made software fade out actually clear screen to black. * * 73 4/01/98 9:21p John * Made NDEBUG, optimized build with no warnings or errors. * * 72 3/25/98 8:07p John * Restructured software rendering into two modules; One for windowed * debug mode and one for DirectX fullscreen. * * 71 3/24/98 3:58p John * Put in (hopefully) final gamma setting code. * * 70 3/17/98 5:55p John * Added code to dump Glide frames. Moved Allender's "hack" code out of * Freespace.cpp into the proper place, graphics lib. * * 69 3/14/98 5:46p John * * 68 3/14/98 5:43p John * Saved area under mouse cursor. Made save_Screen restore it so no mouse * is on those screens. * * 67 3/12/98 8:50a John * took out "allocating zbuffer" mprintf * * 66 3/10/98 4:18p John * Cleaned up graphics lib. Took out most unused gr functions. Made D3D * & Glide have popups and print screen. Took out all >8bpp software * support. Made Fred zbuffer. Made zbuffer allocate dynamically to * support Fred. Made zbuffering key off of functions rather than one * global variable. * * 65 3/06/98 4:09p John * Changed the way we do bitmap RLE'ing... this speds up HUD bitmaps by * about 2x * * 64 3/05/98 4:28p John * Made mouse cursor hide while setting palette. * * 63 3/02/98 5:42p John * Removed WinAVI stuff from Freespace. Made all HUD gauges wriggle from * afterburner. Made gr_set_clip work good with negative x &y. Made * model_caching be on by default. Made each cached model have it's own * bitmap id. Made asteroids not rotate when model_caching is on. * * 62 2/24/98 3:50p John * Made Alt+Tabbing work with Glide. Made Int3's restore Glide screen on * next flip. * * 61 2/24/98 1:59p John * Made gr_aabitmap_ex clip properly * * 60 2/05/98 9:21p John * Some new Direct3D code. Added code to monitor a ton of stuff in the * game. * * 59 1/19/98 6:15p John * Fixed all my Optimized Build compiler warnings * * 58 1/15/98 4:07p John * added grx_set_palette_internal which doesn't clear the screen and flip * before setting the palette. * * 57 1/15/98 4:02p John * Fixed stupid bug on my part where I called graphics rendering functions * from another thread!!! Duh! Fixed it by setting a variable and then * resetting the palette at the next flip. * * 56 1/08/98 5:06p John * Replaced Int3 with a mprintf * * 55 1/08/98 3:10p John * Undid my palette changes for interplay rev * * 54 1/08/98 3:03p John * * 53 1/05/98 11:52a Jasen * JAS: Made graphics code work if os_get_window returns NULL when trying * to go fullscreen. * * 52 12/30/97 6:47p John * Made fade time correct * * 51 12/30/97 6:46p John * Added first rev of palette fade in out functions * * 50 12/21/97 4:33p John * Made debug console functions a class that registers itself * automatically, so you don't need to add the function to * debugfunctions.cpp. * * 49 12/05/97 4:26p John * made palette set code be like it was before. * * 48 12/04/97 8:05p John * added test code to brighten palette * * 47 12/03/97 2:16p John * Took out blur code and fake_vram buffer. * * 46 12/02/97 4:00p John * Added first rev of thruster glow, along with variable levels of * translucency, which retquired some restructing of palman. * * 45 11/30/97 12:18p John * added more 24 & 32-bpp primitives * * 44 11/29/97 2:06p John * added mode 16-bpp support * * 43 11/21/97 11:32a John * Added nebulas. Fixed some warpout bugs. * * 42 11/20/97 9:51a John * added code to force screen to 16-bit even if rendering 8. * * 41 11/17/97 10:33a John * updated force_windowed code. * * 40 11/14/97 3:54p John * Added triple buffering. * * 39 11/14/97 3:08p Johnson * fixed bug with fred. * * 38 11/14/97 12:30p John * Fixed some DirectX bugs. Moved the 8-16 xlat tables into Graphics * libs. Made 16-bpp DirectX modes know what bitmap format they're in. * * 37 11/06/97 4:12p John * Took out debug code that returned NULL for DD. * * 36 11/05/97 12:35p John * added correct gr_bitmap_ex that does clipping * * * 35 10/31/97 9:43a John * fixed red background color bug. * * 34 10/19/97 1:53p John * hacked in a fix to a zbuffer error caused by inaccuracies. * * 33 10/19/97 12:55p John * new code to lock / unlock surfaces for smooth directx integration. * * 32 10/15/97 4:48p John * added 16-bpp aascaler * * 31 10/14/97 4:50p John * more 16 bpp stuff. * * 30 10/14/97 8:08a John * added a bunch more 16 bit support * * 29 10/09/97 5:23p John * Added support for more 16-bpp functions * * 28 10/03/97 9:10a John * added better antialiased line drawer * * 27 9/23/97 11:50a Lawrance * jas: added xparency to rle'd bitblts * * 26 9/23/97 10:45a John * made so you can tell bitblt code to rle a bitmap by passing flag to * gr_set_bitmap * * 25 9/20/97 10:48a John * added motion blur code. * * 24 9/09/97 10:39a Sandeep * fixed warning level 4 * * 23 9/07/97 2:34p John * fixed bug with fullscreen toggling not working when in > 8bpp mode. * * 22 9/03/97 4:32p John * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani * to bm_load functions not needed. Made bmpman keep track of palettes * for bitmaps not mapped into game palettes. * * 21 8/26/97 11:30a John * removed call to restoredisplymode when going from fullscreen to * windowed, which hopefully fixes the screwey taskbar problem. * * 20 8/04/97 4:47p John * added gr_aascaler. * * 19 7/17/97 9:31a John * made all directX header files name start with a v * * 18 7/10/97 2:06p John * added code to specify alphablending type for bitmaps. * * 17 6/20/97 1:50p John * added rle code to bmpman. made gr8_aabitmap use it. * * 16 6/17/97 12:03p John * Moved color/alphacolor functions into their own module. Made all color * functions be part of the low-level graphics drivers, not just the * grsoft. * * 15 6/13/97 5:35p John * added some antialiased bitmaps and lines * * 14 6/12/97 2:50a Lawrance * bm_unlock() now passed bitmap number, not pointer * * 13 6/11/97 5:49p John * Changed palette code to only recalculate alphacolors when needed, not * when palette changes. * * 12 6/11/97 1:12p John * Started fixing all the text colors in the game. * * 11 6/06/97 5:03p John * fixed bug withalpha colors failing after gr_init * * 10 6/06/97 4:41p John * Fixed alpha colors to be smoothly integrated into gr_set_color_fast * code. * * 9 5/29/97 3:09p John * Took out debug menu. * Made software scaler draw larger bitmaps. * Optimized Direct3D some. * * 8 5/16/97 9:11a John * fixed bug that made Ctrl+Break in fullscreen hang * * 7 5/14/97 4:40p John * took out mprintf * * 6 5/14/97 4:38p John * Fixed print_screen bug. * * 5 5/14/97 2:09p John * made fullscreen use 254 palette entries. Used * CreateCompatibleDC(NULL) Instead of GetDC(HWND_DESKTOP) because the * GetDC method fails when you change screen depth dynamically under NT. * * 4 5/14/97 10:53a John * fixed some discrepencies between d3d and software palette setting. * * 3 5/14/97 8:53a John * Fixed a palette bug when switching into/outof d3d mode. * * 2 5/13/97 12:39p John * Got fullscreen mode working. * * 1 5/12/97 12:14p John * * $NoKeywords: $ */ #include #include #include #include "osapi/osapi.h" #include "graphics/2d.h" #include "bmpman/bmpman.h" #include "io/key.h" #include "math/floating.h" #include "palman/palman.h" #include "graphics/grsoft.h" #include "graphics/grinternal.h" // Headers for 2d functions #include "graphics/pixel.h" #include "graphics/line.h" #include "graphics/scaler.h" #include "graphics/tmapper.h" #include "graphics/circle.h" #include "graphics/shade.h" #include "graphics/rect.h" #include "graphics/gradient.h" #include "pcxutils/pcxutils.h" #include "osapi/osapi.h" #include "io/mouse.h" #include "graphics/font.h" #include "io/timer.h" #include "graphics/colors.h" #include "graphics/bitblt.h" #include "bmpman/bmpman.h" #ifdef _WIN32 // Windows specific // This structure is the same as LOGPALETTE except that LOGPALETTE // requires you to malloc out space for the palette, which just isn't // worth the trouble. typedef struct { WORD palVersion; WORD palNumEntries; PALETTEENTRY palPalEntry[256]; } EZ_LOGPALETTE; // This structure is the same as BITMAPINFO except that BITMAPINFO // requires you to malloc out space for the palette, which just isn't // worth the trouble. I also went ahead and threw a handy union to // easily reference the hicolor masks in 15/16 bpp modes. typedef struct { BITMAPINFOHEADER Header; union { RGBQUAD aColors[256]; ushort PalIndex[256]; uint hicolor_masks[3]; } Colors; } EZ_BITMAPINFO; EZ_BITMAPINFO DibInfo; HBITMAP hDibSection = NULL; HBITMAP hOldBitmap = NULL; HDC hDibDC = NULL; void *lpDibBits=NULL; HPALETTE hOldPalette=NULL, hPalette = NULL; #endif // ifdef WIN32 int Gr_soft_inited = 0; static volatile int Grsoft_activated = 0; // If set, that means application got focus, so reset palette void gr_buffer_release() { if ( hPalette ) { if (hDibDC) SelectPalette( hDibDC, hOldPalette, FALSE ); if (!DeleteObject(hPalette)) { mprintf(( "JOHN: Couldn't delete palette object\n" )); } hPalette = NULL; } if ( hDibDC ) { SelectObject(hDibDC, hOldBitmap ); DeleteDC(hDibDC); hDibDC = NULL; } if ( hDibSection ) { DeleteObject(hDibSection); hDibSection = NULL; } } void gr_buffer_create( int w, int h, int bpp ) { int i; if (w & 3) { Int3(); // w must be multiple 4 return; } gr_buffer_release(); memset( &DibInfo, 0, sizeof(EZ_BITMAPINFO)); DibInfo.Header.biSize = sizeof(BITMAPINFOHEADER); DibInfo.Header.biWidth = w; DibInfo.Header.biHeight = h; DibInfo.Header.biPlanes = 1; DibInfo.Header.biClrUsed = 0; switch( bpp ) { case 8: Gr_red.bits = 8; Gr_red.shift = 16; Gr_red.scale = 1; Gr_red.mask = 0xff0000; Gr_green.bits = 8; Gr_green.shift = 8; Gr_green.scale = 1; Gr_green.mask = 0xff00; Gr_blue.bits = 8; Gr_blue.shift = 0; Gr_blue.scale = 1; Gr_blue.mask = 0xff; DibInfo.Header.biCompression = BI_RGB; DibInfo.Header.biBitCount = 8; for (i=0; i<256; i++ ) { DibInfo.Colors.aColors[i].rgbRed = 0; DibInfo.Colors.aColors[i].rgbGreen = 0; DibInfo.Colors.aColors[i].rgbBlue = 0; DibInfo.Colors.aColors[i].rgbReserved = 0; } break; case 15: Gr_red.bits = 5; Gr_red.shift = 10; Gr_red.scale = 8; Gr_red.mask = 0x7C00; Gr_green.bits = 5; Gr_green.shift = 5; Gr_green.scale = 8; Gr_green.mask = 0x3E0; Gr_blue.bits = 5; Gr_blue.shift = 0; Gr_blue.scale = 8; Gr_blue.mask = 0x1F; DibInfo.Header.biCompression = BI_BITFIELDS; DibInfo.Header.biBitCount = 16; DibInfo.Colors.hicolor_masks[0] = Gr_red.mask; DibInfo.Colors.hicolor_masks[1] = Gr_green.mask; DibInfo.Colors.hicolor_masks[2] = Gr_blue.mask; break; case 16: Gr_red.bits = 5; Gr_red.shift = 11; Gr_red.scale = 8; Gr_red.mask = 0xF800; Gr_green.bits = 6; Gr_green.shift = 5; Gr_green.scale = 4; Gr_green.mask = 0x7E0; Gr_blue.bits = 5; Gr_blue.shift = 0; Gr_blue.scale = 8; Gr_blue.mask = 0x1F; DibInfo.Header.biCompression = BI_BITFIELDS; DibInfo.Header.biBitCount = 16; DibInfo.Colors.hicolor_masks[0] = Gr_red.mask; DibInfo.Colors.hicolor_masks[1] = Gr_green.mask; DibInfo.Colors.hicolor_masks[2] = Gr_blue.mask; break; case 24: case 32: Gr_red.bits = 8; Gr_red.shift = 16; Gr_red.scale = 1; Gr_red.mask = 0xff0000; Gr_green.bits = 8; Gr_green.shift = 8; Gr_green.scale = 1; Gr_green.mask = 0xff00; Gr_blue.bits = 8; Gr_blue.shift = 0; Gr_blue.scale = 1; Gr_blue.mask = 0xff; DibInfo.Header.biCompression = BI_RGB; DibInfo.Header.biBitCount = (unsigned short)(bpp); break; default: Int3(); // Illegal bpp } lpDibBits = NULL; hDibDC = CreateCompatibleDC(NULL); hDibSection = CreateDIBSection(hDibDC,(BITMAPINFO *)&DibInfo,DIB_RGB_COLORS,&lpDibBits,NULL,NULL); hOldBitmap = (HBITMAP)SelectObject(hDibDC, hDibSection ); if ( hDibSection == NULL ) { Int3(); // couldn't allocate dib section } } // This makes a best-fit palette from the 256 target colors and // the system colors which should look better than only using the // colors in the range 10-246, but it will totally reorder the palette. // All colors get changed in target_palette. HPALETTE gr_create_palette_0(ubyte * target_palette) { EZ_LOGPALETTE LogicalPalette; HDC ScreenDC; HPALETTE hpal,hpalOld; PALETTEENTRY pe[256]; int NumSysColors, NumColors; int i; // Create a 1-1 mapping of the system palette LogicalPalette.palVersion = 0x300; LogicalPalette.palNumEntries = 256; // Pack in all the colors for (i=0;i<256; i++) { LogicalPalette.palPalEntry[i].peRed = target_palette[i*3+0]; LogicalPalette.palPalEntry[i].peGreen = target_palette[i*3+1]; LogicalPalette.palPalEntry[i].peBlue = target_palette[i*3+2]; LogicalPalette.palPalEntry[i].peFlags = 0; //PC_EXPLICIT; } hpal = CreatePalette( (LOGPALETTE *)&LogicalPalette ); ScreenDC = CreateCompatibleDC(NULL); if ( !(GetDeviceCaps(ScreenDC,RASTERCAPS) & RC_PALETTE) ) { DeleteDC(ScreenDC); return hpal; } NumSysColors = GetDeviceCaps( ScreenDC, NUMCOLORS ); NumColors = GetDeviceCaps( ScreenDC, SIZEPALETTE ); // Reset all the Palette Manager tables SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC ); SetSystemPaletteUse( ScreenDC, SYSPAL_STATIC ); // Enter our palette's values into the free slots hpalOld=SelectPalette( ScreenDC, hpal, FALSE ); RealizePalette( ScreenDC ); SelectPalette( ScreenDC, hpalOld, FALSE ); GetSystemPaletteEntries(ScreenDC,0,NumColors,pe); for (i=0; i= 236 ); GetSystemPaletteEntries(ScreenDC,0,NumSysColors/2,LogicalPalette.palPalEntry); GetSystemPaletteEntries(ScreenDC,UserHighest+1,NumSysColors/2,LogicalPalette.palPalEntry+1+UserHighest); DeleteDC(ScreenDC); for (i=0; i<256; i++ ) { if ( (i >= UserLowest) && (i<=UserHighest) ) { LogicalPalette.palPalEntry[i].peFlags = PC_NOCOLLAPSE; } else LogicalPalette.palPalEntry[i].peFlags = 0; target_palette[i*3+0] = LogicalPalette.palPalEntry[i].peRed; target_palette[i*3+1] = LogicalPalette.palPalEntry[i].peGreen; target_palette[i*3+2] = LogicalPalette.palPalEntry[i].peBlue; } return CreatePalette( (LOGPALETTE *)&LogicalPalette ); } HPALETTE gr_create_palette_254( ubyte * target_palette ) { EZ_LOGPALETTE LogicalPalette; HDC ScreenDC; int NumSysColors, NumColors, UserLowest, UserHighest; int i; // Pack in all the colors for (i=0;i<256; i++) { LogicalPalette.palPalEntry[i].peRed = target_palette[i*3+0]; LogicalPalette.palPalEntry[i].peGreen = target_palette[i*3+1]; LogicalPalette.palPalEntry[i].peBlue = target_palette[i*3+2]; LogicalPalette.palPalEntry[i].peFlags = 0; //PC_EXPLICIT; } // Create a 1-1 mapping of the system palette LogicalPalette.palVersion = 0x300; LogicalPalette.palNumEntries = 256; ScreenDC = CreateCompatibleDC(NULL); // Reset all the Palette Manager tables SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC ); SetSystemPaletteUse( ScreenDC, SYSPAL_STATIC ); if ( !(GetDeviceCaps(ScreenDC,RASTERCAPS) & RC_PALETTE) ) { DeleteDC(ScreenDC); return CreatePalette( (LOGPALETTE *)&LogicalPalette ); } SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC ); NumSysColors = 2; NumColors = GetDeviceCaps( ScreenDC, SIZEPALETTE ); Assert( NumColors <= 256 ); UserLowest = NumSysColors/2; // 10 normally UserHighest = NumColors - NumSysColors/2 - 1; // 245 normally Assert( (UserHighest - UserLowest + 1) >= 236 ); GetSystemPaletteEntries(ScreenDC,0,NumSysColors/2,LogicalPalette.palPalEntry); GetSystemPaletteEntries(ScreenDC,UserHighest+1,NumSysColors/2,LogicalPalette.palPalEntry+1+UserHighest); DeleteDC(ScreenDC); for (i=0; i<256; i++ ) { if ( (i >= UserLowest) && (i<=UserHighest) ) { LogicalPalette.palPalEntry[i].peFlags = PC_NOCOLLAPSE; } else LogicalPalette.palPalEntry[i].peFlags = 0; target_palette[i*3+0] = LogicalPalette.palPalEntry[i].peRed; target_palette[i*3+1] = LogicalPalette.palPalEntry[i].peGreen; target_palette[i*3+2] = LogicalPalette.palPalEntry[i].peBlue; } return CreatePalette( (LOGPALETTE *)&LogicalPalette ); } void grx_set_palette_internal( ubyte * new_pal ) { if ( hPalette ) { if (hDibDC) SelectPalette( hDibDC, hOldPalette, FALSE ); if (!DeleteObject(hPalette)) { mprintf(( "JOHN: Couldn't delete palette object\n" )); } hPalette = NULL; } // Make sure color 0 is black if ( (new_pal[0]!=0) || (new_pal[1]!=0) || (new_pal[2]!=0) ) { // color 0 isn't black!! switch it! int i; int black_index = -1; for (i=1; i<256; i++ ) { if ( (new_pal[i*3+0]==0) && (new_pal[i*3+1]==0) && (new_pal[i*3+2]==0) ) { black_index = i; break; } } if ( black_index > -1 ) { // swap black and color 0, so color 0 is black ubyte tmp[3]; tmp[0] = new_pal[black_index*3+0]; tmp[1] = new_pal[black_index*3+1]; tmp[2] = new_pal[black_index*3+2]; new_pal[black_index*3+0] = new_pal[0]; new_pal[black_index*3+1] = new_pal[1]; new_pal[black_index*3+2] = new_pal[2]; new_pal[0] = tmp[0]; new_pal[1] = tmp[1]; new_pal[2] = tmp[2]; } else { // no black in palette, force color 0 to be black. new_pal[0] = 0; new_pal[1] = 0; new_pal[2] = 0; } } if ( gr_screen.bits_per_pixel==8 ) { // Name n_preserved One-one Speed Windowed? // ------------------------------------------------------------------- // gr_create_palette_256 256 0-255 Slow Yes // gr_create_palette_254 254 1-254 Fast No // gr_create_palette_236 236 10-245 Fast Yes // gr_create_palette_0 0 none Fast Yes /* n_preserved = 256; if ( n_preserved <= 0 ) { hPalette = gr_create_palette_0(new_pal); // No colors mapped one-to-one, but probably has close to all 256 colors in it somewhere. } else if ( n_preserved <= 236 ) { hPalette = gr_create_palette_236(new_pal); // All colors except low 10 and high 10 mapped one-to-one } else if ( n_preserved <= 254 ) { hPalette = gr_create_palette_254(new_pal); // All colors except 0 and 255 mapped one-to-one, but changes system colors. Not pretty in a window. } else { */ hPalette = gr_create_palette_256(new_pal); // All 256 mapped one-to-one, but BLT's are slow. if ( hDibDC ) { int i; for (i=0; i<256; i++ ) { DibInfo.Colors.aColors[i].rgbRed = new_pal[i*3+0]; DibInfo.Colors.aColors[i].rgbGreen = new_pal[i*3+1]; DibInfo.Colors.aColors[i].rgbBlue = new_pal[i*3+2]; DibInfo.Colors.aColors[i].rgbReserved = 0; } hOldPalette = SelectPalette( hDibDC, hPalette, FALSE ); SetDIBColorTable( hDibDC, 0, 256, DibInfo.Colors.aColors ); } } else { hPalette = NULL; } } void grx_set_palette( ubyte * new_pal, int is_alphacolor ) { if ( hPalette ) { Mouse_hidden++; gr_reset_clip(); gr_clear(); gr_flip(); Mouse_hidden--; } grx_set_palette_internal(new_pal); } void grx_print_screen(char * filename) { int i; ubyte **row_data = (ubyte **)malloc( gr_screen.max_h * sizeof(ubyte *) ); if ( !row_data ) { mprintf(( "couldn't allocate enough memory to dump screen\n" )); return; } gr_lock(); for (i=0; i (r2)) (x) = (r2); } while(0) void grx_save_mouse_area(int x, int y, int w, int h ) { Grx_mouse_saved_x1 = x; Grx_mouse_saved_y1 = y; Grx_mouse_saved_x2 = x+w-1; Grx_mouse_saved_y2 = y+h-1; CLAMP(Grx_mouse_saved_x1, gr_screen.clip_left, gr_screen.clip_right ); CLAMP(Grx_mouse_saved_x2, gr_screen.clip_left, gr_screen.clip_right ); CLAMP(Grx_mouse_saved_y1, gr_screen.clip_top, gr_screen.clip_bottom ); CLAMP(Grx_mouse_saved_y2, gr_screen.clip_top, gr_screen.clip_bottom ); Grx_mouse_saved_w = Grx_mouse_saved_x2 - Grx_mouse_saved_x1 + 1; Grx_mouse_saved_h = Grx_mouse_saved_y2 - Grx_mouse_saved_y1 + 1; if ( Grx_mouse_saved_w < 1 ) return; if ( Grx_mouse_saved_h < 1 ) return; // Make sure we're not saving too much! Assert( (Grx_mouse_saved_w*Grx_mouse_saved_h) <= MAX_SAVE_SIZE ); Grx_mouse_saved = 1; gr_lock(); ubyte *sptr, *dptr; dptr = Grx_mouse_saved_data; for (int i=0; i gr_screen.max_w-1 ) { gr_screen.clip_left = gr_screen.max_w-1-x; } if ( gr_screen.clip_right+x < 0 ) { gr_screen.clip_right = -x; } else if ( gr_screen.clip_right+x >= gr_screen.max_w-1 ) { gr_screen.clip_right = gr_screen.max_w-1-x; } if ( gr_screen.clip_top+y < 0 ) { gr_screen.clip_top = -y; } else if ( gr_screen.clip_top+y > gr_screen.max_h-1 ) { gr_screen.clip_top = gr_screen.max_h-1-y; } if ( gr_screen.clip_bottom+y < 0 ) { gr_screen.clip_bottom = -y; } else if ( gr_screen.clip_bottom+y > gr_screen.max_h-1 ) { gr_screen.clip_bottom = gr_screen.max_h-1-y; } gr_screen.clip_width = gr_screen.clip_right - gr_screen.clip_left + 1; gr_screen.clip_height = gr_screen.clip_bottom - gr_screen.clip_top + 1; } // resets the clipping region to entire screen // // should call this before gr_surface_flip() if you clipped some portion of the screen but still // want a full-screen display void grx_reset_clip() { gr_screen.offset_x = 0; gr_screen.offset_y = 0; gr_screen.clip_left = 0; gr_screen.clip_top = 0; gr_screen.clip_right = gr_screen.max_w - 1; gr_screen.clip_bottom = gr_screen.max_h - 1; gr_screen.clip_width = gr_screen.max_w; gr_screen.clip_height = gr_screen.max_h; } // Sets the current bitmap void grx_set_bitmap( int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha, int sx, int sy ) { gr_screen.current_alpha = alpha; gr_screen.current_alphablend_mode = alphablend_mode; gr_screen.current_bitblt_mode = bitblt_mode; gr_screen.current_bitmap = bitmap_num; gr_screen.current_bitmap_sx = sx; gr_screen.current_bitmap_sy = sy; } // clears entire clipping region to black. void grx_clear() { gr_lock(); int i,w; ubyte *pDestBits; w = gr_screen.clip_right-gr_screen.clip_left+1; for (i=gr_screen.clip_top; i<=gr_screen.clip_bottom; i++) { pDestBits = GR_SCREEN_PTR(ubyte,gr_screen.clip_left,i); memset( pDestBits, 0, w ); } gr_unlock(); } void grx_start_frame() { } void grx_stop_frame() { } void gr_soft_fog_set(int fog_mode, int r, int g, int b, float near, float far) { } void gr_soft_get_pixel(int x, int y, int *r, int *g, int *b) { } void grx_fade_in(int instantaneous); void grx_fade_out(int instantaneous); void grx_flash(int r, int g, int b); static ubyte *Gr_saved_screen = NULL; static uint Gr_saved_screen_palette_checksum = 0; static ubyte Gr_saved_screen_palette[768]; int gr8_save_screen() { int i; gr_reset_clip(); if (gr_screen.bits_per_pixel != 8) { mprintf(( "Save Screen only works in 8 bpp!\n" )); return -1; } if ( Gr_saved_screen ) { mprintf(( "Screen alread saved!\n" )); return -1; } Gr_saved_screen = (ubyte *)malloc( gr_screen.max_w*gr_screen.max_h ); if (!Gr_saved_screen) { mprintf(( "Couldn't get memory for saved screen!\n" )); return -1; } Gr_saved_screen_palette_checksum = gr_palette_checksum; memcpy( Gr_saved_screen_palette, gr_palette, 768 ); gr_lock(); for (i=0; i 255 ) { v = 255; } else if ( v < 0 ) { v = 0; } Gr_gamma_lookup[i] = v; } // ubyte new_pal[768]; // if ( gr_screen.bits_per_pixel!=8 ) return; // // for (i=0; i<768; i++ ) { // new_pal[i] = ubyte(Gr_gamma_lookup[gr_palette[i]]); // } // grx_change_palette( new_pal ); gr_screen.signature = Gr_signature++; } void gr_grx_push_texture_matrix(int unit) {} void gr_grx_pop_texture_matrix(int unit) {} void gr_grx_translate_texture_matrix(int unit, vector *shift) {} void gr_soft_init() { // int i; HWND hwnd = (HWND)os_get_window(); // software mode only supports 640x480 Assert(gr_screen.res == GR_640); if(gr_screen.res != GR_640){ gr_screen.res = GR_640; gr_screen.max_w = 640; gr_screen.max_h = 480; } // Prepare the window to go full screen if ( hwnd ) { DWORD style, exstyle; RECT client_rect; exstyle = 0; style = WS_CAPTION | WS_SYSMENU; // Create Game Window client_rect.left = client_rect.top = 0; client_rect.right = gr_screen.max_w; client_rect.bottom = gr_screen.max_h; AdjustWindowRect(&client_rect,style,FALSE); RECT work_rect; SystemParametersInfo( SPI_GETWORKAREA, 0, &work_rect, 0 ); int x = work_rect.left + (( work_rect.right - work_rect.left )-(client_rect.right - client_rect.left))/2; int y = work_rect.top; if ( x < work_rect.left ) { x = work_rect.left; } int WinX = x; int WinY = y; int WinW = client_rect.right - client_rect.left; int WinH = client_rect.bottom - client_rect.top; ShowWindow(hwnd, SW_SHOWNORMAL ); SetWindowLong( hwnd, GWL_STYLE, style ); SetWindowLong( hwnd, GWL_EXSTYLE, exstyle ); SetWindowPos( hwnd, HWND_NOTOPMOST, WinX, WinY, WinW, WinH, SWP_SHOWWINDOW ); SetActiveWindow(hwnd); SetForegroundWindow(hwnd); } Palette_flashed = 0; Palette_flashed_last_frame = 0; gr_screen.bits_per_pixel = 8; gr_screen.bytes_per_pixel = 1; gr_buffer_create( gr_screen.max_w, gr_screen.max_h, gr_screen.bits_per_pixel ); gr_screen.offscreen_buffer_base = lpDibBits; gr_screen.rowsize = DibInfo.Header.biWidth*((gr_screen.bits_per_pixel+7)/8); Assert( DibInfo.Header.biWidth == gr_screen.max_w ); if (DibInfo.Header.biHeight > 0) { // top down gr_screen.offscreen_buffer = (void *)((uint)gr_screen.offscreen_buffer_base + (gr_screen.max_h - 1) * gr_screen.rowsize); gr_screen.rowsize *= -1; } else { // top up gr_screen.offscreen_buffer = gr_screen.offscreen_buffer_base; } grx_init_alphacolors(); gr_screen.gf_flip = grx_flip; gr_screen.gf_flip_window = grx_flip_window; gr_screen.gf_set_clip = grx_set_clip; gr_screen.gf_reset_clip = grx_reset_clip; gr_screen.gf_set_font = grx_set_font; gr_screen.gf_set_color = grx_set_color; gr_screen.gf_set_bitmap = grx_set_bitmap; gr_screen.gf_create_shader = grx_create_shader; gr_screen.gf_set_shader = grx_set_shader; gr_screen.gf_clear = grx_clear; // gr_screen.gf_bitmap = grx_bitmap; // ]gr_screen.gf_bitmap_ex = grx_bitmap_ex; gr_screen.gf_aabitmap = grx_aabitmap; gr_screen.gf_aabitmap_ex = grx_aabitmap_ex; gr_screen.gf_rect = grx_rect; gr_screen.gf_shade = gr8_shade; gr_screen.gf_string = gr8_string; gr_screen.gf_circle = gr8_circle; gr_screen.gf_line = gr8_line; gr_screen.gf_aaline = gr8_aaline; gr_screen.gf_pixel = gr8_pixel; gr_screen.gf_scaler = gr8_scaler; gr_screen.gf_aascaler = gr8_aascaler; gr_screen.gf_tmapper = grx_tmapper; gr_screen.gf_gradient = gr8_gradient; gr_screen.gf_set_palette = grx_set_palette; gr_screen.gf_get_color = grx_get_color; gr_screen.gf_init_color = grx_init_color; gr_screen.gf_init_alphacolor = grx_init_alphacolor; gr_screen.gf_set_color_fast = grx_set_color_fast; gr_screen.gf_print_screen = grx_print_screen; gr_screen.gf_start_frame = grx_start_frame; gr_screen.gf_stop_frame = grx_stop_frame; gr_screen.gf_fade_in = grx_fade_in; gr_screen.gf_fade_out = grx_fade_out; gr_screen.gf_flash = grx_flash; // Retrieves the zbuffer mode. gr_screen.gf_zbuffer_get = gr8_zbuffer_get; gr_screen.gf_zbuffer_set = gr8_zbuffer_set; gr_screen.gf_zbuffer_clear = gr8_zbuffer_clear; gr_screen.gf_save_screen = gr8_save_screen; gr_screen.gf_restore_screen = gr8_restore_screen; gr_screen.gf_free_screen = gr8_free_screen; // Screen dumping stuff gr_screen.gf_dump_frame_start = gr8_dump_frame_start; gr_screen.gf_dump_frame_stop = gr8_dump_frame_stop; gr_screen.gf_dump_frame = gr8_dump_frame; // Gamma stuff gr_screen.gf_set_gamma = gr8_set_gamma; // Lock/unlock stuff gr_screen.gf_lock = gr_soft_lock; gr_screen.gf_unlock = gr_soft_unlock; // region gr_screen.gf_get_region = grx_get_region; // fog stuff gr_screen.gf_fog_set = gr_soft_fog_set; // pixel get gr_screen.gf_get_pixel = gr_soft_get_pixel; // poly culling gr_screen.gf_set_cull = gr_soft_set_cull; // cross fade gr_screen.gf_cross_fade = gr_soft_cross_fade; // filter gr_screen.gf_filter_set = gr_soft_filter_set; // tcache set gr_screen.gf_tcache_set = gr_soft_tcache_set; // set clear color gr_screen.gf_set_clear_color = gr_soft_set_clear_color; // now for the bitmap functions gr_screen.gf_bm_get_next_handle = bm_gfx_get_next_handle; gr_screen.gf_bm_close = bm_gfx_close; gr_screen.gf_bm_init = bm_gfx_init; gr_screen.gf_bm_get_frame_usage = bm_gfx_get_frame_usage; gr_screen.gf_bm_create = bm_gfx_create; gr_screen.gf_bm_load = bm_gfx_load; gr_screen.gf_bm_load_duplicate = bm_gfx_load_duplicate; gr_screen.gf_bm_load_animation = bm_gfx_load_animation; gr_screen.gf_bm_get_info = bm_gfx_get_info; gr_screen.gf_bm_lock = bm_gfx_lock; gr_screen.gf_bm_unlock = bm_gfx_unlock; gr_screen.gf_bm_get_palette = bm_gfx_get_palette; gr_screen.gf_bm_release = bm_gfx_release; gr_screen.gf_bm_unload = bm_gfx_unload; gr_screen.gf_bm_unload_all = bm_gfx_unload_all; gr_screen.gf_bm_page_in_texture = bm_gfx_page_in_texture; gr_screen.gf_bm_page_in_start = bm_gfx_page_in_start; gr_screen.gf_bm_page_in_stop = bm_gfx_page_in_stop; gr_screen.gf_bm_get_cache_slot = bm_gfx_get_cache_slot; gr_screen.gf_bm_24_to_16 = bm_gfx_24_to_16; gr_screen.gf_bm_get_components = bm_gfx_get_components; gr_screen.gf_bm_get_section_size = bm_gfx_get_section_size; gr_screen.gf_bm_page_in_nondarkening_texture = bm_gfx_page_in_nondarkening_texture; gr_screen.gf_bm_page_in_xparent_texture = bm_gfx_page_in_xparent_texture; gr_screen.gf_bm_page_in_aabitmap = bm_gfx_page_in_aabitmap; gr_screen.gf_push_texture_matrix = gr_grx_push_texture_matrix; gr_screen.gf_pop_texture_matrix = gr_grx_pop_texture_matrix; gr_screen.gf_translate_texture_matrix = gr_grx_translate_texture_matrix; gr_reset_clip(); gr_clear(); gr_flip(); } void gr_soft_force_windowed() { } void gr_soft_cleanup() { if (Gr_soft_inited) { gr_buffer_release(); Gr_soft_inited = 0; } } void grx_change_palette( ubyte * new_pal ) { if ( hPalette ) { if (hDibDC) SelectPalette( hDibDC, hOldPalette, FALSE ); if (!DeleteObject(hPalette)) Int3(); hPalette = NULL; } hPalette = gr_create_palette_256(new_pal); // All 256 mapped one-to-one, but BLT's are slow. if ( hDibDC ) { int i; for (i=0; i<256; i++ ) { DibInfo.Colors.aColors[i].rgbRed = new_pal[i*3+0]; DibInfo.Colors.aColors[i].rgbGreen = new_pal[i*3+1]; DibInfo.Colors.aColors[i].rgbBlue = new_pal[i*3+2]; DibInfo.Colors.aColors[i].rgbReserved = 0; } hOldPalette = SelectPalette( hDibDC, hPalette, FALSE ); SetDIBColorTable( hDibDC, 0, 256, DibInfo.Colors.aColors ); } } void grx_flash( int r, int g, int b ) { int t,i; ubyte new_pal[768]; if ( (r==0) && (g==0) && (b==0) ) { return; } Palette_flashed++; for (i=0; i<256; i++ ) { t = gr_palette[i*3+0] + r; if ( t < 0 ) t = 0; else if (t>255) t = 255; new_pal[i*3+0] = (ubyte)t; t = gr_palette[i*3+1] + g; if ( t < 0 ) t = 0; else if (t>255) t = 255; new_pal[i*3+1] = (ubyte)t; t = gr_palette[i*3+2] + b; if ( t < 0 ) t = 0; else if (t>255) t = 255; new_pal[i*3+2] = (ubyte)t; } grx_change_palette( new_pal ); } static int gr_palette_faded_out = 0; #define FADE_TIME (F1_0/4) // How long to fade out void grx_fade_out(int instantaneous) { #ifndef HARDWARE_ONLY int i; ubyte new_pal[768]; if (!gr_palette_faded_out) { if ( !instantaneous ) { int count = 0; fix start_time, stop_time, t1; start_time = timer_get_fixed_seconds(); t1 = 0; do { for (i=0; i<768; i++ ) { int c = (gr_palette[i]*(FADE_TIME-t1))/FADE_TIME; if (c < 0 ) c = 0; else if ( c > 255 ) c = 255; new_pal[i] = (ubyte)c; } grx_change_palette( new_pal ); gr_flip(); count++; t1 = timer_get_fixed_seconds() - start_time; } while ( (t1 < FADE_TIME) && (t1>=0) ); // Loop as long as time not up and timer hasn't rolled stop_time = timer_get_fixed_seconds(); mprintf(( "Took %d frames (and %.1f secs) to fade out\n", count, f2fl(stop_time-start_time) )); } gr_palette_faded_out = 1; } gr_reset_clip(); gr_clear(); gr_flip(); memset( new_pal, 0, 768 ); grx_change_palette( new_pal ); #else Int3(); #endif } void grx_fade_in(int instantaneous) { #ifndef HARDWARE_ONLY int i; ubyte new_pal[768]; if (gr_palette_faded_out) { if ( !instantaneous ) { int count = 0; fix start_time, stop_time, t1; start_time = timer_get_fixed_seconds(); t1 = 0; do { for (i=0; i<768; i++ ) { int c = (gr_palette[i]*t1)/FADE_TIME; if (c < 0 ) c = 0; else if ( c > 255 ) c = 255; new_pal[i] = (ubyte)c; } grx_change_palette( new_pal ); gr_flip(); count++; t1 = timer_get_fixed_seconds() - start_time; } while ( (t1 < FADE_TIME) && (t1>=0) ); // Loop as long as time not up and timer hasn't rolled stop_time = timer_get_fixed_seconds(); mprintf(( "Took %d frames (and %.1f secs) to fade in\n", count, f2fl(stop_time-start_time) )); } gr_palette_faded_out = 0; } memcpy( new_pal, gr_palette, 768 ); grx_change_palette( new_pal ); #else Int3(); #endif }