#include #include #include #include #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::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; }