t2 engine svn checkout

This commit is contained in:
loop 2024-01-07 04:36:33 +00:00
commit ff569bd2ae
988 changed files with 394180 additions and 0 deletions

52
dgl/bitmapBm8.cc Normal file
View file

@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/gBitmap.h"
#include "dgl/gPalette.h"
#include "Core/stream.h"
#include "Platform/platform.h"
bool GBitmap::readBmp8(Stream& stream)
{
stream.read(&byteSize);
stream.read(&width);
stream.read(&height);
stream.read(&bytesPerPixel);
stream.read(&numMipLevels);
U32 i;
for (i = 0; i < numMipLevels; i++)
stream.read(&mipLevelOffsets[i]);
internalFormat = GBitmap::Palettized;
pPalette = new GPalette;
pPalette->read(stream);
pBits = new U8[byteSize];
stream.read(byteSize, pBits);
return true;
}
bool GBitmap::writeBmp8(Stream& stream)
{
AssertFatal(pPalette != NULL, "Error, must have a palette to write the bmp!");
stream.write(byteSize);
stream.write(width);
stream.write(height);
stream.write(bytesPerPixel);
stream.write(numMipLevels);
U32 i;
for (i = 0; i < numMipLevels; i++)
stream.write(mipLevelOffsets[i]);
pPalette->write(stream);
stream.write(byteSize, pBits);
return true;
}

205
dgl/bitmapBmp.cc Normal file
View file

@ -0,0 +1,205 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/gBitmap.h"
#include "dgl/gPalette.h"
#include "Core/stream.h"
#include "Platform/platform.h"
// structures mirror those defined by the win32 API
struct RGBQUAD {
U8 rgbBlue;
U8 rgbGreen;
U8 rgbRed;
U8 rgbReserved;
};
struct BITMAPFILEHEADER {
U16 bfType;
U32 bfSize;
U16 bfReserved1;
U16 bfReserved2;
U32 bfOffBits;
};
struct BITMAPINFOHEADER{
U32 biSize;
S32 biWidth;
S32 biHeight;
U16 biPlanes;
U16 biBitCount;
U32 biCompression;
U32 biSizeImage;
S32 biXPelsPerMeter;
S32 biYPelsPerMeter;
U32 biClrUsed;
U32 biClrImportant;
};
// constants for the biCompression field
#define BI_RGB 0L
#define BI_RLE8 1L
#define BI_RLE4 2L
#define BI_BITFIELDS 3L
//------------------------------------------------------------------------------
//-------------------------------------- Supplimentary I/O (Partially located in
// bitmapPng.cc)
//
bool GBitmap::readMSBmp(Stream& stream)
{
BITMAPINFOHEADER bi;
BITMAPFILEHEADER bf;
RGBQUAD rgb[256];
stream.read(&bf.bfType);
stream.read(&bf.bfSize);
stream.read(&bf.bfReserved1);
stream.read(&bf.bfReserved2);
stream.read(&bf.bfOffBits);
stream.read(&bi.biSize);
stream.read(&bi.biWidth);
stream.read(&bi.biHeight);
stream.read(&bi.biPlanes);
stream.read(&bi.biBitCount);
stream.read(&bi.biCompression);
stream.read(&bi.biSizeImage);
stream.read(&bi.biXPelsPerMeter);
stream.read(&bi.biYPelsPerMeter);
stream.read(&bi.biClrUsed);
stream.read(&bi.biClrImportant);
BitmapFormat fmt = RGB;
if(bi.biBitCount == 8)
{
fmt = Palettized;
if(!bi.biClrUsed)
bi.biClrUsed = 256;
stream.read(sizeof(RGBQUAD) * bi.biClrUsed, rgb);
pPalette = new GPalette;
for (U32 i = 0; i < 256; i++)
{
(pPalette->getColors())[i].red = rgb[i].rgbRed;
(pPalette->getColors())[i].green = rgb[i].rgbGreen;
(pPalette->getColors())[i].blue = rgb[i].rgbBlue;
(pPalette->getColors())[i].alpha = 255;
}
}
U8 *rowBuffer = new U8[bi.biWidth * 4];
allocateBitmap(bi.biWidth, bi.biHeight, false, fmt);
S32 width = getWidth();
S32 height = getHeight();
for(int i = 0; i < bi.biHeight; i++)
{
U8 *rowDest = getAddress(0, height - i - 1);
stream.read(bytesPerPixel * width, rowDest);
}
if(bytesPerPixel == 3) // do BGR swap
{
U8 *ptr = getAddress(0,0);
for(int i = 0; i < width * height; i++)
{
U8 tmp = ptr[0];
ptr[0] = ptr[2];
ptr[2] = tmp;
ptr += 3;
}
}
delete[] rowBuffer;
return true;
}
bool GBitmap::writeMSBmp(Stream& io_rStream) const
{
RGBQUAD rgb[256];
BITMAPINFOHEADER bi;
BITMAPFILEHEADER bf;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = getWidth();
bi.biHeight = getHeight(); //our data is top-down
bi.biPlanes = 1;
if(getFormat() == Palettized)
{
bi.biBitCount = 8;
bi.biCompression = BI_RGB;
bi.biClrUsed = 256;
AssertFatal(pPalette != NULL, "Error, must have a palette");
}
else if(getFormat() == RGB)
{
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
bi.biClrUsed = 0;
}
U32 bytesPP = bi.biBitCount >> 3;
bi.biSizeImage = getWidth() * getHeight() * bytesPP;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
bf.bfType = makeFourCCTag('B','M',0,0); //Type of file 'BM'
bf.bfOffBits= sizeof(BITMAPINFOHEADER)
+ sizeof(BITMAPFILEHEADER)
+ (sizeof(RGBQUAD)*bi.biClrUsed);
bf.bfSize = bf.bfOffBits + bi.biSizeImage;
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
io_rStream.write(bf.bfType);
io_rStream.write(bf.bfSize);
io_rStream.write(bf.bfReserved1);
io_rStream.write(bf.bfReserved2);
io_rStream.write(bf.bfOffBits);
io_rStream.write(bi.biSize);
io_rStream.write(bi.biWidth);
io_rStream.write(bi.biHeight);
io_rStream.write(bi.biPlanes);
io_rStream.write(bi.biBitCount);
io_rStream.write(bi.biCompression);
io_rStream.write(bi.biSizeImage);
io_rStream.write(bi.biXPelsPerMeter);
io_rStream.write(bi.biYPelsPerMeter);
io_rStream.write(bi.biClrUsed);
io_rStream.write(bi.biClrImportant);
if(getFormat() == Palettized)
{
for (S32 ndx=0; ndx<256; ndx++)
{
rgb[ndx].rgbRed = pPalette->getColor(ndx).red;
rgb[ndx].rgbGreen = pPalette->getColor(ndx).green;
rgb[ndx].rgbBlue = pPalette->getColor(ndx).blue;
rgb[ndx].rgbReserved = 0;
}
io_rStream.write(sizeof(RGBQUAD)*256, (U8*)&rgb);
}
//write the bitmap bits
U8* pMSUpsideDownBits = new U8[bi.biSizeImage];
for (U32 i = 0; i < getHeight(); i++) {
const U8* pSrc = getAddress(0, i);
U8* pDst = pMSUpsideDownBits + (getHeight() - i - 1) * getWidth() * bytesPP;
dMemcpy(pDst, pSrc, getWidth() * bytesPP);
}
io_rStream.write(bi.biSizeImage, pMSUpsideDownBits);
delete [] pMSUpsideDownBits;
return io_rStream.getStatus() == Stream::Ok;
}

172
dgl/bitmapGif.cc Normal file
View file

@ -0,0 +1,172 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Core/stream.h"
#include "Core/fileStream.h"
#include "Core/memstream.h"
#include "dgl/gPalette.h"
#include "dgl/gBitmap.h"
#include "gif_lib.h"
//-------------------------------------- Replacement I/O for standard LIBjpeg
// functions. we don't wanna use
// FILE*'s...
static int gifReadDataFn(GifFileType *gifinfo, GifByteType *data, int length)
{
Stream *stream = (Stream*)gifinfo->UserData;
AssertFatal(stream != NULL, "jpegReadDataFn::No stream.");
int pos = stream->getPosition();
if (stream->read(length, data))
return length;
if (stream->getStatus() == Stream::EOS)
return (stream->getPosition()-pos);
else
return 0;
}
//--------------------------------------
static int gifWriteDataFn(GifFileType *gifinfo, GifByteType *data, int length)
{
Stream *stream = (Stream*)gifinfo->UserData;
AssertFatal(stream != NULL, "jpegWriteDataFn::No stream.");
if (stream->write(length, data))
return length;
else
return 0;
}
//--------------------------------------
bool GBitmap::readGIF(Stream &stream)
{
GifFileType *gifinfo = DGifOpen( (void*)&stream, gifReadDataFn);
if (!gifinfo)
return false;
GifRecordType recordType;
do
{
if (DGifGetRecordType(gifinfo, &recordType) == GIF_ERROR)
break;
if (recordType == IMAGE_DESC_RECORD_TYPE)
{
if (DGifGetImageDesc(gifinfo) == GIF_ERROR)
break;
BitmapFormat format = (gifinfo->SBackGroundColor == 0 ) ? RGB : RGBA;
allocateBitmap(gifinfo->SWidth, gifinfo->SHeight, false, format);
U32 gwidth = gifinfo->Image.Width ? gifinfo->Image.Width : width;
U32 gheight= gifinfo->Image.Height ? gifinfo->Image.Height : height;
U32 gifSize = gwidth * gheight;
U8 *data = new U8[gifSize];
if (DGifGetLine(gifinfo, data, gifSize) != GIF_ERROR)
{
// use the global or local color table ?
GifColorType *color = gifinfo->SColorMap->Colors;
if (gifinfo->Image.ColorMap)
color = gifinfo->Image.ColorMap->Colors;
if (color)
{
U8 *dst = getAddress(gifinfo->Image.Left, gifinfo->Image.Top);
U8 *src = data;
U32 right = gifinfo->Image.Left + gwidth;
U32 bottom = gifinfo->Image.Top + gheight;
U32 next = (width - gwidth) * bytesPerPixel;
if (format == RGBA)
{
for (U32 y=gifinfo->Image.Top; y<bottom; y++)
{
for (U32 x=gifinfo->Image.Left; x<right; x++, src++)
{
if (*src == gifinfo->SBackGroundColor)
{
// this is a transparent pixel
dst[0] = 0; // red
dst[1] = 0; // green
dst[2] = 0; // blue
dst[3] = 0; // alpha
}
else
{
dst[0] = color[*src].Red;
dst[1] = color[*src].Green;
dst[2] = color[*src].Blue;
dst[3] = 0; // alpha
}
dst += bytesPerPixel;
}
dst += next;
}
}
else
{
for (U32 y=gifinfo->Image.Top; y<bottom; y++)
{
for (U32 x=gifinfo->Image.Left; x<right; x++, src++)
{
dst[0] = color[*src].Red;
dst[1] = color[*src].Green;
dst[2] = color[*src].Blue;
dst += bytesPerPixel;
}
dst += next;
}
}
delete [] data;
DGifCloseFile(gifinfo);
return true;
}
}
// failure
delete [] data;
break;
}
else if (recordType == EXTENSION_RECORD_TYPE)
{
GifByteType *extension;
S32 extCode;
// Skip any extension blocks in file
if (DGifGetExtension(gifinfo, &extCode, &extension) != GIF_ERROR)
{
while (extension != NULL)
{
if (DGifGetExtensionNext(gifinfo, &extension) == GIF_ERROR)
return false;
}
}
else
return false;
}
break;
}while (recordType != TERMINATE_RECORD_TYPE);
DGifCloseFile(gifinfo);
return false;
}
//--------------------------------------------------------------------------
bool GBitmap::writeGIF(Stream&) const
{
return false;
}

189
dgl/bitmapJpeg.cc Normal file
View file

@ -0,0 +1,189 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Core/stream.h"
#include "Core/fileStream.h"
#include "Core/memstream.h"
#include "dgl/gPalette.h"
#include "dgl/gBitmap.h"
#include "jpeglib.h"
//-------------------------------------- Replacement I/O for standard LIBjpeg
// functions. we don't wanna use
// FILE*'s...
static int jpegReadDataFn(void *client_data, unsigned char *data, int length)
{
Stream *stream = (Stream*)client_data;
AssertFatal(stream != NULL, "jpegReadDataFn::No stream.");
int pos = stream->getPosition();
if (stream->read(length, data))
return length;
if (stream->getStatus() == Stream::EOS)
return (stream->getPosition()-pos);
else
return 0;
}
//--------------------------------------
static int jpegWriteDataFn(void *client_data, unsigned char *data, int length)
{
Stream *stream = (Stream*)client_data;
AssertFatal(stream != NULL, "jpegWriteDataFn::No stream.");
if (stream->write(length, data))
return length;
else
return 0;
}
//--------------------------------------
static void jpegFlushDataFn(void *)
{
//
}
//--------------------------------------
static int jpegErrorFn(void *client_data)
{
Stream *stream = (Stream*)client_data;
AssertFatal(stream != NULL, "jpegErrorFn::No stream.");
return (stream->getStatus() != Stream::Ok);
}
//--------------------------------------
bool GBitmap::readJPEG(Stream &stream)
{
JFREAD = jpegReadDataFn;
JFERROR = jpegErrorFn;
jpeg_decompress_struct cinfo;
jpeg_error_mgr jerr;
// We set up the normal JPEG error routines, then override error_exit.
//cinfo.err = jpeg_std_error(&jerr.pub);
//jerr.pub.error_exit = my_error_exit;
// if (setjmp(jerr.setjmp_buffer))
// {
// // If we get here, the JPEG code has signaled an error.
// // We need to clean up the JPEG object, close the input file, and return.
// jpeg_destroy_decompress(&cinfo);
// return false;
// }
cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
cinfo.client_data = (void*)&stream; // set the stream into the client_data
// Now we can initialize the JPEG decompression object.
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo);
// Read file header, set default decompression parameters
jpeg_read_header(&cinfo, true);
BitmapFormat format;
switch (cinfo.out_color_space)
{
case JCS_GRAYSCALE: format = Alpha; break;
case JCS_RGB: format = RGB; break;
default:
jpeg_destroy_decompress(&cinfo);
return false;
}
// Start decompressor
jpeg_start_decompress(&cinfo);
// allocate the bitmap space and init internal variables...
allocateBitmap(cinfo.output_width, cinfo.output_height, false, format);
// Set up the row pointers...
U32 rowBytes = cinfo.output_width * cinfo.output_components;
U8* pBase = (U8*)getBits();
for (U32 i = 0; i < height; i++)
{
JSAMPROW rowPointer = pBase + (i * rowBytes);
jpeg_read_scanlines(&cinfo, &rowPointer, 1);
}
// Finish decompression
jpeg_finish_decompress(&cinfo);
// Release JPEG decompression object
// This is an important step since it will release a good deal of memory.
jpeg_destroy_decompress(&cinfo);
return true;
}
//--------------------------------------------------------------------------
bool GBitmap::writeJPEG(Stream&) const
{
return false;
/*
if (compressHard == false) {
return _writePNG(stream, 6, 0, PNG_ALL_FILTERS);
} else {
U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough...
MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true);
// We have to try the potentially useful compression methods here.
const U32 zStrategies[] = { Z_DEFAULT_STRATEGY,
Z_FILTERED };
const U32 pngFilters[] = { PNG_FILTER_NONE,
PNG_FILTER_SUB,
PNG_FILTER_UP,
PNG_FILTER_AVG,
PNG_FILTER_PAETH,
PNG_ALL_FILTERS };
U32 minSize = 0xFFFFFFFF;
U32 bestStrategy = 0xFFFFFFFF;
U32 bestFilter = 0xFFFFFFFF;
U32 bestCLevel = 0xFFFFFFFF;
for (U32 cl = 0; cl <=9; cl++) {
for (U32 zs = 0; zs < 2; zs++) {
for (U32 pf = 0; pf < 6; pf++) {
pMemStream->setPosition(0);
if (_writePNG(*pMemStream, cl, zStrategies[zs], pngFilters[pf]) == false)
AssertFatal(false, "Handle this error!");
if (pMemStream->getPosition() < minSize) {
minSize = pMemStream->getPosition();
bestStrategy = zs;
bestFilter = pf;
bestCLevel = cl;
}
}
}
}
AssertFatal(minSize != 0xFFFFFFFF, "Error, no best found?");
delete pMemStream;
delete [] buffer;
return _writePNG(stream,
bestCLevel,
zStrategies[bestStrategy],
pngFilters[bestFilter]);
}
*/
}

415
dgl/bitmapPng.cc Normal file
View file

