📄 mapdice.cpp
字号:
/*******************************************************************************\
Map Converter from BMP color and RAW elevation to Falcon 4.0 LOD format
Scott Randolph
Spectrum HoloByte
November 14, 1995
\*******************************************************************************/
#include <stdio.h>
#include <math.h>
#include "..\..\Terrain\Ttypes.h"
#include "..\..\Terrain\TPost.h"
#include "..\..\Terrain\TDskPost.h"
#include "..\..\3Dlib\Image.h"
#define MAX_LEVELS 6 // How many levels of detail to generate
#define LAST_TEX_LEVEL 2 // What is the number of the last level to be textured
const float altScale = 8.0f * FEET_PER_METER; // Must match units in *-E.RAW file
float FeetPerPost = (FEET_PER_KM / 4.0f); // I've got 250m posts at the moment
const int MEA_DOWNSAMPLE_SHIFT = 5; // From 250m to 8km
const float FeetToMEAcell = 1.0f / (FeetPerPost * (1<<MEA_DOWNSAMPLE_SHIFT));
static const WORD INVALID_TEXID = 0xFFFF;
int main(int argc, char* argv[]) {
BYTE *ColorIndexBuffer = NULL;
DWORD *ColorPaletteBuffer = NULL;
BYTE *ElevationBuffer = NULL;
WORD *TexIDBuffer = NULL;
WORD *FarFieldBuffer = NULL;
WORD *NormalBuffer = NULL;
TdiskPost *postBuffer = NULL;
TdiskPost *postBufferPrev = NULL;
DWORD ElevationBufferSize;
DWORD TexIDBufferSize;
DWORD FarFieldBufferSize;
DWORD NormalBufferSize;
DWORD postBufferSize;
CImageFileMemory colorFile;
HANDLE elevationFile;
HANDLE textureFile;
HANDLE farFieldFile;
HANDLE headerFile;
HANDLE postFile;
HANDLE offsetFile;
int bufferWidth;
int bufferHeight;
Int16 MEAvalue;
int MEAwidth;
int MEAheight;
int texMapWidth;
int texMapHeight;
int farMapWidth;
int farMapHeight;
OPENFILENAME dialogInfo;
char filename[256];
char dataRootDir[256];
char dataSet[256];
char texPath[256];
int row;
int col;
int r;
int c;
int top;
int left;
int bottom;
int right;
int LOD;
int blockRow;
int blockCol;
DWORD dataOffset;
int LastFarTexLevel;
DWORD fileOffset = 0xFFFFFFFF;
DWORD bytes;
int result;
// See if we got a filename on the command line
if ( argc == 2) {
result = GetFullPathName( argv[1], sizeof( filename ), filename, NULL );
} else {
result = 0;
}
// If we didn't get it on the command line, ask the user
// for the name of the BMP color file
if (!result) {
filename[0] = NULL;
dialogInfo.lStructSize = sizeof( dialogInfo );
dialogInfo.hwndOwner = NULL;
dialogInfo.hInstance = NULL;
dialogInfo.lpstrFilter = "24 Bit BMP\0*-C.GIF\0\0";
dialogInfo.lpstrCustomFilter = NULL;
dialogInfo.nMaxCustFilter = 0;
dialogInfo.nFilterIndex = 1;
dialogInfo.lpstrFile = filename;
dialogInfo.nMaxFile = sizeof( filename );
dialogInfo.lpstrFileTitle = NULL;
dialogInfo.nMaxFileTitle = 0;
dialogInfo.lpstrInitialDir = "J:\\TerrData";
dialogInfo.lpstrTitle = "Select a base GIF file (*-C.GIF)";
dialogInfo.Flags = OFN_FILEMUSTEXIST;
dialogInfo.lpstrDefExt = "GIF";
if ( !GetOpenFileName( &dialogInfo ) ) {
return -1;
}
}
// Extract the path to the directory ONE above the one containing the selected file
// (the "root" of the data tree)
char *p = &filename[ strlen(filename)-1 ];
while ( (*p != ':') && (*p != '\\') && (p != filename) ) {
if (*p == '.') *p = '\0';
p--;
}
*p = '\0';
char *base = p+1;
char *dir = filename;
while ( (*p != ':') && (*p != '\\') && (p != filename) ) {
p--;
}
*p = '\0';
strcpy( dataRootDir, dir );
strcpy( dataSet, base );
dataSet[strlen(dataSet)-2] = '\0'; // Get rid of the "-C"
strcpy( texPath, dir );
strcat( texPath, "\\texture\\" );
/************************************************************************************\
Got all input args -- Begin Setup
\************************************************************************************/
// Open the color input file
sprintf( filename, "%s\\terrain\\%s-C.GIF", dataRootDir, dataSet );
printf( "Reading COLOR file %s\n", filename );
colorFile.imageType = CheckImageType( filename );
ShiAssert( colorFile.imageType != IMAGE_TYPE_UNKNOWN );
result = colorFile.glOpenFileMem( filename );
if ( result != 1 ) {
char message[256];
sprintf( message, "Failed to open %s", filename );
ShiError( message );
}
// Read the image data (note that ReadTextureImage will close texFile for us)
colorFile.glReadFileMem();
result = ReadTextureImage( &colorFile );
if (result != GOOD_READ) {
ShiError( "Failed to read terrain texture. CD Error?" );
}
ShiAssert(colorFile.image.image);
ShiAssert(colorFile.image.palette);
// Store the image data
bufferWidth = colorFile.image.width;
bufferHeight = colorFile.image.height;
ColorIndexBuffer = colorFile.image.image;
ColorPaletteBuffer = (DWORD*)colorFile.image.palette;
// Allocate space for the elevation buffer
ElevationBufferSize = bufferWidth*bufferHeight*sizeof(*ElevationBuffer);
ElevationBuffer = (BYTE*)malloc( ElevationBufferSize );
ShiAssert( ElevationBuffer );
// Open the elevation information file
sprintf( filename, "%s\\terrain\\%s-E.RAW", dataRootDir, dataSet );
printf( "Reading ELEVATION file %s\n", filename );
elevationFile = CreateFile( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( elevationFile == INVALID_HANDLE_VALUE ) {
char string[256];
PutErrorString( string );
strcat( string, "Failed to open elevation file." );
ShiError( string );
}
// Read in the data
if ( !ReadFile( elevationFile, ElevationBuffer, ElevationBufferSize, &bytes, NULL ) ) bytes=0xFFFFFFFF;
if ( bytes != ElevationBufferSize ) {
char string[256];
PutErrorString( string );
strcat( string, "Couldn't read required elevation data." );
ShiError( string );
}
CloseHandle( elevationFile );
// Store the size of the MEA table we're going to build
MEAwidth = bufferWidth >> MEA_DOWNSAMPLE_SHIFT;
MEAheight = bufferHeight >> MEA_DOWNSAMPLE_SHIFT;
// Open the MEA table output file
sprintf( filename, "%s\\terrain\\Theater.MEA", dataRootDir );
printf( "Writing the MEA table %s\n", filename );
headerFile = CreateFile( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( headerFile == INVALID_HANDLE_VALUE ) {
char string[256];
PutErrorString( string );
strcat( string, "Failed to open MEA table output file." );
ShiError( string );
}
// Store the maximum height encountered in each MEA cell on the map
for (row=0; row < MEAheight; row++) {
for (col=0; col < MEAwidth; col++) {
MEAvalue = -32000;
top = row<<MEA_DOWNSAMPLE_SHIFT;
left = col<<MEA_DOWNSAMPLE_SHIFT;
bottom = ((row+1)<<MEA_DOWNSAMPLE_SHIFT) - 1;
right = ((col+1)<<MEA_DOWNSAMPLE_SHIFT) - 1;
// Search for the maximum height within this MEA cell
for (r = top; r <= bottom; r++) {
for (c = left; c <= right; c++) {
dataOffset = r*bufferWidth + c;
MEAvalue = max( MEAvalue, (Int16)(ElevationBuffer[dataOffset] * altScale) );
}
}
// Now we look one post outward (if we're not at an edge)
if ((row>0) && (row<MEAheight-1) && (col>0) && (col<MEAwidth-1)) {
for (c = left-1; c <= right+1; c++) {
dataOffset = (top-1)*bufferWidth + c;
MEAvalue = max( MEAvalue, (Int16)(ElevationBuffer[dataOffset] * altScale) );
dataOffset = (top+1)*bufferWidth + c;
MEAvalue = max( MEAvalue, (Int16)(ElevationBuffer[dataOffset] * altScale) );
}
for (r = top; r <= bottom; r++) {
dataOffset = r*bufferWidth + (left-1);
MEAvalue = max( MEAvalue, (Int16)(ElevationBuffer[dataOffset] * altScale) );
dataOffset = r*bufferWidth + (left+1);
MEAvalue = max( MEAvalue, (Int16)(ElevationBuffer[dataOffset] * altScale) );
}
}
// Write out this element of the MEA table
WriteFile( headerFile, &MEAvalue, sizeof(MEAvalue), &bytes, NULL );
ShiAssert( bytes == sizeof(MEAvalue) );
}
}
// Close the MEA table file
CloseHandle( headerFile );
// Allocate space for the surface normal buffer
NormalBufferSize = bufferWidth*bufferHeight*sizeof(*NormalBuffer);
NormalBuffer = (WORD*)malloc( NormalBufferSize );
ShiAssert( NormalBuffer );
// Compute the normal at each post based on its neighbors
printf("Computing the surface normal at each post\n");
for (r=0; r < bufferHeight; r++) {
for (c=0; c < bufferWidth; c++) {
dataOffset = r*bufferWidth + c;
ShiAssert( dataOffset < (DWORD)bufferWidth*bufferHeight );
ShiAssert( dataOffset >= 0 );
// Compute the cartesian components of the surface normal based on
// the known post spacing and the height changes between the neighbors
double Nx, Ny, Nz;
double normalizer;
// Start with the height changes (rise) in x direction and in the y direction
// At the edges of the map, just use a normal pointing straight up for now.
if ( (r == 0) || (c == 0) || (r == bufferHeight-1) || (c == bufferWidth-1) ) {
Nx = 0.0f;
Ny = 0.0f;
} else {
ShiAssert( dataOffset+bufferWidth < (DWORD)bufferWidth*bufferHeight );
ShiAssert( dataOffset-bufferWidth >= 0 );
Nx = altScale * (ElevationBuffer[dataOffset+bufferWidth] - ElevationBuffer[dataOffset-bufferWidth]);
Ny = altScale * (ElevationBuffer[dataOffset-1] - ElevationBuffer[dataOffset+1]);
}
Nz = GLOBAL_POST_TO_WORLD( 2 );
// Now normalize the vector
normalizer = 1.0 / sqrt(Nx*Nx + Ny*Ny + Nz*Nz);
Nx *= normalizer;
Ny *= normalizer;
Nz *= normalizer;
// Now store the normal in spherical coordinates (unit vector, so rho = 1)
double theta;
double phi;
// Convert from catesian to spherical coordinates
phi = asin( Nz );
ShiAssert( phi <= PI/2.0 );
ShiAssert( phi >= 0.0 );
// BUG IN ATAN2 -- fails when both args are 0.0, therefore...
if ( fabs(Nx) < 0.000001 ) {
if ( Ny < 0.0 ) {
theta = -PI / 2.0;
} else {
theta = PI / 2.0;
}
} else {
theta = atan2( Ny, Nx );
}
if (theta < 0.0) theta += PI*2.0;
ShiAssert( theta < PI*2.0 );
ShiAssert( theta >= 0.0 );
// Scale theta from 0 - 2 PI (360 degrees) to 0 - 255
static const double thetaInStart = 0.0;
static const double thetaInStop = PI*2.0;
static const double thetaInRange = thetaInStop - thetaInStart;
static const double thetaOutScale = 255.99;
theta = thetaOutScale * (theta - thetaInStart) / thetaInRange;
// Scale phi from 1.3 - PI/2 to 0 - 63
static const double phiInStart = 1.3;
static const double phiInStop = PI/2.0;
static const double phiInRange = phiInStop - phiInStart;
static const double phiOutScale = 63.99;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -