/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** 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 3 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 . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Command & Conquer * * * * $Archive:: /G/wwlib/dsurface.cpp $* * * * $Author:: Neal_k $* * * * $Modtime:: 6/23/00 2:26p $* * * * $Revision:: 2 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * DSurface::Blit_From -- Blit from one surface to this one. * * DSurface::Blit_From -- Blit graphic memory from one rectangle to another. * * DSurface::Build_Hicolor_Pixel -- Construct a hicolor pixel according to the surface pixel * * DSurface::Build_Remap_Table -- Build a highcolor remap table. * * DSurface::Bytes_Per_Pixel -- Fetches the bytes per pixel of the surface. * * DSurface::Create_Primary -- Creates a primary (visible) surface. * * DSurface::DSurface -- Create a surface attached to specified DDraw Surface Object. * * DSurface::DSurface -- Default constructor for surface object. * * DSurface::DSurface -- Off screen direct draw surface constructor. * * DSurface::Fill_Rect -- Fills a rectangle with clipping control. * * DSurface::Fill_Rect -- This routine will fill the specified rectangle. * * DSurface::Lock -- Fetches a working pointer into surface memory. * * DSurface::Restore_Check -- Checks for and restores surface memory if necessary. * * DSurface::Stride -- Fetches the bytes between rows. * * DSurface::Unlock -- Unlock a previously locked surface. * * DSurface::~DSurface -- Destructor for a direct draw surface object. * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "always.h" #include "dsurface.h" #include extern LPDIRECTDRAW DirectDrawObject; //pointer to direct draw object extern LPDIRECTDRAWSURFACE PaletteSurface; /* ** Clipper object (for primary surface). */ LPDIRECTDRAWCLIPPER DSurface::Clipper = NULL; int DSurface::RedRight = 0; int DSurface::RedLeft = 0; int DSurface::BlueRight = 0; int DSurface::BlueLeft = 0; int DSurface::GreenRight = 0; int DSurface::GreenLeft = 0; unsigned short DSurface::HalfbrightMask = 0; unsigned short DSurface::QuarterbrightMask = 0; unsigned short DSurface::EighthbrightMask = 0; DDPIXELFORMAT DSurface::PixelFormat; /*********************************************************************************************** * DSurface::DSurface -- Off screen direct draw surface constructor. * * * * This constructor will create a Direct Draw enabled surface in video memory if possible. * * Such a surface will be able to use hardware assist if possible. The surface created * * is NOT visible. It only exists as a work surface and cannot be flipped to the visible * * surface. It can only be blitted to the visible surface. * * * * INPUT: width -- The width of the surface to create. * * * * height -- The height of the surface to create. * * * * OUTPUT: none * * * * WARNINGS: The surface pixel format is the same as that of the visible display mode. It * * is important to construct surfaces using this routine, only AFTER the display * * mode has been set. * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ DSurface::DSurface(int width, int height, bool system_memory, DDPIXELFORMAT *pixform) : XSurface(width, height), BytesPerPixel(0), LockPtr(NULL), IsPrimary(false), IsVideoRam(false), SurfacePtr(NULL), Description(NULL), DCUnlockCount(0) { Description = new DDSURFACEDESC; if (Description != NULL) { memset(Description, '\0', sizeof(DDSURFACEDESC)); Description->dwSize = sizeof(DDSURFACEDESC); Description->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; Description->dwWidth = width; Description->dwHeight = height; Description->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; if (system_memory == true) Description->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; /* ** Was a custom (non-display-depth) pixel format specified? */ if (pixform) { Description->ddpfPixelFormat=*pixform; Description->dwFlags |= DDSD_PIXELFORMAT; } DirectDrawObject->CreateSurface(Description, &SurfacePtr, NULL); /* ** Get a description of the surface that was just allocated. */ if (SurfacePtr != NULL) { memset(Description, '\0', sizeof(DDSURFACEDESC)); Description->dwSize = sizeof(DDSURFACEDESC); SurfacePtr->GetSurfaceDesc(Description); BytesPerPixel = (Description->ddpfPixelFormat.dwRGBBitCount+7)/8; IsVideoRam = ((Description->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) != 0); /* ** If this is a hicolor surface, then build the shift values for ** building and extracting the colors from the hicolor pixel. */ if (BytesPerPixel == 2) { int index; int shift = Description->ddpfPixelFormat.dwRBitMask; ThisRedRight = 0; ThisRedLeft = 0; for (index = 0; index < 16; index++) { if (shift & 0x01) break; shift >>= 1; ThisRedRight++; } for (index = 0; index < 8; index++) { if (shift & 0x80) break; shift <<= 1; ThisRedLeft++; } shift = Description->ddpfPixelFormat.dwGBitMask; ThisGreenRight = 0; ThisGreenLeft = 0; for (index = 0; index < 16; index++) { if (shift & 0x01) break; ThisGreenRight++; shift >>= 1; } for (index = 0; index < 8; index++) { if (shift & 0x80) break; ThisGreenLeft++; shift <<= 1; } shift = Description->ddpfPixelFormat.dwBBitMask; ThisBlueRight = 0; ThisBlueLeft = 0; for (index = 0; index < 16; index++) { if (shift & 0x01) break; ThisBlueRight++; shift >>= 1; } for (index = 0; index < 8; index++) { if (shift & 0x80) break; ThisBlueLeft++; shift <<= 1; } } } } } /*********************************************************************************************** * DSurface::~DSurface -- Destructor for a direct draw surface object. * * * * This will destruct (make invalid) the direct draw surface. * * * * INPUT: none * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ DSurface::~DSurface(void) { /* ** If this is the primary surface, then the clipper must be detached from ** this surface and the clipper object deleted. */ if (IsPrimary && SurfacePtr != NULL && Clipper != NULL) { SurfacePtr->SetClipper(NULL); Clipper->Release(); Clipper = NULL; } /* ** Delete the description of the surface. */ delete Description; Description = NULL; if (SurfacePtr != NULL) { SurfacePtr->Release(); } SurfacePtr = NULL; } /*********************************************************************************************** * DSurface::DSurface -- Default constructor for surface object. * * * * This default constructor for a surface object should not be used. Although it properly * * creates a non-functional surface, there is no use for such a surface. This default * * constructor is provided for those rare cases where symatics require a default * * constructor. * * * * INPUT: none * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ DSurface::DSurface(void) : BytesPerPixel(0), LockPtr(NULL), SurfacePtr(NULL), Description(NULL), DCUnlockCount(0) { Description = new DDSURFACEDESC; memset(Description, '\0', sizeof(DDSURFACEDESC)); Description->dwSize = sizeof(DDSURFACEDESC); } /*********************************************************************************************** * DSurface::GetDC -- Get the windows device context from our surface * * * * INPUT: none * * * * OUTPUT: none * * * * WARNINGS: Any current locks will get unlocked while the DC is held * * * * HISTORY: * * 06/21/2000 NAK : Created. * *=============================================================================================*/ HDC DSurface::GetDC(void) { HDC hdc = NULL; HRESULT hr; // We have to remove all current locks to get the device context unfortunately... while (LockCount) { Unlock(); DCUnlockCount++; } hr = SurfacePtr->GetDC(&hdc); if (hr != DD_OK) { while(DCUnlockCount) // restore the lock state { Lock(); DCUnlockCount--; } return(NULL); } // GetDC() locks the surface internally, so we need to reflect that here if (hr == DD_OK) { LockCount++; }else{ hdc = NULL; } return (hdc); } /*********************************************************************************************** * DSurface::ReleaseDC -- Release the windows device context from our surface * * * * INPUT: none * * * * OUTPUT: none * * * * WARNINGS: Restores any locks held before the call to GetDC() * * * * HISTORY: * * 06/21/2000 NAK : Created. * *=============================================================================================*/ int DSurface::ReleaseDC(HDC hdc) { HRESULT hr; hr = SurfacePtr->ReleaseDC(hdc); assert(hr == DD_OK); // ReleaseDC() unlocks the surface internally, so we need to reflect that here. if ((hr == DD_OK) && (LockCount > 0)) { LockCount--; } while(DCUnlockCount) // restore the lock state { Lock(); DCUnlockCount--; } return (1); } /*********************************************************************************************** * DSurface::Create_Primary -- Creates a primary (visible) surface. * * * * This routine is used to create the surface object that represents the currently * * visible display. The surface is not allocated, it is merely linked to the preexisting * * surface that the Windows GDI is also currently using. * * * * INPUT: backsurface -- Optional pointer to specify where the backpage (flip enabled) * * pointer will be placed. If this parameter is NULL, then no * * back surface will be created. * * * * OUTPUT: Returns with a pointer to the primary surface. * * * * WARNINGS: There can be only one primary surface. If an additional call to this routine * * is made, another surface pointer will be returned, but it will point to the * * same surface as before. * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ DSurface * DSurface::Create_Primary(DSurface ** backsurface1) { DSurface * surface = new DSurface(); int backcount = (backsurface1 != NULL) ? 1 : 0; /* ** Setup parameter for creating the primary surface. This will ** always be the visible surface plus optional back buffers of identical ** dimensions. */ surface->Description->dwFlags = DDSD_CAPS; surface->Description->ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if (backcount > 0) { surface->Description->ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX; surface->Description->dwFlags |= DDSD_BACKBUFFERCOUNT; surface->Description->dwBackBufferCount = backcount; } HRESULT result = DirectDrawObject->CreateSurface(surface->Description, &surface->SurfacePtr, NULL); /* ** If the primary surface object was created, then fetch a pointer to the ** back buffer if there is one present. */ if (result == DD_OK) { if (backcount > 0) { LPDIRECTDRAWSURFACE back; DDSCAPS caps; caps.dwCaps = DDSCAPS_BACKBUFFER; result = surface->SurfacePtr->GetAttachedSurface(&caps, &back); if (result == DD_OK) { *backsurface1 = new DSurface(back); } } /* ** Get a description of the surface that was just allocated. */ memset(surface->Description, '\0', sizeof(DDSURFACEDESC)); surface->Description->dwSize = sizeof(DDSURFACEDESC); surface->SurfacePtr->GetSurfaceDesc(surface->Description); surface->BytesPerPixel = (surface->Description->ddpfPixelFormat.dwRGBBitCount+7)/8; surface->IsPrimary = true; // surface->Window.Set(Rect(0, 0, surface->Description->dwWidth, surface->Description->dwHeight)); surface->Width = surface->Description->dwWidth; surface->Height = surface->Description->dwHeight; PaletteSurface = surface->SurfacePtr; /* ** Attach a clipper object to the surface so that it can cooperate ** with the system GDI. This only comes into play if there are going ** to be GDI graphical elements on top of the surface (normally this ** isn't the case for full screen games). It doesn't hurt to attach ** a clipper object anyway -- just in case. */ if (DirectDrawObject->CreateClipper(0, &Clipper, NULL) == DD_OK) { if (Clipper->SetHWnd(0, GetActiveWindow()) == DD_OK) { surface->SurfacePtr->SetClipper(Clipper); } } /* ** Fetch the pixel format for the surface. */ memcpy(&PixelFormat, &surface->Description->ddpfPixelFormat, sizeof(DDPIXELFORMAT)); /* ** If this is a hicolor surface, then build the shift values for ** building and extracting the colors from the hicolor pixel. */ if (surface->Bytes_Per_Pixel() == 2) { int index; int shift = PixelFormat.dwRBitMask; RedRight = 0; RedLeft = 0; for (index = 0; index < 16; index++) { if (shift & 0x01) break; shift >>= 1; RedRight++; } for (index = 0; index < 8; index++) { if (shift & 0x80) break; shift <<= 1; RedLeft++; } shift = PixelFormat.dwGBitMask; GreenRight = 0; GreenLeft = 0; for (index = 0; index < 16; index++) { if (shift & 0x01) break; GreenRight++; shift >>= 1; } for (index = 0; index < 8; index++) { if (shift & 0x80) break; GreenLeft++; shift <<= 1; } shift = PixelFormat.dwBBitMask; BlueRight = 0; BlueLeft = 0; for (index = 0; index < 16; index++) { if (shift & 0x01) break; BlueRight++; shift >>= 1; } for (index = 0; index < 8; index++) { if (shift & 0x80) break; BlueLeft++; shift <<= 1; } /* ** Create the halfbright mask. */ HalfbrightMask = (unsigned short)Build_Hicolor_Pixel(127, 127, 127); QuarterbrightMask = (unsigned short)Build_Hicolor_Pixel(63, 63, 63); EighthbrightMask = (unsigned short)Build_Hicolor_Pixel(31, 31, 31); } } else { delete surface; surface = NULL; } return(surface); } /*********************************************************************************************** * DSurface::DSurface -- Create a surface attached to specified DDraw Surface Object. * * * * If an existing Direct Draw Surface Object is available, use this constructor to create * * a DSurface object that is attached to the surface specified. * * * * INPUT: surfaceptr -- Pointer to a preexisting Direct Draw Surface Object. * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ DSurface::DSurface(LPDIRECTDRAWSURFACE surfaceptr) : BytesPerPixel(0), LockPtr(NULL), SurfacePtr(surfaceptr), Description(NULL) { if (SurfacePtr != NULL) { Description = new DDSURFACEDESC; memset(Description, '\0', sizeof(DDSURFACEDESC)); Description->dwSize = sizeof(DDSURFACEDESC); HRESULT result = SurfacePtr->GetSurfaceDesc(Description); if (result == DD_OK) { BytesPerPixel = (Description->ddpfPixelFormat.dwRGBBitCount+7)/8; // Window.Set(Rect(0, 0, Description->dwWidth, Description->dwHeight)); Width = Description->dwWidth; Height = Description->dwHeight; } } } /*********************************************************************************************** * DSurface::Bytes_Per_Pixel -- Fetches the bytes per pixel of the surface. * * * * This routine will return with the number of bytes that each pixel consumes. The value * * is dependant upon the graphic mode of the display. * * * * INPUT: none * * * * OUTPUT: Returns with the bytes per pixel of the surface object. * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ int DSurface::Bytes_Per_Pixel(void) const { return(BytesPerPixel); } /*********************************************************************************************** * DSurface::Stride -- Fetches the bytes between rows. * * * * This routine will return the number of bytes to add so that the pointer will be * * positioned at the same column, but one row down the screen. This value may very well * * NOT be equal to the width multiplied by the bytes per pixel. * * * * INPUT: none * * * * OUTPUT: Returns with the byte difference between subsequent pixel rows. * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ int DSurface::Stride(void) const { return(Description->lPitch); } /*********************************************************************************************** * DSurface::Lock -- Fetches a working pointer into surface memory. * * * * This routine will return with a pointer to the pixel at the location specified. In order * * to directly manipulate surface memory, the surface memory must be mapped into the * * program's logical address space. In addition, all blitter activity on the surface will * * be suspended. Every call to Lock must be have a corresponding call to Unlock if the * * pointer returned is not equal to NULL. * * * * INPUT: point -- Pixel coordinate to return a pointer to. * * * * OUTPUT: Returns with a pointer to the pixel specified. If the return value is NULL, then * * the surface could not be locked and no call to Unlock should be performed. * * * * WARNINGS: It is important not to keep a surface locked indefinately since the blitter * * will not be able to function. Due to the time that locking consumes, it is * * also important to not perform unnecessarily frequent Lock calls. * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ void * DSurface::Lock(Point2D point) const { Restore_Check(); if (LockCount == 0) { DDSURFACEDESC desc; memset(&desc, '\0', sizeof(desc)); desc.dwSize = sizeof(desc); HRESULT result = SurfacePtr->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT, NULL); if (result != DD_OK) return(NULL); memcpy(Description, &desc, sizeof(DDSURFACEDESC)); BytesPerPixel = (Description->ddpfPixelFormat.dwRGBBitCount+7)/8; LockPtr = Description->lpSurface; } XSurface::Lock(); return(((char*)LockPtr) + point.Y * Stride() + point.X * Bytes_Per_Pixel()); } /*********************************************************************************************** * DSurface::Unlock -- Unlock a previously locked surface. * * * * After a surface has been successfully locked, a call to the Unlock() function is * * required. * * * * INPUT: none * * * * OUTPUT: bool; Was the unlock successful? * * * * WARNINGS: Only pair a call to Unlock if the prior Lock actually returned a non-NULL * * value. * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ bool DSurface::Unlock(void) const { Restore_Check(); if (LockCount > 0) { XSurface::Unlock(); if (LockCount == 0) { SurfacePtr->Unlock(LockPtr); LockPtr = NULL; } return(true); } return(false); } /*********************************************************************************************** * DSurface::Restore_Check -- Checks for and restores surface memory if necessary. * * * * This routine will check to see if surface memory has been lost to the surface. If it * * has, then the surface memory will be restored. * * * * INPUT: none * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ void DSurface::Restore_Check(void) const { if (SurfacePtr->IsLost() == DDERR_SURFACELOST) { SurfacePtr->Restore(); if (LockCount > 0 && SurfacePtr->IsLost() != DDERR_SURFACELOST) { int oldlockcount = LockCount; LockCount = 0; Lock(); LockCount++; Unlock(); LockCount = oldlockcount; } } } /*********************************************************************************************** * DSurface::Blit_From -- Blit graphic memory from one rectangle to another. * * * * This routine will use the blitter (if possible) to blit a block of graphic memory from * * one screen rectangle to another. If the rectangles do no match in size, scaling may * * be performed. * * * * INPUT: destrect -- The destination rectangle. * * * * ssource -- The source surface to blit from. * * * * sourecrect -- The source rectangle. * * * * trans -- Should transparency checking be performed? * * * * OUTPUT: bool; Was the blit performed without error? * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ bool DSurface::Blit_From(Rect const & destrect, Surface const & ssource, Rect const & sourcerect, bool trans) { return(Blit_From(Get_Rect(), destrect, ssource, ssource.Get_Rect(), sourcerect, trans)); } /*********************************************************************************************** * DSurface::Blit_From -- Blit from one surface to this one. * * * * Use this routine to blit a rectangle from the specified surface to this surface while * * performing clipping upon the blit rectangles specified. * * * * INPUT: dcliprect -- The clipping rectangle to use for this surface. * * * * destrect -- The destination rectangle of the blit. The is relative to the * * dcliprect parameter. * * * * ssource -- The source surface of the blit. * * * * scliprect -- The source clipping rectangle. * * * * sourcrect -- The source rectangle of the blit. This rectangle is relative to * * the source clipping rectangle. * * * * trans -- Is this a transparent blit request? * * * * OUTPUT: bool; Was there a blit performed? A 'false' return value would indicate that the * * blit was clipped into nothing. * * * * WARNINGS: none * * * * HISTORY: * * 05/27/1997 JLB : Created. * *=============================================================================================*/ bool DSurface::Blit_From(Rect const & dcliprect, Rect const & destrect, Surface const & ssource, Rect const & scliprect, Rect const & sourcerect, bool trans) { if (!dcliprect.Is_Valid() || !scliprect.Is_Valid() || !destrect.Is_Valid() || !sourcerect.Is_Valid()) return(false); /* ** For non-direct draw surfaces, perform a manual blit operation. This is also ** necessary if any of the surfaces are currently locked. It is also necessary if the ** blit regions overlap and the blitter cannot handle overlapped regions. ** ** NOTE: Its legal to blit to a locked surface but not from a locked surface. ** ST - 4/23/97 1:03AM */ if (!ssource.Is_Direct_Draw() || ((DSurface&)ssource).Is_Locked() || trans || Bytes_Per_Pixel() != ssource.Bytes_Per_Pixel()) { return(XSurface::Blit_From(destrect, ssource, sourcerect, trans)); } Restore_Check(); DSurface const & source = (DSurface const &)ssource; Rect drect = destrect; Rect srect = sourcerect; Rect swindow = scliprect.Intersect(ssource.Get_Rect()); Rect dwindow = dcliprect.Intersect(Get_Rect()); if (Blit_Clip(drect, dwindow, srect, swindow)) { RECT xdestrect; xdestrect.left = drect.X+dwindow.X; xdestrect.top = drect.Y+dwindow.Y; xdestrect.right = drect.X+dwindow.X+drect.Width; xdestrect.bottom = drect.Y+dwindow.Y+drect.Height; RECT xsrcrect; xsrcrect.left = srect.X+swindow.X; xsrcrect.top = srect.Y+swindow.Y; xsrcrect.right = srect.X+swindow.X+srect.Width; xsrcrect.bottom = srect.Y+swindow.Y+srect.Height; HRESULT result = SurfacePtr->Blt(&xdestrect, source.SurfacePtr, &xsrcrect, DDBLT_WAIT, NULL); return(result == DD_OK); } return(false); } /*********************************************************************************************** * DSurface::Fill_Rect -- This routine will fill the specified rectangle. * * * * This routine will fill the specified rectangle with a color. * * * * INPUT: fillrect -- The rectangle to fill. * * * * color -- The color to fill with. * * * * OUTPUT: bool; Was the fill performed without error? * * * * WARNINGS: none * * * * HISTORY: * * 02/07/1997 JLB : Created. * *=============================================================================================*/ bool DSurface::Fill_Rect(Rect const & fillrect, int color) { return(DSurface::Fill_Rect(Get_Rect(), fillrect, color)); } /*********************************************************************************************** * DSurface::Fill_Rect -- Fills a rectangle with clipping control. * * * * This routine will fill a rectangle on this surface, but will clip the request against * * a clipping rectangle first. * * * * INPUT: cliprect -- The clipping rectangle to use for this surface. * * * * fillrect -- The rectangle to fill with the specified color. The rectangle is * * relative to the clipping rectangle. * * * * color -- The color (surface dependant format) to use when filling the rectangle * * pixels. * * * * OUTPUT: bool; Was a fill operation performed? A 'false' return value would mean that the * * fill request was clipped into nothing. * * * * WARNINGS: none * * * * HISTORY: * * 05/27/1997 JLB : Created. * *=============================================================================================*/ bool DSurface::Fill_Rect(Rect const & cliprect, Rect const & fillrect, int color) { if (!fillrect.Is_Valid()) return(false); /* ** If the buffer is locked, then using the blitter to perform the fill is not possible. ** In such a case, perform a manual fill of the region. */ if (Is_Locked()) { return(XSurface::Fill_Rect(cliprect, fillrect, color)); } Restore_Check(); /* ** Ensure that the clipping rectangle is legal. */ Rect crect = cliprect.Intersect(Get_Rect()); /* ** Bias the fill rect to the clipping rectangle. */ Rect frect = fillrect.Bias_To(cliprect); /* ** Find the region that should be filled after being clipped by the ** clipping rectangle. This could result in no fill operation being performed ** if the desired fill rectangle has been completely clipped away. */ frect = frect.Intersect(crect); if (!frect.Is_Valid()) return(false); RECT rect; rect.left = frect.X; rect.top = frect.Y; rect.right = rect.left + frect.Width; rect.bottom = rect.top + frect.Height; DDBLTFX fx; memset(&fx, '\0', sizeof(fx)); fx.dwSize = sizeof(fx); fx.dwFillColor = color; HRESULT result = SurfacePtr->Blt(&rect, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx); return(result == DD_OK); } /*********************************************************************************************** * DSurface::Build_Hicolor_Pixel -- Construct a hicolor pixel according to the surface pixel f * * * * This routine will construct a pixel according to the highcolor pixel format for this * * surface. * * * * INPUT: red -- The red component of the color (0..255). * * * * green -- The green component of the color (0..255). * * * * blue -- The blue component of the color (0..255). * * * * OUTPUT: Returns with a screen format pixel number that most closesly matches the color * * specified. * * * * WARNINGS: The return value is card dependant and only applies to hicolor displays. * * * * HISTORY: * * 05/27/1997 JLB : Created. * *=============================================================================================*/ int DSurface::Build_Hicolor_Pixel(int red, int green, int blue) { return(((red >> RedLeft) << RedRight) | ((green >> GreenLeft) << GreenRight) | ((blue >> BlueLeft) << BlueRight)); } /*********************************************************************************************** * DSurface::Build_Remap_Table -- Build a highcolor remap table. * * * * This will build a complete hicolor remap table for the palette specified. This table * * can then be used to quickly fetch a pixel that matches the color index of the palette. * * * * INPUT: table -- The location to store the hicolor table. The buffer must be 256*2 bytes * * long. * * * * palette -- The palette to use to create the remap table. * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 05/27/1997 JLB : Created. * *=============================================================================================*/ void DSurface::Build_Remap_Table(unsigned short * table, PaletteClass const & palette) { assert(table != NULL); /* ** Build the hicolor index table according to the palette. */ for (int index = 0; index < 256; index++) { table[index] = (unsigned short)Build_Hicolor_Pixel(palette[index].Get_Red(), palette[index].Get_Green(), palette[index].Get_Blue()); } }