@ -0,0 +1,415 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Core/stream.h"
#include "Core/fileStream.h"
#include "Core/memstream.h"
#include "dgl/gPalette.h"
#include "dgl/gBitmap.h"
#include "Sim/frameAllocator.h"
#define PNG_INTERNAL 1
#include "time.h"
#include "png.h"
#include "zlib.h"
#ifdef NULL
#undef NULL
#define NULL 0
#endif
// Our chunk signatures...
static png_byte DGL_CHUNK_dcCf[5] = { 100, 99, 67, 102, '\0' };
static png_byte DGL_CHUNK_dcCs[5] = { 100, 99, 67, 115, '\0' };
static const U32 csgMaxRowPointers = 1024;
static png_bytep sRowPointers[1024];
//-------------------------------------- Instead of using the user_ptr,
// we use a global pointer, we
// need to ensure that only one thread
// at once may be using the variable.
// NOTE: Removed mutex for g_varAccess.
// may have to re-thread safe this.
static Stream* sg_pStream = NULL;
//-------------------------------------- Replacement I/O for standard LIBPng
// functions. we don't wanna use
// FILE*'s...
static void pngReadDataFn(png_structp /*png_ptr*/,
png_bytep data,
png_size_t length)
{
AssertFatal(sg_pStream != NULL, "No stream?");
bool success = sg_pStream->read(length, data);
AssertFatal(success, "Png Read catastrofic error!");
}
//--------------------------------------
static void pngWriteDataFn(png_structp /*png_ptr*/,
png_bytep data,
png_size_t length)
{
AssertFatal(sg_pStream != NULL, "No stream?");
sg_pStream->write(length, data);
}
//--------------------------------------
static void pngFlushDataFn(png_structp /*png_ptr*/)
{
//
}
static png_voidp pngMallocFn(png_structp /*png_ptr*/, png_size_t size)
{
return FrameAllocator::alloc(size);
// return (png_voidp)dMalloc(size);
}
static void pngFreeFn(png_structp /*png_ptr*/, png_voidp /*mem*/)
{
// dFree(mem);
}
//--------------------------------------
static void pngFatalErrorFn(png_structp /*png_ptr*/,
png_const_charp pMessage)
{
AssertISV(false, avar("Error reading PNG file:\n %s", pMessage));
}
//--------------------------------------
static void pngWarningFn(png_structp, png_const_charp /*pMessage*/)
{
// AssertWarn(false, avar("Warning reading PNG file:\n %s", pMessage));
}
//--------------------------------------
bool GBitmap::readPNG(Stream& io_rStream)
{
static const U32 cs_headerBytesChecked = 8;
U8 header[cs_headerBytesChecked];
io_rStream.read(cs_headerBytesChecked, header);
bool isPng = png_check_sig(header, cs_headerBytesChecked) != 0;
if (isPng == false) {
AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG");
return false;
}
U32 prevWaterMark = FrameAllocator::getWaterMark();
png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
NULL,
pngFatalErrorFn,
pngWarningFn,
NULL,
pngMallocFn,
pngFreeFn);
if (png_ptr == NULL) {
FrameAllocator::setWaterMark(prevWaterMark);
return false;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr,
(png_infopp)NULL,
(png_infopp)NULL);
FrameAllocator::setWaterMark(prevWaterMark);
return false;
}
png_infop end_info = png_create_info_struct(png_ptr);
if (end_info == NULL) {
png_destroy_read_struct(&png_ptr,
&info_ptr,
(png_infopp)NULL);
FrameAllocator::setWaterMark(prevWaterMark);
return false;
}
sg_pStream = &io_rStream;
png_set_read_fn(png_ptr, NULL, pngReadDataFn);
// Read off the info on the image.
png_set_sig_bytes(png_ptr, cs_headerBytesChecked);
png_read_info(png_ptr, info_ptr);
// OK, at this point, if we have reached it ok, then we can reset the
// image to accept the new data...
//
deleteImage();
png_uint_32 width;
png_uint_32 height;
S32 bit_depth;
S32 color_type;
png_get_IHDR(png_ptr, info_ptr,
&width, &height, // obv.
&bit_depth, &color_type, // obv.
NULL, // interlace
NULL, // compression_type
NULL); // filter_type
// First, handle the color transformations. We need this to read in the
// data as RGB or RGBA, _always_, with a maximal channel width of 8 bits.
//
bool transAlpha = false;
BitmapFormat format = RGB;
// Strip off any 16 bit info
//
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
// Expand a transparency channel into a full alpha channel...
//
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_expand(png_ptr);
transAlpha = true;
}
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_expand(png_ptr);
format = transAlpha ? RGBA : RGB;
} else if (color_type == PNG_COLOR_TYPE_GRAY) {
png_set_expand(png_ptr);
//png_set_gray_to_rgb(png_ptr);
format = Alpha; //transAlpha ? RGBA : RGB;
} else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_set_expand(png_ptr);
png_set_gray_to_rgb(png_ptr);
format = RGBA;
} else if (color_type == PNG_COLOR_TYPE_RGB) {
format = transAlpha ? RGBA : RGB;
png_set_expand(png_ptr);
} else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
png_set_expand(png_ptr);
format = RGBA;
}
// Update the info pointer with the result of the transformations
// above...
png_read_update_info(png_ptr, info_ptr);
png_uint_32 rowBytes = png_get_rowbytes(png_ptr, info_ptr);
if (format == RGB) {
AssertFatal(rowBytes == width * 3,
"Error, our rowbytes are incorrect for this transform... (3)");
} else if (format == RGBA) {
AssertFatal(rowBytes == width * 4,
"Error, our rowbytes are incorrect for this transform... (4)");
}
// actually allocate the bitmap space...
allocateBitmap(width, height,
false, // don't extrude miplevels...
format); // use determined format...
// Set up the row pointers...
AssertISV(height <= csgMaxRowPointers, "Error, cannot load pngs taller than 1024 pixels!");
png_bytep* rowPointers = sRowPointers;
U8* pBase = (U8*)getBits();
for (U32 i = 0; i < height; i++)
rowPointers[i] = pBase + (i * rowBytes);
// And actually read the image!
png_read_image(png_ptr, rowPointers);
// We're outta here, destroy the png structs, and release the lock
// as quickly as possible...
//png_read_end(png_ptr, end_info);
png_read_end(png_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
sg_pStream = NULL;
// Ok, the image is read in, now we need to finish up the initialization,
// which means: setting up the detailing members, init'ing the palette
// key, etc...
//
// actually, all of that was handled by allocateBitmap, so we're outta here
//
FrameAllocator::setWaterMark(prevWaterMark);
return true;
}
//--------------------------------------------------------------------------
bool GBitmap::_writePNG(Stream& stream,
const U32 compressionLevel,
const U32 strategy,
const U32 filter) const
{
// ONLY RGB bitmap writing supported at this time!
AssertFatal(getFormat() == RGB || getFormat() == RGBA || getFormat() == Alpha, "GBitmap::writePNG: ONLY RGB bitmap writing supported at this time.");
if (internalFormat != RGB && internalFormat != RGBA && internalFormat != Alpha)
return (false);
#define MAX_HEIGHT 4096
if (height >= MAX_HEIGHT)
return (false);
png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
NULL,
pngFatalErrorFn,
pngWarningFn,
NULL,
pngMallocFn,
pngFreeFn);
if (png_ptr == NULL)
return (false);
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return false;
}
sg_pStream = &stream;
png_set_write_fn(png_ptr, NULL, pngWriteDataFn, pngFlushDataFn);
// Set the compression level, image filters, and compression strategy...
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
png_ptr->zlib_strategy = strategy;
png_set_compression_window_bits(png_ptr, 15);
png_set_compression_level(png_ptr, compressionLevel);
png_set_filter(png_ptr, 0, filter);
// Set the image information here. Width and height are up to 2^31,
// bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
// the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
// PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
// or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
// PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
// currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
if (getFormat() == RGB) {
png_set_IHDR(png_ptr, info_ptr,
width, height, // the width & height
8, PNG_COLOR_TYPE_RGB, // bit_depth, color_type,
NULL, // no interlace
NULL, // compression type
NULL); // filter type
}
else if (getFormat() == RGBA) {
png_set_IHDR(png_ptr, info_ptr,
width, height, // the width & height
8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
NULL, // no interlace
NULL, // compression type
NULL); // filter type
}
else if (getFormat() == Alpha) {
png_set_IHDR(png_ptr, info_ptr,
width, height, // the width & height
8, PNG_COLOR_TYPE_GRAY, // bit_depth, color_type,
NULL, // no interlace
NULL, // compression type
NULL); // filter type
}
png_write_info(png_ptr, info_ptr);
png_bytep row_pointers[MAX_HEIGHT];
for (U32 i=0; i<height; i++)
row_pointers[i] = const_cast<png_bytep>(getAddress(0, i));
png_write_image(png_ptr, row_pointers);
// Write S3TC data if present...
// Write FXT1 data if present...
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return true;
}
//--------------------------------------------------------------------------
bool GBitmap::writePNG(Stream& stream, const bool compressHard) const
{
U32 waterMark = FrameAllocator::getWaterMark();
if (compressHard == false) {
bool retVal = _writePNG(stream, 6, 0, PNG_ALL_FILTERS);
FrameAllocator::setWaterMark(waterMark);
return retVal;
} else {
U8* buffer = new U8[1 << 22]; // 4 Megs. Should be enough...
MemStream* pMemStream = new MemStream(1 << 22, buffer, false, true);
// We have to try the potentially useful compression methods here.
const U32 zStrategies[] = { Z_DEFAULT_STRATEGY,
Z_FILTERED };
const U32 pngFilters[] = { PNG_FILTER_NONE,
PNG_FILTER_SUB,
PNG_FILTER_UP,
PNG_FILTER_AVG,
PNG_FILTER_PAETH,
PNG_ALL_FILTERS };
U32 minSize = 0xFFFFFFFF;
U32 bestStrategy = 0xFFFFFFFF;
U32 bestFilter = 0xFFFFFFFF;
U32 bestCLevel = 0xFFFFFFFF;
for (U32 cl = 0; cl <=9; cl++) {
for (U32 zs = 0; zs < 2; zs++) {
for (U32 pf = 0; pf < 6; pf++) {
pMemStream->setPosition(0);
if (_writePNG(*pMemStream, cl, zStrategies[zs], pngFilters[pf]) == false)
AssertFatal(false, "Handle this error!");
if (pMemStream->getPosition() < minSize) {
minSize = pMemStream->getPosition();
bestStrategy = zs;
bestFilter = pf;
bestCLevel = cl;
}
}
}
}
AssertFatal(minSize != 0xFFFFFFFF, "Error, no best found?");
delete pMemStream;
delete [] buffer;
bool retVal = _writePNG(stream,
bestCLevel,
zStrategies[bestStrategy],
pngFilters[bestFilter]);
FrameAllocator::setWaterMark(waterMark);
return retVal;
}
}
//--------------------------------------------------------------------------
bool GBitmap::writePNGUncompressed(Stream& stream) const
{
U32 waterMark = FrameAllocator::getWaterMark();
bool retVal = _writePNG(stream, 0, 0, PNG_FILTER_NONE);
FrameAllocator::setWaterMark(waterMark);
return retVal;
}

746
dgl/dgl.cc Normal file
View file

