This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwlib/dsurface.cpp

932 lines
48 KiB
C++
Raw Permalink Normal View History

/*
** 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 <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** 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 <assert.h>
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());
}
}