Initial commit

This commit is contained in:
Eagle517
2025-02-17 23:17:30 -06:00
commit 7cad314c94
4726 changed files with 1145203 additions and 0 deletions

50
engine/dgl/bitmapBm8.cc Executable file
View File

@ -0,0 +1,50 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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;
}

203
engine/dgl/bitmapBmp.cc Executable file
View File

@ -0,0 +1,203 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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;
}

170
engine/dgl/bitmapGif.cc Executable file
View File

@ -0,0 +1,170 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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;
}

208
engine/dgl/bitmapJpeg.cc Executable file
View File

@ -0,0 +1,208 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "core/stream.h"
#include "core/fileStream.h"
#include "core/memstream.h"
#include "dgl/gPalette.h"
#include "dgl/gBitmap.h"
#include "jpeglib.h"
U32 gJpegQuality = 90;
//-------------------------------------- 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 int jpegFlushDataFn(void *)
{
// do nothing since we can't flush the stream object
return 0;
}
//--------------------------------------
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& stream) const
{
// JPEG format has no support for transparancy so any image
// in Alpha format should be saved as a grayscale which coincides
// with how the readJPEG function will read-in a JPEG. So the
// only formats supported are RGB and Alpha, not RGBA.
AssertFatal(getFormat() == RGB || getFormat() == Alpha,
"GBitmap::writeJPEG: ONLY RGB bitmap writing supported at this time.");
if (internalFormat != RGB && internalFormat != Alpha)
return false;
// maximum image size allowed
#define MAX_HEIGHT 4096
if (height >= MAX_HEIGHT)
return false;
// Bind our own stream writing, error, and memory flush functions
// to the jpeg library interface
JFWRITE = jpegWriteDataFn;
JFFLUSH = jpegFlushDataFn;
JFERROR = jpegErrorFn;
// Allocate and initialize our jpeg compression structure and error manager
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
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
jpeg_create_compress(&cinfo); // allocates a small amount of memory
// specify the destination for the compressed data(our stream)
jpeg_stdio_dest(&cinfo);
// set the image properties
cinfo.image_width = getWidth(); // image width
cinfo.image_height = getHeight(); // image height
cinfo.input_components = bytesPerPixel; // samples per pixel(RGB:3, Alpha:1)
switch (internalFormat)
{
case Alpha: // no alpha support in JPEG format, so turn it into a grayscale
cinfo.in_color_space = JCS_GRAYSCALE;
break;
case RGB: // otherwise we are writing in RGB format
cinfo.in_color_space = JCS_RGB;
break;
}
// use default compression params(75% compression)
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, gJpegQuality, false);
// begin JPEG compression cycle
jpeg_start_compress(&cinfo, true);
// Set up the row pointers...
U32 rowBytes = cinfo.image_width * cinfo.input_components;
U8* pBase = (U8*)getBits();
for (U32 i = 0; i < height; i++)
{
// write the image data
JSAMPROW rowPointer = pBase + (i * rowBytes);
jpeg_write_scanlines(&cinfo, &rowPointer, 1);
}
// complete the compression cycle
jpeg_finish_compress(&cinfo);
// release the JPEG compression object
jpeg_destroy_compress(&cinfo);
// return success
return true;
}

456
engine/dgl/bitmapPng.cc Executable file
View File

@ -0,0 +1,456 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "core/stream.h"
#include "core/fileStream.h"
#include "core/memstream.h"
#include "dgl/gPalette.h"
#include "dgl/gBitmap.h"
#include "core/frameAllocator.h"
#define PNG_INTERNAL 1
// Ignore PNG time chunks
#define PNG_NO_READ_TIME
#define PNG_NO_WRITE_TIME
#include <time.h>
#include "png.h"
#include "zlib.h"
// 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 = 1 << GBitmap::c_maxMipLevels - 1; ///< 2^11 = 2048, 12 mip levels (see c_maxMipLievels)
static png_bytep sRowPointers[csgMaxRowPointers];
//-------------------------------------- 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 catastrophic 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();
#if defined(PNG_USER_MEM_SUPPORTED)
png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
NULL,
pngFatalErrorFn,
pngWarningFn,
NULL,
pngMallocFn,
pngFreeFn);
#else
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL,
pngFatalErrorFn,
pngWarningFn);
#endif
if (png_ptr == NULL)
{
FrameAllocator::setWaterMark(prevWaterMark);
return false;
}
// Enable optimizations if appropriate.
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
png_uint_32 mask, flags;
flags = png_get_asm_flags(png_ptr);
mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
png_set_asm_flags(png_ptr, flags | mask);
#endif
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 2048 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);
#if defined(PNG_USER_MEM_SUPPORTED)
png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
NULL,
pngFatalErrorFn,
pngWarningFn,
NULL,
pngMallocFn,
pngFreeFn);
#else
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL,
pngFatalErrorFn,
pngWarningFn);
#endif
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,
PNG_INTERLACE_NONE, // no interlace
PNG_COMPRESSION_TYPE_BASE, // compression type
PNG_FILTER_TYPE_BASE); // 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,
PNG_INTERLACE_NONE, // no interlace
PNG_COMPRESSION_TYPE_BASE, // compression type
PNG_FILTER_TYPE_BASE); // 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,
PNG_INTERLACE_NONE, // no interlace
PNG_COMPRESSION_TYPE_BASE, // compression type
PNG_FILTER_TYPE_BASE); // 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, "PNG output failed!");
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;
}

1017
engine/dgl/dgl.cc Executable file

File diff suppressed because it is too large Load Diff

280
engine/dgl/dgl.h Executable file
View File

