mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
415
Code/wwlib/blit.cpp
Normal file
415
Code/wwlib/blit.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
** 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/blit.cpp $*
|
||||
* *
|
||||
* $Author:: Eric_c $*
|
||||
* *
|
||||
* $Modtime:: 4/15/99 10:13a $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Bit_Blit -- Blit a block of pixels to the destination surface. *
|
||||
* Bit_Blit -- Blits data to a surface w/ clipping. *
|
||||
* Buffer_Size -- Determines size of buffer for given dimensions. *
|
||||
* From_Buffer -- Copy graphic data from a buffer to a surface. *
|
||||
* RLE_Blit -- Blits RLE compressed data without extra clipping. *
|
||||
* RLE_Blit -- Blits a rectangle of RLE compressed data to a surface. *
|
||||
* To_Buffer -- Copies a graphic region into a linear RAM buffer. *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "always.h"
|
||||
#include "blit.h"
|
||||
#include "bsurface.h"
|
||||
//#include "rle.h"
|
||||
#include "xsurface.h"
|
||||
//#include <stdlib.h>
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Buffer_Size -- Determines size of buffer for given dimensions. *
|
||||
* *
|
||||
* This routine will determine the byte size of a buffer if it were to hold the pixels *
|
||||
* of the dimensions specified. It takes into account the bytes per pixel. *
|
||||
* *
|
||||
* INPUT: surface -- The surface to base the buffer size calculation upon. *
|
||||
* *
|
||||
* width -- Pixel width of a graphic region. *
|
||||
* *
|
||||
* height -- Pixel height of a graphic region. *
|
||||
* *
|
||||
* OUTPUT: Returns with the number of bytes such a region would consume if it were linearly *
|
||||
* packed into a memory buffer. *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/07/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
int Buffer_Size(Surface const & surface, int width, int height)
|
||||
{
|
||||
return(width * height * surface.Bytes_Per_Pixel());
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* To_Buffer -- Copies a graphic region into a linear RAM buffer. *
|
||||
* *
|
||||
* This routine will copy the graphic rectangle specified, into a RAM buffer. The size of *
|
||||
* the RAM buffer must be big enough to hold the pixel data. Use the Buffer_Size() function *
|
||||
* to determine how big it must be. *
|
||||
* *
|
||||
* INPUT: surface -- The surface to copy the pixel data from. *
|
||||
* *
|
||||
* rect -- The graphic rectangle to copy from. *
|
||||
* *
|
||||
* buffer -- Reference to the buffer that will be filled with the pixel data. *
|
||||
* *
|
||||
* OUTPUT: bool; Was the data copy performed without error? *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/07/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool To_Buffer(Surface const & surface, Rect const & rect, Buffer & buffer)
|
||||
{
|
||||
if (!rect.Is_Valid()) return(false);
|
||||
|
||||
BSurface from(rect.Width, rect.Height, surface.Bytes_Per_Pixel(), buffer);
|
||||
return(from.Blit_From(Rect(0, 0, rect.Width, rect.Height), surface, rect));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* From_Buffer -- Copy graphic data from a buffer to a surface. *
|
||||
* *
|
||||
* This routine will take pixel data and move it from the specified buffer and into the *
|
||||
* surface rectangle specified. It is the counterpart routine of To_Buffer(). *
|
||||
* *
|
||||
* INPUT: surface -- The surface to store the pixel data to. *
|
||||
* *
|
||||
* rect -- The destination rectangle to store the pixel data to. *
|
||||
* *
|
||||
* buffer -- Reference to the buffer that contains the pixel data. *
|
||||
* *
|
||||
* OUTPUT: bool; Was the pixel data copy performed without error? *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/07/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool From_Buffer(Surface & surface, Rect const & rect, Buffer const & buffer)
|
||||
{
|
||||
if (!rect.Is_Valid()) return(false);
|
||||
|
||||
BSurface from(rect.Width, rect.Height, surface.Bytes_Per_Pixel(), buffer);
|
||||
return(surface.Blit_From(rect, from, Rect(0, 0, rect.Width, rect.Height)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Bit_Blit -- Blits data to a surface w/ clipping. *
|
||||
* *
|
||||
* This routine will take source pixel data and blit it to the surface specified while *
|
||||
* also performing clipping on both the source and the destination data. Typical users of *
|
||||
* this routine would be to draw shape (sprite) data. *
|
||||
* *
|
||||
* INPUT: dest -- Destintaion surface rect. This specifies the destination surface and *
|
||||
* any coordinate clipping rectangle. *
|
||||
* *
|
||||
* destrect -- The destination rectangle of the blit. The coordinates are relative *
|
||||
* to the destination clipping rectangle. *
|
||||
* *
|
||||
* source -- Source surface rect. This specifies the source surface as well as any *
|
||||
* clipping rectangle it may contain. *
|
||||
* *
|
||||
* srcrect -- The rectange, relative to the source clipping rectangle, that *
|
||||
* specifies the source blit data. It is presumed that the dimensions of *
|
||||
* the source rectangle are the same as the destination rectangle. *
|
||||
* *
|
||||
* blitter -- The blitter to use for moving the source pixels to the destination *
|
||||
* surface. *
|
||||
* *
|
||||
* OUTPUT: bool; Was the blit performed even if it was for only a single pixel. Failure would *
|
||||
* indicate that the blit was completely clipped away. *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 05/19/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Bit_Blit(Surface & dest, Rect const & destrect, Surface const & source, Rect const & sourcerect, Blitter const & blitter)
|
||||
{
|
||||
return(Bit_Blit(dest, dest.Get_Rect(), destrect, source, source.Get_Rect(), sourcerect, blitter));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Bit_Blit -- Blit a block of pixels to the destination surface. *
|
||||
* *
|
||||
* This routine will blit a block of pixels and perform clipping on the blit as controlled *
|
||||
* by the clipping rectangles. *
|
||||
* *
|
||||
* INPUT: dest -- Surface to blit to. *
|
||||
* *
|
||||
* dcliprect-- The destination surface clipping rectangle. *
|
||||
* *
|
||||
* ddrect -- The destination rect of the blit. It is relative to the clipping *
|
||||
* rectangle and will be clipped against same. *
|
||||
* *
|
||||
* source -- The source surface to blit from. *
|
||||
* *
|
||||
* scliprect-- The source surface clipping rectangle. *
|
||||
* *
|
||||
* ssrect -- The source rectangle of the blit. It is relative to the source *
|
||||
* clipping rectangle and will be clipped against same. *
|
||||
* *
|
||||
* blitter -- The blitter to use for blitting of this rectangle. *
|
||||
* *
|
||||
* OUTPUT: bool; Was the blit performed? A 'false' return value would indicate that the *
|
||||
* blit was clipped into nothing. *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 05/27/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Bit_Blit(Surface & dest, Rect const & dcliprect, Rect const & ddrect, Surface const & source, Rect const & scliprect, Rect const & ssrect, Blitter const & blitter)
|
||||
{
|
||||
Rect srect = ssrect;
|
||||
Rect drect = ddrect;
|
||||
bool overlapped = false;
|
||||
void * dbuffer = NULL;
|
||||
void * sbuffer = NULL;
|
||||
|
||||
/*
|
||||
** Prepare for the blit by performing any clipping as well as fetching pointers into the
|
||||
** pixel buffers. If there were any errors, then this blit cannot be performed.
|
||||
*/
|
||||
if (!XSurface::Prep_For_Blit(dest, dcliprect, drect, source, scliprect, srect, overlapped, dbuffer, sbuffer)) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/*
|
||||
** If there is no difference between the width and the stride of the source and
|
||||
** destination surfaces, then the copy can be performed as one huge copy operation.
|
||||
** This is the simplist case and the one that is performed with a full screen
|
||||
** blit.
|
||||
*/
|
||||
if (drect.Width * dest.Bytes_Per_Pixel() == dest.Stride() && dest.Stride() == source.Stride()) {
|
||||
|
||||
int length = MIN(srect.Height*srect.Width, drect.Height*drect.Width);
|
||||
if (overlapped) {
|
||||
blitter.BlitBackward(dbuffer, sbuffer, length);
|
||||
} else {
|
||||
blitter.BlitForward(dbuffer, sbuffer, length);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
** If the rectangles overlap, then the copy must proceed from the
|
||||
** last row to the first rather than the normal direction.
|
||||
*/
|
||||
int sstride = source.Stride();
|
||||
int dstride = dest.Stride();
|
||||
if (overlapped) {
|
||||
sstride = -sstride;
|
||||
dstride = -dstride;
|
||||
sbuffer = ((char*)sbuffer) + (srect.Height-1) * source.Stride();
|
||||
dbuffer = ((char*)dbuffer) + (drect.Height-1) * dest.Stride();
|
||||
}
|
||||
|
||||
/*
|
||||
** This perform a line-by-line pixel copy.
|
||||
*/
|
||||
int height = MIN(srect.Height, drect.Height);
|
||||
if (overlapped) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
blitter.BlitBackward(dbuffer, sbuffer, srect.Width);
|
||||
dbuffer = (void*)(((char*)dbuffer) + dstride);
|
||||
sbuffer = (void*)(((char*)sbuffer) + sstride);
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
blitter.BlitForward(dbuffer, sbuffer, srect.Width);
|
||||
dbuffer = (void*)(((char*)dbuffer) + dstride);
|
||||
sbuffer = (void*)(((char*)sbuffer) + sstride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dest.Unlock();
|
||||
source.Unlock();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* RLE_Blit -- Blits RLE compressed data without extra clipping. *
|
||||
* *
|
||||
* This routine will blit a rectangle of RLE compressed data to the specified surface. It *
|
||||
* is functionally similar to the other RLE blit routine, but does not use any sub *
|
||||
* clipping rectangles. The blit is naturally clipped to the edge of the destination *
|
||||
* surface. *
|
||||
* *
|
||||
* INPUT: dest -- Reference to the destination surface. *
|
||||
* *
|
||||
* destrect -- The destination rectangle to draw the pixels to. *
|
||||
* *
|
||||
* source -- Reference to the source RLE surface data. *
|
||||
* *
|
||||
* sourcerect -- The source rectangle of from the RLE surface to blit from. *
|
||||
* *
|
||||
* blitter -- Reference to the blitter to perform the blit operation with. *
|
||||
* *
|
||||
* OUTPUT: bool; Was a blit performed? A 'false' value would mean that the blit has been *
|
||||
* clipped into nothing. *
|
||||
* *
|
||||
* WARNINGS: The dimensions of the source and destination rectangles should be the same *
|
||||
* until such time that the blitter can support scaling (as of this writing, it *
|
||||
* cannot). *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 05/27/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool RLE_Blit(Surface & dest, Rect const & destrect, Surface const & source, Rect const & sourcerect, RLEBlitter const & blitter)
|
||||
{
|
||||
return(RLE_Blit(dest, dest.Get_Rect(), destrect, source, source.Get_Rect(), sourcerect, blitter));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* RLE_Blit -- Blits a rectangle of RLE compressed data to a surface. *
|
||||
* *
|
||||
* This routine will blit a rectangle of REL compressed pixel data from a sprite to the *
|
||||
* surface specified. Appropriate clipping and coordinate adjustments will occur as *
|
||||
* controlled by the parameters. This is the workhorse RLE blit dispatcher routine. *
|
||||
* *
|
||||
* INPUT: dest -- The destination surface to blit to. *
|
||||
* *
|
||||
* dcliprect-- The clipping rectangle to use on the destination. Pixels won't be *
|
||||
* drawn outside of this rectangle and the destination rect coordinates *
|
||||
* are biased to this clipping rectange. *
|
||||
* *
|
||||
* ddrect -- The destination rectangle of the blit. The upper left coordinates are *
|
||||
* biased to the destination clipping rectangle when blitted. Thus, *
|
||||
* a dest X,Y position of 0,0 really means the upper left corner of the *
|
||||
* destination clipping rectangle. *
|
||||
* *
|
||||
* source -- The source surface of the RLE compressed data. *
|
||||
* *
|
||||
* scliprect-- It is quite likely that this will be the full size of the source *
|
||||
* surface. *
|
||||
* *
|
||||
* ssrect -- The source rectangle to blit from within the source surface. It *
|
||||
* behaves similarly to the ddrect parameter, but for the source. The *
|
||||
* width and height of this rectangle should match the width and height *
|
||||
* of the ddrect parameter (scaling is not yet supported). *
|
||||
* *
|
||||
* blitter -- The blitter to use for this pixel copy. It must be an RLE blitter. *
|
||||
* *
|
||||
* OUTPUT: bool; Did the blit draw at least one pixel? *
|
||||
* *
|
||||
* WARNINGS: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 05/24/1997 JLB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool RLE_Blit(Surface & dest, Rect const & dcliprect, Rect const & ddrect, Surface const & source, Rect const & scliprect, Rect const & ssrect, RLEBlitter const & blitter)
|
||||
{
|
||||
Rect srect = ssrect; // Desired source rect.
|
||||
Rect drect = ddrect; // Desired destination rect.
|
||||
|
||||
/*
|
||||
** Adjust the desired draw rectangles to account for clipping. This is where the desired rectangles
|
||||
** get clipped to the bounding rectangles of the surfaces.
|
||||
*/
|
||||
if (!Blit_Clip(drect, dcliprect, srect, scliprect)) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine the top and left skip margins. These require special handling
|
||||
** since the shape is compressed.
|
||||
*/
|
||||
int leftmargin = srect.X - scliprect.X;
|
||||
int topmargin = srect.Y - scliprect.Y;
|
||||
|
||||
void * dbuffer = dest.Lock(dcliprect.Top_Left() + drect.Top_Left());
|
||||
// void * dbuffer = dest.Lock(Point2D(dcliprect.X + drect.X, dcliprect.Y + drect.Y));
|
||||
if (dbuffer == NULL) return(false);
|
||||
|
||||
/*
|
||||
** Lock the source pointer. This must always lock at location 0,0 since
|
||||
** normal pixel offset logic does not work for RLE compressed buffers. If there
|
||||
** is a pixel offset required, it is handled below.
|
||||
*/
|
||||
void * sbuffer = source.Lock();
|
||||
if (sbuffer == NULL) {
|
||||
dest.Unlock();
|
||||
return(false);
|
||||
}
|
||||
|
||||
/*
|
||||
** Skip any top margin lines. This must be manually performed on a line
|
||||
** by line basis because the length of each line is Variable.
|
||||
*/
|
||||
while (topmargin > 0) {
|
||||
sbuffer = ((unsigned char *)sbuffer) + (*(unsigned short *)sbuffer);
|
||||
topmargin--;
|
||||
}
|
||||
|
||||
/*
|
||||
** This perform a line-by-line pixel copy.
|
||||
*/
|
||||
int dstride = dest.Stride();
|
||||
int height = MIN(srect.Height, drect.Height);
|
||||
for (int y = 0; y < height; y++) {
|
||||
|
||||
/*
|
||||
** Blit the correct sub-portion to the destination surface.
|
||||
*/
|
||||
blitter.Blit(dbuffer, ((unsigned short *)sbuffer)+1, srect.Width, leftmargin);
|
||||
|
||||
/*
|
||||
** Advance the source and dest pointers for the next line processing.
|
||||
*/
|
||||
sbuffer = ((unsigned char *)sbuffer) + (*(unsigned short *)sbuffer);
|
||||
dbuffer = (void*)(((char*)dbuffer) + dstride);
|
||||
}
|
||||
|
||||
dest.Unlock();
|
||||
source.Unlock();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user