/*
* 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 -----------//