@ -0,0 +1,746 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "math/mPoint.h"
#include "dgl/gTexManager.h"
#include "dgl/dgl.h"
#include "core/color.h"
#include "math/mPoint.h"
#include "math/mRect.h"
#include "dgl/gFont.h"
#include "console/console.h"
#include "math/mMatrix.h"
#include "sim/frameAllocator.h"
#include "platform/profiler.h"
namespace {
ColorI sg_bitmapModulation(255, 255, 255, 255);
ColorI sg_textAnchorColor(255, 255, 255, 255);
ColorI sg_stackColor(255, 255, 255, 255);
RectI sgCurrentClipRect;
} // namespace {}
//--------------------------------------------------------------------------
void dglSetBitmapModulation(const ColorF& in_rColor)
{
ColorF c = in_rColor;
c.clamp();
sg_bitmapModulation = c;
sg_textAnchorColor = sg_bitmapModulation;
}
void dglGetBitmapModulation(ColorF* color)
{
*color = sg_bitmapModulation;
}
void dglGetBitmapModulation(ColorI* color)
{
*color = sg_bitmapModulation;
}
void dglClearBitmapModulation()
{
sg_bitmapModulation.set(255, 255, 255, 255);
}
void dglSetTextAnchorColor(const ColorF& in_rColor)
{
ColorF c = in_rColor;
c.clamp();
sg_textAnchorColor = c;
}
//--------------------------------------------------------------------------
void dglDrawBitmapStretchSR(TextureObject* texture,
const RectI& dstRect,
const RectI& srcRect,
const U32 in_flip)
{
AssertFatal(texture != NULL, "GSurface::drawBitmapStretchSR: NULL Handle");
if(!dstRect.isValidRect())
return;
AssertFatal(srcRect.isValidRect() == true,
"GSurface::drawBitmapStretchSR: routines assume normal rects");
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture->texGLName);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
F32 texLeft = F32(srcRect.point.x) / F32(texture->texWidth);
F32 texRight = F32(srcRect.point.x + srcRect.extent.x) / F32(texture->texWidth);
F32 texTop = F32(srcRect.point.y) / F32(texture->texHeight);
F32 texBottom = F32(srcRect.point.y + srcRect.extent.y) / F32(texture->texHeight);
F32 screenLeft = dstRect.point.x;
F32 screenRight = dstRect.point.x + dstRect.extent.x;
F32 screenTop = dstRect.point.y;
F32 screenBottom = dstRect.point.y + dstRect.extent.y;
if(in_flip & GFlip_X)
{
F32 temp = texLeft;
texLeft = texRight;
texRight = temp;
}
if(in_flip & GFlip_Y)
{
F32 temp = texTop;
texTop = texBottom;
texBottom = temp;
}
glColor4ub(sg_bitmapModulation.red,
sg_bitmapModulation.green,
sg_bitmapModulation.blue,
sg_bitmapModulation.alpha);
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(texLeft, texBottom);
glVertex2f(screenLeft, screenBottom);
glTexCoord2f(texRight, texBottom);
glVertex2f(screenRight, screenBottom);
glTexCoord2f(texRight, texTop);
glVertex2f(screenRight, screenTop);
glTexCoord2f(texLeft, texTop);
glVertex2f(screenLeft, screenTop);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
void dglDrawBitmap(TextureObject* texture, const Point2I& in_rAt, const U32 in_flip)
{
AssertFatal(texture != NULL, "GSurface::drawBitmap: NULL Handle");
// All non-StretchSR bitmaps are transformed into StretchSR calls...
//
RectI subRegion(0, 0,
texture->bitmapWidth,
texture->bitmapHeight);
RectI stretch(in_rAt.x, in_rAt.y,
texture->bitmapWidth,
texture->bitmapHeight);
dglDrawBitmapStretchSR(texture,
stretch,
subRegion,
in_flip);
}
void dglDrawBitmapStretch(TextureObject* texture, const RectI& dstRect, const U32 in_flip)
{
AssertFatal(texture != NULL, "GSurface::drawBitmapStretch: NULL Handle");
AssertFatal(dstRect.isValidRect() == true,
"GSurface::drawBitmapStretch: routines assume normal rects");
RectI subRegion(0, 0,
texture->bitmapWidth,
texture->bitmapHeight);
dglDrawBitmapStretchSR(texture,
dstRect,
subRegion,
in_flip);
}
void dglDrawBitmapSR(TextureObject *texture, const Point2I& in_rAt, const RectI& srcRect, const U32 in_flip)
{
AssertFatal(texture != NULL, "GSurface::drawBitmapSR: NULL Handle");
AssertFatal(srcRect.isValidRect() == true,
"GSurface::drawBitmapSR: routines assume normal rects");
RectI stretch(in_rAt.x, in_rAt.y,
srcRect.len_x(),
srcRect.len_y());
dglDrawBitmapStretchSR(texture,
stretch,
srcRect,
in_flip);
}
U32 dglDrawText(GFont* font,
const Point2I& ptDraw,
const void* in_string,
const ColorI* colorTable,
const U32 maxColorIndex)
{
return dglDrawTextN(font, ptDraw, in_string, dStrlen((const char *) in_string), colorTable, maxColorIndex);
}
struct TextVertex
{
Point3F p;
Point2F t;
ColorI c;
void set(F32 x, F32 y, F32 tx, F32 ty, ColorI color)
{
p.x = x;
p.y = y;
p.z = 0;
t.x = tx;
t.y = ty;
c = color;
}
};
U32 dglDrawTextN(GFont* font,
const Point2I& ptDraw,
const void* in_string,
U32 n,
const ColorI* colorTable,
const U32 maxColorIndex)
{
// return on zero length strings
if( n < 1 )
return ptDraw.x;
PROFILE_START(DrawText);
Point2I pt;
U8 c;
const U8 *str = (const U8*)in_string;
const U8 *endStr = str + n;
pt.x = ptDraw.x;
ColorI currentColor;
S32 currentPt = 0;
U32 storedWaterMark;
TextureObject *lastTexture = NULL;
storedWaterMark = FrameAllocator::getWaterMark();
currentColor = sg_bitmapModulation;
TextVertex *vert = (TextVertex *) FrameAllocator::alloc(4 * n * sizeof(TextVertex));
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnableClientState ( GL_VERTEX_ARRAY );
glVertexPointer ( 3, GL_FLOAT, sizeof(TextVertex), &(vert[0].p) );
glEnableClientState ( GL_COLOR_ARRAY );
glColorPointer ( 4, GL_UNSIGNED_BYTE, sizeof(TextVertex), &(vert[0].c) );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(TextVertex), &(vert[0].t) );
// first build the point, color, and coord arrays
for (c = *str; str < endStr; c = *(++str))
{
// We have to do a little dance here since \t = 0x9, \n = 0xa, and \r = 0xd
if ((c >= 2 && c <= 8) ||
(c >= 11 && c <= 12) ||
(c == 14))
{
// Color code
if (colorTable)
{
static U8 remap[15] =
{
0x0,
0x0,
0x0,
0x1,
0x2,
0x3,
0x4,
0x5,
0x6,
0x0,
0x0,
0x7,
0x8,
0x0,
0x9
};
U8 remapped = remap[c];
// Ignore if the color is greater than the specified max index:
if ( remapped <= maxColorIndex )
{
const ColorI &clr = colorTable[remapped];
currentColor = sg_bitmapModulation = clr;
}
}
continue;
}
// reset color?
if ( c == 15 )
{
currentColor = sg_textAnchorColor;
sg_bitmapModulation = sg_textAnchorColor;
continue;
}
// push color:
if ( c == 16 )
{
sg_stackColor = sg_bitmapModulation;
continue;
}
// pop color:
if ( c == 17 )
{
currentColor = sg_stackColor;
sg_bitmapModulation = sg_stackColor;
continue;
}
// Tab character
if( !font->isValidChar( c ) )
{
if ( c == '\t' )
{
const GFont::CharInfo &ci = font->getCharInfo( ' ' );
pt.x += ci.xIncrement * GFont::TabWidthInSpaces;
}
continue;
}
const GFont::CharInfo &ci = font->getCharInfo(c);
TextureObject *newObj = font->getTextureHandle(ci.bitmapIndex);
if(newObj != lastTexture)
{
if(currentPt)
{
glBindTexture(GL_TEXTURE_2D, lastTexture->texGLName);
glDrawArrays( GL_QUADS, 0, currentPt );
currentPt = 0;
}
lastTexture = newObj;
}
if(ci.width != 0 && ci.height != 0)
{
pt.y = ptDraw.y + font->getBaseline() - ci.yOrigin;
pt.x += ci.xOrigin;
F32 texLeft = F32(ci.xOffset) / F32(lastTexture->texWidth);
F32 texRight = F32(ci.xOffset + ci.width) / F32(lastTexture->texWidth);
F32 texTop = F32(ci.yOffset) / F32(lastTexture->texHeight);
F32 texBottom = F32(ci.yOffset + ci.height) / F32(lastTexture->texHeight);
F32 screenLeft = pt.x;
F32 screenRight = pt.x + ci.width;
F32 screenTop = pt.y;
F32 screenBottom = pt.y + ci.height;
vert[currentPt++].set(screenLeft, screenBottom, texLeft, texBottom, currentColor);
vert[currentPt++].set(screenRight, screenBottom, texRight, texBottom, currentColor);
vert[currentPt++].set(screenRight, screenTop, texRight, texTop, currentColor);
vert[currentPt++].set(screenLeft, screenTop, texLeft, texTop, currentColor);
pt.x += ci.xIncrement - ci.xOrigin;
}
else
pt.x += ci.xIncrement;
}
/* if (gOpenGLNoDrawArraysAlpha)
{
glBegin(GL_QUADS);
for (S32 i = 0; i < rd[page].count; ++i)
{
glColor4fv((float *) &colArray[rd[page].start+i]);
glTexCoord2f(texArray[rd[page].start+i].x, texArray[rd[page].start+i].y);
glVertex2f(ptArray[rd[page].start+i].x, ptArray[rd[page].start+i].y);
}
glEnd();
}
else*/
if(currentPt)
{
glBindTexture(GL_TEXTURE_2D, lastTexture->texGLName);
glDrawArrays( GL_QUADS, 0, currentPt );
}
glDisableClientState ( GL_VERTEX_ARRAY );
glDisableClientState ( GL_COLOR_ARRAY );
glDisableClientState ( GL_TEXTURE_COORD_ARRAY );
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
// restore the FrameAllocator
FrameAllocator::setWaterMark(storedWaterMark);
AssertFatal(pt.x >= ptDraw.x, "How did this happen?");
PROFILE_END();
return pt.x - ptDraw.x;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Drawing primitives
void dglDrawLine(S32 x1, S32 y1, S32 x2, S32 y2, const ColorI &color)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glColor4ub(color.red, color.green, color.blue, color.alpha);
glBegin(GL_LINES);
glVertex2f((F32)x1 + 0.5, (F32)y1 + 0.5);
glVertex2f((F32)x2 + 0.5, (F32)y2 + 0.5);
glEnd();
}
void dglDrawLine(const Point2I &startPt, const Point2I &endPt, const ColorI &color)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glColor4ub(color.red, color.green, color.blue, color.alpha);
glBegin(GL_LINES);
glVertex2f((F32)startPt.x + 0.5, (F32)startPt.y + 0.5);
glVertex2f((F32)endPt.x + 0.5, (F32)endPt.y + 0.5);
glEnd();
}
void dglDrawRect(const Point2I &upperL, const Point2I &lowerR, const ColorI &color)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glColor4ub(color.red, color.green, color.blue, color.alpha);
glBegin(GL_LINE_LOOP);
glVertex2f((F32)upperL.x + 0.5, (F32)upperL.y + 0.5);
glVertex2f((F32)lowerR.x + 0.5, (F32)upperL.y + 0.5);
glVertex2f((F32)lowerR.x + 0.5, (F32)lowerR.y + 0.5);
glVertex2f((F32)upperL.x + 0.5, (F32)lowerR.y + 0.5);
glEnd();
}
void dglDrawRect(const RectI &rect, const ColorI &color)
{
Point2I lowerR(rect.point.x + rect.extent.x - 1, rect.point.y + rect.extent.y - 1);
dglDrawRect(rect.point, lowerR, color);
}
void dglDrawRectFill(const Point2I &upperL, const Point2I &lowerR, const ColorI &color)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glColor4ub(color.red, color.green, color.blue, color.alpha);
glRecti((F32)upperL.x, (F32)upperL.y, (F32)lowerR.x, (F32)lowerR.y);
}
void dglDrawRectFill(const RectI &rect, const ColorI &color)
{
Point2I lowerR(rect.point.x + rect.extent.x - 1, rect.point.y + rect.extent.y - 1);
dglDrawRectFill(rect.point, lowerR, color);
}
void dglDraw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle )
{
width *= 0.5;
MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );
Point3F offset( screenPoint.x, screenPoint.y, 0.0 );
Point3F points[4];
points[0] = Point3F(-width, -width, 0.0);
points[1] = Point3F(-width, width, 0.0);
points[2] = Point3F( width, width, 0.0);
points[3] = Point3F( width, -width, 0.0);
for( int i=0; i<4; i++ )
{
rotMatrix.mulP( points[i] );
points[i] += offset;
}
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.0, 0.0);
glVertex2fv(points[0]);
glTexCoord2f(0.0, 1.0);
glVertex2fv(points[1]);
glTexCoord2f(1.0, 1.0);
glVertex2fv(points[2]);
glTexCoord2f(1.0, 0.0);
glVertex2fv(points[3]);
glEnd();
}
void dglDrawBillboard( const Point3F &position, F32 width, F32 spinAngle )
{
MatrixF modelview;
dglGetModelview( &modelview );
modelview.transpose();
width *= 0.5;
Point3F points[4];
points[0] = Point3F(-width, 0.0, -width);
points[1] = Point3F(-width, 0.0, width);
points[2] = Point3F( width, 0.0, width);
points[3] = Point3F( width, 0.0, -width);
MatrixF rotMatrix( EulerF( 0.0, spinAngle, 0.0 ) );
for( int i=0; i<4; i++ )
{
rotMatrix.mulP( points[i] );
modelview.mulP( points[i] );
points[i] += position;
}
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.0, 0.0);
glVertex3fv(points[0]);
glTexCoord2f(0.0, 1.0);
glVertex3fv(points[1]);
glTexCoord2f(1.0, 1.0);
glVertex3fv(points[2]);
glTexCoord2f(1.0, 0.0);
glVertex3fv(points[3]);
glEnd();
}
void dglSetClipRect(const RectI &clipRect)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
U32 screenWidth = Platform::getWindowSize().x;
U32 screenHeight = Platform::getWindowSize().y;
glOrtho(clipRect.point.x, clipRect.point.x + clipRect.extent.x,
clipRect.extent.y, 0,
0, 1);
glTranslatef(0, -clipRect.point.y, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(clipRect.point.x, screenHeight - (clipRect.point.y + clipRect.extent.y),
clipRect.extent.x, clipRect.extent.y);
sgCurrentClipRect = clipRect;
}
const RectI& dglGetClipRect()
{
return sgCurrentClipRect;
}
bool dglPointToScreen( Point3F &point3D, Point3F &screenPoint )
{
GLdouble glMV[16];
GLdouble glPR[16];
GLint glVP[4];
glGetDoublev(GL_PROJECTION_MATRIX, glPR);
glGetDoublev(GL_MODELVIEW_MATRIX, glMV);
RectI viewport;
dglGetViewport(&viewport);
glVP[0] = viewport.point.x;
glVP[1] = viewport.point.y + viewport.extent.y;
glVP[2] = viewport.extent.x;
glVP[3] = -viewport.extent.y;
MatrixF mv;
dglGetModelview(&mv);
MatrixF pr;
dglGetProjection(&pr);
F64 x, y, z;
int result = gluProject( point3D.x, point3D.y, point3D.z, (const F64 *)&glMV, (const F64 *)&glPR, (const S32 *)&glVP, &x, &y, &z );
screenPoint.x = x;
screenPoint.y = y;
screenPoint.z = z;
return (result == GL_TRUE);
}
bool dglIsInCanonicalState()
{
bool ret = true;
// Canonical state:
// BLEND disabled
// TEXTURE_2D disabled on both texture units.
// ActiveTexture set to 0
// LIGHTING off
// winding : clockwise ?
// cullface : disabled
ret &= glIsEnabled(GL_BLEND) == GL_FALSE;
ret &= glIsEnabled(GL_CULL_FACE) == GL_FALSE;
GLint temp;
if (dglDoesSupportARBMultitexture() == true) {
glActiveTextureARB(GL_TEXTURE1_ARB);
ret &= glIsEnabled(GL_TEXTURE_2D) == GL_FALSE;
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &temp);
ret &= temp == GL_REPLACE;
glActiveTextureARB(GL_TEXTURE0_ARB);
ret &= glIsEnabled(GL_TEXTURE_2D) == GL_FALSE;
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &temp);
ret &= temp == GL_REPLACE;
glClientActiveTextureARB(GL_TEXTURE1_ARB);
ret &= glIsEnabled(GL_TEXTURE_COORD_ARRAY) == GL_FALSE;
glClientActiveTextureARB(GL_TEXTURE0_ARB);
ret &= glIsEnabled(GL_TEXTURE_COORD_ARRAY) == GL_FALSE;
} else {
ret &= glIsEnabled(GL_TEXTURE_2D) == GL_FALSE;
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &temp);
ret &= temp == GL_REPLACE;
ret &= glIsEnabled(GL_TEXTURE_COORD_ARRAY) == GL_FALSE;
}
ret &= glIsEnabled(GL_LIGHTING) == GL_FALSE;
ret &= glIsEnabled(GL_COLOR_ARRAY) == GL_FALSE;
ret &= glIsEnabled(GL_VERTEX_ARRAY) == GL_FALSE;
ret &= glIsEnabled(GL_NORMAL_ARRAY) == GL_FALSE;
if (dglDoesSupportFogCoord())
ret &= glIsEnabled(GL_FOG_COORDINATE_ARRAY_EXT) == GL_FALSE;
return ret;
}
void dglSetCanonicalState()
{
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_LIGHTING);
if (dglDoesSupportARBMultitexture() == true) {
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
} else {
glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (dglDoesSupportFogCoord())
glDisableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
}
void dglGetTransformState(S32* mvDepth,
S32* pDepth,
S32* t0Depth,
F32* t0Matrix,
S32* t1Depth,
F32* t1Matrix,
S32* vp)
{
glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, mvDepth);
glGetIntegerv(GL_PROJECTION_STACK_DEPTH, pDepth);
glGetIntegerv(GL_TEXTURE_STACK_DEPTH, t0Depth);
glGetFloatv(GL_TEXTURE_MATRIX, t0Matrix);
if (dglDoesSupportARBMultitexture())
{
glActiveTextureARB(GL_TEXTURE1_ARB);
glGetIntegerv(GL_TEXTURE_STACK_DEPTH, t1Depth);
glGetFloatv(GL_TEXTURE_MATRIX, t1Matrix);
glActiveTextureARB(GL_TEXTURE0_ARB);
}
else
{
*t1Depth = 0;
for (U32 i = 0; i < 16; i++)
t1Matrix[i] = 0;
}
RectI v;
dglGetViewport(&v);
vp[0] = v.point.x;
vp[1] = v.point.y;
vp[2] = v.extent.x;
vp[3] = v.extent.y;
}
bool dglCheckState(const S32 mvDepth, const S32 pDepth,
const S32 t0Depth, const F32* t0Matrix,
const S32 t1Depth, const F32* t1Matrix,
const S32* vp)
{
GLint md, pd;
RectI v;
glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &md);
glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &pd);
GLint t0d, t1d;
GLfloat t0m[16], t1m[16];
glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &t0d);
glGetFloatv(GL_TEXTURE_MATRIX, t0m);
if (dglDoesSupportARBMultitexture())
{
glActiveTextureARB(GL_TEXTURE1_ARB);
glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &t1d);
glGetFloatv(GL_TEXTURE_MATRIX, t1m);
glActiveTextureARB(GL_TEXTURE0_ARB);
}
else
{
t1d = 0;
for (U32 i = 0; i < 16; i++)
t1m[i] = 0;
}
dglGetViewport(&v);
return ((md == mvDepth) &&
(pd == pDepth) &&
(t0d == t0Depth) &&
(dMemcmp(t0m, t0Matrix, sizeof(F32) * 16) == 0) &&
(t1d == t1Depth) &&
(dMemcmp(t1m, t1Matrix, sizeof(F32) * 16) == 0) &&
((v.point.x == vp[0]) &&
(v.point.y == vp[1]) &&
(v.extent.x == vp[2]) &&
(v.extent.y == vp[3])));
}

120
dgl/dgl.h Normal file
View file

@ -0,0 +1,120 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _DGL_H_
#define _DGL_H_
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _PLATFORMGL_H_
#include "PlatformWin32/platformGL.h"
#endif
class TextureObject;
class GFont;
class MatrixF;
class RectI;
class ColorI;
class ColorF;
class Point2I;
class Point2F;
class Point3F;
//------------------------------------------------------------------------------
//-------------------------------------- Bitmap Drawing
//
static const U32 GFlip_None = 0;
static const U32 GFlip_X = 1 << 0;
static const U32 GFlip_Y = 1 << 1;
static const U32 GFlip_XY = GFlip_X | GFlip_Y;
void dglSetBitmapModulation(const ColorF& in_rColor);
void dglGetBitmapModulation(ColorF* color);
void dglGetBitmapModulation(ColorI* color);
void dglClearBitmapModulation();
// Note that you must call this _after_ SetBitmapModulation if the two are different
// SetBMod sets the text anchor to the modulation color
void dglSetTextAnchorColor(const ColorF&);
void dglDrawBitmap(TextureObject* texObject,
const Point2I& in_rAt,
const U32 in_flip = GFlip_None);
void dglDrawBitmapStretch(TextureObject* texObject,
const RectI& in_rStretch,
const U32 in_flip = GFlip_None);
void dglDrawBitmapSR(TextureObject* texObject,
const Point2I& in_rAt,
const RectI& in_rSubRegion,
const U32 in_flip = GFlip_None);
void dglDrawBitmapStretchSR(TextureObject* texObject,
const RectI& in_rStretch,
const RectI& in_rSubRegion,
const U32 in_flip = GFlip_None);
// Returns the number of x pixels traversed
U32 dglDrawText(GFont *font, const Point2I &ptDraw, const void *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9);
U32 dglDrawTextN(GFont *font, const Point2I &ptDraw, const void *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Drawing primitives
void dglDrawLine(S32 x1, S32 y1, S32 x2, S32 y2, const ColorI &color);
void dglDrawLine(const Point2I &startPt, const Point2I &endPt, const ColorI &color);
void dglDrawRect(const Point2I &upperL, const Point2I &lowerR, const ColorI &color);
void dglDrawRect(const RectI &rect, const ColorI &color);
void dglDrawRectFill(const Point2I &upperL, const Point2I &lowerR, const ColorI &color);
void dglDrawRectFill(const RectI &rect, const ColorI &color);
void dglDraw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle );
void dglDrawBillboard( const Point3F &position, F32 width, F32 spinAngle );
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Matrix functions
void dglLoadMatrix(const MatrixF *m);
void dglMultMatrix(const MatrixF *m);
void dglGetModelview(MatrixF *m);
void dglGetProjection(MatrixF *m);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Camera functions
F32 dglGetPixelScale();
F32 dglGetWorldToScreenScale();
F32 dglProjectRadius(F32 dist, F32 radius);
void dglSetViewport(const RectI &aViewPort);
void dglGetViewport(RectI* outViewport);
void dglSetFrustum(F64 left, F64 right, F64 bottom, F64 top, F64 nearDist, F64 farDist, bool ortho = false);
void dglGetFrustum(F64 *left, F64 *right, F64 *bottom, F64 *top, F64 *nearDist, F64 *farDist);
bool dglIsOrtho();
void dglSetClipRect(const RectI &clipRect);
const RectI& dglGetClipRect();
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Misc
bool dglPointToScreen( Point3F &point3D, Point3F &screenPoint );
//--------------------------------------------------------------------------
// Debug stuff
bool dglIsInCanonicalState();
void dglSetCanonicalState();
void dglGetTransformState(S32* mvDepth,
S32* pDepth,
S32* t0Depth,
F32* t0Matrix,
S32* t1Depth,
F32* t1Matrix,
S32* vp);
bool dglCheckState(const S32 mvDepth, const S32 pDepth,
const S32 t0Depth, const F32* t0Matrix,
const S32 t1Depth, const F32* t1Matrix,
const S32* vp);
#endif // _H_DGL

146
dgl/dglMatrix.cc Normal file
View file

@ -0,0 +1,146 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Math/mMatrix.h"
#include "dgl/dgl.h"
#include "console/console.h"
void dglLoadMatrix(const MatrixF *m)
{
//F32 mat[16];
//m->transposeTo(mat);
const_cast<MatrixF*>(m)->transpose();
glLoadMatrixf(*m);
const_cast<MatrixF*>(m)->transpose();
}
void dglMultMatrix(const MatrixF *m)
{
//F32 mat[16];
//m->transposeTo(mat);
// const F32* mp = *m;
// Con::errorf(ConsoleLogEntry::General, "Mult: %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g",
// mp[0],
// mp[1],
// mp[2],
// mp[3],
// mp[4],
// mp[5],
// mp[6],
// mp[7],
// mp[8],
// mp[9],
// mp[10],
// mp[11],
// mp[12],
// mp[13],
// mp[14],
// mp[15]);
const_cast<MatrixF*>(m)->transpose();
glMultMatrixf(*m);
const_cast<MatrixF*>(m)->transpose();
}
void dglGetModelview(MatrixF *m)
{
glGetFloatv(GL_MODELVIEW_MATRIX, *m);
m->transpose();
}
void dglGetProjection(MatrixF *m)
{
glGetFloatv(GL_PROJECTION_MATRIX, *m);
m->transpose();
}
static F64 frustLeft = 0, frustRight = 1, frustBottom, frustTop, frustNear, frustFar;
static RectI viewPort;
static F32 pixelScale;
static F32 worldToScreenScale;
static bool isOrtho;
void dglSetFrustum(F64 left, F64 right, F64 bottom, F64 top, F64 nearPlane, F64 farPlane, bool ortho)
{
// this converts from a coord system looking down the pos-y axis
// to ogl's down neg z axis.
// it's stored in OGL matrix form
static F32 darkToOGLCoord[16] = { 1, 0, 0, 0,
0, 0, -1, 0,
0, 1, 0, 0,
0, 0, 0, 1 };
frustLeft = left;
frustRight = right;
frustBottom = bottom;
frustTop = top;
frustNear = nearPlane;
frustFar = farPlane;
isOrtho = ortho;
if (ortho)
{
glOrtho(left, right, bottom, top, nearPlane, farPlane);
worldToScreenScale = viewPort.extent.x / (frustRight - frustLeft);
}
else
{
glFrustum(left, right, bottom, top, nearPlane, farPlane);
worldToScreenScale = (frustNear * viewPort.extent.x) / (frustRight - frustLeft);
}
glMultMatrixf(darkToOGLCoord);
}
void dglGetFrustum(F64 *left, F64 *right, F64 *bottom, F64 *top, F64 *nearPlane, F64 *farPlane)
{
*left = frustLeft;
*right = frustRight;
*bottom = frustBottom;
*top = frustTop;
*nearPlane = frustNear;
*farPlane = frustFar;
}
bool dglIsOrtho()
{
return isOrtho;
}
void dglSetViewport(const RectI &aViewPort)
{
viewPort = aViewPort;
U32 screenHeight = Platform::getWindowSize().y;
//glViewport(viewPort.point.x, viewPort.point.y + viewPort.extent.y,
// viewPort.extent.x, -viewPort.extent.y);
glViewport(viewPort.point.x, screenHeight - (viewPort.point.y + viewPort.extent.y),
viewPort.extent.x, viewPort.extent.y);
pixelScale = viewPort.extent.x / 640.0;
worldToScreenScale = (frustNear * viewPort.extent.x) / (frustRight - frustLeft);
}
void dglGetViewport(RectI* outViewport)
{
AssertFatal(outViewport != NULL, "Error, bad point in GetViewport");
*outViewport = viewPort;
}
F32 dglGetPixelScale()
{
return pixelScale;
}
F32 dglGetWorldToScreenScale()
{
return worldToScreenScale;
}
F32 dglProjectRadius(F32 dist, F32 radius)
{
return (radius / dist) * worldToScreenScale;
}

