CnC_Remastered_Collection/REDALERT/WIN32LIB/GBUFFER.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

708 lines
32 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
***************************************************************************
* *
* Project Name : Westwood 32 bit Library *
* *
* File Name : GBUFFER.CPP *
* *
* Programmer : Phil W. Gorrow *
* *
* Start Date : May 3, 1994 *
* *
* Last Update : October 9, 1995 [] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* VVPC::VirtualViewPort -- Default constructor for a virtual viewport *
* VVPC:~VirtualViewPortClass -- Destructor for a virtual viewport *
* VVPC::Clear -- Clears a graphic page to correct color *
* VBC::VideoBufferClass -- Lowlevel constructor for video buffer class *
* GVPC::Change -- Changes position and size of a Graphic View Port *
* VVPC::Change -- Changes position and size of a Video View Port *
* Set_Logic_Page -- Sets LogicPage to new buffer *
* GBC::DD_Init -- Inits a direct draw surface for a GBC *
* GBC::Init -- Core function responsible for initing a GBC *
* GBC::Lock -- Locks a Direct Draw Surface *
* GBC::Unlock -- Unlocks a direct draw surface *
* GBC::GraphicBufferClass -- Default constructor (requires explicit init)*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef GBUFFER_H
#include "gbuffer.h"
#include "misc.h"
#endif
//#pragma inline
int TotalLocks;
BOOL AllowHardwareBlitFills = TRUE;
//int CacheAllowed;
/*=========================================================================*/
/* The following PRIVATE functions are in this file: */
/*=========================================================================*/
/*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
/***************************************************************************
* GVPC::GRAPHICVIEWPORTCLASS -- Constructor for basic view port class *
* m *
* INPUT: GraphicBufferClass * gbuffer - buffer to attach to *
* int x - x offset into buffer *
* int y - y offset into buffer *
* int w - view port width in pixels *
* int h - view port height in pixels *
* *
* OUTPUT: Constructors may not have a return value *
* *
* HISTORY: *
* 05/09/1994 PWG : Created. *
*=========================================================================*/
GraphicViewPortClass::GraphicViewPortClass(GraphicBufferClass *gbuffer, int x, int y, int w, int h) :
LockCount(0),
GraphicBuff(NULL)
{
Attach(gbuffer, x, y, w, h);
}
/***************************************************************************
* GVPC::GRAPHICVIEWPORTCLASS -- Default constructor for view port class *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 05/09/1994 PWG : Created. *
*=========================================================================*/
GraphicViewPortClass::GraphicViewPortClass(void)
{
}
/***************************************************************************
* GVPC::~GRAPHICVIEWPORTCLASS -- Destructor for GraphicViewPortClass *
* *
* INPUT: none *
* *
* OUTPUT: A destructor may not return a value. *
* *
* HISTORY: *
* 05/10/1994 PWG : Created. *
*=========================================================================*/
GraphicViewPortClass::~GraphicViewPortClass(void)
{
Offset = 0;
Width = 0; // Record width of Buffer
Height = 0; // Record height of Buffer
XAdd = 0; // Record XAdd of Buffer
XPos = 0; // Record XPos of Buffer
YPos = 0; // Record YPos of Buffer
Pitch = 0; // Record width of Buffer
IsDirectDraw = FALSE;
LockCount = 0;
GraphicBuff = NULL;
}
/***************************************************************************
* GVPC::ATTACH -- Attaches a viewport to a buffer class *
* *
* INPUT: GraphicBufferClass *g_buff - pointer to gbuff to attach to *
* int x - x position to attach to *
* int y - y position to attach to *
* int w - width of the view port *
* int h - height of the view port *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 05/10/1994 PWG : Created. *
*=========================================================================*/
void GraphicViewPortClass::Attach(GraphicBufferClass *gbuffer, int x, int y, int w, int h)
{
/*======================================================================*/
/* Can not attach a Graphic View Port if it is actually the physical */
/* representation of a Graphic Buffer. */
/*======================================================================*/
if (this == Get_Graphic_Buffer()) {
return;
}
/*======================================================================*/
/* Verify that the x and y coordinates are valid and placed within the */
/* physical buffer. */
/*======================================================================*/
if (x < 0) // you cannot place view port off
x = 0; // the left edge of physical buf
if (x >= gbuffer->Get_Width()) // you cannot place left edge off
x = gbuffer->Get_Width() - 1; // the right edge of physical buf
if (y < 0) // you cannot place view port off
y = 0; // the top edge of physical buf
if (y >= gbuffer->Get_Height()) // you cannot place view port off
y = gbuffer->Get_Height() - 1; // bottom edge of physical buf
/*======================================================================*/
/* Adjust the width and height of necessary */
/*======================================================================*/
if (x + w > gbuffer->Get_Width()) // if the x plus width is larger
w = gbuffer->Get_Width() - x; // than physical, fix width
if (y + h > gbuffer->Get_Height()) // if the y plus height is larger
h = gbuffer->Get_Height() - y; // than physical, fix height
/*======================================================================*/
/* Get a pointer to the top left edge of the buffer. */
/*======================================================================*/
Offset = gbuffer->Get_Offset() + ((gbuffer->Get_Width()+gbuffer->Get_Pitch()) * y) + x;
/*======================================================================*/
/* Copy over all of the variables that we need to store. */
/*======================================================================*/
XPos = x;
YPos = y;
XAdd = gbuffer->Get_Width() - w;
Width = w;
Height = h;
Pitch = gbuffer->Get_Pitch();
GraphicBuff = gbuffer;
IsDirectDraw= gbuffer->IsDirectDraw;
}
/***************************************************************************
* GVPC::CHANGE -- Changes position and size of a Graphic View Port *
* *
* INPUT: int the new x pixel position of the graphic view port *
* int the new y pixel position of the graphic view port *
* int the new width of the viewport in pixels *
* int the new height of the viewport in pixels *
* *
* OUTPUT: BOOL whether the Graphic View Port could be sucessfully *
* resized. *
* *
* WARNINGS: You may not resize a Graphic View Port which is derived *
* from a Graphic View Port Buffer, *
* *
* HISTORY: *
* 09/14/1994 SKB : Created. *
*=========================================================================*/
BOOL GraphicViewPortClass::Change(int x, int y, int w, int h)
{
/*======================================================================*/
/* Can not change a Graphic View Port if it is actually the physical */
/* representation of a Graphic Buffer. */
/*======================================================================*/
if (this == Get_Graphic_Buffer()) {
return(FALSE);
}
/*======================================================================*/
/* Since there is no allocated information, just re-attach it to the */
/* existing graphic buffer as if we were creating the */
/* GraphicViewPort. */
/*======================================================================*/
Attach(Get_Graphic_Buffer(), x, y, w, h);
return(TRUE);
}
/***************************************************************************
* GBC::DD_INIT -- Inits a direct draw surface for a GBC *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 10/09/1995 : Created. *
*=========================================================================*/
void GraphicBufferClass::DD_Init(GBC_Enum flags)
{
//
// Create the direct draw surface description
//
memset (&VideoSurfaceDescription , 0 , sizeof ( VideoSurfaceDescription ));
VideoSurfaceDescription.dwSize = sizeof( VideoSurfaceDescription );
VideoSurfaceDescription.dwFlags = DDSD_CAPS;
VideoSurfaceDescription.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (!(flags & GBC_VISIBLE)) {
VideoSurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
VideoSurfaceDescription.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH;
VideoSurfaceDescription.dwHeight = Height;
VideoSurfaceDescription.dwWidth = Width;
}
//
// Need to set the DDSCAPS_MODEX flag if we want a 320 wide mode
//
if ( Width == 320 ) {
VideoSurfaceDescription.ddsCaps.dwCaps |= DDSCAPS_MODEX;
}
//
// Call CreateSurface
//
DirectDrawObject->CreateSurface( &VideoSurfaceDescription , &VideoSurfacePtr , NULL);
AllSurfaces.Add_DD_Surface (VideoSurfacePtr);
if ( GBC_VISIBLE & flags ){
PaletteSurface=VideoSurfacePtr;
}
Allocated = FALSE; // even if system alloced, dont flag it cuz
// we dont want it freed.
IsDirectDraw = TRUE; // flag it as a video surface
Offset = NOT_LOCKED; // flag it as unavailable for reading or writing
LockCount = 0; // surface is not locked
}
void GraphicBufferClass::Attach_DD_Surface (GraphicBufferClass * attach_buffer)
{
VideoSurfacePtr->AddAttachedSurface (attach_buffer->Get_DD_Surface());
}
/***************************************************************************
* GBC::INIT -- Core function responsible for initing a GBC *
* *
* INPUT: int - the width in pixels of the GraphicBufferClass *
* int - the heigh in pixels of the GraphicBufferClass *
* void * - pointer to user supplied buffer (system will *
* allocate space if buffer is NULL) *
* long - size of the user provided buffer *
* GBC_Enum - flags if this is defined as a direct draw *
* surface *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 10/09/1995 : Created. *
*=========================================================================*/
void GraphicBufferClass::Init(int w, int h, void *buffer, long size, GBC_Enum flags)
{
Size = size; // find size of physical buffer
Width = w; // Record width of Buffer
Height = h; // Record height of Buffer
//
// If the surface we are creating is a direct draw object then
// we need to do a direct draw init. Otherwise we will do
// a normal alloc.
//
if (flags & (GBC_VIDEOMEM | GBC_VISIBLE)) {
DD_Init(flags);
} else {
if (buffer) { // if buffer is specified
Buffer = (BYTE *)buffer; // point to it and mark
Allocated = FALSE; // it as user allocated
} else {
if (!Size) Size = w*h;
Buffer = new BYTE[Size]; // otherwise allocate it and
Allocated = TRUE; // mark it system alloced
}
Offset = (long)Buffer; // Get offset to the buffer
IsDirectDraw = FALSE;
}
Pitch = 0; // Record width of Buffer
XAdd = 0; // Record XAdd of Buffer
XPos = 0; // Record XPos of Buffer
YPos = 0; // Record YPos of Buffer
GraphicBuff = this; // Get a pointer to our self
}
/***********************************************************************************************
* GBC::Un_Init -- releases the video surface belonging to this gbuffer *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/6/96 12:44PM ST : Created *
*=============================================================================================*/
void GraphicBufferClass::Un_Init (void)
{
if ( IsDirectDraw ){
if ( VideoSurfacePtr ){
while ( LockCount ){
if (VideoSurfacePtr->Unlock ( NULL ) == DDERR_SURFACELOST){
if (Gbuffer_Focus_Loss_Function){
Gbuffer_Focus_Loss_Function();
}
AllSurfaces.Restore_Surfaces();
}
}
AllSurfaces.Remove_DD_Surface (VideoSurfacePtr);
VideoSurfacePtr->Release();
VideoSurfacePtr = NULL;
}
}
}
/***************************************************************************
* GBC::GRAPHICBUFFERCLASS -- Default constructor (requires explicit init) *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 10/09/1995 : Created. *
*=========================================================================*/
GraphicBufferClass::GraphicBufferClass(void)
{
GraphicBuff = this; // Get a pointer to our self
VideoSurfacePtr = NULL;
memset(&VideoSurfaceDescription, 0, sizeof(DDSURFACEDESC));
}
/***************************************************************************
* GBC::GRAPHICBUFFERCLASS -- Constructor for fixed size buffers *
* *
* INPUT: long size - size of the buffer to create *
* int w - width of buffer in pixels (default = 320) *
* int h - height of buffer in pixels (default = 200) *
* void *buffer - a pointer to the buffer if any (optional) *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 05/13/1994 PWG : Created. *
*=========================================================================*/
GraphicBufferClass::GraphicBufferClass(int w, int h, void *buffer, long size)
{
Init(w, h, buffer, size, GBC_NONE);
}
/*=========================================================================*
* GBC::GRAPHICBUFFERCLASS -- inline constructor for GraphicBufferClass *
* *
* INPUT: int w - width of buffer in pixels (default = 320) *
* int h - height of buffer in pixels (default = 200) *
* void *buffer - a pointer to the buffer if any (optional) *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 05/03/1994 PWG : Created. *
*=========================================================================*/
GraphicBufferClass::GraphicBufferClass(int w, int h, void *buffer)
{
Init(w, h, buffer, w * h, GBC_NONE);
}
/*====================================================================================*
* GBC::GRAPHICBUFFERCLASS -- contructor for GraphicsBufferClass with special flags *
* *
* INPUT: int w - width of buffer in pixels (default = 320) *
* int h - height of buffer in pixels (default = 200) *
* void *buffer - unused *
* unsigned flags - flags for creation of special buffer types *
* GBC_VISIBLE - buffer is a visible screen surface *
* GBC_VIDEOMEM - buffer resides in video memory *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 09-21-95 04:19pm ST : Created *
*====================================================================================*/
GraphicBufferClass::GraphicBufferClass(int w, int h, GBC_Enum flags)
{
Init(w, h, NULL, w * h, flags);
}
/*=========================================================================*
* GBC::~GRAPHICBUFFERCLASS -- Destructor for the graphic buffer class *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 05/03/1994 PWG : Created. *
*=========================================================================*/
GraphicBufferClass::~GraphicBufferClass()
{
//
// Release the direct draw surface if it exists
//
Un_Init();
}
/***************************************************************************
* SET_LOGIC_PAGE -- Sets LogicPage to new buffer *
* *
* INPUT: GraphicBufferClass * the buffer we are going to set *
* *
* OUTPUT: GraphicBufferClass * the previous buffer type *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/23/1995 PWG : Created. *
*=========================================================================*/
GraphicViewPortClass *Set_Logic_Page(GraphicViewPortClass *ptr)
{
GraphicViewPortClass *old = LogicPage;
LogicPage = ptr;
return(old);
}
/***************************************************************************
* SET_LOGIC_PAGE -- Sets LogicPage to new buffer *
* *
* INPUT: GraphicBufferClass & the buffer we are going to set *
* *
* OUTPUT: GraphicBufferClass * the previous buffer type *
* *
* WARNINGS: *
* *
* HISTORY: *
* 02/23/1995 PWG : Created. *
*=========================================================================*/
GraphicViewPortClass *Set_Logic_Page(GraphicViewPortClass &ptr)
{
GraphicViewPortClass *old = LogicPage;
LogicPage = &ptr;
return(old);
}
/***************************************************************************
* GBC::LOCK -- Locks a Direct Draw Surface *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 10/09/1995 : Created. *
* 10/09/1995 : Code stolen from Steve Tall *
*=========================================================================*/
extern void Colour_Debug (int call_number);
extern bool GameInFocus;
extern void Block_Mouse(GraphicBufferClass *buffer);
extern void Unblock_Mouse(GraphicBufferClass *buffer);
BOOL GraphicBufferClass::Lock(void)
{
HRESULT result;
int restore_attempts=0;
//
// If its not a direct draw surface then the lock is always sucessful.
//
if (!IsDirectDraw) return(TRUE);
/*
** If the video surface pointer is null then return
*/
if (!VideoSurfacePtr) return (FALSE);
/*
** If we dont have focus then return failure
*/
if (!GameInFocus) return (FALSE);
Block_Mouse(this);
//
// If surface is already locked then inc the lock count and return true
//
if (LockCount){
LockCount++;
Unblock_Mouse(this);
return(TRUE);
}
//
// If it isn't locked at all then we will have to request that Direct
// Draw actually lock the surface.
//
if (VideoSurfacePtr){
while (!LockCount && restore_attempts<2) {
result = VideoSurfacePtr->Lock ( NULL
, &(VideoSurfaceDescription)
, DDLOCK_WAIT
, NULL);
switch (result){
case DD_OK :
Offset = (unsigned long)VideoSurfaceDescription.lpSurface;
Pitch = VideoSurfaceDescription.lPitch;
Pitch -= Width;
LockCount++; // increment count so we can track if
TotalLocks++; // Total number of times we have locked (for debugging)
//Colour_Debug (1);
Unblock_Mouse(this);
return (TRUE); // we locked it multiple times.
case DDERR_SURFACELOST :
if (Gbuffer_Focus_Loss_Function){
Gbuffer_Focus_Loss_Function();
}
AllSurfaces.Restore_Surfaces();
restore_attempts++;
break;
default :
Unblock_Mouse(this);
return (FALSE);
}
}
}
//Colour_Debug(1);
Unblock_Mouse(this);
return (FALSE); //Return false because we couldnt lock or restore the surface
}
/***************************************************************************
* GBC::UNLOCK -- Unlocks a direct draw surface *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* HISTORY: *
* 10/09/1995 : Created. *
* 10/09/1995 : Code stolen from Steve Tall *
*=========================================================================*/
BOOL GraphicBufferClass::Unlock(void)
{
//
// If there is no lock count or this is not a direct draw surface
// then just return true as there is no harm done.
//
if (!(LockCount && IsDirectDraw)) {
return(TRUE);
}
//
// If lock count is directly equal to one then we actually need to
// unlock so just give it a shot.
//
if (LockCount == 1 && VideoSurfacePtr) {
Block_Mouse(this);
if ( VideoSurfacePtr->Unlock ( NULL ) != DD_OK ){
Unblock_Mouse(this);
return(FALSE);
} else {
Offset=NOT_LOCKED;
LockCount--;
Unblock_Mouse(this);
return(TRUE);
}
}
//Colour_Debug (0);
LockCount--;
return(TRUE);
}
/***********************************************************************************************
* GVPC::DD_Linear_Blit_To_Linear -- blit using the hardware blitter *
* *
* *
* *
* INPUT: destination vvpc *
* x coord to blit from *
* y coord to blit from *
* x coord to blit to *
* y coord to blit to *
* width to blit *
* height to blit *
* *
* OUTPUT: DD_OK if successful *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 09-22-95 11:05am ST : Created *
*=============================================================================================*/
HRESULT GraphicViewPortClass::DD_Linear_Blit_To_Linear (
GraphicViewPortClass &dest
, int source_x
, int source_y
, int dest_x
, int dest_y
, int width
, int height
, BOOL mask )
{
RECT source_rectangle;
RECT dest_rectangle;
int key_source=0;
if ( mask ){
key_source=DDBLT_KEYSRC;
}
source_rectangle.left = source_x;
source_rectangle.top = source_y;
source_rectangle.right = source_x+width;
source_rectangle.bottom = source_y+height;
dest_rectangle.left = dest_x;
dest_rectangle.top = dest_y;
dest_rectangle.right = dest_x+width;
dest_rectangle.bottom = dest_y+height;
return ( dest.GraphicBuff->Get_DD_Surface()->Blt ( &dest_rectangle,
GraphicBuff->Get_DD_Surface(),
&source_rectangle,
key_source | DDBLT_WAIT | DDBLT_ASYNC,
NULL ) );
}