Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
574 lines
14 KiB
C++
574 lines
14 KiB
C++
// TCTd.cpp : super multizone tool !
|
|
//
|
|
|
|
|
|
#include <Stuff\StuffHeaders.hpp>
|
|
#include <MLR\MLRTexturePool.hpp>
|
|
#include <DLLPlatform\DLLPlatform.hpp>
|
|
|
|
#include <ElementRenderer\ElementRenderer.hpp>
|
|
#include <ElementRenderer\GroupElement.hpp>
|
|
#include <ElementRenderer\ListElement.hpp>
|
|
#include <ElementRenderer\SwitchElement.hpp>
|
|
#include <ElementRenderer\ShapeElement.hpp>
|
|
#include <MLR\MLRHeaders.hpp>
|
|
#include <gosFX\gosFX.hpp>
|
|
|
|
#include "ImageLib\image.h"
|
|
|
|
#include "HFslimMZ0p3.hpp"
|
|
|
|
//#define NON_DEBUG_BUG 1
|
|
|
|
HFSlimMZ0p3 *theTerrain;
|
|
|
|
void
|
|
MakeBSP(
|
|
Stuff::DynamicArrayOf<Stuff::Plane> *planes,
|
|
WORD *plane_count,
|
|
ElementRenderer::GroupElement *tile,
|
|
MemoryStream *stream
|
|
);
|
|
|
|
char theName[1024];
|
|
|
|
char contentPath[1024];
|
|
char inputPath[1024];
|
|
|
|
char texturePath[1024];
|
|
char outputPath[1024];
|
|
|
|
void FileExport(HFSlimMZ0p3*, const char *fname);
|
|
void FileExportMaster(int, int, Scalar, Scalar, const char *fname);
|
|
void ImportMegabasetexture(Page *map_to_convert);
|
|
|
|
FILE *analyzeFile;
|
|
|
|
void __stdcall InitializeGameEngine()
|
|
{
|
|
//
|
|
//---------------------
|
|
// Initialize libraries
|
|
//---------------------
|
|
//
|
|
Stuff::InitializeClasses();
|
|
MidLevelRenderer::InitializeClasses(32768*16);
|
|
gosFX::InitializeClasses();
|
|
ElementRenderer::InitializeClasses();
|
|
|
|
theTerrain = new HFSlimMZ0p3;
|
|
Register_Pointer(theTerrain);
|
|
|
|
analyzeFile = fopen("analyze.txt", "wt");
|
|
Verify(analyzeFile);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void __stdcall DoGameLogic()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void __stdcall UpdateDisplay()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void __stdcall TerminateGameEngine()
|
|
{
|
|
Unregister_Pointer(theTerrain);
|
|
delete theTerrain;
|
|
|
|
fclose(analyzeFile);
|
|
|
|
//
|
|
//-------------------
|
|
// Turn off libraries
|
|
//-------------------
|
|
//
|
|
ElementRenderer::TerminateClasses();
|
|
gosFX::TerminateClasses();
|
|
MidLevelRenderer::TerminateClasses();
|
|
Stuff::TerminateClasses();
|
|
}
|
|
|
|
//
|
|
// Setup the GameOS structure
|
|
//
|
|
void __stdcall GetGameOSEnvironment( char* CommandLine )
|
|
{
|
|
CommandLine=CommandLine;
|
|
Environment.applicationName = "TCT";
|
|
Environment.directoryPath = "\\Tools\\TCTb";
|
|
Environment.screenWidth = 640;
|
|
Environment.screenHeight = 480;
|
|
Environment.fullScreen = FALSE;
|
|
Environment.bitDepth = 16;
|
|
Environment.debugLog = "TCTLog.txt";
|
|
Environment.spew = ""; //"GameOS*";
|
|
|
|
Environment.UpdateRenderers = UpdateDisplay;
|
|
Environment.DoGameLogic = DoGameLogic;
|
|
Environment.InitializeGameEngine = InitializeGameEngine;
|
|
Environment.TerminateGameEngine = TerminateGameEngine;
|
|
|
|
Environment.Renderer = 0;
|
|
Environment.FullScreenDevice = 0;
|
|
|
|
Environment.AntiAlias = 0; // true/false - Enable full screen antialiasing
|
|
|
|
//
|
|
// Texture infomation
|
|
//
|
|
Environment.Texture_S_256 = 13;
|
|
Environment.Texture_S_128 = 12;
|
|
Environment.Texture_S_64 = 1;
|
|
Environment.Texture_S_32 = 1;
|
|
Environment.Texture_S_16 = 1;
|
|
|
|
Environment.Texture_K_256 = 1;
|
|
Environment.Texture_K_128 = 1;
|
|
Environment.Texture_K_64 = 1;
|
|
Environment.Texture_K_32 = 1;
|
|
Environment.Texture_K_16 = 1;
|
|
|
|
Environment.Texture_A_256 = 1;
|
|
Environment.Texture_A_128 = 1;
|
|
Environment.Texture_A_64 = 1;
|
|
Environment.Texture_A_32 = 1;
|
|
Environment.Texture_A_16 = 1;
|
|
}
|
|
|
|
int
|
|
__cdecl main()
|
|
{
|
|
InitGameOS(NULL, NULL, "blabla");
|
|
InitializeGameEngine();
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// Open up the .ini file, and figure out how many map to convert
|
|
//--------------------------------------------------------------
|
|
//
|
|
{
|
|
NotationFile config_file("TCTd.ini");
|
|
NotationFile::PageIterator *maps = config_file.MakePageIterator();
|
|
Check_Object(maps);
|
|
|
|
//
|
|
//----------------------------
|
|
// Convert the maps one by one
|
|
//----------------------------
|
|
//
|
|
Page *map_to_convert;
|
|
while ((map_to_convert = maps->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(map_to_convert);
|
|
const char* map = map_to_convert->GetName();
|
|
Check_Pointer(map);
|
|
|
|
const char *path;
|
|
strcpy(contentPath, "Content\\");
|
|
strcpy(texturePath, "Textures\\");
|
|
|
|
const char *default_path = "\\";
|
|
if(!map_to_convert->GetEntry("InputPath", &path))
|
|
{
|
|
path = default_path;
|
|
}
|
|
strncpy(inputPath, path, 1024);
|
|
|
|
fprintf(stdout, "Inputpath: %s\n", inputPath);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::Heap);
|
|
MidLevelRenderer::TGAFilePool *pool = new MidLevelRenderer::TGAFilePool(texturePath);
|
|
Check_Object(pool);
|
|
MidLevelRenderer::MLRTexturePool::Instance =
|
|
new MidLevelRenderer::MLRTexturePool(pool);
|
|
Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
|
|
gos_PopCurrentHeap();
|
|
|
|
path = map;
|
|
strncpy(theName, path, 1024);
|
|
fprintf(stdout, "Mapname: %s\n", theName);
|
|
|
|
float dX, dY, dZ;
|
|
if(!map_to_convert->GetEntry("DeltaX", &dX))
|
|
{
|
|
dX = 5.0f;
|
|
}
|
|
if(!map_to_convert->GetEntry("DeltaY", &dY))
|
|
{
|
|
dY = 5.0f;
|
|
}
|
|
if(!map_to_convert->GetEntry("DeltaZ", &dZ))
|
|
{
|
|
dZ = 5.0f;
|
|
}
|
|
fprintf(stdout, "Heighfield size: %f %f %f\n", dX, dY, dZ);
|
|
|
|
theTerrain->SetScale(dX, dY, dZ);
|
|
|
|
fprintf(stdout, "Start importing the mega texture.\n");
|
|
ImportMegabasetexture(map_to_convert);
|
|
}
|
|
}
|
|
|
|
TerminateGameEngine();
|
|
ExitGameOS();
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
ImportBitmap(Image &timg, int iRBX, int optPolys, int bucketSize, int smooth)
|
|
{
|
|
if(timg.GetWidth()!=timg.GetHeight())
|
|
{
|
|
fprintf(stdout, "Bitmap Must Be Square - Dimension Error\n");
|
|
return false;
|
|
}
|
|
|
|
if(timg.GetBpp()<8)
|
|
{
|
|
fprintf(stdout, "Bitmap Must Be At Least 8 bit - Depth Error\n");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(timg.GetBpp()>8) //Not a Bitmapped Image Resolve
|
|
{
|
|
RMETHOD rmd;
|
|
|
|
switch(iRBX)
|
|
{
|
|
case 0:
|
|
rmd=RMD_REDC;
|
|
break;
|
|
case 1:
|
|
rmd=RMD_GREENC;
|
|
break;
|
|
case 2:
|
|
rmd=RMD_BLUEC;
|
|
break;
|
|
case 3:
|
|
rmd=RMD_ALPHAC;
|
|
break;
|
|
case 4:
|
|
rmd=RMD_MAX;
|
|
break;
|
|
case 5:
|
|
rmd=RMD_BHT;
|
|
break;
|
|
default:
|
|
rmd=RMD_MAX;
|
|
}
|
|
|
|
timg.ReduceTo8Bit(rmd);
|
|
}
|
|
|
|
Verify(timg.GetWidth() % 256 == 0);
|
|
Verify(timg.GetHeight() % 256 == 0);
|
|
|
|
theTerrain->FillFromImage(timg, smooth);
|
|
fprintf(stdout, "Heightfield image loaded.\n");
|
|
|
|
int xDim, zDim;
|
|
theTerrain->GetZoneDimensions(&xDim, &zDim);
|
|
Verify((optPolys > 0) && (bucketSize > 0));
|
|
theTerrain->OptimizeHField(xDim*zDim*optPolys/2, bucketSize);
|
|
|
|
|
|
fprintf(stdout, "Terrain optimized.\n");
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ImportBitmap(const char *fname, int iRBX, int optPolys, int bucketSize, int smooth)
|
|
{
|
|
Image timg;
|
|
char tfn[MAX_PATH];
|
|
|
|
strcpy(tfn, fname);
|
|
timg.Load(tfn);
|
|
return ImportBitmap(timg, iRBX, optPolys, bucketSize, smooth);
|
|
}
|
|
|
|
void
|
|
ImportMegabasetexture(
|
|
Page *map_to_convert
|
|
)
|
|
{
|
|
char buf[MAX_PATH];
|
|
|
|
GetCurrentDirectory(MAX_PATH, buf);
|
|
|
|
Check_Object(map_to_convert);
|
|
|
|
const char *hf_name;
|
|
if(!map_to_convert->GetEntry("HeightField", &hf_name))
|
|
{
|
|
SetCurrentDirectory(buf);
|
|
return;
|
|
}
|
|
|
|
int polyCount = 5000;
|
|
map_to_convert->GetEntry("PolyCount", &polyCount);
|
|
int bucketSize = 64;
|
|
map_to_convert->GetEntry("BucketSize", &bucketSize);
|
|
int smoothPass = 2;
|
|
map_to_convert->GetEntry("SmoothingPasses", &smoothPass);
|
|
|
|
int xDim, zDim;
|
|
char hf_path[1024];
|
|
strcpy(hf_path, inputPath);
|
|
strcat(hf_path, hf_name);
|
|
if(false==ImportBitmap(hf_path, 4, polyCount, bucketSize, smoothPass))
|
|
{
|
|
SetCurrentDirectory(buf);
|
|
return;
|
|
}
|
|
|
|
int borderPix = 0;
|
|
map_to_convert->GetEntry("BorderPixels", &borderPix);
|
|
int nrOfLevels = 1;
|
|
map_to_convert->GetEntry("NumberOfLevels", &nrOfLevels);
|
|
fprintf(stdout, "HF: %s pc: %d bs: %d l: %d\n", hf_name, polyCount, bucketSize, nrOfLevels);
|
|
|
|
theTerrain->SetAllDepth(nrOfLevels);
|
|
|
|
theTerrain->GetZoneDimensions(&xDim, &zDim);
|
|
|
|
const char *mega_detail_name;
|
|
if(!map_to_convert->GetEntry("DetailTexture", &mega_detail_name))
|
|
{
|
|
SetCurrentDirectory(buf);
|
|
return;
|
|
}
|
|
char detailName[1024];
|
|
sprintf(detailName, "Maps\\%s\\%s", theName, mega_detail_name);
|
|
|
|
Scalar ratio = 16.0f;
|
|
map_to_convert->GetEntry("DetailRatio", &ratio);
|
|
Scalar dStart = 32.0f;
|
|
map_to_convert->GetEntry("DetailFadeBegin", &dStart);
|
|
Scalar dEnd = 64.0f;
|
|
map_to_convert->GetEntry("DetailFadeEnd", &dEnd);
|
|
|
|
const char *mega_alpha_name;
|
|
MLRState::AlphaMode alpha;
|
|
|
|
if(map_to_convert->GetEntry("DetailAlphaMode", &mega_alpha_name))
|
|
{
|
|
if(!strncmp(mega_alpha_name, "OneOne", sizeof("OneOne")))
|
|
{
|
|
alpha = MLRState::OneOneMode;
|
|
} else
|
|
if(!strncmp(mega_alpha_name, "AlphaInvAlpha", sizeof("AlphaInvAlpha")))
|
|
{
|
|
alpha = MLRState::AlphaInvAlphaMode;
|
|
} else
|
|
if(!strncmp(mega_alpha_name, "OneInvAlpha", sizeof("OneInvAlpha")))
|
|
{
|
|
alpha = MLRState::OneInvAlphaMode;
|
|
} else {
|
|
alpha = MLRState::AlphaOneMode;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alpha = MLRState::AlphaOneMode;
|
|
}
|
|
|
|
theTerrain->SetDetailTextureInfo(
|
|
detailName,
|
|
0.0f,
|
|
0.0f,
|
|
ratio,
|
|
ratio,
|
|
dStart,
|
|
dEnd,
|
|
alpha
|
|
);
|
|
theTerrain->SetBorderPixels(borderPix);
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nCalling SetMegaTexture (2)");
|
|
#endif
|
|
|
|
if(true == theTerrain->SetMegaTexture(
|
|
nrOfLevels,
|
|
bucketSize,
|
|
theName)
|
|
)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nCalling SetMegaTexture (tctd0p3) (returned TRUE)");
|
|
#endif
|
|
FileExport(theTerrain, outputPath);
|
|
}
|
|
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nCalling SetMegaTexture (done)");
|
|
#endif
|
|
sprintf(outputPath, "%sMaps\\%s\\%s.erf", contentPath, theName, theName);
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\n%s", outputPath);
|
|
#endif
|
|
FileExportMaster(xDim, zDim, theTerrain->GetXScale(), theTerrain->GetZScale(), outputPath);
|
|
|
|
SetCurrentDirectory(buf);
|
|
}
|
|
|
|
bool Debug_Tile=false;
|
|
bool Debug_Zone=false;
|
|
|
|
void
|
|
ZoneExport(
|
|
ElementRenderer::GridElement *terrain,
|
|
const char* zone_filename
|
|
)
|
|
{
|
|
Check_Object(terrain);
|
|
Check_Pointer(zone_filename);
|
|
|
|
//
|
|
//--------------------------------------------------------
|
|
// Make a memory stream array to avoid reallocating memory
|
|
//--------------------------------------------------------
|
|
//
|
|
DynamicArrayOf<DynamicMemoryStream *> tile_streams(64);
|
|
int triangle_count = terrain->CountTriangles();
|
|
Verify(triangle_count < 32768);
|
|
DynamicArrayOf<Plane> planes(triangle_count*2);
|
|
WORD plane_count = 0;
|
|
|
|
//
|
|
//---------------------------
|
|
// Step through all the tiles
|
|
//---------------------------
|
|
//
|
|
int t;
|
|
for (t=0; t<64; ++t)
|
|
{
|
|
tile_streams[t] = new DynamicMemoryStream;
|
|
Check_Object(tile_streams[t]);
|
|
ElementRenderer::GroupElement *tile =
|
|
Cast_Object(
|
|
ElementRenderer::GroupElement*,
|
|
terrain->GetIndexedElement(t)
|
|
);
|
|
Check_Object(tile);
|
|
|
|
//
|
|
//-----------------------------------------------
|
|
// For each tile, run the collision process on it
|
|
//-----------------------------------------------
|
|
//
|
|
fprintf(stdout, "\r Working on tile %d", t);
|
|
MakeBSP(&planes, &plane_count, tile, tile_streams[t]);
|
|
}
|
|
fprintf(stdout, "\r Used %d planes \n", plane_count);
|
|
|
|
//
|
|
//------------------------------------------
|
|
// Copy the stream info into the output file
|
|
//------------------------------------------
|
|
//
|
|
Stuff::FileStream zone_stream(zone_filename, Stuff::FileStream::WriteOnly);
|
|
zone_stream << plane_count;
|
|
zone_stream.WriteBytes(planes.GetData(), plane_count * sizeof(Plane));
|
|
for (t=0; t<64; ++t)
|
|
{
|
|
Check_Object(tile_streams[t]);
|
|
tile_streams[t]->Rewind();
|
|
zone_stream << tile_streams[t]->GetSize() << *tile_streams[t];
|
|
Unregister_Object(tile_streams[t]);
|
|
delete tile_streams[t];
|
|
}
|
|
}
|
|
|
|
void
|
|
FileExport(HFSlimMZ0p3 *tT, const char *output_path)
|
|
{
|
|
//
|
|
//---------------------------------------------------
|
|
// Analyze the set file and extract the useful pieces
|
|
//---------------------------------------------------
|
|
//
|
|
|
|
int i, j, xDim, zDim;
|
|
tT->GetZoneDimensions(&xDim, &zDim);
|
|
|
|
Stuff::DynamicArrayOf<ElementRenderer::GridElement*> *terrainArray;
|
|
|
|
terrainArray = tT->GetTerrainArray();
|
|
|
|
ElementRenderer::GridElement *terrain;
|
|
|
|
for(j=0;j<zDim;j++)
|
|
{
|
|
for(i=0;i<xDim;i++)
|
|
{
|
|
terrain = (*terrainArray)[j*zDim+i];
|
|
Check_Object(terrain);
|
|
|
|
fprintf(stdout, "Processing zone %c%c\n", 'A'+j, 'A'+i);
|
|
sprintf(outputPath, "%sMaps\\%s\\%c%c.bsp", contentPath, theName, 'A'+j, 'A'+i);
|
|
ZoneExport(terrain, outputPath);
|
|
|
|
sprintf(outputPath, "%sMaps\\%s\\%c%c.erf", contentPath, theName, 'A'+j, 'A'+i);
|
|
|
|
Stuff::FileStream element_stream(output_path, Stuff::FileStream::WriteOnly);
|
|
ElementRenderer::WriteERFVersion(&element_stream);
|
|
|
|
for (int row=0; row<8; ++row)
|
|
{
|
|
for (int col=0; col<8; ++col)
|
|
{
|
|
ElementRenderer::GroupElement *group =
|
|
Cast_Object(
|
|
ElementRenderer::GroupElement*,
|
|
terrain->GetIndexedElement(row, col)
|
|
);
|
|
Stuff::ChainIteratorOf<Element*>* iterator = group->MakeIterator();
|
|
Check_Object(iterator);
|
|
Element *element = iterator->GetCurrent();
|
|
Check_Object(element);
|
|
Verify(element->GetLocalToWorld() == Stuff::LinearMatrix4D::Identity);
|
|
ElementRenderer::StateChange *state = new ElementRenderer::StateChange;
|
|
state->SetLightingMode(ElementRenderer::StateChange::TerrainMode);
|
|
element->AdoptStateChange(state);
|
|
element->Save(&element_stream);
|
|
Unregister_Object(iterator);
|
|
delete iterator;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FileExportMaster(int xDim, int zDim, Scalar xGrid, Scalar zGrid, const char *output_path)
|
|
{
|
|
gos_PushCurrentHeap(ElementRenderer::Heap);
|
|
ElementRenderer::GridElement *terrain = new ElementRenderer::GridElement(xDim, zDim, 0.0f, 0.0f, xDim*256*xGrid, zDim*256*zGrid);
|
|
terrain->SetSize(0);
|
|
gos_PopCurrentHeap();
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Analyze the set file and extract the useful pieces
|
|
//---------------------------------------------------
|
|
//
|
|
|
|
terrain->SetRootMode();
|
|
|
|
Stuff::FileStream element_stream(output_path, Stuff::FileStream::WriteOnly);
|
|
ElementRenderer::WriteERFVersion(&element_stream);
|
|
terrain->Save(&element_stream);
|
|
} // end of export
|