2015-01-20 01:33:30 -06:00

1008 lines
29 KiB
C++

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "file.hpp"
#include "dat.hpp"
#include "../../zone/map.h"
//#define DEBUGDAT
#define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type);
#define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1;
#define VARSTRUCT_ENCODE_STRING(Buffer, String) sprintf(Buffer, String); Buffer += strlen(String) + 1;
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1;
#define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) *(Type *)Buffer = Value; Buffer += sizeof(Type);
#define VARSTRUCT_SKIP_TYPE(Type, Buffer) Buffer += sizeof(Type);
float HeightWithinQuad(VERTEX p1, VERTEX p2, VERTEX p3, VERTEX p4, float x, float y)
{
// This function returns the height of the given x/y point with the quad defined by p1,p2,p3 and p4.
//
// It is assumed that the point does in fact lie somewhere within the quad. If for some reason it doesn't,
// the program will abort, as thre is a logic flaw.
//
/*
printf("Quad: %8.3f, %8.3f, %8.3f\n", p1.x, p1.y, p1.z);
printf(" %8.3f, %8.3f, %8.3f\n", p2.x, p2.y, p2.z);
printf(" %8.3f, %8.3f, %8.3f\n", p3.x, p3.y, p3.z);
printf(" %8.3f, %8.3f, %8.3f\n", p4.x, p4.y, p4.z);
printf("\n\nPoint: %8.3f, %8.3f\n", x, y);
*/
FACE f;
int inTriangle = 0;
float fAB = (y-p1.y) * (p2.x-p1.x) - (x-p1.x) * (p2.y-p1.y);
float fBC = (y-p2.y) * (p3.x-p2.x) - (x-p2.x) * (p3.y-p2.y);
float fCA = (y-p3.y) * (p1.x-p3.x) - (x-p3.x) * (p1.y-p3.y);
if((fAB * fBC >= 0) && (fBC * fCA >= 0))
{
inTriangle = 1;
f.a = p1;
f.b = p2;
f.c = p3;
}
fAB = (y-p1.y) * (p3.x-p1.x) - (x-p1.x) * (p3.y-p1.y);
fBC = (y-p3.y) * (p4.x-p3.x) - (x-p3.x) * (p4.y-p3.y);
fCA = (y-p4.y) * (p1.x-p4.x) - (x-p4.x) * (p1.y-p4.y);
if((fAB * fBC >= 0) && (fBC * fCA >= 0))
{
inTriangle = 2;
f.a = p1;
f.b = p3;
f.c = p4;
}
if(inTriangle == 0)
{
printf("Something went wrong. Aborting in HeightWithinQuad\n");
exit(0);
}
f.nx = (f.b.y - f.a.y)*(f.c.z - f.a.z) - (f.b.z - f.a.z)*(f.c.y - f.a.y);
f.ny = (f.b.z - f.a.z)*(f.c.x - f.a.x) - (f.b.x - f.a.x)*(f.c.z - f.a.z);
f.nz = (f.b.x - f.a.x)*(f.c.y - f.a.y) - (f.b.y - f.a.y)*(f.c.x - f.a.x);
float len = sqrt(f.nx*f.nx + f.ny*f.ny + f.nz*f.nz);
f.nx /= len;
f.ny /= len;
f.nz /= len;
return (((f.nx) * (x - f.a.x) + (f.ny) * (y - f.a.y)) / -f.nz) + f.a.z;
}
string GetToken(uchar *&Buffer, int &Position)
{
// This is used to return each Token, keyword, etc. from an EQG v4 .zon or .tog file
//
string Token;
while((Buffer[Position] == 9) || (Buffer[Position] == 32))
++Position;
while((Buffer[Position] != 10) && (Buffer[Position] != 9) && (Buffer[Position] != 32))
{
if(Buffer[Position] > 32)
Token = Token + (char)Buffer[Position];
++Position;
}
++Position;
return Token;
}
int AddModelName(Content_3D *C3D, string ModelName)
{
vector<string>::iterator Iterator;
for(unsigned int i = 0; i < C3D->ModelNames.size(); ++i)
{
#ifndef WIN32
if(!strcasecmp(C3D->ModelNames[i].c_str(), ModelName.c_str()))
#else
if(!_stricmp(C3D->ModelNames[i].c_str(), ModelName.c_str()))
#endif
return i;
}
C3D->ModelNames.push_back(ModelName);
return C3D->ModelNames.size() - 1;
}
DATLoader::DATLoader()
{
this->buffer = nullptr;
this->buf_len = -1;
this->archive = nullptr;
this->status = 0;
}
DATLoader::~DATLoader()
{
this->Close();
}
int DATLoader::Open(char *base_path, char *zone_name, Archive *archive) {
#ifdef DEBUGDAT
printf("DATLoader::Open %s, [%s]\n", base_path, zone_name);
fflush(stdout);
#endif
unsigned int i, j, mat_count = 0;
Zone_Model *zm;
char *buffer, *buf_start;
int buf_len, bone_count;
char *filename;
if(zone_name[strlen(zone_name) - 4] == '.')
filename = zone_name;
else
{
filename = new char[strlen(zone_name) + 5];
sprintf(filename, "%s.ter", zone_name);
}
if(!GetFile((uchar **)&buffer, &buf_len, base_path, filename, archive))
{
if(filename != zone_name)
delete[] filename;
return 0;
}
#ifdef DEBUGDAT
printf("Filename = %s, zonename = %s\n", filename, zone_name);
#endif
if(filename != zone_name)
delete[] filename;
buf_start = buffer;
//TODO: Find out what these three unknowns are
int Unknown1 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int Unknown2 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int Unknown3 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
#ifdef DEBUGDAT
printf("Unknowns: %i, %i, %i\n", Unknown1, Unknown2, Unknown3);
#endif
char s[255];
VARSTRUCT_DECODE_STRING(s, buffer)
#ifdef DEBUGDAT
printf("('%s',)\n", s);
#endif
int TileCount = VARSTRUCT_DECODE_TYPE(uint32, buffer);
#ifdef DEBUGDAT
printf("TileCount is %i\n", TileCount);
#endif
// Most of these default values will be overwritten when we read the .zon file
//
int QuadsPerTile = 32;
float MinLAT = -24;
float MaxLAT = -1;
float MinLNG = 0;
float MaxLNG = 62;
float UnitsPerVert = 5.0;
float ZoneMinX = 0;
float ZoneMaxX = 0;
float ZoneMinY = 0;
float ZoneMaxY = 0;
float MinExtentX = -999999, MinExtentY = -999999, MinExtentZ = -999999;
float MaxExtentX = 999999, MaxExtentY = 999999, MaxExtentZ = 999999;
// Parse .zon file.
//
uchar *ZonBuffer;
int ZonBufferLength, ZonPosition;
if(!GetFile((uchar **)&ZonBuffer, &ZonBufferLength, base_path, "*.zon", archive))
{
printf("Unable to open .zon\n");
exit(0);
}
else
{
ZonPosition = 0;
while(ZonPosition < ZonBufferLength)
{
string Token = GetToken(ZonBuffer, ZonPosition);
if(Token == "*MINLNG")
{
Token = GetToken(ZonBuffer, ZonPosition);
MinLNG = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set MinLNG to %8.3f\n", MinLNG);
#endif
}
if(Token == "*MAXLNG")
{
Token = GetToken(ZonBuffer, ZonPosition);
MaxLNG = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set MaxLNG to %8.3f\n", MaxLNG);
#endif
}
if(Token == "*MINLAT")
{
Token = GetToken(ZonBuffer, ZonPosition);
MinLAT = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set MinLAT to %8.3f\n", MinLAT);
#endif
}
if(Token == "*MAXLAT")
{
Token = GetToken(ZonBuffer, ZonPosition);
MaxLAT = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set MaxLAT to %8.3f\n", MaxLAT);
#endif
}
if(Token == "*UNITSPERVERT")
{
Token = GetToken(ZonBuffer, ZonPosition);
UnitsPerVert = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set UnitsPerVert to %8.3f\n", UnitsPerVert);
#endif
}
if(Token == "*QUADSPERTILE")
{
Token = GetToken(ZonBuffer, ZonPosition);
QuadsPerTile = atoi(Token.c_str());
#ifdef DEBUGDAT
printf("Set QuadsPerTile to %i\n", QuadsPerTile);
#endif
}
if(Token == "*MIN_EXTENTS")
{
Token = GetToken(ZonBuffer, ZonPosition);
MinExtentX = atof(Token.c_str());
Token = GetToken(ZonBuffer, ZonPosition);
MinExtentY = atof(Token.c_str());
Token = GetToken(ZonBuffer, ZonPosition);
MinExtentZ = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set MinExtents to %8.3f, %8.3f, %8.3f\n", MinExtentX, MinExtentY, MinExtentZ);
#endif
}
if(Token == "*MAX_EXTENTS")
{
Token = GetToken(ZonBuffer, ZonPosition);
MaxExtentX = atof(Token.c_str());
Token = GetToken(ZonBuffer, ZonPosition);
MaxExtentY = atof(Token.c_str());
Token = GetToken(ZonBuffer, ZonPosition);
MaxExtentZ = atof(Token.c_str());
#ifdef DEBUGDAT
printf("Set MaxExtents to %8.3f, %8.3f, %8.3f\n", MaxExtentX, MaxExtentY, MaxExtentZ);
#endif
}
}
}
float UnitsPerVertX = UnitsPerVert;
float UnitsPerVertY = UnitsPerVert;
float LATRange = (MaxLAT - MinLAT);
float LNGRange = (MaxLNG - MinLNG);
ZoneMinX = MinLAT * QuadsPerTile * UnitsPerVert;
ZoneMaxX = (MaxLAT + 1) * QuadsPerTile * UnitsPerVert;
ZoneMinY = MinLNG * QuadsPerTile * UnitsPerVert;
ZoneMaxY = (MaxLNG + 1) * QuadsPerTile * UnitsPerVert;
int QuadCount = (QuadsPerTile * QuadsPerTile);
int VertCount = ((QuadsPerTile + 1) * (QuadsPerTile + 1));
#ifdef DEBUGDAT
printf("X Range: %8.3f to %8.3f\n", ZoneMinX, ZoneMaxX);
printf("Y Range: %8.3f to %8.3f\n", ZoneMinY, ZoneMaxY);
printf("UnitsPerVertX = %8.3f, UnitsPerVertY = %8.3f\n", UnitsPerVertX, UnitsPerVertY);
printf("LATRange is from %8.3f to %8.3f (%8.3f), x = %8.3f to %8.3f (%8.3f)\n",
MinLAT, MaxLAT, LATRange, ZoneMinX, ZoneMaxX, ZoneMaxX - ZoneMinX);
#endif
int VertexNumber = -1;
int PolyNumber = -1;
this->model_data.zone_model = new Zone_Model;
zm = this->model_data.zone_model;
zm->vert_count = QuadCount * TileCount * 4;
zm->poly_count = QuadCount * 2 * TileCount;
zm->verts = new Vertex *[zm->vert_count];
zm->polys = new Polygon *[zm->poly_count];
this->model_data.plac_count = 0;
this->model_data.model_count = 0;
this->model_data.ObjectGroupCount = 0;
float *Floats = new float[VertCount];
int *Color1 = new int[VertCount];
int *Color2 = new int[VertCount];
uint8 *Bytes = new uint8[QuadCount];
for(int TileNumber = 0; TileNumber < TileCount; ++TileNumber)
{
int TileLNG = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int TileLAT = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int TileUNK = VARSTRUCT_DECODE_TYPE(uint32, buffer);
float TileYStart = ZoneMinY + (TileLNG - 100000 - MinLNG) * UnitsPerVertY * QuadsPerTile;
float TileXStart = ZoneMinX + (TileLAT - 100000 - MinLAT) * UnitsPerVertX * QuadsPerTile;
#ifdef DEBUGDAT
printf("TileXStart = %8.3f + %f * %f * %i\n", ZoneMinX, (TileLAT - 100000 - MinLAT) , UnitsPerVertX, QuadsPerTile);
printf("****** Tile # %5d header %6d, %6d, %6d (LNG: %6d, LAT: %6d)\n", TileNumber, TileLNG, TileLAT, TileUNK,
TileLNG - 100000, TileLAT - 100000);
printf("TileXStart = %8.3f, TileYStart = %8.3f\n", TileXStart, TileYStart);
printf("TileXEnd = %8.3f, TileYEnd = %8.3f\n", TileXStart + QuadsPerTile * UnitsPerVertX,
TileYStart + QuadsPerTile * UnitsPerVertY);
#endif
// Height Values
//
bool AllFloatsTheSame = true;
for(int i = 0; i < VertCount; ++i)
{
Floats[i] = VARSTRUCT_DECODE_TYPE(float, buffer);
if((i > 0) && (Floats[i] != Floats[0]))
AllFloatsTheSame = false;
}
// It is an assumption that these next two groups are Color info, but they look like it.
//
for(int i = 0; i < VertCount; ++i)
{
Color1[i] = VARSTRUCT_DECODE_TYPE(uint32, buffer);
}
for(int i = 0; i < VertCount; ++i)
{
Color2[i] = VARSTRUCT_DECODE_TYPE(uint32, buffer);
}
// The low order bit of this group of bytes indicates whether the corresponding quad should
// be rendered or not.
for(int i = 0; i < QuadCount; ++i)
{
Bytes[i] = VARSTRUCT_DECODE_TYPE(uint8, buffer);
}
float UnkFloat = VARSTRUCT_DECODE_TYPE(float, buffer);
int UnkUnk = VARSTRUCT_DECODE_TYPE(uint32, buffer);
buffer -= 4;
float UnkUnk2 = VARSTRUCT_DECODE_TYPE(float, buffer);
#ifdef DEBUGDAT
printf("Unknowns %.1f %i (%8.3f)\n", UnkFloat, UnkUnk, UnkUnk2);
#endif
if(UnkUnk > 0)
{
int8 UnkByte = VARSTRUCT_DECODE_TYPE(uint8, buffer);
#ifdef DEBUGDAT
printf("Byte is (%i,)\n", UnkByte);
#endif
if(UnkByte > 0)
{
float f1 = VARSTRUCT_DECODE_TYPE(float, buffer);
float f2 = VARSTRUCT_DECODE_TYPE(float, buffer);
float f3 = VARSTRUCT_DECODE_TYPE(float, buffer);
float f4 = VARSTRUCT_DECODE_TYPE(float, buffer);
#ifdef DEBUGDAT
printf("Floats: %.1f %.1f %1.f %.1f\n", f1, f2, f3, f4);
#endif
}
float f1 = VARSTRUCT_DECODE_TYPE(float, buffer);
#ifdef DEBUGDAT
printf("Float: (%.1f,)\n", f1);
#endif
}
int LayerCount = VARSTRUCT_DECODE_TYPE(uint32, buffer);
VARSTRUCT_DECODE_STRING(s, buffer);
int OverlayCount = 0;
for(int Layer = 1; Layer < LayerCount; ++Layer)
{
VARSTRUCT_DECODE_STRING(s, buffer);
int Size = VARSTRUCT_DECODE_TYPE(uint32, buffer);
for(int b = 0; b < (Size * Size); ++b)
{
uint8 Byte = VARSTRUCT_DECODE_TYPE(uint8, buffer);
}
++OverlayCount;
}
int Count1 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
#ifdef DEBUGDAT
printf("Count 1 is (%iL,)\n", Count1);
#endif
// The Count1 section is a list of single placeable models
//
for(int j = 0; j < Count1; ++j)
{
char ModelName[255];
VARSTRUCT_DECODE_STRING(ModelName, buffer);
#ifdef DEBUGDAT
printf("%s\n", ModelName);
#endif
int ModelNumber = AddModelName(&model_data, ModelName);
VARSTRUCT_DECODE_STRING(s, buffer);
#ifdef DEBUGDAT
printf("%s\n", s);
#endif
// Although the LNG/LAT is included for each model within this tile, the values always appear to be
// the same as for the parent tile.
//
int Longitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int Latitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
float x = VARSTRUCT_DECODE_TYPE(float, buffer);
float y = VARSTRUCT_DECODE_TYPE(float, buffer);
float z = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotX = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotY = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotZ = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleX = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleY = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleZ = VARSTRUCT_DECODE_TYPE(float, buffer);
VARSTRUCT_DECODE_TYPE(uint8, buffer);
Placeable p(ModelNumber, 0, 0, 0, RotX, RotY, RotZ, ScaleX, ScaleY, ScaleZ);
model_data.PlaceableList.push_back(p);
#ifdef DEBUGDAT
printf("Model: %s LOC: %8.3f, %8.3f, %8.3f, ROT: %8.3f, %8.3f, %8.3f\n", ModelName, x, y, z, RotX, RotY, RotZ);
#endif
ObjectGroupEntry NewObjectGroup;
NewObjectGroup.FromTOG = false;
NewObjectGroup.y = y;
NewObjectGroup.x = x;
NewObjectGroup.z = z;
NewObjectGroup.TileX = TileYStart;
NewObjectGroup.TileY = TileXStart;
// The objects in the Count1 section have a Z offset relative to the ground level, so we calculate the
// ground level within this quad for the given x/y offsets. However ...
//
// Some objects within a tile have an X/Y offset specified such that they actually sit within the bounds
// of another tile, which means based on the data for the tile we are processing, we should be unable to
// calculate the Z value for that object.
//
// By hand editing an .EQG, it was discovered that what the client appears to do is calculate the Z value
// for these objects by adjusting the x/y offsets by +/- (QuadsPerTile * UnitsPerVert) until the offsets
// are within this tiles boundaries and using the corresponding height values.
//
// For example, if a model has an offset of -157.5, -157.5 and QPT * UPV = 160, then the height value used
// would be the height at +2.5, +2.5 in this tile.
//
// This doesn't make a great deal of sense, but it is how the EQ graphics engine appears to do things.
//
// These 'Adjusted' x/y offsets are used only for determing the ground Z for the object. The actual placement
// of the object relative to the terrain uses the unadjusted offsets.
//
// For the record, as of SoF, this applies to the following zones and objects:
//
// arcstone: Model translations adjusted from -14.000, 219.000 to 146.000, 59.000
// arcstone: Model translations adjusted from 159.692, 256.589 to 159.692, 96.589
// arcstone: Model translations adjusted from 122.314, 170.098 to 122.314, 10.098
// elddar: Model translations adjusted from 144.980, 396.406 to 144.980, 76.406
// elddar: Model translations adjusted from 167.534, -193.584 to 7.534, 126.416
// kithicor: Model translations adjusted from 18.217, 166.512 to 18.217, 6.512
// hro.out: Model translations adjusted from 38.249, -4.658 to 38.249, 155.342
// steppes: Model translations adjusted from 101.380, 380.000 to 101.380, 124.000
// steppes: Model translations adjusted from 32.770, -210.000 to 32.770, 46.000
// steppes: Model translations adjusted from 560.000, 150.000 to 48.000, 22.000
// steppes: Model translations adjusted from 420.000, 445.000 to 36.000, 61.000
//
float TerrainHeight = 0;
float AdjustedX = x;
float AdjustedY = y;
if(AdjustedX < 0)
AdjustedX = AdjustedX + (-(int)(AdjustedX / (UnitsPerVertX * QuadsPerTile)) + 1) * (UnitsPerVertX * QuadsPerTile);
else
AdjustedX = fmod(AdjustedX, UnitsPerVertX * QuadsPerTile);
if(AdjustedY < 0)
AdjustedY = AdjustedY + (-(int)(AdjustedY / (UnitsPerVertX * QuadsPerTile)) + 1) * (UnitsPerVertX * QuadsPerTile);
else
AdjustedY = fmod(AdjustedY, UnitsPerVertY * QuadsPerTile);
#ifdef DEBUGDAT
if((AdjustedX != x) || (AdjustedY != y))
printf(" Model translations adjusted from %8.3f, %8.3f to %8.3f, %8.3f\n", x, y, AdjustedX, AdjustedY);
#endif
// Calculated which quad the adjusted x/y coordinated of the object lie in.
//
int RowNumber = (int)(AdjustedY / UnitsPerVertY);
int Column = (int)(AdjustedX / UnitsPerVertX);
int Quad = RowNumber * QuadsPerTile + Column;
float QuadVertex1Z = Floats[Quad + RowNumber];
float QuadVertex2Z = Floats[Quad + RowNumber + QuadsPerTile + 1];
float QuadVertex3Z = Floats[Quad + RowNumber + QuadsPerTile + 2];
float QuadVertex4Z = Floats[Quad + RowNumber + 1];
VERTEX P1(RowNumber * UnitsPerVertX, (Quad % QuadsPerTile) * UnitsPerVertY, QuadVertex1Z);
VERTEX P2(P1.x + UnitsPerVertX, P1.y, QuadVertex2Z);
VERTEX P3(P1.x + UnitsPerVertX, P1.y + UnitsPerVertY, QuadVertex3Z);
VERTEX P4(P1.x, P1.y + UnitsPerVertY, QuadVertex4Z);
TerrainHeight = HeightWithinQuad(P1, P2, P3, P4, AdjustedY, AdjustedX);
#ifdef DEBUGDAT
printf("XY: %8.3f, %8.3f Row: %i, Columm: %i, Quad: %i\n", x, y, RowNumber, Column, Quad);
printf("Zs: %8.3f, %8.3f, %8.3f, %8.3f\n", QuadVertex1Z, QuadVertex2Z, QuadVertex3Z, QuadVertex4Z);
printf("Height is %8.3f\n", TerrainHeight);
#endif
NewObjectGroup.TileZ = TerrainHeight;
NewObjectGroup.RotX = 0;
NewObjectGroup.RotY = 0;
NewObjectGroup.RotZ = 0;
NewObjectGroup.ScaleX = 1;
NewObjectGroup.ScaleY = 1;
NewObjectGroup.ScaleZ = 1;
NewObjectGroup.SubObjects.push_back(model_data.PlaceableList.size()-1);
model_data.ObjectGroups.push_back(NewObjectGroup);
#ifdef DEBUGDAT
printf("ObjectGroup %i created.\n", model_data.ObjectGroups.size()-1);
#endif
}
// We don't currently do anything with the Count2 objects.
// Things like water, teleports, zonelines seem to be in here, judging from the strings.
//
int Count2 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
#ifdef DEBUGDAT
printf("Count 2 is (%iL,)\n", Count2);
#endif
for(int j = 0; j < Count2; ++j)
{
VARSTRUCT_DECODE_STRING(s, buffer);
#ifdef DEBUGDAT
printf("%s\n", s);
#endif
VARSTRUCT_DECODE_TYPE(uint32, buffer);
VARSTRUCT_DECODE_STRING(s, buffer);
#ifdef DEBUGDAT
printf("%s\n", s);
#endif
int Longitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int Latitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
float x = VARSTRUCT_DECODE_TYPE(float, buffer);
float y = VARSTRUCT_DECODE_TYPE(float, buffer);
float z = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotX = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotY = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotZ = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleX = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleY = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleZ = VARSTRUCT_DECODE_TYPE(float, buffer);
float SizeX = VARSTRUCT_DECODE_TYPE(float, buffer);
float SizeY = VARSTRUCT_DECODE_TYPE(float, buffer);
float SizeZ = VARSTRUCT_DECODE_TYPE(float, buffer);
}
int Count3 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
// We don't currently do anything with the Count 3 data. Mostly seems to be camp fires and suchlike.
//
#ifdef DEBUGDAT
printf("Count 3 is (%iL,)\n", Count3);
#endif
for(int j = 0; j < Count3; ++j)
{
VARSTRUCT_DECODE_STRING(s, buffer);
#ifdef DEBUGDAT
printf("%s\n", s);
#endif
VARSTRUCT_DECODE_STRING(s, buffer);
#ifdef DEBUGDAT
printf("%s\n", s);
#endif
VARSTRUCT_DECODE_TYPE(uint8, buffer);
int Longitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int Latitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
float x = VARSTRUCT_DECODE_TYPE(float, buffer);
float y = VARSTRUCT_DECODE_TYPE(float, buffer);
float z = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotX = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotY = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotZ = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleX = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleY = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleZ = VARSTRUCT_DECODE_TYPE(float, buffer);
VARSTRUCT_DECODE_TYPE(float, buffer);
}
int Count4 = VARSTRUCT_DECODE_TYPE(uint32, buffer);
// The data in this section mostly references .tog (Object Group) files.
//
#ifdef DEBUGDAT
printf("Count 4 is (%iL,)\n", Count4);
#endif
for(int j = 0; j < Count4; ++j)
{
char TogName[255];
VARSTRUCT_DECODE_STRING(TogName, buffer);
#ifdef DEBUGDAT
printf("%s\n", TogName);
#endif
int Longitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
int Latitude = VARSTRUCT_DECODE_TYPE(uint32, buffer);
float x = VARSTRUCT_DECODE_TYPE(float, buffer);
float y = VARSTRUCT_DECODE_TYPE(float, buffer);
float z = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotX = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotY = VARSTRUCT_DECODE_TYPE(float, buffer);
float RotZ = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleX = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleY = VARSTRUCT_DECODE_TYPE(float, buffer);
float ScaleZ = VARSTRUCT_DECODE_TYPE(float, buffer);
float ZAdjust = VARSTRUCT_DECODE_TYPE(float, buffer);
#ifdef DEBUGDAT
printf("ZAdjust %8.3f\n", ZAdjust);
#endif
char TogFileName[255];
sprintf(TogFileName, "%s.tog", TogName);
uchar *TogBuffer;
int TogBufferLength, TogPosition;
if(!GetFile((uchar **)&TogBuffer, &TogBufferLength, base_path, TogFileName, archive))
{
printf("Unable to open %s\n", TogFileName);
}
else
{
ObjectGroupEntry NewObjectGroup;
NewObjectGroup.FromTOG = true;
NewObjectGroup.y = y;
NewObjectGroup.x = x;
NewObjectGroup.z = z;
NewObjectGroup.TileX = TileYStart;
NewObjectGroup.TileY = TileXStart;
NewObjectGroup.TileZ = 0;
NewObjectGroup.RotX = RotX;
NewObjectGroup.RotY = RotY;
NewObjectGroup.RotZ = RotZ;
NewObjectGroup.ScaleX = ScaleX;
NewObjectGroup.ScaleY = ScaleY;
NewObjectGroup.ScaleZ = ScaleZ;
NewObjectGroup.z = NewObjectGroup.z + (NewObjectGroup.ScaleZ * ZAdjust);
Placeable p;
TogPosition = 0;
string ModelName;
while(TogPosition < TogBufferLength)
{
string Token = GetToken(TogBuffer, TogPosition);
if(Token == "*NAME")
{
Token = GetToken(TogBuffer, TogPosition);
ModelName = Token;
p.model = AddModelName(&model_data, Token.c_str());
}
if(Token == "*POSITION")
{
p.x = atof(GetToken(TogBuffer, TogPosition).c_str());
p.y = atof(GetToken(TogBuffer, TogPosition).c_str());
p.z = atof(GetToken(TogBuffer, TogPosition).c_str());
}
if(Token == "*ROTATION")
{
p.rx = atof(GetToken(TogBuffer, TogPosition).c_str());
p.ry = atof(GetToken(TogBuffer, TogPosition).c_str());
p.rz = atof(GetToken(TogBuffer, TogPosition).c_str());
}
if(Token == "*SCALE")
{
p.scale[0] = atof(GetToken(TogBuffer, TogPosition).c_str());
p.scale[1] = p.scale[2] = p.scale[0];
}
if(Token == "*END_OBJECT")
{
#ifdef DEBUGDAT
printf("Pushing back object with model: %3i %s\n", p.model, ModelName.c_str());
printf(" Position : %8.3f, %8.3f, %8.3f\n", p.x, p.y, p.z);
printf(" Rotations : %8.3f, %8.3f, %8.3f\n", p.rx, p.ry, p.rz);
printf(" Scale : %8.3f, %8.3f, %8.3f\n", p.scale[0], p.scale[1], p.scale[2]);
#endif
model_data.PlaceableList.push_back(p);
NewObjectGroup.SubObjects.push_back(model_data.PlaceableList.size()-1);
}
if(Token == "*END_OBJECTGROUP")
{
#ifdef DEBUGDAT
printf("Pushing back new ObjectGroup\n");
printf(" Position : %8.3f, %8.3f, %8.3f\n", NewObjectGroup.x, NewObjectGroup.y, NewObjectGroup.z);
printf(" Rotations : %8.3f, %8.3f, %8.3f\n", NewObjectGroup.RotX, NewObjectGroup.RotY, NewObjectGroup.RotZ);
printf(" Scale : %8.3f, %8.3f, %8.3f\n", NewObjectGroup.ScaleX, NewObjectGroup.ScaleY, NewObjectGroup.ScaleZ);
printf("Adjusting NewObjectGroup.z by %8.3f\n", NewObjectGroup.ScaleZ * ZAdjust);
#endif
model_data.ObjectGroups.push_back(NewObjectGroup);
#ifdef DEBUGDAT
printf("ObjectGroup %i created.\n", model_data.ObjectGroups.size()-1);
// There can be several object groups defined in the same .tog
NewObjectGroup.SubObjects.clear();
#endif
}
if(Token == "*BEGIN_AREA")
{
while(Token != "*END_AREA")
{
#ifdef DEBUGDAT
printf("Skipping %s\n", Token.c_str());
#endif
Token = GetToken(TogBuffer, TogPosition);
}
}
}
}
}
// If all the height values in this tile are the same, then we can just make one big quad of two triangles.
//
// This cuts over 200MB off the size of the oceanoftears .map, however not very much for other zones.
//
if(AllFloatsTheSame)
{
float QuadVertex1X = TileXStart;
float QuadVertex1Y = TileYStart;
float QuadVertex1Z = Floats[0];
float QuadVertex2X = QuadVertex1X + (QuadsPerTile * UnitsPerVertX);
float QuadVertex2Y = QuadVertex1Y;
float QuadVertex2Z = QuadVertex1Z;
float QuadVertex3X = QuadVertex2X;
float QuadVertex3Y = QuadVertex1Y + (QuadsPerTile * UnitsPerVertY);
float QuadVertex3Z = QuadVertex1Z;
float QuadVertex4X = QuadVertex1X;
float QuadVertex4Y = QuadVertex3Y;
float QuadVertex4Z = QuadVertex1Z;
++VertexNumber;
zm->verts[VertexNumber++] = new Vertex(QuadVertex1Y, QuadVertex1X, QuadVertex1Z);
zm->verts[VertexNumber++] = new Vertex(QuadVertex2Y, QuadVertex2X, QuadVertex2Z);
zm->verts[VertexNumber++] = new Vertex(QuadVertex3Y, QuadVertex3X, QuadVertex3Z);
zm->verts[VertexNumber] = new Vertex(QuadVertex4Y, QuadVertex4X, QuadVertex4Z);
PolyNumber++;
zm->polys[PolyNumber] = new Polygon;
zm->polys[PolyNumber]->v1 = VertexNumber;
zm->polys[PolyNumber]->v2 = VertexNumber - 2;
zm->polys[PolyNumber]->v3 = VertexNumber - 1;
zm->polys[PolyNumber]->tex = -1;
PolyNumber++;
zm->polys[PolyNumber] = new Polygon;
zm->polys[PolyNumber]->v1 = VertexNumber;
zm->polys[PolyNumber]->v2 = VertexNumber - 3;
zm->polys[PolyNumber]->v3 = VertexNumber - 2;
zm->polys[PolyNumber]->tex = -1;
}
else
{
int RowNumber = -1;
// This is the code that generates triangles for this tile of the terrain based on the height values we decode above.
//
for(int Quad = 0; Quad < QuadCount; ++Quad)
{
if((Quad % QuadsPerTile) == 0)
++RowNumber;
// Other common values for this Byte are 0x80, 0x82. Setting them all to zero has no obvious visual
// effect.
if(Bytes[Quad] & 0x01) // Indicates Quad should not be included because an object will overlay it.
continue;
float QuadVertex1X = TileXStart + (RowNumber * UnitsPerVertX);
float QuadVertex1Y = TileYStart + (Quad % QuadsPerTile) * UnitsPerVertY;
float QuadVertex1Z = Floats[Quad + RowNumber];
float QuadVertex2X = QuadVertex1X + UnitsPerVertX;
float QuadVertex2Y = QuadVertex1Y;
float QuadVertex2Z = Floats[Quad + RowNumber + QuadsPerTile + 1];
float QuadVertex3X = QuadVertex1X + UnitsPerVertX;
float QuadVertex3Y = QuadVertex1Y + UnitsPerVertY;
float QuadVertex3Z = Floats[Quad + RowNumber + QuadsPerTile + 2];
float QuadVertex4X = QuadVertex1X;
float QuadVertex4Y = QuadVertex1Y + UnitsPerVertY;
float QuadVertex4Z = Floats[Quad + RowNumber + 1];
++VertexNumber;
zm->verts[VertexNumber++] = new Vertex(QuadVertex1Y, QuadVertex1X, QuadVertex1Z);
zm->verts[VertexNumber++] = new Vertex(QuadVertex2Y, QuadVertex2X, QuadVertex2Z);
zm->verts[VertexNumber++] = new Vertex(QuadVertex3Y, QuadVertex3X, QuadVertex3Z);
zm->verts[VertexNumber] = new Vertex(QuadVertex4Y, QuadVertex4X, QuadVertex4Z);
PolyNumber++;
zm->polys[PolyNumber] = new Polygon;
zm->polys[PolyNumber]->v1 = VertexNumber;
zm->polys[PolyNumber]->v2 = VertexNumber - 2;
zm->polys[PolyNumber]->v3 = VertexNumber - 1;
zm->polys[PolyNumber]->tex = -1;
PolyNumber++;
zm->polys[PolyNumber] = new Polygon;
zm->polys[PolyNumber]->v1 = VertexNumber;
zm->polys[PolyNumber]->v2 = VertexNumber - 3;
zm->polys[PolyNumber]->v3 = VertexNumber - 2;
zm->polys[PolyNumber]->tex = -1;
}
}
zm->vert_count = VertexNumber + 1;
zm->poly_count = PolyNumber + 1;
}
delete [] Floats;
delete [] Color1;
delete [] Color2;
delete [] Bytes;
this->status = 1;
return 1;
}
int DATLoader::Close() {
if(!status)
return 1;
Zone_Model *zm = this->model_data.zone_model;
int i;
for(i = 0; i < zm->vert_count; ++i)
delete zm->verts[i];
for(i = 0; i < zm->poly_count; ++i)
delete zm->polys[i];
delete[] zm->verts;
delete[] zm->polys;
delete this->model_data.zone_model;
status = 0;
return 1;
}