771
dgl/gBitmap.cc Normal file
View file

@ -0,0 +1,771 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Core/stream.h"
#include "Core/fileStream.h"
#include "dgl/gBitmap.h"
#include "dgl/gPalette.h"
#include "Core/resManager.h"
#include "Platform/platform.h"
#include "console/console.h"
const U32 GBitmap::csFileVersion = 3;
U32 GBitmap::sBitmapIdSource = 0;
GBitmap::GBitmap()
: internalFormat(RGB),
pBits(NULL),
byteSize(0),
width(0),
height(0),
numMipLevels(0),
bytesPerPixel(0),
pPalette(NULL)
{
for (U32 i = 0; i < c_maxMipLevels; i++)
mipLevelOffsets[i] = 0xffffffff;
}
GBitmap::GBitmap(const GBitmap& rCopy)
{
AssertFatal(rCopy.pPalette == NULL, "Cant copy bitmaps with palettes");
internalFormat = rCopy.internalFormat;
byteSize = rCopy.byteSize;
pBits = new U8[byteSize];
dMemcpy(pBits, rCopy.pBits, byteSize);
width = rCopy.width;
height = rCopy.height;
bytesPerPixel = rCopy.bytesPerPixel;
numMipLevels = rCopy.numMipLevels;
dMemcpy(mipLevelOffsets, rCopy.mipLevelOffsets, sizeof(mipLevelOffsets));
pPalette = NULL;
}
GBitmap::GBitmap(const U32 in_width,
const U32 in_height,
const bool in_extrudeMipLevels,
const BitmapFormat in_format)
: pBits(NULL),
byteSize(0),
pPalette(NULL)
{
for (U32 i = 0; i < c_maxMipLevels; i++)
mipLevelOffsets[i] = 0xffffffff;
allocateBitmap(in_width, in_height, in_extrudeMipLevels, in_format);
}
//--------------------------------------------------------------------------
GBitmap::~GBitmap()
{
deleteImage();
}
//--------------------------------------------------------------------------
void GBitmap::deleteImage()
{
delete [] pBits;
pBits = NULL;
byteSize = 0;
width = 0;
height = 0;
numMipLevels = 0;
delete pPalette;
pPalette = NULL;
}
//--------------------------------------------------------------------------
void GBitmap::setPalette(GPalette* in_pPalette)
{
delete pPalette;
pPalette = in_pPalette;
}
//--------------------------------------------------------------------------
void GBitmap::allocateBitmap(const U32 in_width, const U32 in_height, const bool in_extrudeMipLevels, const BitmapFormat in_format)
{
//-------------------------------------- Some debug checks...
U32 svByteSize = byteSize;
U8 *svBits = pBits;
AssertFatal(in_width != 0 && in_height != 0, "GBitmap::allocateBitmap: width or height is 0");
if (in_extrudeMipLevels == true) {
//AssertFatal(in_width <= 256 && in_height <= 256, "GBitmap::allocateBitmap: width or height is too large");
AssertFatal(isPow2(in_width) == true && isPow2(in_height) == true, "GBitmap::GBitmap: in order to extrude miplevels, bitmap w/h must be pow2");
}
internalFormat = in_format;
width = in_width;
height = in_height;
bytesPerPixel = 1;
switch (internalFormat) {
case Alpha:
case Palettized:
case Luminance:
case Intensity: bytesPerPixel = 1;
break;
case RGB: bytesPerPixel = 3;
break;
case RGBA: bytesPerPixel = 4;
break;
case RGB565:
case RGB5551: bytesPerPixel = 2;
break;
default:
AssertFatal(false, "GBitmap::GBitmap: misunderstood format specifier");
break;
}
// Set up the mip levels, if necessary...
numMipLevels = 1;
U32 allocPixels = in_width * in_height * bytesPerPixel;
mipLevelOffsets[0] = 0;
if (in_extrudeMipLevels == true) {
U32 currWidth = in_width;
U32 currHeight = in_height;
do {
mipLevelOffsets[numMipLevels] = mipLevelOffsets[numMipLevels - 1] +
(currWidth * currHeight * bytesPerPixel);
currWidth >>= 1;
currHeight >>= 1;
if (currWidth == 0) currWidth = 1;
if (currHeight == 0) currHeight = 1;
numMipLevels++;
allocPixels += currWidth * currHeight * bytesPerPixel;
} while (currWidth != 1 || currHeight != 1);
}
AssertFatal(numMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
// Set up the memory...
byteSize = allocPixels;
pBits = new U8[byteSize];
dMemset(pBits, 0xFF, byteSize);
if(svBits != NULL)
{
dMemcpy(pBits, svBits, getMin(byteSize, svByteSize));
delete[] svBits;
}
}
//--------------------------------------------------------------------------
void bitmapExtrude5551_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
{
const U16 *src = (const U16 *) srcMip;
U16 *dst = (U16 *) mip;
U32 stride = srcHeight != 1 ? srcWidth : 0;
U32 width = srcWidth >> 1;
U32 height = srcHeight >> 1;
if (width == 0) width = 1;
if (height == 0) height = 1;
if (srcWidth != 1) {
for(U32 y = 0; y < height; y++)
{
for(U32 x = 0; x < width; x++)
{
U32 a = src[0];
U32 b = src[1];
U32 c = src[stride];
U32 d = src[stride+1];
dst[x] = ((( (a >> 11) + (b >> 11) + (c >> 11) + (d >> 11)) >> 2) << 11) |
((( ((a >> 6) & 0x1f) + ((b >> 6) & 0x1f) + ((c >> 6) & 0x1f) + ((d >> 6) & 0x1F)) >> 2) << 6) |
((( ((a >> 1) & 0x1F) + ((b >> 1) & 0x1F) + ((c >> 1) & 0x1f) + ((d >> 1) & 0x1f)) >> 2) << 1);
src += 2;
}
src += stride;
dst += width;
}
} else {
for(U32 y = 0; y < height; y++)
{
U32 a = src[0];
U32 c = src[stride];
dst[y] = ((( (a >> 11) + (c >> 11)) >> 1) << 11) |
((( ((a >> 6) & 0x1f) + ((c >> 6) & 0x1f)) >> 1) << 6) |
((( ((a >> 1) & 0x1F) + ((c >> 1) & 0x1f)) >> 1) << 1);
src += 1 + stride;
}
}
}
//--------------------------------------------------------------------------
void bitmapExtrudeRGB_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
{
const U8 *src = (const U8 *) srcMip;
U8 *dst = (U8 *) mip;
U32 stride = srcHeight != 1 ? (srcWidth) * 3 : 0;
U32 width = srcWidth >> 1;
U32 height = srcHeight >> 1;
if (width == 0) width = 1;
if (height == 0) height = 1;
if (srcWidth != 1) {
for(U32 y = 0; y < height; y++)
{
for(U32 x = 0; x < width; x++)
{
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3])) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3])) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3])) >> 2;
src += 4;
}
src += stride; // skip
}
} else {
for(U32 y = 0; y < height; y++)
{
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src += 4;
src += stride; // skip
}
}
}
//--------------------------------------------------------------------------
void bitmapExtrudePaletted_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
{
const U8 *src = (const U8 *) srcMip;
U8 *dst = (U8 *) mip;
U32 stride = srcHeight != 1 ? (srcWidth) * 3 : 0;
U32 width = srcWidth >> 1;
U32 height = srcHeight >> 1;
if (width == 0) width = 1;
if (height == 0) height = 1;
dMemset(mip, 0, width * height);
// if (srcWidth != 1) {
// for(U32 y = 0; y < height; y++)
// {
// for(U32 x = 0; x < width; x++)
// {
// *dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3])) >> 2;
// src++;
// *dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3])) >> 2;
// src++;
// *dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3])) >> 2;
// src += 4;
// }
// src += stride; // skip
// }
// } else {
// for(U32 y = 0; y < height; y++)
// {
// *dst++ = (U32(*src) + U32(src[stride])) >> 1;
// src++;
// *dst++ = (U32(*src) + U32(src[stride])) >> 1;
// src++;
// *dst++ = (U32(*src) + U32(src[stride])) >> 1;
// src += 4;
// src += stride; // skip
// }
// }
}
//--------------------------------------------------------------------------
void bitmapExtrudeRGBA_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
{
const U8 *src = (const U8 *) srcMip;
U8 *dst = (U8 *) mip;
U32 stride = srcHeight != 1 ? (srcWidth) * 4 : 0;
U32 width = srcWidth >> 1;
U32 height = srcHeight >> 1;
if (width == 0) width = 1;
if (height == 0) height = 1;
if (srcWidth != 1) {
for(U32 y = 0; y < height; y++)
{
for(U32 x = 0; x < width; x++)
{
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4])) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4])) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4])) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4])) >> 2;
src += 5;
}
src += stride; // skip
}
} else {
for(U32 y = 0; y < height; y++)
{
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride])) >> 1;
src += 5;
src += stride; // skip
}
}
}
void (*bitmapExtrude5551)(const void *srcMip, void *mip, U32 height, U32 width) = bitmapExtrude5551_c;
void (*bitmapExtrudeRGB)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeRGB_c;
void (*bitmapExtrudeRGBA)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeRGBA_c;
void (*bitmapExtrudePaletted)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudePaletted_c;
//--------------------------------------------------------------------------
void GBitmap::extrudeMipLevels(bool clearBorders)
{
if(numMipLevels == 1)
allocateBitmap(getWidth(), getHeight(), true, getFormat());
// AssertFatal(getFormat() != Palettized, "Cannot calc miplevels for palettized bitmaps yet");
switch (getFormat())
{
case RGB5551:
{
for(U32 i = 1; i < numMipLevels; i++)
bitmapExtrude5551(getBits(i - 1), getWritableBits(i), getHeight(i), getWidth(i));
break;
}
case RGB:
{
for(U32 i = 1; i < numMipLevels; i++)
bitmapExtrudeRGB(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
break;
}
case RGBA:
{
for(U32 i = 1; i < numMipLevels; i++)
bitmapExtrudeRGBA(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
break;
}
case Palettized:
{
for(U32 i = 1; i < numMipLevels; i++)
bitmapExtrudePaletted(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
break;
}
}
if (clearBorders)
{
for (U32 i = 1; i<numMipLevels; i++)
{
U32 width = getWidth(i);
U32 height = getHeight(i);
if (height<3 || width<3)
// bmp is all borders at this mip level
dMemset(getWritableBits(i),0,width*height*bytesPerPixel);
else
{
width *= bytesPerPixel;
U8 * bytes = getWritableBits(i);
U8 * end = bytes + (height-1)*width - bytesPerPixel; // end = last row, 2nd column
// clear first row sans the last pixel
dMemset(bytes,0,width-bytesPerPixel);
bytes -= bytesPerPixel;
while (bytes<end)
{
// clear last pixel of row N-1 and first pixel of row N
bytes += width;
dMemset(bytes,0,bytesPerPixel*2);
}
// clear last row sans the first pixel
dMemset(bytes+2*bytesPerPixel,0,width-bytesPerPixel);
}
}
}
}
//--------------------------------------------------------------------------
void GBitmap::extrudeMipLevelsDetail()
{
AssertFatal(getFormat() == GBitmap::RGB, "Error, only handles RGB for now...");
U32 i,j;
if(numMipLevels == 1)
allocateBitmap(getWidth(), getHeight(), true, getFormat());
for (i = 1; i < numMipLevels; i++) {
bitmapExtrudeRGB(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
}
// Ok, now that we have the levels extruded, we need to move the lower miplevels
// closer to 0.5.
for (i = 1; i < numMipLevels - 1; i++) {
U8* pMipBits = (U8*)getWritableBits(i);
U32 numBytes = getWidth(i) * getHeight(i) * 3;
U32 shift = i;
U32 start = ((1 << i) - 1) * 0x80;
for (j = 0; j < numBytes; j++) {
U32 newVal = (start + pMipBits[j]) >> shift;
AssertFatal(newVal <= 255, "Error, oob");
pMipBits[j] = U8(newVal);
}
}
AssertFatal(getWidth(numMipLevels - 1) == 1 && getHeight(numMipLevels - 1) == 1,
"Error, last miplevel should be 1x1!");
((U8*)getWritableBits(numMipLevels - 1))[0] = 0x80;
((U8*)getWritableBits(numMipLevels - 1))[1] = 0x80;
((U8*)getWritableBits(numMipLevels - 1))[2] = 0x80;
}
//--------------------------------------------------------------------------
void bitmapConvertRGB_to_5551_c(U8 *src, U32 pixels)
{
U16 *dst = (U16 *)src;
for(U32 j = 0; j < pixels; j++)
{
U32 r = src[0] >> 3;
U32 g = src[1] >> 3;
U32 b = src[2] >> 3;
*dst++ = (b << 1) | (g << 6) | (r << 11) | 1;
src += 3;
}
}
void (*bitmapConvertRGB_to_5551)(U8 *src, U32 pixels) = bitmapConvertRGB_to_5551_c;
//--------------------------------------------------------------------------
bool GBitmap::setFormat(BitmapFormat fmt)
{
if (getFormat() == fmt)
return true;
// this is a nasty pointer math hack
// is there a quick way to calc pixels of a fully mipped bitmap?
U32 pixels = 0;
for (U32 i=0; i < numMipLevels; i++)
pixels += getHeight(i) * getWidth(i);
switch (getFormat())
{
case RGB:
switch (fmt)
{
case RGB5551:
bitmapConvertRGB_to_5551(pBits, pixels);
internalFormat = RGB5551;
bytesPerPixel = 2;
break;
}
break;
default:
AssertWarn(0, "GBitmap::setFormat: unable to convert bitmap to requested format.");
return false;
}
U32 offset = 0;
for (U32 j=0; j < numMipLevels; j++)
{
mipLevelOffsets[j] = offset;
offset += getHeight(j) * getWidth(j) * bytesPerPixel;
}
return true;
}
//--------------------------------------------------------------------------
bool GBitmap::getColor(const U32 x, const U32 y, ColorI& rColor) const
{
if (x >= width || y >= height)
return false;
if (internalFormat == Palettized && pPalette == NULL)
return false;
const U8* pLoc = getAddress(x, y);
switch (internalFormat) {
case Palettized:
rColor = pPalette->getColor(*pLoc);
break;
case Alpha:
case Intensity:
case Luminance:
rColor.red = *pLoc;
rColor.green = *pLoc;
rColor.blue = *pLoc;
rColor.alpha = *pLoc;
break;
case RGB:
rColor.red = pLoc[0];
rColor.green = pLoc[1];
rColor.blue = pLoc[2];
rColor.alpha = 255;
break;
case RGBA:
rColor.red = pLoc[0];
rColor.green = pLoc[1];
rColor.blue = pLoc[2];
rColor.alpha = pLoc[3];
break;
case RGB5551:
rColor.red = *((U16*)pLoc) >> 11;
rColor.green = (*((U16*)pLoc) >> 6) & 0x1f;
rColor.blue = (*((U16*)pLoc) >> 1) & 0x1f;
rColor.alpha = (*((U16*)pLoc) & 1) ? 255 : 0;
break;
default:
AssertFatal(false, "Bad internal format");
return false;
}
return true;
}
//--------------------------------------------------------------------------
bool GBitmap::setColor(const U32 x, const U32 y, ColorI& rColor)
{
if (x >= width || y >= height)
return false;
if (internalFormat == Palettized && pPalette == NULL)
return false;
U8* pLoc = getAddress(x, y);
switch (internalFormat) {
case Palettized:
rColor = pPalette->getColor(*pLoc);
break;
case Alpha:
case Intensity:
case Luminance:
*pLoc = rColor.alpha;
break;
case RGB:
pLoc[0] = rColor.red;
pLoc[1] = rColor.green;
pLoc[2] = rColor.blue;
break;
case RGBA:
pLoc[0] = rColor.red;
pLoc[1] = rColor.green;
pLoc[2] = rColor.blue;
pLoc[3] = rColor.alpha;
break;
case RGB5551:
*((U16*)pLoc) = (rColor.blue << 1) | (rColor.green << 6) | (rColor.red << 11) | ((rColor.alpha>0) ? 1 : 0);
break;
default:
AssertFatal(false, "Bad internal format");
return false;
}
return true;
}
//------------------------------------------------------------------------------
//-------------------------------------- Persistent I/O
//
bool GBitmap::read(Stream& io_rStream)
{
// Handle versioning
U32 version;
io_rStream.read(&version);
AssertFatal(version == csFileVersion, "Bitmap::read: incorrect file version");
//-------------------------------------- Read the object
U32 fmt;
io_rStream.read(&fmt);
internalFormat = BitmapFormat(fmt);
bytesPerPixel = 1;
switch (internalFormat) {
case Alpha:
case Palettized:
case Luminance:
case Intensity: bytesPerPixel = 1;
break;
case RGB: bytesPerPixel = 3;
break;
case RGBA: bytesPerPixel = 4;
break;
case RGB565:
case RGB5551: bytesPerPixel = 2;
break;
default:
AssertFatal(false, "GBitmap::GBitmap: misunderstood format specifier");
break;
}
io_rStream.read(&byteSize);
pBits = new U8[byteSize];
io_rStream.read(byteSize, pBits);
io_rStream.read(&width);
io_rStream.read(&height);
io_rStream.read(&numMipLevels);
for (U32 i = 0; i < c_maxMipLevels; i++)
io_rStream.read(&mipLevelOffsets[i]);
if (internalFormat == Palettized) {
pPalette = new GPalette;
pPalette->read(io_rStream);
}
return (io_rStream.getStatus() == Stream::Ok);
}
bool GBitmap::write(Stream& io_rStream) const
{
// Handle versioning
io_rStream.write(csFileVersion);
//-------------------------------------- Write the object
io_rStream.write(U32(internalFormat));
io_rStream.write(byteSize);
io_rStream.write(byteSize, pBits);
io_rStream.write(width);
io_rStream.write(height);
io_rStream.write(numMipLevels);
for (U32 i = 0; i < c_maxMipLevels; i++)
io_rStream.write(mipLevelOffsets[i]);
if (internalFormat == Palettized) {
AssertFatal(pPalette != NULL,
"GBitmap::write: cannot write a palettized bitmap wo/ a palette");
pPalette->write(io_rStream);
}
return (io_rStream.getStatus() == Stream::Ok);
}
//-------------------------------------- GFXBitmap
ResourceInstance* constructBitmapJPEG(Stream &stream)
{
GBitmap* bmp = new GBitmap;
if (bmp->readJPEG(stream))
return bmp;
else
{
delete bmp;
return NULL;
}
}
ResourceInstance* constructBitmapPNG(Stream &stream)
{
GBitmap* bmp = new GBitmap;
if (bmp->readPNG(stream))
return bmp;
else
{
delete bmp;
return NULL;
}
}
ResourceInstance* constructBitmapBM8(Stream &stream)
{
GBitmap* bmp = new GBitmap;
if (bmp->readBmp8(stream))
return bmp;
else
{
delete bmp;
return NULL;
}
}
ResourceInstance* constructBitmapBMP(Stream &stream)
{
GBitmap *bmp = new GBitmap;
if(bmp->readMSBmp(stream))
return bmp;
else
{
delete bmp;
return NULL;
}
}
ResourceInstance* constructBitmapGIF(Stream &stream)
{
GBitmap *bmp = new GBitmap;
if(bmp->readGIF(stream))
return bmp;
else
{
delete bmp;
return NULL;
}
}
ResourceInstance* constructBitmapDBM(Stream &stream)
{
GBitmap* bmp = new GBitmap;
if (bmp->read(stream))
return bmp;
else
{
delete bmp;
return NULL;
}
}

221
dgl/gBitmap.h Normal file
View file

@ -0,0 +1,221 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GBITMAP_H_
#define _GBITMAP_H_
//Includes
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _RESMANAGER_H_
#include "Core/resManager.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
//-------------------------------------- Forward decls.
class Stream;
class GPalette;
extern ResourceInstance* constructBitmapBM8(Stream& stream);
extern ResourceInstance* constructBitmapBMP(Stream& stream);
extern ResourceInstance* constructBitmapPNG(Stream& stream);
extern ResourceInstance* constructBitmapJPEG(Stream& stream);
extern ResourceInstance* constructBitmapGIF(Stream& stream);
extern ResourceInstance* constructBitmapDBM(Stream& stream);
//------------------------------------------------------------------------------
//-------------------------------------- GBitmap
//
class GBitmap: public ResourceInstance
{
//-------------------------------------- public enumerants and structures
public:
enum BitmapFormat { // BitmapFormat and UsageHint are
Palettized = 0, // written to the stream in write(...),
Intensity = 1, // be sure to maintain compatability
RGB = 2, // if they are changed...
RGBA = 3,
Alpha = 4,
RGB565 = 5,
RGB5551 = 6,
Luminance = 7
};
enum Constants {
c_maxMipLevels = 10
};
public:
GBitmap();
GBitmap(const GBitmap&);
GBitmap(const U32 in_width,
const U32 in_height,
const bool in_extrudeMipLevels = false,
const BitmapFormat in_format = RGB);
virtual ~GBitmap();
void allocateBitmap(const U32 in_width,
const U32 in_height,
const bool in_extrudeMipLevels = false,
const BitmapFormat in_format = RGB);
void extrudeMipLevels(bool clearBorders = false);
void extrudeMipLevelsDetail();
BitmapFormat getFormat() const;
bool setFormat(BitmapFormat fmt);
U32 getNumMipLevels() const;
U32 getWidth(const U32 in_mipLevel = 0) const;
U32 getHeight(const U32 in_mipLevel = 0) const;
U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = U32(0));
const U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = U32(0)) const;
const U8* getBits(const U32 in_mipLevel = 0) const;
U8* getWritableBits(const U32 in_mipLevel = 0);
bool getColor(const U32 x, const U32 y, ColorI& rColor) const;
bool setColor(const U32 x, const U32 y, ColorI& rColor);
// Note that on set palette, the bitmap delete's its palette.
GPalette const* getPalette() const;
void setPalette(GPalette* in_pPalette);
//-------------------------------------- Internal data/operators
static U32 sBitmapIdSource;
void deleteImage();
BitmapFormat internalFormat;
public:
U8* pBits; // Master bytes
U32 byteSize;
U32 width; // Top level w/h
U32 height;
U32 bytesPerPixel;
U32 numMipLevels;
U32 mipLevelOffsets[c_maxMipLevels];
GPalette* pPalette; // Note that this palette pointer is ALWAYS
// owned by the bitmap, and will be
// deleted on exit, or written out on a
// write.
//-------------------------------------- Input/Output interface
public:
bool readJPEG(Stream& io_rStream); // located in bitmapJpeg.cc
bool writeJPEG(Stream& io_rStream) const;
bool readPNG(Stream& io_rStream); // located in bitmapPng.cc
bool writePNG(Stream& io_rStream, const bool compressHard = false) const;
bool writePNGUncompressed(Stream& io_rStream) const;
bool readBmp8(Stream& io_rStream); // located in bitmapMS.cc
bool writeBmp8(Stream& io_rStream); // located in bitmapMS.cc
bool readMSBmp(Stream& io_rStream); // located in bitmapMS.cc
bool writeMSBmp(Stream& io_rStream) const; // located in bitmapMS.cc
bool readGIF(Stream& io_rStream); // located in bitmapGIF.cc
bool writeGIF(Stream& io_rStream) const; // located in bitmapGIF.cc
bool read(Stream& io_rStream);
bool write(Stream& io_rStream) const;
private:
bool _writePNG(Stream& stream, const U32, const U32, const U32) const;
static const U32 csFileVersion;
};
//------------------------------------------------------------------------------
//-------------------------------------- Inlines
//
inline GBitmap::BitmapFormat GBitmap::getFormat() const
{
return internalFormat;
}
inline U32 GBitmap::getNumMipLevels() const
{
return numMipLevels;
}
inline U32 GBitmap::getWidth(const U32 in_mipLevel) const
{
AssertFatal(in_mipLevel < numMipLevels,
avar("GBitmap::getWidth: mip level out of range: (%d, %d)",
in_mipLevel, numMipLevels));
U32 retVal = width >> in_mipLevel;
return (retVal != 0) ? retVal : 1;
}
inline U32 GBitmap::getHeight(const U32 in_mipLevel) const
{
AssertFatal(in_mipLevel < numMipLevels,
avar("Bitmap::getHeight: mip level out of range: (%d, %d)",
in_mipLevel, numMipLevels));
U32 retVal = height >> in_mipLevel;
return (retVal != 0) ? retVal : 1;
}
inline const GPalette* GBitmap::getPalette() const
{
AssertFatal(getFormat() == Palettized,
"Error, incorrect internal format to return a palette");
return pPalette;
}
inline const U8* GBitmap::getBits(const U32 in_mipLevel) const
{
AssertFatal(in_mipLevel < numMipLevels,
avar("GBitmap::getBits: mip level out of range: (%d, %d)",
in_mipLevel, numMipLevels));
return &pBits[mipLevelOffsets[in_mipLevel]];
}
inline U8* GBitmap::getWritableBits(const U32 in_mipLevel)
{
AssertFatal(in_mipLevel < numMipLevels,
avar("GBitmap::getWritableBits: mip level out of range: (%d, %d)",
in_mipLevel, numMipLevels));
return &pBits[mipLevelOffsets[in_mipLevel]];
}
inline U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel)
{
return (getWritableBits(mipLevel) + ((in_y * getWidth(mipLevel)) + in_x) * bytesPerPixel);
}
inline const U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel) const
{
return (getBits(mipLevel) + ((in_y * getWidth(mipLevel)) + in_x) * bytesPerPixel);
}
extern void (*bitmapExtrude5551)(const void *srcMip, void *mip, U32 height, U32 width);
extern void (*bitmapExtrudeRGB)(const void *srcMip, void *mip, U32 height, U32 width);
extern void (*bitmapConvertRGB_to_5551)(U8 *src, U32 pixels);
extern void (*bitmapExtrudePaletted)(const void *srcMip, void *mip, U32 height, U32 width);
void bitmapExtrudeRGB_c(const void *srcMip, void *mip, U32 height, U32 width);
#endif //_GBITMAP_H_