@ -0,0 +1,280 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _DGL_H_
#define _DGL_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _PLATFORMGL_H_
#include "platform/platformGL.h"
#endif
class TextureObject;
class GFont;
class MatrixF;
class RectI;
class ColorI;
class ColorF;
class Point2I;
class Point2F;
class Point3F;
//------------------------------------------------------------------------------
//-------------------------------------- Bitmap Drawing
//
/// Enumerations used for telling the bitmap drawing how/if to flip a bitmap
/// @see dglDrawBitmap
/// @see dglDrawBitmapStretch
/// @see dglDrawBitmapSR
/// @see dglDrawBitmapStretchSR
enum GFlipConstants
{
GFlip_None = 0,
GFlip_X = BIT(0),
GFlip_Y = BIT(1),
GFlip_XY = GFlip_X | GFlip_Y
};
/// @defgroup dgl_bitmap_mod Bitmap Modulation
/// These functions control a modulation color that is used to modulate all drawn objects
/// @{
/// Sets the current color to modulate objects with, similar to glColor3fv()
/// @see dglGetBitmapModulation
/// @see dglClearBitmapModulation
void dglSetBitmapModulation(const ColorF& in_rColor);
/// Gets the current color modulation in float format [0,1]
/// @see dglSetBitmapModulation
/// @see dglClearBitmapModulation
void dglGetBitmapModulation(ColorF* color);
/// Gets the current color modulation in integer format [0,256)
/// @see dglSetBitmapModulation
/// @see dglClearBitmapModulation
void dglGetBitmapModulation(ColorI* color);
/// Sets current color modulation to white, so no modulation takes place
/// @see dglSetBitmapModulation
/// @see dglGetBitmapModulation
void dglClearBitmapModulation();
/// @}
// Note that you must call this _after_ SetBitmapModulation if the two are different
// SetBMod sets the text anchor to the modulation color
/// Sets the anchor color for text coloring, useful when mixing text colors
void dglSetTextAnchorColor(const ColorF&);
/// @defgroup dgl_bitmap_draw Bitmap Drawing Functions
/// These functions allow you to draw a bitmap.
/// Each function will draw the bitmap in a specific way regarding stretching
/// @{
/// Draws a bitmap, starting from the lower left corner, going up and right
/// @param texObject texture object to be drawn
/// @param in_rAt where to draw the texture in 2d coordinates
/// @param in_flip enumerated constant representing any flipping to be done about the x and/or y axis
void dglDrawBitmap(TextureObject* texObject,
const Point2I& in_rAt,
const U32 in_flip = GFlip_None);
/// Draws a bitmap that is stretched
/// @param texObject texture object to be drawn
/// @param in_rStretch rectangle where the texture will be drawn in 2d coordinates
/// @param in_flip enumerated constant representing any flipping to be done about the x and/or y axis
void dglDrawBitmapStretch(TextureObject* texObject,
const RectI& in_rStretch,
const U32 in_flip = GFlip_None);
/// Draws a sub region of a texture
/// @param texObject texture object to be drawn
/// @param in_rAt point where the texture is to be drawn
/// @param in_rSubRegion portion of the texture to be drawn
/// @param in_flip enumerated constant representing any flipping to be done about the x and/or y axis
void dglDrawBitmapSR(TextureObject* texObject,
const Point2I& in_rAt,
const RectI& in_rSubRegion,
const U32 in_flip = GFlip_None);
/// Draws a stretched sub region of a texture
/// @param texObject texture object to be drawn
/// @param in_rStretch rectangle where the texture object will be drawn
/// @param in_rSubRegion sub region of the texture that will be applied over the stretch region of the screen
/// @param in_flip enumerated constant representing any flipping to be done about the x and/or y axis
void dglDrawBitmapStretchSR(TextureObject* texObject,
const RectI& in_rStretch,
const RectI& in_rSubRegion,
const U32 in_flip = GFlip_None);
/// @}
/// @defgroup dgl_text Text Functions
/// These functions draw a string on the string with a given font
/// @{
/// Draws text at a location in 2d gui coordinates
/// Also supports color tags to modulate the given text
/// @returns the number of x-pixels traversed
/// @param font font to draw with, usually found in the profile
/// @param ptDraw point where to start drawing text
/// @param in_string string to be drawn
/// @param colorTable lookups for the color tags
/// @param maxColorIndex size of the colorTable
/// @param rot rotation of text
U32 dglDrawText(GFont *font, const Point2I &ptDraw, const void *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f);
/// Draws "n" number of characters from the string, in_string
/// @returns the number of x-pixels traversed
/// @see dglDrawText
U32 dglDrawTextN(GFont *font, const Point2I &ptDraw, const void *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f);
/// @}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Drawing primitives
/// @defgroup dgl_primitive Primitive Drawing
/// Easy functions for drawing lines and (un)textured rectangles in 2d or 3d space
/// @{
/// draws a line from x1,y1 to x2,y2 in the specified color
void dglDrawLine(S32 x1, S32 y1, S32 x2, S32 y2, const ColorI &color);
/// draws a line from startPt to endPt in specified color
void dglDrawLine(const Point2I &startPt, const Point2I &endPt, const ColorI &color);
/// draws a wireframe rectangle from upperL to lowerR in specified color
void dglDrawRect(const Point2I &upperL, const Point2I &lowerR, const ColorI &color);
/// draws a wireframe rectangle in "rect" in specified color
void dglDrawRect(const RectI &rect, const ColorI &color);
/// draws an UNTEXTURED filled rectangle from upperL to lowerR in specified color
void dglDrawRectFill(const Point2I &upperL, const Point2I &lowerR, const ColorI &color);
/// draws an UNTEXTURED filled rectangle in "rect" in specified color
void dglDrawRectFill(const RectI &rect, const ColorI &color);
/// draws a square, with center point "screenPoint", width of "width" on an angle of "spinAngle" in 2d
void dglDraw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle );
/// draws a square, with center point "position", width of "width" on an angle of "spinAngle" in 3d
void dglDrawBillboard( const Point3F &position, F32 width, F32 spinAngle );
/// Draws a wireframe cube around "center" with size "extent"
void dglWireCube(const Point3F &extent, const Point3F &center);
/// Draws a solid cube around "center" with size "extent"
void dglSolidCube(const Point3F &extent, const Point3F & enter);
/// @}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Matrix functions
/// @defgroup dgl_matrix Matrix Functions
/// These functions manipulate the current matrix. The current matrix could be modelivew, projection, or texture
/// @note Make sure you specify which matrix you want to manipulate with a call to glMatrixMode(enum matrix); before calling dglLoadMatrix() or dglMultMatrix()
/// @{
/// loads matrix "m" into the current matrix mode
void dglLoadMatrix(const MatrixF *m);
/// multiplies the current transformation matrix by matrix "m"
void dglMultMatrix(const MatrixF *m);
/// returns the current modelview matrix
void dglGetModelview(MatrixF *m);
/// returns the current projection matrix
void dglGetProjection(MatrixF *m);
/// @}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Camera functions
/// @defgroup dgl_camera_func Camera functions
/// @{
/// Returns the pixel scale, namely:
///
/// viewPort.extent.x / 640.0
F32 dglGetPixelScale();
/// The scale factor of a world unit to a screen unit
F32 dglGetWorldToScreenScale();
/// Returns the screen length of a line of distance "radius" that is "dist" units away from the camera that is perpendicular to the line of sight, namely:
///
/// (radius / dist) * worldToScreenScale
F32 dglProjectRadius(F32 dist, F32 radius);
/// @}
/// @defgroup dgl_view Viewing Volume Functions
/// These functions set up the view cube of the window.
/// @{
/// sets the viewport for the window
void dglSetViewport(const RectI &aViewPort);
/// gets the current viewport of the window
void dglGetViewport(RectI* outViewport);
/// Sets the viewing frustrum. This effectively creates the view volume and sets up the 6 clipping planes (near, far, left, right, top, bottom)
/// @param left This is the position of the left vertical clipping plane
/// @param right This is the position of the right vertical clipping plane
/// @param top This is the position of the top horizontal clipping plane
/// @param bottom This is the position of the bottom horizontal clipping plane
/// @param nearDist This is the distance between the eye and the near clipping plane
/// @param farDist This is the distance between the eye and the far clipping plane
/// @param ortho (optional, default is false) If left false, calling this function will create a projection viewing volume. If true, it will be orthographic
void dglSetFrustum(F64 left, F64 right, F64 bottom, F64 top, F64 nearDist, F64 farDist, bool ortho = false);
/// Returns the parameters for the current viewing frustrum
/// @see dglSetFrustrum
void dglGetFrustum(F64 *left, F64 *right, F64 *bottom, F64 *top, F64 *nearDist, F64 *farDist);
/// returns whether or not the coordinate system is orthographic (if it is not projected)
bool dglIsOrtho();
/// Sets up an orthographical viewport and clipping region. This is best used for guis
/// @param clipRect The bounds of the coordinate system
void dglSetClipRect(const RectI &clipRect);
/// Gets the last clip rect specified by a call to dglSetClipRect
/// @see dglSetClipRect
const RectI& dglGetClipRect();
/// @}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Misc
/// Projects a point on the screen in 3d space into a point on the screen
/// @returns true if the point is on the screen, false if not and screenPoint will be (0,0,0)
bool dglPointToScreen( Point3F &point3D, Point3F &screenPoint );
//--------------------------------------------------------------------------
// Debug functions
/// Checks to see if all states are "canonical"
/// @see dglSetCanonicalState
bool dglIsInCanonicalState();
/// Sets states to a "canonical" state
/// @note a "canonical" state is described as:
///
/// BLEND disabled
///
/// TEXTURE_2D disabled on both texture units.
///
/// ActiveTexture set to 0
///
/// LIGHTING off
///
/// winding : clockwise ?
///
/// cullface : disabled
void dglSetCanonicalState();
/// Gets the current state of all transformation matrices
/// @param mvDepth Number of "pushes" made to the modelview matrix without balancing "pops"
/// @param pDepth Number of "pushes" made to the projection matrix without balancing "pops"
/// @param t0Depth Number of "pushes" made to the texture 0 matrix without balancing "pops"
/// @param t0Matrix The current texture 0 matrix, should be a 4-element array
/// @param t1Depth Number of "pushes" made to the texture 1 matrix without balancing "pops"
/// @param t1Matrix The current texture 1 matrix, should be a 4-element array
/// @param vp The current viewport, should be a 4-element array
/// @see dglCheckState
void dglGetTransformState(S32* mvDepth,
S32* pDepth,
S32* t0Depth,
F32* t0Matrix,
S32* t1Depth,
F32* t1Matrix,
S32* vp);
/// Checks to see that the given information matches the current transform state
/// @see dglGetTransformState
bool dglCheckState(const S32 mvDepth, const S32 pDepth,
const S32 t0Depth, const F32* t0Matrix,
const S32 t1Depth, const F32* t1Matrix,
const S32* vp);
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// Advanced hardware functionality.
/// Number of full screen anti-aliasting samples
extern signed int gFSAASamples;
#endif // _H_DGL

144
engine/dgl/dglMatrix.cc Executable file
View File

@ -0,0 +1,144 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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;
}

939
engine/dgl/gBitmap.cc Executable file
View File

