/* * 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 : OVGABUF.CPP //Description : OVGABUF direct draw surface class #include #include #include #include #include #include #include //-------- Begin of function VgaBuf::VgaBuf ----------// VgaBuf::VgaBuf() { memset( this, 0, sizeof(VgaBuf) ); } //-------- End of function VgaBuf::VgaBuf ----------// //-------- Begin of function VgaBuf::~VgaBuf ----------// VgaBuf::~VgaBuf() { deinit(); } //-------- End of function VgaBuf::~VgaBuf ----------// //-------- Begin of function VgaBuf::init_front ----------// // // Create a direct draw front buffer. // void VgaBuf::init_front(LPDIRECTDRAW2 ddPtr) { DDSURFACEDESC ddsd; HRESULT rc; DDCAPS ddcaps; //------ Get Direct Draw capacity info --------// ddcaps.dwSize = sizeof( ddcaps ); if( ddPtr->GetCaps( &ddcaps, NULL ) != DD_OK ) err.run( "Error creating Direct Draw front surface!" ); //---------------------------------------------// // Create the Front Buffer //---------------------------------------------// ZeroMemory( &ddsd, sizeof(ddsd) ); ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; LPDIRECTDRAWSURFACE dd1Buf; rc = ddPtr->CreateSurface( &ddsd, &dd1Buf, NULL ); if( rc != DD_OK ) err.run( "Error creating Direct Draw front surface!" ); rc = dd1Buf->QueryInterface(IID_IDirectDrawSurface2, (void **)&dd_buf); if( rc != DD_OK ) { dd1Buf->Release(); err.run ( "Error creating Direct Draw front surface!!" ); } dd1Buf->Release(); is_front = 1; } //-------- End of function VgaBuf::init_front ----------// //-------- Begin of function VgaBuf::init_back ----------// // // Create a direct draw back buffer. // // [DWORD] w : width of the surface [default 0 : VGA_WIDTH] // [DWORD] h : height of the surface [default 0 : VGA_HEIGHT] // void VgaBuf::init_back( LPDIRECTDRAW2 ddPtr, DWORD w, DWORD h ) { DDSURFACEDESC ddsd; HRESULT rc; //--------- fill in surface desc -----------// memset( &ddsd, 0, sizeof( ddsd ) ); ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = w ? w : VGA_WIDTH; ddsd.dwHeight = h ? h : VGA_HEIGHT; LPDIRECTDRAWSURFACE dd1Buf; rc = ddPtr->CreateSurface( &ddsd, &dd1Buf, NULL ); if( rc != DD_OK ) err.run( "Error creating direct draw back surface!" ); rc = dd1Buf->QueryInterface(IID_IDirectDrawSurface2, (void **)&dd_buf); if( rc != DD_OK ) { dd1Buf->Release(); err.run( "Error creating direct draw back surface!!" ); } dd1Buf->Release(); } //-------- End of function VgaBuf::init_back ----------// //------ Begin of function VgaBuf::deinit --------// void VgaBuf::deinit() { if( dd_buf ) { dd_buf->Release(); dd_buf = NULL; } } //-------- End of function VgaBuf::deinit ----------// //-------- Begin of function VgaBuf::activate_pal ----------// // // Activate a palette to the current direct draw surface buffer. // void VgaBuf::activate_pal(LPDIRECTDRAWPALETTE ddPalPtr) { err_when(!ddPalPtr || !dd_buf); HRESULT rc = dd_buf->SetPalette(ddPalPtr); if( rc == DDERR_SURFACELOST ) { dd_buf->Restore(); rc = dd_buf->SetPalette(ddPalPtr); } #ifdef DEBUG if( rc != DD_OK ) debug_msg( "VgaBuf::activate_pal(), failed activating the palette" ); #endif } //--------- End of function VgaBuf::activate_pal ----------// //-------- Begin of function VgaBuf::color_match ----------// DWORD VgaBuf::color_match(COLORREF rgb) { COLORREF rgbT; HDC hdc; DWORD dw = CLR_INVALID; DDSURFACEDESC ddsd; HRESULT hres; if( dd_buf->GetDC(&hdc) == DD_OK ) { rgbT = GetPixel(hdc, 0, 0); SetPixel(hdc, 0, 0, rgb); dd_buf->ReleaseDC(hdc); } ddsd.dwSize = sizeof(ddsd); hres = dd_buf->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); if (hres == DD_OK) { dw = *(DWORD *)ddsd.lpSurface; dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1; dd_buf->Unlock(NULL); } if (dd_buf->GetDC(&hdc) == DD_OK) { SetPixel(hdc, 0, 0, rgbT); dd_buf->ReleaseDC(hdc); } return dw; } //-------- End Endof function VgaBuf::color_match ----------// //-------- Begin of function VgaBuf::is_buf_lost ----------// // BOOL VgaBuf::is_buf_lost() { return dd_buf && dd_buf->IsLost() == DDERR_SURFACELOST; } //--------- End of function VgaBuf::is_buf_lost ----------// //-------- Begin of function VgaBuf::restore_buf ----------// // // Restore buffers that have been lost. // BOOL VgaBuf::restore_buf() { if( dd_buf == NULL || dd_buf->Restore() != DD_OK ) { #ifdef DEBUG debug_msg("Error restoring direct draw buffer"); #endif return FALSE; } return TRUE; } //--------- End of function VgaBuf::restore_buf ----------// //------------- Begin of function VgaBuf::lock_buf --------------// void VgaBuf::lock_buf() { err_if( buf_locked ) err_now( "VgaBuf::lock_buf() error, buffer already locked." ); memset( &buf_des, 0, sizeof(buf_des) ); buf_des.dwSize = sizeof(buf_des); int rc = dd_buf->Lock(NULL, &buf_des, DDLOCK_WAIT, NULL); cur_buf_ptr = (char*) buf_des.lpSurface; //--------------------------------------// if( rc==DD_OK ) buf_locked = TRUE; else { if( is_front ) err_now( "VgaBuf::lock_buf() locking front buffer failed." ); else err_now( "VgaBuf::lock_buf() locking back buffer failed." ); #ifdef DEBUG debug_msg( "Failed to lock the buffer." ); #endif } } //--------------- End of function VgaBuf::lock_buf --------------// //------------- Begin of function VgaBuf::unlock_buf --------------// void VgaBuf::unlock_buf() { // ####### begin Gilbert 16/9 #####// if( !dd_buf ) return; // ####### end Gilbert 16/9 #####// err_when( !buf_locked ); int rc = dd_buf->Unlock(NULL); if( rc==DD_OK ) buf_locked = FALSE; else { switch(rc) { case DDERR_INVALIDOBJECT: err_now( "VgaBuf::unlock_buf error: DDERR_INVALIDOBJECT" ); case DDERR_INVALIDPARAMS: err_now( "VgaBuf::unlock_buf error: DDERR_INVALIDPARAMS" ); case DDERR_INVALIDRECT: err_now( "VgaBuf::unlock_buf error: DDERR_INVALIDRECT" ); case DDERR_NOTLOCKED: err_now( "VgaBuf::unlock_buf error: DDERR_NOTLOCKED" ); case DDERR_SURFACELOST: err_now( "VgaBuf::unlock_buf error: DDERR_SURFACELOST" ); } if( is_front ) err_now( "VgaBuf::unlock_buf() unlocking front buffer failed." ); else err_now( "VgaBuf::unlock_buf() unlocking back buffer failed." ); #ifdef DEBUG debug_msg( "Failed to unlock the buffer." ); #endif } } //--------------- End of function VgaBuf::unlock_buf --------------// //------------- Begin of function VgaBuf::temp_unlock --------------// // // Unlock the Vga buffer temporarily. // void VgaBuf::temp_unlock() { // ######### begin Gilbert 16/9 ########// save_locked_flag = buf_locked; if( buf_locked ) unlock_buf(); // ######### end Gilbert 16/9 ########// } //--------------- End of function VgaBuf::temp_unlock --------------// //------------- Begin of function VgaBuf::temp_restore_lock --------------// // // Restore the previous lock stage. // void VgaBuf::temp_restore_lock() { if( save_locked_flag ) lock_buf(); } //--------------- End of function VgaBuf::temp_restore_lock --------------// //------------- Begin of function VgaBuf::put_bitmap --------------// // // Put a bitmap on the surface buffer // void VgaBuf::put_bitmap(int x,int y,char* bitmapPtr) { err_when( !buf_locked ); if( is_front ) mouse.hide_area( x, y, x+*((short*)bitmapPtr)-1, y+*(((short*)bitmapPtr)+1)-1 ); IMGblt(buf_ptr(), buf_pitch(), x, y, bitmapPtr); if( is_front ) mouse.show_area(); } //--------------- End of function VgaBuf::put_bitmap --------------// //------- Begin of function VgaBuf::put_bitmap_trans --------// // // Put a bitmap on the surface buffer and hide the mouse cursor while displaying // void VgaBuf::put_bitmap_trans(int x,int y,char* bitmapPtr) { err_when( !buf_locked ); if( is_front ) mouse.hide_area( x, y, x+*((short*)bitmapPtr)-1, y+*(((short*)bitmapPtr)+1)-1 ); IMGbltTrans(buf_ptr(), buf_pitch(), x, y, bitmapPtr); if( is_front ) mouse.show_area(); } //--------- End of function VgaBuf::put_bitmap_trans --------// //------- Begin of function VgaBuf::put_bitmap_remap --------// // // Put a bitmap on the surface buffer and hide the mouse cursor while displaying // void VgaBuf::put_bitmap_remap(int x,int y,char* bitmapPtr,char *colorTable) { err_when( !buf_locked ); if( is_front ) mouse.hide_area( x, y, x+*((short*)bitmapPtr)-1, y+*(((short*)bitmapPtr)+1)-1 ); IMGbltRemap(buf_ptr(), buf_pitch(), x, y, bitmapPtr, colorTable); if( is_front ) mouse.show_area(); } //--------- End of function VgaBuf::put_bitmap_remap --------// //---------- Begin of function VgaBuf::save_area_common_buf ----------// // // Save screen area to sys.common_data_buf. // void VgaBuf::save_area_common_buf(int x1, int y1, int x2, int y2) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); long saveSize = sizeof(short)*6 + (x2-x1+1) * (y2-y1+1); err_if( saveSize > COMMON_DATA_BUF_SIZE ) err_now( "VgaBuf::save_area_common_buf()" ); short* shortPtr = (short*) sys.common_data_buf; *shortPtr++ = x1; *shortPtr++ = y1; *shortPtr++ = x2; *shortPtr++ = y2; //-------- read screen ---------// if( is_front ) mouse.hide_area( x1,y1,x2,y2 ); // if the mouse cursor is in that area, hide it read_bitmap( x1,y1,x2,y2, (char*) shortPtr ); if( is_front ) mouse.show_area(); } //------------ End of function VgaBuf::save_area_common_buf ----------// //---------- Begin of function VgaBuf::rest_area_common_buf ----------// // // Restore screen area to the screen from Vga image buffer. // This screen should be previously saved by save_area() // void VgaBuf::rest_area_common_buf() { short* shortPtr = (short*) sys.common_data_buf; int x1 = *shortPtr++; int y1 = *shortPtr++; int x2 = *shortPtr++; int y2 = *shortPtr++; put_bitmap( x1, y1, (char*) shortPtr ); } //------------ End of function VgaBuf::rest_area_common_buf ----------// //---------- Begin of function VgaBuf::save_area ---------// // // save_area() differs from save_area() as : // // save_area() save the screen to a user-defined buffer. // save_area() save the screen to the global screen saving buffer in Vga object // // x1,y1,x2,y2 = the area of the screen // [char*] saveScr = the pointer to the previous saved buffer // (default : initialize a new buffer) // char* VgaBuf::save_area(int x1, int y1, int x2, int y2, char* saveScr ) { err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); long newSize = sizeof(short)*6 + (x2-x1+1) * (y2-y1+1); saveScr = mem_resize( saveScr, newSize ); short* shortPtr = (short*) saveScr; *shortPtr++ = x1; *shortPtr++ = y1; *shortPtr++ = x2; *shortPtr++ = y2; if( is_front ) mouse.hide_area( x1,y1,x2,y2 ); // if the mouse cursor is in that area, hide it read_bitmap( x1,y1,x2,y2, (char*) shortPtr ); if( is_front ) mouse.show_area(); return saveScr; } //------------ End of function VgaBuf::save_area ---------// //----------- Begin of function VgaBuf::rest_area --------// // // Restore previously saved screen // // char* saveScr = the previously saved screen // [int] releaseFlag = whether release the buffer of the saved screen or not // (default : 1) // void VgaBuf::rest_area(char* saveScr, int releaseFlag) { int x1,y1,x2,y2; if( saveScr == NULL ) return; short* shortPtr = (short*) saveScr; x1 = *shortPtr++; y1 = *shortPtr++; x2 = *shortPtr++; y2 = *shortPtr++; err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); put_bitmap( x1, y1, (char*) shortPtr ); if( releaseFlag ) mem_del( saveScr ); } //------------ End of function VgaBuf::rest_area ----------// //------------ Begin of function VgaBuf::write_bmp_file --------------// // // Load a BMP file into the current VgaBuf DIB object. // // fileName - the name of the BMP file. // // return : 1-succeeded, 0-failed. // int VgaBuf::write_bmp_file(char* fileName) { File bmpFile; bmpFile.file_create(fileName, 1, 0); // 1-handle error, 0-disable variable file size //------------ Write the file header ------------// BITMAPFILEHEADER bmpFileHdr; bmpFileHdr.bfType = 0x4D42; // set the type to "BM" bmpFileHdr.bfReserved1 = 0; bmpFileHdr.bfReserved2 = 0; bmpFileHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256; bmpFileHdr.bfSize = buf_size() + bmpFileHdr.bfOffBits; bmpFile.file_write(&bmpFileHdr, sizeof(bmpFileHdr)); //------------ Write in the info header -----------// BITMAPINFOHEADER bmpInfoHdr; bmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER); bmpInfoHdr.biWidth = buf_des.dwWidth; bmpInfoHdr.biHeight = buf_des.dwHeight; bmpInfoHdr.biPlanes = 1; bmpInfoHdr.biBitCount = 8; bmpInfoHdr.biCompression = BI_RGB; bmpInfoHdr.biSizeImage = buf_size(); bmpInfoHdr.biXPelsPerMeter = 0; bmpInfoHdr.biYPelsPerMeter = 0; bmpInfoHdr.biClrUsed = 0; bmpInfoHdr.biClrImportant = 0; bmpFile.file_write(&bmpInfoHdr, sizeof(bmpInfoHdr)); //------------ write the color table -----------// LPDIRECTDRAWPALETTE ddPalettePtr; // get the direct draw surface's palette dd_buf->GetPalette(&ddPalettePtr); PALETTEENTRY *palEntries = (PALETTEENTRY*) mem_add( sizeof(PALETTEENTRY)*256 ); ddPalettePtr->GetEntries(0, 0, 256, palEntries); RGBQUAD *colorTable = (RGBQUAD*) mem_add( sizeof(RGBQUAD)*256 ); // allocate a color table with 256 entries for( int i=0 ; i<256 ; i++ ) { colorTable[i].rgbBlue = palEntries[i].peBlue; colorTable[i].rgbGreen = palEntries[i].peGreen; colorTable[i].rgbRed = palEntries[i].peRed; colorTable[i].rgbReserved = 0; } bmpFile.file_write(colorTable, sizeof(RGBQUAD)*256); mem_del(palEntries); mem_del(colorTable); //----------- write the bitmap ----------// for( int y=buf_height()-1 ; y>=0 ; y-- ) // write in reversed order as DIB's vertical order is reversed bmpFile.file_write(buf_ptr(0,y), buf_width()); //------------ close the file -----------// bmpFile.file_close(); return 1; } //------------ End of function VgaBuf::write_bmp_file --------------// int VgaBuf::write_bmp_file(char * fileName, int offset_x, int offset_y, int width, int height) { if (!width || !height || !offset_x || !offset_y) return 0; if (offset_x + width > buf_des.dwWidth) return 0; if (offset_y + width > buf_des.dwHeight) return 0; File bmpFile; bmpFile.file_create(fileName, 1, 0); // 1-handle error, 0-disable variable file size //------------ Write the file header ------------// BITMAPFILEHEADER bmpFileHdr; bmpFileHdr.bfType = 0x4D42; // set the type to "BM" bmpFileHdr.bfReserved1 = 0; bmpFileHdr.bfReserved2 = 0; bmpFileHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256; bmpFileHdr.bfSize = bmpFileHdr.bfOffBits + width * height; bmpFile.file_write(&bmpFileHdr, sizeof(bmpFileHdr)); //------------ Write in the info header -----------// BITMAPINFOHEADER bmpInfoHdr; bmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER); bmpInfoHdr.biWidth = width; bmpInfoHdr.biHeight = height; bmpInfoHdr.biPlanes = 1; bmpInfoHdr.biBitCount = 8; bmpInfoHdr.biCompression = BI_RGB; bmpInfoHdr.biSizeImage = width * height; bmpInfoHdr.biXPelsPerMeter = 0; bmpInfoHdr.biYPelsPerMeter = 0; bmpInfoHdr.biClrUsed = 0; bmpInfoHdr.biClrImportant = 0; bmpFile.file_write(&bmpInfoHdr, sizeof(bmpInfoHdr)); //------------ write the color table -----------// LPDIRECTDRAWPALETTE ddPalettePtr; // get the direct draw surface's palette dd_buf->GetPalette(&ddPalettePtr); PALETTEENTRY *palEntries = (PALETTEENTRY*) mem_add(sizeof(PALETTEENTRY) * 256); ddPalettePtr->GetEntries(0, 0, 256, palEntries); RGBQUAD *colorTable = (RGBQUAD*) mem_add(sizeof(RGBQUAD) * 256); // allocate a color table with 256 entries for (int i = 0; i < 256; i++) { colorTable[i].rgbBlue = palEntries[i].peBlue; colorTable[i].rgbGreen = palEntries[i].peGreen; colorTable[i].rgbRed = palEntries[i].peRed; colorTable[i].rgbReserved = 0; } bmpFile.file_write(colorTable, sizeof(RGBQUAD) * 256); mem_del(palEntries); mem_del(colorTable); //----------- write the bitmap ----------// char paddingBytes[4]; for (int y = offset_y + height - 1; y >= offset_y; y--) // write in reversed order as DIB's vertical order is reversed { bmpFile.file_write(buf_ptr(offset_x, y), width); if (width % 4 != 0) bmpFile.file_write(paddingBytes, 4 - (width % 4)); } //------------ close the file -----------// bmpFile.file_close(); return 1; } //---------- Begin of function VgaBuf::put_large_bitmap ---------// // // Put a picture on the screen, when a picture's size is > 64K // Pass a file pointer to put_large_bitmap() for continously reading the file // // Syntax // // x, y = the location of the picture on the screen // filePtr = pointer to the // //--------- Format of Picture buffer -------// // // int = whether this picture buffer contains the palette or not // -1 (0xFF) if has, otherwise not // char[256][3] = VGA color palette // // = picture width // = picture height // // char[...] = non-compressed flat picture bitmap // //---------------------------------------------// void VgaBuf::put_large_bitmap(int x1, int y1, File* filePtr) { if( filePtr == NULL ) return; int pictWidth = filePtr->file_get_short(); int hasPalette=0; //------- read in color palette if this picture has one -----// /* if( pictWidth == -1 ) // if the has palette in it { //------- set all palette to dark black ------// ColorPal colorPal; colorPal.red=0; colorPal.green=0; colorPal.blue=0; palette.set_single(colorPal); //-------- get the palette of the picture --------// ColorPal palBuf[256]; filePtr->file_read( palBuf, sizeof(ColorPal)*256 ); palette.set_fade_in(0, 255, palBuf, 15 ); // 15 steps for the whole fade in process, each step 0.01 seconds, 10 steps = 0.1 second hasPalette=1; pictWidth = filePtr->file_get_short(); } */ //------ read in bitmap and display it --------// int pictHeight = filePtr->file_get_short(); int x2 = x1 + pictWidth - 1; int y2 = y1 + pictHeight - 1; long pictSize = (long) x2 * y2; err_when( x1>x2 || y1>y2 || x1<0 || y1<0 || x2>=VGA_WIDTH || y2>=VGA_HEIGHT ); //---- if pict size less than 64K, read in the picture in one step ----// if( pictSize <= COMMON_DATA_BUF_SIZE ) { filePtr->file_read( sys.common_data_buf, pictSize ); if( is_front ) mouse.hide_area( x1,y1,x2,y2 ); // if the mouse cursor is in that area, hide it put_bitmap2( x1, y1, pictWidth, pictHeight, sys.common_data_buf ); if( is_front ) mouse.show_area(); } else //----- if the picture size > 64K, read in line by line -----// { int bufferLine = COMMON_DATA_BUF_SIZE / pictWidth; // max. no. of lines can be in the buffer int ty=y1+bufferLine-1; if( ty> y2 ) ty=y2; while( y1<=y2 ) { filePtr->file_read( sys.common_data_buf, (unsigned)pictWidth * (ty-y1+1) ); if( is_front ) mouse.hide_area( x1,y1,x2,ty ); // if the mouse cursor is in that area, hide it put_bitmap2( x1, y1, pictWidth, ty-y1+1, sys.common_data_buf ); if( is_front ) mouse.show_area(); y1 += bufferLine; if( (ty+=bufferLine) > y2 ) ty=y2; } } /* if( hasPalette ) while( !palette.fade_in() ); */ } //----------- End of function VgaBuf::put_large_bitmap --------// //----------- Begin of function VgaBuf::convert_gray ----------// // // Convert an specified area of the bitmap from color to gray-scale. // void VgaBuf::convert_gray(int x1, int y1, int x2, int y2) { remap_bar(x1, y1, x2, y2, vga.gray_remap_table); } //--------- End of function VgaBuf::convert_gray -----------//