76
dgl/gChunkedTexManager.h Normal file
View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GCHUNKEDTEXMANAGER_H_
#define _GCHUNKEDTEXMANAGER_H_
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
class ChunkedTextureObject
{
public:
ChunkedTextureObject *next;
StringTableEntry texFileName;
U32 texWidthCount;
U32 texHeightCount;
U32 width;
U32 height;
TextureHandle *textureHandles;
S32 refCount;
GBitmap *bitmap;
};
class ChunkedTextureManager
{
friend class ChunkedTextureHandle;
static ChunkedTextureObject* loadTexture(const char *textureName);
static ChunkedTextureObject* registerTexture(const char *textureName, GBitmap *data, bool keep);
static void freeTexture(ChunkedTextureObject *to);
static void refresh(ChunkedTextureObject *to);
public:
static void makeZombie();
static void resurrect();
};
class ChunkedTextureHandle
{
ChunkedTextureObject *object;
void lock();
void unlock();
public:
ChunkedTextureHandle() { object = NULL; }
ChunkedTextureHandle(const ChunkedTextureHandle &th) {
object = th.object;
lock();
}
ChunkedTextureHandle(const char *textureName)
{
object = ChunkedTextureManager::loadTexture(textureName);
lock();
}
ChunkedTextureHandle(const char *textureName, GBitmap *bmp)
{
object = ChunkedTextureManager::registerTexture(textureName, bmp, true);
lock();
}
~ChunkedTextureHandle() { unlock(); }
ChunkedTextureHandle& operator=(const ChunkedTextureHandle &t) { unlock(); object = t.object; lock(); return *this; }
void refresh() { if(object) ChunkedTextureManager::refresh(object); }
operator ChunkedTextureObject*() { return object; }
const char* getName() const { return (object ? object->texFileName : NULL); }
U32 getWidth() const { return (object ? object->width : 0UL); }
U32 getHeight() const { return (object ? object->height : 0UL); }
GBitmap* getBitmap() { return (object ? object->bitmap : NULL); }
TextureHandle getSubTexture(U32 x, U32 y);
U32 getTextureCountWidth() { return (object ? object->texWidthCount : 0UL); };
U32 getTextureCountHeight(){ return (object ? object->texHeightCount : 0UL); };
};
#endif

470
dgl/gFont.cc Normal file
View file

@ -0,0 +1,470 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Core/stream.h"
#include "dgl/gFont.h"
#include "dgl/gBitmap.h"
#include "Core/fileStream.h"
#include "dgl/gTexManager.h"
S32 GFont::smSheetIdCount = 0;
ResourceInstance* constructFont(Stream& stream)
{
GFont *ret = new GFont;
if(!ret->read(stream))
{
delete ret;
return NULL;
}
return ret;
}
const U32 GFont::csm_fileVersion = 1;
Resource<GFont> GFont::create(const char *faceName, S32 size)
{
char buf[256];
dSprintf(buf, sizeof(buf), "fonts/%s_%d.gft", faceName, size);
Resource<GFont> ret = ResourceManager->load(buf);
if(bool(ret))
return ret;
GFont *resFont = createFont(faceName, size);
if (resFont == NULL) {
AssertISV(dStricmp(faceName, "Arial") != 0, "Error, The Arial Font must always be available!");
// Need to handle this case better. For now, let's just return a font that we're
// positive exists, in the correct size...
return create("Arial", size);
}
FileStream stream;
if(ResourceManager->openFileForWrite(stream, ResourceManager->getBasePath(), buf))
{
resFont->write(stream);
stream.close();
}
ResourceManager->add(buf, resFont, false);
return ResourceManager->load(buf);
}
GFont::GFont()
{
VECTOR_SET_ASSOCIATION(mCharInfoList);
for (U32 i = 0; i < 256; i++)
mRemapTable[i] = -1;
mTextureSheets = NULL;
}
GFont::~GFont()
{
delete [] mTextureSheets;
mTextureSheets = NULL;
}
void GFont::insertBitmap(U16 index, U8 *src, U32 stride, U32 width, U32 height, S32 xOrigin, S32 yOrigin, S32 xIncrement)
{
CharInfo c;
c.bitmapIndex = -1;
c.xOffset = 0;
c.yOffset = 0;
c.width = width;
c.height = height;
c.xOrigin = xOrigin;
c.yOrigin = yOrigin;
c.xIncrement = xIncrement;
c.bitmapData = new U8[c.width * c.height];
for(U32 y = 0; S32(y) < c.height; y++)
{
U32 x;
for(x = 0; x < width; x++)
c.bitmapData[y * c.width + x] = src[y * stride + x];
}
mRemapTable[index] = mCharInfoList.size();
mCharInfoList.push_back(c);
}
static S32 QSORT_CALLBACK CharInfoCompare(const void *a, const void *b)
{
S32 ha = (*((GFont::CharInfo **) a))->height;
S32 hb = (*((GFont::CharInfo **) b))->height;
return hb - ha;
}
void GFont::pack(U32 inFontHeight, U32 inBaseLine)
{
mFontHeight = inFontHeight;
mBaseLine = inBaseLine;
// pack all the bitmap data into sheets.
Vector<CharInfo *> vec;
U32 size = mCharInfoList.size();
U32 i;
for(i = 0; i < size; i++)
{
CharInfo *ch = &mCharInfoList[i];
vec.push_back(ch);
}
dQsort(vec.address(), size, sizeof(CharInfo *), CharInfoCompare);
// sorted by height
Vector<Point2I> sheetSizes;
Point2I curSheetSize(256, 256);
S32 curY = 0;
S32 curX = 0;
S32 curLnHeight = 0;
for(i = 0; i < size; i++)
{
CharInfo *ci = vec[i];
if(curX + ci->width > curSheetSize.x)
{
curY += curLnHeight;
curX = 0;
curLnHeight = 0;
}
if(curY + ci->height > curSheetSize.y)
{
sheetSizes.push_back(curSheetSize);
curX = 0;
curY = 0;
curLnHeight = 0;
}
if(ci->height > curLnHeight)
curLnHeight = ci->height;
ci->bitmapIndex = sheetSizes.size();
ci->xOffset = curX;
ci->yOffset = curY;
curX += ci->width;
}
curY += curLnHeight;
if(curY < 64)
curSheetSize.y = 64;
else if(curY < 128)
curSheetSize.y = 128;
sheetSizes.push_back(curSheetSize);
Vector<GBitmap *> bitmapArray;
mNumSheets = sheetSizes.size();
mTextureSheets = new TextureHandle[mNumSheets];
for(i = 0; i < mNumSheets; i++)
bitmapArray.push_back(new GBitmap(sheetSizes[i].x, sheetSizes[i].y, false, GBitmap::Alpha));
for(i = 0; i < size; i++)
{
CharInfo *ci = vec[i];
GBitmap *bmp = bitmapArray[ci->bitmapIndex];
S32 x, y;
for(y = 0; y < ci->height; y++)
for(x = 0; x < ci->width; x++)
*bmp->getAddress(x + ci->xOffset, y + ci->yOffset) =
ci->bitmapData[y * ci->width + x];
delete[] ci->bitmapData;
}
for(i = 0; i < mNumSheets; i++)
assignSheet(i, bitmapArray[i]);
}
TextureHandle GFont::getTextureHandle(S32 index)
{
return mTextureSheets[index];
}
void GFont::assignSheet(S32 sheetNum, GBitmap *bmp)
{
char buf[30];
dSprintf(buf, sizeof(buf), "font_%d", smSheetIdCount++);
mTextureSheets[sheetNum] = TextureHandle(buf, bmp);
}
U32 GFont::getStrWidth(const char* in_pString) const
{
AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined");
// If we ain't running debug...
if (in_pString == NULL)
return 0;
return getStrNWidth(in_pString, dStrlen(in_pString));
}
U32 GFont::getStrWidthPrecise(const char* in_pString) const
{
AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined");
// If we ain't running debug...
if (in_pString == NULL)
return 0;
return getStrNWidthPrecise(in_pString, dStrlen(in_pString));
}
//-----------------------------------------------------------------------------
U32 GFont::getStrNWidth(const char *str, U32 n) const
{
AssertFatal(str != NULL, "GFont::getStrNWidth: String is NULL");
if (str == NULL)
return(0);
U32 totWidth = 0;
const char *curChar;
const char *endStr;
for (curChar = str, endStr = str + n; curChar < endStr; curChar++)
{
if(isValidChar(*curChar))
{
const CharInfo& rChar = getCharInfo(*curChar);
totWidth += rChar.xIncrement;
}
else if (*curChar == '\t')
{
const CharInfo& rChar = getCharInfo(' ');
totWidth += rChar.xIncrement * TabWidthInSpaces;
}
}
return(totWidth);
}
U32 GFont::getStrNWidthPrecise(const char *str, U32 n) const
{
AssertFatal(str != NULL, "GFont::getStrNWidth: String is NULL");
if (str == NULL)
return(0);
U32 totWidth = 0;
const char *curChar;
const char *endStr;
for (curChar = str, endStr = str + n; curChar < endStr; curChar++)
{
if(isValidChar(*curChar))
{
const CharInfo& rChar = getCharInfo(*curChar);
totWidth += rChar.xIncrement;
}
else if (*curChar == '\t')
{
const CharInfo& rChar = getCharInfo(' ');
totWidth += rChar.xIncrement * TabWidthInSpaces;
}
}
if (n != 0) {
// Need to check the last char to see if it has some slop...
char endChar = str[n-1];
if (isValidChar(endChar)) {
const CharInfo& rChar = getCharInfo(endChar);
if (rChar.width > rChar.xIncrement)
totWidth += (rChar.width - rChar.xIncrement);
}
}
return(totWidth);
}
U32 GFont::getBreakPos(const char *string, U32 slen, U32 width, bool breakOnWhitespace)
{
U32 ret = 0;
U32 lastws = 0;
while(ret < slen)
{
char c = string[ret];
if(c == '\t')
c = ' ';
if(!isValidChar(c))
{
ret++;
continue;
}
if(c == ' ')
lastws = ret+1;
const CharInfo& rChar = getCharInfo(c);
if(rChar.width > width || rChar.xIncrement > width)
{
if(lastws && breakOnWhitespace)
return lastws;
return ret;
}
width -= rChar.xIncrement;
ret++;
}
return ret;
}
void GFont::wrapString(const char *txt, U32 lineWidth, Vector<U32> &startLineOffset, Vector<U32> &lineLen)
{
startLineOffset.clear();
lineLen.clear();
if (!txt || !txt[0] || lineWidth < getCharWidth('W')) //make sure the line width is greater then a single character
return;
U32 len = dStrlen(txt);
U32 startLine;
for (U32 i = 0; i < len;)
{
startLine = i;
startLineOffset.push_back(startLine);
// loop until the string is too large
bool needsNewLine = false;
U32 lineStrWidth = 0;
for (; i < len; i++)
{
if(isValidChar(txt[i]))
{
lineStrWidth += getCharInfo(txt[i]).xIncrement;
if ( txt[i] == '\n' || lineStrWidth > lineWidth )
{
needsNewLine = true;
break;
}
}
}
if (!needsNewLine)
{
// we are done!
lineLen.push_back(i - startLine);
return;
}
// now determine where to put the newline
// else we need to backtrack until we find a either space character
// or \\ character to break up the line.
S32 j;
for (j = i - 1; j >= startLine; j--)
{
if (dIsspace(txt[j]))
break;
}
if (j < startLine)
{
// the line consists of a single word!
// So, just break up the word
j = i - 1;
}
lineLen.push_back(j - startLine);
i = j;
// now we need to increment through any space characters at the
// beginning of the next line
for (i++; i < len; i++)
{
if (!dIsspace(txt[i]) || txt[i] == '\n')
break;
}
}
}
//------------------------------------------------------------------------------
//-------------------------------------- Persist functionality
//
static const U32 csm_fileVersion = 1;
bool GFont::read(Stream& io_rStream)
{
// Handle versioning
U32 version;
io_rStream.read(&version);
if(version != csm_fileVersion)
return false;
// Read Font Information
io_rStream.read(&mFontHeight);
io_rStream.read(&mBaseLine);
U32 size = 0;
io_rStream.read(&size);
mCharInfoList.setSize(size);
U32 i;
for(i = 0; i < size; i++)
{
CharInfo *ci = &mCharInfoList[i];
io_rStream.read(&ci->bitmapIndex);
io_rStream.read(&ci->xOffset);
io_rStream.read(&ci->yOffset);
io_rStream.read(&ci->width);
io_rStream.read(&ci->height);
io_rStream.read(&ci->xOrigin);
io_rStream.read(&ci->yOrigin);
io_rStream.read(&ci->xIncrement);
}
io_rStream.read(&mNumSheets);
mTextureSheets = new TextureHandle[mNumSheets];
for(i = 0; i < mNumSheets; i++)
{
GBitmap *bmp = new GBitmap;
if(!bmp->readPNG(io_rStream))
{
delete bmp;
return false;
}
assignSheet(i, bmp);
}
// Read character remap table
for(i = 0; i < 256; i++)
io_rStream.read(&mRemapTable[i]);
return (io_rStream.getStatus() == Stream::Ok);
}
bool
GFont::write(Stream& stream) const
{
// Handle versioning
stream.write(csm_fileVersion);
// Write Font Information
stream.write(mFontHeight);
stream.write(mBaseLine);
stream.write(U32(mCharInfoList.size()));
U32 i;
for(i = 0; i < mCharInfoList.size(); i++)
{
const CharInfo *ci = &mCharInfoList[i];
stream.write(ci->bitmapIndex);
stream.write(ci->xOffset);
stream.write(ci->yOffset);
stream.write(ci->width);
stream.write(ci->height);
stream.write(ci->xOrigin);
stream.write(ci->yOrigin);
stream.write(ci->xIncrement);
}
stream.write(mNumSheets);
for(i = 0; i < mNumSheets; i++)
mTextureSheets[i].getBitmap()->writePNG(stream);
for(i = 0; i < 256; i++)
stream.write(mRemapTable[i]);
return (stream.getStatus() == Stream::Ok);
}

