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.
538 lines
12 KiB
C++
538 lines
12 KiB
C++
// TCTc.cpp : Defines the class behaviors for the application.
|
|
//
|
|
|
|
|
|
#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\MLR.hpp>
|
|
#include <MLR\MLRHeaders.hpp>
|
|
|
|
#include "ImageLib\image.h"
|
|
|
|
#include "HFslim.hpp"
|
|
HFSlim *theTerrain;
|
|
|
|
char theName[1024];
|
|
char texturePath[1024];
|
|
char outputPath[1024];
|
|
|
|
DetailLevelInfo detailLevelInfo;
|
|
|
|
void FileExport(const char *fname);
|
|
void ImportMegabasetexture(NotationFile *mega_file);
|
|
|
|
FILE *analyzeFile;
|
|
|
|
void InitializeGameEngine()
|
|
{
|
|
//
|
|
//---------------------
|
|
// Initialize libraries
|
|
//---------------------
|
|
//
|
|
Stuff::InitializeClasses();
|
|
MidLevelRenderer::InitializeClasses(32768*16);
|
|
ElementRenderer::InitializeClasses();
|
|
|
|
analyzeFile = fopen("analyze.txt", "wt");
|
|
Verify(analyzeFile);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void DoGameLogic()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void UpdateDisplay()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void TerminateGameEngine()
|
|
{
|
|
fclose(analyzeFile);
|
|
|
|
//
|
|
//-------------------
|
|
// Turn off libraries
|
|
//-------------------
|
|
//
|
|
ElementRenderer::TerminateClasses();
|
|
MidLevelRenderer::TerminateClasses();
|
|
Stuff::TerminateClasses();
|
|
}
|
|
|
|
void
|
|
DumpScene(const char* name)
|
|
{}
|
|
|
|
//
|
|
// Setup the GameOS structure
|
|
//
|
|
void __stdcall GetGameOSEnvironment( char* CommandLine )
|
|
{
|
|
CommandLine=CommandLine;
|
|
Environment.applicationName = "TCT";
|
|
Environment.screenWidth = 640;
|
|
Environment.screenHeight = 480;
|
|
Environment.fullScreen = FALSE;
|
|
Environment.bitDepth = 16;
|
|
Environment.debugLog = ""; //"DebugLog.txt";
|
|
Environment.spew = ""; //"GameOS*";
|
|
|
|
Environment.UpdateRenderers = UpdateDisplay;
|
|
Environment.DoGameLogic = DoGameLogic;
|
|
Environment.InitializeGameEngine = InitializeGameEngine;
|
|
Environment.TerminateGameEngine = TerminateGameEngine;
|
|
|
|
Environment.SceneDump = DumpScene;
|
|
|
|
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
|
|
main()
|
|
{
|
|
InitGameOS(NULL, NULL, '\0');
|
|
InitializeGameEngine();
|
|
|
|
FileStream *temp_output = Stuff::FileStream::MakeFileStream();
|
|
Register_Object(temp_output);
|
|
temp_output->Open("TCTc.ini", FileStream::ReadOnly);
|
|
|
|
NotationFile *config_file = new NotationFile(temp_output);
|
|
Register_Object(config_file);
|
|
|
|
Check_Object(config_file);
|
|
|
|
const char *texPath;
|
|
if(!config_file->GetEntry("Miscellaneous", "Texturepath", &texPath))
|
|
{
|
|
return -1;
|
|
}
|
|
strncpy(texturePath, texPath, 1024);
|
|
fprintf(stdout, "Texturepath: %s\n", texturePath);
|
|
|
|
const char *default_path = "\\";
|
|
const char *output_path;
|
|
if(!config_file->GetEntry("Miscellaneous", "OutputPath", &output_path))
|
|
{
|
|
output_path = default_path;
|
|
}
|
|
strncpy(outputPath, output_path, 1024);
|
|
|
|
fprintf(stdout, "Outputpath: %s\n", outputPath);
|
|
|
|
MidLevelRenderer::TGAFilePool *pool = new MidLevelRenderer::TGAFilePool(texturePath);
|
|
Register_Object(pool);
|
|
MidLevelRenderer::MLRTexturePool::Instance =
|
|
new MidLevelRenderer::MLRTexturePool(pool);
|
|
Register_Object(MidLevelRenderer::MLRTexturePool::Instance);
|
|
|
|
if(!config_file->GetEntry("Miscellaneous", "OutputName", &texPath))
|
|
{
|
|
return -1;
|
|
}
|
|
strncpy(theName, texPath, 1024);
|
|
fprintf(stdout, "Output: %s\n", theName);
|
|
|
|
float dX, dY, dZ;
|
|
if(!config_file->GetEntry("HeightField", "DeltaX", &dX))
|
|
{
|
|
dX = 5.0f;
|
|
}
|
|
if(!config_file->GetEntry("HeightField", "DeltaY", &dY))
|
|
{
|
|
dY = 5.0f;
|
|
}
|
|
if(!config_file->GetEntry("HeightField", "DeltaZ", &dZ))
|
|
{
|
|
dZ = 5.0f;
|
|
}
|
|
fprintf(stdout, "Heighfield size: %f %f %f\n", dX, dY, dZ);
|
|
|
|
theTerrain = new HFSlim;
|
|
Register_Object(theTerrain);
|
|
|
|
theTerrain->SetScale(dX, dY, dZ);
|
|
theTerrain->SetOffset(0.0f, 0.0f);
|
|
|
|
fprintf(stdout, "Start importing the mega texture.\n");
|
|
ImportMegabasetexture(config_file);
|
|
|
|
Unregister_Object(config_file);
|
|
delete config_file;
|
|
|
|
temp_output->Close();
|
|
Unregister_Object(temp_output);
|
|
delete temp_output;
|
|
|
|
Unregister_Object(theTerrain);
|
|
delete theTerrain;
|
|
|
|
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);
|
|
}
|
|
|
|
theTerrain->FillFromImage(timg, smooth);
|
|
fprintf(stdout, "Heightfield image loaded.\n");
|
|
|
|
Verify((optPolys > 0) && (bucketSize > 0));
|
|
theTerrain->OptimizeHField(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(NotationFile *mega_file)
|
|
{
|
|
char buf[MAX_PATH];
|
|
|
|
GetCurrentDirectory(MAX_PATH, buf);
|
|
|
|
Check_Object(mega_file);
|
|
|
|
const char *hf_name;
|
|
if(!mega_file->GetEntry("HeightField", "HeightField", &hf_name))
|
|
{
|
|
SetCurrentDirectory(buf);
|
|
return;
|
|
}
|
|
int polyCount;
|
|
if(!mega_file->GetEntry("HeightField", "PolyCount", &polyCount))
|
|
{
|
|
polyCount = 0;
|
|
}
|
|
int bucketSize;
|
|
if(!mega_file->GetEntry("HeightField", "BucketSize", &bucketSize))
|
|
{
|
|
polyCount = 0;
|
|
}
|
|
int smoothPass;
|
|
if(!mega_file->GetEntry("HeightField", "SmoothingPasses", &smoothPass))
|
|
{
|
|
polyCount = 0;
|
|
}
|
|
|
|
if(false==ImportBitmap(hf_name, 4, polyCount, bucketSize, smoothPass))
|
|
{
|
|
return;
|
|
}
|
|
|
|
int borderPix;
|
|
if(!mega_file->GetEntry("BaseTexture", "BorderPixels", &borderPix))
|
|
{
|
|
borderPix = 0;
|
|
}
|
|
|
|
int nrOfLevels;
|
|
if(!mega_file->GetEntry("BaseTexture", "NumberOfLevels", &nrOfLevels))
|
|
{
|
|
nrOfLevels = 1;
|
|
}
|
|
fprintf(stdout, "HF: %s pc: %d bs: %d l: %d\n", hf_name, polyCount, bucketSize, nrOfLevels);
|
|
|
|
theTerrain->SetAllDepth(nrOfLevels);
|
|
|
|
const char *mega_base_name;
|
|
if(!mega_file->GetEntry("BaseTexture", "BaseName", &mega_base_name))
|
|
{
|
|
SetCurrentDirectory(buf);
|
|
return;
|
|
}
|
|
|
|
const char *detailLevelFileName;
|
|
if(mega_file->GetEntry("BaseTexture", "LevelInfo", &detailLevelFileName))
|
|
{
|
|
char name[1024];
|
|
strcpy(name, texturePath);
|
|
strcat(name, detailLevelFileName);
|
|
|
|
FILE *hd;
|
|
|
|
hd = fopen(name, "rb");
|
|
|
|
fread(&detailLevelInfo.width, sizeof(unsigned short), 1, hd);
|
|
fread(&detailLevelInfo.height, sizeof(unsigned short), 1, hd);
|
|
|
|
detailLevelInfo.array = new unsigned char [detailLevelInfo.width*detailLevelInfo.height];
|
|
|
|
size_t how_many = fread(detailLevelInfo.array, 1, detailLevelInfo.width*detailLevelInfo.height, hd);
|
|
if(how_many==detailLevelInfo.width*detailLevelInfo.height)
|
|
{
|
|
for(int i=0;i<detailLevelInfo.width*detailLevelInfo.height;i++)
|
|
{
|
|
if(detailLevelInfo.array[i] < 256/3)
|
|
{
|
|
detailLevelInfo.array[i] = 0;
|
|
}
|
|
else if(detailLevelInfo.array[i] < 512/3)
|
|
{
|
|
detailLevelInfo.array[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
detailLevelInfo.array[i] = 2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete [] detailLevelInfo.array;
|
|
detailLevelInfo.width = 0;
|
|
detailLevelInfo.height = 0;
|
|
|
|
}
|
|
fclose(hd);
|
|
}
|
|
else
|
|
{
|
|
detailLevelInfo.width = 0;
|
|
detailLevelInfo.height = 0;
|
|
}
|
|
|
|
const char *mega_detail_name;
|
|
if(!mega_file->GetEntry("DetailTexture", "DetailTexture", &mega_detail_name))
|
|
{
|
|
SetCurrentDirectory(buf);
|
|
return;
|
|
}
|
|
|
|
Scalar ratio;
|
|
if(!mega_file->GetEntry("DetailTexture", "DetailRatio", &ratio))
|
|
{
|
|
ratio = 16.0f;
|
|
}
|
|
|
|
Scalar dStart;
|
|
if(!mega_file->GetEntry("DetailTexture", "DetailFadeBegin", &dStart))
|
|
{
|
|
dStart = 32.0f;
|
|
}
|
|
|
|
Scalar dEnd;
|
|
if(!mega_file->GetEntry("DetailTexture", "DetailFadeEnd", &dEnd))
|
|
{
|
|
dEnd = 64.0f;
|
|
}
|
|
|
|
const char *mega_alpha_name;
|
|
MLRState::AlphaMode alpha;
|
|
|
|
if(mega_file->GetEntry("DetailTexture", "DetailAlphaMode", &mega_alpha_name))
|
|
{
|
|
if(!strncmp(mega_alpha_name, "OneOne", sizeof("OneOne")))
|
|
{
|
|
alpha = MLRState::OneOneMode;
|
|
} else
|
|
if(!strncmp(mega_alpha_name, "AlphaOne", sizeof("AlphaOne")))
|
|
{
|
|
alpha = MLRState::AlphaOneMode;
|
|
} else
|
|
if(!strncmp(mega_alpha_name, "OneAlpha", sizeof("OneAlpha")))
|
|
{
|
|
alpha = MLRState::OneAlphaMode;
|
|
} 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;
|
|
}
|
|
|
|
fprintf(stdout, "BaseTexture: %s (with %d border pixels, Detail: %s\n",
|
|
mega_base_name,
|
|
borderPix,
|
|
mega_detail_name
|
|
);
|
|
|
|
theTerrain->SetDetailTextureInfo(
|
|
mega_detail_name,
|
|
0.0f,
|
|
0.0f,
|
|
ratio,
|
|
ratio,
|
|
dStart,
|
|
dEnd,
|
|
alpha
|
|
);
|
|
|
|
theTerrain->SetBorderPixels(borderPix);
|
|
|
|
char lowestLevelTextureName[1024];
|
|
sprintf(lowestLevelTextureName, "%s_0_0000", mega_base_name);
|
|
MidLevelRenderer::MLRTexturePool::Instance->Add(lowestLevelTextureName);
|
|
|
|
if(true == theTerrain->SetMegaTexture(nrOfLevels, bucketSize, mega_base_name, &detailLevelInfo))
|
|
{
|
|
FileExport(outputPath);
|
|
}
|
|
|
|
SetCurrentDirectory(buf);
|
|
}
|
|
|
|
void
|
|
FileExport(const char *output_path)
|
|
{
|
|
Check_Object(theTerrain->GetGroup());
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Analyze the set file and extract the useful pieces
|
|
//---------------------------------------------------
|
|
//
|
|
|
|
Stuff::MString erf_name(theName);
|
|
Stuff::MString path(output_path);
|
|
|
|
erf_name += "_jm.erf";
|
|
|
|
ElementRenderer::Element *terrain;
|
|
bool terrainVisible;
|
|
terrain = theTerrain->GetOptTerrain();
|
|
terrainVisible = theTerrain->IsOptDisplayed();
|
|
theTerrain->DisplayOpt(false);
|
|
|
|
unsigned cullMode = terrain->GetCullMode();
|
|
|
|
terrain->SetRootMode();
|
|
|
|
Stuff::FileStream *element_stream =
|
|
Stuff::FileStream::MakeFileStream();
|
|
|
|
Register_Object(element_stream);
|
|
|
|
Stuff::MString contents_name = path;
|
|
contents_name += erf_name;
|
|
|
|
element_stream->Open(contents_name, Stuff::FileStream::WriteOnly);
|
|
|
|
ElementRenderer::WriteERFVersion(element_stream);
|
|
|
|
terrain->Save(element_stream);
|
|
|
|
Unregister_Object(element_stream);
|
|
delete element_stream;
|
|
|
|
switch(cullMode)
|
|
{
|
|
case ElementRenderer::Element::RootMode:
|
|
terrain->SetRootMode();
|
|
break;
|
|
case ElementRenderer::Element::VolumeCullMode:
|
|
terrain->SetVolumeCullMode();
|
|
break;
|
|
case ElementRenderer::Element::NeverCullMode:
|
|
terrain->SetNeverCullMode();
|
|
break;
|
|
case ElementRenderer::Element::AlwaysCullMode:
|
|
terrain->SetAlwaysCullMode();
|
|
break;
|
|
}
|
|
|
|
} // end of export
|