www.pudn.com > zfxcengine-0.1.0.zip > ceMeshFormatQ3BSP.cpp
#include "Geometry/ceMeshFormatQ3BSP.h"
#include "Core/ceExceptions.h"
namespace ZFXCE {
//------------------------------------------------------------------------------
const INT VERION_Q3LEVEL = 46;
//------------------------------------------------------------------------------
ceMeshFormatQ3BSP::ceMeshFormatQ3BSP()
{
Desc = std::string("Quake3 Maps");
FileExt = std::string("bsp");
FileType = CE_VFS_BIN;
m_pEntityData = NULL;
m_uiNumOfVertices =0;
m_uiNumOfIndices=0;
m_uiNumOfFaces=0;
m_uiNumOfTextures=0;
m_uiNumOfLightmaps=0;
}
//------------------------------------------------------------------------------
ceMeshFormatQ3BSP::~ceMeshFormatQ3BSP()
{
if (0 != m_RenderVertices.size()) {
for (vector::iterator it = m_RenderVertices.begin();
it != m_RenderVertices.end(); ++it) {
delete *it;
}
m_RenderVertices.clear();
}
if (0 != this->m_Vertices.size()) {
for (vector::iterator it = m_Vertices.begin();
it != m_Vertices.end(); ++it){
delete *it;
}
m_Vertices.clear();
}
if (0 != m_Indices.size())
m_Indices.clear();
if (0 != m_Lightmaps.size())
m_Lightmaps.clear();
if (0 != m_Lumps.size())
m_Lumps.clear();
if (0 != m_Faces.size()) {
for (vector::iterator it = m_Faces.begin(); it != m_Faces.end(); ++it) {
delete *it;
}
m_Faces.clear();
}
if (0 != m_Textures.size())
m_Textures.clear();
delete [] m_pEntityData;
m_pEntityData = NULL;
}
//------------------------------------------------------------------------------
ceMesh *ceMeshFormatQ3BSP::Load(BYTE *pData, size_t sSize)
{
PUSH_FUNCTION;
LoadQ3BSP(pData, sSize);
return (ConvertQ3BSPToMesh());
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::ValidateFormat(BYTE *pData, size_t sSize,
UINT &uiOffset, sQ3BSPHeader *pHeader)
{
PUSH_FUNCTION;
// Read in header
pHeader = (sQ3BSPHeader*) pData;
uiOffset += sizeof(sQ3BSPHeader);
// Version and identify string validation
ce_check (VERION_Q3LEVEL == pHeader->iVersion, "False fileversion for Q3 level");
if (pHeader->strID[0] != 'I' || pHeader->strID[1] != 'B' || pHeader->strID[2] != 'S'
|| pHeader->strID[3] != 'P')
{
ce_warn(false,"Falscher Identifikationsstring!");
}
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::GetLumps(BYTE *pData, size_t sSize, UINT &uiOffset,
std::vector &Lumps)
{
PUSH_FUNCTION;
for (UINT l=0; l < kMaxLumps; ++l) {
sQ3BSPLump Lump;
memcpy(&Lump, pData+uiOffset, sizeof(sQ3BSPLump) );
uiOffset += sizeof(sQ3BSPLump);
Lumps.push_back(Lump);
}
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::CountLumps()
{
PUSH_FUNCTION;
m_uiNumOfVertices = m_Lumps[kVertices].iSize / sizeof(sQ3BSPVertex);
m_uiNumOfIndices = m_Lumps[kMeshVerts].iSize / sizeof(INT);
m_uiNumOfFaces = m_Lumps[kFaces].iSize / sizeof(sQ3BSPFace);
m_uiNumOfTextures = m_Lumps[kTextures].iSize / sizeof(sQ3BSPTexture);
m_uiNumOfLightmaps = m_Lumps[kLightmaps].iSize / sizeof(sQ3BSPLightmap);
}
//------------------------------------------------------------------------------
sQ3BSPVertex *ceMeshFormatQ3BSP::GetVertices(BYTE *pData, size_t sSize, UINT &uiOffset)
{
PUSH_FUNCTION;
sQ3BSPVertex* Vertices = new sQ3BSPVertex[m_uiNumOfVertices];
uiOffset = m_Lumps[kVertices].iOffset;
memcpy(&Vertices[0], pData+uiOffset, sizeof(sQ3BSPVertex) * m_uiNumOfVertices);
for (size_t i=0; i Lightmaps;
uiOffset = m_Lumps[kLightmaps].iOffset;
for (UINT l=0; l < m_uiNumOfLightmaps; ++l) {
sQ3BSPLightmap Lightmap;
memcpy(&Lightmap, pData+uiOffset, sizeof(sQ3BSPLightmap) );
uiOffset += sizeof(sQ3BSPLightmap);
ChangeGamma( (BYTE*) &Lightmap.bLMapData[0], 128*128*3, 3.0f);
m_Lightmaps.push_back(Lightmap);
}
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::GetEntityTest(BYTE *pData, size_t sSize, UINT &uiOffset)
{
PUSH_FUNCTION;
m_pEntityData = new CHAR[m_Lumps[kEntities].iSize];
uiOffset = m_Lumps[kEntities].iOffset;
memcpy(&m_pEntityData[0], pData+uiOffset, sizeof(CHAR) * m_Lumps[kEntities].iSize );
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::GetRenderVertices(BYTE *pData, size_t sSize,
UINT &uiOffset, const sQ3BSPVertex* Vertices)
{
sRenderVertex* RenderVertices = new sRenderVertex[m_uiNumOfVertices];
for (UINT v=0; v < m_uiNumOfVertices; ++v) {
memcpy(&RenderVertices[v].vPosition, &Vertices[v].vPosition, sizeof(ceVec3f) );
memcpy(&RenderVertices[v].vTC, &Vertices[v].vTexCoord, sizeof(ceVec2f) );
// light maps
memcpy(&RenderVertices[v].vTCLightmap, &Vertices[v].vLightmap, sizeof(ceVec2f));
// Brighten up the vertex colors a little bit
for (UINT c=0; c < 4; c++) {
const FLOAT Increase = 3.5f;
RenderVertices[v].Color[c] = (UCHAR) (Vertices[v].bColor[c] * Increase);
}
m_RenderVertices.push_back(&RenderVertices[v]);
}
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::LoadEntities(const std::string &strEntityText)
{
PUSH_FUNCTION;
const char seps[] = " \t\n\"";
char* token = strtok((char*) strEntityText.c_str(), seps );
while(true) {
if(!token)
break;
if (strcmp(token, "info_player_deathmatch") == 0 ||
strcmp(token, "info_player_start") == 0) {
token = strtok(NULL, seps);
if (0 == strcmp(token, "angle")) {
// skip angle, not needed
token = strtok(NULL, seps);
// read next token after angle
token = strtok(NULL, seps);
}
if(strcmp(token, "origin") == 0) {
const FLOAT x = (FLOAT)atof(strtok(NULL, seps) );
const FLOAT y = (FLOAT)atof(strtok(NULL, seps) );
const FLOAT z = (FLOAT)atof(strtok(NULL, seps) );
tStartPosition Pos;
Pos.vPosition = ceVec3f(x,y,z);
Pos.vLookAt = ceVec3f(x,y+1.0f, z);
m_StartPositions.push_back(Pos);
}
else
cout << "Unknown Token: \"" << token << "\""<< endl;
}
// get next token
token = strtok(NULL, seps);
}
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::ChangeGamma(BYTE *pImage, INT size, FLOAT factor)
{
PUSH_FUNCTION;
// Go through every pixel in the lightmap
for (INT i = 0; i < size / 3; i++, pImage += 3) {
FLOAT scale = 1.0f, temp = 0.0f;
FLOAT r = 0, g = 0, b = 0;
// Extract the current RGB values
r = (FLOAT) pImage[0];
g = (FLOAT) pImage[1];
b = (FLOAT) pImage[2];
// Multiply the factor by the RGB values, while keeping it to a 255 ratio
const FLOAT fVal = 1 / 255.0f;
r = r * factor * fVal;
g = g * factor * fVal;
b = b * factor * fVal;
// Check if the the values went past the highest value
if (r > 1.0f && (temp = (1.0f/r)) < scale) scale = temp;
if (g > 1.0f && (temp = (1.0f/g)) < scale) scale = temp;
if (b > 1.0f && (temp = (1.0f/b)) < scale) scale = temp;
// Get the scale for this pixel and multiply it by our pixel values
scale*=255.0f;
r*=scale;
g*=scale;
b*=scale;
// Assign the new gamma'nized RGB values to our image
pImage[0] = (BYTE)r;
pImage[1] = (BYTE)g;
pImage[2] = (BYTE)b;
}
}
//------------------------------------------------------------------------------
void ceMeshFormatQ3BSP::LoadQ3BSP(BYTE *pData, size_t sSize)
{
PUSH_FUNCTION;
// Problems : Not tested in this format, texture support does not work
// (see CreateCube with texture name for examples)
// Eventually No light map support
// Questions to : kim.kulling@web.de
// Init offset for parse level data buffer
UINT uiOffset = 0;
// Read in header
sQ3BSPHeader *pHeader = NULL;
ValidateFormat(pData, sSize, uiOffset, pHeader);
// Read in lumps of level
GetLumps(pData, sSize, uiOffset, m_Lumps);
// Count the different lumps
CountLumps();
// Read in Vertices
sQ3BSPVertex* Vertices = GetVertices(pData, sSize, uiOffset);
// Read in Indices
GetIndices(pData, sSize, uiOffset);
// Read Faces
GetFaces(pData, sSize, uiOffset);
// Read Textures
GetTextures(pData, sSize, uiOffset);
// Read Lightmaps
GetLightmaps(pData, sSize, uiOffset);
// Load entity text
GetEntityTest(pData, sSize, uiOffset);
// Load the entities
LoadEntities(m_pEntityData);
// Set render verties
GetRenderVertices(pData, sSize, uiOffset, Vertices);
}
//------------------------------------------------------------------------------
ceMesh *ceMeshFormatQ3BSP::ConvertQ3BSPToMesh()
{
ceMesh *pMesh = new ceMesh();
std::vector vertices;
std::vector colors;
unsigned char col[4];
ceColorRGBA temp;
std::vector TexturCoords;
std::vector LightCoords;
ceVec2f texcoor, lightcoor;
pMesh->SetTextureNames(m_vTextureList);
for (std::vector::iterator it = m_RenderVertices.begin();
it != m_RenderVertices.end(); ++it) {
vertices.push_back((*it)->vPosition);
memcpy(&col[0], (*it)->Color, sizeof(unsigned char)*4);
temp.r = col[0];
temp.g = col[1];
temp.b = col[2];
temp.a = col[3];
colors.push_back(temp);
TexturCoords.push_back((*it)->vTC);
LightCoords.push_back((*it)->vTCLightmap);
}
// Loop over all faces
std::vector faces;
for (std::vector::iterator it = m_Faces.begin(); it != m_Faces.end(); ++it) {
Face face;
face.UIIndices.push_back((*it)->iVertexIndex);
face.m_vTexID = (*it)->iTextureID;
face.m_uiLightMapID = (*it)->iLightmapID;
faces.push_back(face);
}
pMesh->SetFaces(faces);
pMesh->SetVertices(vertices);
pMesh->SetColor(colors);
return pMesh;
}
//------------------------------------------------------------------------------
} // Namespace ZFXCE