added everything
This commit is contained in:
50
engine/dgl/bitmapBm8.cc
Executable file
50
engine/dgl/bitmapBm8.cc
Executable 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
203
engine/dgl/bitmapBmp.cc
Executable 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
170
engine/dgl/bitmapGif.cc
Executable 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
208
engine/dgl/bitmapJpeg.cc
Executable 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
456
engine/dgl/bitmapPng.cc
Executable 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;
|
||||
}
|
1151
engine/dgl/dgl.cc
Executable file
1151
engine/dgl/dgl.cc
Executable file
File diff suppressed because it is too large
Load Diff
288
engine/dgl/dgl.h
Executable file
288
engine/dgl/dgl.h
Executable file
@ -0,0 +1,288 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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,
|
||||
F32 fSpin = 0.0f,
|
||||
bool bSilhouette = false);
|
||||
/// 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,
|
||||
F32 fSpin = 0.0f,
|
||||
bool bSilhouette = false);
|
||||
/// @}
|
||||
/// @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(const GFont *font, const Point2I &ptDraw, const UTF16 *in_string, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f);
|
||||
/// Converts UTF8 text to UTF16, and calls the UTF16 version of dglDrawText
|
||||
U32 dglDrawText(const GFont *font, const Point2I &ptDraw, const UTF8 *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(const GFont *font, const Point2I &ptDraw, const UTF16 *in_string, U32 n, const ColorI *colorTable = NULL, const U32 maxColorIndex = 9, F32 rot = 0.f);
|
||||
/// Converts UTF8 text to UTF16, and calls the UTF16 version of dglDrawTextN
|
||||
U32 dglDrawTextN(const GFont *font, const Point2I &ptDraw, const UTF8 *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 ¢er);
|
||||
/// 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( const 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
144
engine/dgl/dglMatrix.cc
Executable 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;
|
||||
}
|
||||
|
932
engine/dgl/gBitmap.cc
Executable file
932
engine/dgl/gBitmap.cc
Executable file
@ -0,0 +1,932 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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_BIG_ENDIAN)
|
||||
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_BIG_ENDIAN)
|
||||
*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:
|
||||
rColor.red = *((U16*)pLoc) >> 11;
|
||||
rColor.green = (*((U16*)pLoc) >> 6) & 0x1f;
|
||||
rColor.blue = (*((U16*)pLoc) >> 1) & 0x1f;
|
||||
rColor.alpha = (*((U16*)pLoc) & 1) ? 255 : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Bad internal format");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool GBitmap::setColor(const U32 x, const U32 y, ColorI& rColor)
|
||||
{
|
||||
if (x >= width || y >= height)
|
||||
return false;
|
||||
if (internalFormat == Palettized && pPalette == NULL)
|
||||
return false;
|
||||
|
||||
U8* pLoc = getAddress(x, y);
|
||||
|
||||
switch (internalFormat) {
|
||||
case Palettized:
|
||||
rColor = pPalette->getColor(*pLoc);
|
||||
break;
|
||||
|
||||
case Alpha:
|
||||
case Intensity:
|
||||
case Luminance:
|
||||
*pLoc = rColor.alpha;
|
||||
break;
|
||||
|
||||
case RGB:
|
||||
dMemcpy( pLoc, &rColor, 3 * sizeof( U8 ) );
|
||||
break;
|
||||
|
||||
case RGBA:
|
||||
dMemcpy( pLoc, &rColor, 4 * sizeof( U8 ) );
|
||||
break;
|
||||
|
||||
case RGB5551:
|
||||
#if defined(TORQUE_BIG_ENDIAN)
|
||||
*((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 true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------- 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
234
engine/dgl/gBitmap.h
Executable 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
74
engine/dgl/gChunkedTexManager.h
Executable 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
318
engine/dgl/gDynamicTexture.cc
Executable 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
232
engine/dgl/gDynamicTexture.h
Executable 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
|
1218
engine/dgl/gFont.cc
Executable file
1218
engine/dgl/gFont.cc
Executable file
File diff suppressed because it is too large
Load Diff
196
engine/dgl/gFont.h
Executable file
196
engine/dgl/gFont.h
Executable file
@ -0,0 +1,196 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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* constructFont(Stream& stream);
|
||||
|
||||
class TextureHandle;
|
||||
|
||||
class GFont : public ResourceInstance
|
||||
{
|
||||
friend ResourceInstance* constructFont(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;
|
||||
|
||||
bool mNeedSave;
|
||||
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) const
|
||||
{
|
||||
return mTextureSheets[index];
|
||||
}
|
||||
|
||||
/// While this is const to the outside world, it calls loadCharInfo() to load char info as it is used
|
||||
const PlatformFont::CharInfo& getCharInfo(const UTF16 in_charIndex) const;
|
||||
|
||||
static const PlatformFont::CharInfo& getDefaultCharInfo();
|
||||
|
||||
U32 getCharHeight(const UTF16 in_charIndex) const;
|
||||
U32 getCharWidth(const UTF16 in_charIndex) const;
|
||||
U32 getCharXIncrement(const UTF16 in_charIndex) const;
|
||||
|
||||
bool isValidChar(const UTF16 in_charIndex) const;
|
||||
|
||||
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 UTF16 *str16, U32 slen, U32 width, bool breakOnWhitespace) const;
|
||||
|
||||
/// These are the preferred width functions.
|
||||
U32 getStrNWidth(const UTF16*, U32 n) const;
|
||||
U32 getStrNWidthPrecise(const UTF16*, U32 n) const;
|
||||
|
||||
/// These UTF8 versions of the width functions will be deprecated, please avoid them.
|
||||
U32 getStrWidth(const UTF8*) const; // Note: ignores c/r
|
||||
U32 getStrNWidth(const UTF8*, U32 n) const;
|
||||
|
||||
U32 getStrWidthPrecise(const UTF8*) const; // Note: ignores c/r
|
||||
U32 getStrNWidthPrecise(const UTF8*, U32 n) const;
|
||||
|
||||
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() const
|
||||
{
|
||||
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
|
||||
{
|
||||
const PlatformFont::CharInfo& rChar = getCharInfo(in_charIndex);
|
||||
return rChar.xIncrement;
|
||||
}
|
||||
|
||||
inline U32 GFont::getCharWidth(const UTF16 in_charIndex) const
|
||||
{
|
||||
const PlatformFont::CharInfo& rChar = getCharInfo(in_charIndex);
|
||||
return rChar.width;
|
||||
}
|
||||
|
||||
inline U32 GFont::getCharHeight(const UTF16 in_charIndex) const
|
||||
{
|
||||
const PlatformFont::CharInfo& rChar = getCharInfo(in_charIndex);
|
||||
return rChar.height;
|
||||
}
|
||||
|
||||
inline bool GFont::isValidChar(const UTF16 in_charIndex) const
|
||||
{
|
||||
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
146
engine/dgl/gPalette.cc
Executable 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
99
engine/dgl/gPalette.h
Executable 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_
|
1767
engine/dgl/gTexManager.cc
Executable file
1767
engine/dgl/gTexManager.cc
Executable file
File diff suppressed because it is too large
Load Diff
469
engine/dgl/gTexManager.h
Executable file
469
engine/dgl/gTexManager.h
Executable file
@ -0,0 +1,469 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
// we have a slightly more complicated versions of lock() and unlock() for debug, so they are in gTexManager.cc
|
||||
#if defined(TORQUE_DEBUG)
|
||||
void lock();
|
||||
void unlock();
|
||||
#else
|
||||
inline void lock()
|
||||
{
|
||||
if ( object )
|
||||
object->refCount++;
|
||||
}
|
||||
|
||||
inline void unlock()
|
||||
{
|
||||
// Do nothing if the manager isn't active or we do not have an object
|
||||
if(!TextureManager::isActive() || (object == NULL))
|
||||
return;
|
||||
|
||||
object->refCount--;
|
||||
if (object->holding == false)
|
||||
{
|
||||
if(!object->refCount)
|
||||
TextureManager::freeTexture(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertISV(object->refCount >= 0, avar("Texture holding out of balance: %d (0x%x)", object->refCount, object->refCount));
|
||||
}
|
||||
|
||||
object = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
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()
|
||||
{
|
||||
TextureManager::refresh(object);
|
||||
}
|
||||
|
||||
void refresh(GBitmap* bmp)
|
||||
{
|
||||
AssertFatal(object->type == TerrainTexture, "Error, only terrain textures may be refreshed in this manner!");
|
||||
TextureManager::refresh(object, bmp);
|
||||
}
|
||||
|
||||
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); }
|
||||
const GBitmap* getBitmap() const { return (object ? object->bitmap : NULL); }
|
||||
bool isValid() const { return (object ? true : false); }
|
||||
/// 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
336
engine/dgl/gVectorField.cc
Executable 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
150
engine/dgl/gVectorField.h
Executable 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
97
engine/dgl/lensFlare.cc
Executable 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
65
engine/dgl/lensFlare.h
Executable 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
332
engine/dgl/materialList.cc
Executable 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
101
engine/dgl/materialList.h
Executable 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(©);
|
||||
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
171
engine/dgl/materialPropertyMap.cc
Executable 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;
|
||||
}
|
72
engine/dgl/materialPropertyMap.h
Executable file
72
engine/dgl/materialPropertyMap.h
Executable 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
162
engine/dgl/splineUtil.cc
Executable 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
84
engine/dgl/splineUtil.h
Executable 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
57
engine/dgl/stripCache.cc
Executable 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
33
engine/dgl/stripCache.h
Executable 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_
|
Reference in New Issue
Block a user