@ -0,0 +1,939 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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 "util/safeDelete.h"
#include "math/mRect.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)
{
if (rCopy.pPalette)
{
pPalette = new GPalette;
pPalette->setPaletteType(rCopy.pPalette->getPaletteType());
dMemcpy(rCopy.pPalette->getColors(), pPalette->getColors(), sizeof(ColorI)*256);
}
else
pPalette = NULL;
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));
}
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;
SAFE_DELETE(pPalette);
}
//--------------------------------------------------------------------------
void GBitmap::setPalette(GPalette* in_pPalette)
{
SAFE_DELETE(pPalette);
pPalette = in_pPalette;
}
void GBitmap::copyRect(const GBitmap *src, const RectI &srcRect, const Point2I &dstPt)
{
if(src->getFormat() != getFormat())
return;
if(srcRect.extent.x + srcRect.point.x > src->getWidth() || srcRect.extent.y + srcRect.point.y > src->getHeight())
return;
if(srcRect.extent.x + dstPt.x > getWidth() || srcRect.extent.y + dstPt.y > getHeight())
return;
for(U32 i = 0; i < srcRect.extent.y; i++)
{
dMemcpy(getAddress(dstPt.x, dstPt.y + i),
src->getAddress(srcRect.point.x, srcRect.point.y + i),
bytesPerPixel * srcRect.extent.x);
}
}
//--------------------------------------------------------------------------
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];
#if defined(TORQUE_BIG_ENDIAN)
dst[x] = ((( (a >> 10) + (b >> 10) + (c >> 10) + (d >> 10)) >> 2) << 10) |
((( ((a >> 5) & 0x1F) + ((b >> 5) & 0x1F) + ((c >> 5) & 0x1F) + ((d >> 5) & 0x1F)) >> 2) << 5) |
((( ((a >> 0) & 0x1F) + ((b >> 0) & 0x1F) + ((c >> 0) & 0x1F) + ((d >> 0) & 0x1F)) >> 2) << 0);
#else
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);
#endif
src += 2;
}
src += stride;
dst += width;
}
}
else
{
for(U32 y = 0; y < height; y++)
{
U32 a = src[0];
U32 c = src[stride];
#if defined(TORQUE_OS_MAC)
dst[y] = ((( (a >> 10) + (c >> 10)) >> 1) << 10) |
((( ((a >> 5) & 0x1F) + ((c >> 5) & 0x1f)) >> 1) << 5) |
((( ((a >> 0) & 0x1F) + ((c >> 0) & 0x1f)) >> 1) << 0);
#else
dst[y] = ((( (a >> 11) + (c >> 11)) >> 1) << 11) |
((( ((a >> 6) & 0x1f) + ((c >> 6) & 0x1f)) >> 1) << 6) |
((( ((a >> 1) & 0x1F) + ((c >> 1) & 0x1f)) >> 1) << 1);
#endif
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) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3]) + 2) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3]) + 2) >> 2;
src += 4;
}
src += stride; // skip
}
}
else
{
for(U32 y = 0; y < height; y++)
{
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 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) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
src++;
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
src += 5;
}
src += stride; // skip
}
}
else
{
for(U32 y = 0; y < height; y++)
{
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
src++;
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 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;
#if defined(TORQUE_OS_MAC)
*dst++ = (1 << 15) | (b << 10) | (g << 5) | (r << 0);
#else
*dst++ = (b << 1) | (g << 6) | (r << 11) | 1;
#endif
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::getColorBGRA(const U32 x, const U32 y, ColorI& rColor) const
{
if(!getColor(x, y, rColor))
return false;
//jk - swap red and blue...
U8 r = rColor.red;
rColor.red = rColor.blue;
rColor.blue = r;
return true;
}
bool GBitmap::setColorBGRA(const U32 x, const U32 y, ColorI& rColor)
{
//jk - copy then swap red and blue...
//jk - using a copy so the color object provided by the caller isn't swapped...
ColorI temp = rColor;
U8 r = temp.red;
temp.red = temp.blue;
temp.blue = r;
return setColor(x, y, temp);
}
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.set( *pLoc, *pLoc, *pLoc, *pLoc );
break;
case RGB:
rColor.set( pLoc[0], pLoc[1], pLoc[2], 255 );
break;
case RGBA:
rColor.set( pLoc[0], pLoc[1], pLoc[2], pLoc[3] );
break;
case RGB5551:
#if defined(TORQUE_OS_MAC)
rColor.red = (*((U16*)pLoc) >> 0) & 0x1F;
rColor.green = (*((U16*)pLoc) >> 5) & 0x1F;
rColor.blue = (*((U16*)pLoc) >> 10) & 0x1F;
rColor.alpha = ((*((U16*)pLoc) >> 15) & 0x01) ? 255 : 0;
#else
rColor.red = *((U16*)pLoc) >> 11;
rColor.green = (*((U16*)pLoc) >> 6) & 0x1f;
rColor.blue = (*((U16*)pLoc) >> 1) & 0x1f;
rColor.alpha = (*((U16*)pLoc) & 1) ? 255 : 0;
#endif
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:
dMemcpy( pLoc, &rColor, 3 * sizeof( U8 ) );
break;
case RGBA:
dMemcpy( pLoc, &rColor, 4 * sizeof( U8 ) );
break;
case RGB5551:
#if defined(TORQUE_OS_MAC)
*((U16*)pLoc) = (((rColor.alpha>0) ? 1 : 0)<<15) | (rColor.blue << 10) | (rColor.green << 5) | (rColor.red << 0);
#else
*((U16*)pLoc) = (rColor.blue << 1) | (rColor.green << 6) | (rColor.red << 11) | ((rColor.alpha>0) ? 1 : 0);
#endif
break;
default:
AssertFatal(false, "Bad internal format");
return false;
}
return true;
}
//-----------------------------------------------------------------------------
GBitmap* GBitmap::createPaddedBitmap()
{
if (isPow2(getWidth()) && isPow2(getHeight()))
return NULL;
AssertFatal(getNumMipLevels() == 1,
"Cannot have non-pow2 bitmap with miplevels");
U32 width = getWidth();
U32 height = getHeight();
U32 newWidth = getNextPow2(getWidth());
U32 newHeight = getNextPow2(getHeight());
GBitmap* pReturn = new GBitmap(newWidth, newHeight, false, getFormat());
for (U32 i = 0; i < height; i++)
{
U8* pDest = (U8*)pReturn->getAddress(0, i);
const U8* pSrc = (const U8*)getAddress(0, i);
dMemcpy(pDest, pSrc, width * bytesPerPixel);
pDest += width * bytesPerPixel;
// set the src pixel to the last pixel in the row
const U8 *pSrcPixel = pDest - bytesPerPixel;
for(U32 j = width; j < newWidth; j++)
for(U32 k = 0; k < bytesPerPixel; k++)
*pDest++ = pSrcPixel[k];
}
for(U32 i = height; i < newHeight; i++)
{
U8* pDest = (U8*)pReturn->getAddress(0, i);
U8* pSrc = (U8*)pReturn->getAddress(0, height-1);
dMemcpy(pDest, pSrc, newWidth * bytesPerPixel);
}
//if (pBitmap->getFormat() == GBitmap::Palettized)
//{
// pReturn->pPalette = new GPalette;
// dMemcpy(pReturn->pPalette->getColors(), pBitmap->pPalette->getColors(), sizeof(ColorI) * 256);
// pReturn->pPalette->setPaletteType(pBitmap->pPalette->getPaletteType());
//}
return pReturn;
}
//------------------------------------------------------------------------------
//-------------------------------------- Persistent I/O
//
#define EXT_ARRAY_SIZE 5
static const char* extArray[EXT_ARRAY_SIZE] = { "", ".jpg", ".png", ".gif", ".bmp" };
ResourceObject * GBitmap::findBmpResource(const char * path)
{
char fileNameBuffer[512];
dStrcpy( fileNameBuffer, path );
// Try some different possible filenames.
U32 len = dStrlen( fileNameBuffer );
for( U32 i = 0; i < EXT_ARRAY_SIZE; i++ )
{
dStrcpy( fileNameBuffer + len, extArray[i] );
ResourceObject * ret = ResourceManager->find( fileNameBuffer );
if (ret)
return ret;
}
return NULL;
}
GBitmap *GBitmap::load(const char *path)
{
ResourceObject * ro = findBmpResource(path);
if (ro)
{
GBitmap *bmp = (GBitmap*)ResourceManager->loadInstance(ro);
return bmp;
}
// If unable to load texture in current directory
// look in the parent directory. But never look in the root.
char fileNameBuffer[512];
dStrcpy( fileNameBuffer, path );
char *name = dStrrchr( fileNameBuffer, '/' );
if( name )
{
*name++ = 0;
char *parent = dStrrchr( fileNameBuffer, '/' );
if( parent )
{
parent[1] = 0;
dStrcat( fileNameBuffer, name );
return load( fileNameBuffer );
}
}
return NULL;
}
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;
}
}

234
engine/dgl/gBitmap.h Executable file
View File

@ -0,0 +1,234 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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;
class RectI;
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:
/// BitmapFormat and UsageHint are
/// written to the stream in write(...),
/// be sure to maintain compatability
/// if they are changed.
enum BitmapFormat {
Palettized = 0,
Intensity = 1,
RGB = 2,
RGBA = 3,
Alpha = 4,
RGB565 = 5,
RGB5551 = 6,
Luminance = 7
};
enum Constants {
c_maxMipLevels = 12 //(2^(12 + 1) = 2048)
};
public:
static GBitmap *load(const char *path);
static ResourceObject * findBmpResource(const char * path);
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();
GBitmap *createPaddedBitmap();
void copyRect(const GBitmap *src, const RectI &srcRect, const Point2I &dstPoint);
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 getColorBGRA(const U32 x, const U32 y, ColorI& rColor) const;
bool setColorBGRA(const U32 x, const U32 y, ColorI& rColor);
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 deletes 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_

74
engine/dgl/gChunkedTexManager.h Executable file
View File

@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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

318
engine/dgl/gDynamicTexture.cc Executable file
View File

