749 lines
No EOL
28 KiB
C++
749 lines
No EOL
28 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** Confidential - Westwood Studios ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : LightMap *
|
|
* *
|
|
* $Archive:: /Commando/Code/Tool $*
|
|
* *
|
|
* $Author:: Ian_l $*
|
|
* *
|
|
* $Modtime:: 6/06/01 5:40p $*
|
|
* *
|
|
* $Revision:: 35 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#ifndef _LIGHTMAPPACKER_H
|
|
#define _LIGHTMAPPACKER_H
|
|
|
|
// Includes.
|
|
#include "ProceduralTexture.h"
|
|
#include "StringBuilder.h"
|
|
#include "Triangle.h"
|
|
#include "vector.h"
|
|
#include "vector2.h"
|
|
#include "matrix3.h"
|
|
#include "listnode.h"
|
|
#include "Targa.h"
|
|
#include "w3d_file.h"
|
|
#include <srPixelConvert.hpp>
|
|
#include <srColorSurface.hpp>
|
|
|
|
|
|
// Defines.
|
|
#define UNPACKED_TEXEL_BYTE_COUNT 4 // No. of bytes for internal unpacked texel format (ARGB).
|
|
|
|
|
|
class ColorSurface : public srColorSurface
|
|
{
|
|
public:
|
|
ColorSurface (srPixelConvert::e_surfaceType pixelformat, short width, short height)
|
|
: srColorSurface (pixelformat, width, height)
|
|
{}
|
|
};
|
|
|
|
|
|
class TrueColorTarga : public Targa
|
|
{
|
|
public:
|
|
|
|
// Public functions.
|
|
TrueColorTarga();
|
|
TrueColorTarga (unsigned width, unsigned height, unsigned pixeldepth);
|
|
TrueColorTarga (unsigned width, unsigned height, unsigned pixeldepth, const W3dRGBStruct &clearcolor);
|
|
|
|
void Reformat (unsigned width, unsigned height, unsigned pixeldepth);
|
|
void Reformat (unsigned width, unsigned height, unsigned pixeldepth, const W3dRGBStruct &clearcolor);
|
|
|
|
unsigned Width() const {return (Header.Width);}
|
|
unsigned Height() const {return (Header.Height);}
|
|
unsigned Pixel_Depth() const {return (Header.PixelDepth);}
|
|
void Scale (unsigned width, unsigned height) {Scale (*this, width, height);}
|
|
void Scale (TrueColorTarga &destination) {Scale (destination, destination.Width(), destination.Height());}
|
|
void Scale (float filtererror) {Scale (*this, filtererror);}
|
|
void Transpose() {Transpose (*this);}
|
|
|
|
void Pad (unsigned padwidth, unsigned padheight, const W3dRGBStruct &padcolor, DynamicVectorClass <PackingTriangle*> &triangleptrs)
|
|
{
|
|
Pad (*this, padwidth, padheight, padcolor, triangleptrs);
|
|
}
|
|
|
|
char *Load (const char *pathname);
|
|
char *Save (const char *pathname);
|
|
void Blit (TrueColorTarga &destination, unsigned x, unsigned y);
|
|
void Scale (TrueColorTarga &destination, unsigned width, unsigned height);
|
|
int Compare (TrueColorTarga &comparison, float epsilon);
|
|
int Compare (TrueColorTarga &comparison, unsigned x, unsigned y, float epsilon);
|
|
bool Fill (const W3dRGBStruct &fillcolor);
|
|
void Add (TrueColorTarga &targa);
|
|
void Rasterize (TrueColorTarga &destination, const W3dRGBStruct &fillcolor, unsigned vertexcount, const W3dRGBStruct *vertexcolors, Vector2 *uvs);
|
|
|
|
bool Get_Color (const Vector2 &t, W3dRGBStruct &color) const;
|
|
bool Set_Color (unsigned x, unsigned y, const W3dRGBStruct &color);
|
|
|
|
protected:
|
|
|
|
enum TransposeEnum {
|
|
UNTRANSPOSED,
|
|
TRANSPOSED,
|
|
TRANSPOSE_COUNT
|
|
};
|
|
|
|
struct UnpackedTexelStruct {
|
|
|
|
UnpackedTexelStruct () {}
|
|
UnpackedTexelStruct (unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
Set (r, g, b, a);
|
|
}
|
|
|
|
void Set (unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
Byte [0] = a;
|
|
Byte [1] = r;
|
|
Byte [2] = g;
|
|
Byte [3] = b;
|
|
}
|
|
|
|
unsigned char Alpha() const {return (Byte [0]);}
|
|
unsigned char Red() const {return (Byte [1]);}
|
|
unsigned char Green() const {return (Byte [2]);}
|
|
unsigned char Blue() const {return (Byte [3]);}
|
|
|
|
// Equality operator.
|
|
bool operator == (const UnpackedTexelStruct &t) {
|
|
ASSERT (sizeof (unsigned long) == sizeof (Byte));
|
|
return (*((unsigned long*) Byte) == *((unsigned long*) t.Byte));
|
|
}
|
|
|
|
// Inequality operator.
|
|
bool operator != (const UnpackedTexelStruct &t) {
|
|
return (!(*this == t));
|
|
}
|
|
|
|
// Addition operator.
|
|
UnpackedTexelStruct operator += (UnpackedTexelStruct t)
|
|
{
|
|
Byte [0] = MIN (((unsigned) Byte [0]) + ((unsigned) t.Byte [0]), (unsigned) UCHAR_MAX);
|
|
Byte [1] = MIN (((unsigned) Byte [1]) + ((unsigned) t.Byte [1]), (unsigned) UCHAR_MAX);
|
|
Byte [2] = MIN (((unsigned) Byte [2]) + ((unsigned) t.Byte [2]), (unsigned) UCHAR_MAX);
|
|
Byte [3] = MIN (((unsigned) Byte [3]) + ((unsigned) t.Byte [3]), (unsigned) UCHAR_MAX);
|
|
return (*this);
|
|
}
|
|
|
|
// Public data.
|
|
unsigned char Byte [UNPACKED_TEXEL_BYTE_COUNT];
|
|
};
|
|
|
|
struct PointStruct {
|
|
|
|
// Equality operator.
|
|
bool operator == (const PointStruct &p) {
|
|
return ((X == p.X) && (Y == p.Y));
|
|
}
|
|
|
|
// Inequality operator.
|
|
bool operator != (const PointStruct &p) {
|
|
return (!(*this == p));
|
|
}
|
|
|
|
// Public data.
|
|
int X;
|
|
int Y;
|
|
};
|
|
|
|
void Clear (const UnpackedTexelStruct &cleartexel);
|
|
|
|
private:
|
|
|
|
// Inlines.
|
|
unsigned char *Get_Texel (int x, int y) const;
|
|
UnpackedTexelStruct *Unpack_Texel (unsigned char *packedtexelptr, unsigned packedbytespertexel, UnpackedTexelStruct &unpackedtexel) const;
|
|
void Pack_Texel (const UnpackedTexelStruct &unpackedtexel, unsigned char *packedtexelptr, unsigned packedbytespertexel);
|
|
|
|
// Static functions.
|
|
static srPixelConvert::e_surfaceType Pixel_Format (unsigned pixeldepth);
|
|
|
|
void Scale (TrueColorTarga &destination, float filtererror);
|
|
void Transpose (TrueColorTarga &destination);
|
|
bool Fill_Four_Connected (unsigned x, unsigned y, const UnpackedTexelStruct &filltexel, DynamicVectorClass <PointStruct> &fourconnectedarray);
|
|
void Pad (TrueColorTarga &destination, unsigned verticalpadthickness, unsigned horizontalpadthickness, const W3dRGBStruct &padcolor, DynamicVectorClass <PackingTriangle*> &triangleptrs);
|
|
};
|
|
|
|
|
|
class Page : public TrueColorTarga
|
|
{
|
|
public:
|
|
|
|
// Public functions.
|
|
Page (unsigned bitdepth, const W3dRGBStruct &clearcolor);
|
|
~Page ();
|
|
|
|
bool Pack (TrueColorTarga &targa, float epsilon, DynamicVectorClass <PackingTriangle*> &triangleptrs);
|
|
|
|
|
|
float Packing_Efficiency() const
|
|
{
|
|
return (((float) UsedTexelCount) / (((unsigned) Width()) * ((unsigned) Height())));
|
|
}
|
|
|
|
float Replica_Efficiency() const
|
|
{
|
|
return (((float) ReplicaTexelCount) / (((unsigned) Width()) * ((unsigned) Height())));
|
|
}
|
|
|
|
private:
|
|
|
|
class Region : public GenericNode {
|
|
|
|
public:
|
|
|
|
// Public functions.
|
|
Region () {}
|
|
Region (const Region ®ion)
|
|
{
|
|
Set (region.X0, region.Y0, region.X1, region.Y1);
|
|
}
|
|
|
|
unsigned Width () {return (X1 - X0 + 1);}
|
|
unsigned Height() {return (Y1 - Y0 + 1);}
|
|
|
|
void Set (unsigned x0, unsigned y0, unsigned x1, unsigned y1)
|
|
{
|
|
X0 = x0; Y0 = y0; X1 = x1; Y1 = y1;
|
|
}
|
|
|
|
bool Accomodates (unsigned width, unsigned height, Region &targetregion);
|
|
bool Intersects (const Region &targetregion, unsigned &subregioncount, Region **subregions);
|
|
|
|
// Public data.
|
|
unsigned X0, Y0;
|
|
unsigned X1, Y1;
|
|
};
|
|
|
|
// Private functions.
|
|
bool Replica_Region (TrueColorTarga &targa, float epsilon, Region &replicaregion);
|
|
bool Lowest_Cost_Region (TrueColorTarga &targa, unsigned &lowestcost, Region &lowestcostregion);
|
|
void Insert_Region (const Region &insertionregion);
|
|
bool Contains (const Region &testregion);
|
|
|
|
// Statistics functions.
|
|
void Reset_Statistics();
|
|
|
|
// Private data.
|
|
GenericList VacantRegionList;
|
|
GenericList UsedRegionList;
|
|
|
|
// Statistics counters.
|
|
unsigned AssetCount;
|
|
unsigned UsedTexelCount;
|
|
unsigned ReplicaTexelCount;
|
|
};
|
|
|
|
|
|
class TargaLoader {
|
|
|
|
public:
|
|
|
|
// Public functions.
|
|
TargaLoader (float samplerate, W3dRGBStruct fillcolor);
|
|
~TargaLoader();
|
|
|
|
TrueColorTarga *Load (const Triangle &triangle);
|
|
|
|
private:
|
|
|
|
struct TargaCacheStruct {
|
|
|
|
TargaCacheStruct()
|
|
{
|
|
Ptr = NULL;
|
|
}
|
|
|
|
~TargaCacheStruct()
|
|
{
|
|
if (Ptr != NULL) delete Ptr;
|
|
}
|
|
|
|
// Equality operator.
|
|
bool operator == (const TargaCacheStruct &t) {
|
|
return ((ID == t.ID) && (Ptr == t.Ptr));
|
|
}
|
|
|
|
// Inequality operator.
|
|
bool operator != (const TargaCacheStruct &t) {
|
|
return (!(*this == t));
|
|
}
|
|
|
|
// Data.
|
|
unsigned ID;
|
|
TrueColorTarga *Ptr;
|
|
};
|
|
|
|
// Private functions.
|
|
TargaLoader() {}
|
|
|
|
unsigned Index (unsigned id)
|
|
{
|
|
return (id % ((unsigned) Cache.Length()));
|
|
}
|
|
|
|
// Private data.
|
|
VectorClass <TargaCacheStruct> Cache; // A simple array of targacache objects.
|
|
DynamicVectorClass <TrueColorTarga*> CleanupList; // List of targas that have been displaced from the cache but cannot
|
|
// yet be deleted because they may still be referenced.
|
|
float SampleRate; // No. of texels per unit length.
|
|
W3dRGBStruct FillColor; // Color to replace during fill operations.
|
|
};
|
|
|
|
|
|
class TrianglePacker {
|
|
|
|
public:
|
|
|
|
TrianglePacker (const PackingTriangle *principaltriangleptr, const DynamicVectorClass <Triangle> &adjtriangles, unsigned groupid, unsigned edgeblendthickness, float samplerate, W3dRGBStruct fillcolor);
|
|
|
|
DynamicVectorClass <PackingTriangle*> &Principal_Triangles() {return (PrincipalTriangles);}
|
|
|
|
// Query functions.
|
|
unsigned Width() const {return (UpperBound.U - LowerBound.U);}
|
|
unsigned Height() const {return (UpperBound.V - LowerBound.V);}
|
|
|
|
// Operations.
|
|
TrianglePacker *Merge (const TrianglePacker &trianglepacker);
|
|
void Rasterize (TargaLoader &targaloader, ProceduralTexture *proceduraltexture, TrueColorTarga &rasterizedtarga);
|
|
|
|
// Statistics.
|
|
unsigned Adjacent_Face_Count() const
|
|
{
|
|
return (AdjacentTriangles [ADJACENT_PROJECTION_COMMON].Count() +
|
|
AdjacentTriangles [ADJACENT_PROJECTION_VALID].Count() +
|
|
AdjacentTriangles [ADJACENT_PROJECTION_NONE].Count());
|
|
}
|
|
|
|
unsigned Blended_Face_Count() const
|
|
{
|
|
return (AdjacentTriangles [ADJACENT_PROJECTION_COMMON].Count() +
|
|
AdjacentTriangles [ADJACENT_PROJECTION_VALID].Count());
|
|
}
|
|
|
|
float Edge_Blend_Area() const;
|
|
|
|
private:
|
|
|
|
enum ProjectionEnum {
|
|
PROJECTION_Y_POSITIVE,
|
|
PROJECTION_Y_NEGATIVE,
|
|
PROJECTION_Z_POSITIVE,
|
|
PROJECTION_Z_NEGATIVE,
|
|
PROJECTION_X_POSITIVE,
|
|
PROJECTION_X_NEGATIVE,
|
|
PROJECTION_COUNT
|
|
};
|
|
|
|
enum AdjacentProjectionEnum {
|
|
ADJACENT_PROJECTION_COMMON, // Adjacent triangles that use the same projection as this object.
|
|
ADJACENT_PROJECTION_VALID, // Adjacent triangles that map to a different projection but have non-zero area if object's projection is used.
|
|
ADJACENT_PROJECTION_NONE, // Adjacent triangles that cannot be projected using object's projection.
|
|
ADJACENT_PROJECTION_COUNT
|
|
};
|
|
|
|
class ProjectionTriangle {
|
|
|
|
public:
|
|
|
|
// Public functions.
|
|
ProjectionTriangle() {}
|
|
ProjectionTriangle (const Vector3 *points, const Vector2 *sourceuvs, const TrueColorTarga *sourcetargaptr, const Vector2 *projectionuvs);
|
|
|
|
// Public data.
|
|
Vector3 Points [Triangle::VERTICES_COUNT];
|
|
Vector2 SourceUVs [Triangle::VERTICES_COUNT];
|
|
TrueColorTarga *SourceTargaPtr;
|
|
Vector2 ProjectionUVs [Triangle::VERTICES_COUNT];
|
|
};
|
|
|
|
class SampleSurface {
|
|
|
|
public:
|
|
|
|
// Public functions.
|
|
SampleSurface (unsigned width, unsigned height, ProceduralTexture *blendtexture = NULL);
|
|
|
|
bool Sample (const Vector2 &samplepoint, const ProjectionTriangle &projectiontriangle, unsigned priority);
|
|
bool Sample (float alpha, float beta, const ProjectionTriangle &projectiontriangle, unsigned priority);
|
|
|
|
bool Get_Color (unsigned x, unsigned y, W3dRGBStruct &color)
|
|
{
|
|
SampleStruct *sampleptr;
|
|
|
|
ASSERT ((x < Width) && (y < Height));
|
|
sampleptr = Surface + (y * Width + x);
|
|
if (sampleptr->Count > 0) {
|
|
|
|
float oocount;
|
|
unsigned r, g, b;
|
|
|
|
oocount = 1.0f / sampleptr->Count;
|
|
r = sampleptr->Red * oocount;
|
|
g = sampleptr->Green * oocount;
|
|
b = sampleptr->Blue * oocount;
|
|
color.Set ((uint8) MIN (r, UCHAR_MAX), (uint8) MIN (g, UCHAR_MAX), (uint8) MIN (b, UCHAR_MAX));
|
|
return (true);
|
|
} else {
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
unsigned Priority (unsigned x, unsigned y)
|
|
{
|
|
SampleStruct *sampleptr;
|
|
|
|
ASSERT ((x < Width) && (y < Height));
|
|
sampleptr = Surface + (y * Width + x);
|
|
return (sampleptr->Priority);
|
|
}
|
|
|
|
float Sampling_Ratio() {return (((float) SampledTexelCount) / ((float) (Width * Height)));}
|
|
|
|
private:
|
|
|
|
struct SampleStruct {
|
|
unsigned Red;
|
|
unsigned Green;
|
|
unsigned Blue;
|
|
unsigned Count;
|
|
unsigned Priority;
|
|
};
|
|
|
|
SampleSurface() {}
|
|
|
|
unsigned Width;
|
|
unsigned Height;
|
|
unsigned SampledTexelCount;
|
|
SampleStruct *Surface;
|
|
ProceduralTexture *BlendTexture;
|
|
};
|
|
|
|
// Private functions.
|
|
TrianglePacker() {}
|
|
TrianglePacker (const TrianglePacker &trianglepacker); // Copy constructor.
|
|
void Set_Bounds();
|
|
bool Can_Project (const Vector3 &normal);
|
|
Vector2 Project (const Vector3 &point) const;
|
|
// void Get_Projection_Triangle (const Triangle &triangle, ProjectionTriangleStruct &projectiontriangle);
|
|
bool Sample (const Vector2 &samplepoint, const ProjectionTriangle &projectiontriangle, W3dRGBStruct &color);
|
|
|
|
static ProjectionEnum Get_Projection (const Vector3 &normal);
|
|
|
|
// Private data.
|
|
ProjectionEnum Projection; // Texture projection to be used for rasterization.
|
|
unsigned GroupID;
|
|
unsigned EdgeBlendThickness;
|
|
float SampleRate; // No. of texels per unit length.
|
|
W3dRGBStruct FillColor; // Color to replace during fill operations.
|
|
DynamicVectorClass <PackingTriangle*> PrincipalTriangles; // Set of triangles that will be rasterized in their entirety (ie. not edge blended).
|
|
DynamicVectorClass <Triangle> AdjacentTriangles [ADJACENT_PROJECTION_COUNT]; // Set of triangles that will be edge-blended.
|
|
Vector2 LowerBound; // Lower bound of all principal triangle points projected onto the texel plane.
|
|
Vector2 UpperBound; // Upper bound of all principal triangle points projected onto the texel plane.
|
|
};
|
|
|
|
|
|
class LightmapPacker {
|
|
|
|
public:
|
|
|
|
enum ThicknessEnum {
|
|
EDGE_BLEND_THICKNESS = 2 // No. of texels to pad around every packed map.
|
|
// NOTE: The edge blend thickness is designed to prevent
|
|
// bleeding between adjacent maps under mip-mapping. The
|
|
// no, of allowable mip-maps is dependant upon this
|
|
// thickness value.
|
|
};
|
|
|
|
enum StatisticsEnum {
|
|
|
|
STATISTICS_PAGE_FORMAT,
|
|
STATISTICS_LIGHTMAPS_PROCESSED,
|
|
STATISTICS_ADJACENT_FACE_BLEND_PERCENTAGE,
|
|
STATISTICS_EDGE_BLEND_EFFICIENCY,
|
|
STATISTICS_SCALING_EFFICIENCY,
|
|
STATISTICS_PAGES_CREATED,
|
|
STATISTICS_PACKING_EFFICIENCY,
|
|
STATISTICS_CULLING_EFFICIENCY,
|
|
STATISTICS_TEXTURE_SWAP_EFFICIENCY,
|
|
STATISTICS_OVERSIZE_LIGHTMAPS,
|
|
STATISTICS_COUNT,
|
|
|
|
STATISTICS_STRING_SIZE = 32 // Size of statistic string in bytes.
|
|
};
|
|
|
|
LightmapPacker();
|
|
Finish();
|
|
~LightmapPacker();
|
|
|
|
void Submit (PackingTriangle *principaltriangleptr, const DynamicVectorClass <Triangle> &adjtriangles);
|
|
TrianglePacker *Merge (TrianglePacker *trianglepackerptr);
|
|
void Pack (ProceduralTexture *proceduraltexture = NULL);
|
|
void Pack (TrueColorTarga &targa, DynamicVectorClass <PackingTriangle*> &triangleptrs);
|
|
|
|
static const char *Lightmap_Pathname (unsigned pageindex);
|
|
static const char *Asset_Directory();
|
|
static const char *Asset_Directory (const char *filename);
|
|
static void Delete_Assets();
|
|
static void Copy_Assets (const char *pathname);
|
|
static const char *Get_Statistic (unsigned index) {ASSERT (index < STATISTICS_COUNT); return (_Statistics [index]);}
|
|
|
|
private:
|
|
|
|
// Statistics functions.
|
|
void Reset_Statistics();
|
|
void Update_Statistics (const Page &page);
|
|
void Update_Statistics (const TrianglePacker &trianglepacker);
|
|
void Collate_Statistics();
|
|
|
|
W3dRGBStruct FillColor; // Color used to pad unused texels in lightmaps.
|
|
float ScaleFactor; // Global lightmap scaling factor (0.0...1.0).
|
|
float FilterError; // Maximum allowed variance between a color component of original
|
|
// lightmap and that of packed lightmap, expressed as a fraction
|
|
// of color component's total range ie. a setting of 0.0 will
|
|
// allow no variance (packed lightmap must match original) and
|
|
// a setting of 1.0 allows complete variance.
|
|
float SampleRate; // Sample rate used by rasterizers (such as Edge_Blend()) in texels per unit length.
|
|
unsigned PageBitDepth; // Bit depth of page texels.
|
|
|
|
|
|
int CurrentPageIndex; // Current page (-1 indicates no page exists).
|
|
|
|
DynamicVectorClass <TrianglePacker*> TrianglePackerPtrs;
|
|
DynamicVectorClass <Page*> PagePtrs;
|
|
TextureNameNode *PlaceholderTextureNameNodePtr;
|
|
|
|
// Statistics counters.
|
|
unsigned FaceCount;
|
|
unsigned LightmapCount;
|
|
unsigned AdjacentFaceCount;
|
|
unsigned BlendedFaceCount;
|
|
double EdgeBlendAreaSum;
|
|
__int64 UnscaledTexelCount;
|
|
__int64 ScaledTexelCount;
|
|
double PackingEfficiencySum;
|
|
double ReplicaEfficiencySum;
|
|
unsigned TextureSwapCount;
|
|
unsigned OversizeCount;
|
|
unsigned AllFillColorCount;
|
|
|
|
static unsigned _BasePageIndex;
|
|
static char _Statistics [STATISTICS_COUNT][STATISTICS_STRING_SIZE];
|
|
};
|
|
|
|
|
|
/***********************************************************************************************
|
|
* TrueColorTarga::Get_Color -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/27/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
inline bool TrueColorTarga::Get_Color (const Vector2 &t, W3dRGBStruct &color) const
|
|
{
|
|
int x, y;
|
|
unsigned char *texelptr;
|
|
UnpackedTexelStruct unpackedtexel;
|
|
|
|
x = t.U * Width();
|
|
y = t.V * Height();
|
|
texelptr = Get_Texel (x, y);
|
|
if (texelptr == NULL) return (false);
|
|
Unpack_Texel (texelptr, TGA_BytesPerPixel (Pixel_Depth()), unpackedtexel);
|
|
color.Set (unpackedtexel.Red(), unpackedtexel.Green(), unpackedtexel.Blue());
|
|
return (true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* TrueColorTarga::Set_Color -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/27/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
inline bool TrueColorTarga::Set_Color (unsigned x, unsigned y, const W3dRGBStruct &color)
|
|
{
|
|
UnpackedTexelStruct unpackedtexel (color.R, color.G, color.B, 0);
|
|
|
|
unsigned char *texelptr;
|
|
|
|
texelptr = Get_Texel (x, y);
|
|
if (texelptr != NULL) {
|
|
Pack_Texel (unpackedtexel, texelptr, TGA_BytesPerPixel (Pixel_Depth()));
|
|
return (true);
|
|
} else {
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* TrueColorTarga::Get_Texel -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 9/27/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
inline unsigned char *TrueColorTarga::Get_Texel (int x, int y) const
|
|
{
|
|
// Check for (x, y) out of range.
|
|
if ((x < 0) || (x >= ((int) Width ()))) return (NULL);
|
|
if ((y < 0) || (y >= ((int) Height()))) return (NULL);
|
|
|
|
return ((unsigned char*) GetImage()) + (((Width() * y) + x) * TGA_BytesPerPixel (Pixel_Depth()));
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* TrueColorTarga::Unpack_Texel -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 9/27/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
inline TrueColorTarga::UnpackedTexelStruct *TrueColorTarga::Unpack_Texel (unsigned char *packedtexelptr, unsigned packedbytespertexel, UnpackedTexelStruct &unpackedtexel) const
|
|
{
|
|
switch (packedbytespertexel) {
|
|
|
|
case 4:
|
|
|
|
// Packed format same as unpacked format.
|
|
ASSERT (sizeof (UnpackedTexelStruct) == 4);
|
|
unpackedtexel = *((UnpackedTexelStruct*) packedtexelptr);
|
|
break;
|
|
|
|
case 3:
|
|
|
|
// Unpack to ordering ARGB. Set Alpha to zero.
|
|
unpackedtexel.Byte [0] = 0; // Alpha
|
|
unpackedtexel.Byte [1] = *(packedtexelptr + 0); // Red
|
|
unpackedtexel.Byte [2] = *(packedtexelptr + 1); // Green
|
|
unpackedtexel.Byte [3] = *(packedtexelptr + 2); // Blue
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
static unsigned char _alpha [2] = {0x00, 0xff};
|
|
|
|
unsigned short packedtexel = *((unsigned short*) packedtexelptr);
|
|
|
|
// Unpack to ordering ARGB. Bit replicate Alpha.
|
|
unpackedtexel.Byte [0] = _alpha [packedtexel >> 15]; // Alpha
|
|
unpackedtexel.Byte [1] = ((packedtexel & 0x7c00) >> 7) | 0x3; // Red
|
|
unpackedtexel.Byte [2] = ((packedtexel & 0x03e0) >> 2) | 0x3; // Green
|
|
unpackedtexel.Byte [3] = ((packedtexel & 0x001f) << 3) | 0x3; // Blue
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unrecognized byte count.
|
|
ASSERT (0);
|
|
break;
|
|
}
|
|
return (&unpackedtexel);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* TrueColorTarga::Pack_Texel -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 9/27/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
inline void TrueColorTarga::Pack_Texel (const UnpackedTexelStruct &unpackedtexel, unsigned char *packedtexelptr, unsigned packedbytespertexel)
|
|
{
|
|
switch (packedbytespertexel) {
|
|
|
|
case 4:
|
|
*(packedtexelptr + 0) = unpackedtexel.Byte [0];
|
|
*(packedtexelptr + 1) = unpackedtexel.Byte [1];
|
|
*(packedtexelptr + 2) = unpackedtexel.Byte [2];
|
|
*(packedtexelptr + 3) = unpackedtexel.Byte [3];
|
|
break;
|
|
|
|
case 3:
|
|
|
|
// Pack to ordering RGB. Lose Alpha.
|
|
*(packedtexelptr + 0) = unpackedtexel.Byte [1];
|
|
*(packedtexelptr + 1) = unpackedtexel.Byte [2];
|
|
*(packedtexelptr + 2) = unpackedtexel.Byte [3];
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
unsigned a, r, g, b;
|
|
|
|
// Pack to ordering ARGB. Round Alpha, Red, Green, Blue.
|
|
a = unpackedtexel.Byte [0] >> 7;
|
|
r = MIN (0x1f, (unpackedtexel.Byte [1] >> 3) + ((unpackedtexel.Byte [1] & 0x4) >> 2));
|
|
g = MIN (0x1f, (unpackedtexel.Byte [2] >> 3) + ((unpackedtexel.Byte [2] & 0x4) >> 2));
|
|
b = MIN (0x1f, (unpackedtexel.Byte [3] >> 3) + ((unpackedtexel.Byte [3] & 0x4) >> 2));
|
|
*((unsigned short*) packedtexelptr) = ((a << 15) | (r << 10) | (g << 5) | b);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unrecognized byte count.
|
|
ASSERT (0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#endif // LIGHTMAPPACKER_H
|