156
dgl/gFont.h Normal file
View file

@ -0,0 +1,156 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GFONT_H_
#define _GFONT_H_
//Includes
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _GBITMAP_H_
#include "dgl/gBitmap.h"
#endif
#ifndef _TVECTOR_H_
#include "Core/tVector.h"
#endif
#ifndef _MRECT_H_
#include "Math/mRect.h"
#endif
#ifndef _RESMANAGER_H_
#include "Core/resManager.h"
#endif
extern ResourceInstance* constructFont(Stream& stream);
class TextureHandle;
class GFont : public ResourceInstance
{
static const U32 csm_fileVersion;
static S32 smSheetIdCount;
// Enumerations and structs available to everyone...
public:
// A justification consists of a horizontal type | a vertical type.
// Note that a justification of 0 evalutes to left/top, the default.
// The robustness of the rendering functions should be considered
// suspect for a while, especially the justified versions...
//
struct CharInfo {
S16 bitmapIndex; // Note: -1 indicates character is NOT to be
// rendered, i.e., \n, \r, etc.
U8 xOffset; // x offset into bitmap sheet
U8 yOffset; // y offset into bitmap sheet
U8 width; // width of character (pixels)
U8 height; // height of character (pixels)
S8 xOrigin;
S8 yOrigin;
S8 xIncrement;
U8 *bitmapData; // temp storage for bitmap data
};
enum Constants {
TabWidthInSpaces = 3
};
// Enumerations and structures available to derived classes
private:
U32 mNumSheets;
TextureHandle *mTextureSheets;
U32 mFontHeight; // ascent + descent of the font
U32 mBaseLine; // ascent of the font (pixels above the baseline of any character in the font)
Vector<CharInfo> mCharInfoList; // - List of character info structures, must
// be accessed through the getCharInfo(U32)
// function to account for remapping...
S16 mRemapTable[256]; // - Index remapping
S16 getActualIndex(const U8 in_charIndex) const;
void assignSheet(S32 sheetNum, GBitmap *bmp);
public:
GFont();
virtual ~GFont();
// Queries about this font
public:
TextureHandle getTextureHandle(S32 index);
U32 getCharHeight(const U8 in_charIndex) const;
U32 getCharWidth(const U8 in_charIndex) const;
U32 getCharXIncrement(const U8 in_charIndex) const;
bool isValidChar(const U8 in_charIndex) const;
const CharInfo& getCharInfo(const U8 in_charIndex) const;
// Rendering assistance functions...
public:
U32 getBreakPos(const char *string, U32 strlen, U32 width, bool breakOnWhitespace);
U32 getStrWidth(const char*) const; // Note: ignores c/r
U32 getStrNWidth(const char*, U32 n) const;
U32 getStrWidthPrecise(const char*) const; // Note: ignores c/r
U32 getStrNWidthPrecise(const char*, U32 n) const;
void wrapString(const char *string, U32 width, Vector<U32> &startLineOffset, Vector<U32> &lineLen);
bool read(Stream& io_rStream);
bool write(Stream& io_rStream) const;
U32 getHeight() { return mFontHeight; }
U32 getBaseline() { return mBaseLine; }
U32 getAscent() { return mBaseLine; }
U32 getDescent() { return mFontHeight - mBaseLine; }
void insertBitmap(U16 index, U8 *src, U32 stride, U32 width, U32 height, S32 xOrigin, S32 yOrigin, S32 xIncrement);
void pack(U32 fontHeight, U32 baseLine);
static Resource<GFont> create(const char *face, S32 size);
};
inline bool GFont::isValidChar(const U8 in_charIndex) const
{
return mRemapTable[in_charIndex] != -1;
}
inline S16 GFont::getActualIndex(const U8 in_charIndex) const
{
AssertFatal(isValidChar(in_charIndex) == true,
avar("GFont::getActualIndex: invalid character: 0x%x",
in_charIndex));
return mRemapTable[in_charIndex];
}
inline const GFont::CharInfo& GFont::getCharInfo(const U8 in_charIndex) const
{
S16 remap = getActualIndex(in_charIndex);
AssertFatal(remap != -1, "No remap info for this character");
return mCharInfoList[remap];
}
inline U32 GFont::getCharXIncrement(const U8 in_charIndex) const
{
const CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.xIncrement;
}
inline U32 GFont::getCharWidth(const U8 in_charIndex) const
{
const CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.width;
}
inline U32 GFont::getCharHeight(const U8 in_charIndex) const
{
const CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.height;
}
#endif //_GFONT_H_

148
dgl/gPalette.cc Normal file
View file

@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Core/stream.h"
#include "Core/fileStream.h"
#include "dgl/gPalette.h"
const U32 GPalette::csm_fileVersion = 1;
GPalette::GPalette()
: m_paletteType(RGB)
{
//
}
GPalette::~GPalette()
{
//
}
//-------------------------------------- Supplimentary I/O
bool
GPalette::readMSPalette(const char* in_pFileName)
{
AssertFatal(in_pFileName != NULL, "GPalette::readMSPalette: NULL FileName");
FileStream frs;
if (frs.open(in_pFileName, FileStream::Read) == false) {
return false;
} else {
bool success = readMSPalette(frs);
frs.close();
return success;
}
}
bool
GPalette::writeMSPalette(const char* in_pFileName) const
{
AssertFatal(in_pFileName != NULL, "GPalette::writeMSPalette: NULL FileName");
FileStream fws;
if (fws.open(in_pFileName, FileStream::Write) == false) {
return false;
} else {
bool success = writeMSPalette(fws);
fws.close();
return success;
}
}
bool
GPalette::readMSPalette(Stream& io_rStream)
{
AssertFatal(io_rStream.getStatus() != Stream::Closed,
"GPalette::writeMSPalette: can't write to a closed stream!");
U32 data;
U32 size;
io_rStream.read(&data);
io_rStream.read(&size);
if (data == makeFourCCTag('R', 'I', 'F', 'F')) {
io_rStream.read(&data);
io_rStream.read(&size);
}
if (data == makeFourCCTag('P', 'A', 'L', ' ')) {
io_rStream.read(&data); // get number of colors (ignored)
io_rStream.read(&data); // skip the version number.
// Read the colors...
io_rStream.read(256 * sizeof(ColorI), m_pColors);
// With MS Pals, we assume that the type is RGB, clear out all the alpha
// members so the palette keys are consistent across multiple palettes
//
for (U32 i = 0; i < 256; i++)
m_pColors[i].alpha = 0;
m_paletteType = RGB;
return (io_rStream.getStatus() == Stream::Ok);
}
AssertWarn(false, "GPalette::readMSPalette: not a MS Palette");
return false;
}
bool
GPalette::writeMSPalette(Stream& io_rStream) const
{
AssertFatal(io_rStream.getStatus() != Stream::Closed,
"GPalette::writeMSPalette: can't write to a closed stream!");
io_rStream.write(U32(makeFourCCTag('R', 'I', 'F', 'F')));
io_rStream.write(U32((256 * sizeof(ColorI)) + 8 + 4 + 4));
io_rStream.write(U32(makeFourCCTag('P', 'A', 'L', ' ')));
io_rStream.write(U32(makeFourCCTag('d', 'a', 't', 'a')));
io_rStream.write(U32(0x0404)); // Number of colors + 4
io_rStream.write(U16(0x300)); // version
io_rStream.write(U16(256)); // num colors...
io_rStream.write(256 * sizeof(ColorI), m_pColors);
return (io_rStream.getStatus() == Stream::Ok);
}
//------------------------------------------------------------------------------
//-------------------------------------- Persistent I/O
//
bool
GPalette::read(Stream& io_rStream)
{
// Handle versioning
U32 version;
io_rStream.read(&version);
AssertFatal(version == csm_fileVersion, "Palette::read: wrong file version...");
U32 type;
io_rStream.read(&type);
m_paletteType = PaletteType(type);
io_rStream.read(256 * sizeof(ColorI), m_pColors);
return (io_rStream.getStatus() == Stream::Ok);
}
bool
GPalette::write(Stream& io_rStream) const
{
// Handle versioning...
io_rStream.write(csm_fileVersion);
io_rStream.write(U32(m_paletteType));
io_rStream.write(256 * sizeof(ColorI), m_pColors);
return (io_rStream.getStatus() == Stream::Ok);
}

101
dgl/gPalette.h Normal file
View file

@ -0,0 +1,101 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GPALETTE_H_
#define _GPALETTE_H_
//Includes
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
//-------------------------------------- Forward decls.
class Stream;
//------------------------------------------------------------------------------
//-------------------------------------- GPalette
//
class GPalette
{
public:
enum PaletteType {
RGB,
RGBA
};
protected:
PaletteType m_paletteType;
ColorI m_pColors[256];
public:
GPalette();
virtual ~GPalette();
PaletteType getPaletteType() const;
void setPaletteType(const PaletteType pt) { m_paletteType = pt; }
const ColorI* getColors() const;
ColorI* getColors();
const ColorI& getColor(const U32 in_index) const;
ColorI& getColor(const U32 in_index);
//-------------------------------------- Supplimentary output members
public:
bool readMSPalette(Stream& io_rStream);
bool readMSPalette(const char* in_pFileName);
bool writeMSPalette(Stream& io_rStream) const;
bool writeMSPalette(const char* in_pFileName) const;
//-------------------------------------- Persistent members
public:
bool read(Stream& io_rStream);
bool write(Stream& io_rStream) const;
private:
static const U32 csm_fileVersion;
};
//------------------------------------------------------------------------------
//-------------------------------------- Inlines (Trust)
//
inline GPalette::PaletteType
GPalette::getPaletteType() const
{
return m_paletteType;
}
inline const ColorI*
GPalette::getColors() const
{
return m_pColors;
}
inline ColorI*
GPalette::getColors()
{
return m_pColors;
}
inline const ColorI&
GPalette::getColor(const U32 in_index) const
{
AssertFatal(in_index < 256, "Out of range index");
return m_pColors[in_index];
}
inline ColorI&
GPalette::getColor(const U32 in_index)
{
AssertFatal(in_index < 256, "Out of range index");
return m_pColors[in_index];
}
#endif //_GPALETTE_H_

1468
dgl/gTexManager.cc Normal file

File diff suppressed because it is too large Load diff

285
dgl/gTexManager.h Normal file
View file

@ -0,0 +1,285 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GTEXMANAGER_H_
#define _GTEXMANAGER_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
//-------------------------------------- Forward Decls.
class GBitmap;
//------------------------------------------------------------------------------
//-------------------------------------- TextureHandle
//
enum TextureHandleType
{
BitmapTexture = 0,
BitmapKeepTexture,
BitmapNoDownloadTexture,
RegisteredTexture,
MeshTexture,
TerrainTexture,
SkyTexture,
InteriorTexture,
DetailTexture,
ZeroBorderTexture
};
class TextureObject
{
public:
TextureObject *next;
TextureObject *prev;
TextureObject *hashNext;
U32 texGLName;
U32 smallTexGLName;
#ifdef GATHER_METRICS
U32 textureSpace;
#endif
StringTableEntry texFileName;
GBitmap * bitmap;
U32 texWidth;
U32 texHeight;
U32 bitmapWidth;
U32 bitmapHeight;
U32 downloadedWidth;
U32 downloadedHeight;
TextureHandleType type;
bool clamp;
bool holding;
S32 refCount;
};
typedef void (*TextureEventCallback)(const U32 eventCode, const U32 userData);
struct TextureManager
{
// additional functions for refreshing the textures, reloading larger
// mip levels, etc, will go in here, as well as delay-load functions.
friend class TextureHandle;
friend class InteriorLMManager;
friend struct TextureDictionary;
private:
static TextureObject* loadTexture(const char *textureName, TextureHandleType type, bool clampToEdge);
static TextureObject* registerTexture(const char *textureName, const GBitmap *data, bool clampToEdge);
static TextureObject* registerTexture(const char *textureName, GBitmap *data, TextureHandleType type, bool clampToEdge);
static void freeTexture(TextureObject *to);
static bool createGLName(GBitmap *pb, bool clampToEdge, U32 firstMip, TextureHandleType type, TextureObject* obj);
static void refresh(TextureObject *to);
static void refresh(TextureObject *to, GBitmap*);
static GBitmap* createMipBitmap(const GBitmap* pBitmap);
static GBitmap* createPaddedBitmap(GBitmap* pBitmap);
public:
static void create();
static void preDestroy();
static void destroy();
static void makeZombie(); // This pair of functions is a flush() equivalent. To flush
static void resurrect(); // the cache, call:
// makeZombie(); /* blah blah blah */ resurrect();
// Note that NO drawing must take place until resurrect is
// called. The manager is a stinking corpse at this point.
// The split is necessary to support changing the OpenGL
// device in the "right way". This way glDeleteTexture is
// called on the original device rather than on the new
// device, as a flush() call would necessitate.
static void flush(); // Added for convenience when you don't need to worry about
// the above problems.
static bool smIsZombie;
#ifdef GATHER_METRICS
static void dumpStats();
#endif
enum EventCodes {
BeginZombification = 0,
CacheResurrected = 1
};
static U32 registerEventCallback(TextureEventCallback, const U32 userData);
static void unregisterEventCallback(const U32 callbackKey);
private:
static void postTextureEvent(const U32);
static bool smUseSmallTextures;
public:
static const char * csmTexturePrefix;
static void setSmallTexturesActive(const bool t) { smUseSmallTextures = t; }
static bool areSmallTexturesActive() { return smUseSmallTextures; }
#ifdef GATHER_METRICS
static U32 smTextureSpaceLoaded;
static U32 smTextureCacheMisses;
static F32 getResidentFraction();
#endif
};
//------------------------------------------------------------------
//
// TextureHandle - this is how you access a bitmap, etc.
//
// Texture handles can be allocated in 2 ways - by name to be loaded
// from disk, or by name to a dynamically generated texture
//
// If you create a GBitmap and register it, the Texture manager
// owns the pointer - so if you re-register a texture with the same
// name, the texture manager will delete the second copy.
//
//------------------------------------------------------------------
class TextureHandle
{
TextureObject *object;
void lock();
void unlock();
public:
TextureHandle() { object = NULL; }
TextureHandle(const TextureHandle &th) {
object = th.object;
lock();
}
TextureHandle(const char* textureName,
TextureHandleType type=BitmapTexture,
bool clampToEdge = false) {
object = TextureManager::loadTexture(textureName, type, clampToEdge);
lock();
}
TextureHandle(const char* textureName,
const GBitmap* bmp,
bool clampToEdge = false) {
object = TextureManager::registerTexture(textureName, bmp, clampToEdge);
lock();
}
TextureHandle(const char* textureName,
GBitmap* bmp,
TextureHandleType type,
bool clampToEdge = false) {
object = TextureManager::registerTexture(textureName, bmp, type, clampToEdge);
lock();
}
~TextureHandle() { unlock(); }
TextureHandle& operator=(const TextureHandle &t) {
unlock();
object = t.object;
lock();
return *this;
}
void set(const char *textureName,
TextureHandleType type=BitmapTexture,
bool clampToEdge = false) {
TextureObject* newObject = TextureManager::loadTexture(textureName, type, clampToEdge);;
if (newObject != object)
{
unlock();
object = newObject;
lock();
}
}
void set(const char *textureName,
const GBitmap *data,
bool clampToEdge = false) {
TextureObject* newObject = TextureManager::registerTexture(textureName, data, clampToEdge);
if (newObject != object)
{
unlock();
object = newObject;
lock();
}
}
void set(const char *textureName,
GBitmap *bmp,
TextureHandleType type,
bool clampToEdge = false) {
TextureObject* newObject = TextureManager::registerTexture(textureName, bmp, type, clampToEdge);
if (newObject != object)
{
unlock();
object = newObject;
lock();
}
}
bool operator==(const TextureHandle &t) const { return t.object == object; }
bool operator!=(const TextureHandle &t) const { return t.object != object; }
void setClamp(const bool);
void refresh();
void refresh(GBitmap*);
operator TextureObject*() { return object; }
const char* getName() const { return (object ? object->texFileName : NULL); }
U32 getWidth() const { return (object ? object->bitmapWidth : 0UL); }
U32 getHeight() const { return (object ? object->bitmapHeight : 0UL); }
U32 getDownloadedWidth() const { return (object ? object->downloadedWidth : 0UL); }
U32 getDownloadedHeight() const { return (object ? object->downloadedHeight : 0UL); }
GBitmap* getBitmap() { return (object ? object->bitmap : NULL); }
U32 getGLName() const;
};
#if defined(GATHER_METRICS) && GATHER_METRICS > 1
#ifndef _PLATFORMGL_H_
#include "engine/platformWIN32/platformGL.h"
#endif
inline U32 TextureHandle::getGLName() const
{
if (!object)
return 0;
U32 useName = tex->texGLName;
if (TextureManager::areSmallTexturesActive() && object->smallTexGLName != 0)
useName = object->smallTexGLName;
if (useName != 0) {
GLboolean res;
glAreTexturesResident(1, &useName, &res);
if (res == GL_FALSE)
TextureManager::smTextureCacheMisses++;
}
return useName;
}
#else
inline U32 TextureHandle::getGLName() const
{
if (!object)
return 0;
U32 useName = object->texGLName;
if (TextureManager::areSmallTexturesActive() && object->smallTexGLName != 0)
useName = object->smallTexGLName;
return useName;
}
#endif
#endif // _GTEXMANAGER_H_