@ -0,0 +1,318 @@
//------------------------------------------------------------------------------
// Gridwalkers
//
// Copyright (c) 2003 Pat Wilson and Flaming Duck Studio
// Portions Copyright (c) 2001 GarageGames.Com
//------------------------------------------------------------------------------
#include "dgl/gDynamicTexture.h"
#include "dgl/gBitmap.h"
#include "gui/core/guiControl.h"
#include "dgl/dgl.h"
#include "util/safeDelete.h"
Vector<DynamicTexture *> DynamicTexture::smRegisteredGuiUpdaters;
Vector<DynamicTexture *> DynamicTexture::smRegisteredScreenUpdaters;
Vector<DynamicTexture *> DynamicTexture::smUpdateAtEndOfFrame;
//--------------------------------------------------------------------------
void dynamicTextureCB(const U32 eventCode, void *userData)
{
DynamicTexture* ts = reinterpret_cast<DynamicTexture*>(userData);
if(eventCode==TextureManager::BeginZombification)
{
SAFE_DELETE(ts->mTextureHandle);
}
else if(eventCode==TextureManager::CacheResurrected)
{
GBitmap *bmp = new GBitmap( ts->mSize.x, ts->mSize.y, false, GBitmap::RGBA );
ts->mTextureHandle = new TextureHandle( NULL, bmp, BitmapKeepTexture, true );
}
}
//------------------------------------------------------------------------------
DynamicTexture::DynamicTexture()
{
initDT();
}
//------------------------------------------------------------------------------
DynamicTexture::DynamicTexture( GuiControl * control )
{
initDT();
registerForGuiUpdates( control );
}
//------------------------------------------------------------------------------
DynamicTexture::DynamicTexture( const RectI &updateRect )
{
initDT();
mUpdateRect = updateRect;
setUpdateRect( updateRect );
}
//------------------------------------------------------------------------------
DynamicTexture::~DynamicTexture()
{
TextureManager::unregisterEventCallback(mTexCBHandle);
SAFE_DELETE( mTextureHandle );
SAFE_DELETE( mTempDynamicTexture );
}
//------------------------------------------------------------------------------
void DynamicTexture::setEnableRTT( bool enable /* = true */ )
{
mRTT = enable;
if( enable && mTempDynamicTexture == NULL )
mTempDynamicTexture = new DynamicTexture( mUpdateRect );
}
//------------------------------------------------------------------------------
void DynamicTexture::update()
{
if( !mHasUpdateRect )
return;
RectI *rect = &mUpdateRect;
// Different-rect updating provided it is the same size
if( 0 )
{
/// rect = something differing
AssertFatal( rect->extent.x <= mUpdateRect.extent.x &&
rect->extent.y <= mUpdateRect.extent.x, "Cannot update a DynamicTexture with an update area larger than it's allocated area." );
}
// Do the screen copy
glReadBuffer( GL_BACK );
glBindTexture( GL_TEXTURE_2D, mTextureHandle->getGLName() );
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // 0 = no mipmaplevels
0, 0, // X and y offsets, see docs
rect->point.x, rect->point.y,
rect->extent.x, rect->extent.y );
}
//------------------------------------------------------------------------------
void DynamicTexture::setUpdateRect( const RectI &newRect )
{
mHasUpdateRect = true;
// Check to see if this is being called as part of the constructor
if( mTextureHandle == NULL )
{
GBitmap *bmp = new GBitmap( newRect.extent.x, newRect.extent.y, false, GBitmap::RGBA );
mTextureHandle = new TextureHandle( NULL, bmp, BitmapKeepTexture, true );
mSize = newRect.extent;
}
if( mTempDynamicTexture != NULL )
mTempDynamicTexture->setUpdateRect( newRect );
// Flip from upper-left point to lower-left point (for GL)
RectI updateRect = newRect;
updateRect.point.y = Platform::getWindowSize().y - updateRect.point.y - updateRect.extent.y;
if( updateRect.extent == mUpdateRect.extent )
{
if( updateRect.point != mUpdateRect.point )
mUpdateRect.point = updateRect.point;
}
else
{
TextureObject *to = mTextureHandle->object;
mUpdateRect = updateRect;
// If the new texture size can fit in the existing allocated size,
// then we are golden, otherwise we have to re-create or we'll get
// hosed.
if( mTextureHandle->getDownloadedWidth() >= mUpdateRect.extent.x &&
mTextureHandle->getDownloadedHeight() >= mUpdateRect.extent.y )
{
// We don't have to resize the actual memory (yay)
to->bitmapWidth = mUpdateRect.extent.x;
to->bitmapHeight = mUpdateRect.extent.y;
}
else
{
// Damn, we gotta reallocate
delete mTextureHandle;
mTextureHandle = NULL;
GBitmap *bmp = new GBitmap( updateRect.extent.x, updateRect.extent.y, false, GBitmap::RGBA );
mTextureHandle = new TextureHandle( NULL, bmp, BitmapKeepTexture, true );
mSize = updateRect.extent;
}
}
// DON'T USE mUpdateRect here
// Note that this looks a bit funny, this is because grabbing pixels results in
// the rows getting flipped, to adjust for this, the texture coordinates must be flipped
TextureObject *obj = (TextureObject *)mTextureHandle;
F32 maxX = F32(newRect.extent.x) / F32(obj->texWidth);
F32 maxY = F32(newRect.extent.y) / F32(obj->texHeight);
mTextureCoords = RectF( (F32)newRect.point.x, maxY, maxX, (F32)newRect.point.y );
}
//------------------------------------------------------------------------------
void DynamicTexture::renderGuiControl( GuiControl *ctrl /* = NULL */, bool rttMode /* = false */ )
{
if( ctrl == NULL )
{
if( mGuiControl == NULL )
return;
else
ctrl = mGuiControl;
}
else
mGuiControl = ctrl;
setUpdateRect( ctrl->mBounds ); // This CHANGES mUpdateRect
// If we are simulating rendering to offscreen type thing
// grab the current contents of the framebuffer and store them
if( rttMode )
{
setEnableRTT( true );
storePixels();
}
// Now render the control and grab the pixels
dglSetClipRect( ctrl->mBounds );
//ctrl->preRender();
ctrl->onRender( ctrl->mBounds.point, ctrl->mBounds );
update();
// Now restore the contents of the framebuffer so it doesn't look like we did
// anything at all (bwahahaha, Trogdor strikes again)
if( rttMode )
{
dglSetClipRect( ctrl->mBounds );
restorePixels();
}
}
//------------------------------------------------------------------------------
void DynamicTexture::storePixels()
{
mTempDynamicTexture->update();
}
//------------------------------------------------------------------------------
void DynamicTexture::restorePixels()
{
dglClearBitmapModulation();
dglDrawBitmapStretch( mTempDynamicTexture->getTextureHandle(), mUpdateRect, GFlip_Y );
}
//------------------------------------------------------------------------------
void DynamicTexture::registerForGuiUpdates( GuiControl *control )
{
if( control == NULL )
return;
unregisterForGuiUpdates();
// Sign it up in the vector
smRegisteredGuiUpdaters.push_back( this );
mGuiControl = control;
}
//------------------------------------------------------------------------------
bool DynamicTexture::unregisterForGuiUpdates()
{
for( RegisteredUpdateItr i = smRegisteredGuiUpdaters.begin();
i != smRegisteredGuiUpdaters.end(); i++ )
{
if( (*i) == this )
{
smRegisteredGuiUpdaters.erase( i );
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
void DynamicTexture::updateGuiTextures()
{
for( RegisteredUpdateItr i = smRegisteredGuiUpdaters.begin();
i != smRegisteredGuiUpdaters.end(); i++ )
{
(*i)->renderGuiControl( (*i)->mGuiControl );
}
}
//------------------------------------------------------------------------------
void DynamicTexture::registerForScreenUpdates()
{
unregisterForScreenUpdates();
// Sign it up in the vector
smRegisteredScreenUpdaters.push_back( this );
}
//------------------------------------------------------------------------------
bool DynamicTexture::unregisterForScreenUpdates()
{
for( RegisteredUpdateItr i = smRegisteredScreenUpdaters.begin();
i != smRegisteredScreenUpdaters.end(); i++ )
{
if( (*i) == this )
{
smRegisteredScreenUpdaters.erase( i );
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
void DynamicTexture::updateScreenTextures()
{
for( RegisteredUpdateItr i = smRegisteredScreenUpdaters.begin();
i != smRegisteredScreenUpdaters.end(); i++ )
{
(*i)->update();
}
}
//------------------------------------------------------------------------------
void DynamicTexture::updateEndOfFrameTextures()
{
for( RegisteredUpdateItr i = smUpdateAtEndOfFrame.begin();
i != smUpdateAtEndOfFrame.end(); i++ )
{
(*i)->update();
}
smUpdateAtEndOfFrame.clear();
}

232
engine/dgl/gDynamicTexture.h Executable file
View File

@ -0,0 +1,232 @@
//------------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.Com, Inc.
//------------------------------------------------------------------------------
#ifndef _GDYNAMICTEXTURE_H_
#define _GDYNAMICTEXTURE_H_
#include "dgl/gTexManager.h"
#include "math/mRect.h"
#include "core/tVector.h"
// Forward definitions
class GuiControl;
extern void dynamicTextureCB(const U32 eventCode, void *userData);
class DynamicTexture
{
friend void dynamicTextureCB(const U32 eventCode, void *userData);
private:
TextureHandle *mTextureHandle; ///< TextureHandle
Point2I mSize;
S32 mTexCBHandle;
RectI mUpdateRect; ///< When you call update() this is the rect, in screen coordinates, that gets grabbed
RectF mTextureCoords; ///< This is the texturecoord information you need to know to create texturecoords
///< if you are not using dglDrawBitmap
bool mRTT; ///< Supports RTT emulation for Gui @see renderGuiControl
bool mHasUpdateRect; ///< Lets this have a default constructor
GuiControl *mGuiControl; ///< If the object is registered as wanting a Gui update every frame, this is
///< the variable that contains the Gui control it will render
DynamicTexture *mTempDynamicTexture; ///< For RTT emulation
typedef Vector<DynamicTexture *>::iterator RegisteredUpdateItr;
static Vector<DynamicTexture *> smRegisteredGuiUpdaters; ///< This is a vector of DynamicTexture objects that
///< will be updated every frame with their mGuiControl
///< rendered to them.
static Vector<DynamicTexture *> smRegisteredScreenUpdaters;
static Vector<DynamicTexture *> smUpdateAtEndOfFrame;
/// Helper function for the constructors
void initDT();
public:
/// Default Constructor
DynamicTexture();
/// Constructor
///
/// @param updateRect The screen-rect this will grab from the color-buffer when update() is called
DynamicTexture( const RectI &updateRect );
/// Gui updater Constructor
///
/// @param control Gui control to render to this texture every frame
DynamicTexture( GuiControl *control );
/// Destructor
~DynamicTexture();
/// Grabs the rectangle defined by mUpdateRect from the color-buffer
/// and sticks it in the texture
void update();
/// @defgroup dyntex_guiupdate Automatic Gui Updates
/// This collection of functions is used to make textures which automatically
/// update every frame based on the content of a GuiControl
/// @{
/// This registers this DynamicTexture to be updated every frame with the contents
/// of a GuiControl
///
/// @param control Gui control to render to this texture every frame
void registerForGuiUpdates( GuiControl *control );
/// This will unregister this DynamicTexture from per-frame Gui updates
///
/// @returns True if it removed this from updating
bool unregisterForGuiUpdates();
/// This method is called in GuiCanvas before the screen-rendering takes place
/// to update all of the registered GUI update textures
static void updateGuiTextures();
/// @}
/// @defgroup dyntex_screenupdate Automatic Screen Updates
/// This collection of functions is used to make tuextures which automatically
/// update every frame based on a absolute set of screen coordinates
/// @{
/// This will register this DynamicTexture to be updated every frame
void registerForScreenUpdates();
/// This will unregister this control from screen updates
///
/// @returns True if it removed this from updating
bool unregisterForScreenUpdates();
/// This method is called in GuiCanvas right before the buffers are swapped
static void updateScreenTextures();
/// This method just registers this texture to be updated at the end of the
/// current frame
void updateAtEndOfFrame();
/// This method will update all the textures that asked to be rendered at the
/// end of the current frame
static void updateEndOfFrameTextures();
/// @}
/// This lets you change the rect that this texture grabs from the screen
/// This is not a cheap operation, you don't want to do it unless
/// you have a good reason to.
///
/// @param newUpdatePoint The new rect, in screen coordinates, to use for the update rect
void setUpdateRect( const RectI &newRect );
/// @defgroup dyntex_rtt Render To Texture Simulation
/// Render To Texture is really great because it allows you to draw to offscreen
/// buffers and not muck around with copying pixels etc. Unfortunatly there is
/// no way to do this cross-platform (that I know of) in OpenGL 1.5 so this
/// is the work around. When the time comes to draw something to a texture
/// we will copy the current contents of that area of the color buffer into
/// a temporary DynamicTexture, draw (to that area), grab those pixels, then
/// restore the contents of the color buffer to what it was before we drew
/// to it. This method is NOT necesasary for every application of DynamicTexture.
/// In fact, most applications will not need it at all.
/// @{
/// Manually enable or disable RTT mode
void setEnableRTT( bool enable = true );
/// Stores the pixels defined by the updateRect into a temporary
/// DynamicTexture object so that they can be restored at a later
/// time.
void storePixels();
/// Restores the pixels in the temporary DynamicTexture object
/// by doing a dglDrawBitmap with them and drawing them, stretched
/// to the updateRect.
void restorePixels();
/// @}
/// Returns the texture handle for this so it can be used to render
///
/// @return Texture handle for the dynamic texture
TextureHandle getTextureHandle() const;
/// Returns a const pointer to the texture coordinate information
///
/// @return Texture coordinate information
const RectF * const texCoordInfo() const;
/// Returns the update rect of this dynamic texture
///
/// @return Update rect for the dynamic texture
const RectI * const getUpdateRect() const;
/// Returns the GuiControl this texture is using, if any
GuiControl *getGuiControl() const;
/// Renders a GuiControl, and it's children, to the texture
/// This has two different behaviors depending on if RTT emulation
/// is specified as enabled.
///
/// In OpenGL, rendering to an off screen
/// buffer is a platform-specific operation and I don't have a Mac
/// to make sure this works and what have you, so what happens is,
/// if RTT mode is turned on, the area that will be used to draw
/// the texture will be saved, with the temp DyanmicTexture object
/// then the rendering will take place, it will grab the texture,
/// then restore the edited area of the color-buffer.
///
/// If RTT is turned off, then it will draw the control on the screen,
/// grab it, and leave it. This is not as useless as it seems, this is
/// not at all a bad way to do things, just do it all in the GuiCanvas
/// before it begins rendering the content control
/// @see GuiCanvas::renderFrame
///
/// @param ctrl GuiControl to render
void renderGuiControl( GuiControl *ctrl = NULL, bool rttMode = false );
};
//------------------------------------------------------------------------------
inline TextureHandle DynamicTexture::getTextureHandle() const
{
return *mTextureHandle;
}
inline const RectF * const DynamicTexture::texCoordInfo() const
{
return &mTextureCoords;
}
inline GuiControl *DynamicTexture::getGuiControl() const
{
return mGuiControl;
}
inline const RectI * const DynamicTexture::getUpdateRect() const
{
return &mUpdateRect;
}
inline void DynamicTexture::updateAtEndOfFrame()
{
smUpdateAtEndOfFrame.push_back( this );
}
inline void DynamicTexture::initDT()
{
mTexCBHandle = TextureManager::registerEventCallback(dynamicTextureCB, this);
mTextureHandle = NULL;
mRTT = false;
mHasUpdateRect = false;
mGuiControl = NULL;
mTempDynamicTexture = NULL;
}
//------------------------------------------------------------------------------
#endif

475
engine/dgl/gFont.cc Executable file
View File

@ -0,0 +1,475 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "core/stream.h"
#include "dgl/gFont.h"
#include "dgl/gBitmap.h"
#include "core/fileStream.h"
#include "dgl/gTexManager.h"
S32 GOldFont::smSheetIdCount = 0;
ResourceInstance* constructFont(Stream& stream)
{
GOldFont *ret = new GOldFont;
if(!ret->read(stream))
{
delete ret;
return NULL;
}
return ret;
}
const U32 GOldFont::csm_fileVersion = 1;
Resource<GOldFont> GOldFont::create(const char *faceName, U32 size, const char *cacheDirectory, U32 charset /* = 0 */)
{
char buf[256];
dSprintf(buf, sizeof(buf), "%s/%s_%d.gft", cacheDirectory, faceName, size);
Resource<GOldFont> ret = ResourceManager->load(buf);
if(bool(ret))
return ret;
GOldFont *resFont = createFont(faceName, size, charset);
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, cacheDirectory);
}
FileStream stream;
if(ResourceManager->openFileForWrite(stream, buf))
{
resFont->write(stream);
stream.close();
}
ResourceManager->add(buf, resFont, false);
return ResourceManager->load(buf);
}
GOldFont::GOldFont()
{
VECTOR_SET_ASSOCIATION(mCharInfoList);
for (U32 i = 0; i < 256; i++)
mRemapTable[i] = -1;
mTextureSheets = NULL;
}
GOldFont::~GOldFont()
{
delete [] mTextureSheets;
mTextureSheets = NULL;
}
void GOldFont::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 = (*((GOldFont::CharInfo **) a))->height;
S32 hb = (*((GOldFont::CharInfo **) b))->height;
return hb - ha;
}
void GOldFont::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]);
mTextureSheets[i].setFilterNearest();
}
}
TextureHandle GOldFont::getTextureHandle(S32 index)
{
return mTextureSheets[index];
}
void GOldFont::assignSheet(S32 sheetNum, GBitmap *bmp)
{
char buf[30];
dSprintf(buf, sizeof(buf), "font_%d", smSheetIdCount++);
mTextureSheets[sheetNum] = TextureHandle(buf, bmp);
}
U32 GOldFont::getStrWidth(const char* in_pString) const
{
AssertFatal(in_pString != NULL, "GOldFont::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 GOldFont::getStrWidthPrecise(const char* in_pString) const
{
AssertFatal(in_pString != NULL, "GOldFont::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 GOldFont::getStrNWidth(const char *str, U32 n) const
{
AssertFatal(str != NULL, "GOldFont::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 GOldFont::getStrNWidthPrecise(const char *str, U32 n) const
{
AssertFatal(str != NULL, "GOldFont::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 GOldFont::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 GOldFont::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 GOldFont::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);
mTextureSheets[i].setFilterNearest();
}
// Read character remap table
for(i = 0; i < 256; i++)
io_rStream.read(&mRemapTable[i]);
return (io_rStream.getStatus() == Stream::Ok);
}
bool
GOldFont::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
engine/dgl/gFont.h Executable file
View File

@ -0,0 +1,156 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _GOLDFONT_H_
#define _GOLDFONT_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
#include "gNewFont.h"
extern ResourceInstance* constructFont(Stream& stream);
class TextureHandle;
class GOldFont : 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:
GOldFont();
virtual ~GOldFont();
// 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<GOldFont> create(const char *face, U32 size, const char *cacheDirectory, U32 charset = 0);
};
inline bool GOldFont::isValidChar(const U8 in_charIndex) const
{
return mRemapTable[in_charIndex] != -1;
}
inline S16 GOldFont::getActualIndex(const U8 in_charIndex) const
{
AssertFatal(isValidChar(in_charIndex) == true,
avar("GOldFont::getActualIndex: invalid character: 0x%x",
in_charIndex));
return mRemapTable[in_charIndex];
}
inline const GOldFont::CharInfo& GOldFont::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 GOldFont::getCharXIncrement(const U8 in_charIndex) const
{
const CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.xIncrement;
}
inline U32 GOldFont::getCharWidth(const U8 in_charIndex) const
{
const CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.width;
}
inline U32 GOldFont::getCharHeight(const U8 in_charIndex) const
{
const CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.height;
}
#endif //_GFONT_H_

1181
engine/dgl/gNewFont.cc Normal file

File diff suppressed because it is too large Load Diff

192
engine/dgl/gNewFont.h Normal file
View File

@ -0,0 +1,192 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _GFONT_H_
#define _GFONT_H_
//Includes
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _PLATFORMFONT_H_
#include "platform/platformFont.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
#include "dgl/gTexManager.h"
extern ResourceInstance* constructNewFont(Stream& stream);
class TextureHandle;
class GFont : public ResourceInstance
{
friend ResourceInstance* constructNewFont(Stream& stream);
static const U32 csm_fileVersion;
static S32 smSheetIdCount;
// Enumerations and structs available to everyone...
public:
enum Constants
{
TabWidthInSpaces = 3,
TextureSheetSize = 256,
};
// Enumerations and structures available to derived classes
private:
PlatformFont *mPlatformFont;
Vector<TextureHandle>mTextureSheets;
S32 mCurX;
S32 mCurY;
S32 mCurSheet;
StringTableEntry mGFTFile;
StringTableEntry mFaceName;
U32 mSize;
U32 mCharSet;
U32 mHeight;
U32 mBaseline;
U32 mAscent;
U32 mDescent;
Vector<PlatformFont::CharInfo> mCharInfoList; // - List of character info structures, must
// be accessed through the getCharInfo(U32)
// function to account for remapping...
S32 mRemapTable[65536]; // - Index remapping
public:
GFont();
virtual ~GFont();
protected:
bool loadCharInfo(const UTF16 ch);
void addBitmap(PlatformFont::CharInfo &charInfo);
void addSheet(void);
void assignSheet(S32 sheetNum, GBitmap *bmp);
void *mMutex;
public:
static Resource<GFont> create(const char *faceName, U32 size, const char *cacheDirectory, U32 charset = TGE_ANSI_CHARSET);
TextureHandle getTextureHandle(S32 index)
{
return mTextureSheets[index];
}
const PlatformFont::CharInfo& getCharInfo(const UTF16 in_charIndex);
U32 getCharHeight(const UTF16 in_charIndex);
U32 getCharWidth(const UTF16 in_charIndex);
U32 getCharXIncrement(const UTF16 in_charIndex);
bool isValidChar(const UTF16 in_charIndex);
const U32 getHeight() const { return mHeight; }
const U32 getBaseline() const { return mBaseline; }
const U32 getAscent() const { return mAscent; }
const U32 getDescent() const { return mDescent; }
U32 getBreakPos(const UTF8 *string, U32 strlen, U32 width, bool breakOnWhitespace);
/// These are the preferred width functions.
U32 getStrNWidth(const UTF16*, U32 n);
U32 getStrNWidthPrecise(const UTF16*, U32 n);
/// These UTF8 versions of the width functions will be deprecated, please avoid them.
U32 getStrWidth(const UTF8*); // Note: ignores c/r
U32 getStrNWidth(const UTF8*, U32 n);
U32 getStrWidthPrecise(const UTF8*); // Note: ignores c/r
U32 getStrNWidthPrecise(const UTF8*, U32 n);
void wrapString(const UTF8 *string, U32 width, Vector<U32> &startLineOffset, Vector<U32> &lineLen);
/// Dump information about this font to the console.
void dumpInfo();
/// Export to an image strip for image processing.
void exportStrip(const char *fileName, U32 padding, U32 kerning);
/// Import an image strip generated with exportStrip, make sure parameters match!
void importStrip(const char *fileName, U32 padding, U32 kerning);
/// Query as to presence of platform font. If absent, we cannot generate more
/// chars!
const bool hasPlatformFont() const
{
return mPlatformFont;
}
/// Query to determine if we should use add or modulate (as A8 textures
/// are treated as having 0 for RGB).
bool isAlphaOnly()
{
return mTextureSheets[0].getBitmap()->getFormat() == GBitmap::Alpha;
}
/// Get the filename for a cached font.
static void getFontCacheFilename(const char *faceName, U32 faceSize, U32 buffLen, char *outBuff);
bool read(Stream& io_rStream);
bool write(Stream& io_rStream);
/// Override existing platform font if any with a new one from an external
/// source. This is primarily used in font processing tools to enable
/// trickery (ie, putting characters from multiple fonts in a single
/// GFT) and should be used with caution!
void forcePlatformFont(PlatformFont *pf)
{
mPlatformFont = pf;
}
};
inline U32 GFont::getCharXIncrement(const UTF16 in_charIndex)
{
const PlatformFont::CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.xIncrement;
}
inline U32 GFont::getCharWidth(const UTF16 in_charIndex)
{
const PlatformFont::CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.width;
}
inline U32 GFont::getCharHeight(const UTF16 in_charIndex)
{
const PlatformFont::CharInfo& rChar = getCharInfo(in_charIndex);
return rChar.height;
}
inline bool GFont::isValidChar(const UTF16 in_charIndex)
{
if(mRemapTable[in_charIndex] != -1)
return true;
if(mPlatformFont)
return mPlatformFont->isValidChar(in_charIndex);
return false;
}
#endif //_GFONT_H_

146
engine/dgl/gPalette.cc Executable file
View File

@ -0,0 +1,146 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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);
}

99
engine/dgl/gPalette.h Executable file
View File

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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_

1782
engine/dgl/gTexManager.cc Executable file

File diff suppressed because it is too large Load Diff

428
engine/dgl/gTexManager.h Executable file
View File

@ -0,0 +1,428 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _GTEXMANAGER_H_
#define _GTEXMANAGER_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
// to be removed at some point, hopefully...
#ifndef _PLATFORMGL_H_
#include "platform/platformAssert.h"
#include "platform/platformGL.h"
#endif
//-------------------------------------- Forward Decls.
class GBitmap;
//------------------------------------------------------------------------------
//-------------------------------------- TextureHandle
//
/// Enumerated values for different types of textures
/// Generally speaking, all textures will have mipmaps extruded automatically
/// and use linear magnification and linear_mipmap_nearest minification filtering
/// unless trilinear filtering is enabled. Then, the minification is linear_maipmap_linear.
/// Most texture types have their bitmap data destroyed after texture creation.
/// Also, detail settings affect any of the textures except the ones noted.
/// Detail settings are based on the mip maps, so if the detail level is turned down,
/// the highest resolution detail map will NOT be the one that is in the actual
/// texture file, but one that has been averaged down appropriately.
///
/// @note "Small textures" are a different set of textures, dynamically created with
/// certain texture types whose first mip level is the same as the 4th mip level
/// of the first texture. So, the full res small texture will be the same as the
/// 4th averaged down version of the origional texture.
enum TextureHandleType
{
BitmapTexture = 0, ///< Regular bitmap - does not to be pow2, but will be converted to pow2, only 1 mip level
BitmapKeepTexture, ///< Same as BitmapTexture, but the data will be kept after creation
BitmapNoDownloadTexture, ///< Same as BitmapTexture except data will not be loaded to OpenGL and cannot be "bound"
RegisteredTexture, ///< INTERNAL USE ONLY - texture that has already been created and is just being reinstated
MeshTexture, ///< Has "small textures"
TerrainTexture, ///< OFF LIMITS - for terrain engine use only. You WILL cause problems if you use this type
SkyTexture, ///< Hooks into the sky texture detail level
InteriorTexture, ///< Has "small textures" and hooks into the interior texture detail level
BumpTexture, ///< Same as DetailTexture, except colors are halved
InvertedBumpTexture, ///< Same as BumpTexture, except colors are then inverted
DetailTexture, ///< If not palettized, will extrude mipmaps, only used for terrain detail maps
ZeroBorderTexture ///< Clears the border of the texture on all mip levels
};
class TextureObject
{
public:
TextureObject *next;
TextureObject *prev;
TextureObject *hashNext;
GLuint texGLName; ///< GL-Bindable texture index
GLuint smallTexGLName; ///< @see TextureHandleType
#ifdef TORQUE_GATHER_METRICS
U32 textureSpace;
#endif
StringTableEntry texFileName;
/// The actual bitmap data of the texture
/// @note this is usually destroyed once the texture has been loaded,
/// except in the case of BitmapKeepTexture, so any changes that might
/// need to be made to it need to be done within the loading code
GBitmap * bitmap;
U32 texWidth;
U32 texHeight;
U32 bitmapWidth;
U32 bitmapHeight;
U32 downloadedWidth;
U32 downloadedHeight;
TextureHandleType type;
bool filterNearest;
bool clamp;
bool holding;
S32 refCount;
};
typedef void (*TextureEventCallback)(const U32 eventCode, void *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 bool smTextureManagerActive;
/// Loads a texture from file, and returns the result of registerTexture
static TextureObject* loadTexture(const char *textureName, TextureHandleType type, bool clampToEdge, bool checkOnly = false);
/// Inserts a texture into the hash table, and gives the texture an OpenGL name
static TextureObject* registerTexture(const char *textureName, const GBitmap *data, bool clampToEdge);
/// Inserts a texture into the hash table, and gives the texture an OpenGL name
static TextureObject* registerTexture(const char *textureName, GBitmap *data, TextureHandleType type, bool clampToEdge);
/// Deletes the texture data and removes the texture from the texture dictionary hash table and OpenGL
static void freeTexture(TextureObject *to);
/// Creates the OpenGL texture and sets all related GL states.
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);
/// Just in case the texture specified does not have sides of power-of-2,
/// this function will copy the texture data into a new texture that IS power-of-2
/// and fill in the empty areas with the adjacent pixel
static GBitmap* createPaddedBitmap(GBitmap* pBitmap);
public:
static void create();
static void preDestroy();
static void destroy();
static bool isActive() { return smTextureManagerActive; }
/// @name Zombification
/// This pair of functions is a flush() equivalent. To flush
/// 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 makeZombie();
static void resurrect();
/// @}
/// Added for convenience when you don't need to worry about the above problems. (Zombification)
static void flush();
static bool smIsZombie; ///< Is the texture manager a skulking undead brain-eating zombie from the great beyond? I sure hope not...
#ifdef TORQUE_GATHER_METRICS
static void dumpStats();
#endif
enum EventCodes
{
BeginZombification = 0,
CacheResurrected = 1
};
static U32 registerEventCallback(TextureEventCallback, void *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; }
static GBitmap *loadBitmapInstance(const char *textureName, bool recurse = true);
#ifdef TORQUE_GATHER_METRICS
static U32 smTextureSpaceLoaded;
static U32 smTextureCacheMisses;
static F32 getResidentFraction();
#endif
};
/// This is the main texture manager interface. Texturing can be
/// a bit complicated, but if you follow these easy steps, it is
/// really quite simple!
///
/// In order to use a texture on disk, first you must create a
/// TextureHandle data structure for it.
/// @code
/// TextureHandle handle = TextureHandle("pathToTexture", textureType);
/// @endcode
/// See the documentation on the different enumerated types for more info
/// on texture types.
///
/// Ok, now you have your texture loaded into video memory or ram,
/// whichever is chooses. In order to tell OpenGL to use your texture,
/// you have to bind it. GL_TEXTURE_2D is the type of texture you're
/// binding - a 2 dimisional texture. Also note that you only have
/// to do this if you are using direct OpenGL commands to draw rather
/// than dgl. Dgl manages the below on it's own so you don't have to worry about it.
/// @code
/// glBindTexture(GL_TEXTURE_2D, handle.getGLName());
/// @endcode
/// Now you can begin to draw you texture. If you havn't already,
/// make sure you make a call to glEnable(GL_TEXTURE_2D); before
/// you start drawing and a call to glDisable(GL_TEXTURE_2D); when
/// you're done. Failure to call glEnable will cause the texture not
/// to draw, and failure to call glDisable will probably case
/// an assert in debug mode and ugly artifacts in release.
///
/// If you are going through dgl, all you need is the TextureHandle and
/// some points. See the dgl documentation for more info on each
/// individual function in the dgl library. However, most dgl functions
/// will take a TextureObject data type. And, it just so happens that
/// a TextureHandle has a TextureObject! It also has an
/// operator TextureObject*(), which lets you cast a TextureHandle to
/// a TextureObject. That means that all you have to do is ignore
/// the TextureObject parameter and just give it a TextureHandle.
///
/// Some tips on texture performance:
///
/// Instead of using hard-coded paths, use a hook to a console variable.
/// You will probably change the directory structure for your game,
/// and that means that you will have to go back to all of the hardcoded
/// paths and change them by hand, then rebuild the engine. It is much
/// better to use script variables since they are all in one place and
/// easier to change.
///
/// Add the path string for your texture to the StringTable. Doing so
/// helps in string lookups and faster string performance.
///
/// Don't create the texture every frame if at all possible. Make it
/// a global variable if you have to - just don't load every frame.
/// Loading data off of the disk every frame WILL cause massive
/// performance loss and should be avoided at all costs. This is
/// not to mention the overhead of generating mip map levels
/// and uploading the texture into memory when the texture is created.
///
/// @note
/// 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.
///
/// Also note the operator TextureObject*, as you can actually cast
/// a TextureHandle to a TextureObject* if necessary.
class TextureHandle
{
friend class DynamicTexture;
TextureObject *object;
void lock();
void unlock();
public:
TextureHandle() { object = NULL; }
TextureHandle(TextureObject *to)
{
object = to;
lock();
}
TextureHandle(const TextureHandle &th)
{
object = th.object;
lock();
}
TextureHandle(const char* textureName,
TextureHandleType type, // was =BitmapTexture - dc removed to eliminate overload confusion.
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;
}
bool set(const char *textureName,
TextureHandleType type=BitmapTexture,
bool clampToEdge = false)
{
TextureObject* newObject = TextureManager::loadTexture(textureName, type, clampToEdge);
if (newObject != object)
{
unlock();
object = newObject;
lock();
}
return (object != NULL);
}
bool set(const char *textureName,
const GBitmap *data,
bool clampToEdge = false)
{
TextureObject* newObject = TextureManager::registerTexture(textureName, data, clampToEdge);
if (newObject != object)
{
unlock();
object = newObject;
lock();
}
return (object != NULL);
}
bool 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();
}
return (object != NULL);
}
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 setFilterNearest();
void refresh();
void refresh(GBitmap*);
operator TextureObject*() { return object; }
/// Returns the texture's filename if it exists
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); }
/// Gets the OpenGL index of the texture for use in glBindTexture().
U32 getGLName() const;
};
#if defined(TORQUE_GATHER_METRICS) && TORQUE_GATHER_METRICS > 1
#ifndef _PLATFORMGL_H_
#if defined(TORQUE_OS_MAC)
#include "PlatformMacCarb/platformGL.h"
#elif defined(TORQUE_OS_WIN32)
#include "PlatformWin32/platformGL.h"
#endif
#endif
inline U32 TextureHandle::getGLName() const
{
if (!object)
return 0;
U32 useName = object->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_

336
engine/dgl/gVectorField.cc Executable file
View File

@ -0,0 +1,336 @@
//------------------------------------------------------------------------------
// Vector Field Rendering Object
//------------------------------------------------------------------------------
#include "dgl/gVectorField.h"
#include "core/fileStream.h"
#include "dgl/dgl.h"
#include "math/mRect.h"
#include "core/color.h"
#include "core/frameAllocator.h"
#include "util/safeDelete.h"
#define NUM_VERTS mFieldResolution.x * mFieldResolution.y
#define NUM_IDXS mFieldResolution.x * 2
#define NUM_STRIPS mFieldResolution.y - 1
#define INDEX(x, y) (x + y * mFieldResolution.x)
#define VERT(x, y) mFieldVerts[INDEX(x,y)]
//------------------------------------------------------------------------------
VectorField::VectorField()
{
nullField();
}
//------------------------------------------------------------------------------
VectorField::VectorField( const Point2I &resolution, F32 maxX /* = 1.f */,
F32 maxY /* = 1.f */, TextureCoordFlip flip /* = Flip_None */,
VectorFieldInitFn initFn /* = NULL */ )
{
nullField();
allocVectorField( resolution );
initVectorField( maxX, maxY, flip, initFn );
}
//------------------------------------------------------------------------------
VectorField::VectorField( const char *fileName )
{
nullField();
loadField( fileName );
}
//------------------------------------------------------------------------------
VectorField::~VectorField()
{
destroyVectorField();
}
//------------------------------------------------------------------------------
void VectorField::destroyVectorField()
{
SAFE_DELETE_ARRAY( mVectorField );
SAFE_DELETE_ARRAY( mFieldIndices );
SAFE_DELETE_ARRAY( mFieldVerts );
#ifdef ENABLE_FIELD_VISUALIZE
SAFE_DELETE_ARRAY( mUnflippedVecField );
#endif
}
//------------------------------------------------------------------------------
void VectorField::allocVectorField( const Point2I &resolution )
{
destroyVectorField();
mFieldResolution = resolution;
mVectorField = new Point2F[NUM_VERTS];
// Create index buffer
mFieldIndices = new U16[NUM_IDXS];
bool up = false;
U32 x = 0, y = 0;
// It would be way more efficent if we did one index buffer with degenerate
// polys but you know what, I hate writing that stuff, and after 3 hours on a
// friday night, I'm going with the easy way.
for( int i = 0; i < NUM_IDXS; i++ )
{
mFieldIndices[i] = INDEX(x, y);
if( up )
{
x++;
y--;
}
else
y++;
up = !up;
}
#ifdef ENABLE_FIELD_VISUALIZE
mUnflippedVecField = new Point2F[NUM_VERTS];
#endif
}
//------------------------------------------------------------------------------
void FN_CDECL defaultInitFn( const int x, const int y, const Point2I &resolution,
const F32 maxX, const F32 maxY, Point2F *outVec )
{
outVec->x = ( (F32)x / ( (F32)resolution.x - 1.f ) ) * maxX;
outVec->y = ( (F32)y / ( (F32)resolution.y - 1.f ) ) * maxY;
}
void VectorField::initVectorField( F32 maxX /* = 1.f */, F32 maxY /* = 1.f */, TextureCoordFlip flip /* = Flip_None */, VectorFieldInitFn initFn /* = NULL */ )
{
mMax.x = maxX;
mMax.y = maxY;
// Create the vertex buffer to render the field
mFieldVerts = new Point2F[NUM_VERTS];
// Initialize all this stuff at once since we are working in the same space
for( int x = 0; x < mFieldResolution.x; x++ )
{
for( int y = 0; y < mFieldResolution.y; y++ )
{
// Vertices
defaultInitFn( x, y, mFieldResolution, maxX, maxY, &VERT(x, y) );
// Initialize the texture coordinates to their normal values
defaultInitFn( x, y, mFieldResolution, maxX, maxY, &getVector( x, y ) );
// If provided, pass the normal values on to a custom function
if( initFn != NULL )
(*initFn)( x, y, mFieldResolution, maxX, maxY, &getVector( x, y ) );
}
}
#ifdef ENABLE_FIELD_VISUALIZE
dMemcpy( mUnflippedVecField, mVectorField, sizeof(Point2F) * NUM_VERTS );
#endif
// Flip?
if( flip != Flip_None )
{
FrameAllocatorMarker marker; // Ben = teh win
// Make this easy, create a copy of the coord array
Point2F *fieldCopy = (Point2F *)marker.alloc( sizeof(Point2F) * NUM_VERTS );
dMemcpy( fieldCopy, mVectorField, sizeof(Point2F) * NUM_VERTS );
for( int i = 0; i < NUM_VERTS; i++ )
{
if( flip & Flip_X )
mVectorField[i].x = fieldCopy[NUM_VERTS - i - 1].x;
if( flip & Flip_Y )
mVectorField[i].y = fieldCopy[NUM_VERTS - i - 1].y;
}
}
}
//------------------------------------------------------------------------------
#define WRITEPOINT2X( p, s ) s->write( p.x ); s->write( p.y );
#define READPOINT2X( p, s ) s->read( &p.x ); s->read( &p.y );
void VectorField::serialize( Stream *stream ) const
{
WRITEPOINT2X( mFieldResolution, stream );
for( int x = 0; x < mFieldResolution.x; x++ )
{
for( int y = 0; y < mFieldResolution.y; y++ )
{
WRITEPOINT2X( getVector( x, y ), stream );
}
}
}
//------------------------------------------------------------------------------
void VectorField::unserialize( Stream *stream )
{
READPOINT2X( mFieldResolution, stream );
allocVectorField( mFieldResolution );
for( int x = 0; x < mFieldResolution.x; x++ )
{
for( int y = 0; y < mFieldResolution.y; y++ )
{
READPOINT2X( getVector( x, y ), stream );
}
}
}
//------------------------------------------------------------------------------
bool VectorField::loadField( const char *fileName )
{
FileStream fs;
if( !fs.open( fileName, FileStream::Read ) )
return false;
unserialize( &fs );
return true;
}
//------------------------------------------------------------------------------
bool VectorField::saveField( const char *fileName ) const
{
FileStream fs;
if( !fs.open( fileName, FileStream::Write ) )
return false;
serialize( &fs );
return true;
}
//------------------------------------------------------------------------------
void VectorField::renderField( bool texture /* = false */ ) const
{
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0.0, mMax.x, 0.0, mMax.y );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glEnableClientState( GL_VERTEX_ARRAY );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
if( texture )
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glColor4f( 1.f, 1.f, 1.f, 1.f );
for( int i = 0; i < NUM_STRIPS; i++ )
{
glTexCoordPointer( 2, GL_FLOAT, 0, &mVectorField[i * mFieldResolution.x] );
glVertexPointer( 2, GL_FLOAT, 0, &mFieldVerts[i * mFieldResolution.x] );
glDrawElements( GL_QUAD_STRIP, NUM_IDXS, GL_UNSIGNED_SHORT, mFieldIndices );
}
if( texture )
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glDisable(GL_BLEND);
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
}
#ifdef ENABLE_FIELD_VISUALIZE
void VectorField::visualizeField( F32 alpha /* = 1.0f */ ) const
{
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0.0, mMax.x, 0.0, mMax.y );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glDisable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
// Draw the field in wireframe, apparently it's a back facing poly...whatever
GLint mode[2];
glGetIntegerv( GL_POLYGON_MODE, mode );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glEnableClientState( GL_VERTEX_ARRAY );
glColor4f( 1.f, 1.f, 1.f, alpha );
for( int i = 0; i < NUM_STRIPS; i++ )
{
glVertexPointer( 2, GL_FLOAT, 0, &mFieldVerts[i * mFieldResolution.x] );
glDrawElements( GL_QUAD_STRIP, NUM_IDXS, GL_UNSIGNED_SHORT, mFieldIndices );
}
glDisableClientState( GL_VERTEX_ARRAY );
glPolygonMode( GL_FRONT, mode[0] );
glPolygonMode( GL_BACK, mode[1] );
// Draw the vectors
glBegin( GL_LINES );
glColor4f( 0.f, 1.f, 0.f, 1.f );
for( int i = 0; i < NUM_VERTS; i++ )
{
// Base point
glVertex2fv( (F32 *)&mFieldVerts[i] );
glVertex2fv( (F32 *)&mUnflippedVecField[i]);
}
glEnd();
// Draw the verts
glPointSize( 3.f );
glEnable( GL_POINT_SMOOTH );
glBegin( GL_POINTS );
glColor4f( 1.f, 0.f, 0.f, alpha );
for( int i = 0; i < NUM_VERTS; i++ )
glVertex2fv( (F32 *)&mFieldVerts[i] );
glEnd();
glDisable( GL_POINT_SMOOTH );
glPointSize( 1.f );
glDisable( GL_BLEND );
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
}
#endif

