4032 lines
166 KiB
C++
4032 lines
166 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:: 7/24/01 4:56p $*
|
|
* *
|
|
* $Revision:: 65 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
// Includes.
|
|
#include "StdAfx.h"
|
|
#include "LightMap.h"
|
|
#include "LightMapDoc.h"
|
|
#include "MainFrm.h"
|
|
#include "StringBuilder.h"
|
|
#include "aabtreebuilder.h"
|
|
#include "meshmatdesc.h"
|
|
#include "ramfile.h"
|
|
#include "vector3i.h"
|
|
#include "w3d_file.h"
|
|
#include "wwmath.h"
|
|
#include <stdlib.h>
|
|
#include <winbase.h>
|
|
|
|
|
|
// Static data.
|
|
const char *LightMapDoc::_TemporarySolveFilename [TEMPORARY_SOLVE_FILENAME_COUNT] = { // Name of temporary file created when a solve is inserted.
|
|
"~S0",
|
|
"~S1"
|
|
};
|
|
|
|
const char *LightMapDoc::_TemporaryOptimizeFilename = "~O"; // Name of temporary file created when a document is optimized.
|
|
const char *LightMapDoc::_TemporaryReorderFilename = "~R"; // Name of temporary file created when a document is reordered.
|
|
|
|
// The following is maintained by MFC tools.
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
IMPLEMENT_DYNCREATE(LightMapDoc, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(LightMapDoc, CDocument)
|
|
//{{AFX_MSG_MAP(LightMapDoc)
|
|
ON_COMMAND(ID_FILE_SAVE, OnFileSave)
|
|
ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
|
|
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
|
|
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::LightMapDoc -- Constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::LightMapDoc() :
|
|
W3dFile (NULL),
|
|
MeshCount (0),
|
|
TriangleCount (0),
|
|
CanInsertSolve (false),
|
|
SolveCount (0)
|
|
{
|
|
MeshStatus.Set_Growth_Step (512);
|
|
|
|
// LightMapDoc implicitly references some Surrender objects. Thus Surrender must be initialized here.
|
|
srInit();
|
|
|
|
// Get the solve to delete any assets left over from a previous session.
|
|
LightscapeSolve::Delete_Assets();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::~LightMapDoc -- Destructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::~LightMapDoc()
|
|
{
|
|
char pathname [_MAX_PATH];
|
|
|
|
// Clean-up. Delete any temporary files (if they exist).
|
|
for (unsigned f = 0; f < TEMPORARY_SOLVE_FILENAME_COUNT; f++) {
|
|
strcpy (pathname, theApp.Working_Path());
|
|
strcat (pathname, _TemporarySolveFilename [f]);
|
|
strcat (pathname, theApp.Instance_Name());
|
|
DeleteFile (pathname);
|
|
}
|
|
strcpy (pathname, theApp.Working_Path());
|
|
strcat (pathname, _TemporaryOptimizeFilename);
|
|
strcat (pathname, theApp.Instance_Name());
|
|
DeleteFile (pathname);
|
|
strcpy (pathname, theApp.Working_Path());
|
|
strcat (pathname, _TemporaryReorderFilename);
|
|
strcat (pathname, theApp.Instance_Name());
|
|
DeleteFile (pathname);
|
|
|
|
// Get the solve to delete its assets.
|
|
LightscapeSolve::Delete_Assets();
|
|
|
|
// LightMapDoc initializes Surrender (see constructor). Thus Surrender must be exited here.
|
|
srExit();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnNewDocument -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
BOOL LightMapDoc::OnNewDocument()
|
|
{
|
|
if (!CDocument::OnNewDocument()) {
|
|
return (FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnOpenDocument -- Open a document file (but do not read it yet). *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
BOOL LightMapDoc::OnOpenDocument (LPCTSTR pathname)
|
|
{
|
|
const char *openedtext = "Document opened"; // Status bar messages.
|
|
const char *notopenedtext = "Document not opened";
|
|
|
|
if (strlen (pathname) > 0) {
|
|
|
|
// Prompt for the existing document to be saved.
|
|
if (SaveModified()) {
|
|
|
|
CMainFrame *frameptr = (CMainFrame*) AfxGetApp()->m_pMainWnd;
|
|
CStatusBar *statusptr = &(frameptr->m_wndStatusBar);
|
|
|
|
// Delete contents of any previous document.
|
|
DeleteContents();
|
|
|
|
// Open a w3d document for read access.
|
|
W3dFile = new RawFileClass (pathname);
|
|
ASSERT (W3dFile != NULL);
|
|
|
|
// NOTE: RawFileClass will not keep a copy of the filename unless Set_Name()
|
|
// is explicitly called.
|
|
W3dFile->Set_Name (pathname);
|
|
|
|
// Check that this is a valid w3d document.
|
|
if (Check_Document()) {
|
|
|
|
// Return success.
|
|
statusptr->SetPaneText (0, openedtext);
|
|
|
|
// Make a copy of the name of the file for later reference.
|
|
_splitpath (pathname, NULL, NULL, DocumentName, NULL);
|
|
|
|
return (TRUE);
|
|
|
|
} else {
|
|
|
|
// Clean-up.
|
|
delete W3dFile;
|
|
W3dFile = NULL;
|
|
|
|
// Return failure.
|
|
statusptr->SetPaneText (0, notopenedtext);
|
|
return (FALSE);
|
|
}
|
|
|
|
} else {
|
|
|
|
// Return failure.
|
|
return (FALSE);
|
|
}
|
|
|
|
} else {
|
|
|
|
// Return failure.
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Check_Document -- Is the current open document a valid w3d file? *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
bool LightMapDoc::Check_Document()
|
|
{
|
|
ASSERT (W3dFile != NULL);
|
|
W3dFile->Open (FileClass::READ);
|
|
|
|
ChunkLoadClass w3dchunk (W3dFile);
|
|
|
|
try {
|
|
|
|
unsigned meshcount;
|
|
unsigned anomalycount;
|
|
unsigned trianglecount;
|
|
|
|
// While there are chunks...
|
|
meshcount = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
// Is this a mesh chunk?
|
|
if (w3dchunk.Cur_Chunk_ID() == W3D_CHUNK_MESH) {
|
|
|
|
W3dMeshHeader3Struct header;
|
|
unsigned chunkmeshheader3count = 0;
|
|
|
|
// If the first chunk is not the mesh header then the mesh is invalid/corrupt.
|
|
w3dchunk.Open_Chunk();
|
|
if (w3dchunk.Cur_Chunk_ID() != W3D_CHUNK_MESH_HEADER3) throw ("A mesh does not start with a valid mesh header (W3D_CHUNK_MESH_HEADER3).");
|
|
if (w3dchunk.Read (&header, sizeof (header)) != sizeof (header)) throw ("Cannot read data in W3D_CHUNK_MESH_HEADER3.");
|
|
if (header.Version != W3D_CURRENT_MESH_VERSION) throw ("An unsupported mesh version has been found.");
|
|
|
|
chunkmeshheader3count++;
|
|
w3dchunk.Close_Chunk();
|
|
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MESH_HEADER3:
|
|
chunkmeshheader3count++;
|
|
break;
|
|
|
|
default:
|
|
|
|
// Do nothing.
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// Check for missing/too many header chunks.
|
|
if (chunkmeshheader3count != 1) throw ("A mesh does not contain exactly one chunk W3D_CHUNK_MESH_HEADER3.");
|
|
|
|
meshcount++;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// While there are chunks...
|
|
W3dFile->Seek (0, SEEK_SET);
|
|
anomalycount = 0;
|
|
trianglecount = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
// Is this a mesh chunk?
|
|
if (w3dchunk.Cur_Chunk_ID() == W3D_CHUNK_MESH) {
|
|
|
|
char *meshfilebuffer;
|
|
|
|
meshfilebuffer = new char [w3dchunk.Cur_Chunk_Length()];
|
|
ASSERT (meshfilebuffer != NULL);
|
|
if (w3dchunk.Read (meshfilebuffer, w3dchunk.Cur_Chunk_Length()) != w3dchunk.Cur_Chunk_Length()) throw ("Cannot read data in W3D_CHUNK_MESH.");
|
|
|
|
RAMFileClass meshfile (meshfilebuffer, w3dchunk.Cur_Chunk_Length());
|
|
MeshInfoStruct meshinfo (meshfile);
|
|
MeshAnomalyStruct meshanomaly (meshinfo);
|
|
MeshStatusStruct meshstatus (meshinfo.Header.MeshName, meshinfo.Header.NumTris, meshanomaly.MeshAnomalies);
|
|
|
|
if (meshanomaly.MeshAnomalies != 0) anomalycount++;
|
|
trianglecount += meshstatus.TriangleCount;
|
|
MeshStatus.Add (meshstatus);
|
|
|
|
// A solve can be inserted if a vertex solve and/or a lightmap solve can be inserted.
|
|
CanInsertSolve |= (meshstatus.Can_Insert_Vertex_Solve() || meshstatus.Can_Insert_Multi_Pass_Solve() || meshstatus.Can_Insert_Multi_Texture_Solve());
|
|
|
|
delete [] meshfilebuffer;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
W3dFile->Close();
|
|
MeshCount = meshcount;
|
|
TriangleCount = trianglecount;
|
|
|
|
if (anomalycount > 0) {
|
|
|
|
const char *anomalytext =
|
|
"%d meshes have mesh anomalies associated with them. If the anomaly is serious, a\
|
|
vertex or lightmap solve cannot be inserted. Check each mesh for specific anomalies\
|
|
by left-clicking on the mesh name in the list.";
|
|
|
|
StringBuilder anomalymessage (8192);
|
|
|
|
anomalymessage.Copy (anomalytext, anomalycount);
|
|
MessageBox (NULL, anomalymessage.String(), "Attention", MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
|
}
|
|
|
|
return (true);
|
|
|
|
} catch (const char *message) {
|
|
|
|
const char *invalidprefix = "This w3d file is not valid because:\n\n";
|
|
|
|
StringBuilder invalidmessage (8192);
|
|
|
|
// Clean-up.
|
|
MeshStatus.Clear();
|
|
W3dFile->Close();
|
|
|
|
// Report to user why document cannot be opened.
|
|
invalidmessage.Copy (invalidprefix);
|
|
invalidmessage.Concatenate (message);
|
|
MessageBox (NULL, invalidmessage.String(), NULL, MB_ICONERROR | MB_SETFOREGROUND);
|
|
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* MeshInfoStruct::MeshInfoStruct -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::MeshInfoStruct::MeshInfoStruct (FileClass &meshfile)
|
|
{
|
|
ChunkLoadClass w3dchunk (&meshfile);
|
|
|
|
unsigned s, materialpass;
|
|
|
|
// Initialize the member fields.
|
|
memset (&Header, 0x0, sizeof (Header));
|
|
TriangleChunk = NULL;
|
|
VertexChunk = NULL;
|
|
for (s = 0; s < PrelitModeEnum::COUNT; s++) {
|
|
memset (&MaterialInfo [s], 0x0, sizeof (MaterialInfo [s]));
|
|
VertexMaterials [s] = NULL;
|
|
ShaderChunk [s] = NULL;
|
|
for (unsigned p = 0; p < MeshMatDescClass::MAX_PASSES; p++) {
|
|
ShaderIdChunk [s][p] = NULL;
|
|
}
|
|
}
|
|
DIGsExist = false;
|
|
SCGsExist = false;
|
|
DeformExists = false;
|
|
IsMultiStage = false;
|
|
VertexColorsExist = false;
|
|
|
|
meshfile.Open (FileClass::READ);
|
|
|
|
try {
|
|
|
|
materialpass = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MESH_HEADER3:
|
|
if (w3dchunk.Read (&Header, sizeof (Header)) != sizeof (Header)) {
|
|
throw ("Cannot read data in W3D_CHUNK_MESH_HEADER3.");
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_INFO:
|
|
if (w3dchunk.Read (&MaterialInfo [UNLIT], sizeof (MaterialInfo [UNLIT])) != sizeof (MaterialInfo [UNLIT])) {
|
|
throw ("Cannot read data in W3D_CHUNK_MATERIAL_INFO.");
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_TRIANGLES:
|
|
if (TriangleChunk == NULL) {
|
|
TriangleChunk = new ChunkClass (w3dchunk);
|
|
ASSERT (TriangleChunk != NULL);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTICES:
|
|
if (VertexChunk == NULL) {
|
|
VertexChunk = new ChunkClass (w3dchunk);
|
|
ASSERT (VertexChunk != NULL);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIALS:
|
|
Parse_Vertex_Materials (w3dchunk, PrelitModeEnum::UNLIT);
|
|
break;
|
|
|
|
case W3D_CHUNK_SHADERS:
|
|
if (ShaderChunk [PrelitModeEnum::UNLIT] == NULL) {
|
|
ShaderChunk [PrelitModeEnum::UNLIT] = new ChunkClass (w3dchunk);
|
|
ASSERT (ShaderChunk [PrelitModeEnum::UNLIT] != NULL);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_PASS:
|
|
Parse_Material_Pass (w3dchunk, PrelitModeEnum::UNLIT, materialpass);
|
|
materialpass++;
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_UNLIT:
|
|
Parse_Prelit_Chunk (w3dchunk, PrelitModeEnum::UNLIT);
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_VERTEX:
|
|
Parse_Prelit_Chunk (w3dchunk, PrelitModeEnum::VERTEX);
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS:
|
|
Parse_Prelit_Chunk (w3dchunk, PrelitModeEnum::MULTI_PASS);
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE:
|
|
Parse_Prelit_Chunk (w3dchunk, PrelitModeEnum::MULTI_TEXTURE);
|
|
break;
|
|
|
|
case W3D_CHUNK_DEFORM:
|
|
DeformExists = true;
|
|
break;
|
|
|
|
default:
|
|
|
|
// Do nothing.
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// Clean-up.
|
|
meshfile.Close();
|
|
|
|
} catch (const char *message) {
|
|
|
|
// Clean-up.
|
|
meshfile.Close();
|
|
|
|
// Throw to enclosing catch.
|
|
throw (message);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* MeshInfoStruct::Parse_Vertex_Materials -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::MeshInfoStruct::Parse_Vertex_Materials (ChunkLoadClass &w3dchunk, unsigned prelitmode)
|
|
{
|
|
if (VertexMaterials [prelitmode] == NULL) {
|
|
|
|
W3dVertexMaterialStruct vertexmaterialinfo;
|
|
|
|
VertexMaterials [prelitmode] = new DynamicVectorClass <W3dVertexMaterialStruct>;
|
|
ASSERT (VertexMaterials [prelitmode] != NULL);
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIAL_NAME:
|
|
case W3D_CHUNK_VERTEX_MAPPER_ARGS0:
|
|
case W3D_CHUNK_VERTEX_MAPPER_ARGS1:
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIAL_INFO:
|
|
if (w3dchunk.Read (&vertexmaterialinfo, sizeof (vertexmaterialinfo)) != sizeof (vertexmaterialinfo)) {
|
|
throw ("Cannot read data in W3D_CHUNK_VERTEX_MATERIAL_INFO.");
|
|
}
|
|
VertexMaterials [prelitmode]->Add (vertexmaterialinfo);
|
|
break;
|
|
|
|
default:
|
|
|
|
// Do nothing.
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* MeshInfoStruct::Parse_Material_Pass -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 08/28/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::MeshInfoStruct::Parse_Material_Pass (ChunkLoadClass &w3dchunk, unsigned prelitmode, unsigned materialpass)
|
|
{
|
|
unsigned chunkstagecount;
|
|
|
|
// While there are material chunks...
|
|
chunkstagecount = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_SHADER_IDS:
|
|
if ((materialpass < MeshMatDescClass::MAX_PASSES) && (ShaderIdChunk [prelitmode][materialpass] == NULL)) {
|
|
ShaderIdChunk [prelitmode][materialpass] = new ChunkClass (w3dchunk);
|
|
ASSERT (ShaderIdChunk [prelitmode][materialpass] != NULL);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_SCG:
|
|
|
|
// Flag that an SCG chunk has been found.
|
|
SCGsExist = true;
|
|
break;
|
|
|
|
case W3D_CHUNK_DCG:
|
|
{
|
|
// Scan the chunk for color information and flag appropriately.
|
|
ChunkClass *dcgschunk;
|
|
W3dRGBAStruct *dcgs;
|
|
|
|
dcgschunk = new ChunkClass (w3dchunk);
|
|
ASSERT (dcgschunk != NULL);
|
|
|
|
dcgs = (W3dRGBAStruct*) dcgschunk->Get_Data();
|
|
for (unsigned v = 0; v < dcgschunk->Get_Size() / sizeof (*dcgs); v++) {
|
|
if ((dcgs [v].R != UCHAR_MAX) ||
|
|
(dcgs [v].G != UCHAR_MAX) ||
|
|
(dcgs [v].B != UCHAR_MAX)) {
|
|
|
|
VertexColorsExist = true;
|
|
}
|
|
}
|
|
|
|
delete dcgschunk;
|
|
break;
|
|
}
|
|
|
|
case W3D_CHUNK_DIG:
|
|
|
|
// Flag that a DIG chunk has been found.
|
|
DIGsExist = true;
|
|
break;
|
|
|
|
case W3D_CHUNK_TEXTURE_STAGE:
|
|
chunkstagecount++;
|
|
break;
|
|
|
|
default:
|
|
|
|
// Do nothing.
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// Flag if more than one texture stage exists on this material pass.
|
|
if (chunkstagecount > 1) IsMultiStage = true;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* MeshInfoStruct::Parse_Prelit_Chunk -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 08/28/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::MeshInfoStruct::Parse_Prelit_Chunk (ChunkLoadClass &w3dchunk, unsigned prelitmode)
|
|
{
|
|
unsigned materialpass;
|
|
|
|
materialpass = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MATERIAL_INFO:
|
|
if (w3dchunk.Read (&MaterialInfo [prelitmode], sizeof (MaterialInfo [prelitmode])) != sizeof (MaterialInfo [prelitmode])) {
|
|
throw ("Cannot read data in W3D_CHUNK_MATERIAL_INFO.");
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIALS:
|
|
Parse_Vertex_Materials (w3dchunk, prelitmode);
|
|
break;
|
|
|
|
case W3D_CHUNK_SHADERS:
|
|
if (ShaderChunk [prelitmode] == NULL) {
|
|
ShaderChunk [prelitmode] = new ChunkClass (w3dchunk);
|
|
ASSERT (ShaderChunk [prelitmode] != NULL);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_PASS:
|
|
Parse_Material_Pass (w3dchunk, prelitmode, materialpass);
|
|
materialpass++;
|
|
break;
|
|
|
|
default:
|
|
|
|
// Do nothing.
|
|
break;
|
|
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* MeshInfoStruct::~MeshInfoStruct -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::MeshInfoStruct::~MeshInfoStruct()
|
|
{
|
|
unsigned s;
|
|
|
|
if (TriangleChunk != NULL) delete TriangleChunk;
|
|
if (VertexChunk != NULL) delete VertexChunk;
|
|
for (s = 0; s < PrelitModeEnum::COUNT; s++) {
|
|
if (VertexMaterials [s] != NULL) delete VertexMaterials [s];
|
|
if (ShaderChunk [s] != NULL) delete ShaderChunk [s];
|
|
for (unsigned p = 0; p < MeshMatDescClass::MAX_PASSES; p++) {
|
|
if (ShaderIdChunk [s][p] != NULL) delete ShaderIdChunk [s][p];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* MeshAnomalyStruct::MeshAnomalyStruct -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::MeshAnomalyStruct::MeshAnomalyStruct (const MeshInfoStruct &meshinfo)
|
|
{
|
|
const W3dRGBStruct black ((uint8) 0x00, (uint8) 0x00, (uint8) 0x00);
|
|
const W3dRGBStruct white ((uint8) 0xff, (uint8) 0xff, (uint8) 0xff);
|
|
|
|
// Initialize the member fields.
|
|
MeshAnomalies = 0;
|
|
|
|
// Is the mesh hidden (not rendered)?
|
|
if (meshinfo.Header.Attributes & W3D_MESH_FLAG_HIDDEN) MeshAnomalies |= (1 << MESH_HIDDEN);
|
|
|
|
// Has this mesh already been prelit?
|
|
if (meshinfo.Header.Attributes & W3D_MESH_FLAG_PRELIT_MASK) MeshAnomalies |= (1 << MESH_PRELIT);
|
|
|
|
// Does mesh have a hierarchy?
|
|
if ((meshinfo.Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) MeshAnomalies |= (1 << MESH_HAS_HIERARCHY);
|
|
|
|
// Is this mesh 2-sided?
|
|
if (meshinfo.Header.Attributes & W3D_MESH_FLAG_TWO_SIDED) MeshAnomalies |= (1 << MESH_TWO_SIDED);
|
|
|
|
// Are there any vertex materials?
|
|
if (meshinfo.MaterialInfo [PrelitModeEnum::UNLIT].VertexMaterialCount == 0) MeshAnomalies |= (1 << MESH_NO_VERTEX_MATERIALS);
|
|
|
|
// Are there any shaders?
|
|
if (meshinfo.MaterialInfo [PrelitModeEnum::UNLIT].ShaderCount == 0) MeshAnomalies |= (1 << MESH_NO_SHADERS);
|
|
|
|
// Is there a deform chunk?
|
|
if (meshinfo.DeformExists) MeshAnomalies |= (1 << MESH_W3D_CHUNK_DEFORM);
|
|
|
|
// Are there too many existing material passes?
|
|
if (meshinfo.MaterialInfo [PrelitModeEnum::UNLIT].PassCount > MeshMatDescClass::MAX_PASSES - 1) MeshAnomalies |= (1 << MESH_TOO_MANY_PASSES);
|
|
|
|
// Determine if one or more passes has too many texture stages.
|
|
if (meshinfo.IsMultiStage) MeshAnomalies |= (1 << MESH_TOO_MANY_STAGES);
|
|
|
|
// For each vertex material...
|
|
if (meshinfo.VertexMaterials [PrelitModeEnum::UNLIT] != NULL) {
|
|
for (int vm = 0; vm < meshinfo.VertexMaterials [PrelitModeEnum::UNLIT]->Count(); vm++) {
|
|
|
|
// Test for emissive.
|
|
if ((*meshinfo.VertexMaterials [PrelitModeEnum::UNLIT]) [vm].Emissive != black) MeshAnomalies |= (1 << MESH_HAS_EMISSIVE);
|
|
|
|
// Test for specular to diffuse.
|
|
if (((*meshinfo.VertexMaterials [PrelitModeEnum::UNLIT]) [vm].Attributes & W3DVERTMAT_COPY_SPECULAR_TO_DIFFUSE) != 0) MeshAnomalies |= (1 << MESH_SPECULAR_TO_DIFFUSE);
|
|
}
|
|
}
|
|
|
|
// Test shaders.
|
|
if (meshinfo.ShaderChunk [PrelitModeEnum::UNLIT] != NULL) {
|
|
|
|
W3dShaderStruct *shaderptr = (W3dShaderStruct*) meshinfo.ShaderChunk [PrelitModeEnum::UNLIT]->Get_Data();
|
|
|
|
for (unsigned s = 0; s < meshinfo.ShaderChunk [PrelitModeEnum::UNLIT]->Get_Size() / sizeof (W3dShaderStruct); s++) {
|
|
|
|
if (shaderptr->PriGradient != W3DSHADER_PRIGRADIENT_MODULATE) MeshAnomalies |= (1 << MESH_NOT_MODULATED_PRIMARY);
|
|
if (shaderptr->SecGradient != W3DSHADER_SECGRADIENT_DISABLE) MeshAnomalies |= (1 << MESH_HAS_SPECULAR);
|
|
if (shaderptr->AlphaTest != W3DSHADER_ALPHATEST_DISABLE) MeshAnomalies |= (1 << MESH_ALPHATEST);
|
|
shaderptr++;
|
|
}
|
|
}
|
|
|
|
// Determine if there is an SCG chunk.
|
|
if (meshinfo.SCGsExist) MeshAnomalies |= (1 << MESH_HAS_SCG);
|
|
|
|
// Determine if there is a DIG chunk.
|
|
if (meshinfo.DIGsExist) MeshAnomalies |= (1 << MESH_HAS_DIG);
|
|
|
|
// Determine if there is destination blending in pass 0.
|
|
if ((meshinfo.ShaderChunk [PrelitModeEnum::UNLIT] != NULL) && (meshinfo.ShaderIdChunk [PrelitModeEnum::UNLIT] [0] != NULL)) {
|
|
for (unsigned s = 0; s < meshinfo.ShaderIdChunk [PrelitModeEnum::UNLIT] [0]->Get_Size() / sizeof (uint32); s++) {
|
|
|
|
uint32 shaderid;
|
|
W3dShaderStruct *shaderptr;
|
|
|
|
shaderid = *((uint32*) meshinfo.ShaderIdChunk [PrelitModeEnum::UNLIT][0]->Get_Data() + s);
|
|
shaderptr = ((W3dShaderStruct*) meshinfo.ShaderChunk [PrelitModeEnum::UNLIT]->Get_Data()) + shaderid;
|
|
|
|
if (shaderptr->DestBlend != W3DSHADER_DESTBLENDFUNC_ZERO) MeshAnomalies |= (1 << MESH_PASS_ZERO_DESTBLEND);
|
|
}
|
|
}
|
|
|
|
// Determine if there is vertex coloring.
|
|
if (meshinfo.VertexColorsExist) MeshAnomalies |= (1 << MESH_VERTEX_COLORING);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* SplitVertexInfoStruct::SplitVertexInfoStruct -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/04/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::SplitVertexInfoStruct::SplitVertexInfoStruct (const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve)
|
|
{
|
|
const unsigned verticesperface = 3; // No. of vertices in a triangle.
|
|
const unsigned facecount = meshinfo.TriangleChunk->Get_Size() / sizeof (W3dTriStruct);
|
|
const unsigned vertexcount = meshinfo.VertexChunk->Get_Size() / sizeof (W3dVectorStruct);
|
|
const unsigned facevertexcount = facecount * verticesperface;
|
|
|
|
W3dTriStruct *triangles;
|
|
unsigned worstcasevertexcount;
|
|
unsigned splitvertexindex, facevertexindex, t, v;
|
|
|
|
worstcasevertexcount = MAX (vertexcount, facevertexcount);
|
|
|
|
// Allocate a remap table of worst case size ie. assume 3 vertices per triangle.
|
|
RemapTable = new uint32 [worstcasevertexcount];
|
|
ASSERT (RemapTable != NULL);
|
|
|
|
IndexTable = new uint32 [facevertexcount];
|
|
ASSERT (IndexTable != NULL);
|
|
|
|
// Allocate and copy a table of lightmap UV's.
|
|
UVTable = new W3dTexCoordStruct [facevertexcount];
|
|
ASSERT (UVTable != NULL);
|
|
if (meshsolve.Get_Statistics()->Valid_Lightmap_Solve()) {
|
|
for (t = 0; t < facevertexcount; t++) {
|
|
UVTable [t] = meshsolve.Lightmap_UV (t);
|
|
}
|
|
} else {
|
|
for (t = 0; t < facevertexcount; t++) {
|
|
UVTable [t].U = 0.0f;
|
|
UVTable [t].V = 0.0f;
|
|
}
|
|
}
|
|
|
|
// Allocate and initialize a table of lightmap UV ptrs of worst case size.
|
|
UVPtrTable = new W3dTexCoordStruct* [worstcasevertexcount];
|
|
ASSERT (UVPtrTable != NULL);
|
|
for (t = 0; t < worstcasevertexcount; t++) {
|
|
UVPtrTable [t] = NULL;
|
|
}
|
|
|
|
// Get the base address of the triangle chunk data.
|
|
triangles = (W3dTriStruct*) meshinfo.TriangleChunk->Get_Data();
|
|
ASSERT (triangles != NULL);
|
|
|
|
// For each face...
|
|
splitvertexindex = vertexcount;
|
|
facevertexindex = 0;
|
|
for (unsigned f = 0; f < facecount; f++) {
|
|
|
|
// For each face vertex...
|
|
for (v = 0; v < verticesperface; v++) {
|
|
|
|
uint32 vertexindex;
|
|
|
|
vertexindex = triangles [f].Vindex [v];
|
|
ASSERT (vertexindex < vertexcount);
|
|
|
|
// Has this index not been used before?
|
|
if (UVPtrTable [vertexindex] == NULL) {
|
|
|
|
RemapTable [vertexindex] = vertexindex;
|
|
IndexTable [facevertexindex] = vertexindex;
|
|
UVPtrTable [vertexindex] = UVTable + facevertexindex;
|
|
|
|
} else {
|
|
|
|
// Does this vertex reference the same UV coordinate as the vertex that has already been indexed?
|
|
if (*UVPtrTable [vertexindex] == UVTable [facevertexindex]) {
|
|
|
|
IndexTable [facevertexindex] = vertexindex;
|
|
|
|
} else {
|
|
|
|
// Split the vertex.
|
|
RemapTable [splitvertexindex] = vertexindex;
|
|
IndexTable [facevertexindex] = splitvertexindex;
|
|
UVPtrTable [splitvertexindex] = UVTable + facevertexindex;
|
|
splitvertexindex++;
|
|
}
|
|
}
|
|
|
|
facevertexindex++;
|
|
}
|
|
}
|
|
|
|
// Iterate over the original vertices to see if any were unreferenced by a triangle.
|
|
// NOTE: The existence of these suggests some redundancy in the mesh data!
|
|
for (v = 0; v < vertexcount; v++) {
|
|
|
|
if (UVPtrTable [v] == NULL) {
|
|
|
|
// Remap it to the zeroth vertex in the zeroth triangle.
|
|
RemapTable [v] = RemapTable [IndexTable [0]];
|
|
UVPtrTable [v] = UVPtrTable [IndexTable [0]];
|
|
}
|
|
}
|
|
|
|
VertexCount = splitvertexindex;
|
|
FaceVertexCount = facevertexcount;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* SplitVertexInfoStruct::~SplitVertexInfoStruct -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/04/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
LightMapDoc::SplitVertexInfoStruct::~SplitVertexInfoStruct()
|
|
{
|
|
// Clean-up.
|
|
delete [] UVPtrTable;
|
|
delete [] UVTable;
|
|
delete [] IndexTable;
|
|
delete [] RemapTable;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Mesh_Anomalies_String -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/02/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
const char *LightMapDoc::Mesh_Anomalies_String (unsigned meshindex, bool verbose, StringBuilder &string)
|
|
{
|
|
static char *_meshtext [2][LightMapDoc::MESH_FLAG_COUNT] = {{
|
|
"Hidden",
|
|
"Prelit",
|
|
"No vertex materials",
|
|
"No shaders",
|
|
"Hierarchy",
|
|
"Not modulated primary",
|
|
"Specular",
|
|
"Specular->diffuse",
|
|
"Deform chunk",
|
|
"2-sided",
|
|
"Emissive",
|
|
"SCG",
|
|
"DIG",
|
|
"Too many passes",
|
|
"Alpha-test",
|
|
"Not opaque",
|
|
"Too many stages",
|
|
"Vertex colors"
|
|
},
|
|
{
|
|
": mesh is flagged as hidden. This mesh will not receive a solve. Is this what you intended?",
|
|
": mesh already contains a vertex and/or lightmap solve. Please ensure that you have selected the correct W3D model file.",
|
|
": mesh does not contain any vertex materials. A valid mesh must have at least one vertex material.",
|
|
": mesh does not contain any shaders. A valid mesh must have at least one shader.",
|
|
": mesh contains a hierarchy and cannot be solved. Please export this model from MAX with the 'geometry only' option.",
|
|
": mesh contains a shader where the primary gradient is not set to 'modulate'. This is not supported. Please check that the\
|
|
shaders for this mesh have been defined correctly.",
|
|
": mesh has a shader where the secondary gradient is set to 'enabled' (specular lighting). Specular lighting cannot be\
|
|
calculated for prelit meshes. If you wish to insert a solve for this mesh re-export the model from MAX with the secondary\
|
|
gradient disabled.",
|
|
": mesh has a vertex material with 'copy specular to diffuse' enabled (specular lighting). Specular lighting cannot be\
|
|
calculated for prelit meshes. If you want to insert a solve for this mesh re-export the model from MAX with this option\
|
|
unchecked.",
|
|
": unsupported chunk (DEFORM chunk).",
|
|
": mesh is two-sided. A solve cannot be inserted.",
|
|
": mesh has a vertex material with an emissive component. A solve cannot be inserted.",
|
|
": mesh has one or more SCG chunks. A solve cannot be inserted.",
|
|
": mesh has one or more DIG chunks. A vertex solve for this mesh cannot be inserted.",
|
|
": mesh has too many existing material passes (maximum supported passes is 3). A multi-pass lightmap solve for this mesh\
|
|
cannot be inserted.",
|
|
": mesh uses alpha testing in one or more passes. A multi-pass lightmap solve cannot be inserted.",
|
|
": mesh has destination blending in the zeroth pass. A multi-pass lightmap solve cannot be inserted.",
|
|
": mesh has a material pass with more than one texture stage. A multi-texture lightmap solve cannot be inserted.",
|
|
": mesh has vertex coloring. Is this what you intended?"
|
|
}};
|
|
|
|
unsigned long meshanomalies = MeshStatus [meshindex].MeshAnomalies;
|
|
|
|
if (verbose) {
|
|
string.Copy ("");
|
|
for (unsigned meshflagindex = 0; meshflagindex < MESH_FLAG_COUNT; meshflagindex++) {
|
|
if (meshanomalies & (1 << meshflagindex)) {
|
|
string.Concatenate ("%s%s\r\n\r\n", _meshtext [0][meshflagindex], _meshtext [1][meshflagindex]);
|
|
}
|
|
}
|
|
if (string.String() [0] == '\0') string.Copy ("No mesh anomalies.\r\n\r\n");
|
|
|
|
} else {
|
|
string.Copy ("");
|
|
for (unsigned meshflagindex = 0; meshflagindex < LightMapDoc::MESH_FLAG_COUNT; meshflagindex++) {
|
|
if (meshanomalies & (1 << meshflagindex)) {
|
|
if (string.String() [0] != '\0') string.Concatenate (", ");
|
|
string.Concatenate (_meshtext [0][meshflagindex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (string.String());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Solve_Anomalies_String -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/02/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
const char *LightMapDoc::Solve_Anomalies_String (unsigned meshindex, bool verbose, StringBuilder &string)
|
|
{
|
|
static char *_solvetext [2][SolveStatistics::SOLVE_STATISTIC_COUNT] = {{
|
|
"Vertices not found",
|
|
"No color data",
|
|
"Faces not found",
|
|
"No lightmaps",
|
|
"Not smooth",
|
|
"Ambiguous",
|
|
"Degenerate",
|
|
"[U]",
|
|
"[E]",
|
|
"Fill color",
|
|
"Placeholder used"
|
|
},
|
|
{
|
|
": %d vertices that exist in the W3D mesh cannot be located in the Lightscape solve\
|
|
file (.ls). These vertices will show up hot pink in the solve. First, ensure that the MAX\
|
|
model that was used to create the .w3d model is identical to that used to create the solve.\
|
|
Second, ensure that the MAX model and the Lightscape model use the same units of measurement.\
|
|
Third, try increasing the Spatial Tolerance in Tools | Options. Fourth, Lightscape may\
|
|
have eliminated some vertices during mesh initiation. Please ensure that the Lightscape\
|
|
Length Tolerance was set to a reasonable value prior to generating the solve.",
|
|
": %d vertices in the W3D mesh have no corresponding color data in the Lightscape\
|
|
solve file. A vertex solve for this mesh cannot be inserted. If you wish to insert a vertex\
|
|
solve, ensure that one or more solve files contain a Lightscape radiosty mesh.",
|
|
": %d faces that exist in the W3D mesh cannot be located in the Lightscape solve file (.ls).\
|
|
For these faces, a placeholder texture ('Placeholder.tga') has been substituted for the\
|
|
missing lightmap. To correct this problem, first ensure that the MAX model that was used to\
|
|
create the .w3d model is identical to that used to create the solve. Second, ensure that\
|
|
the MAX model and the Lightscape model use the same units of measurement. Third, Lightscape\
|
|
may have eliminated some small or degenerate faces. Please ensure that the Lightscape\
|
|
Length Tolerance was set to a reasonable value prior to generating the solve.",
|
|
": %d faces in the W3D mesh have no associated lightmap in the Lightscape solve file.\
|
|
A lightmap solve for this mesh cannot be inserted. If you want to insert a lightmap solve,\
|
|
ensure that one or more solve files contain lightmaps for this mesh (ie. it must have been\
|
|
processed with the Lightscape 'Mesh to Texture' option).",
|
|
": %d vertices in the W3D mesh have not been smoothed. They can only be matched up with\
|
|
vertices in the Lightscape solve that are outside the smoothing angle. This is most likely\
|
|
caused by small or degenerate faces. Save the model and then check this mesh for visual\
|
|
artefacts.",
|
|
": %d faces can be matched with more than one face in the Lightscape solve. This is most\
|
|
likely caused by coincident faces (ie. two identical faces at the same location).\
|
|
Although this will not cause any visual artefacts, in the interests of efficiency, you\
|
|
may wish to remove them from the MAX model and re-export the w3d model (the solve does\
|
|
not need to be recalculated).",
|
|
": %d faces are degenerate (ie. two or more points are identical). Although this will not\
|
|
cause any visual artefacts, it may cause unpredicatable run-time behaviour. You should\
|
|
remove them from the MAX model and re-export the w3d model (the solve does not need to\
|
|
be recalculated).",
|
|
": Diagnostic information only. %d faces are 'undersize'.",
|
|
": Diagnostic information only. %d faces have been 'edge matched'.",
|
|
": %d lightmaps contained only fill color texels. These texels have been automatically\
|
|
replaced with texel data from the nearest valid texels on this page. If you are not satisfied\
|
|
with the results you may wish to fix the abberrant lightmaps and re-insert the solve.",
|
|
": %d faces that exist in the W3D mesh cannot be located in the Lightscape solve\
|
|
file (.ls). For these faces, a placeholder lightmap ('Placeholder.tga') has been substituted\
|
|
for the missing lightmap."
|
|
}};
|
|
|
|
SolveStatistics *solvestatisticsptr = &(MeshStatus [meshindex].SolveStatistics);
|
|
|
|
if (verbose) {
|
|
string.Copy ("");
|
|
if (Solve_Inserted()) {
|
|
for (unsigned index = 0; index < SolveStatistics::SOLVE_STATISTIC_COUNT; index++) {
|
|
if (solvestatisticsptr->Count [index] > 0) {
|
|
string.Concatenate (_solvetext [0][index]);
|
|
string.Concatenate (_solvetext [1][index], solvestatisticsptr->Count [index]);
|
|
string.Concatenate ("\r\n\r\n");
|
|
}
|
|
}
|
|
if (string.String() [0] == '\0') string.Copy ("No solve anomalies.\r\n\r\n");
|
|
}
|
|
|
|
} else {
|
|
string.Copy ("");
|
|
for (unsigned index = 0; index < SolveStatistics::SOLVE_STATISTIC_COUNT; index++) {
|
|
if (solvestatisticsptr->Count [index] > 0) {
|
|
if (string.String() [0] != '\0') string.Concatenate (", ");
|
|
string.Concatenate (_solvetext [0][index]);
|
|
}
|
|
}
|
|
}
|
|
return (string.String());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Vertex_Solve_Status_String -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/02/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
const char *LightMapDoc::Vertex_Solve_Status_String (unsigned meshindex, StringBuilder &string)
|
|
{
|
|
static char *_insertedtext [2][2] = {
|
|
{"Cannot insert", ""},
|
|
{"Cannot insert", "Inserted"}
|
|
};
|
|
|
|
if (!Solve_Inserted()) {
|
|
string.Copy (_insertedtext [0][MeshStatus [meshindex].Can_Insert_Vertex_Solve()]);
|
|
} else {
|
|
string.Copy (_insertedtext [1][MeshStatus [meshindex].Inserted_Vertex_Solve()]);
|
|
}
|
|
|
|
return (string.String());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Lightmap_Solve_Status_String -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/02/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
const char *LightMapDoc::Lightmap_Solve_Status_String (unsigned meshindex, StringBuilder &string)
|
|
{
|
|
static char *_insertedtext [2][4] = {
|
|
{"Cannot insert", "Multi-pass only", "Multi-texture only", ""},
|
|
{"Cannot insert", "Multi-pass inserted", "Multi-texture inserted", "Inserted"}
|
|
};
|
|
|
|
unsigned code;
|
|
|
|
if (!Solve_Inserted()) {
|
|
code = (MeshStatus [meshindex].Can_Insert_Multi_Pass_Solve() ? 1 : 0)
|
|
+ (MeshStatus [meshindex].Can_Insert_Multi_Texture_Solve() ? 2 : 0);
|
|
string.Copy (_insertedtext [0][code]);
|
|
|
|
} else {
|
|
code = (MeshStatus [meshindex].Inserted_Multi_Pass_Solve() ? 1 : 0)
|
|
+ (MeshStatus [meshindex].Inserted_Multi_Texture_Solve() ? 2 : 0);
|
|
string.Copy (_insertedtext [1][code]);
|
|
}
|
|
|
|
return (string.String());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Reorder - reorder the meshes within the document for optimal spatial coherence.* *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Reorder()
|
|
{
|
|
RawFileClass *reorderfile = NULL;
|
|
|
|
try {
|
|
|
|
DynamicVectorClass <MeshReorderStruct> meshes;
|
|
|
|
{
|
|
W3dFile->Open (FileClass::READ);
|
|
|
|
ChunkLoadClass w3dchunk (W3dFile);
|
|
|
|
// Read the (unordered) mesh chunks.
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
// Is this a mesh chunk?
|
|
if (w3dchunk.Cur_Chunk_ID() == W3D_CHUNK_MESH) {
|
|
|
|
ChunkClass *chunk = new ChunkClass (w3dchunk);
|
|
|
|
RAMFileClass meshfile (chunk->Get_Data(), chunk->Get_Size());
|
|
MeshInfoStruct meshinfo (meshfile);
|
|
MeshReorderStruct mesh;
|
|
|
|
mesh.Chunk = chunk;
|
|
mesh.Position.Set (meshinfo.Header.SphCenter.X, meshinfo.Header.SphCenter.Y, meshinfo.Header.SphCenter.Z);
|
|
meshes.Add (mesh);
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
W3dFile->Close();
|
|
}
|
|
|
|
// If more than one chunk, spatially sort the mesh chunks.
|
|
if (meshes.Count() > 1) {
|
|
|
|
const float floatmax = 0.5f * (sqrt (FLT_MAX / 3.0f));
|
|
|
|
int m;
|
|
float distance, mindistance;
|
|
Vector3 seed;
|
|
MeshReorderStruct t;
|
|
|
|
// Find an extreme position to use as the seed.
|
|
mindistance = FLT_MAX;
|
|
for (m = 0; m < meshes.Count(); m++) {
|
|
distance = meshes [m].Position.X + meshes [m].Position.Y + meshes [m].Position.Z;
|
|
if (distance < mindistance) {
|
|
mindistance = distance;
|
|
seed = meshes [m].Position;
|
|
}
|
|
}
|
|
|
|
for (m = 0; m < meshes.Count() - 1; m++) {
|
|
|
|
float distancesquared, mindistancesquared;
|
|
unsigned nearestmeshindex;
|
|
|
|
mindistancesquared = FLT_MAX;
|
|
for (int n = m; n < meshes.Count(); n++) {
|
|
distancesquared = (meshes [n].Position - seed).Length2();
|
|
if (distancesquared < mindistancesquared) {
|
|
nearestmeshindex = n;
|
|
mindistancesquared = distancesquared;
|
|
}
|
|
}
|
|
|
|
// Swap mesh positions.
|
|
t = meshes [m];
|
|
meshes [m] = meshes [nearestmeshindex];
|
|
meshes [nearestmeshindex] = t;
|
|
|
|
// If it exists, swap mesh status.
|
|
if (MeshStatus.Count() > 0) {
|
|
|
|
MeshStatusStruct s;
|
|
|
|
s = MeshStatus [m];
|
|
MeshStatus [m] = MeshStatus [nearestmeshindex];
|
|
MeshStatus [nearestmeshindex] = s;
|
|
}
|
|
|
|
seed = meshes [m].Position;
|
|
}
|
|
}
|
|
|
|
// Write out the reordered mesh chunks.
|
|
{
|
|
char temporarypathname [_MAX_PATH];
|
|
bool outputmeshchunks;
|
|
|
|
W3dFile->Open (FileClass::READ);
|
|
|
|
// Create a temporary file to contain the results of the solve.
|
|
strcpy (temporarypathname, theApp.Working_Path());
|
|
strcat (temporarypathname, _TemporaryReorderFilename);
|
|
strcat (temporarypathname, theApp.Instance_Name());
|
|
reorderfile = new RawFileClass (temporarypathname);
|
|
ASSERT (reorderfile != NULL);
|
|
|
|
// NOTE: RawFileClass will not keep a copy of the filename unless Set_Name() is explicitly called.
|
|
reorderfile->Set_Name (temporarypathname);
|
|
|
|
// NOTE: WRITE only access will truncate any existing temporary file.
|
|
reorderfile->Open (FileClass::WRITE);
|
|
|
|
ChunkLoadClass w3dchunk (W3dFile);
|
|
ChunkSaveClass reorderchunk (reorderfile);
|
|
|
|
outputmeshchunks = false;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
// Is this a mesh chunk?
|
|
if (w3dchunk.Cur_Chunk_ID() == W3D_CHUNK_MESH) {
|
|
if (!outputmeshchunks) {
|
|
for (int m = 0; m < meshes.Count(); m++) {
|
|
reorderchunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
reorderchunk.Write (meshes [m].Chunk->Get_Data(), meshes [m].Chunk->Get_Size());
|
|
reorderchunk.End_Chunk();
|
|
|
|
// Clean-up.
|
|
delete meshes [m].Chunk;
|
|
}
|
|
outputmeshchunks = true;
|
|
}
|
|
} else {
|
|
Copy_Chunk (w3dchunk, reorderchunk);
|
|
}
|
|
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
}
|
|
|
|
// Clean-up.
|
|
delete W3dFile;
|
|
reorderfile->Close();
|
|
|
|
// Make the reorder file the w3d file.
|
|
W3dFile = reorderfile;
|
|
|
|
} catch (const char *errormessage) {
|
|
|
|
W3dFile->Close();
|
|
if (reorderfile != NULL) delete reorderfile;
|
|
|
|
// Throw to caller.
|
|
throw (errormessage);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Optimize -- Simplify the document (if necessary). *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Optimize()
|
|
{
|
|
RawFileClass *optimizefile = NULL;
|
|
|
|
try {
|
|
|
|
char temporarypathname [_MAX_PATH];
|
|
|
|
W3dFile->Open (FileClass::READ);
|
|
|
|
// Create a temporary file to contain the results of the solve.
|
|
strcpy (temporarypathname, theApp.Working_Path());
|
|
strcat (temporarypathname, _TemporaryOptimizeFilename);
|
|
strcat (temporarypathname, theApp.Instance_Name());
|
|
optimizefile = new RawFileClass (temporarypathname);
|
|
ASSERT (optimizefile != NULL);
|
|
|
|
// NOTE: RawFileClass will not keep a copy of the filename unless Set_Name() is explicitly called.
|
|
optimizefile->Set_Name (temporarypathname);
|
|
|
|
// NOTE: WRITE only access will truncate any existing temporary file.
|
|
optimizefile->Open (FileClass::WRITE);
|
|
|
|
ChunkLoadClass w3dchunk (W3dFile);
|
|
ChunkSaveClass optimizechunk (optimizefile);
|
|
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
// Is this a mesh chunk?
|
|
if (w3dchunk.Cur_Chunk_ID() == W3D_CHUNK_MESH) {
|
|
|
|
optimizechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_PRELIT_VERTEX:
|
|
|
|
optimizechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MATERIAL_PASS:
|
|
Optimize_Prelit_Vertex_Material_Pass (w3dchunk, optimizechunk);
|
|
break;
|
|
|
|
default:
|
|
Copy_Chunk (w3dchunk, optimizechunk);
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
optimizechunk.End_Chunk();
|
|
break;
|
|
|
|
default:
|
|
Copy_Chunk(w3dchunk, optimizechunk);
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
optimizechunk.End_Chunk();
|
|
|
|
} else {
|
|
Copy_Chunk (w3dchunk, optimizechunk);
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// Clean-up.
|
|
delete W3dFile;
|
|
optimizefile->Close();
|
|
|
|
// Make the optimize file the w3d file.
|
|
W3dFile = optimizefile;
|
|
|
|
// Once a document has been optimized, a solve can no longer be inserted because some
|
|
// information has been lost (namely DIG colors).
|
|
CanInsertSolve = false;
|
|
|
|
} catch (const char *errormessage) {
|
|
|
|
W3dFile->Close();
|
|
if (optimizefile != NULL) delete optimizefile;
|
|
|
|
// Throw to caller.
|
|
throw (errormessage);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Optimize_Prelit_Vertex_Material_Pass -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Optimize_Prelit_Vertex_Material_Pass (ChunkLoadClass &w3dchunk, ChunkSaveClass &optimizechunk)
|
|
{
|
|
unsigned i, digcount;
|
|
ChunkClass *dcgschunk;
|
|
ChunkClass *digschunk [MAX_SOLVE_COUNT];
|
|
|
|
optimizechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
digcount = 0;
|
|
dcgschunk = NULL;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_DCG:
|
|
dcgschunk = new ChunkClass (w3dchunk);
|
|
break;
|
|
|
|
case W3D_CHUNK_DIG:
|
|
ASSERT (digcount <= MAX_SOLVE_COUNT);
|
|
digschunk [digcount] = new ChunkClass (w3dchunk);
|
|
digcount++;
|
|
break;
|
|
|
|
default:
|
|
Copy_Chunk (w3dchunk, optimizechunk);
|
|
break;
|
|
}
|
|
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// For each DIG chunk...
|
|
for (i = 0; i < digcount; i++) {
|
|
|
|
W3dRGBStruct *digs;
|
|
W3dRGBAStruct *dcgs;
|
|
|
|
// Copy the DIG chunk into a DCG chunk, blend the DCG chunk (if it exists).
|
|
optimizechunk.Begin_Chunk (W3D_CHUNK_DCG);
|
|
|
|
digs = (W3dRGBStruct*) digschunk [i]->Get_Data();
|
|
if (dcgschunk != NULL) {
|
|
dcgs = (W3dRGBAStruct*) dcgschunk->Get_Data();
|
|
} else {
|
|
dcgs = NULL;
|
|
}
|
|
for (unsigned v = 0; v < digschunk [i]->Get_Size() / sizeof (*digs); v++) {
|
|
|
|
W3dRGBStruct blendcolor;
|
|
unsigned char alpha;
|
|
W3dRGBAStruct outputcolor;
|
|
|
|
blendcolor = digs [v];
|
|
if (dcgs != NULL) {
|
|
|
|
W3dRGBStruct color;
|
|
|
|
color.Set (dcgs [v].R, dcgs [v].G, dcgs [v].B);
|
|
blendcolor *= color;
|
|
alpha = dcgs [v].A;
|
|
} else {
|
|
alpha = UCHAR_MAX;
|
|
}
|
|
|
|
outputcolor.R = blendcolor.R;
|
|
outputcolor.G = blendcolor.G;
|
|
outputcolor.B = blendcolor.B;
|
|
outputcolor.A = alpha;
|
|
|
|
optimizechunk.Write (&outputcolor, sizeof (outputcolor));
|
|
}
|
|
|
|
optimizechunk.End_Chunk();
|
|
}
|
|
|
|
// If there were no DIG chunks write the DCG chunk as is (if it exists).
|
|
if ((digcount == 0) && (dcgschunk != NULL)) {
|
|
optimizechunk.Begin_Chunk (W3D_CHUNK_DCG);
|
|
optimizechunk.Write ((W3dRGBAStruct*) dcgschunk->Get_Data(), dcgschunk->Get_Size());
|
|
optimizechunk.End_Chunk();
|
|
}
|
|
|
|
optimizechunk.End_Chunk();
|
|
|
|
// Clean-up.
|
|
if (dcgschunk != NULL) delete dcgschunk;
|
|
for (i = 0; i < digcount; i++) {
|
|
if (digschunk [i] != NULL) delete digschunk [i];
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnFileSave -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::OnFileSave()
|
|
{
|
|
OnSaveDocument (GetPathName());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnFileSaveAs -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::OnFileSaveAs()
|
|
{
|
|
CFileDialog dialog (FALSE, LightMapApp::Document_File_Extension(), NULL, LightMapApp::File_Dialog_Flags(), LightMapApp::File_Dialog_Filter());
|
|
|
|
if (dialog.DoModal() == IDOK) OnSaveDocument (dialog.GetPathName());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnSaveDocument -- Save the currently open document. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
BOOL LightMapDoc::OnSaveDocument (LPCTSTR pathname)
|
|
{
|
|
const char *savingmodeltext = "Step 1/3: Saving Westwood 3D file (.W3D)";
|
|
const char *savinglightstext = "Step 2/3: Saving Westwood light file (.WLT)";
|
|
const char *savingassetstext = "Step 3/3: Saving lightmaps";
|
|
const char *savedtext = "Document saved";
|
|
const char *notsavedtext = "Document not saved";
|
|
|
|
CMainFrame* frameptr = (CMainFrame*) AfxGetApp()->m_pMainWnd;
|
|
CStatusBar* statusptr = &(frameptr->m_wndStatusBar);
|
|
|
|
StringBuilder errormessage (8192);
|
|
|
|
try {
|
|
|
|
ASSERT (pathname != NULL);
|
|
|
|
// Inform the user that the save has started.
|
|
CWaitCursor waitcursor;
|
|
|
|
// Optimize the document.
|
|
Optimize();
|
|
|
|
// If the filename of the current document and the save document do not match
|
|
// or the document has been modified then the document must be saved.
|
|
if (IsModified() || stricmp (W3dFile->File_Name(), pathname) != 0) {
|
|
|
|
char drivename [_MAX_DRIVE];
|
|
char directoryname [_MAX_DIR];
|
|
char filename [_MAX_FNAME];
|
|
unsigned filenamesize;
|
|
char lightmapdirectory [_MAX_DIR];
|
|
RawFileClass savefile (pathname);
|
|
ChunkLoadClass loadchunk (W3dFile);
|
|
ChunkSaveClass savechunk (&savefile);
|
|
char lightmappathname [_MAX_PATH];
|
|
|
|
// Extract the file name from the path name, check that the length is okay.
|
|
_splitpath (pathname, NULL, NULL, filename, NULL);
|
|
filenamesize = strlen (filename) + 1;
|
|
if (filenamesize > W3D_NAME_LEN) {
|
|
|
|
const char *controlstring = "File name is too long. Please use %d characters or less.";
|
|
|
|
throw (errormessage.Copy (controlstring, W3D_NAME_LEN));
|
|
}
|
|
|
|
strcpy (lightmapdirectory, filename);
|
|
|
|
// Convert filename to uppercase.
|
|
_strupr (filename);
|
|
|
|
W3dFile->Open (FileClass::READ);
|
|
|
|
// Open a save file with write access.
|
|
if (!savefile.Open (FileClass::WRITE)) throw ("Cannot create file with this file name.");
|
|
|
|
{
|
|
CProgressCtrl progressbar;
|
|
CRect srect, trect;
|
|
BOOL success;
|
|
|
|
statusptr->GetItemRect (0, &srect);
|
|
statusptr->SetPaneText (0, savingmodeltext);
|
|
statusptr->GetDC()->DrawText (savingmodeltext, -1, &trect, DT_CALCRECT);
|
|
|
|
CRect prect (srect.TopLeft().x + trect.Width(), srect.TopLeft().y, srect.BottomRight().x, srect.BottomRight().y);
|
|
|
|
success = progressbar.Create (WS_CHILD | WS_VISIBLE | PBS_SMOOTH, prect, statusptr, 0);
|
|
ASSERT (success);
|
|
progressbar.SetRange32 (0, MeshCount);
|
|
progressbar.SetStep (1);
|
|
|
|
// While there are load chunks...
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MESH:
|
|
Rename_Mesh (loadchunk, savechunk, filename, lightmapdirectory);
|
|
progressbar.StepIt();
|
|
break;
|
|
|
|
case W3D_CHUNK_COLLECTION:
|
|
Rename_Collection (loadchunk, savechunk, filename);
|
|
break;
|
|
|
|
case W3D_CHUNK_HLOD:
|
|
Rename_HLOD (loadchunk, savechunk, filename);
|
|
break;
|
|
|
|
case W3D_CHUNK_DAZZLE:
|
|
Rename_Dazzle (loadchunk, savechunk, filename);
|
|
break;
|
|
|
|
default:
|
|
|
|
// Any other chunk.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
}
|
|
|
|
// Copy the lightmap assets.
|
|
_splitpath (pathname, drivename, directoryname, NULL, NULL);
|
|
strcpy (lightmappathname, drivename);
|
|
strcat (lightmappathname, directoryname);
|
|
strcat (lightmappathname, lightmapdirectory);
|
|
statusptr->SetPaneText (0, savingassetstext);
|
|
LightscapeSolve::Copy_Assets (lightmappathname);
|
|
|
|
// Save the lights.
|
|
statusptr->SetPaneText (0, savinglightstext);
|
|
Save_Lights (pathname);
|
|
|
|
// Clean-up.
|
|
W3dFile->Close();
|
|
savefile.Close();
|
|
}
|
|
|
|
// Return success.
|
|
SetModifiedFlag (FALSE);
|
|
statusptr->SetPaneText (0, savedtext);
|
|
return (TRUE);
|
|
|
|
} catch (const char *message) {
|
|
|
|
// Clean-up.
|
|
// NOTE 0: Can safely call close even if files are not open.
|
|
// NOTE 1: Save file will be closed when it goes out of scope.
|
|
W3dFile->Close();
|
|
|
|
// Report why save failed to user.
|
|
MessageBox (NULL, message, NULL, MB_ICONERROR | MB_SETFOREGROUND);
|
|
|
|
// Return failure.
|
|
statusptr->SetPaneText (0, notsavedtext);
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_Mesh -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_Mesh (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *filename, const char *lightmapdirectory)
|
|
{
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MESH_HEADER3:
|
|
Rename_Mesh_Header (loadchunk, savechunk, filename);
|
|
break;
|
|
|
|
case W3D_CHUNK_TEXTURES:
|
|
Rename_Lightmaps (loadchunk, savechunk, lightmapdirectory);
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_UNLIT:
|
|
case W3D_CHUNK_PRELIT_VERTEX:
|
|
case W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS:
|
|
case W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE:
|
|
Rename_Prelit_Chunks (loadchunk, savechunk, lightmapdirectory);
|
|
break;
|
|
|
|
default:
|
|
// Other mesh chunks.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_Mesh_Header -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_Mesh_Header (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *filename)
|
|
{
|
|
unsigned filenamesize = strlen (filename) + 1;
|
|
|
|
W3dMeshHeader3Struct header;
|
|
|
|
if (loadchunk.Read (&header, loadchunk.Cur_Chunk_Length()) != loadchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_MESH_HEADER3.");
|
|
}
|
|
|
|
// If there is a container modify the container name, otherwise modify the mesh name.
|
|
if (strlen (header.ContainerName) > 0) {
|
|
ASSERT (filenamesize <= sizeof (header.ContainerName));
|
|
strcpy (header.ContainerName, filename);
|
|
} else {
|
|
ASSERT (filenamesize <= sizeof (header.MeshName));
|
|
strcpy (header.MeshName, filename);
|
|
}
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
savechunk.Write (&header, sizeof (header));
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_Prelit_Chunks -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 02/02/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_Prelit_Chunks (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *lightmapdirectory)
|
|
{
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_TEXTURES:
|
|
Rename_Lightmaps (loadchunk, savechunk, lightmapdirectory);
|
|
break;
|
|
|
|
default:
|
|
// Other mesh chunks.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_Lightmaps -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_Lightmaps (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *lightmapdirectory)
|
|
{
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_TEXTURE_NAME:
|
|
{
|
|
ChunkClass *loadpathchunk;
|
|
char loaddrivename [_MAX_DRIVE];
|
|
char loaddirectoryname [_MAX_DIR];
|
|
char loadfilename [_MAX_FNAME];
|
|
char loadextname [_MAX_EXT];
|
|
char pathname [_MAX_PATH];
|
|
|
|
loadpathchunk = new ChunkClass (loadchunk);
|
|
ASSERT (loadpathchunk != NULL);
|
|
|
|
// Break the load pathname into its component parts.
|
|
_splitpath ((const char*) loadpathchunk->Get_Data(), loaddrivename, loaddirectoryname, loadfilename, loadextname);
|
|
|
|
// If the directory component matches that of the existing lightmap assets
|
|
// then a lightmap is being references - modify the path to match the destination.
|
|
// Otherwise leave it unmodified.
|
|
// NOTE: Ignore case sensitivity in the directory name comparison.
|
|
savechunk.Begin_Chunk (loadpathchunk->ChunkType);
|
|
if ((strlen (loaddrivename) == 0) && (stricmp (loaddirectoryname, LightscapeSolve::Asset_Directory()) == 0)) {
|
|
strcpy (pathname, LightscapeSolve::Asset_Directory (lightmapdirectory));
|
|
strcat (pathname, loadfilename);
|
|
strcat (pathname, loadextname);
|
|
savechunk.Write (pathname, strlen (pathname) + 1);
|
|
} else {
|
|
savechunk.Write (loadpathchunk->Get_Data(), loadpathchunk->Get_Size());
|
|
}
|
|
savechunk.End_Chunk();
|
|
delete loadpathchunk;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
|
|
// Copy other texture chunks unmodified.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
savechunk.End_Chunk();
|
|
}
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_Collection -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_Collection (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *filename)
|
|
{
|
|
unsigned filenamesize = strlen (filename) + 1;
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_COLLECTION_HEADER:
|
|
{
|
|
W3dCollectionHeaderStruct header;
|
|
|
|
ASSERT (filenamesize <= sizeof (header.Name));
|
|
|
|
if (loadchunk.Read (&header, loadchunk.Cur_Chunk_Length()) != loadchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_COLLECTION_HEADER.");
|
|
}
|
|
strcpy (header.Name, filename);
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
savechunk.Write (&header, sizeof (header));
|
|
savechunk.End_Chunk();
|
|
break;
|
|
}
|
|
|
|
case W3D_CHUNK_COLLECTION_OBJ_NAME:
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
if (loadchunk.Cur_Chunk_Length() > 0) {
|
|
|
|
char *loadname, *savename, *suffix;
|
|
|
|
loadname = new char [loadchunk.Cur_Chunk_Length()];
|
|
ASSERT (loadname != NULL);
|
|
|
|
// Allocate a string long enough to hold the save string.
|
|
savename = new char [loadchunk.Cur_Chunk_Length() + filenamesize];
|
|
ASSERT (savename != NULL);
|
|
|
|
if (loadchunk.Read (loadname, loadchunk.Cur_Chunk_Length()) != loadchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_COLLECTION_OBJ_NAME.");
|
|
}
|
|
|
|
strcpy (savename, filename);
|
|
suffix = strrchr (loadname, '.');
|
|
if (suffix != NULL) {
|
|
strcat (savename, suffix);
|
|
}
|
|
|
|
savechunk.Write (savename, strlen (savename) + 1);
|
|
|
|
// Clean-up.
|
|
delete [] savename;
|
|
delete [] loadname;
|
|
}
|
|
savechunk.End_Chunk();
|
|
break;
|
|
|
|
default:
|
|
|
|
// Other collection chunks.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_HLOD -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_HLOD (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *filename)
|
|
{
|
|
unsigned filenamesize = strlen (filename) + 1;
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_HLOD_HEADER:
|
|
{
|
|
W3dHLodHeaderStruct header;
|
|
|
|
ASSERT (filenamesize <= sizeof (header.Name));
|
|
|
|
if (loadchunk.Read (&header, loadchunk.Cur_Chunk_Length()) != loadchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_HLOD_HEADER.");
|
|
}
|
|
strcpy (header.Name, filename);
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
savechunk.Write (&header, sizeof (header));
|
|
savechunk.End_Chunk();
|
|
break;
|
|
}
|
|
|
|
case W3D_CHUNK_HLOD_LOD_ARRAY:
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_HLOD_SUB_OBJECT:
|
|
{
|
|
W3dHLodSubObjectStruct subobject;
|
|
char subobjectname [sizeof (subobject.Name)];
|
|
char *suffix;
|
|
|
|
if (loadchunk.Read (&subobject, loadchunk.Cur_Chunk_Length()) != loadchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_HLOD_LOD_ARRAY.");
|
|
}
|
|
|
|
ASSERT (filenamesize <= sizeof (subobjectname));
|
|
strcpy (subobjectname, filename);
|
|
suffix = strrchr (subobject.Name, '.');
|
|
if (suffix != NULL) {
|
|
ASSERT ((filenamesize + strlen (suffix)) <= sizeof (subobjectname));
|
|
strcat (subobjectname, suffix);
|
|
}
|
|
strcpy (subobject.Name, subobjectname);
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
savechunk.Write (&subobject, sizeof (subobject));
|
|
savechunk.End_Chunk();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
|
|
// Other collection chunks.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
savechunk.End_Chunk();
|
|
break;
|
|
|
|
default:
|
|
|
|
// Other collection chunks.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Rename_Dazzle -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Rename_Dazzle (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk, const char *filename)
|
|
{
|
|
unsigned filenamesize = strlen (filename) + 1;
|
|
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
|
|
while (loadchunk.Open_Chunk()) {
|
|
|
|
switch (loadchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_DAZZLE_NAME:
|
|
{
|
|
savechunk.Begin_Chunk (loadchunk.Cur_Chunk_ID());
|
|
if (loadchunk.Cur_Chunk_Length() > 0) {
|
|
|
|
char *loadname, *savename, *suffix;
|
|
|
|
loadname = new char [loadchunk.Cur_Chunk_Length()];
|
|
ASSERT (loadname != NULL);
|
|
|
|
// Allocate a string long enough to hold the save string.
|
|
savename = new char [loadchunk.Cur_Chunk_Length() + filenamesize];
|
|
ASSERT (savename != NULL);
|
|
|
|
if (loadchunk.Read (loadname, loadchunk.Cur_Chunk_Length()) != loadchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_COLLECTION_OBJ_NAME.");
|
|
}
|
|
|
|
strcpy (savename, filename);
|
|
suffix = strrchr (loadname, '.');
|
|
if (suffix != NULL) {
|
|
strcat (savename, suffix);
|
|
}
|
|
|
|
savechunk.Write (savename, strlen (savename) + 1);
|
|
|
|
// Clean-up.
|
|
delete [] savename;
|
|
delete [] loadname;
|
|
}
|
|
savechunk.End_Chunk();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Other dazzle chunks.
|
|
Copy_Chunk (loadchunk, savechunk);
|
|
break;
|
|
}
|
|
loadchunk.Close_Chunk();
|
|
}
|
|
|
|
savechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Save_Lights -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/04/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Save_Lights (const char *pathname)
|
|
{
|
|
const char *extension = ".wlt"; // Extension for Westwood light file.
|
|
|
|
char lightpathname [_MAX_PATH];
|
|
char drivename [_MAX_DRIVE];
|
|
char directoryname [_MAX_DIR];
|
|
char filename [_MAX_FNAME];
|
|
|
|
_splitpath (pathname, drivename, directoryname, filename, NULL);
|
|
strcpy (lightpathname, drivename);
|
|
strcat (lightpathname, directoryname);
|
|
strcat (lightpathname, filename);
|
|
strcat (lightpathname, extension);
|
|
|
|
RawFileClass *lightfile = new RawFileClass (lightpathname);
|
|
ASSERT (lightfile != NULL);
|
|
|
|
// NOTE: RawFileClass will not keep a copy of the filename unless Set_Name() is explicitly called.
|
|
lightfile->Set_Name (lightpathname);
|
|
|
|
// NOTE: WRITE only access will truncate any existing temporary file.
|
|
lightfile->Open (FileClass::WRITE);
|
|
|
|
ChunkSaveClass lightchunk (lightfile);
|
|
|
|
for (unsigned s = 0; s < MAX_SOLVE_COUNT; s++) {
|
|
|
|
lightchunk.Begin_Chunk (W3D_CHUNK_LIGHTSCAPE);
|
|
|
|
// For each light...
|
|
for (int l = 0; l < Lights [s].Count(); l++) {
|
|
|
|
const Matrix3D t = Lights [s][l]->Get_Transform();
|
|
const W3dLightTransformStruct transform = {t [0][0], t [0][1], t [0][2], t [0][3],
|
|
t [1][0], t [1][1], t [1][2], t [1][3],
|
|
t [2][0], t [2][1], t [2][2], t [2][3]};
|
|
|
|
// Save light attributes.
|
|
lightchunk.Begin_Chunk (W3D_CHUNK_LIGHTSCAPE_LIGHT);
|
|
|
|
Lights [s][l]->Save_W3D (lightchunk);
|
|
|
|
// Save light position and orientation.
|
|
lightchunk.Begin_Chunk (W3D_CHUNK_LIGHT_TRANSFORM);
|
|
lightchunk.Write (&transform, sizeof (transform));
|
|
lightchunk.End_Chunk();
|
|
|
|
lightchunk.End_Chunk();
|
|
}
|
|
lightchunk.End_Chunk();
|
|
}
|
|
lightfile->Close();
|
|
|
|
// Clean-up.
|
|
delete lightfile;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::DeleteContents -- Delete the document's data (close the document file). *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::DeleteContents()
|
|
{
|
|
// Get the solve to delete its assets.
|
|
LightscapeSolve::Delete_Assets();
|
|
|
|
// Close any previously opened document.
|
|
if (W3dFile != NULL) {
|
|
delete W3dFile;
|
|
W3dFile = NULL;
|
|
}
|
|
|
|
// Re-initialize data.
|
|
MeshCount = 0;
|
|
TriangleCount = 0;
|
|
CanInsertSolve = false;
|
|
SolveCount = 0;
|
|
MeshStatus.Clear();
|
|
|
|
// Release references to lights.
|
|
for (unsigned s = 0; s < MAX_SOLVE_COUNT; s++) {
|
|
for (int l = 0; l < Lights [s].Count(); l++) {
|
|
Lights [s][l]->Release_Ref();
|
|
}
|
|
Lights [s].Clear();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnUpdateFileSave -- Is the 'File->Save' menu option selectable? *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::OnUpdateFileSave (CCmdUI* cmdui)
|
|
{
|
|
cmdui->Enable (Is_Open() && IsModified());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::OnUpdateFileSaveAs -- Is the 'File->Save As...' menu option selectable? *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::OnUpdateFileSaveAs (CCmdUI* cmdui)
|
|
{
|
|
cmdui->Enable (Is_Open());
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Insert_Solve -- Add a lightmap solve to the current open document file. *
|
|
* *
|
|
* Add a lightmap pass to the current open w3d file using the supplied solvepathname as the *
|
|
* solve file. For each chunk translate as appropriate, writing the results to a temporary *
|
|
* file. If the temporary file is successfully created close the current document and make the *
|
|
* temporary file the current open document. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Insert_Solve (const char *solvedirectoryname, const char *solvefilenamelist, const char *inclusionstring, bool invertselection, bool blendnoise)
|
|
{
|
|
const char *buildingtext = "Step 1/2: Building solve database"; // Status bar message.
|
|
const char *insertingtext = "Step 2/2: Inserting solve"; // Status bar message.
|
|
const char *solvetext = "Solve #"; // Status bar message.
|
|
const char *insertedtext = " inserted"; // Status bar message.
|
|
const char *notinsertedtext = " not inserted"; // Status bar message.
|
|
|
|
char temporarypathname [_MAX_PATH];
|
|
char *meshfilebuffer = NULL;
|
|
|
|
ASSERT (CanInsertSolve);
|
|
ASSERT (SolveCount < MAX_SOLVE_COUNT);
|
|
|
|
CMainFrame* frameptr = (CMainFrame*) AfxGetApp()->m_pMainWnd;
|
|
CStatusBar* statusptr = &(frameptr->m_wndStatusBar);
|
|
RawFileClass *solvefile = NULL;
|
|
|
|
try {
|
|
|
|
// Reorder the meshes within the document.
|
|
Reorder();
|
|
|
|
// Inform the user that the insertion process has started.
|
|
CWaitCursor waitcursor;
|
|
|
|
W3dFile->Open (FileClass::READ);
|
|
|
|
// Create a temporary file to contain the results of the solve.
|
|
strcpy (temporarypathname, theApp.Working_Path());
|
|
strcat (temporarypathname, _TemporarySolveFilename [SolveCount % TEMPORARY_SOLVE_FILENAME_COUNT]);
|
|
strcat (temporarypathname, theApp.Instance_Name());
|
|
solvefile = new RawFileClass (temporarypathname);
|
|
ASSERT (solvefile != NULL);
|
|
|
|
// NOTE: RawFileClass will not keep a copy of the filename unless Set_Name() is explicitly called.
|
|
solvefile->Set_Name (temporarypathname);
|
|
|
|
// NOTE: WRITE only access will truncate any existing temporary file.
|
|
solvefile->Open (FileClass::WRITE);
|
|
|
|
ChunkLoadClass w3dchunk (W3dFile);
|
|
ChunkSaveClass solvechunk (solvefile);
|
|
CProgressCtrl progressbar;
|
|
CRect srect, trect;
|
|
BOOL success;
|
|
unsigned meshindex;
|
|
unsigned anomalycount;
|
|
|
|
// Create the solve for the entire model from the solution file(s).
|
|
LightscapeSolve solve (solvedirectoryname, solvefilenamelist, statusptr, buildingtext, blendnoise);
|
|
|
|
statusptr->GetItemRect (0, &srect);
|
|
statusptr->SetPaneText (0, insertingtext);
|
|
statusptr->GetDC()->DrawText (insertingtext, -1, &trect, DT_CALCRECT);
|
|
|
|
CRect prect (srect.TopLeft().x + trect.Width(), srect.TopLeft().y, srect.BottomRight().x, srect.BottomRight().y);
|
|
|
|
success = progressbar.Create (WS_CHILD | WS_VISIBLE | PBS_SMOOTH, prect, statusptr, 0);
|
|
ASSERT (success);
|
|
progressbar.SetRange32 (0, TriangleCount);
|
|
|
|
// While there are w3d chunks...
|
|
meshindex = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
// Is this a mesh chunk?
|
|
if (w3dchunk.Cur_Chunk_ID() == W3D_CHUNK_MESH) {
|
|
|
|
bool includemesh;
|
|
|
|
// Currently, nothing has been inserted.
|
|
unsigned long insertedflags = 0;
|
|
|
|
// If this mesh name contains the inclusion character (if not null) and if a vertex solve and/or a lightmap solve can be inserted...
|
|
if (inclusionstring == NULL) {
|
|
includemesh = true;
|
|
} else {
|
|
includemesh = strstr (MeshStatus [meshindex].Name, inclusionstring) != NULL;
|
|
if (invertselection) includemesh = !includemesh;
|
|
}
|
|
if (includemesh && (MeshStatus [meshindex].Can_Insert_Vertex_Solve() || MeshStatus [meshindex].Can_Insert_Multi_Pass_Solve() || MeshStatus [meshindex].Can_Insert_Multi_Texture_Solve())) {
|
|
|
|
unsigned long fileposition;
|
|
ChunkLoadClass meshchunk (w3dchunk);
|
|
|
|
meshfilebuffer = new char [w3dchunk.Cur_Chunk_Length()];
|
|
ASSERT (meshfilebuffer != NULL);
|
|
fileposition = W3dFile->Seek (0, SEEK_CUR);
|
|
if (meshchunk.Read (meshfilebuffer, w3dchunk.Cur_Chunk_Length()) != w3dchunk.Cur_Chunk_Length()) throw ("Cannot read data in W3D_CHUNK_MESH.");
|
|
W3dFile->Seek (fileposition, SEEK_SET);
|
|
|
|
RAMFileClass meshfile (meshfilebuffer, w3dchunk.Cur_Chunk_Length());
|
|
MeshInfoStruct meshinfo (meshfile);
|
|
LightscapeMeshSolve meshsolve (solve, *meshinfo.TriangleChunk, *meshinfo.VertexChunk);
|
|
SplitVertexInfoStruct splitvertexinfo (meshinfo, meshsolve);
|
|
unsigned long prelitflags;
|
|
|
|
// Update the status for this mesh.
|
|
// Analyze the mesh status to see if it is compatible with each solve type (vertex, lightmap or both).
|
|
MeshStatus [meshindex].SolveStatistics = *meshsolve.Get_Statistics();
|
|
prelitflags = MeshStatus [meshindex].Prelit_Flags();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
// While there are mesh chunks...
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MESH_HEADER3:
|
|
Translate_Mesh_Header3 (w3dchunk, prelitflags, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTICES:
|
|
Translate_Vertices (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_NORMALS:
|
|
Translate_Vertex_Normals (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_INFLUENCES:
|
|
Translate_Vertex_Influences (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_TRIANGLES:
|
|
Translate_Triangles (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_SHADE_INDICES:
|
|
Translate_Vertex_Shade_Indices (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_INFO:
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_UNLIT) Insert_Solve (UNLIT, meshfile, UNLIT, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_VERTEX) {
|
|
Insert_Solve (UNLIT, meshfile, VERTEX, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
insertedflags |= W3D_MESH_FLAG_PRELIT_VERTEX;
|
|
}
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_PASS) {
|
|
Insert_Solve (UNLIT, meshfile, MULTI_PASS, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
insertedflags |= W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_PASS;
|
|
}
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_TEXTURE) {
|
|
Insert_Solve (UNLIT, meshfile, MULTI_TEXTURE, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
insertedflags |= W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_TEXTURE;
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIALS:
|
|
case W3D_CHUNK_SHADERS:
|
|
case W3D_CHUNK_TEXTURES:
|
|
case W3D_CHUNK_MATERIAL_PASS:
|
|
// Skip these chunks.
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_VERTEX:
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_VERTEX) {
|
|
Insert_Solve (VERTEX, w3dchunk, VERTEX, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
insertedflags |= W3D_MESH_FLAG_PRELIT_VERTEX;
|
|
} else {
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS:
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_PASS) {
|
|
Insert_Solve (MULTI_PASS, w3dchunk, MULTI_PASS, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
insertedflags |= W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_PASS;
|
|
} else {
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
}
|
|
break;
|
|
|
|
case W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE:
|
|
if (prelitflags & W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_TEXTURE) {
|
|
Insert_Solve (MULTI_TEXTURE, w3dchunk, MULTI_TEXTURE, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
insertedflags |= W3D_MESH_FLAG_PRELIT_LIGHTMAP_MULTI_TEXTURE;
|
|
} else {
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
// This chunk does not need to be modified. Just copy it.
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
|
|
// Clean-up.
|
|
delete [] meshfilebuffer;
|
|
meshfilebuffer = NULL;
|
|
|
|
} else {
|
|
|
|
// No solves can be inserted. Just copy the existing mesh chunk.
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
}
|
|
|
|
// Update mesh status.
|
|
MeshStatus [meshindex].InsertedFlags = insertedflags;
|
|
|
|
// Advance progress bar.
|
|
progressbar.SetStep (MeshStatus [meshindex].TriangleCount);
|
|
progressbar.StepIt();
|
|
|
|
// Advance mesh counter.
|
|
meshindex++;
|
|
|
|
} else {
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
solve.Finish();
|
|
progressbar.ShowWindow (SW_HIDE);
|
|
|
|
// Scan the mesh status array to see if there were any anomalies.
|
|
anomalycount = 0;
|
|
for (unsigned m = 0; m < MeshCount; m++) {
|
|
if (!(MeshStatus [m].SolveStatistics == 0)) anomalycount++;
|
|
}
|
|
|
|
if (anomalycount > 0) {
|
|
|
|
const char *anomalytext =
|
|
"%d meshes have solve anomalies associated with them. If the anomaly is serious, a\
|
|
vertex or lightmap solve may not have been inserted. Check each mesh for specific\
|
|
anomalies by left-clicking on the mesh name in the list.";
|
|
|
|
StringBuilder anomalymessage (8192);
|
|
|
|
anomalymessage.Copy (anomalytext, anomalycount);
|
|
MessageBox (NULL, anomalymessage.String(), "Attention", MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
|
}
|
|
|
|
// Add lights to the light array.
|
|
// NOTE: Add references to the lights from the solve.
|
|
// This will ensure that the lights will not be deleted when the solve goes out of scope.
|
|
for (unsigned l = 0; l < solve.Light_Count(); l++) {
|
|
|
|
LightClass *light = solve.Get_Light (l);
|
|
|
|
Lights [SolveCount].Add (light);
|
|
light->Add_Ref();
|
|
}
|
|
|
|
// Clean-up.
|
|
delete W3dFile;
|
|
solvefile->Close();
|
|
|
|
// Make the current solve file the w3d file.
|
|
W3dFile = solvefile;
|
|
|
|
// Flag that the document has been modified.
|
|
SetModifiedFlag (TRUE);
|
|
|
|
// Increment no. of solves inserted so far.
|
|
SolveCount++;
|
|
|
|
// Inform user that solve has been inserted.
|
|
StringBuilder string (256);
|
|
string.Copy ("%s%d%s", solvetext, SolveCount, insertedtext);
|
|
statusptr->SetPaneText (0, string.String());
|
|
|
|
UpdateAllViews (NULL);
|
|
|
|
} catch (const char *errormessage) {
|
|
|
|
const char *prefixmessage = "The solve cannot be inserted.\n\n";
|
|
|
|
char *messagebuffer;
|
|
|
|
// Clean-up.
|
|
if (meshfilebuffer != NULL) delete [] meshfilebuffer;
|
|
W3dFile->Close();
|
|
if (solvefile != NULL) delete solvefile;
|
|
|
|
// Prefix the error message.
|
|
messagebuffer = new char [strlen (prefixmessage) + strlen (errormessage) + 1];
|
|
ASSERT (messagebuffer);
|
|
strcpy (messagebuffer, prefixmessage);
|
|
strcat (messagebuffer, errormessage);
|
|
MessageBox (NULL, messagebuffer, NULL, MB_ICONERROR | MB_SETFOREGROUND);
|
|
delete messagebuffer;
|
|
|
|
// Inform user that solve has NOT been inserted.
|
|
StringBuilder string (256);
|
|
string.Copy ("%s%d%s", solvetext, SolveCount, notinsertedtext);
|
|
statusptr->SetPaneText (0, string.String());
|
|
|
|
UpdateAllViews (NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Mesh_Header3 -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Mesh_Header3 (ChunkLoadClass &w3dchunk, unsigned long prelitflags, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
W3dMeshHeader3Struct header;
|
|
|
|
if (w3dchunk.Read (&header, sizeof (header)) != sizeof (header)) throw ("Cannot read data in W3D_CHUNK_MESH_HEADER3.");
|
|
|
|
// Flag that this is a lightmapped mesh.
|
|
header.Attributes |= prelitflags;
|
|
|
|
// For asset tracking purposes, stamp the version no. of this tool into the mesh.
|
|
header.PrelitVersion = theApp.Application_Version();
|
|
|
|
// Set no. of vertices to accout for vertex splitting.
|
|
header.NumVertices = splitvertexinfo.Vertex_Count();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
solvechunk.Write (&header, sizeof (header));
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Vertices -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Vertices (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *vertexchunk;
|
|
W3dVectorStruct *vertices;
|
|
|
|
vertexchunk = new ChunkClass (w3dchunk);
|
|
ASSERT (vertexchunk != NULL);
|
|
|
|
vertices = (W3dVectorStruct*) vertexchunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (vertices + splitvertexinfo.Remap (v), sizeof (W3dVectorStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete vertexchunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Vertex_Normals -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Vertex_Normals (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *vertexnormalchunk;
|
|
W3dVectorStruct *vertexnormals;
|
|
|
|
vertexnormalchunk = new ChunkClass (w3dchunk);
|
|
ASSERT (vertexnormalchunk != NULL);
|
|
|
|
vertexnormals = (W3dVectorStruct*) vertexnormalchunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned n = 0; n < splitvertexinfo.Vertex_Count(); n++) {
|
|
solvechunk.Write (vertexnormals + splitvertexinfo.Remap (n), sizeof (W3dVectorStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete vertexnormalchunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Vertex_Influences -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Vertex_Influences (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *vertexinfluencechunk;
|
|
W3dVertInfStruct *vertexinfluences;
|
|
|
|
vertexinfluencechunk = new ChunkClass (w3dchunk);
|
|
ASSERT (vertexinfluencechunk != NULL);
|
|
|
|
vertexinfluences = (W3dVertInfStruct*) vertexinfluencechunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (vertexinfluences + splitvertexinfo.Remap (v), sizeof (W3dVertInfStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete vertexinfluencechunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Triangles -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Triangles (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
const unsigned verticesperface = 3; // No. of vertices in a triangle.
|
|
|
|
ChunkClass *trianglechunk;
|
|
unsigned facecount, facevertexindex;
|
|
W3dTriStruct *triangles;
|
|
|
|
trianglechunk = new ChunkClass (w3dchunk);
|
|
ASSERT (trianglechunk != NULL);
|
|
facecount = trianglechunk->Get_Size() / sizeof (W3dTriStruct);
|
|
triangles = (W3dTriStruct*) trianglechunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
facevertexindex = 0;
|
|
for (unsigned f = 0; f < facecount; f++) {
|
|
|
|
W3dTriStruct triangle = triangles [f];
|
|
|
|
for (unsigned v = 0; v < verticesperface; v++) {
|
|
triangle.Vindex [v] = splitvertexinfo.Index (facevertexindex);
|
|
facevertexindex++;
|
|
}
|
|
solvechunk.Write (&triangle, sizeof (triangle));
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
|
|
delete trianglechunk;
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Vertex_Shade_Indices -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 04/06/01 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Vertex_Shade_Indices (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *vertexshadeindiceschunk;
|
|
uint32 *vertexshadeindices;
|
|
|
|
vertexshadeindiceschunk = new ChunkClass (w3dchunk);
|
|
ASSERT (vertexshadeindiceschunk != NULL);
|
|
|
|
vertexshadeindices = (uint32*) vertexshadeindiceschunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (vertexshadeindices + splitvertexinfo.Remap (v), sizeof (uint32));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete vertexshadeindiceschunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Insert_Solve -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Insert_Solve (PrelitModeEnum inputmode, FileClass &meshfile, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkLoadClass w3dchunk (&meshfile);
|
|
unsigned materialpass;
|
|
bool hastexturechunk;
|
|
|
|
// This routine can only parse unlit W3D chunks.
|
|
ASSERT (inputmode == UNLIT);
|
|
|
|
// Output the appropriate prelit wrapper chunk.
|
|
switch (outputmode) {
|
|
|
|
case UNLIT:
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_PRELIT_UNLIT);
|
|
break;
|
|
|
|
case VERTEX:
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_PRELIT_VERTEX);
|
|
break;
|
|
|
|
case MULTI_PASS:
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS);
|
|
break;
|
|
|
|
case MULTI_TEXTURE:
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE);
|
|
break;
|
|
}
|
|
|
|
meshfile.Open (FileClass::READ);
|
|
|
|
// While there are mesh chunks...
|
|
materialpass = 0;
|
|
hastexturechunk = false;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MESH_HEADER3:
|
|
|
|
// Ignore these chunk types.
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_INFO:
|
|
Translate_Material_Info (inputmode, w3dchunk, outputmode, solvechunk, meshinfo, meshsolve);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIALS:
|
|
Translate_Vertex_Materials (inputmode, w3dchunk, outputmode, solvechunk, meshinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_SHADERS:
|
|
Translate_Shaders (inputmode, w3dchunk, outputmode, solvechunk, meshinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_TEXTURES:
|
|
Translate_Textures (w3dchunk, outputmode, solvechunk, meshsolve);
|
|
hastexturechunk = true;
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_PASS:
|
|
|
|
// If adding lightmaps and no texture chunk has been encountered so far add one now.
|
|
// NOTE: WW3D expects the texture chunk to precede the material pass chunk.
|
|
if (!hastexturechunk && ((outputmode == MULTI_PASS) || (outputmode == MULTI_TEXTURE))) {
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURES);
|
|
Add_Lightmap_Textures (solvechunk, meshsolve);
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
Translate_Material_Pass (inputmode, w3dchunk, materialpass, outputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
materialpass++;
|
|
break;
|
|
|
|
default:
|
|
|
|
// Ignore these chunk types.
|
|
break;
|
|
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
// If this is the last pass, add an additional material pass now.
|
|
if ((materialpass == meshinfo.MaterialInfo [inputmode].PassCount) && (outputmode == MULTI_PASS)) {
|
|
Add_Lightmap_Material_Pass (inputmode, materialpass - 1, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
}
|
|
|
|
meshfile.Close();
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Insert_Solve -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Insert_Solve (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
unsigned materialpass;
|
|
|
|
// This routine can only parse prelit W3D chunks.
|
|
ASSERT (inputmode != UNLIT);
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
// While there are mesh chunks...
|
|
materialpass = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_MATERIAL_INFO:
|
|
Translate_Material_Info (inputmode, w3dchunk, outputmode, solvechunk, meshinfo, meshsolve);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIALS:
|
|
Translate_Vertex_Materials (inputmode, w3dchunk, outputmode, solvechunk, meshinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_SHADERS:
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
|
|
case W3D_CHUNK_TEXTURES:
|
|
Translate_Textures (w3dchunk, outputmode, solvechunk, meshsolve);
|
|
break;
|
|
|
|
case W3D_CHUNK_MATERIAL_PASS:
|
|
Translate_Material_Pass (inputmode, w3dchunk, materialpass, outputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
materialpass++;
|
|
break;
|
|
|
|
default:
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Material_Info -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Material_Info (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve)
|
|
{
|
|
W3dMaterialInfoStruct materialinfo;
|
|
|
|
if (w3dchunk.Read (&materialinfo, sizeof (materialinfo)) != sizeof (materialinfo)) {
|
|
throw ("Cannot read data in W3D_CHUNK_MATERIAL_INFO.");
|
|
}
|
|
|
|
if ((outputmode == MULTI_PASS) || (outputmode == MULTI_TEXTURE)) {
|
|
if (outputmode == MULTI_PASS) {
|
|
if (inputmode == UNLIT) {
|
|
|
|
// Increment pass count to accomodate lightmap pass.
|
|
materialinfo.PassCount++;
|
|
|
|
materialinfo.VertexMaterialCount += meshinfo.Lightmap_Vertex_Material_Count();
|
|
materialinfo.ShaderCount += meshinfo.Lightmap_Shader_Count();
|
|
}
|
|
}
|
|
|
|
// Increment texture count to accomodate additional lightmap textures.
|
|
ASSERT (materialinfo.TextureCount == meshinfo.MaterialInfo [inputmode].TextureCount);
|
|
materialinfo.TextureCount += meshsolve.Lightmap_Count();
|
|
}
|
|
|
|
WWASSERT (MAX_SOLVE_COUNT == 2);
|
|
if (inputmode != UNLIT) {
|
|
materialinfo.VertexMaterialCount *= 2;
|
|
}
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
solvechunk.Write (&materialinfo, sizeof (materialinfo));
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Vertex_Materials -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Vertex_Materials (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo)
|
|
{
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
ASSERT (meshinfo.MaterialInfo [inputmode].VertexMaterialCount > 0);
|
|
|
|
if (inputmode == UNLIT) {
|
|
|
|
const W3dRGBStruct black ((uint8) 0x00, (uint8) 0x00, (uint8) 0x00);
|
|
const W3dRGBStruct white ((uint8) 0xff, (uint8) 0xff, (uint8) 0xff);
|
|
|
|
W3dVertexMaterialStruct vertexmaterialinfo;
|
|
|
|
// Translate the existing vertex materials.
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIAL_NAME:
|
|
|
|
// Copy chunk unmodified.
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MAPPER_ARGS0:
|
|
|
|
switch (outputmode) {
|
|
|
|
case UNLIT:
|
|
case VERTEX:
|
|
case MULTI_PASS:
|
|
|
|
// Copy chunk unmodified.
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
|
|
case MULTI_TEXTURE:
|
|
{
|
|
char *argbuffer;
|
|
|
|
// Any args in stage 0 must be moved to stage 1 because the base texture is in stage 1.
|
|
argbuffer = new char [w3dchunk.Cur_Chunk_Length()];
|
|
if (w3dchunk.Read (argbuffer, w3dchunk.Cur_Chunk_Length()) != w3dchunk.Cur_Chunk_Length()) {
|
|
throw ("Cannot read data in W3D_CHUNK_VERTEX_MAPPER_ARGS.");
|
|
}
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_VERTEX_MAPPER_ARGS1);
|
|
solvechunk.Write (argbuffer, w3dchunk.Cur_Chunk_Length());
|
|
solvechunk.End_Chunk();
|
|
delete [] argbuffer;
|
|
break;
|
|
}
|
|
}
|
|
|
|
case W3D_CHUNK_VERTEX_MAPPER_ARGS1:
|
|
|
|
// Remove this chunk.
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIAL_INFO:
|
|
{
|
|
W3dRGBStruct diffuse;
|
|
|
|
// Read the chunk.
|
|
if (w3dchunk.Read (&vertexmaterialinfo, sizeof (vertexmaterialinfo)) != sizeof (vertexmaterialinfo)) {
|
|
throw ("Cannot read data in W3D_CHUNK_VERTEX_MATERIAL_INFO.");
|
|
}
|
|
|
|
switch (outputmode) {
|
|
|
|
case UNLIT:
|
|
// No change.
|
|
break;
|
|
|
|
case MULTI_TEXTURE:
|
|
{
|
|
uint32 stage0attributes, stage1attributes;
|
|
|
|
// If there are any mappers in stage 0 it must be shifted to stage 1 because
|
|
// the base texture is now in stage 1.
|
|
stage0attributes = vertexmaterialinfo.Attributes & W3DVERTMAT_STAGE0_MAPPING_MASK;
|
|
if (W3DVERTMAT_STAGE0_MAPPING_MASK > W3DVERTMAT_STAGE1_MAPPING_MASK) {
|
|
stage1attributes = stage0attributes / (W3DVERTMAT_STAGE0_MAPPING_MASK / W3DVERTMAT_STAGE1_MAPPING_MASK);
|
|
} else {
|
|
stage1attributes = stage0attributes * (W3DVERTMAT_STAGE1_MAPPING_MASK / W3DVERTMAT_STAGE0_MAPPING_MASK);
|
|
}
|
|
|
|
// Clear the stage 0 and stage 1 attributes.
|
|
// NOTE: Stage 1 attributes should be unused but clear them anyway as a precaution.
|
|
vertexmaterialinfo.Attributes &= ~(W3DVERTMAT_STAGE0_MAPPING_MASK | W3DVERTMAT_STAGE1_MAPPING_MASK);
|
|
|
|
// Add in the new stage 1 attributes.
|
|
vertexmaterialinfo.Attributes |= stage1attributes;
|
|
|
|
// NOTE: Fall thru.
|
|
}
|
|
|
|
default:
|
|
vertexmaterialinfo.Emissive = vertexmaterialinfo.Diffuse;
|
|
vertexmaterialinfo.Ambient = black;
|
|
vertexmaterialinfo.Diffuse = black;
|
|
vertexmaterialinfo.Specular = black;
|
|
vertexmaterialinfo.Shininess = 1.0f;
|
|
vertexmaterialinfo.Translucency = 0.0f;
|
|
break;
|
|
}
|
|
|
|
// Write the modified chunk.
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
solvechunk.Write (&vertexmaterialinfo, sizeof (vertexmaterialinfo));
|
|
solvechunk.End_Chunk();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
|
|
// Any other chunk type can be copied unmodified.
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
// Write out a vertex material for the lightmap pass.
|
|
if (outputmode == MULTI_PASS) {
|
|
|
|
const char *vertexmaterialname = "Lightmap";
|
|
|
|
W3dVertexMaterialStruct vertexmaterialinfo;
|
|
|
|
// Only 1 lightmap vertex material is supported.
|
|
ASSERT (meshinfo.Lightmap_Vertex_Material_Count() == 1);
|
|
|
|
W3d_Vertex_Material_Reset (&vertexmaterialinfo);
|
|
vertexmaterialinfo.Emissive = white;
|
|
vertexmaterialinfo.Ambient = black;
|
|
vertexmaterialinfo.Diffuse = black;
|
|
vertexmaterialinfo.Specular = black;
|
|
vertexmaterialinfo.Shininess = 1.0f;
|
|
vertexmaterialinfo.Translucency = 0.0f;
|
|
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_VERTEX_MATERIAL);
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_VERTEX_MATERIAL_NAME);
|
|
solvechunk.Write (vertexmaterialname, strlen (vertexmaterialname) + 1);
|
|
solvechunk.End_Chunk();
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_VERTEX_MATERIAL_INFO);
|
|
solvechunk.Write (&vertexmaterialinfo, sizeof (vertexmaterialinfo));
|
|
solvechunk.End_Chunk();
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
} else {
|
|
|
|
DynamicVectorClass <ChunkClass*> vertexmaterialchunks;
|
|
|
|
// Duplicate all of the existing vertex materials.
|
|
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
ChunkClass *vertexmaterialchunkptr;
|
|
|
|
vertexmaterialchunkptr = new ChunkClass (w3dchunk);
|
|
|
|
solvechunk.Begin_Chunk (vertexmaterialchunkptr->ChunkType);
|
|
solvechunk.Write (vertexmaterialchunkptr->Get_Data(), vertexmaterialchunkptr->Get_Size());
|
|
solvechunk.End_Chunk();
|
|
|
|
vertexmaterialchunks.Add (vertexmaterialchunkptr);
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
for (int vm = 0; vm < vertexmaterialchunks.Count(); vm++) {
|
|
solvechunk.Begin_Chunk (vertexmaterialchunks [vm]->ChunkType);
|
|
solvechunk.Write (vertexmaterialchunks [vm]->Get_Data(), vertexmaterialchunks [vm]->Get_Size());
|
|
solvechunk.End_Chunk();
|
|
|
|
delete vertexmaterialchunks [vm];
|
|
}
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Shaders -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Shaders (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo)
|
|
{
|
|
unsigned s;
|
|
W3dShaderStruct shader;
|
|
|
|
ASSERT (meshinfo.MaterialInfo [inputmode].ShaderCount > 0);
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
for (s = 0; s < meshinfo.MaterialInfo [inputmode].ShaderCount; s++) {
|
|
|
|
if (w3dchunk.Read (&shader, sizeof (shader)) != sizeof (shader)) {
|
|
throw ("Cannot read data in W3D_CHUNK_SHADERS.");
|
|
}
|
|
|
|
switch (outputmode) {
|
|
|
|
case UNLIT:
|
|
case VERTEX:
|
|
case MULTI_PASS:
|
|
|
|
// No change.
|
|
break;
|
|
|
|
case MULTI_TEXTURE:
|
|
// If texturing is not currently enabled then enable single-texture rendering -
|
|
// otherwise enable multi-texture rendering.
|
|
if (W3d_Shader_Get_Texturing (&shader) == W3DSHADER_TEXTURING_DISABLE) {
|
|
|
|
W3d_Shader_Set_Texturing (&shader, W3DSHADER_TEXTURING_ENABLE);
|
|
|
|
} else {
|
|
|
|
ASSERT (W3d_Shader_Get_Texturing (&shader) == W3DSHADER_TEXTURING_ENABLE);
|
|
|
|
// Enable detail texture.
|
|
W3d_Shader_Set_Detail_Color_Func (&shader, W3DSHADER_DETAILCOLORFUNC_SCALE);
|
|
W3d_Shader_Set_Detail_Alpha_Func (&shader, W3DSHADER_DETAILALPHAFUNC_SCALE);
|
|
W3d_Shader_Set_Post_Detail_Color_Func (&shader, W3DSHADER_DETAILCOLORFUNC_SCALE);
|
|
W3d_Shader_Set_Post_Detail_Alpha_Func (&shader, W3DSHADER_DETAILALPHAFUNC_SCALE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
solvechunk.Write (&shader, sizeof (shader));
|
|
}
|
|
|
|
if (outputmode == MULTI_PASS) {
|
|
|
|
// Write out a set of shaders for the lightmap pass.
|
|
for (s = 0; s < meshinfo.Lightmap_Shader_Count(); s++) {
|
|
|
|
W3d_Shader_Reset (&shader);
|
|
|
|
W3d_Shader_Set_Depth_Compare (&shader, W3DSHADER_DEPTHCOMPARE_PASS_LEQUAL);
|
|
W3d_Shader_Set_Depth_Mask (&shader, W3DSHADER_DEPTHMASK_WRITE_DISABLE);
|
|
W3d_Shader_Set_Src_Blend_Func (&shader, W3DSHADER_SRCBLENDFUNC_ZERO);
|
|
W3d_Shader_Set_Dest_Blend_Func (&shader, W3DSHADER_DESTBLENDFUNC_SRC_COLOR);
|
|
W3d_Shader_Set_Pri_Gradient (&shader, W3DSHADER_PRIGRADIENT_DISABLE);
|
|
W3d_Shader_Set_Sec_Gradient (&shader, W3DSHADER_SECGRADIENT_DISABLE);
|
|
W3d_Shader_Set_Texturing (&shader, W3DSHADER_TEXTURING_ENABLE);
|
|
W3d_Shader_Set_Detail_Color_Func (&shader, W3DSHADER_DETAILCOLORFUNC_DISABLE);
|
|
W3d_Shader_Set_Detail_Alpha_Func (&shader, W3DSHADER_DETAILALPHAFUNC_DISABLE);
|
|
W3d_Shader_Set_Alpha_Test (&shader, W3DSHADER_ALPHATEST_DISABLE);
|
|
W3d_Shader_Set_Post_Detail_Color_Func (&shader, W3DSHADER_DETAILCOLORFUNC_DISABLE);
|
|
W3d_Shader_Set_Post_Detail_Alpha_Func (&shader, W3DSHADER_DETAILALPHAFUNC_DISABLE);
|
|
|
|
solvechunk.Write (&shader, sizeof (shader));
|
|
}
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Textures -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Textures (ChunkLoadClass &w3dchunk, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const LightscapeMeshSolve &meshsolve)
|
|
{
|
|
switch (outputmode) {
|
|
|
|
case UNLIT:
|
|
case VERTEX:
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
|
|
case MULTI_PASS:
|
|
case MULTI_TEXTURE:
|
|
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURES);
|
|
|
|
// Copy the existing texture chunks.
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
ChunkClass *datachunk;
|
|
|
|
datachunk = new ChunkClass (w3dchunk);
|
|
ASSERT (datachunk != NULL);
|
|
|
|
solvechunk.Begin_Chunk (datachunk->ChunkType);
|
|
solvechunk.Write (datachunk->Get_Data(), datachunk->Get_Size());
|
|
solvechunk.End_Chunk();
|
|
|
|
w3dchunk.Close_Chunk();
|
|
|
|
// Clean-up.
|
|
delete datachunk;
|
|
}
|
|
|
|
Add_Lightmap_Textures (solvechunk, meshsolve);
|
|
solvechunk.End_Chunk();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Add_Lightmap_Textures -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Add_Lightmap_Textures (ChunkSaveClass &solvechunk, const LightscapeMeshSolve &meshsolve)
|
|
{
|
|
const int undefined = 0; // Arbitrary value for any unused data field.
|
|
|
|
W3dTextureInfoStruct textureinfo;
|
|
|
|
// Write additional texture chunks, one chunk per lightmap.
|
|
// NOTE: The allowable no. of mip-map levels is dependant upon and increases with the
|
|
// edge blend thickness specified in the lightmap packer.
|
|
textureinfo.Attributes = W3DTEXTURE_MIP_LEVELS_2 | W3DTEXTURE_CLAMP_U | W3DTEXTURE_CLAMP_V;
|
|
textureinfo.AnimType = (uint16) undefined;
|
|
textureinfo.FrameCount = 1;
|
|
textureinfo.FrameRate = (float32) undefined;
|
|
for (unsigned l = 0; l < meshsolve.Lightmap_Count(); l++) {
|
|
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURE);
|
|
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURE_NAME);
|
|
solvechunk.Write (meshsolve.Lightmap_Pathname (l), strlen (meshsolve.Lightmap_Pathname (l)) + 1);
|
|
solvechunk.End_Chunk();
|
|
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURE_INFO);
|
|
solvechunk.Write (&textureinfo, sizeof (textureinfo));
|
|
solvechunk.End_Chunk();
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Material_Pass -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Material_Pass (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, unsigned materialpass, PrelitModeEnum outputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
bool hastexturestage;
|
|
unsigned stage;
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
// While there are material chunks...
|
|
hastexturestage = false;
|
|
stage = 0;
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_DCG:
|
|
Translate_DCGs (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_DIG:
|
|
Translate_DIGs (inputmode, w3dchunk, materialpass, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_VERTEX_MATERIAL_IDS:
|
|
Translate_Vertex_Material_IDs (inputmode, w3dchunk, solvechunk, meshinfo, splitvertexinfo);
|
|
break;
|
|
|
|
case W3D_CHUNK_TEXTURE_STAGE:
|
|
if (inputmode == UNLIT) {
|
|
|
|
// Stage 0 is lightmap, stage 1 is base texture.
|
|
if (outputmode == MULTI_TEXTURE) {
|
|
Add_Lightmap_Stage (inputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
}
|
|
Translate_Texture_Stage (w3dchunk, solvechunk, splitvertexinfo);
|
|
hastexturestage = true;
|
|
|
|
} else {
|
|
|
|
// NOTE: If multi-pass, last material pass contains lightmap stage.
|
|
// If multi-texture, zeroth stage is lightmap stage.
|
|
if (((outputmode == MULTI_PASS) && (materialpass == meshinfo.MaterialInfo [inputmode].PassCount - 1)) ||
|
|
((outputmode == MULTI_TEXTURE) && (stage == 0))) {
|
|
|
|
Translate_Lightmap_Stage (inputmode, w3dchunk, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
|
|
} else {
|
|
|
|
Translate_Texture_Stage (w3dchunk, solvechunk, splitvertexinfo);
|
|
}
|
|
stage++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
// Any other chunk type can be copied unmodified.
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
}
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
if (inputmode == UNLIT) {
|
|
|
|
if (!hastexturestage && (outputmode == MULTI_TEXTURE)) {
|
|
|
|
// Stage 0 is lightmap, stage 1 is unused.
|
|
Add_Lightmap_Stage (inputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
}
|
|
|
|
if (outputmode == VERTEX) {
|
|
Add_DIGs (inputmode, materialpass, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
}
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_DCGs -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_DCGs (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *dcgschunk;
|
|
W3dRGBAStruct *dcgs;
|
|
|
|
dcgschunk = new ChunkClass (w3dchunk);
|
|
ASSERT (dcgschunk != NULL);
|
|
|
|
dcgs = (W3dRGBAStruct*) dcgschunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (dcgs + splitvertexinfo.Remap (v), sizeof (W3dRGBAStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete dcgschunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_DIGs -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_DIGs (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, unsigned materialpass, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *digschunk;
|
|
W3dRGBStruct *digs;
|
|
|
|
digschunk = new ChunkClass (w3dchunk);
|
|
ASSERT (digschunk != NULL);
|
|
|
|
digs = (W3dRGBStruct*) digschunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (digs + splitvertexinfo.Remap (v), sizeof (W3dRGBStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete digschunk;
|
|
|
|
Add_DIGs (inputmode, materialpass, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Add_DIGs -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Add_DIGs (PrelitModeEnum inputmode, unsigned materialpass, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
// Output the pre-calculated vertex lighting chunk.
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_DIG);
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
|
|
W3dRGBStruct vertexcolor;
|
|
|
|
vertexcolor = meshsolve.Vertex_Color (splitvertexinfo.Remap (v));
|
|
solvechunk.Write (&vertexcolor, sizeof (vertexcolor));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Vertex_Material_IDs -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Vertex_Material_IDs (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *vertexmaterialidchunk;
|
|
uint32 *vertexmaterialids;
|
|
unsigned vertexmaterialidcount;
|
|
|
|
vertexmaterialidchunk = new ChunkClass (w3dchunk);
|
|
ASSERT (vertexmaterialidchunk != NULL);
|
|
vertexmaterialidcount = vertexmaterialidchunk->Get_Size() / sizeof (uint32);
|
|
|
|
vertexmaterialids = (uint32*) vertexmaterialidchunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
if (vertexmaterialidcount == 1) {
|
|
solvechunk.Write (vertexmaterialids, sizeof (uint32));
|
|
} else {
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (vertexmaterialids + splitvertexinfo.Remap (v), sizeof (uint32));
|
|
}
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
if (inputmode != UNLIT) {
|
|
|
|
uint32 expandedid;
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
if (vertexmaterialidcount == 1) {
|
|
expandedid = (*vertexmaterialids) + meshinfo.MaterialInfo [inputmode].VertexMaterialCount;
|
|
solvechunk.Write (&expandedid, sizeof (uint32));
|
|
} else {
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
expandedid = *(vertexmaterialids + splitvertexinfo.Remap (v)) + meshinfo.MaterialInfo [inputmode].VertexMaterialCount;
|
|
solvechunk.Write (&expandedid, sizeof (uint32));
|
|
}
|
|
}
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
delete vertexmaterialidchunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Texture_Stage -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Texture_Stage (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_STAGE_TEXCOORDS:
|
|
Translate_Stage_Texcoords (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
default:
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
}
|
|
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Stage_Texcoords -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Stage_Texcoords (ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
ChunkClass *texcoordchunk;
|
|
W3dTexCoordStruct *texcoords;
|
|
|
|
texcoordchunk = new ChunkClass (w3dchunk);
|
|
ASSERT (texcoordchunk != NULL);
|
|
|
|
texcoords = (W3dTexCoordStruct*) texcoordchunk->Get_Data();
|
|
|
|
solvechunk.Begin_Chunk (w3dchunk.Cur_Chunk_ID());
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (texcoords + splitvertexinfo.Remap (v), sizeof (W3dTexCoordStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
delete texcoordchunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Add_Lightmap_Material_Pass -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 01/26/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Add_Lightmap_Material_Pass (PrelitModeEnum inputmode, unsigned materialpass, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
uint32 vertexmaterialid;
|
|
uint32 shaderid;
|
|
|
|
// This routine only supports unlit meshes.
|
|
ASSERT (inputmode == UNLIT);
|
|
|
|
// Begin the lightmap material pass.
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_MATERIAL_PASS);
|
|
|
|
// Write vertex material ID chunk.
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_VERTEX_MATERIAL_IDS);
|
|
ASSERT (meshinfo.Lightmap_Vertex_Material_Count() == 1);
|
|
vertexmaterialid = meshinfo.MaterialInfo [inputmode].VertexMaterialCount;
|
|
solvechunk.Write (&vertexmaterialid, sizeof (vertexmaterialid));
|
|
solvechunk.End_Chunk();
|
|
|
|
// Write shader ID chunk.
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_SHADER_IDS);
|
|
if (meshinfo.Lightmap_Shader_Count() == 1) {
|
|
shaderid = meshinfo.MaterialInfo [inputmode].ShaderCount;
|
|
solvechunk.Write (&shaderid, sizeof (shaderid));
|
|
} else {
|
|
ASSERT (meshinfo.ShaderIdChunk [inputmode][materialpass] != NULL);
|
|
for (unsigned s = 0; s < meshinfo.ShaderIdChunk [inputmode][materialpass]->Get_Size() / sizeof (uint32); s++) {
|
|
shaderid = meshinfo.MaterialInfo [inputmode].ShaderCount + *((uint32*) meshinfo.ShaderIdChunk [inputmode][materialpass]->Get_Data() + s);
|
|
solvechunk.Write (&shaderid, sizeof (shaderid));
|
|
}
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
Add_Lightmap_Stage (inputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Add_Lightmap_Stage -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 08/25/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Add_Lightmap_Stage (PrelitModeEnum inputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURE_STAGE);
|
|
Add_Lightmap_Stage_Chunks (inputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Translate_Lightmap_Stage -- *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 08/25/00 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Translate_Lightmap_Stage (PrelitModeEnum inputmode, ChunkLoadClass &w3dchunk, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURE_STAGE);
|
|
|
|
while (w3dchunk.Open_Chunk()) {
|
|
|
|
switch (w3dchunk.Cur_Chunk_ID()) {
|
|
|
|
case W3D_CHUNK_STAGE_TEXCOORDS:
|
|
Translate_Stage_Texcoords (w3dchunk, solvechunk, splitvertexinfo);
|
|
break;
|
|
|
|
default:
|
|
Copy_Chunk (w3dchunk, solvechunk);
|
|
break;
|
|
}
|
|
|
|
w3dchunk.Close_Chunk();
|
|
}
|
|
|
|
Add_Lightmap_Stage_Chunks (inputmode, solvechunk, meshinfo, meshsolve, splitvertexinfo);
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Add_Lightmap_Stage_Chunks -- Add lightmap texture coordinate chunks. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Add_Lightmap_Stage_Chunks (PrelitModeEnum inputmode, ChunkSaveClass &solvechunk, const MeshInfoStruct &meshinfo, const LightscapeMeshSolve &meshsolve, const SplitVertexInfoStruct &splitvertexinfo)
|
|
{
|
|
const unsigned facecount = meshinfo.TriangleChunk->Get_Size() / sizeof (W3dTriStruct);
|
|
|
|
unsigned f;
|
|
unsigned textureindex;
|
|
bool writesingleindex;
|
|
|
|
// Write texture ID's (one per face in face order).
|
|
// If all of the texture indexes are the same then just write a single ID (this will be interpeted as an ID that applies to all faces in the mesh).
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_TEXTURE_IDS);
|
|
writesingleindex = true;
|
|
textureindex = meshinfo.MaterialInfo [inputmode].TextureCount + meshsolve.Lightmap_Index (0);
|
|
for (f = 1; f < facecount; f++) {
|
|
if ((meshinfo.MaterialInfo [inputmode].TextureCount + meshsolve.Lightmap_Index (f)) != textureindex) {
|
|
writesingleindex = false;
|
|
break;
|
|
}
|
|
}
|
|
if (writesingleindex) {
|
|
solvechunk.Write (&textureindex, sizeof (textureindex));
|
|
} else {
|
|
for (f = 0; f < facecount; f++) {
|
|
textureindex = meshinfo.MaterialInfo [inputmode].TextureCount + meshsolve.Lightmap_Index (f);
|
|
solvechunk.Write (&textureindex, sizeof (textureindex));
|
|
}
|
|
}
|
|
solvechunk.End_Chunk();
|
|
|
|
// Write texture coordinates.
|
|
solvechunk.Begin_Chunk (W3D_CHUNK_STAGE_TEXCOORDS);
|
|
for (unsigned v = 0; v < splitvertexinfo.Vertex_Count(); v++) {
|
|
solvechunk.Write (splitvertexinfo.UV (v), sizeof (W3dTexCoordStruct));
|
|
}
|
|
solvechunk.End_Chunk();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* LightMapDoc::Copy_Chunk -- Copy chunk from load file to save file. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
void LightMapDoc::Copy_Chunk (ChunkLoadClass &loadchunk, ChunkSaveClass &savechunk)
|
|
{
|
|
ChunkClass *chunk;
|
|
|
|
chunk = new ChunkClass (loadchunk);
|
|
ASSERT (chunk != NULL);
|
|
|
|
savechunk.Begin_Chunk (chunk->ChunkType);
|
|
savechunk.Write (chunk->Get_Data(), chunk->Get_Size());
|
|
savechunk.End_Chunk();
|
|
|
|
delete chunk;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* ChunkClass::ChunkClass -- Create a chunk from load file. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 6/1/99 IML : Created. *
|
|
*=============================================================================================*/
|
|
ChunkClass::ChunkClass (ChunkLoadClass &loadchunk) : ChunkHeader (loadchunk.Cur_Chunk_ID(), loadchunk.Cur_Chunk_Length())
|
|
{
|
|
const char *controlstring = "Cannot read data in chunk %d.";
|
|
|
|
ChunkType = loadchunk.Cur_Chunk_ID();
|
|
ChunkSize = loadchunk.Cur_Chunk_Length();
|
|
|
|
Data = new char [ChunkSize];
|
|
ASSERT (Data != NULL);
|
|
|
|
if (loadchunk.Read (Data, ChunkSize) != ChunkSize) {
|
|
|
|
static char _messagebuffer [256];
|
|
|
|
StringBuilder errormessage (_messagebuffer, sizeof (_messagebuffer));
|
|
|
|
// Clean-up.
|
|
delete [] Data;
|
|
Data = NULL;
|
|
|
|
throw (errormessage.Copy (controlstring, ChunkType));
|
|
}
|
|
}
|
|
|
|
|
|
// The following is maintained by MFC tools.
|
|
void LightMapDoc::Serialize(CArchive& ar)
|
|
{
|
|
if (ar.IsStoring())
|
|
{
|
|
// TODO: add storing code here
|
|
}
|
|
else
|
|
{
|
|
// TODO: add loading code here
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _DEBUG
|
|
void LightMapDoc::AssertValid() const
|
|
{
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void LightMapDoc::Dump(CDumpContext& dc) const
|
|
{
|
|
CDocument::Dump(dc);
|
|
}
|
|
|
|
#endif //_DEBUG
|