99
dgl/lensFlare.cc Normal file
View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/lensFlare.h"
#include "dgl/dgl.h"
//**************************************************************************
// Lens Flare
//**************************************************************************
//--------------------------------------------------------------------------
// Clean up
//--------------------------------------------------------------------------
LensFlare::~LensFlare()
{
for( int i=0; i<mFlareList.size(); i++ )
{
delete mFlareList[i];
}
}
//--------------------------------------------------------------------------
// Add Flare
//--------------------------------------------------------------------------
void LensFlare::addFlare( LFlare &flare )
{
LFlare *newFlare = new LFlare;
*newFlare = flare;
mFlareList.push_back( newFlare );
}
//--------------------------------------------------------------------------
// Render
//--------------------------------------------------------------------------
void LensFlare::render( const MatrixF &camTrans, const Point3F &lightPos )
{
Point3F camPos = camTrans.getPosition();
Point3F camDir;
camTrans.getRow( 1, &camDir );
Point3F camAdjust = camPos + camDir;
Point3F lensFlareLine = lightPos - ( camAdjust );
lensFlareLine.normalize();
Point3F startPoint = camAdjust - lensFlareLine;
lensFlareLine *= 2.0;
for( int i=0; i<mFlareList.size(); i++ )
{
const LFlare *flare = mFlareList[i];
Point3F flarePos = startPoint + lensFlareLine * flare->offset;
renderFlare( flarePos, *flare );
}
}
//--------------------------------------------------------------------------
// Render flare
//--------------------------------------------------------------------------
void LensFlare::renderFlare( Point3F &pos, const LFlare &flare )
{
Point3F screenPoint;
if( !dglPointToScreen( pos, screenPoint ) )
{
return;
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// set ortho mode
RectI viewport;
dglGetViewport(&viewport);
dglSetClipRect( viewport );
glColor4fv( flare.color );
glBindTexture(GL_TEXTURE_2D, flare.tex.getGLName());
dglDraw2DSquare( Point2F( screenPoint.x, screenPoint.y ), flare.size, 0 );
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}

67
dgl/lensFlare.h Normal file
View file

@ -0,0 +1,67 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _LENSFLARE_H_
#define _LENSFLARE_H_
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _MMATH_H_
#include "Math/mMath.h"
#endif
#ifndef _TVECTOR_H_
#include "Core/tVector.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
//**************************************************************************
// Lens flare data
//**************************************************************************
struct LFlare
{
ColorF color;
TextureHandle tex;
F32 size; // size in screen pixels (scaled to 640x480)
F32 offset; // offset of flare along flare line values around 0.0-1.0 are good
LFlare()
{
dMemset( this, 0, sizeof( LFlare ) );
color.set( 1.0, 1.0, 1.0, 1.0 );
}
};
//**************************************************************************
// Lens Flare
//**************************************************************************
class LensFlare
{
private:
Vector <LFlare*> mFlareList;
void renderFlare( Point3F &pos, const LFlare &flare );
public:
~LensFlare();
void addFlare( LFlare &flare );
void render( const MatrixF &camTrans, const Point3F &lightPos );
};
#endif

305
dgl/materialList.cc Normal file
View file

@ -0,0 +1,305 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Platform/platform.h"
#include "dgl/gTexManager.h"
#include "Core/resManager.h"
#include "Core/stream.h"
#include "dgl/materialList.h"
//--------------------------------------
MaterialList::MaterialList()
{
mTextureType = BitmapTexture;
mClampToEdge = false;
VECTOR_SET_ASSOCIATION(mMaterialNames);
VECTOR_SET_ASSOCIATION(mMaterials);
}
MaterialList::MaterialList(const MaterialList* pCopy)
{
VECTOR_SET_ASSOCIATION(mMaterialNames);
VECTOR_SET_ASSOCIATION(mMaterials);
mClampToEdge = pCopy->mClampToEdge;
mTextureType = pCopy->mTextureType;
mMaterialNames.setSize(pCopy->mMaterialNames.size());
U32 i;
for (i = 0; i < mMaterialNames.size(); i++) {
if (pCopy->mMaterialNames[i]) {
mMaterialNames[i] = new char[dStrlen(pCopy->mMaterialNames[i]) + 1];
dStrcpy(mMaterialNames[i], pCopy->mMaterialNames[i]);
} else {
mMaterialNames[i] = NULL;
}
}
mMaterials.setSize(pCopy->mMaterials.size());
for (i = 0; i < mMaterials.size(); i++) {
constructInPlace(&mMaterials[i]);
mMaterials[i] = pCopy->mMaterials[i];
}
}
MaterialList::MaterialList(U32 materialCount, const char **materialNames)
{
VECTOR_SET_ASSOCIATION(mMaterialNames);
VECTOR_SET_ASSOCIATION(mMaterials);
set(materialCount, materialNames);
}
//--------------------------------------
void MaterialList::set(U32 materialCount, const char **materialNames)
{
free();
mMaterials.setSize(materialCount);
mMaterialNames.setSize(materialCount);
for(U32 i = 0; i < materialCount; i++)
{
// vectors DO NOT initialize classes so manually call the constructor
constructInPlace(&mMaterials[i]);
mMaterialNames[i] = new char[dStrlen(materialNames[i]) + 1];
dStrcpy(mMaterialNames[i], materialNames[i]);
}
}
//--------------------------------------
MaterialList::~MaterialList()
{
free();
}
//--------------------------------------
void MaterialList::load(U32 index)
{
AssertFatal(index < size(), "MaterialList:: index out of range.");
if (index < size())
{
TextureHandle &handle = mMaterials[index];
if (handle.getBitmap() == NULL)
{
const char *name = mMaterialNames[index];
if (name && *name)
handle.set(name, mTextureType, mClampToEdge);
}
}
}
//--------------------------------------
bool MaterialList::load()
{
AssertFatal(mMaterials.size() == mMaterials.size(), "MaterialList::load: internal vectors out of sync.");
for(U32 i=0; i < mMaterials.size(); i++)
load(i);
return true;
}
//--------------------------------------
void MaterialList::unload()
{
AssertFatal(mMaterials.size() == mMaterials.size(), "MaterialList::unload: internal vectors out of sync.");
for(U32 i=0; i < mMaterials.size(); i++)
mMaterials[i].~TextureHandle();
}
//--------------------------------------
void MaterialList::free()
{
AssertFatal(mMaterials.size() == mMaterials.size(), "MaterialList::free: internal vectors out of sync.");
for(U32 i=0; i < mMaterials.size(); i++)
{
if(mMaterialNames[i])
delete [] mMaterialNames[i];
mMaterials[i].~TextureHandle();
}
mMaterialNames.setSize(0);
mMaterials.setSize(0);
}
//--------------------------------------
U32 MaterialList::push_back(TextureHandle textureHandle, const char * filename)
{
mMaterials.increment();
mMaterialNames.increment();
// vectors DO NOT initialize classes so manually call the constructor
constructInPlace(&mMaterials.last());
mMaterials.last() = textureHandle;
mMaterialNames.last() = new char[dStrlen(filename) + 1];
dStrcpy(mMaterialNames.last(), filename);
// return the index
return mMaterials.size()-1;
}
//--------------------------------------
U32 MaterialList::push_back(const char *filename)
{
mMaterials.increment();
mMaterialNames.increment();
// vectors DO NOT initialize classes so manually call the constructor
constructInPlace(&mMaterials.last());
mMaterialNames.last() = new char[dStrlen(filename) + 1];
dStrcpy(mMaterialNames.last(), filename);
// return the index
return mMaterials.size()-1;
}
//--------------------------------------
U32 MaterialList::push_back(const char *filename, GBitmap *bmp, TextureHandleType type, bool clampToEdge)
{
mMaterials.increment();
mMaterialNames.increment();
// vectors DO NOT initialize classes so manually call the constructor
constructInPlace(&mMaterials.last());
mMaterials.last().set(filename, bmp, type, clampToEdge);
mMaterialNames.last() = new char[dStrlen(filename) + 1];
dStrcpy(mMaterialNames.last(), filename);
// return the index
return mMaterials.size()-1;
}
//--------------------------------------
bool MaterialList::read(Stream &stream)
{
free();
// check the stream version
U8 version;
if ( stream.read(&version) && version != BINARY_FILE_VERSION)
return readText(stream,version);
// how many materials?
U32 count;
if ( !stream.read(&count) )
return false;
// pre-size the vectors for efficiency
mMaterials.reserve(count);
mMaterialNames.reserve(count);
// read in the materials
for (U32 i=0; i<count; i++)
{
char buffer[256];
stream.readString(buffer);
if( !buffer[0] )
{
AssertWarn(0, "MaterialList::read: error reading stream");
return false;
}
// add it to the list
mMaterials.increment();
mMaterialNames.increment();
// vectors DO NOT initialize classes so manually call the constructor
constructInPlace(&mMaterials.last());
mMaterialNames.last() = new char[dStrlen(buffer) + 1];
dStrcpy(mMaterialNames.last(), buffer);
}
return (stream.getStatus() == Stream::Ok);
}
//--------------------------------------
bool MaterialList::write(Stream &stream)
{
AssertFatal(mMaterials.size() == mMaterialNames.size(), "MaterialList::write: internal vectors out of sync.");
stream.write((U8)BINARY_FILE_VERSION); // version
stream.write((U32)mMaterials.size()); // material count
for(U32 i=0; i < mMaterials.size(); i++) // material names
stream.writeString(mMaterialNames[i]);
return (stream.getStatus() == Stream::Ok);
}
//--------------------------------------
bool MaterialList::readText(Stream &stream, U8 firstByte)
{
free();
if (!firstByte)
return (stream.getStatus() == Stream::Ok || stream.getStatus() == Stream::EOS);
char buf[1024];
buf[0] = firstByte;
U32 offset = 1;
for(;;)
{
stream.readLine((U8*)(buf+offset), sizeof(buf)-offset);
if(!buf[0])
break;
offset = 0;
mMaterials.increment();
mMaterialNames.increment();
// vectors DO NOT initialize classes so manually call the constructor
constructInPlace(&mMaterials.last());
mMaterialNames.last() = new char[dStrlen(buf) + 1];
dStrcpy(mMaterialNames.last(), buf);
}
return (stream.getStatus() == Stream::Ok || stream.getStatus() == Stream::EOS);
}
bool MaterialList::readText(Stream &stream)
{
U8 firstByte;
stream.read(&firstByte);
return readText(stream,firstByte);
}
//--------------------------------------
bool MaterialList::writeText(Stream &stream)
{
AssertFatal(mMaterials.size() == mMaterialNames.size(), "MaterialList::writeText: internal vectors out of sync.");
for(U32 i=0; i < mMaterials.size(); i++)
stream.writeLine((U8*)mMaterialNames[i]);
stream.writeLine((U8*)"");
return (stream.getStatus() == Stream::Ok);
}
//--------------------------------------
ResourceInstance* constructMaterialList(Stream &stream)
{
MaterialList *matList = new MaterialList;
if(matList->readText(stream))
return matList;
else
{
delete matList;
return NULL;
}
}

103
dgl/materialList.h Normal file
View file

@ -0,0 +1,103 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _MATERIALLIST_H_
#define _MATERIALLIST_H_
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _RESMANAGER_H_
#include "Core/resManager.h"
#endif
#ifndef _CONSOLE_H_
#include "console/console.h"
#endif
//--------------------------------------
class MaterialList : public ResourceInstance
{
private:
friend class TSMaterialList;
enum Constants { BINARY_FILE_VERSION = 1 };
public:
VectorPtr<char*> mMaterialNames;
Vector<TextureHandle> mMaterials;
protected:
bool mClampToEdge;
TextureHandleType mTextureType;
public:
MaterialList();
MaterialList(U32 materialCount, const char **materialNames);
~MaterialList();
// Note: this is not to be confused with MaterialList(const MaterialList&). Copying
// a material list in the middle of it's lifetime is not a good thing, so we force
// it to copy at construction time by retricting the copy syntax to
// ML* pML = new ML(&copy);
explicit MaterialList(const MaterialList*);
S32 getMaterialCount() { return mMaterials.size(); }
const char * getMaterialName(U32 index) { return mMaterialNames[index]; }
TextureHandle &getMaterial(U32 index)
{
AssertFatal(index < mMaterials.size(), "MaterialList::getMaterial: index lookup out of range.");
return mMaterials[index];
}
// material properties
void setTextureType(TextureHandleType type) { mTextureType = type; }
void setClampToEdge(bool tf) { mClampToEdge = tf; }
void set(U32 materialCount, const char **materialNames);
U32 push_back(TextureHandle textureHandle, const char *filename);
U32 push_back(const char *filename);
U32 push_back(const char *filename, GBitmap *bmp, TextureHandleType type, bool clampToEdge = false);
virtual void load(U32 index);
bool load();
bool load(TextureHandleType type, bool clampToEdge = false);
void unload();
virtual void free();
typedef Vector<TextureHandle>::iterator iterator;
typedef Vector<TextureHandle>::value_type value;
TextureHandle& front() { return mMaterials.front(); }
TextureHandle& first() { return mMaterials.first(); }
TextureHandle& last() { return mMaterials.last(); }
bool empty() { return mMaterials.empty(); }
S32 size() { return mMaterials.size(); }
iterator begin() { return mMaterials.begin(); }
iterator end() { return mMaterials.end(); }
value operator[] (S32 index) { return getMaterial(U32(index)); }
bool read(Stream &stream);
bool write(Stream &stream);
bool readText(Stream &stream, U8 firstByte);
bool readText(Stream &stream);
bool writeText(Stream &stream);
};
//--------------------------------------
inline bool MaterialList::load(TextureHandleType type, bool clampToEdge)
{
mTextureType = type;
mClampToEdge = clampToEdge;
return load();
}
extern ResourceInstance* constructMaterialList(Stream &stream);
#endif

189
dgl/materialPropertyMap.cc Normal file
View file

@ -0,0 +1,189 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/materialPropertyMap.h"
namespace {
bool cMatPropMapAddMapping(SimObject*, S32 argc, const char** argv)
{
MaterialPropertyMap* pMap = static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
if (pMap == NULL) {
Con::errorf(ConsoleLogEntry::General, "Error, cannot find the global material map object");
return false;
}
return pMap->addMapping(argc - 1, argv + 1);
}
} // namespace {}
IMPLEMENT_CONOBJECT(MaterialPropertyMap);
MaterialPropertyMap::MaterialPropertyMap()
{
VECTOR_SET_ASSOCIATION(mMapEntries);
}
MaterialPropertyMap::~MaterialPropertyMap()
{
}
const MaterialPropertyMap::MapEntry* MaterialPropertyMap::getMapEntry(StringTableEntry name) const
{
// DMMNOTE: Really slow. Shouldn't be a problem since these are one time scans
// for each object, but might want to replace this with a hash table
//
const MapEntry* ret = NULL;
for (U32 i = 0; i < mMapEntries.size(); i++) {
if (dStricmp(mMapEntries[i].name, name) == 0) {
ret = &mMapEntries[i];
break;
}
}
return ret;
}
const MaterialPropertyMap::MapEntry* MaterialPropertyMap::getMapEntryFromIndex(S32 index) const
{
const MapEntry* ret = NULL;
if(index < mMapEntries.size())
ret = &mMapEntries[index];
return ret;
}
S32 MaterialPropertyMap::getIndexFromName(StringTableEntry name) const
{
S32 ret = -1;
for (U32 i = 0; i < mMapEntries.size(); i++) {
if (dStricmp(mMapEntries[i].name, name) == 0) {
ret = i;
break;
}
}
return ret;
}
MaterialPropertyMap::MapEntry* MaterialPropertyMap::getNCMapEntry(StringTableEntry name)
{
return const_cast<MapEntry*>(getMapEntry(name));
}
bool MaterialPropertyMap::addMapping(const S32 argc, const char** argv)
{
const char* matName = StringTable->insert(argv[0]);
MapEntry* pEntry = getNCMapEntry(matName);
if (pEntry != NULL) {
Con::warnf(ConsoleLogEntry::General, "Warning, overwriting material properties for: %s", matName);
} else {
mMapEntries.increment();
pEntry = &mMapEntries.last();
pEntry->sound = -1;
pEntry->puffColor[0].set(0.0f, 0.0f, 0.0f);
pEntry->puffColor[1].set(0.0f, 0.0f, 0.0f);
}
pEntry->name = matName;
pEntry->detailMapName = NULL;
pEntry->environMapName = NULL;
pEntry->matType = Default;
pEntry->matFlags = 0;
for (U32 i = 1; S32(i) < argc; i++) {
const char* param = argv[i];
if (dStrnicmp(param, "detail:", dStrlen("detail:")) == 0) {
// Set the detail map
const char* pColon = dStrchr(param, ':');
pColon++;
while (*pColon == ' ' || *pColon == '\t')
pColon++;
pEntry->detailMapName = StringTable->insert(pColon);
}
else if (dStrnicmp(param, "environment:", dStrlen("environment:")) == 0) {
// Set the detail map
const char* pColon = dStrchr(param, ':');
pColon++;
while (*pColon == ' ' || *pColon == '\t')
pColon++;
const char* start = pColon;
while (*pColon != ' ')
pColon++;
const char* end = pColon;
pColon++;
char buffer[256];
dStrncpy(buffer, start, end - start);
buffer[end - start] = '\0';
pEntry->environMapName = StringTable->insert(buffer);
pEntry->environMapFactor = dAtof(pColon);
}
else if (dStrnicmp(param, "color:", dStrlen("color:")) == 0) {
const char* curChar = dStrchr(param, ':');
curChar++;
while (*curChar == ' ' || *curChar == '\t')
curChar++;
char buffer[5][256];
S32 index = 0;
for(S32 x = 0; x < 5; ++x, index = 0)
{
while(*curChar != ' ' && *curChar != '\0')
buffer[x][index++] = *curChar++;
buffer[x][index++] = '\0';
while(*curChar == ' ')
++curChar;
}
pEntry->puffColor[0].set(dAtof(buffer[0]), dAtof(buffer[1]), dAtof(buffer[2]), dAtof(buffer[3]));
pEntry->puffColor[1].set(dAtof(buffer[0]), dAtof(buffer[1]), dAtof(buffer[2]), dAtof(buffer[4]));
}
else if (dStrnicmp(param, "sound:", dStrlen("sound:")) == 0) {
// Set the detail map
const char* pColon = dStrchr(param, ':');
pColon++;
while (*pColon == ' ' || *pColon == '\t')
pColon++;
const char* start = pColon;
while(*pColon != ' ' && *pColon != '\0')
pColon++;
const char* end = pColon;
pColon++;
char buffer[256];
dStrncpy(buffer, start, end - start);
buffer[end - start] = '\0';
pEntry->sound = dAtoi(buffer);
}
else if (param[0] == '\0') {
// Empty statement allowed, does nothing
}
else {
Con::warnf(ConsoleLogEntry::General, "Warning, misunderstood material parameter: %s in materialEntry %s", param, matName);
}
}
return true;
}
void MaterialPropertyMap::consoleInit()
{
//-------------------------------------- Class level variables
// Con::addVariable("pref::Interior::LightUpdatePeriod", TypeS32, &smLightUpdatePeriod);
//-------------------------------------- Class level commands
Con::addCommand("addMaterialMapping", cMatPropMapAddMapping, "addMaterialMapping(\"matName\", ...)", 2, 99);
}

75
dgl/materialPropertyMap.h Normal file
View file

@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _MATERIALPROPERTYMAP_H_
#define _MATERIALPROPERTYMAP_H_
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _TVECTOR_H_
#include "Core/tVector.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
class MaterialPropertyMap : public SimObject
{
typedef SimObject Parent;
public:
enum MaterialType {
Default
};
enum MaterialFlags {
None = 0 << 0
};
struct MapEntry {
StringTableEntry name;
StringTableEntry detailMapName;
StringTableEntry environMapName;
MaterialType matType;
U32 matFlags;
float environMapFactor;
S32 sound;
ColorF puffColor[2];
};
public:
MaterialPropertyMap();
~MaterialPropertyMap();
const MapEntry* getMapEntry(StringTableEntry) const;
const MapEntry* getMapEntryFromIndex(S32 index) const;
S32 getIndexFromName(StringTableEntry name) const;
DECLARE_CONOBJECT(MaterialPropertyMap);
static void consoleInit();
// Should only be used by console functions
public:
bool addMapping(const S32, const char**);
//-------------------------------------- Internal interface
private:
MapEntry* getNCMapEntry(StringTableEntry);
//-------------------------------------- Data
private:
Vector<MapEntry> mMapEntries;
};
#endif // _H_MATERIALPROPERTYMAPPING_

147
dgl/rectClipper.cc Normal file
View file

@ -0,0 +1,147 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/rectClipper.h"
//#pragma message "Check to make sure new RectI semantics followed"
namespace {
inline void
swap(F32& in_one, F32& in_two)
{
F32 temp = in_one;
in_one = in_two;
in_two = temp;
}
}
bool
RectClipper::clipLine(const Point2I& in_rStart,
const Point2I& in_rEnd,
Point2I& out_rStart,
Point2I& out_rEnd) const
{
// Check for trivial rejection
if ((in_rStart.x < m_clipRect.point.x && in_rEnd.x < m_clipRect.point.x) ||
(in_rStart.x >= m_clipRect.point.x + m_clipRect.extent.x &&
in_rEnd.x >= m_clipRect.point.x + m_clipRect.extent.x))
return false;
if ((in_rStart.y < m_clipRect.point.y && in_rEnd.y < m_clipRect.point.y) ||
(in_rStart.y >= m_clipRect.point.y + m_clipRect.extent.y &&
in_rEnd.y >= m_clipRect.point.y + m_clipRect.extent.y))
return false;
F32 x1 = F32(in_rStart.x);
F32 y1 = F32(in_rStart.y);
F32 x2 = F32(in_rEnd.x);
F32 y2 = F32(in_rEnd.y);
// I'm using essentially what's in the Phoenix libs, Liang-Biarsky based, but
// converted to FP math for greater precision on the back end...
//
bool flipped = false;
if (x1 > x2) {
swap(x1, x2);
swap(y1, y2);
flipped = !flipped;
}
F32 dx = x2 - x1;
F32 dy = y2 - y1;
// Clip x coord
F32 t;
if (x1 < F32(m_clipRect.point.x)) {
t = (F32(m_clipRect.point.x) - x1) / F32(dx);
x1 = F32(m_clipRect.point.x);
y1 += t * dy;
dx = x2 - x1;
dy = y2 - y1;
}
if (x2 >= F32(m_clipRect.point.x + m_clipRect.extent.x))
{
t = (F32(m_clipRect.point.x + m_clipRect.extent.x - 1) - x1) / F32(dx);
x2 = F32(m_clipRect.point.x + m_clipRect.extent.x - 1);
y2 = y1 + (t * dy);
dx = x2 - x1;
dy = y2 - y1;
}
// Recheck trivial rejection condition...
if((y1 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1) &&
y2 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1)) ||
(y1 < F32(m_clipRect.point.y) && y2 < F32(m_clipRect.point.y)))
return false;
if (y1 > y2) {
swap(x1, x2);
swap(y1, y2);
flipped = !flipped;
}
if (y1 < F32(m_clipRect.point.y)) {
t = (F32(m_clipRect.point.y) - y1) / F32(dy);
y1 = F32(m_clipRect.point.y);
x1 += t * dx;
dx = x2 - x1;
dy = y2 - y1;
}
if (y2 > F32(m_clipRect.point.y + m_clipRect.extent.y - 1))
{
t = (F32(m_clipRect.point.y + m_clipRect.extent.y - 1) - y1) / F32(dy);
y2 = F32(m_clipRect.point.y + m_clipRect.extent.y - 1);
x2 = x1 + (t * dx);
}
if (flipped == true) {
out_rEnd.x = S32(x1 + 0.5f);
out_rEnd.y = S32(y1 + 0.5f);
out_rStart.x = S32(x2 + 0.5f);
out_rStart.y = S32(y2 + 0.5f);
} else {
out_rStart.x = S32(x1 + 0.5f);
out_rStart.y = S32(y1 + 0.5f);
out_rEnd.x = S32(x2 + 0.5f);
out_rEnd.y = S32(y2 + 0.5f);
}
return true;
}
bool
RectClipper::clipRect(const RectI& in_rRect,
RectI& out_rRect) const
{
AssertFatal(in_rRect.isValidRect(), "Inappropriate min/max coords for rectangle");
if (in_rRect.point.x + in_rRect.extent.x - 1 < m_clipRect.point.x ||
in_rRect.point.x > m_clipRect.point.x + m_clipRect.extent.x - 1)
return false;
if (in_rRect.point.y + in_rRect.extent.y - 1 < m_clipRect.point.y ||
in_rRect.point.y > m_clipRect.point.y + m_clipRect.extent.y - 1)
return false;
if (in_rRect.point.x < m_clipRect.point.x) out_rRect.point.x = m_clipRect.point.x;
else out_rRect.point.x = in_rRect.point.x;
if (in_rRect.point.y < m_clipRect.point.y) out_rRect.point.y = m_clipRect.point.y;
else out_rRect.point.y = in_rRect.point.y;
Point2I bottomR;
bottomR.x = getMin(in_rRect.point.x + in_rRect.extent.x - 1,
m_clipRect.point.x + m_clipRect.extent.x - 1);
bottomR.y = getMin(in_rRect.point.y + in_rRect.extent.y - 1,
m_clipRect.point.y + m_clipRect.extent.y - 1);
out_rRect.extent.x = bottomR.x - out_rRect.point.x + 1;
out_rRect.extent.x = bottomR.y - out_rRect.point.y + 1;
return true;
}

