/* * Seven Kingdoms: Ancient Adversaries * * Copyright 1997,1998 Enlight Software Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ //Filename : OVGA.CPP //Description : VGA manipulation functions (Direct Draw version) #define DEBUG_LOG_LOCAL 1 #include #include #include #include #include #include #include #include #include #include // ##### begin Gilbert 16/9 #######// #include // ##### end Gilbert 16/9 #######// //-------- Define constant --------// #define UP_OPAQUE_COLOR (VGA_GRAY+10) #define DOWN_OPAQUE_COLOR (VGA_GRAY+13) //------ Define static class member vars ---------// char Vga::use_back_buf = 0; char Vga::opaque_flag = 0; VgaBuf* Vga::active_buf = &vga_front; // default: front buffer char low_video_memory_flag = 0; //-------- Begin of function Vga::Vga ----------// Vga::Vga() { memset( this, 0, sizeof(Vga) ); vga_color_table = new ColorTable; } //-------- End of function Vga::Vga ----------// //-------- Begin of function Vga::~Vga ----------// Vga::~Vga() { deinit(); // 1-is final delete vga_color_table; err_when( back_up_pal ); // this must be free up immediately after its use } //-------- End of function Vga::~Vga ----------// //-------- Begin of function Vga::init ----------// BOOL Vga::init() { char* warnStr = "Warning: Due to the low memory of your display card, " "you may experience problems when you quit the game or " "switch tasks during the game. " "To avoid this problem, set your Windows display " "to 800x600 256 color mode before running the game."; //--------- Initialize DirectDraw object --------// if( !init_dd() ) return FALSE; // get current display mode DDSURFACEDESC ddsd; DDSCAPS ddsCaps; DWORD dwTotal; DWORD dwFree; memset(&ddsd, 0, sizeof(ddsd) ); ddsd.dwSize = sizeof(ddsd); ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY; if( dd_obj->GetDisplayMode(&ddsd) == DD_OK && dd_obj->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree) == DD_OK ) { if( dwFree < VGA_WIDTH*VGA_HEIGHT*VGA_BPP/8 && !(ddsd.dwWidth==VGA_WIDTH && ddsd.dwHeight==VGA_HEIGHT && (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)) ) { // not enough memory except same video mode ShowCursor(TRUE); // approximation of video memory required, actual video memory used should be calculated from vga_(true)_front->buf_pitch() extern char new_config_dat_flag; if( new_config_dat_flag ) { MessageBox(sys.main_hwnd, warnStr, WIN_TITLE, MB_OK | MB_ICONWARNING | MB_SETFOREGROUND ); } low_video_memory_flag = 1; ShowCursor(FALSE); } } if( !set_mode() ) { MessageBox( sys.main_hwnd, "Unable to change to 800x600x8bpp video mode. " "Your display might not support this video mode.", WIN_TITLE, MB_OK | MB_ICONWARNING | MB_SETFOREGROUND ); return FALSE; } return TRUE; } //-------- End of function Vga::init ----------// //-------- Begin of function Vga::init_dd ----------// BOOL Vga::init_dd() { if(dd_obj) // the Direct Draw object has been initialized already return TRUE; //--------- Create direct draw object --------// DEBUG_LOG("Attempt DirectDrawCreate"); LPDIRECTDRAW dd1Obj; int rc = DirectDrawCreate( NULL, &dd1Obj, NULL ); DEBUG_LOG("DirectDrawCreate finish"); if( rc != DD_OK ) { #ifdef DEBUG debug_msg("DirectDrawCreate failed err=%d", rc); #endif return FALSE; } //-------- Query DirectDraw2 interface --------// DEBUG_LOG("Attempt Query DirectDraw2"); rc = dd1Obj->QueryInterface(IID_IDirectDraw2, (void **)&dd_obj); DEBUG_LOG("Query DirectDraw2 finish"); if( rc != DD_OK ) { #ifdef DEBUG debug_msg("Query DirectDraw2 failed err=%d", rc); #endif dd1Obj->Release(); return FALSE; } dd1Obj->Release(); return TRUE; } //-------- End of function Vga::init_dd ----------// //-------- Begin of function Vga::set_mode ----------// BOOL Vga::set_mode() { DWORD dwStyle; HRESULT rc; //-----------------------------------------------------------// // Convert it to a plain window //-----------------------------------------------------------// dwStyle = GetWindowStyle(sys.main_hwnd); dwStyle |= WS_POPUP; dwStyle &= ~(WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX); SetWindowLong(sys.main_hwnd, GWL_STYLE, dwStyle); //-----------------------------------------------------------// // grab exclusive mode if we are going to run as fullscreen // otherwise grab normal mode. //-----------------------------------------------------------// DEBUG_LOG("Attempt DirectDraw SetCooperativeLevel"); rc = dd_obj->SetCooperativeLevel( sys.main_hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); DEBUG_LOG("DirectDraw SetCooperativeLevel finish"); if( rc != DD_OK ) { #ifdef DEBUG debug_msg("SetCooperativeLevel failed err=%d", rc); #endif return FALSE; } //-------------- set Direct Draw mode ---------------// DEBUG_LOG("Attempt DirectDraw SetDisplayMode"); // ###### begin Gilbert 25/7 #######// // IDirectDraw2::SetDisplayMode requires 5 parameters rc = dd_obj->SetDisplayMode( VGA_WIDTH, VGA_HEIGHT, VGA_BPP, 0, 0); // ###### end Gilbert 25/7 #######// DEBUG_LOG("DirectDraw SetDisplayMode finish"); if( rc != DD_OK ) { #ifdef DEBUG debug_msg("SetMode failed err=%d", rc); #endif return FALSE; } //----------- display the system cursor -------------// SetCursor(NULL); return TRUE; } //-------- End of function Vga::set_mode ----------// //-------- Begin of function Vga::deinit ----------// void Vga::deinit() { release_pal(); if( dd_obj ) { //DEBUG_LOG("Attempt vga.dd_obj->RestoreDisplayMode()"); // dd_obj->RestoreDisplayMode(); //DEBUG_LOG("vga.dd_obj->RestoreDisplayMode() finish"); DEBUG_LOG("Attempt vga.dd_obj->Release()"); dd_obj->Release(); DEBUG_LOG("vga.dd_obj->Release() finish"); dd_obj = NULL; } } //-------- End of function Vga::deinit ----------// //--------- Start of function Vga::load_pal ----------// // // Load the palette from a file and set it to the front buf. // BOOL Vga::load_pal(char* fileName) { char palBuf[256][3]; File palFile; palFile.file_open(fileName); palFile.file_seek(8); // bypass the header info palFile.file_read(palBuf, 256*3); palFile.file_close(); //--- Create a Direct Draw Palette and associate it with the front buffer ---// if( dd_pal == NULL ) { for(int i=0; i<256; i++) { pal_entry_buf[i].peRed = palBuf[i][0]; pal_entry_buf[i].peGreen = palBuf[i][1]; pal_entry_buf[i].peBlue = palBuf[i][2]; } HRESULT rc = dd_obj->CreatePalette( DDPCAPS_8BIT, pal_entry_buf, &dd_pal, NULL ); if( rc != DD_OK ) return FALSE; } init_color_table(); init_gray_remap_table(); return TRUE; } //----------- End of function Vga::load_pal ----------// //--------- Start of function Vga::init_color_table ----------// void Vga::init_color_table() { //----- initialize interface color table -----// PalDesc palDesc( (unsigned char*) pal_entry_buf, sizeof(PALETTEENTRY), 256, 8); vga_color_table->generate_table( MAX_BRIGHTNESS_ADJUST_DEGREE, palDesc, ColorTable::bright_func ); } //----------- End of function Vga::init_color_table ----------// //--------- Start of function Vga::release_pal ----------// void Vga::release_pal() { // ##### begin Gilbert 16/9 #######// if( dd_pal ) { while( dd_pal->Release() ); dd_pal = NULL; } // ##### end Gilbert 16/9 #######// } //----------- End of function Vga::release_pal ----------// //-------- Begin of function Vga::activate_pal ----------// // // we are getting the palette focus, select our palette // void Vga::activate_pal(VgaBuf* vgaBufPtr) { vgaBufPtr->activate_pal(dd_pal); } //--------- End of function Vga::activate_pal ----------// //-------- Begin of function Vga::adjust_brightness ----------// // // changeValue - the value to add to the RGB values of // all the colors in the palette. // the value can be from -255 to 255. // // preserveContrast - whether preserve the constrast or not // void Vga::adjust_brightness(int changeValue) { //---- find out the maximum rgb value can change without affecting the contrast ---// int i; int newRed, newGreen, newBlue; PALETTEENTRY palBuf[256]; //------------ change palette now -------------// for( i=0 ; i<256 ; i++ ) { newRed = (int)pal_entry_buf[i].peRed + changeValue; newGreen = (int)pal_entry_buf[i].peGreen + changeValue; newBlue = (int)pal_entry_buf[i].peBlue + changeValue; palBuf[i].peRed = min(255, max(newRed,0) ); palBuf[i].peGreen = min(255, max(newGreen,0) ); palBuf[i].peBlue = min(255, max(newBlue,0) ); } //------------ set palette ------------// vga_front.temp_unlock(); dd_pal->SetEntries( 0, 0, 256, palBuf ); vga_front.temp_restore_lock(); } //--------- End of function Vga::adjust_brightness ----------// //--------- Begin of function Vga::blt_buf ----------// // // Blt the back buffer to the front buffer. // // x1, y1, x2, y2 - the coordinations of the area to be blit // [int] putBackCursor - whether put a mouse cursor onto the back buffer // before blitting. // (default: 1) // BOOL Vga::blt_buf(int x1, int y1, int x2, int y2, int putBackCursor) { if( putBackCursor ) { mouse_cursor.hide_area_flag = 0; // do not call mouse.hide_area() which will double paint the cursor mouse_cursor.hide_x1 = x1; mouse_cursor.hide_y1 = y1; mouse_cursor.hide_x2 = x2; mouse_cursor.hide_y2 = y2; //-------- put mouse cursor ---------// mouse_cursor.disp_back_buf(x1, y1, x2, y2); } else { mouse.hide_area(x1, y1, x2, y2); } //--------------------------------------// IMGcopy( vga_front.buf_ptr(), vga_front.buf_pitch(), vga_back.buf_ptr(), vga_back.buf_pitch(), x1, y1, x2, y2 ); //--------------------------------------// if( putBackCursor ) mouse_cursor.hide_area_flag = 0; // do not call mouse.show_area() which will double paint the cursor else mouse.show_area(); return TRUE; } //---------- End of function Vga::blt_buf ----------// //----------- Begin of function Vga::d3_panel_up ------------// // // x1,y1,x2,y2 = the four vertex of the panel // [int] vgaFrontOnly = do all the bitmap processing on the front buffer only // (default: 0) // [int] drawBorderOnly = draw border only, do not brighten the center area // (default: 0) // void Vga::d3_panel_up(int x1,int y1,int x2,int y2,int vgaFrontOnly,int drawBorderOnly) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); VgaBuf* vgaBuf; if( vgaFrontOnly ) vgaBuf = &vga_front; else vgaBuf = &vga_back; if( !drawBorderOnly ) { if( Vga::opaque_flag ) vgaBuf->bar(x1+1, y1+1, x2-1, y2-1, UP_OPAQUE_COLOR); else vgaBuf->adjust_brightness(x1+1, y1+1, x2-1, y2-1, IF_UP_BRIGHTNESS_ADJUST); } mouse.hide_area( x1,y1,x2,y2 ); //--------- white border on top and left sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+1,y1,x2,y1, IF_LIGHT_BORDER_COLOR ); // top side IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1,y1,x1,y2 , IF_LIGHT_BORDER_COLOR ); // left side //--------- black border on bottom and right sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+1,y2,x2,y2, IF_DARK_BORDER_COLOR ); // bottom side IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x2,y1+1,x2,y2, IF_DARK_BORDER_COLOR ); // right side //-------------------------------------------// mouse.show_area(); //----- blt the area from the back buffer to the front buffer ------// if( !vgaFrontOnly && !use_back_buf ) // only blt the back to the front is the active buffer is the front vga.blt_buf(x1, y1, x2, y2, 0); } //------------- End of function Vga::d3_panel_up ------------// //----------- Begin of function Vga::d3_panel_down ------------// // // x1,y1,x2,y2 = the four vertex of the panel // [int] vgaFrontOnly = do all the bitmap processing on the front buffer only // (default: 0) // [int] drawBorderOnly = draw border only, do not brighten the center area // (default: 0) // void Vga::d3_panel_down(int x1,int y1,int x2,int y2,int vgaFrontOnly,int drawBorderOnly) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); VgaBuf* vgaBuf; if( vgaFrontOnly ) vgaBuf = &vga_front; else vgaBuf = &vga_back; if( !drawBorderOnly ) { if( Vga::opaque_flag ) vgaBuf->bar(x1+1, y1+1, x2-1, y2-1, DOWN_OPAQUE_COLOR); else vgaBuf->adjust_brightness(x1+1, y1+1, x2-1, y2-1, IF_DOWN_BRIGHTNESS_ADJUST); } mouse.hide_area( x1,y1,x2,y2 ); //--------- white border on top and left sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+1,y1,x2,y1, IF_DARK_BORDER_COLOR ); // top side IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1,y1,x1,y2 , IF_DARK_BORDER_COLOR ); // left side //--------- black border on bottom and right sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+1,y2,x2,y2, IF_LIGHT_BORDER_COLOR ); // bottom side IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x2,y1+1,x2,y2, IF_LIGHT_BORDER_COLOR ); // right side //-------------------------------------------// mouse.show_area(); //----- blt the area from the back buffer to the front buffer ------// if( !vgaFrontOnly && !use_back_buf ) // only blt the back to the front is the active buffer is the front vga.blt_buf(x1, y1, x2, y2, 0); } //------------- End of function Vga::d3_panel_down ------------// //----------- Begin of function Vga::d3_panel2_up ------------// // // x1,y1,x2,y2 = the four vertex of the panel // [int] vgaFrontOnly = do all the bitmap processing on the front buffer only // (default: 0) // [int] drawBorderOnly = draw border only, do not brighten the center area // (default: 0) // void Vga::d3_panel2_up(int x1,int y1,int x2,int y2,int vgaFrontOnly,int drawBorderOnly) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); VgaBuf* vgaBuf; if( vgaFrontOnly ) vgaBuf = &vga_front; else vgaBuf = &vga_back; if( !drawBorderOnly ) vgaBuf->adjust_brightness(x1+2, y1+2, x2-3, y2-3, IF_UP_BRIGHTNESS_ADJUST); mouse.hide_area( x1,y1,x2,y2 ); //--------- white border on top and left sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1,y1,x2-3,y1+1,0x9a ); vgaBuf->draw_pixel(x2-2, y1, 0x9a); IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1,y1+2,x1+1,y2-3, 0x9a ); // left side vgaBuf->draw_pixel(x1, y2-2, 0x9a); //--------- black border on bottom and right sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x2-2,y1+2,x2-1,y2-1, 0x90 ); // bottom side vgaBuf->draw_pixel(x2-1, y1+1, 0x90); IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+2,y2-2,x2-3,y2-1, 0x90 ); // right side vgaBuf->draw_pixel(x1+1, y2-1, 0x90); //--------- junction between white and black border --------// vgaBuf->draw_pixel(x2-1, y1, 0x97); vgaBuf->draw_pixel(x2-2, y1+1, 0x97); vgaBuf->draw_pixel(x1, y2-1, 0x97); vgaBuf->draw_pixel(x1+1, y2-2, 0x97); //--------- gray shadow on bottom and right sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x2, y1+1, x2, y2, 0x97); IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+1, y2, x2-1, y2, 0x97); //-------------------------------------------// mouse.show_area(); //----- blt the area from the back buffer to the front buffer ------// if( !vgaFrontOnly && !use_back_buf ) // only blt the back to the front is the active buffer is the front vga.blt_buf(x1, y1, x2, y2, 0); } //------------- End of function Vga::d3_panel_up ------------// //----------- Begin of function Vga::d3_panel2_down ------------// // // x1,y1,x2,y2 = the four vertex of the panel // [int] vgaFrontOnly = do all the bitmap processing on the front buffer only // (default: 0) // [int] drawBorderOnly = draw border only, do not brighten the center area // (default: 0) // void Vga::d3_panel2_down(int x1,int y1,int x2,int y2,int vgaFrontOnly,int drawBorderOnly) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); VgaBuf* vgaBuf; if( vgaFrontOnly ) vgaBuf = &vga_front; else vgaBuf = &vga_back; if( !drawBorderOnly ) vgaBuf->adjust_brightness(x1+2, y1+2, x2-3, y2-3, IF_DOWN_BRIGHTNESS_ADJUST); mouse.hide_area( x1,y1,x2,y2 ); //--------- black border on top and left sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1,y1,x2-3,y1+1,0x90 ); vgaBuf->draw_pixel(x2-2, y1, 0x90); IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1,y1+2,x1+1,y2-3, 0x90 ); // left side vgaBuf->draw_pixel(x1, y2-2, 0x90); //--------- while border on bottom and right sides -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x2-2,y1+2,x2-1,y2-1, 0x9a ); // bottom side vgaBuf->draw_pixel(x2-1, y1+1, 0x9a); IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+2,y2-2,x2-3,y2-1, 0x9a ); // right side vgaBuf->draw_pixel(x1+1, y2-1, 0x9a); //--------- junction between white and black border --------// vgaBuf->draw_pixel(x2-1, y1, 0x97); vgaBuf->draw_pixel(x2-2, y1+1, 0x97); vgaBuf->draw_pixel(x1, y2-1, 0x97); vgaBuf->draw_pixel(x1+1, y2-2, 0x97); //--------- remove shadow, copy from back -----------// IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x2, y1+1, x2, y2, 0x9c); IMGbar( vgaBuf->buf_ptr(), vgaBuf->buf_pitch(), x1+1, y2, x2-1, y2, 0x9c); mouse.show_area(); //----- blt the area from the back buffer to the front buffer ------// if( !vgaFrontOnly && !use_back_buf ) // only blt the back to the front is the active buffer is the front vga.blt_buf(x1, y1, x2, y2, 0); } //------------- End of function Vga::d3_panel2_down ------------// //------------- Start of function Vga::separator --------------// // // Draw a VGA separator line // // Syntax : separator( x1, y1, x2, y2 ) // // int x1,y1 - the top left vertex of the separator // int x2,y2 - the bottom right vertex of the separator // void Vga::separator(int x1, int y1, int x2, int y2) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); if( y1+1==y2 ) // horizontal line { vga_front.adjust_brightness(x1, y1, x2, y1, IF_UP_BRIGHTNESS_ADJUST); vga_front.adjust_brightness(x1, y2, x2, y2, IF_DOWN_BRIGHTNESS_ADJUST); } else { vga_front.adjust_brightness(x1, y1, x1, y2, IF_UP_BRIGHTNESS_ADJUST); vga_front.adjust_brightness(x2, y1, x2, y2, IF_DOWN_BRIGHTNESS_ADJUST); } } //--------------- End of function Vga::separator --------------// //----------- Begin of function Vga::init_gray_remap_table ----------// // // Initialize a gray remap table for VgaBuf::convert_gray to use. // void Vga::init_gray_remap_table() { //------ create a color to gray-scale remap table ------// #define FIRST_GRAY_COLOR 0x90 #define GRAY_SCALE_COUNT 16 // no. of gray colors // #define FIRST_GRAY_COLOR 0x96 // #define GRAY_SCALE_COUNT 10 // no. of gray colors PALETTEENTRY* palEntry = vga.pal_entry_buf; int i, grayIndex; for( i=0 ; i<256 ; i++, palEntry++ ) { //--------------------------------------------------------// // // How to calculate the gray index (0-31) // // formula is : grey = red * 0.3 + green * 0.59 + blue * 0.11 // the range of the result value is 0-255 // this value is then divided by 8 to 0-31 // //--------------------------------------------------------// grayIndex = ((int)palEntry->peRed * 30 + (int)palEntry->peGreen * 59 + (int)palEntry->peBlue * 11) / 100 / (256/GRAY_SCALE_COUNT); gray_remap_table[i] = FIRST_GRAY_COLOR + grayIndex; } } //--------- End of function Vga::init_gray_remap_table -----------//