/* * Copyright (C) 2008-2013 TrinityCore * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "Utils.h" #include "WorldModelHandler.h" #include "Constants.h" #include "Stream.h" #include #include "G3D/Matrix4.h" #include "G3D/Quat.h" #ifdef _WIN32 #include "direct.h" #else #include #include #endif const float Constants::TileSize = 533.0f + (1/3.0f); const float Constants::MaxXY = 32.0f * Constants::TileSize; const float Constants::ChunkSize = Constants::TileSize / 16.0f; const float Constants::UnitSize = Constants::ChunkSize / 8.0f; const float Constants::Origin[] = { -Constants::MaxXY, 0.0f, -Constants::MaxXY }; const float Constants::PI = 3.1415926f; const float Constants::MaxStandableHeight = 1.5f; const char* Constants::VMAPMagic = "VMAP041"; bool Constants::ToWoWCoords = false; bool Constants::Debug = false; const float Constants::BaseUnitDim = 0.533333f; const int Constants::VertexPerMap = (Constants::TileSize / Constants::BaseUnitDim) + 0.5f; const int Constants::VertexPerTile = 40; const int Constants::TilesPerMap = Constants::VertexPerMap / Constants::VertexPerTile; void Utils::CreateDir( const std::string& Path ) { #ifdef _WIN32 _mkdir( Path.c_str()); #else mkdir( Path.c_str(), 0777 ); #endif } void Utils::Reverse(std::string& str) { std::reverse(str.begin(), str.end()); } Vector3 Utils::ToRecast(const Vector3& val ) { return Vector3(-val.y, val.z, -val.x); } std::string Utils::GetAdtPath(const std::string& world, int x, int y ) { return "World\\Maps\\" + world + "\\" + world + "_" + Utils::ToString(x) + "_" + Utils::ToString(y) + ".adt"; } std::string Utils::FixModelPath(const std::string& path ) { return Utils::GetPathBase(path) + ".M2"; } Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3 vec, bool translate) { // Sources of information: /// http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18&oldid=3715 // This function applies to both external doodads and WMOs // Rotate our Doodad vertex G3D::Matrix4 rot = G3D::Matrix3::fromEulerAnglesXYZ(Utils::ToRadians(def.Rotation.z), Utils::ToRadians(-def.Rotation.x), Utils::ToRadians(def.Rotation.y + 180)); Vector3 ret = Utils::VectorTransform(vec, rot); // And finally scale and translate it to our origin ret = ret * def.Scale(); if (translate) ret = ret + Vector3(Constants::MaxXY - def.Position.z, Constants::MaxXY - def.Position.x, def.Position.y); return ret; } Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate ) { G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW); Vector3 ret = Utils::VectorTransform(vec, G3D::Matrix4(quat.toRotationMatrix())); ret = ret * (inst.Scale / 1024.0f); if (translate) ret = ret + Vector3(Constants::MaxXY - inst.Position.z, Constants::MaxXY - inst.Position.x, inst.Position.y); return ret; } float Utils::ToRadians( float degrees ) { return Constants::PI * degrees / 180.0f; } Vector3 Utils::VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal ) { G3D::Vector3 ret(vec.x, vec.y, vec.z); ret = matrix.homoMul(ret, normal ? 0 : 1); return Vector3(ret.x, ret.y, ret.z); } std::string Utils::GetPathBase(const std::string& path ) { size_t lastIndex = path.find_last_of("."); if (lastIndex != std::string::npos) return path.substr(0, lastIndex); return path; } Vector3 Vector3::Read(Stream* file) { return file->Read(); } Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate) { if (Utils::Distance(height, 0.0f) > 0.5f) basePosition.z = 0.0f; return Utils::TransformDoodadVertex(def, basePosition + Vector3(x * Constants::UnitSize, y * Constants::UnitSize, height), translate); } float Utils::Distance( float x, float y ) { return sqrt(x*x + y*y); } std::string Utils::Replace( std::string str, const std::string& oldStr, const std::string& newStr ) { size_t pos = 0; while((pos = str.find(oldStr, pos)) != std::string::npos) { str.replace(pos, oldStr.length(), newStr); pos += newStr.length(); } return str; } void Utils::SaveToDisk(Stream* stream, const std::string& path) { FILE* disk = fopen(path.c_str(), "wb"); if (!disk) { printf("SaveToDisk: Could not save file %s to disk, please verify that you have write permissions on that directory\n", path.c_str()); delete stream; return; } uint32 size = stream->GetSize(); stream->Reset(); // Reset the stream just in case // Read the data to an array char* data = stream->Read(size); // And write it in the file size_t wrote = fwrite(data, size, 1, disk); if (wrote != 1) { printf("SaveToDisk: Error writing to the file while trying to save %s to disk.\n", path.c_str()); delete[] data; delete stream; fclose(disk); return; } // Close the filestream fclose(disk); delete stream; // Free the used memory delete[] data; } Vector3 Utils::ToWoWCoords(const Vector3& vec ) { return Vector3(-vec.z, -vec.x, vec.y); } std::string Utils::GetExtension( std::string path ) { std::string::size_type idx = path.rfind('.'); std::string extension = ""; if(idx != std::string::npos) extension = path.substr(idx+1); return extension; } void MapChunkHeader::Read(Stream* stream) { Flags = stream->Read(); IndexX = stream->Read(); IndexY = stream->Read(); Layers = stream->Read(); DoodadRefs = stream->Read(); OffsetMCVT = stream->Read(); OffsetMCNR = stream->Read(); OffsetMCLY = stream->Read(); OffsetMCRF = stream->Read(); OffsetMCAL = stream->Read(); SizeMCAL = stream->Read(); OffsetMCSH = stream->Read(); SizeMCSH = stream->Read(); AreaId = stream->Read(); MapObjectRefs = stream->Read(); Holes = stream->Read(); LowQualityTextureMap = new uint32[4]; stream->Read(LowQualityTextureMap, sizeof(uint32) * 4); PredTex = stream->Read(); NumberEffectDoodad = stream->Read(); OffsetMCSE = stream->Read(); SoundEmitters = stream->Read(); OffsetMCLQ = stream->Read(); SizeMCLQ = stream->Read(); Position = Vector3::Read(stream); OffsetMCCV = stream->Read(); } void MHDR::Read(Stream* stream) { int count = 0; Flags = stream->Read(); OffsetMCIN = stream->Read(); OffsetMTEX = stream->Read(); OffsetMMDX = stream->Read(); OffsetMMID = stream->Read(); OffsetMWMO = stream->Read(); OffsetMWID = stream->Read(); OffsetMDDF = stream->Read(); OffsetMODF = stream->Read(); OffsetMFBO = stream->Read(); OffsetMH2O = stream->Read(); OffsetMTFX = stream->Read(); } void ModelHeader::Read(Stream* stream) { stream->Read(Magic, 4); Magic[4] = '\0'; // null-terminate it. Version = stream->Read(); LengthModelName = stream->Read(); OffsetName = stream->Read(); ModelFlags = stream->Read(); CountGlobalSequences = stream->Read(); OffsetGlobalSequences = stream->Read(); CountAnimations = stream->Read(); OffsetAnimations = stream->Read(); CountAnimationLookup = stream->Read(); OffsetAnimationLookup = stream->Read(); CountBones = stream->Read(); OffsetBones = stream->Read(); CountKeyBoneLookup = stream->Read(); OffsetKeyBoneLookup = stream->Read(); CountVertices = stream->Read(); OffsetVertices = stream->Read(); CountViews = stream->Read(); CountColors = stream->Read(); OffsetColors = stream->Read(); CountTextures = stream->Read(); OffsetTextures = stream->Read(); CountTransparency = stream->Read(); OffsetTransparency = stream->Read(); CountUvAnimation = stream->Read(); OffsetUvAnimation = stream->Read(); CountTexReplace = stream->Read(); OffsetTexReplace = stream->Read(); CountRenderFlags = stream->Read(); OffsetRenderFlags = stream->Read(); CountBoneLookup = stream->Read(); OffsetBoneLookup = stream->Read(); CountTexLookup = stream->Read(); OffsetTexLookup = stream->Read(); CountTexUnits = stream->Read(); OffsetTexUnits = stream->Read(); CountTransLookup = stream->Read(); OffsetTransLookup = stream->Read(); CountUvAnimLookup = stream->Read(); OffsetUvAnimLookup = stream->Read(); VertexBox[0] = Vector3::Read(stream); VertexBox[1] = Vector3::Read(stream); VertexRadius = stream->Read(); BoundingBox[0] = Vector3::Read(stream); BoundingBox[1] = Vector3::Read(stream); BoundingRadius = stream->Read(); CountBoundingTriangles = stream->Read(); OffsetBoundingTriangles = stream->Read(); CountBoundingVertices = stream->Read(); OffsetBoundingVertices = stream->Read(); CountBoundingNormals = stream->Read(); OffsetBoundingNormals = stream->Read(); } WorldModelHeader WorldModelHeader::Read(Stream* stream) { WorldModelHeader ret; int count = 0; ret.CountMaterials = stream->Read(); ret.CountGroups = stream->Read(); ret.CountPortals = stream->Read(); ret.CountLights = stream->Read(); ret.CountModels = stream->Read(); ret.CountDoodads = stream->Read(); ret.CountSets = stream->Read(); ret.AmbientColorUnk = stream->Read(); ret.WmoId = stream->Read(); ret.BoundingBox[0] = Vector3::Read(stream); ret.BoundingBox[1] = Vector3::Read(stream); ret.LiquidTypeRelated = stream->Read(); return ret; } DoodadInstance DoodadInstance::Read(Stream* stream) { DoodadInstance ret; ret.FileOffset = stream->Read(); ret.Position = Vector3::Read(stream); ret.QuatW = stream->Read(); ret.QuatX = stream->Read(); ret.QuatY = stream->Read(); ret.QuatZ = stream->Read(); ret.Scale = stream->Read(); ret.LightColor = stream->Read(); return ret; } DoodadSet DoodadSet::Read(Stream* stream) { DoodadSet ret; ret.Name = std::string(stream->Read(20), 20); ret.FirstInstanceIndex = stream->Read(); ret.CountInstances = stream->Read(); ret.UnknownZero = stream->Read(); return ret; } LiquidHeader LiquidHeader::Read(Stream* stream) { LiquidHeader ret; ret.CountXVertices = stream->Read(); ret.CountYVertices = stream->Read(); ret.Width = stream->Read(); ret.Height = stream->Read(); ret.BaseLocation = Vector3::Read(stream); ret.MaterialId = stream->Read(); return ret; } LiquidData LiquidData::Read(Stream* stream, LiquidHeader& header) { LiquidData ret; ret.HeightMap = new float*[header.CountXVertices]; for (uint32 i = 0; i < header.CountXVertices; ++i) ret.HeightMap[i] = new float[header.CountYVertices]; ret.RenderFlags = new uint8*[header.Width]; for (uint32 i = 0; i < header.Width; ++i) ret.RenderFlags[i] = new uint8[header.Height]; for (uint32 y = 0; y < header.CountYVertices; y++) { for (uint32 x = 0; x < header.CountXVertices; x++) { stream->Read(); // Dummy value ret.HeightMap[x][y] = stream->Read(); } } for (uint32 y = 0; y < header.Height; y++) for (uint32 x = 0; x < header.Width; x++) ret.RenderFlags[x][y] = stream->Read(); return ret; } H2ORenderMask H2ORenderMask::Read(Stream* stream) { H2ORenderMask ret; stream->Read(ret.Mask, sizeof(uint8) * 8); return ret; } bool MCNKLiquidData::IsWater(int x, int y, float height) { if (!Heights) return false; if (!Mask.ShouldRender(x, y)) return false; float diff = Heights[x][y] - height; if (diff > Constants::MaxStandableHeight) return true; return false; } H2OHeader H2OHeader::Read(Stream* stream) { H2OHeader ret; ret.OffsetInformation = stream->Read(); ret.LayerCount = stream->Read(); ret.OffsetRender = stream->Read(); return ret; } H2OInformation H2OInformation::Read(Stream* stream) { H2OInformation ret; ret.LiquidType = stream->Read(); ret.Flags = stream->Read(); ret.HeightLevel1 = stream->Read(); ret.HeightLevel2 = stream->Read(); ret.OffsetX = stream->Read(); ret.OffsetY = stream->Read(); ret.Width = stream->Read(); ret.Height = stream->Read(); ret.OffsetMask2 = stream->Read(); ret.OffsetHeightmap = stream->Read(); return ret; } char* Utils::GetPlainName(const char* FileName) { char* temp; if((temp = (char*)strrchr(FileName, '\\')) != NULL) FileName = temp + 1; return (char*)FileName; } WMOGroupHeader WMOGroupHeader::Read(Stream* stream) { WMOGroupHeader ret; ret.OffsetGroupName = stream->Read(); ret.OffsetDescriptiveName = stream->Read(); ret.Flags = stream->Read(); ret.BoundingBox[0] = Vector3::Read(stream); ret.BoundingBox[1] = Vector3::Read(stream); ret.OffsetPortals = stream->Read(); ret.CountPortals = stream->Read(); stream->Read(ret.CountBatches, sizeof(uint16) * 4); stream->Read(ret.Fogs, sizeof(uint8) * 4); ret.LiquidTypeRelated = stream->Read(); ret.WmoId = stream->Read(); return ret; } void Utils::InitializeMmapTileHeader(MmapTileHeader& header) { memset(&header, 0, sizeof(MmapTileHeader)); header.mmapMagic = MMAP_MAGIC; header.dtVersion = DT_NAVMESH_VERSION; header.mmapVersion = MMAP_VERSION; header.size = 0; header.usesLiquids = true; }