00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00027 #include "../Include/FlyLegacy.h"
00028 #include "../Include/Globals.h"
00029 #include "../Include/QTR.h"
00030 #include "../Include/Utility.h"
00031 #include "../Include/Endian.h"
00032
00033
00034 CQTRFile::CQTRFile (void)
00035 {
00036 header.numNodes = 0;
00037 header.magic = 50;
00038 header.width = 0;
00039 header.height = 0;
00040 header.rasterBytes = 0;
00041 for (int i=0; i<4; i++) header.elev[i] = 0;
00042 }
00043
00044 CQTRFile::CQTRFile (int index)
00045 {
00046 char qtrFilename[1024];
00047 sprintf (qtrFilename, "DATA\\%03X.QTR", index);
00048 Load (qtrFilename);
00049 }
00050
00051 CQTRFile::CQTRFile (const char* qtrFilename)
00052 {
00053 Load (qtrFilename);
00054 }
00055
00056 CQTRFile::~CQTRFile (void)
00057 {
00058 delete[] qtreenode;
00059 delete[] raster;
00060 }
00061
00062 bool CQTRFile::Load (const char *qtrFilename)
00063 {
00064 int i;
00065
00066 PODFILE *p = popen (&globals->pfs, qtrFilename);
00067 if (p == NULL) {
00068 fprintf (stderr, "Error opening QTR filename : %s\n", qtrFilename);
00069 return false;
00070 }
00071
00072
00073 size_t nRead = pread (&header, SIZEOF_QTR_HEADER, 1, p);
00074 if (nRead != 1) {
00075 pclose (p);
00076 return false;
00077 }
00078
00079
00080 header.numNodes = LittleEndian (header.numNodes);
00081 header.magic = LittleEndian (header.magic);
00082 header.width = LittleEndian (header.width);
00083 header.height = LittleEndian (header.height);
00084 header.rasterBytes = LittleEndian (header.rasterBytes);
00085 for (i=0; i<4; i++) header.elev[i] = LittleEndian (header.elev[i]);
00086
00087
00088 qtreenode = new SQTRNode[header.numNodes];
00089 nRead = pread (qtreenode, SIZEOF_QTR_NODE, header.numNodes, p);
00090 if (nRead != header.numNodes) {
00091 pclose (p);
00092 return false;
00093 }
00094
00095
00096 for (i=0; i<header.numNodes; i++) {
00097 SQTRNode *node = &qtreenode[i];
00098
00099 node->center = LittleEndian (node->center);
00100 switch (node->type) {
00101 case QTR_NODE_BRANCH:
00102 node->branchData.nwNode = LittleEndian (node->branchData.nwNode);
00103 node->branchData.neNode = LittleEndian (node->branchData.neNode);
00104 node->branchData.swNode = LittleEndian (node->branchData.swNode);
00105 node->branchData.seNode = LittleEndian (node->branchData.seNode);
00106 break;
00107
00108 case QTR_NODE_LEAF:
00109 node->leafData.nwElevation = LittleEndian (node->leafData.nwElevation);
00110 node->leafData.neElevation = LittleEndian (node->leafData.neElevation);
00111 node->leafData.swElevation = LittleEndian (node->leafData.swElevation);
00112 node->leafData.seElevation = LittleEndian (node->leafData.seElevation);
00113 break;
00114
00115 case QTR_NODE_RASTER_ABS:
00116 case QTR_NODE_RASTER_REL:
00117 node->rasterData.offset = LittleEndian (node->rasterData.offset);
00118 node->rasterData.dummy = LittleEndian (node->rasterData.dummy);
00119 break;
00120 }
00121 }
00122
00123
00124 raster = new char[header.rasterBytes];
00125 nRead = pread (raster, sizeof(char), header.rasterBytes, p);
00126 if (nRead != header.rasterBytes) {
00127 pclose (p);
00128 return false;
00129 }
00130
00131 pclose (p);
00132 return true;
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 bool CQTRFile::Save (const char *qtrFilename)
00176 {
00177 FILE *fQTR = fopen (qtrFilename, "wb");
00178 if (fQTR == NULL) {
00179 fprintf (stderr, "Error opening QTR filename : %s\n", qtrFilename);
00180 return false;
00181 }
00182
00184
00185 size_t nWrite = fwrite (&header, sizeof(SQTRHeader), 1, fQTR);
00186 if (nWrite != 1) {
00187 fclose (fQTR);
00188 return false;
00189 }
00190
00191
00192 nWrite = fwrite (qtreenode, sizeof(SQTRNode), header.numNodes, fQTR);
00193 if (nWrite != header.numNodes) {
00194 fclose (fQTR);
00195 return false;
00196 }
00197
00198
00199 nWrite = fwrite (raster, sizeof(char), header.rasterBytes, fQTR);
00200 if (nWrite != header.rasterBytes) {
00201 fclose (fQTR);
00202 return false;
00203 }
00204
00205 fclose (fQTR);
00206 return true;
00207 }
00208
00209 unsigned short CQTRFile::NumQuadtreeNodes (void)
00210 {
00211 return header.numNodes;
00212 }
00213
00214 SQTRNode *CQTRFile::GetQuadtreeNode (unsigned short i)
00215 {
00216 SQTRNode *rc = NULL;
00217 if (i < header.numNodes) {
00218 rc = &qtreenode[i];
00219 }
00220 return rc;
00221 }
00222
00223 char* CQTRFile::GetRasterData (unsigned long offset)
00224 {
00225 char* rc = NULL;
00226 if (offset <= header.rasterBytes) {
00227 rc = &raster[offset];
00228 }
00229 return rc;
00230 }
00231
00232
00233
00234
00235 float CQTRFile::ExtractRelativeData (char* data, int x, int z)
00236 {
00237 short *pBase = (short *)data;
00238 short base = *pBase;
00239 data += sizeof(short);
00240 unsigned char offset = data[(z * 8) + x];
00241 short metres = base + (offset * 16);
00242 return MetresToFeet ((float)metres);
00243 }
00244
00245
00246
00247
00248 float CQTRFile::ExtractAbsoluteData (short* data, int x, int z)
00249 {
00250 float metres = (float)(data[(z * 8) + x]);
00251 return MetresToFeet (metres);
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 float CQTRFile::Search (int level, unsigned short node, int x, int z)
00266 {
00267 float rc = 0.0f;
00268
00269 SQTRNode *qtrnode = GetQuadtreeNode (node);
00270
00271 if (level == 0) {
00272
00273 rc = qtrnode->center;
00274 } else {
00275
00276
00277
00278 int half = 1 << (level - 1);
00279 int qx = (x / half) % 2;
00280 int qz = (z / half) % 2;
00281 int quadrant = qx * 2 + qz;
00282 int xNew = x % half;
00283 int zNew = z % half;
00284
00285
00286 switch (qtrnode->type) {
00287 case QTR_NODE_LEAF:
00288
00289 switch (quadrant) {
00290 case 0:
00291 rc = qtrnode->leafData.nwElevation;
00292 break;
00293 case 1:
00294 rc = qtrnode->leafData.neElevation;
00295 break;
00296 case 2:
00297 rc = qtrnode->leafData.swElevation;
00298 break;
00299 case 3:
00300 rc = qtrnode->leafData.seElevation;
00301 break;
00302 default:
00303 gtfo ("CQTRFile::Search : Invalid quadrant");
00304 }
00305 break;
00306
00307 case QTR_NODE_BRANCH:
00308
00309 switch (quadrant) {
00310 case 0:
00311 rc = Search (level-1, qtrnode->branchData.nwNode, xNew, zNew);
00312 break;
00313 case 1:
00314 rc = Search (level-1, qtrnode->branchData.swNode, xNew, zNew);
00315 break;
00316 case 2:
00317 rc = Search (level-1, qtrnode->branchData.neNode, xNew, zNew);
00318 break;
00319 case 3:
00320 rc = Search (level-1, qtrnode->branchData.seNode, xNew, zNew);
00321 break;
00322 default:
00323 gtfo ("CQTRFile::Search : Invalid quadrant");
00324 }
00325 break;
00326
00327 case QTR_NODE_RASTER_REL:
00328 {
00329
00330 if (level != 3) {
00331 gtfo ("CQTRFile : Attempt to traverse relative raster data block at level %d",
00332 level);
00333 }
00334 int rasterSize = 1 << level;
00335 int xr = x % rasterSize;
00336 int zr = z % rasterSize;
00337 rc = ExtractRelativeData (GetRasterData(qtrnode->rasterData.offset), xr, zr);
00338 }
00339 break;
00340
00341 case QTR_NODE_RASTER_ABS:
00342 {
00343
00344 if (level != 3) {
00345 gtfo ("CQTRFile : Attempt to traverse absolute raster data block at level %d",
00346 level);
00347 }
00348 int rasterSize = 1 << level;
00349 int xr = x % rasterSize;
00350 int zr = z % rasterSize;
00351 rc = ExtractAbsoluteData ((short *)GetRasterData(qtrnode->rasterData.offset),
00352 xr, zr);
00353 }
00354 break;
00355 }
00356 }
00357
00358 return rc;
00359 }
00360
00361
00362
00363
00364 void CQTRFile::Dump (const char* txtFilename)
00365 {
00366 FILE *fOut = fopen (txtFilename, "w");
00367
00368 int nBranchNodes = 0;
00369 int nLeafNodes = 0;
00370 int nRelativeNodes = 0;
00371 int nAbsoluteNodes = 0;
00372
00373
00374 fprintf (fOut, "QTR Header:\n\n");
00375 fprintf (fOut, " numNodes : %d\n", header.numNodes);
00376 fprintf (fOut, " dimensions : %d x %d\n", header.width, header.height);
00377 fprintf (fOut, " elevations : NW=%d NE=%d SW=%d SE=%d\n",
00378 header.elev[0], header.elev[1], header.elev[2], header.elev[3]);
00379 fprintf (fOut, " rasterBytes: %d\n", header.rasterBytes);
00380 fprintf (fOut, "\n");
00381
00382
00383 for (unsigned short i=0; i<header.numNodes; i++) {
00384
00385 SQTRNode *node = &qtreenode[i];
00386
00387 fprintf (fOut, "Node %05d: ", i);
00388 switch (node->type) {
00389 case QTR_NODE_BRANCH:
00390 {
00391 nBranchNodes++;
00392
00393 fprintf (fOut, "BRANCH center=%5d NW=%05d NE=%05d SW=%05d SE=%05d\n",
00394 node->center,
00395 node->branchData.nwNode,
00396 node->branchData.neNode,
00397 node->branchData.swNode,
00398 node->branchData.seNode);
00399 }
00400 break;
00401 case QTR_NODE_LEAF:
00402 {
00403 nLeafNodes++;
00404
00405 fprintf (fOut, "LEAF center=%05d NW=%05d NE=%05d SW=%05d SE=%05d\n",
00406 node->center,
00407 node->leafData.nwElevation,
00408 node->leafData.neElevation,
00409 node->leafData.swElevation,
00410 node->leafData.seElevation);
00411 }
00412 break;
00413 case QTR_NODE_RASTER_REL:
00414 {
00415 nRelativeNodes++;
00416
00417 char *pData = GetRasterData (node->rasterData.offset);
00418 short base = *((short *)pData);
00419 pData += sizeof(short);
00420
00421 fprintf (fOut, "RELATIVE center=%5d offset=0x%08X dummy=0x%08X base=%5d\n",
00422 node->center,
00423 node->rasterData.offset,
00424 node->rasterData.dummy,
00425 base);
00426 for (int row=0; row<8; row++) {
00427 fprintf (fOut, " ");
00428 for (int col=0; col<8; col++) {
00429 unsigned char c = pData[row * 8 + col];
00430 fprintf (fOut, "%5d ", c);
00431 }
00432 fprintf (fOut, "\n");
00433 }
00434 }
00435 break;
00436 case QTR_NODE_RASTER_ABS:
00437 {
00438 nAbsoluteNodes++;
00439
00440 short *pData = (short *)(GetRasterData (node->rasterData.offset));
00441
00442 fprintf (fOut, "ABSOLUTE center=%5d offset=0x%08X, dummy=0x%08X\n",
00443 node->center,
00444 node->rasterData.offset,
00445 node->rasterData.dummy);
00446 for (int row=0; row<8; row++) {
00447 fprintf (fOut, " ");
00448 for (int col=0; col<8; col++) {
00449 short s = pData[row * 8 + col];
00450 fprintf (fOut, "%5d ", s);
00451 }
00452 fprintf (fOut, "\n");
00453 }
00454 }
00455 break;
00456 default:
00457 fprintf (fOut, "*** Unknown node type 0x%02X\n");
00458 }
00459 }
00460
00461
00462 fprintf (fOut, "\n");
00463 fprintf (fOut, "nBranchNodes = %d\n", nBranchNodes);
00464 fprintf (fOut, "nLeafNodes = %d\n", nLeafNodes);
00465 fprintf (fOut, "nRelativeNodes = %d\n", nRelativeNodes);
00466 fprintf (fOut, "nAbsoluteNodes = %d\n", nAbsoluteNodes);
00467
00468 fclose (fOut);
00469 }
00470
00471