150
engine/dgl/gVectorField.h Executable file
View File

@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
// Vector Field
//------------------------------------------------------------------------------
#ifndef _GVECTORFIELD_H_
#define _GVECTORFIELD_H_
#include "math/mPoint.h"
#include "core/stream.h"
// Comment this line out to disable the ability to render out the field
#define ENABLE_FIELD_VISUALIZE
/// Function pointer that is used for functions to init vector fields
/// @note This function will be passed the normal texture coordinates in outVec
typedef void(FN_CDECL *VectorFieldInitFn)( const int x, const int y, const Point2I &resolution, const F32 maxX, const F32 maxY, Point2F *outVec );
class VectorField
{
private:
Point2I mFieldResolution; ///< Resolution of the vector field, x * y = number of quads
Point2F *mVectorField; ///< Vector Field
Point2F *mFieldVerts; ///< Vertices for rendering the field
U16 *mFieldIndices; ///< Indices for rendering the field
Point2F mMax; ///< Maximum texture coordinate values
#ifdef ENABLE_FIELD_VISUALIZE
Point2F *mUnflippedVecField; ///< If the coords get flipped, then this will be unflipped
#endif
/// Helper function to create the vector field
///
/// @param resolution Vector Field resolution
void allocVectorField( const Point2I &resolution );
/// Helper function to destroy the vector field
void destroyVectorField();
/// Helper function to null the pointers
void nullField();
/// Helper inline just so I can store the vector field as a 1d array but access
/// it as a 2d array
Point2F &getVector( const U32 x, const U32 y );
const Point2F &getVector( const U32 x, const U32 y ) const;
/// Put this field out to a stream
void serialize( Stream *stream ) const;
/// Read a stream and set up this field
void unserialize( Stream *stream );
public:
/// This is used to specify flip options for creating the texture coord array
enum TextureCoordFlip
{
Flip_None = 0,
Flip_X = BIT(0),
Flip_Y = BIT(1),
Flip_XY = Flip_X | Flip_Y
};
/// Default Constructor
VectorField();
/// Constructor
///
/// @param resolution Vector Field resolution
/// @param maxX Maximum value that can be assigned to an x-coord
/// @param maxY Maximum value that can be assigned to a y-coord
/// @param flip Flipping options for the texture coordinates
/// @param initFn Function pointer to init the vector field values with
VectorField( const Point2I &resolution, const F32 maxX = 1.f, const F32 maxY = 1.f,
TextureCoordFlip flip = Flip_None, VectorFieldInitFn initFn = NULL );
/// Constructor with file name
///
/// @param fileName File name to load from
VectorField( const char *fileName );
/// Destructor
~VectorField();
/// Init the vector field
/// @param maxX Maximum value that can be assigned to an x-coord
/// @param maxY Maximum value that can be assigned to a y-coord
/// @param flip Flipping options for the texture coordinates
/// @param initFn Function pointer to init the vector field values with
void initVectorField( F32 maxX = 1.f, F32 maxY = 1.f, TextureCoordFlip flip = Flip_None, VectorFieldInitFn initFn = NULL );
/// Load the vector field from a file
/// @see saveField
///
/// @param fileName File name to load from
bool loadField( const char *fileName );
/// Save the vector field to a file
///
/// @param fileName File name to save to
bool saveField( const char *fileName ) const;
/// Render out the vector field
///
/// @param texture True if this should enable texturing
void renderField( bool texture = false ) const;
/// Render the field to let someone visualize what it is doing
void visualizeField( F32 alpha = 1.f ) const;
};
//------------------------------------------------------------------------------
inline Point2F &VectorField::getVector( const U32 x, const U32 y )
{
AssertFatal( x < mFieldResolution.x && y < mFieldResolution.y, "Vector Field access out of bounds" );
return mVectorField[x + y * mFieldResolution.x];
}
inline const Point2F &VectorField::getVector( const U32 x, const U32 y ) const
{
AssertFatal( x < mFieldResolution.x && y < mFieldResolution.y, "Vector Field access out of bounds" );
return mVectorField[x + y * mFieldResolution.x];
}
//------------------------------------------------------------------------------
#ifndef ENABLE_FIELD_VISUALIZE
inline void VectorField::visualizeField( F32 alpha /* = 0.5f */ ) const
{
}
#endif
//------------------------------------------------------------------------------
inline void VectorField::nullField()
{
#ifdef ENABLE_FIELD_VISUALIZE
mUnflippedVecField = NULL;
#endif
mFieldVerts = NULL;
mFieldIndices = NULL;
mVectorField = NULL;
}
#endif

97
engine/dgl/lensFlare.cc Executable file
View File

@ -0,0 +1,97 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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();
}

65
engine/dgl/lensFlare.h Executable file
View File

@ -0,0 +1,65 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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

332
engine/dgl/materialList.cc Executable file
View File

@ -0,0 +1,332 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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());
S32 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, const char* path)
{
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)
{
if (path) {
char buffer[512];
dSprintf(buffer, sizeof(buffer), "%s/%s", path , name);
handle.set(buffer, mTextureType, mClampToEdge);
}
else
handle.set(name, mTextureType, mClampToEdge);
}
}
}
}
//--------------------------------------
bool MaterialList::load(const char* path)
{
AssertFatal(mMaterialNames.size() == mMaterials.size(), "MaterialList::load: internal vectors out of sync.");
for(S32 i=0; i < mMaterials.size(); i++)
load(i,path);
for(S32 i=0; i < mMaterials.size(); i++)
{
// TSMaterialList nulls out the names of IFL materials, so
// we need to ignore empty names.
const char *name = mMaterialNames[i];
if (name && *name && !mMaterials[i])
return false;
}
return true;
}
//--------------------------------------
void MaterialList::unload()
{
AssertFatal(mMaterials.size() == mMaterials.size(), "MaterialList::unload: internal vectors out of sync.");
for(S32 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(S32 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++)
{
// Load the bitmap name
char buffer[256];
stream.readString(buffer);
if( !buffer[0] )
{
AssertWarn(0, "MaterialList::read: error reading stream");
return false;
}
// Material paths are a legacy of Tribes tools,
// strip them off...
char *name = &buffer[dStrlen(buffer)];
while (name != buffer && name[-1] != '/' && name[-1] != '\\')
name--;
// 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(name) + 1];
dStrcpy(mMaterialNames.last(), name);
}
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(S32 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;
// Material paths are a legacy of Tribes tools,
// strip them off...
char *name = &buf[dStrlen(buf)];
while (name != buf && name[-1] != '/' && name[-1] != '\\')
name--;
// 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(name) + 1];
dStrcpy(mMaterialNames.last(), name);
}
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(S32 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;
}
}

101
engine/dgl/materialList.h Executable file
View File

@ -0,0 +1,101 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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*);
U32 getMaterialCount() { return (U32)mMaterials.size(); }
const char * getMaterialName(U32 index) { return mMaterialNames[index]; }
TextureHandle &getMaterial(U32 index)
{
AssertFatal(index < (U32) 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, const char* path = 0);
bool load(const char* path = 0);
bool load(TextureHandleType type, const char* path = 0, 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(); }
U32 size() { return (U32)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, const char* path, bool clampToEdge)
{
mTextureType = type;
mClampToEdge = clampToEdge;
return load(path);
}
extern ResourceInstance* constructMaterialList(Stream &stream);
#endif

171
engine/dgl/materialPropertyMap.cc Executable file
View File

@ -0,0 +1,171 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/materialPropertyMap.h"
ConsoleFunction( addMaterialMapping, bool, 2, 99, "(string matName, ...) Set up a material mapping. See MaterialPropertyMap for details.")
{
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);
}
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 (S32 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 (S32 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;
}

View File

@ -0,0 +1,72 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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);
// 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_