57
dgl/rectClipper.h Normal file
View file

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _RECTCLIPPER_H_
#define _RECTCLIPPER_H_
//Includes
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _MRECT_H_
#include "Math/mRect.h"
#endif
class RectClipper
{
RectI m_clipRect;
public:
RectClipper(const RectI& in_rRect);
bool clipPoint(const Point2I& in_rPoint) const;
bool clipLine(const Point2I& in_rStart,
const Point2I& in_rEnd,
Point2I& out_rStart,
Point2I& out_rEnd) const;
bool clipRect(const RectI& in_rRect,
RectI& out_rRect) const;
};
//------------------------------------------------------------------------------
//-------------------------------------- INLINES
//
inline
RectClipper::RectClipper(const RectI& in_rRect)
: m_clipRect(in_rRect)
{
//
}
inline bool
RectClipper::clipPoint(const Point2I& in_rPoint) const
{
if ((in_rPoint.x < m_clipRect.point.x) ||
(in_rPoint.y < m_clipRect.point.y) ||
(in_rPoint.x >= m_clipRect.point.x + m_clipRect.extent.x) ||
(in_rPoint.y >= m_clipRect.point.y + m_clipRect.extent.y))
return false;
return true;
}
#endif //_RECTCLIPPER_H_

165
dgl/splineUtil.cc Normal file
View file

@ -0,0 +1,165 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/splineUtil.h"
#include "PlatformWin32/platformGL.h"
namespace SplineUtil{
//------------------------------------------------------------------------------
// Draws strip of specified width along spline. Polys on strip segments are
// front-facing (billboarded)
//------------------------------------------------------------------------------
void drawSplineBeam( const Point3F& camPos, U32 numSegments,
F32 width, SplinePatch &spline, F32 uvOffset, F32 numTexRep )
{
Point3F beginPoint, endPoint;
spline.calc( 0.0, beginPoint );
spline.calc( 1.0, endPoint );
F32 approxBeamLength = (beginPoint - endPoint).len();
F32 texRepFactor = approxBeamLength * numTexRep;
glBegin(GL_TRIANGLE_STRIP);
for( int i=0; i<numSegments; i++ )
{
F32 t = ((F32)i) / ((F32)(numSegments - 1));
Point3F curPoint;
spline.calc( t, curPoint );
Point3F segmentDir;
// handle last segment case
Point3F nextPoint;
if( i == (numSegments - 1) )
{
F32 modT = ((F32)(numSegments - 1)) / ((F32)numSegments);
spline.calc( modT, nextPoint );
segmentDir = curPoint - nextPoint;
}
else
{
F32 modT = t + (1.0 / numSegments);
spline.calc( modT, nextPoint );
segmentDir = nextPoint - curPoint;
}
if( segmentDir.isZero() ) continue;
segmentDir.normalize();
Point3F dirFromCam = curPoint - camPos;
Point3F crossVec;
mCross(dirFromCam, segmentDir, &crossVec);
crossVec.normalize();
crossVec *= width * 0.5;
F32 u = uvOffset + texRepFactor * t;
glTexCoord2f( u, 0.0 );
glVertex3fv( curPoint + crossVec );
glTexCoord2f( u, 1.0 );
glVertex3fv( curPoint - crossVec );
}
glEnd();
}
//------------------------------------------------------------------------------
// Draws strip of specified width along spline. Polys on strip segments are
// front-facing (billboarded)
//------------------------------------------------------------------------------
void drawSplineBeam( SplineBeamInfo &sbi )
{
if( !sbi.camPos || !sbi.spline ) return;
Point3F beginPoint, endPoint;
sbi.spline->calc( 0.0, beginPoint );
sbi.spline->calc( 1.0, endPoint );
F32 approxBeamLength = (beginPoint - endPoint).len();
F32 texRepFactor = approxBeamLength * sbi.numTexRep;
glBegin(GL_TRIANGLE_STRIP);
for( int i=0; i<sbi.numSegments; i++ )
{
F32 t = ((F32)i) / ((F32)(sbi.numSegments - 1));
Point3F curPoint;
sbi.spline->calc( t, curPoint );
Point3F segmentDir;
// handle last segment case
Point3F nextPoint;
if( i == (sbi.numSegments - 1) )
{
F32 modT = ((F32)(sbi.numSegments - 1)) / ((F32)sbi.numSegments);
sbi.spline->calc( modT, nextPoint );
segmentDir = curPoint - nextPoint;
}
else
{
F32 modT = t + (1.0 / sbi.numSegments);
sbi.spline->calc( modT, nextPoint );
segmentDir = nextPoint - curPoint;
}
if( segmentDir.isZero() ) continue;
segmentDir.normalize();
Point3F dirFromCam = curPoint - *sbi.camPos;
Point3F crossVec;
mCross(dirFromCam, segmentDir, &crossVec);
crossVec.normalize();
crossVec *= sbi.width * 0.5;
F32 u = sbi.uvOffset + texRepFactor * t;
if( i== 0 && sbi.zeroAlphaStart )
{
glColor4f( sbi.color.red, sbi.color.green, sbi.color.blue, 0.0 );
}
else
{
glColor4fv( sbi.color );
}
glTexCoord2f( u, 0.0 );
glVertex3fv( curPoint + crossVec );
glTexCoord2f( u, 1.0 );
glVertex3fv( curPoint - crossVec );
}
glEnd();
}
} // end SplineUtil namespace

59
dgl/splineUtil.h Normal file
View file

@ -0,0 +1,59 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _SPLINEUTIL_H_
#define _SPLINEUTIL_H_
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _MPOINT_H_
#include "Math/mPoint.h"
#endif
#ifndef _MSPLINEPATCH_H_
#include "Math/mSplinePatch.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
namespace SplineUtil
{
struct SplineBeamInfo
{
Point3F * camPos;
U32 numSegments;
F32 width;
SplinePatch * spline;
F32 uvOffset;
F32 numTexRep;
ColorF color;
bool zeroAlphaStart; // first part of first segment has 0 alpha value
SplineBeamInfo()
{
dMemset( this, 0, sizeof( SplineBeamInfo ) );
numTexRep = 1.0;
}
};
//------------------------------------------------------------------------------
// Draws strip of specified width along spline. Polys on strip segments are front-facing (billboarded)
//------------------------------------------------------------------------------
void drawSplineBeam( const Point3F& camPos, U32 numSegments, F32 width,
SplinePatch &spline, F32 uvOffset = 0.0, F32 numTexRep = 1.0 );
void drawSplineBeam( SplineBeamInfo &sbi );
}
#endif

59
dgl/stripCache.cc Normal file
View file

@ -0,0 +1,59 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/stripCache.h"
#include "PlatformWin32/platformGL.h"
void StripCache::emitStrip(const U32 start, const U32 count, const ColorI& color)
{
if (count < 3) {
AssertFatal(false, "Strip count < 3");
return;
}
if (currIndex + count >= 1024)
flushCache();
// Contiguous index enforcement
if (currIndex != 0 && start != (stripIndices[currIndex - 1]+1))
flushCache();
stripStarts[currStrip] = currIndex;
stripColors[currStrip++] = color;
for (U32 i = start; i < start+count; i++)
stripIndices[currIndex++] = i;
}
void StripCache::flushCache()
{
if (currIndex == 0)
return;
// We know that (for right now) the first index is the least, and the
// last is the greatest. The commented condition in the emitStrip
// call makes sure this range is contiguous...
U32 first = stripIndices[0];
U32 last = stripIndices[currIndex-1];
stripStarts[currStrip] = currIndex;
if (dglDoesSupportCompiledVertexArray())
glLockArraysEXT(first, last - first + 1);
for (U32 i = 0; i < currStrip; i++) {
glColor4ubv(stripColors[i]);
glDrawElements(GL_TRIANGLE_STRIP, stripStarts[i+1] - stripStarts[i],
GL_UNSIGNED_INT, &stripIndices[stripStarts[i]]);
}
if (dglDoesSupportCompiledVertexArray())
glUnlockArraysEXT();
currIndex = 0;
currStrip = 0;
}

35
dgl/stripCache.h Normal file
View file

@ -0,0 +1,35 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _STRIPCACHE_H_
#define _STRIPCACHE_H_
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
class StripCache
{
U32 stripIndices[1024];
U32 stripStarts[512];
ColorI stripColors[512];
U32 currIndex;
U32 currStrip;
public:
StripCache() { currIndex = 0; currStrip = 0; }
// Cache manages locking
void emitStrip(const U32 start, const U32 end, const ColorI& color);
void flushCache();
};
#endif // _H_STRIPCACHE_