162
engine/dgl/splineUtil.cc Executable file
View File

@ -0,0 +1,162 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/splineUtil.h"
#include "platform/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

84
engine/dgl/splineUtil.h Executable file
View File

@ -0,0 +1,84 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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
/// Spline utility namespace. This is used for generating pretty splines so you can get nice curved surfaces.
/// However, many polygons are required, so use these only when needed.
namespace SplineUtil
{
/// All the info that is needed to define a spline. This is optional for actually drawing a spline
/// @see drawSplineBeam
struct SplineBeamInfo
{
Point3F * camPos;
U32 numSegments;
F32 width;
SplinePatch * spline;
/// Offset for u/v texture coordinates, useful for animating the texture on the spline
F32 uvOffset;
/// Stretch for texture
F32 numTexRep;
ColorF color;
bool zeroAlphaStart; ///< first part of first segment has 0 alpha value
SplineBeamInfo()
{
dMemset( this, 0, sizeof( SplineBeamInfo ) );
numTexRep = 1.0;
}
};
/// Function for drawing the spline.
///
/// Use this if you only have a SplinePatch object and want to specify all of the parameters
///
/// @param camPos This parameter is the point at which each polygon will face.
///
/// Usually, you want all of the polygons of the spline to be facing the
/// camera, so the camera pos is a good bet for this parameter.
///
/// @param numSegments The SplineUtil will cut up the spline into numSegments segments.
///
/// More segments means more smoothness, but less framerate.
///
/// @param width The width of the spline beam.
///
/// @param spline The SplinePatch data structure for the given spline beam.
///
/// @see SplinePatch
///
/// @param uvOffset This should be called textureOffset, since it is only
/// an offset along the spline and not perpendicular. This parameter
/// can be used for "sliding" the spline texture down the spline shaft
/// to make it a little more dynamic.
///
/// @param numTexRep This is the scale of the texture so you can squish or stretch it.
void drawSplineBeam( const Point3F& camPos, U32 numSegments, F32 width,
SplinePatch &spline, F32 uvOffset = 0.0, F32 numTexRep = 1.0 );
/// Function for drawing a spline. Only needs SplineBeamInfo.
/// @see SplineBeamInfo
void drawSplineBeam( SplineBeamInfo &sbi );
}
#endif

57
engine/dgl/stripCache.cc Executable file
View File

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/stripCache.h"
#include "platform/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;
}

33
engine/dgl/stripCache.h Executable file
View File

@ -0,0 +1,33 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, 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_