aboutsummaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorDDuarte <dnpd.dd@gmail.com>2014-01-10 18:32:05 +0000
committerDDuarte <dnpd.dd@gmail.com>2014-01-10 18:32:05 +0000
commit33c2bd5ce1f4f8d20981e9f7aea90e37de0abbda (patch)
tree823ad5570f27e923c77203660ee7cc12e26182ec /src/tools
parent352a2682b1d531c83bd2b80704233677448e99de (diff)
parenta63780fd90701ed81a0a5f2030e82ab1f6927ab4 (diff)
Merge branch 'master' into 4.3.4
Conflicts: src/server/game/Entities/Creature/Creature.cpp src/server/game/Entities/Creature/Creature.h src/server/game/Entities/Creature/GossipDef.cpp src/server/game/Entities/Player/Player.cpp src/server/game/Entities/Transport/Transport.cpp src/server/game/Entities/Unit/Unit.cpp src/server/game/Globals/ObjectMgr.cpp src/server/game/Globals/ObjectMgr.h src/server/game/Handlers/QuestHandler.cpp src/server/game/Handlers/SpellHandler.cpp src/server/game/Handlers/TradeHandler.cpp src/server/game/Quests/QuestDef.h src/server/game/Spells/Auras/SpellAuraEffects.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_halazzi.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_janalai.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp src/server/scripts/EasternKingdoms/zone_ghostlands.cpp src/server/scripts/EasternKingdoms/zone_hinterlands.cpp src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp src/server/scripts/EasternKingdoms/zone_swamp_of_sorrows.cpp src/server/scripts/Kalimdor/zone_azshara.cpp src/server/scripts/Kalimdor/zone_darkshore.cpp src/server/scripts/Kalimdor/zone_desolace.cpp src/server/scripts/Northrend/zone_dalaran.cpp src/tools/CMakeLists.txt
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/CMakeLists.txt3
-rw-r--r--src/tools/mesh_extractor/ADT.cpp7
-rw-r--r--src/tools/mesh_extractor/CMakeLists.txt2
-rw-r--r--src/tools/mesh_extractor/Cache.h20
-rw-r--r--src/tools/mesh_extractor/Chunk.cpp16
-rw-r--r--src/tools/mesh_extractor/Chunk.h8
-rw-r--r--src/tools/mesh_extractor/ChunkedData.cpp40
-rw-r--r--src/tools/mesh_extractor/ChunkedData.h7
-rw-r--r--src/tools/mesh_extractor/Constants.h2
-rw-r--r--src/tools/mesh_extractor/ContinentBuilder.cpp140
-rw-r--r--src/tools/mesh_extractor/ContinentBuilder.h65
-rw-r--r--src/tools/mesh_extractor/DBC.cpp43
-rw-r--r--src/tools/mesh_extractor/DBC.h14
-rw-r--r--src/tools/mesh_extractor/DoodadHandler.cpp44
-rw-r--r--src/tools/mesh_extractor/DoodadHandler.h21
-rw-r--r--src/tools/mesh_extractor/Geometry.cpp14
-rw-r--r--src/tools/mesh_extractor/Geometry.h2
-rw-r--r--src/tools/mesh_extractor/LiquidHandler.cpp75
-rw-r--r--src/tools/mesh_extractor/LiquidHandler.h4
-rw-r--r--src/tools/mesh_extractor/MPQ.cpp14
-rw-r--r--src/tools/mesh_extractor/MPQ.h17
-rw-r--r--src/tools/mesh_extractor/MPQManager.cpp95
-rw-r--r--src/tools/mesh_extractor/MPQManager.h13
-rw-r--r--src/tools/mesh_extractor/MapChunk.cpp18
-rw-r--r--src/tools/mesh_extractor/MapChunk.h2
-rw-r--r--src/tools/mesh_extractor/MeshExtractor.cpp96
-rw-r--r--src/tools/mesh_extractor/Model.cpp31
-rw-r--r--src/tools/mesh_extractor/Model.h3
-rw-r--r--src/tools/mesh_extractor/ObjectDataHandler.h1
-rw-r--r--src/tools/mesh_extractor/Stream.cpp47
-rw-r--r--src/tools/mesh_extractor/Stream.h59
-rw-r--r--src/tools/mesh_extractor/TileBuilder.cpp49
-rw-r--r--src/tools/mesh_extractor/TileBuilder.h6
-rw-r--r--src/tools/mesh_extractor/Utils.cpp496
-rw-r--r--src/tools/mesh_extractor/Utils.h81
-rw-r--r--src/tools/mesh_extractor/WDT.cpp21
-rw-r--r--src/tools/mesh_extractor/WDT.h4
-rw-r--r--src/tools/mesh_extractor/WorldModelGroup.cpp72
-rw-r--r--src/tools/mesh_extractor/WorldModelGroup.h4
-rw-r--r--src/tools/mesh_extractor/WorldModelHandler.cpp80
-rw-r--r--src/tools/mesh_extractor/WorldModelHandler.h6
-rw-r--r--src/tools/mesh_extractor/WorldModelRoot.cpp28
-rw-r--r--src/tools/mesh_extractor/WorldModelRoot.h2
43 files changed, 985 insertions, 787 deletions
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 09f23b844cf..db338711d08 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -11,7 +11,8 @@
add_subdirectory(map_extractor)
add_subdirectory(vmap4_assembler)
add_subdirectory(vmap4_extractor)
-add_subdirectory(mmaps_generator)
#if (WITH_MESHEXTRACTOR)
# add_subdirectory(mesh_extractor)
+#else()
+# add_subdirectory(mmaps_generator)
#endif()
diff --git a/src/tools/mesh_extractor/ADT.cpp b/src/tools/mesh_extractor/ADT.cpp
index a32276f9856..ee7e1b12b44 100644
--- a/src/tools/mesh_extractor/ADT.cpp
+++ b/src/tools/mesh_extractor/ADT.cpp
@@ -25,7 +25,7 @@ ADT::ADT( std::string file, int x, int y ) : ObjectData(NULL), Data(NULL), HasOb
{
Data = new ChunkedData(file);
ObjectData = new ChunkedData(file);
- if (ObjectData->Stream)
+ if (ObjectData->_Stream)
HasObjectData = true;
else
ObjectData = NULL;
@@ -33,6 +33,11 @@ ADT::ADT( std::string file, int x, int y ) : ObjectData(NULL), Data(NULL), HasOb
ADT::~ADT()
{
+ // Temporarily delete the underlying streams, they are guaranteed to be different
+ // @TODO: Remove this code once the ChunkedData destructor properly releases _Stream
+ delete ObjectData->_Stream;
+ delete Data->_Stream;
+
delete ObjectData;
delete Data;
diff --git a/src/tools/mesh_extractor/CMakeLists.txt b/src/tools/mesh_extractor/CMakeLists.txt
index 9ed8472051d..f5dbb0fd7ff 100644
--- a/src/tools/mesh_extractor/CMakeLists.txt
+++ b/src/tools/mesh_extractor/CMakeLists.txt
@@ -47,4 +47,4 @@ if( UNIX )
install(TARGETS MeshExtractor DESTINATION bin)
elseif( WIN32 )
install(TARGETS MeshExtractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
-endif()
+endif() \ No newline at end of file
diff --git a/src/tools/mesh_extractor/Cache.h b/src/tools/mesh_extractor/Cache.h
index 017b4c53f72..75496b5364d 100644
--- a/src/tools/mesh_extractor/Cache.h
+++ b/src/tools/mesh_extractor/Cache.h
@@ -31,24 +31,18 @@ class GenericCache
public:
GenericCache() {}
- static const uint32 FlushLimit = 300; // We can't get too close to filling up all the memory, and we have to be wary of the maximum number of open streams.
-
- void Insert(K key, T* val)
- {
- ACE_GUARD(ACE_Thread_Mutex, g, mutex);
-
- if (_items.size() > FlushLimit)
- Clear();
- _items[key] = val;
- }
-
- T* Get(K key)
+ T const* Get(K key)
{
ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
typename std::map<K, T*>::iterator itr = _items.find(key);
if (itr != _items.end())
return itr->second;
- return NULL;
+ else
+ {
+ T* t = new T(key); // Create the object
+ _items[key] = t;
+ return t;
+ }
}
void Clear()
diff --git a/src/tools/mesh_extractor/Chunk.cpp b/src/tools/mesh_extractor/Chunk.cpp
index 42eb9e14881..bc6d9b66b96 100644
--- a/src/tools/mesh_extractor/Chunk.cpp
+++ b/src/tools/mesh_extractor/Chunk.cpp
@@ -25,24 +25,24 @@ int32 Chunk::FindSubChunkOffset(std::string name)
if (name.size() != 4)
return -1;
- FILE* stream = GetStream();
+ Stream* stream = GetStream();
uint32 matched = 0;
- while (uint32(ftell(stream)) < Utils::Size(stream))
+ while (stream->GetPos() < stream->GetSize())
{
- char b = 0;
- if (fread(&b, sizeof(char), 1, stream) != 1 || b != name[matched])
+ char b = stream->Read<char>();
+ if (b != name[matched])
matched = 0;
else
++matched;
if (matched == 4)
- return ftell(stream) - 4;
+ return stream->GetPos() - 4;
}
return -1;
}
-FILE* Chunk::GetStream()
+Stream* Chunk::GetStream()
{
- fseek(Stream, Offset, SEEK_SET);
- return Stream;
+ _Stream->Seek(Offset, SEEK_SET);
+ return _Stream;
}
diff --git a/src/tools/mesh_extractor/Chunk.h b/src/tools/mesh_extractor/Chunk.h
index 0641eb1dc3c..95d06efe206 100644
--- a/src/tools/mesh_extractor/Chunk.h
+++ b/src/tools/mesh_extractor/Chunk.h
@@ -19,19 +19,21 @@
#define CHUNK_H
#include "Define.h"
#include <string>
+#include "Stream.h"
+
class ChunkedData;
class Chunk
{
public:
- Chunk(const char* name, uint32 length, uint32 offset, FILE* stream) : Name(name), Length(length), Offset(offset), Stream(stream) {}
+ Chunk(const char* name, uint32 length, uint32 offset, Stream* stream) : Name(name), Length(length), Offset(offset), _Stream(stream) {}
int32 FindSubChunkOffset(std::string name);
- FILE* GetStream();
+ Stream* GetStream();
std::string Name;
uint32 Length;
uint32 Offset;
- FILE* Stream;
+ Stream* _Stream;
};
#endif \ No newline at end of file
diff --git a/src/tools/mesh_extractor/ChunkedData.cpp b/src/tools/mesh_extractor/ChunkedData.cpp
index 1330e4b47f9..b288b5712cd 100644
--- a/src/tools/mesh_extractor/ChunkedData.cpp
+++ b/src/tools/mesh_extractor/ChunkedData.cpp
@@ -21,18 +21,18 @@
#include <string>
-ChunkedData::ChunkedData( FILE* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) :
-Stream(stream)
+ChunkedData::ChunkedData(Stream* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) :
+_Stream(stream)
{
- if (!Stream)
+ if (!_Stream)
return;
Load(maxLength, chunksHint);
}
ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ )
{
- Stream = MPQHandler->GetFile(file);
- if (!Stream)
+ _Stream = MPQHandler->GetFile(file);
+ if (!_Stream)
return;
Load(0, chunksHint);
}
@@ -40,31 +40,30 @@ ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ )
void ChunkedData::Load( uint32 maxLength, uint32 chunksHint )
{
if (!maxLength)
- maxLength = Utils::Size(Stream);
+ maxLength = _Stream->GetSize();
Chunks.reserve(chunksHint);
- uint32 baseOffset = ftell(Stream);
+ uint32 baseOffset = _Stream->GetPos();
uint32 calcOffset = 0;
- while ((calcOffset + baseOffset) < Utils::Size(Stream) && (calcOffset < maxLength))
+ while ((calcOffset + baseOffset) < _Stream->GetSize() && (calcOffset < maxLength))
{
char nameBytes[5];
- uint32 read = fread(&nameBytes, sizeof(char), 4, Stream);
- nameBytes[read] = '\0';
+ _Stream->Read(nameBytes, sizeof(char) * 4);
+ nameBytes[4] = '\0';
std::string name = std::string(nameBytes);
- // Utils::Reverse(nameBytes);
name = std::string(name.rbegin(), name.rend());
- uint32 length;
- if (fread(&length, sizeof(uint32), 1, Stream) != 1)
- continue;
+
+ uint32 length = _Stream->Read<uint32>();
calcOffset += 8;
- Chunks.push_back(new Chunk(name.c_str(), length, calcOffset + baseOffset, Stream));
+
+ Chunks.push_back(new Chunk(name.c_str(), length, calcOffset + baseOffset, _Stream));
calcOffset += length;
// save an extra seek at the end
- if ((calcOffset + baseOffset) < Utils::Size(Stream) && calcOffset < maxLength)
- fseek(Stream, length, SEEK_CUR);
+ if ((calcOffset + baseOffset) < _Stream->GetSize() && calcOffset < maxLength)
+ _Stream->Seek(length, SEEK_CUR);
}
}
-int ChunkedData::GetFirstIndex( const std::string& name )
+int ChunkedData::GetFirstIndex( const std::string& name ) const
{
for (uint32 i = 0; i < Chunks.size(); ++i)
if (Chunks[i]->Name == name)
@@ -86,6 +85,7 @@ ChunkedData::~ChunkedData()
delete *itr;
Chunks.clear();
- if (Stream)
- fclose(Stream);
+ /* WorldModelGroup Data and SubData share the same _Stream so it's deleted twice and it crashes
+ if (_Stream)
+ delete _Stream;*/
}
diff --git a/src/tools/mesh_extractor/ChunkedData.h b/src/tools/mesh_extractor/ChunkedData.h
index 5befdf30dd1..112bdb47199 100644
--- a/src/tools/mesh_extractor/ChunkedData.h
+++ b/src/tools/mesh_extractor/ChunkedData.h
@@ -20,19 +20,20 @@
#include <vector>
#include "Chunk.h"
+#include "Stream.h"
class ChunkedData
{
public:
- ChunkedData(FILE* stream, uint32 maxLength, uint32 chunksHint = 300);
+ ChunkedData(Stream* stream, uint32 maxLength, uint32 chunksHint = 300);
ChunkedData(const std::string &file, uint32 chunksHint = 300);
~ChunkedData();
- int GetFirstIndex(const std::string& name);
+ int GetFirstIndex(const std::string& name) const;
Chunk* GetChunkByName(const std::string& name);
void Load(uint32 maxLength, uint32 chunksHint);
std::vector<Chunk*> Chunks;
- FILE* Stream;
+ Stream* _Stream;
};
#endif \ No newline at end of file
diff --git a/src/tools/mesh_extractor/Constants.h b/src/tools/mesh_extractor/Constants.h
index 5a89be9fe9c..7d9d6f92b92 100644
--- a/src/tools/mesh_extractor/Constants.h
+++ b/src/tools/mesh_extractor/Constants.h
@@ -26,6 +26,8 @@ public:
TRIANGLE_TYPE_UNKNOWN,
TRIANGLE_TYPE_TERRAIN,
TRIANGLE_TYPE_WATER,
+ TRIANGLE_TYPE_MAGMA,
+ TRIANGLE_TYPE_SLIME,
TRIANGLE_TYPE_DOODAD,
TRIANGLE_TYPE_WMO
};
diff --git a/src/tools/mesh_extractor/ContinentBuilder.cpp b/src/tools/mesh_extractor/ContinentBuilder.cpp
index 841d7a608e4..9e64e7a1b05 100644
--- a/src/tools/mesh_extractor/ContinentBuilder.cpp
+++ b/src/tools/mesh_extractor/ContinentBuilder.cpp
@@ -16,80 +16,21 @@
*/
#include "ContinentBuilder.h"
-#include "TileBuilder.h"
#include "WDT.h"
#include "Utils.h"
#include "DetourNavMesh.h"
#include "Cache.h"
-#include "ace/Task.h"
#include "Recast.h"
#include "DetourCommon.h"
-class BuilderThread : public ACE_Task_Base
-{
-private:
- int X, Y, MapId;
- std::string Continent;
- dtNavMeshParams Params;
- ContinentBuilder* cBuilder;
-public:
- BuilderThread(ContinentBuilder* _cBuilder, dtNavMeshParams& params) : Params(params), cBuilder(_cBuilder), Free(true) {}
-
- void SetData(int x, int y, int map, const std::string& cont)
- {
- X = x;
- Y = y;
- MapId = map;
- Continent = cont;
- }
-
- int svc()
- {
- Free = false;
- printf("[%02i,%02i] Building tile\n", X, Y);
- TileBuilder builder(cBuilder, Continent, X, Y, MapId);
- char buff[100];
- sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X);
- FILE* f = fopen(buff, "r");
- if (f) // Check if file already exists.
- {
- printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y);
- fclose(f);
- Free = true;
- return 0;
- }
- uint8* nav = builder.BuildTiled(Params);
- if (nav)
- {
- f = fopen(buff, "wb");
- if (!f)
- {
- printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
- return 0;
- }
- MmapTileHeader header;
- header.size = builder.DataSize;
- fwrite(&header, sizeof(MmapTileHeader), 1, f);
- fwrite(nav, sizeof(unsigned char), builder.DataSize, f);
- fclose(f);
- }
- dtFree(nav);
- printf("[%02i,%02i] Tile Built!\n", X, Y);
- Free = true;
- return 0;
- }
-
- bool Free;
-};
-
-void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
+void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const
{
// this is for elevation
if (verts && vertCount)
rcCalcBounds(verts, vertCount, bmin, bmax);
else
{
- bmin[1] = FLT_MIN;
+ bmin[1] = -FLT_MAX;
bmax[1] = FLT_MAX;
}
@@ -128,8 +69,6 @@ void ContinentBuilder::Build()
dtNavMeshParams params;
- std::vector<BuilderThread*> Threads;
-
if (TileMap->IsGlobalModel)
{
printf("Map %s ( %u ) is a WMO. Building with 1 thread.\n", Continent.c_str(), MapId);
@@ -159,6 +98,7 @@ void ContinentBuilder::Build()
}
MmapTileHeader mheader;
+ Utils::InitializeMmapTileHeader(mheader);
mheader.size = builder->DataSize;
fwrite(&mheader, sizeof(MmapTileHeader), 1, f);
fwrite(nav, sizeof(unsigned char), builder->DataSize, f);
@@ -170,44 +110,70 @@ void ContinentBuilder::Build()
}
else
{
- params.maxPolys = 32768;
- params.maxTiles = 4096;
+ params.maxPolys = 1024;
+ params.maxTiles = TileMap->TileTable.size();
rcVcopy(params.orig, Constants::Origin);
params.tileHeight = Constants::TileSize;
params.tileWidth = Constants::TileSize;
fwrite(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
- for (uint32 i = 0; i < NumberOfThreads; ++i)
- Threads.push_back(new BuilderThread(this, params));
+ std::vector<BuilderThread*> _threads;
+ BuilderThreadPool* pool = NumberOfThreads > 0 ? new BuilderThreadPool() : NULL;
+
printf("Map %s ( %u ) has %u tiles. Building them with %u threads\n", Continent.c_str(), MapId, uint32(TileMap->TileTable.size()), NumberOfThreads);
+
for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr)
+ pool->Enqueue(new TileBuildRequest(this, Continent, itr->X, itr->Y, MapId, params));
+
+ for (uint32 i = 0; i < NumberOfThreads; ++i)
+ _threads.push_back(new BuilderThread(this, pool->Queue()));
+
+ // Free memory
+ for (std::vector<BuilderThread*>::iterator _th = _threads.begin(); _th != _threads.end(); ++_th)
{
- bool next = false;
- while (!next)
- {
- for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
- {
- if ((*_th)->Free)
- {
- (*_th)->SetData(itr->X, itr->Y, MapId, Continent);
- (*_th)->activate();
- next = true;
- break;
- }
- }
- // Wait for 20 seconds
- ACE_OS::sleep(ACE_Time_Value (0, 20000));
- }
+ (*_th)->wait();
+ delete *_th;
}
+
+ delete pool;
}
Cache->Clear();
+}
- // Free memory
- for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
+int TileBuildRequest::call()
+{
+ printf("[%02i,%02i] Building tile\n", X, Y);
+ // Build the tile and return negative on error
+ TileBuilder tile(_builder, _continent, X, Y, _mapId);
+ char buff[100];
+ sprintf(buff, "mmaps/%03u%02i%02i.mmtile", _mapId, Y, X);
+ FILE* f = fopen(buff, "r");
+ if (f) // Check if file already exists.
{
- (*_th)->wait();
- delete *_th;
+ printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y);
+ fclose(f);
+ return 0;
+ }
+ uint8* nav = tile.BuildTiled(_params);
+ if (nav)
+ {
+ f = fopen(buff, "wb");
+ if (!f)
+ {
+ printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
+ dtFree(nav);
+ return -1;
+ }
+ MmapTileHeader header;
+ Utils::InitializeMmapTileHeader(header);
+ header.size = tile.DataSize;
+ fwrite(&header, sizeof(MmapTileHeader), 1, f);
+ fwrite(nav, sizeof(unsigned char), tile.DataSize, f);
+ fclose(f);
}
+ dtFree(nav);
+ printf("[%02i,%02i] Tile Built!\n", X, Y);
+ return 0;
}
diff --git a/src/tools/mesh_extractor/ContinentBuilder.h b/src/tools/mesh_extractor/ContinentBuilder.h
index 5349b8e1ba5..249fad05eb1 100644
--- a/src/tools/mesh_extractor/ContinentBuilder.h
+++ b/src/tools/mesh_extractor/ContinentBuilder.h
@@ -17,9 +17,15 @@
#ifndef CONT_BUILDER_H
#define CONT_BUILDER_H
+
#include <string>
#include "WDT.h"
#include "Define.h"
+#include "TileBuilder.h"
+
+#include <ace/Task.h>
+#include <ace/Activation_Queue.h>
+#include <ace/Method_Request.h>
class ContinentBuilder
{
@@ -30,7 +36,7 @@ public:
{}
void Build();
- void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax);
+ void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const;
void CalculateTileBounds();
float bmin[3];
float bmax[3];
@@ -44,4 +50,61 @@ private:
int tileXMax;
int tileYMax;
};
+
+class TileBuildRequest : public ACE_Method_Request
+{
+public:
+ TileBuildRequest(ContinentBuilder* builder, std::string& continent, uint32 x, uint32 y, uint32 mapId, dtNavMeshParams& params) : _mapId(mapId), _builder(builder), _continent(continent), X(x), Y(y), _params(params) { }
+
+ virtual int call();
+
+private:
+ uint32 _mapId;
+ ContinentBuilder* _builder;
+ std::string& _continent;
+ uint32 X;
+ uint32 Y;
+ dtNavMeshParams& _params;
+};
+
+class BuilderThreadPool
+{
+public:
+ BuilderThreadPool() : _queue(new ACE_Activation_Queue()) {}
+ ~BuilderThreadPool() { _queue->queue()->close(); delete _queue; }
+
+ void Enqueue(TileBuildRequest* request)
+ {
+ _queue->enqueue(request);
+ }
+
+ ACE_Activation_Queue* Queue() { return _queue; }
+
+private:
+ ACE_Activation_Queue* _queue;
+};
+
+class BuilderThread : public ACE_Task_Base
+{
+private:
+ ContinentBuilder* _builder;
+ ACE_Activation_Queue* _queue;
+public:
+ BuilderThread(ContinentBuilder* builder, ACE_Activation_Queue* queue) : _builder(builder), _queue(queue) { activate(); }
+
+ int svc()
+ {
+ /// @ Set a timeout for dequeue attempts (only used when the queue is empty) as it will never get populated after thread starts
+ ACE_Time_Value timeout(5);
+ ACE_Method_Request* request = NULL;
+ while ((request = _queue->dequeue(&timeout)) != NULL)
+ {
+ request->call();
+ delete request;
+ request = NULL;
+ }
+ return 0;
+ }
+};
+
#endif
diff --git a/src/tools/mesh_extractor/DBC.cpp b/src/tools/mesh_extractor/DBC.cpp
index 9249e320563..5bebc34a389 100644
--- a/src/tools/mesh_extractor/DBC.cpp
+++ b/src/tools/mesh_extractor/DBC.cpp
@@ -19,19 +19,15 @@
#include "DBC.h"
#include "Define.h"
-DBC::DBC( FILE* stream ) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true)
+DBC::DBC(Stream* stream) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true)
{
- char magic[5];
- uint32 count = 0;
- count += fread(&magic, sizeof(char), 4, stream);
- magic[4] = '\0';
- count += fread(&RecordCount, sizeof(uint32), 1, stream);
+ delete[] stream->Read(4); // Read the magic "WDBC"
+
+ RecordCount = stream->Read<int>();
Records.reserve(RecordCount);
- count += fread(&Fields, sizeof(uint32), 1, stream);
- count += fread(&RecordSize, sizeof(uint32), 1, stream);
- count += fread(&StringBlockSize, sizeof(uint32), 1, stream);
- if (count != 8)
- printf("DBC::DBC: Failed to read some data expected 8, read %u\n", count);
+ Fields = stream->Read<int>();
+ RecordSize = stream->Read<int>();
+ StringBlockSize = stream->Read<uint32>();
for (int i = 0; i < RecordCount; i++)
{
@@ -45,20 +41,21 @@ DBC::DBC( FILE* stream ) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true)
IsFaulty = true;
break;
}
- uint32 tmp;
- if (fread(&tmp, sizeof(uint32), 1, stream) != 1)
- printf("DBC::DBC: Failed to read some data expected 1, read 0\n");
- rec->Values.push_back(tmp);
+ rec->Values.push_back(stream->Read<uint32>());
size += 4;
}
}
- StringBlock = new uint8[StringBlockSize];
- count = fread(StringBlock, sizeof(uint8), StringBlockSize, stream);
- if (count != StringBlockSize)
- printf("DBC::DBC: Failed to read some data expected %u, read %u\n", StringBlockSize, count);
+ StringBlock = (uint8*)stream->Read(StringBlockSize);
+}
+
+DBC::~DBC()
+{
+ delete[] StringBlock;
+ for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr)
+ delete *itr;
}
-std::string DBC::GetStringByOffset( int offset )
+std::string DBC::GetStringByOffset( int offset ) const
{
int len = 0;
for (uint32 i = offset; i < StringBlockSize; i++)
@@ -73,14 +70,14 @@ std::string DBC::GetStringByOffset( int offset )
strcpy(d, (const char*)(StringBlock + offset));
d[len] = '\0';
std::string val = std::string(d);
- delete [] d;
+ delete[] d;
return val;
}
-Record* DBC::GetRecordById( int id )
+Record const* DBC::GetRecordById( int id ) const
{
// we assume Id is index 0
- for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr)
+ for (std::vector<Record*>::const_iterator itr = Records.begin(); itr != Records.end(); ++itr)
if ((*itr)->Values[0] == id)
return *itr;
return NULL;
diff --git a/src/tools/mesh_extractor/DBC.h b/src/tools/mesh_extractor/DBC.h
index 0d3b85d8c78..33f5437ebe2 100644
--- a/src/tools/mesh_extractor/DBC.h
+++ b/src/tools/mesh_extractor/DBC.h
@@ -20,17 +20,19 @@
#include <vector>
#include <string>
#include "Define.h"
+#include "Stream.h"
class Record;
class DBC
{
public:
- DBC(FILE* stream);
+ DBC(Stream* stream);
+ ~DBC();
- std::string GetStringByOffset(int offset);
+ std::string GetStringByOffset(int offset) const;
- Record* GetRecordById(int id);
+ Record const* GetRecordById(int id) const;
std::string Name;
std::vector<Record*> Records;
@@ -50,18 +52,18 @@ public:
DBC* Source;
std::vector<int> Values;
- int operator[](int index)
+ int operator[](int index) const
{
return Values[index];
}
template <typename T>
- T GetValue(int index)
+ T GetValue(int index) const
{
return *(T*)(&Values[index]);
}
- std::string GetString(int index)
+ const std::string GetString(int index) const
{
return Source->GetStringByOffset(Values[index]);
}
diff --git a/src/tools/mesh_extractor/DoodadHandler.cpp b/src/tools/mesh_extractor/DoodadHandler.cpp
index 2e0743134d4..5363855740e 100644
--- a/src/tools/mesh_extractor/DoodadHandler.cpp
+++ b/src/tools/mesh_extractor/DoodadHandler.cpp
@@ -34,20 +34,18 @@ DoodadHandler::DoodadHandler( ADT* adt ) :
ReadDoodadPaths(mmid, mmdx);
}
-void DoodadHandler::ProcessInternal( MapChunk* mcnk )
+void DoodadHandler::ProcessInternal(MapChunk* mcnk)
{
if (!IsSane())
return;
uint32 refCount = mcnk->Header.DoodadRefs;
- FILE* stream = mcnk->Source->GetStream();
- fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
+ Stream* stream = mcnk->Source->GetStream();
+ stream->Seek(mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
+
for (uint32 i = 0; i < refCount; i++)
{
- int32 index;
- int32 count;
- if ((count = fread(&index, sizeof(int32), 1, stream)) != 1)
- printf("DoodadHandler::ProcessInternal: Failed to read some data expected 1, read %d\n", count);
+ int32 index = stream->Read<int32>();
if (index < 0 || uint32(index) >= _definitions->size())
continue;
DoodadDefinition doodad = (*_definitions)[index];
@@ -58,12 +56,7 @@ void DoodadHandler::ProcessInternal( MapChunk* mcnk )
continue;
std::string path = (*_paths)[doodad.MmidIndex];
- Model* model = Cache->ModelCache.Get(path);
- if (!model)
- {
- model = new Model(path);
- Cache->ModelCache.Insert(path, model);
- }
+ Model const* model = Cache->ModelCache.Get(path);
if (!model->IsCollidable)
continue;
@@ -73,7 +66,7 @@ void DoodadHandler::ProcessInternal( MapChunk* mcnk )
InsertModelGeometry(doodad, model);
}
// Restore the stream position
- fseek(stream, mcnk->Source->Offset, SEEK_SET);
+ stream->Seek(mcnk->Source->Offset, SEEK_SET);
}
void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk )
@@ -81,7 +74,7 @@ void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk )
int32 count = chunk->Length / 36;
_definitions = new std::vector<DoodadDefinition>;
_definitions->reserve(count);
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
for (int i = 0; i < count; i++)
{
DoodadDefinition def;
@@ -97,25 +90,24 @@ void DoodadHandler::ReadDoodadPaths( Chunk* id, Chunk* data )
_paths->reserve(paths);
for (int i = 0; i < paths; i++)
{
- FILE* idStream = id->GetStream();
- fseek(idStream, i * 4, SEEK_CUR);
- uint32 offset;
- if (fread(&offset, sizeof(uint32), 1, idStream) != 1)
- printf("DoodadHandler::ReadDoodadPaths: Failed to read some data expected 1, read 0\n");
- FILE* dataStream = data->GetStream();
- fseek(dataStream, offset + data->Offset, SEEK_SET);
- _paths->push_back(Utils::ReadString(dataStream));
+ Stream* idStream = id->GetStream();
+ idStream->Seek(i * 4, SEEK_CUR);
+ uint32 offset = idStream->Read<uint32>();
+
+ Stream* dataStream = data->GetStream();
+ dataStream->Seek(offset + data->Offset, SEEK_SET);
+ _paths->push_back(dataStream->ReadString());
}
}
-void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model* model)
+void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model const* model)
{
uint32 vertOffset = Vertices.size();
- for (std::vector<Vector3>::iterator itr = model->Vertices.begin(); itr != model->Vertices.end(); ++itr)
+ for (std::vector<Vector3>::const_iterator itr = model->Vertices.begin(); itr != model->Vertices.end(); ++itr)
Vertices.push_back(Utils::TransformDoodadVertex(def, *itr)); // Vertices have to be converted based on the information from the DoodadDefinition struct
- for (std::vector<Triangle<uint16> >::iterator itr = model->Triangles.begin(); itr != model->Triangles.end(); ++itr)
+ for (std::vector<Triangle<uint16> >::const_iterator itr = model->Triangles.begin(); itr != model->Triangles.end(); ++itr)
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_DOODAD, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
}
diff --git a/src/tools/mesh_extractor/DoodadHandler.h b/src/tools/mesh_extractor/DoodadHandler.h
index c3a8d645016..d7d3e0917b5 100644
--- a/src/tools/mesh_extractor/DoodadHandler.h
+++ b/src/tools/mesh_extractor/DoodadHandler.h
@@ -21,6 +21,7 @@
#include "Utils.h"
#include "Chunk.h"
#include "Model.h"
+#include "Stream.h"
#include <set>
#include <vector>
@@ -39,18 +40,14 @@ public:
return Vector3(vec.z, vec.x, vec.y);
}
- void Read(FILE* stream)
+ void Read(Stream* stream)
{
- int count = 0;
-
- count += fread(&MmidIndex, sizeof(uint32), 1, stream);
- count += fread(&UniqueId, sizeof(uint32), 1, stream);
- Position = (Vector3::Read(stream));
+ MmidIndex = stream->Read<uint32>();
+ UniqueId = stream->Read<uint32>();
+ Position = Vector3::Read(stream);
Rotation = Vector3::Read(stream);
- count += fread(&DecimalScale, sizeof(uint16), 1, stream);
- count += fread(&Flags, sizeof(uint16), 1, stream);
- if (count != 4)
- printf("DoodadDefinition::Read: Failed to read some data expected 4, read %d\n", count);
+ DecimalScale = stream->Read<uint16>();
+ Flags = stream->Read<uint16>();
}
};
@@ -62,7 +59,7 @@ public:
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32> > Triangles;
- bool IsSane() { return _definitions && _paths; }
+ bool IsSane() const { return _definitions && _paths; }
protected:
@@ -71,7 +68,7 @@ protected:
private:
void ReadDoodadDefinitions(Chunk* chunk);
void ReadDoodadPaths(Chunk* id, Chunk* data);
- void InsertModelGeometry(const DoodadDefinition& def, Model* model);
+ void InsertModelGeometry(const DoodadDefinition& def, Model const* model);
std::set<uint32> _drawn;
std::vector<DoodadDefinition>* _definitions;
std::vector<std::string>* _paths;
diff --git a/src/tools/mesh_extractor/Geometry.cpp b/src/tools/mesh_extractor/Geometry.cpp
index 0c7b7a492c5..2ae05c0b736 100644
--- a/src/tools/mesh_extractor/Geometry.cpp
+++ b/src/tools/mesh_extractor/Geometry.cpp
@@ -20,6 +20,7 @@
#include "ADT.h"
#include "WorldModelHandler.h"
#include "DoodadHandler.h"
+#include "LiquidHandler.h"
#include <limits.h>
Geometry::Geometry() : Transform(false)
@@ -34,7 +35,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max )
max = new float[3];
for (int i = 0; i < 3; ++i)
{
- max[i] = std::numeric_limits<float>::lowest();
+ max[i] = -FLT_MAX;
min[i] = std::numeric_limits<float>::max();
}
@@ -60,7 +61,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max )
void Geometry::CalculateMinMaxHeight( float& min, float& max )
{
min = std::numeric_limits<float>::max();
- max = std::numeric_limits<float>::lowest();
+ max = -FLT_MAX;
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
{
@@ -91,12 +92,12 @@ void Geometry::AddData( std::vector<Vector3>& verts, std::vector<Triangle<uint32
Triangles.push_back(Triangle<uint32>(itr->Type, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
}
-void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas )
+void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas ) const
{
verts = new float[Vertices.size() * 3];
for (uint32 i = 0; i < Vertices.size(); ++i)
{
- Vector3& vert = Vertices[i];
+ const Vector3& vert = Vertices[i];
verts[(i * 3) + 0] = vert.x;
verts[(i * 3) + 1] = vert.y;
verts[(i * 3) + 2] = vert.z;
@@ -105,7 +106,7 @@ void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas )
tris = new int[Triangles.size() * 3];
for (uint32 i = 0; i < Triangles.size(); ++i)
{
- Triangle<uint32>& tri = Triangles[i];
+ const Triangle<uint32>& tri = Triangles[i];
tris[(i * 3) + 0] = (int)tri.V0;
tris[(i * 3) + 1] = (int)tri.V1;
tris[(i * 3) + 2] = (int)tri.V2;
@@ -142,5 +143,8 @@ void Geometry::AddAdt( ADT* adt )
if (!adt->_WorldModelHandler->Triangles.empty())
AddData(adt->_WorldModelHandler->Vertices, adt->_WorldModelHandler->Triangles);
+
+ if (!adt->_LiquidHandler->Triangles.empty())
+ AddData(adt->_LiquidHandler->Vertices, adt->_LiquidHandler->Triangles);
}
diff --git a/src/tools/mesh_extractor/Geometry.h b/src/tools/mesh_extractor/Geometry.h
index f2ea43e381e..cd71ac5a828 100644
--- a/src/tools/mesh_extractor/Geometry.h
+++ b/src/tools/mesh_extractor/Geometry.h
@@ -31,7 +31,7 @@ public:
void CalculateMinMaxHeight(float& min, float& max);
void AddData(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris);
void AddAdt(ADT* adt);
- void GetRawData(float*& verts, int*& tris, uint8*& areas);
+ void GetRawData(float*& verts, int*& tris, uint8*& areas) const;
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32> > Triangles;
diff --git a/src/tools/mesh_extractor/LiquidHandler.cpp b/src/tools/mesh_extractor/LiquidHandler.cpp
index eef36d8ea92..1b6f5ce944e 100644
--- a/src/tools/mesh_extractor/LiquidHandler.cpp
+++ b/src/tools/mesh_extractor/LiquidHandler.cpp
@@ -17,10 +17,20 @@
#include "LiquidHandler.h"
#include "Utils.h"
+#include "DBC.h"
+#include "MPQManager.h"
LiquidHandler::LiquidHandler( ADT* adt ) : Source(adt)
{
HandleNewLiquid();
+ HandleOldLiquid();
+}
+
+LiquidHandler::~LiquidHandler()
+{
+ for (std::vector<MCNKLiquidData*>::iterator itr = MCNKData.begin(); itr != MCNKData.end(); ++itr)
+ delete *itr;
+ MCNKData.clear();
}
void LiquidHandler::HandleNewLiquid()
@@ -32,7 +42,7 @@ void LiquidHandler::HandleNewLiquid()
Vertices.reserve(1000);
Triangles.reserve(1000);
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
H2OHeader header[256];
MCNKData.reserve(256);
for (int i = 0; i < 256; i++)
@@ -44,40 +54,44 @@ void LiquidHandler::HandleNewLiquid()
if (h.LayerCount == 0)
{
// Need to fill in missing data with dummies.
- MCNKData.push_back(MCNKLiquidData(NULL, H2ORenderMask()));
+ MCNKData.push_back(new MCNKLiquidData(NULL, H2ORenderMask()));
continue;
}
- fseek(stream, chunk->Offset + h.OffsetInformation, SEEK_SET);
+ stream->Seek(chunk->Offset + h.OffsetInformation, SEEK_SET);
H2OInformation information = H2OInformation::Read(stream);
+ // Load the LiquidTypes DBC
+ DBC const* liquidTypes = MPQHandler->GetDBC("LiquidTypes");
+ Record const* liquid = liquidTypes->GetRecordById(information.LiquidType);
+ ASSERT(liquid);
+
+ // This pointer will be passed to the MCNKLiquidData constructor, from that point on, it is the job of MCNKLiquidData's destructor to release it.
float** heights = new float*[9];
for (int j = 0; j < 9; ++j)
{
heights[j] = new float[9];
memset(heights[j], 0, sizeof(float) * 9);
}
-
+
H2ORenderMask renderMask;
- if (information.LiquidType != 2)
+ if (liquid->GetValue<uint32>(3) != 1) // Read the liquid type and skip Ocean, Slow Ocean and Fast Ocean
{
- fseek(stream, chunk->Offset + h.OffsetRender, SEEK_SET);
+ stream->Seek(chunk->Offset + h.OffsetRender, SEEK_SET);
renderMask = H2ORenderMask::Read(stream);
if ((Utils::IsAllZero(renderMask.Mask, 8) || (information.Width == 8 && information.Height == 8)) && information.OffsetMask2)
{
- fseek(stream, chunk->Offset + information.OffsetMask2, SEEK_SET);
+ stream->Seek(chunk->Offset + information.OffsetMask2, SEEK_SET);
uint32 size = ceil(information.Width * information.Height / 8.0f);
- uint8* altMask = new uint8[size];
- if (fread(altMask, sizeof(uint8), size, stream) == size)
- for (uint32 mi = 0; mi < size; mi++)
- renderMask.Mask[mi + information.OffsetY] |= altMask[mi];
+ uint8* altMask = (uint8*)stream->Read(size);
+ for (uint32 mi = 0; mi < size; mi++)
+ renderMask.Mask[mi + information.OffsetY] |= altMask[mi];
delete[] altMask;
}
- fseek(stream, chunk->Offset + information.OffsetHeightmap, SEEK_SET);
+ stream->Seek(chunk->Offset + information.OffsetHeightmap, SEEK_SET);
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++)
- if (fread(&heights[x][y], sizeof(float), 1, stream) != 1)
- return;
+ heights[x][y] = stream->Read<float>();
}
else
{
@@ -90,7 +104,7 @@ void LiquidHandler::HandleNewLiquid()
heights[x][y] = information.HeightLevel1;
}
- MCNKData.push_back(MCNKLiquidData(heights, renderMask));
+ MCNKData.push_back(new MCNKLiquidData(heights, renderMask));
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
{
@@ -110,10 +124,37 @@ void LiquidHandler::HandleNewLiquid()
Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y, location.z));
Vertices.push_back(Vector3(location.x, location.y - Constants::UnitSize, location.z));
Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y - Constants::UnitSize, location.z));
+
+ // Define the liquid type
+ Constants::TriangleType type = Constants::TRIANGLE_TYPE_UNKNOWN;
+ switch (liquid->GetValue<uint32>(3))
+ {
+ case 0: // Water
+ case 1: // Ocean
+ type = Constants::TRIANGLE_TYPE_WATER;
+ break;
+ case 2: // Magma
+ type = Constants::TRIANGLE_TYPE_MAGMA;
+ break;
+ case 3: // Slime
+ type = Constants::TRIANGLE_TYPE_SLIME;
+ break;
+ }
- Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset+2, vertOffset + 1));
- Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1));
+ Triangles.push_back(Triangle<uint32>(type, vertOffset, vertOffset+2, vertOffset + 1));
+ Triangles.push_back(Triangle<uint32>(type, vertOffset + 2, vertOffset + 3, vertOffset + 1));
}
}
}
}
+
+void LiquidHandler::HandleOldLiquid()
+{
+ for (uint32 i = 0; i < 256; ++i)
+ {
+ MapChunk* mapChunk = Source->MapChunks[i];
+ if (!mapChunk->Header.OffsetMCLQ || mapChunk->Header.SizeMCLQ <= 8)
+ continue;
+ printf("Found old liquid");
+ }
+}
diff --git a/src/tools/mesh_extractor/LiquidHandler.h b/src/tools/mesh_extractor/LiquidHandler.h
index c053b621088..d7f493e2719 100644
--- a/src/tools/mesh_extractor/LiquidHandler.h
+++ b/src/tools/mesh_extractor/LiquidHandler.h
@@ -27,12 +27,14 @@ class LiquidHandler
{
public:
LiquidHandler(ADT* adt);
+ ~LiquidHandler();
ADT* Source;
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32> > Triangles;
- std::vector<MCNKLiquidData> MCNKData;
+ std::vector<MCNKLiquidData*> MCNKData;
private:
void HandleNewLiquid();
+ void HandleOldLiquid();
};
#endif \ No newline at end of file
diff --git a/src/tools/mesh_extractor/MPQ.cpp b/src/tools/mesh_extractor/MPQ.cpp
index 5a2957cac0b..4a86ab0b4de 100644
--- a/src/tools/mesh_extractor/MPQ.cpp
+++ b/src/tools/mesh_extractor/MPQ.cpp
@@ -17,6 +17,7 @@
#include "MPQ.h"
#include "MPQManager.h"
+#include "Stream.h"
#include <deque>
#include <cstdio>
@@ -125,15 +126,8 @@ void MPQFile::close()
eof = true;
}
-FILE* MPQFile::GetFileStream()
+Stream* MPQFile::GetFileStream()
{
- FILE* file = tmpfile();
- if (!file)
- {
- printf("Could not create temporary file. Please run as Administrator or root\n");
- exit(1);
- }
- fwrite(buffer, sizeof(char), size, file);
- fseek(file, 0, SEEK_SET);
- return file;
+ Stream* stream = new Stream(buffer, size);
+ return stream;
}
diff --git a/src/tools/mesh_extractor/MPQ.h b/src/tools/mesh_extractor/MPQ.h
index 17dbe74dcaa..df39e901d5d 100644
--- a/src/tools/mesh_extractor/MPQ.h
+++ b/src/tools/mesh_extractor/MPQ.h
@@ -20,6 +20,7 @@
#include "libmpq/mpq.h"
#include "Define.h"
+#include "Stream.h"
#include <string>
#include <ctype.h>
#include <vector>
@@ -30,7 +31,7 @@ class MPQArchive
{
public:
- mpq_archive_s *mpq_a;
+ mpq_archive_s* mpq_a;
std::vector<std::string> Files;
@@ -70,8 +71,8 @@ class MPQFile
{
//MPQHANDLE handle;
bool eof;
- char *buffer;
- libmpq__off_t pointer,size;
+ char* buffer;
+ libmpq__off_t pointer, size;
// disable copying
MPQFile(const MPQFile& /*f*/) {}
@@ -81,18 +82,18 @@ public:
MPQFile(const char* filename); // filenames are not case sensitive
~MPQFile() { close(); }
size_t Read(void* dest, size_t bytes);
- FILE* GetFileStream();
- size_t getSize() { return size; }
- size_t getPos() { return pointer; }
+ Stream* GetFileStream();
+ size_t getSize() const { return size; }
+ size_t getPos() const { return pointer; }
char* getBuffer() { return buffer; }
char* getPointer() { return buffer + pointer; }
- bool isEof() { return eof; }
+ bool isEof() const { return eof; }
void seek(int offset);
void seekRelative(int offset);
void close();
};
-inline void flipcc(char *fcc)
+inline void flipcc(char* fcc)
{
char t;
t=fcc[0];
diff --git a/src/tools/mesh_extractor/MPQManager.cpp b/src/tools/mesh_extractor/MPQManager.cpp
index 8954da6c154..4834ca368c0 100644
--- a/src/tools/mesh_extractor/MPQManager.cpp
+++ b/src/tools/mesh_extractor/MPQManager.cpp
@@ -19,6 +19,7 @@
#include "MPQ.h"
#include "DBC.h"
#include "Utils.h"
+#include "Stream.h"
#include <ace/Guard_T.h>
char const* MPQManager::Files[] = {
@@ -31,6 +32,12 @@ char const* MPQManager::Files[] = {
"patch-3.MPQ"
};
+char const* MPQManager::LocalePatchFiles[] = {
+ "Data/%s/patch-%s.MPQ",
+ "Data/%s/patch-%s-2.MPQ",
+ "Data/%s/patch-%s-3.MPQ"
+};
+
char const* MPQManager::Languages[] = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
void MPQManager::Initialize()
@@ -48,9 +55,7 @@ void MPQManager::Initialize()
void MPQManager::InitializeDBC()
{
BaseLocale = -1;
- std::string fileName;
uint32 size = sizeof(Languages) / sizeof(char*);
- MPQArchive* _baseLocale = NULL;
for (uint32 i = 0; i < size; ++i)
{
std::string _fileName = "Data/" + std::string(Languages[i]) + "/locale-" + std::string(Languages[i]) + ".MPQ";
@@ -58,20 +63,34 @@ void MPQManager::InitializeDBC()
if (file)
{
if (BaseLocale == -1)
- {
BaseLocale = i;
- _baseLocale = new MPQArchive(_fileName.c_str());
- fileName = _fileName;
- LocaleFiles[i] = _baseLocale;
+
+ // Load the base locale file
+ MPQArchive* arch = new MPQArchive(_fileName.c_str());
+ LocaleFiles[i].push_front(arch);
+
+ Archives.push_front(arch); // For lookup in GetFile
+
+ // Load the locale patches
+ for (uint32 j = 0; j < sizeof(LocalePatchFiles) / sizeof(char*); ++j)
+ {
+ char patchName[100];
+ sprintf(patchName, LocalePatchFiles[j], Languages[i], Languages[i]);
+ FILE* patch = fopen(patchName, "rb");
+ if (file)
+ {
+ MPQArchive* archP = new MPQArchive(patchName);
+ LocaleFiles[i].push_front(archP);
+ Archives.push_front(archP); // For lookup in GetFile
+ fclose(patch);
+ }
}
- else
- LocaleFiles[i] = new MPQArchive(_fileName.c_str());
AvailableLocales.insert(i);
printf("Detected locale: %s\n", Languages[i]);
}
}
- Archives.push_front(_baseLocale);
+
if (BaseLocale == -1)
{
printf("No locale data detected. Please make sure that the executable is in the same folder as your WoW installation.\n");
@@ -81,7 +100,7 @@ void MPQManager::InitializeDBC()
printf("Using default locale: %s\n", Languages[BaseLocale]);
}
-FILE* MPQManager::GetFile(const std::string& path )
+Stream* MPQManager::GetFile(const std::string& path )
{
ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
MPQFile file(path.c_str());
@@ -90,13 +109,54 @@ FILE* MPQManager::GetFile(const std::string& path )
return file.GetFileStream();
}
-DBC* MPQManager::GetDBC(const std::string& name )
+DBC const* MPQManager::GetDBC(const std::string& name )
{
+ std::map<std::string, DBC*>::const_iterator itr = LoadedDBCs.find(name);
+ if (itr != LoadedDBCs.end())
+ return itr->second;
+
std::string path = "DBFilesClient\\" + name + ".dbc";
- return new DBC(GetFile(path));
+ DBC* dbc = new DBC(GetFile(path));
+
+ LoadedDBCs[name] = dbc;
+
+ return dbc;
}
-FILE* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file )
+Stream* MPQManager::GetFileFromLocale( const std::string& path, uint32 locale )
+{
+ ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
+ std::deque<MPQArchive*> files = LocaleFiles[locale];
+ Stream* ret = NULL;
+ for (std::deque<MPQArchive*>::iterator itr = files.begin(); itr != files.end(); ++itr)
+ {
+ mpq_archive* mpq_a = (*itr)->mpq_a;
+
+ uint32_t filenum;
+ if(libmpq__file_number(mpq_a, path.c_str(), &filenum))
+ continue;
+ libmpq__off_t transferred;
+ libmpq__off_t size = 0;
+ libmpq__file_unpacked_size(mpq_a, filenum, &size);
+
+ // HACK: in patch.mpq some files don't want to open and give 1 for filesize
+ if (size <= 1)
+ continue;
+
+ char* buffer = new char[size];
+
+ //libmpq_file_getdata
+ libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
+
+ ret = new Stream(buffer, size);
+
+ delete[] buffer;
+ break;
+ }
+ return ret;
+}
+
+Stream* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file )
{
ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
mpq_archive* mpq_a = file->mpq_a;
@@ -119,14 +179,7 @@ FILE* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file )
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
// Pack the return into a FILE stream
- FILE* ret = tmpfile();
- if (!ret)
- {
- printf("Could not create temporary file. Please run as Administrator or root\n");
- exit(1);
- }
- fwrite(buffer, sizeof(uint8), size, ret);
- fseek(ret, 0, SEEK_SET);
+ Stream* ret = new Stream((char*)buffer, size);
delete[] buffer;
return ret;
}
diff --git a/src/tools/mesh_extractor/MPQManager.h b/src/tools/mesh_extractor/MPQManager.h
index 6172237df49..d44030319cf 100644
--- a/src/tools/mesh_extractor/MPQManager.h
+++ b/src/tools/mesh_extractor/MPQManager.h
@@ -19,6 +19,7 @@
#define MPQ_MANAGER_H
#include "MPQ.h"
+#include "Stream.h"
#include <ace/Synch.h>
#include <set>
#include <map>
@@ -31,22 +32,26 @@ public:
~MPQManager() {}
void Initialize();
- FILE* GetFile(const std::string& path);
- FILE* GetFileFrom(const std::string& path, MPQArchive* file);
- DBC* GetDBC(const std::string& name);
+ Stream* GetFile(const std::string& path);
+ Stream* GetFileFrom(const std::string& path, MPQArchive* file);
+ Stream* GetFileFromLocale(const std::string& path, uint32 locale);
+
+ DBC const* GetDBC(const std::string& name);
std::vector<std::string> GetAllFiles(std::string extension);
std::deque<MPQArchive*> Archives;
int32 BaseLocale;
std::set<uint32> AvailableLocales;
- std::map<uint32, MPQArchive*> LocaleFiles;
+ std::map<uint32, std::deque<MPQArchive*> > LocaleFiles;
static char const* Files[];
+ static char const* LocalePatchFiles[];
static char const* Languages[];
protected:
void InitializeDBC();
private:
ACE_Thread_Mutex mutex;
+ std::map<std::string, DBC*> LoadedDBCs;
};
extern MPQManager* MPQHandler;
diff --git a/src/tools/mesh_extractor/MapChunk.cpp b/src/tools/mesh_extractor/MapChunk.cpp
index 4cd5afad3f1..ee6b4584396 100644
--- a/src/tools/mesh_extractor/MapChunk.cpp
+++ b/src/tools/mesh_extractor/MapChunk.cpp
@@ -21,9 +21,9 @@
MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk)
{
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
Header.Read(stream);
- fseek(stream, chunk->Offset, SEEK_SET);
+ stream->Seek(chunk->Offset, SEEK_SET);
Index = Header.IndexX + Header.IndexY * 16;
GenerateVertices(stream);
}
@@ -47,12 +47,12 @@ void MapChunk::GenerateTriangles()
Constants::TriangleType triangleType = Constants::TRIANGLE_TYPE_TERRAIN;
if (Adt->_LiquidHandler && !Adt->_LiquidHandler->MCNKData.empty())
{
- MCNKLiquidData& data = Adt->_LiquidHandler->MCNKData[Index];
+ MCNKLiquidData* data = Adt->_LiquidHandler->MCNKData[Index];
float maxHeight = std::max(
std::max(
std::max(std::max(Vertices[topLeft].z, Vertices[topRight].z), Vertices[bottomLeft].z),
Vertices[bottomRight].z), Vertices[center].z);
- if (data.IsWater(x, y, maxHeight))
+ if (data->IsWater(x, y, maxHeight))
triangleType = Constants::TRIANGLE_TYPE_WATER;
}
@@ -64,9 +64,9 @@ void MapChunk::GenerateTriangles()
}
}
-void MapChunk::GenerateVertices( FILE* stream )
+void MapChunk::GenerateVertices(Stream* stream)
{
- fseek(stream, Header.OffsetMCVT, SEEK_CUR);
+ stream->Seek(Header.OffsetMCVT, SEEK_CUR);
Vertices.reserve(125);
for (int j = 0; j < 17; j++)
@@ -74,9 +74,7 @@ void MapChunk::GenerateVertices( FILE* stream )
int values = j % 2 ? 8 : 9;
for (int i = 0; i < values; i++)
{
- float tmp;
- if (fread(&tmp, sizeof(float), 1, stream) != 1)
- printf("MapChunk::GenerateVertices: Failed to read some data expected 1, read 0\n");
+ float tmp = stream->Read<float>();
Vector3 vert(Header.Position.x - (j * (Constants::UnitSize * 0.5f)), Header.Position.y - (i * Constants::UnitSize), Header.Position.z + tmp);
if (values == 8)
vert.y -= Constants::UnitSize * 0.5f;
@@ -84,7 +82,7 @@ void MapChunk::GenerateVertices( FILE* stream )
}
}
// Restore stream position.
- fseek(stream, Source->Offset, SEEK_SET);
+ stream->Seek(Source->Offset, SEEK_SET);
}
bool MapChunk::HasHole( uint32 map, int x, int y )
diff --git a/src/tools/mesh_extractor/MapChunk.h b/src/tools/mesh_extractor/MapChunk.h
index 95bce9ffcd6..c5127b08002 100644
--- a/src/tools/mesh_extractor/MapChunk.h
+++ b/src/tools/mesh_extractor/MapChunk.h
@@ -29,7 +29,7 @@ public:
MapChunk(ADT* _adt, Chunk* chunk);
void GenerateTriangles();
- void GenerateVertices(FILE* stream);
+ void GenerateVertices(Stream* stream);
static bool HasHole(uint32 map, int x, int y);
ADT* Adt;
Chunk* Source;
diff --git a/src/tools/mesh_extractor/MeshExtractor.cpp b/src/tools/mesh_extractor/MeshExtractor.cpp
index e60e11b1db8..de791b04d36 100644
--- a/src/tools/mesh_extractor/MeshExtractor.cpp
+++ b/src/tools/mesh_extractor/MeshExtractor.cpp
@@ -34,16 +34,41 @@
MPQManager* MPQHandler;
CacheClass* Cache;
+bool IgnoreMap(uint32 id)
+{
+ switch (id)
+ {
+ case 13: // test.wdt
+ case 25: // ScottTest.wdt
+ case 29: // Test.wdt
+ case 42: // Colin.wdt
+ case 169: // EmeraldDream.wdt (unused, and very large)
+ case 451: // development.wdt
+ case 573: // ExteriorTest.wdt
+ case 597: // CraigTest.wdt
+ case 605: // development_nonweighted.wdt
+ case 606: // QA_DVD.wdt
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
void ExtractMMaps(std::set<uint32>& mapIds, uint32 threads)
{
- DBC* dbc = MPQHandler->GetDBC("Map");
- printf("Map.dbc contains %u rows.\n", dbc->Records.size());
- for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
+ std::string basePath = "mmaps/";
+ Utils::CreateDir(basePath);
+
+ DBC const* dbc = MPQHandler->GetDBC("Map");
+ printf("Map.dbc contains " SIZEFMTD " rows.\n", dbc->Records.size());
+ for (std::vector<Record*>::const_iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
{
uint32 mapId = (*itr)->Values[0];
- // Skip this map if a list of specific maps was provided and this one is not contained in it.
- if (!mapIds.empty() && mapIds.find(mapId) == mapIds.end())
+ // Skip this map if a list of specific maps was provided and this one is not contained in it, or if the map is in the ignore list.
+ if ((!mapIds.empty() && mapIds.find(mapId) == mapIds.end()) || IgnoreMap(mapId))
{
if (Constants::Debug)
printf("Map %u will not be built.\n", mapId);
@@ -75,9 +100,12 @@ void ExtractDBCs()
// Populate list of DBC files
// We get the DBC names by going over the (guaranteed to exist) default locale files
// Then we look in other locale files in case that they are available.
- for (std::vector<std::string>::iterator itr = MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.begin(); itr != MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.end(); ++itr)
- if (itr->rfind(".dbc") == itr->length() - extLen) // Check if the extension is ".dbc"
- DBCFiles.insert(*itr);
+ for (std::map<uint32, std::deque<MPQArchive*> >::iterator itr = MPQHandler->LocaleFiles.begin(); itr != MPQHandler->LocaleFiles.end(); ++itr)
+ for (std::deque<MPQArchive*>::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2)
+ for (std::vector<std::string>::iterator itr3 = (*itr2)->Files.begin(); itr3 != (*itr2)->Files.end(); ++itr3)
+ if (itr3->rfind(".dbc") == itr3->length() - extLen) // Check if the extension is ".dbc"
+ if (DBCFiles.find(*itr3) == DBCFiles.end())
+ DBCFiles.insert(*itr3);
const size_t folderLen = strlen("DBFilesClient\\");
// Iterate over all available locales
@@ -93,10 +121,10 @@ void ExtractDBCs()
std::string component = "component.wow-" + std::string(MPQManager::Languages[*itr]) + ".txt";
// Extract the component file
- Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*itr]), path + component);
+ Utils::SaveToDisk(MPQHandler->GetFileFromLocale(component, *itr), path + component);
// Extract the DBC files for the given locale
for (std::set<std::string>::iterator itr2 = DBCFiles.begin(); itr2 != DBCFiles.end(); ++itr2)
- Utils::SaveToDisk(MPQHandler->GetFileFrom(*itr2, MPQHandler->LocaleFiles[*itr]), path + (itr2->c_str() + folderLen));
+ Utils::SaveToDisk(MPQHandler->GetFileFromLocale(*itr2, *itr), path + (itr2->c_str() + folderLen));
}
printf("DBC extraction finished!\n");
}
@@ -118,8 +146,8 @@ void ExtractGameobjectModels()
return;
}
- DBC* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo");
- for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
+ DBC const* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo");
+ for (std::vector<Record*>::const_iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
{
std::string path = (*itr)->GetString(1);
std::string fileName = Utils::GetPlainName(path.c_str());
@@ -225,8 +253,9 @@ void ExtractGameobjectModels()
fwrite(&model.Header.WmoId, sizeof(uint32), 1, output);
const char grp[] = { 'G' , 'R' , 'P', ' ' };
- for (std::vector<WorldModelGroup>::iterator itr2 = model.Groups.begin(); itr2 != model.Groups.end(); ++itr2)
+ for (std::vector<WorldModelGroup*>::iterator groupItr = model.Groups.begin(); groupItr != model.Groups.end(); ++groupItr)
{
+ WorldModelGroup* itr2 = *groupItr;
const WMOGroupHeader& header = itr2->Header;
fwrite(&header.Flags, sizeof(uint32), 1, output);
fwrite(&header.WmoId, sizeof(uint32), 1, output);
@@ -363,7 +392,6 @@ void LoadTile(dtNavMesh*& navMesh, const char* tile)
int main(int argc, char* argv[])
{
- _setmaxstdio(2048);
uint32 threads = 4, extractFlags = 0;
std::set<uint32> mapIds;
@@ -395,8 +423,8 @@ int main(int argc, char* argv[])
if (extractFlags & Constants::EXTRACT_FLAG_TEST)
{
- float start[] = { 16226.200195f, 16257.000000f, 13.202200f };
- float end[] = { 16245.725586f, 16382.465820f, 47.384956f };
+ float start[] = { -45.4745407f, -29.5000954f, -21.4456501f };
+ float end[] = { -107.686218f, -32.3544769f, -30.3459435f };
//
float m_spos[3];
@@ -425,7 +453,7 @@ int main(int argc, char* argv[])
dtPolyRef m_startRef;
dtPolyRef m_endRef;
- FILE* mmap = fopen("mmaps/001.mmap", "rb");
+ FILE* mmap = fopen("mmaps/631.mmap", "rb");
dtNavMeshParams params;
int count = fread(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
@@ -444,7 +472,7 @@ int main(int argc, char* argv[])
for (int j = 0; j <= 32; ++j)
{
char buff[100];
- sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j);
+ sprintf(buff, "mmaps/631%02i%02i.mmtile", i, j);
LoadTile(navMesh, buff);
}
}
@@ -462,24 +490,38 @@ int main(int argc, char* argv[])
return 0;
}
- int hops;
- dtPolyRef* hopBuffer = new dtPolyRef[8192];
- dtStatus status = navMeshQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, hopBuffer, &hops, 8192);
+ dtStatus status;
+ status = navMeshQuery->initSlicedFindPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter);
+ while (status != DT_SUCCESS)
+ status = navMeshQuery->updateSlicedFindPath(1, 0);
- int resultHopCount;
- float* straightPath = new float[2048*3];
- unsigned char* pathFlags = new unsigned char[2048];
dtPolyRef* pathRefs = new dtPolyRef[2048];
+ int pcount = 0;
+ int resultHopCount = 0;
+ float* straightPath = new float[2048 * 3];
+ unsigned char* pathFlags = new unsigned char[2048];
+ dtPolyRef* hopBuffer = new dtPolyRef[8192];
- status = navMeshQuery->findStraightPath(m_spos, m_epos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048);
+ navMeshQuery->finalizeSlicedFindPath(pathRefs, &pcount, 200);
std::vector<Vector3> FinalPath;
+
+ for (int i = 0; i < pcount; ++i)
+ {
+ navMeshQuery->findStraightPath(m_spos, m_epos, &pathRefs[i], 1,
+ straightPath, pathFlags,
+ hopBuffer, &resultHopCount, 200);
+ Vector3 finalV = Utils::ToWoWCoords(Vector3(straightPath[0 * 3 + 0], straightPath[0 * 3 + 1], straightPath[0 * 3 + 2]));
+ FinalPath.push_back(finalV);
+ printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z);
+ }
+ /*
FinalPath.reserve(resultHopCount);
- for (uint32 i = 0; i < resultHopCount; ++i)
+ for (int i = 0; i < resultHopCount; ++i)
{
Vector3 finalV = Utils::ToWoWCoords(Vector3(straightPath[i * 3 + 0], straightPath[i * 3 + 1], straightPath[i * 3 + 2]));
FinalPath.push_back(finalV);
printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z);
- }
+ }*/
}
return 0;
diff --git a/src/tools/mesh_extractor/Model.cpp b/src/tools/mesh_extractor/Model.cpp
index 2a1a80f41eb..f88f620720c 100644
--- a/src/tools/mesh_extractor/Model.cpp
+++ b/src/tools/mesh_extractor/Model.cpp
@@ -19,15 +19,15 @@
#include "MPQManager.h"
#include "Utils.h"
-Model::Model( std::string path ) : IsCollidable(false), IsBad(false)
+Model::Model(std::string path) : IsCollidable(false), IsBad(false)
{
- Stream = MPQHandler->GetFile(Utils::FixModelPath(path));
- if (!Stream)
+ _Stream = MPQHandler->GetFile(Utils::FixModelPath(path));
+ if (!_Stream)
{
IsBad = true;
return;
}
- Header.Read(Stream);
+ Header.Read(_Stream);
if (Header.OffsetBoundingNormals > 0 && Header.OffsetBoundingVertices > 0 &&
Header.OffsetBoundingTriangles > 0 && Header.BoundingRadius > 0.0f)
{
@@ -40,17 +40,17 @@ Model::Model( std::string path ) : IsCollidable(false), IsBad(false)
Model::~Model()
{
- if (Stream)
- fclose(Stream);
+ if (_Stream)
+ delete _Stream;
}
void Model::ReadVertices()
{
- fseek(Stream, Header.OffsetBoundingVertices, SEEK_SET);
+ _Stream->Seek(Header.OffsetBoundingVertices, SEEK_SET);
Vertices.reserve(Header.CountBoundingVertices);
for (uint32 i = 0; i < Header.CountBoundingVertices; ++i)
{
- Vertices.push_back(Vector3::Read(Stream));
+ Vertices.push_back(Vector3::Read(_Stream));
if (Constants::ToWoWCoords)
Vertices[i] = Utils::ToWoWCoords(Vertices[i]);
}
@@ -58,27 +58,24 @@ void Model::ReadVertices()
void Model::ReadBoundingTriangles()
{
- fseek(Stream, Header.OffsetBoundingTriangles, SEEK_SET);
+ _Stream->Seek(Header.OffsetBoundingTriangles, SEEK_SET);
Triangles.reserve(Header.CountBoundingTriangles / 3);
for (uint32 i = 0; i < Header.CountBoundingTriangles / 3; i++)
{
Triangle<uint16> tri;
tri.Type = Constants::TRIANGLE_TYPE_DOODAD;
- int count = 0;
- count += fread(&tri.V0, sizeof(uint16), 1, Stream);
- count += fread(&tri.V1, sizeof(uint16), 1, Stream);
- count += fread(&tri.V2, sizeof(uint16), 1, Stream);
- if (count != 3)
- printf("Model::ReadBoundingTriangles: Error reading data, expected 3, read %d\n", count);
+ tri.V0 = _Stream->Read<uint16>();
+ tri.V1 = _Stream->Read<uint16>();
+ tri.V2 = _Stream->Read<uint16>();
Triangles.push_back(tri);
}
}
void Model::ReadBoundingNormals()
{
- fseek(Stream, Header.OffsetBoundingNormals, SEEK_SET);
+ _Stream->Seek(Header.OffsetBoundingNormals, SEEK_SET);
Normals.reserve(Header.CountBoundingNormals);
for (uint32 i = 0; i < Header.CountBoundingNormals; i++)
- Normals.push_back(Vector3::Read(Stream));
+ Normals.push_back(Vector3::Read(_Stream));
}
diff --git a/src/tools/mesh_extractor/Model.h b/src/tools/mesh_extractor/Model.h
index a1f224729dd..9b460b1e2b6 100644
--- a/src/tools/mesh_extractor/Model.h
+++ b/src/tools/mesh_extractor/Model.h
@@ -19,6 +19,7 @@
#define MODEL_H
#include <vector>
#include "Utils.h"
+#include "Stream.h"
class Model
{
@@ -34,7 +35,7 @@ public:
std::vector<Vector3> Normals;
std::vector<Triangle<uint16> > Triangles;
bool IsCollidable;
- FILE* Stream;
+ Stream* _Stream;
bool IsBad;
};
#endif \ No newline at end of file
diff --git a/src/tools/mesh_extractor/ObjectDataHandler.h b/src/tools/mesh_extractor/ObjectDataHandler.h
index 3b18427db47..346241f9ae0 100644
--- a/src/tools/mesh_extractor/ObjectDataHandler.h
+++ b/src/tools/mesh_extractor/ObjectDataHandler.h
@@ -24,6 +24,7 @@ class ObjectDataHandler
{
public:
ObjectDataHandler(ADT* _adt) : Source(_adt) {}
+ virtual ~ObjectDataHandler() {}
void ProcessMapChunk(MapChunk* chunk);
virtual void ProcessInternal(MapChunk* data) = 0;
diff --git a/src/tools/mesh_extractor/Stream.cpp b/src/tools/mesh_extractor/Stream.cpp
new file mode 100644
index 00000000000..f775d97d114
--- /dev/null
+++ b/src/tools/mesh_extractor/Stream.cpp
@@ -0,0 +1,47 @@
+#include "Stream.h"
+#include <iostream>
+
+Stream::Stream(char* buffer, uint32 size) : _size(size), _position(0)
+{
+ _buffer = new char[size];
+ memcpy(_buffer, buffer, size); // Initialize the buffer
+}
+
+Stream::~Stream()
+{
+ delete[] _buffer;
+}
+
+char* Stream::Read(uint32 size)
+{
+ char* buff = new char[size];
+ memcpy(buff, &_buffer[_position], size);
+ _position += size;
+ return buff;
+}
+
+void Stream::Seek(uint32 position, uint32 type)
+{
+ switch (type)
+ {
+ case SEEK_SET:
+ _position = position;
+ break;
+ case SEEK_CUR:
+ _position += position;
+ break;
+ }
+}
+
+std::string Stream::ReadString()
+{
+ std::string str;
+ while (true)
+ {
+ char b = Read<char>();
+ if (b == 0)
+ break;
+ str.push_back(b);
+ }
+ return str;
+} \ No newline at end of file
diff --git a/src/tools/mesh_extractor/Stream.h b/src/tools/mesh_extractor/Stream.h
new file mode 100644
index 00000000000..647ff9d5357
--- /dev/null
+++ b/src/tools/mesh_extractor/Stream.h
@@ -0,0 +1,59 @@
+#ifndef STREAM_H
+#define STREAM_H
+
+#include "Define.h"
+#include <iostream>
+
+class Stream
+{
+public:
+ Stream(char* buffer, uint32 size);
+ ~Stream();
+
+ template<typename T>
+ T Read()
+ {
+ T ret = *((T*)(&_buffer[_position]));
+ _position += sizeof(T);
+ return ret;
+ }
+
+ template<typename T>
+ void Read(T* dest, uint32 size)
+ {
+ memcpy(dest, &_buffer[_position], size);
+ _position += size;
+ }
+
+ template<typename T>
+ void Skip()
+ {
+ _position += sizeof(T);
+ }
+
+ char* Read(uint32 size);
+ std::string ReadString();
+
+ void Reset()
+ {
+ _position = 0;
+ }
+
+ void Seek(uint32 position, uint32 type);
+
+ uint32 GetSize() const
+ {
+ return _size;
+ }
+
+ uint32 GetPos() const
+ {
+ return _position;
+ }
+
+private:
+ char* _buffer;
+ uint32 _size;
+ uint32 _position;
+};
+#endif \ No newline at end of file
diff --git a/src/tools/mesh_extractor/TileBuilder.cpp b/src/tools/mesh_extractor/TileBuilder.cpp
index 7b70ccca44c..faee5b767cd 100644
--- a/src/tools/mesh_extractor/TileBuilder.cpp
+++ b/src/tools/mesh_extractor/TileBuilder.cpp
@@ -43,8 +43,8 @@ TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x,
Config.detailSampleDist = 3.0f;
Config.detailSampleMaxError = 1.25f;
Config.walkableClimb = 1.0f / Config.ch;
- Config.walkableHeight = 2.1 / Config.ch;
- Config.walkableRadius = 0.6f / Config.cs;
+ Config.walkableHeight = 2.1;
+ Config.walkableRadius = 0.6f;
Config.maxEdgeLen = Config.walkableRadius * 8;
Config.borderSize = Config.walkableRadius + 8;
Config.tileSize = 1800;
@@ -59,19 +59,19 @@ TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x,
InstanceConfig.mergeRegionArea = 100;
InstanceConfig.walkableSlopeAngle = 50.0f;
InstanceConfig.detailSampleDist = 3.0f;
- InstanceConfig.detailSampleMaxError = 1.5f;
+ InstanceConfig.detailSampleMaxError = 1.25f;
InstanceConfig.walkableClimb = 1.0f / InstanceConfig.ch;
- InstanceConfig.walkableHeight = 2.1f / InstanceConfig.ch;
- InstanceConfig.walkableRadius = 0.6f / InstanceConfig.cs;
+ InstanceConfig.walkableHeight = 2.1f;
+ InstanceConfig.walkableRadius = 0.6f;
InstanceConfig.maxEdgeLen = 8 * InstanceConfig.walkableRadius;
InstanceConfig.maxVertsPerPoly = 6;
- InstanceConfig.maxSimplificationError = 1.25f;
+ InstanceConfig.maxSimplificationError = 1.3f;
InstanceConfig.borderSize = 0;
Context = new rcContext;
}
-void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ )
+void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ ) const
{
bmin = new float[3];
bmax = new float[3];
@@ -81,7 +81,7 @@ void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshPara
bmax[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * (Y + 1));
}
-void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def)
+void TileBuilder::AddGeometry(WorldModelRoot const* root, const WorldModelDefinition& def)
{
_Geometry = new Geometry();
_Geometry->Transform = true;
@@ -91,7 +91,7 @@ void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition&
OutputDebugVertices();
}
-uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams )
+uint8* TileBuilder::BuildInstance( dtNavMeshParams& /*navMeshParams*/ )
{
float* bmin = NULL, *bmax = NULL;
@@ -183,11 +183,11 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams )
rcFreeHeightField(hf);
rcFreeCompactHeightfield(chf);
rcFreeContourSet(contours);
- delete vertices;
- delete triangles;
- delete areas;
- delete bmin;
- delete bmax;
+ delete[] vertices;
+ delete[] triangles;
+ delete[] areas;
+ delete[] bmin;
+ delete[] bmax;
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount)
{
@@ -226,7 +226,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
adt->Read();
_Geometry->AddAdt(adt);
delete adt;
-
+
if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty())
return NULL;
@@ -234,7 +234,8 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
CalculateTileBounds(bmin, bmax, navMeshParams);
_Geometry->CalculateMinMaxHeight(bmin[1], bmax[1]);
- // again, we load everything - wasteful but who cares
+ // This is commented out to reduce the size of the resulting files (and the time it takes to generate them), we shouldn't need to load 4 more ADTs each time.
+ /*// again, we load everything - wasteful but who cares
for (int ty = Y - 1; ty <= Y + 1; ty++)
{
for (int tx = X - 1; tx <= X + 1; tx++)
@@ -245,7 +246,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
ADT* _adt = new ADT(Utils::GetAdtPath(World, tx, ty), tx, ty);
// If this condition is met, it means that this WDT does not contain the ADT
- if (!_adt->Data->Stream)
+ if (!_adt->Data->_Stream)
{
delete _adt;
continue;
@@ -254,7 +255,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
_Geometry->AddAdt(_adt);
delete _adt;
}
- }
+ }*/
OutputDebugVertices();
@@ -351,11 +352,11 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
rcFreeHeightField(hf);
rcFreeCompactHeightfield(chf);
rcFreeContourSet(contours);
- delete vertices;
- delete triangles;
- delete areas;
- delete bmin;
- delete bmax;
+ delete[] vertices;
+ delete[] triangles;
+ delete[] areas;
+ delete[] bmin;
+ delete[] bmax;
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount)
{
@@ -386,7 +387,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
return NULL;
}
-void TileBuilder::OutputDebugVertices()
+void TileBuilder::OutputDebugVertices() const
{
if (Constants::Debug)
{
diff --git a/src/tools/mesh_extractor/TileBuilder.h b/src/tools/mesh_extractor/TileBuilder.h
index fb8950c552b..6171d407212 100644
--- a/src/tools/mesh_extractor/TileBuilder.h
+++ b/src/tools/mesh_extractor/TileBuilder.h
@@ -32,11 +32,11 @@ public:
TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId);
~TileBuilder();
- void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams);
+ void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams) const;
uint8* BuildTiled(dtNavMeshParams& navMeshParams);
uint8* BuildInstance(dtNavMeshParams& navMeshParams);
- void AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def);
- void OutputDebugVertices();
+ void AddGeometry(WorldModelRoot const* root, const WorldModelDefinition& def);
+ void OutputDebugVertices() const;
std::string World;
int X;
int Y;
diff --git a/src/tools/mesh_extractor/Utils.cpp b/src/tools/mesh_extractor/Utils.cpp
index f82eb6ed1c8..b8ebc0b8fd3 100644
--- a/src/tools/mesh_extractor/Utils.cpp
+++ b/src/tools/mesh_extractor/Utils.cpp
@@ -18,6 +18,7 @@
#include "Utils.h"
#include "WorldModelHandler.h"
#include "Constants.h"
+#include "Stream.h"
#include <cstring>
#include "G3D/Matrix4.h"
#include "G3D/Quat.h"
@@ -53,40 +54,9 @@ void Utils::CreateDir( const std::string& Path )
#endif
}
-void Utils::Reverse(char word[])
+void Utils::Reverse(std::string& str)
{
- int len = strlen(word);
- for (int i = 0;i < len / 2; i++)
- {
- word[i] ^= word[len-i-1];
- word[len-i-1] ^= word[i];
- word[i] ^= word[len-i-1];
- }
-}
-
-std::string Utils::ReadString( FILE* file )
-{
- std::string ret;
- while (true)
- {
- char b;
- if (fread(&b, sizeof(char), 1, file) != 1 || b == 0)
- break;
- ret.push_back(b);
- }
- return ret;
-}
-
-uint32 Utils::Size( FILE* file )
-{
- // store the old position
- uint32 offset = ftell(file);
- // Get file size
- fseek(file, 0, SEEK_END);
- uint32 size = ftell(file);
- // reset back to the old position
- fseek(file, offset, SEEK_SET);
- return size;
+ std::reverse(str.begin(), str.end());
}
Vector3 Utils::ToRecast(const Vector3& val )
@@ -104,7 +74,7 @@ std::string Utils::FixModelPath(const std::string& path )
return Utils::GetPathBase(path) + ".M2";
}
-Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate)
+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
@@ -122,7 +92,7 @@ Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool
return ret;
}
-Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate )
+Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& /*root*/, const Vector3& vec, bool translate)
{
G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW);
@@ -153,12 +123,9 @@ std::string Utils::GetPathBase(const std::string& path )
return path;
}
-Vector3 Vector3::Read( FILE* file )
+Vector3 Vector3::Read(Stream* file)
{
- Vector3 ret;
- if (fread(&ret, sizeof(Vector3), 1, file) != 1)
- printf("Vector3::Read: Failed to read some data expected 1, read 0\n");
- return ret;
+ return file->Read<Vector3>();
}
Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate)
@@ -184,41 +151,36 @@ std::string Utils::Replace( std::string str, const std::string& oldStr, const st
return str;
}
-void Utils::SaveToDisk( FILE* stream, const std::string& path )
+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());
- fclose(stream);
+ delete stream;
return;
}
- uint32 size = Utils::Size(stream);
- uint8* data = new uint8[size];
- // Read the data to an array
- size_t read = fread(data, size, 1, stream);
- if (read != 1)
- {
- printf("SaveToDisk: Error reading from Stream while trying to save file %s to disk.\n", path.c_str());
- fclose(disk);
- fclose(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());
- fclose(stream);
+ delete[] data;
+ delete stream;
fclose(disk);
return;
}
// Close the filestream
fclose(disk);
- fclose(stream);
+ delete stream;
// Free the used memory
delete[] data;
@@ -239,249 +201,193 @@ std::string Utils::GetExtension( std::string path )
return extension;
}
-void MapChunkHeader::Read(FILE* stream)
-{
- int count = 0;
-
- count += fread(&Flags, sizeof(uint32), 1, stream);
- count += fread(&IndexX, sizeof(uint32), 1, stream);
- count += fread(&IndexY, sizeof(uint32), 1, stream);
- count += fread(&Layers, sizeof(uint32), 1, stream);
- count += fread(&DoodadRefs, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCVT, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCNR, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCLY, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCRF, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCAL, sizeof(uint32), 1, stream);
- count += fread(&SizeMCAL, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCSH, sizeof(uint32), 1, stream);
- count += fread(&SizeMCSH, sizeof(uint32), 1, stream);
- count += fread(&AreaId, sizeof(uint32), 1, stream);
- count += fread(&MapObjectRefs, sizeof(uint32), 1, stream);
- count += fread(&Holes, sizeof(uint32), 1, stream);
- LowQualityTextureMap = new uint32[4];
- count += fread(LowQualityTextureMap, sizeof(uint32), 4, stream);
- count += fread(&PredTex, sizeof(uint32), 1, stream);
- count += fread(&NumberEffectDoodad, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCSE, sizeof(uint32), 1, stream);
- count += fread(&SoundEmitters, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCLQ, sizeof(uint32), 1, stream);
- count += fread(&SizeMCLQ, sizeof(uint32), 1, stream);
+void MapChunkHeader::Read(Stream* stream)
+{
+ Flags = stream->Read<uint32>();
+ IndexX = stream->Read<uint32>();
+ IndexY = stream->Read<uint32>();
+ Layers = stream->Read<uint32>();
+ DoodadRefs = stream->Read<uint32>();
+ OffsetMCVT = stream->Read<uint32>();
+ OffsetMCNR = stream->Read<uint32>();
+ OffsetMCLY = stream->Read<uint32>();
+ OffsetMCRF = stream->Read<uint32>();
+ OffsetMCAL = stream->Read<uint32>();
+ SizeMCAL = stream->Read<uint32>();
+ OffsetMCSH = stream->Read<uint32>();
+ SizeMCSH = stream->Read<uint32>();
+ AreaId = stream->Read<uint32>();
+ MapObjectRefs = stream->Read<uint32>();
+ Holes = stream->Read<uint32>();
+ stream->Read(LowQualityTextureMap, sizeof(uint32) * 4);
+ PredTex = stream->Read<uint32>();
+ NumberEffectDoodad = stream->Read<uint32>();
+ OffsetMCSE = stream->Read<uint32>();
+ SoundEmitters = stream->Read<uint32>();
+ OffsetMCLQ = stream->Read<uint32>();
+ SizeMCLQ = stream->Read<uint32>();
Position = Vector3::Read(stream);
- count += fread(&OffsetMCCV, sizeof(uint32), 1, stream);
-
- if (count != 27)
- printf("MapChunkHeader::Read: Failed to read some data expected 27, read %d\n", count);
+ OffsetMCCV = stream->Read<uint32>();
}
-void MHDR::Read(FILE* stream)
+void MHDR::Read(Stream* stream)
{
- int count = 0;
-
- count += fread(&Flags, sizeof(uint32), 1, stream);
- count += fread(&OffsetMCIN, sizeof(uint32), 1, stream);
- count += fread(&OffsetMTEX, sizeof(uint32), 1, stream);
- count += fread(&OffsetMMDX, sizeof(uint32), 1, stream);
- count += fread(&OffsetMMID, sizeof(uint32), 1, stream);
- count += fread(&OffsetMWMO, sizeof(uint32), 1, stream);
- count += fread(&OffsetMWID, sizeof(uint32), 1, stream);
- count += fread(&OffsetMDDF, sizeof(uint32), 1, stream);
- count += fread(&OffsetMODF, sizeof(uint32), 1, stream);
- count += fread(&OffsetMFBO, sizeof(uint32), 1, stream);
- count += fread(&OffsetMH2O, sizeof(uint32), 1, stream);
- count += fread(&OffsetMTFX, sizeof(uint32), 1, stream);
-
- if (count != 12)
- printf("MHDR::Read: Failed to read some data expected 12, read %d\n", count);
+ Flags = stream->Read<uint32>();
+ OffsetMCIN = stream->Read<uint32>();
+ OffsetMTEX = stream->Read<uint32>();
+ OffsetMMDX = stream->Read<uint32>();
+ OffsetMMID = stream->Read<uint32>();
+ OffsetMWMO = stream->Read<uint32>();
+ OffsetMWID = stream->Read<uint32>();
+ OffsetMDDF = stream->Read<uint32>();
+ OffsetMODF = stream->Read<uint32>();
+ OffsetMFBO = stream->Read<uint32>();
+ OffsetMH2O = stream->Read<uint32>();
+ OffsetMTFX = stream->Read<uint32>();
}
-void ModelHeader::Read(FILE* stream)
+void ModelHeader::Read(Stream* stream)
{
- int count = 0;
-
- count += fread(&Magic, sizeof(char), 4, stream);
+ stream->Read(Magic, 4);
Magic[4] = '\0'; // null-terminate it.
- count += fread(&Version, sizeof(uint32), 1, stream);
- count += fread(&LengthModelName, sizeof(uint32), 1, stream);
- count += fread(&OffsetName, sizeof(uint32), 1, stream);
- count += fread(&ModelFlags, sizeof(uint32), 1, stream);
- count += fread(&CountGlobalSequences, sizeof(uint32), 1, stream);
- count += fread(&OffsetGlobalSequences, sizeof(uint32), 1, stream);
- count += fread(&CountAnimations, sizeof(uint32), 1, stream);
- count += fread(&OffsetAnimations, sizeof(uint32), 1, stream);
- count += fread(&CountAnimationLookup, sizeof(uint32), 1, stream);
- count += fread(&OffsetAnimationLookup, sizeof(uint32), 1, stream);
- count += fread(&CountBones, sizeof(uint32), 1, stream);
- count += fread(&OffsetBones, sizeof(uint32), 1, stream);
- count += fread(&CountKeyBoneLookup, sizeof(uint32), 1, stream);
- count += fread(&OffsetKeyBoneLookup, sizeof(uint32), 1, stream);
- count += fread(&CountVertices, sizeof(uint32), 1, stream);
- count += fread(&OffsetVertices, sizeof(uint32), 1, stream);
- count += fread(&CountViews, sizeof(uint32), 1, stream);
- count += fread(&CountColors, sizeof(uint32), 1, stream);
- count += fread(&OffsetColors, sizeof(uint32), 1, stream);
- count += fread(&CountTextures, sizeof(uint32), 1, stream);
- count += fread(&OffsetTextures, sizeof(uint32), 1, stream);
- count += fread(&CountTransparency, sizeof(uint32), 1, stream);
- count += fread(&OffsetTransparency, sizeof(uint32), 1, stream);
- count += fread(&CountUvAnimation, sizeof(uint32), 1, stream);
- count += fread(&OffsetUvAnimation, sizeof(uint32), 1, stream);
- count += fread(&CountTexReplace, sizeof(uint32), 1, stream);
- count += fread(&OffsetTexReplace, sizeof(uint32), 1, stream);
- count += fread(&CountRenderFlags, sizeof(uint32), 1, stream);
- count += fread(&OffsetRenderFlags, sizeof(uint32), 1, stream);
- count += fread(&CountBoneLookup, sizeof(uint32), 1, stream);
- count += fread(&OffsetBoneLookup, sizeof(uint32), 1, stream);
- count += fread(&CountTexLookup, sizeof(uint32), 1, stream);
- count += fread(&OffsetTexLookup, sizeof(uint32), 1, stream);
- count += fread(&CountTexUnits, sizeof(uint32), 1, stream);
- count += fread(&OffsetTexUnits, sizeof(uint32), 1, stream);
- count += fread(&CountTransLookup, sizeof(uint32), 1, stream);
- count += fread(&OffsetTransLookup, sizeof(uint32), 1, stream);
- count += fread(&CountUvAnimLookup, sizeof(uint32), 1, stream);
- count += fread(&OffsetUvAnimLookup, sizeof(uint32), 1, stream);
+ Version = stream->Read<uint32>();
+ LengthModelName = stream->Read<uint32>();
+ OffsetName = stream->Read<uint32>();
+ ModelFlags = stream->Read<uint32>();
+ CountGlobalSequences = stream->Read<uint32>();
+ OffsetGlobalSequences = stream->Read<uint32>();
+ CountAnimations = stream->Read<uint32>();
+ OffsetAnimations = stream->Read<uint32>();
+ CountAnimationLookup = stream->Read<uint32>();
+ OffsetAnimationLookup = stream->Read<uint32>();
+ CountBones = stream->Read<uint32>();
+ OffsetBones = stream->Read<uint32>();
+ CountKeyBoneLookup = stream->Read<uint32>();
+ OffsetKeyBoneLookup = stream->Read<uint32>();
+ CountVertices = stream->Read<uint32>();
+ OffsetVertices = stream->Read<uint32>();
+ CountViews = stream->Read<uint32>();
+ CountColors = stream->Read<uint32>();
+ OffsetColors = stream->Read<uint32>();
+ CountTextures = stream->Read<uint32>();
+ OffsetTextures = stream->Read<uint32>();
+ CountTransparency = stream->Read<uint32>();
+ OffsetTransparency = stream->Read<uint32>();
+ CountUvAnimation = stream->Read<uint32>();
+ OffsetUvAnimation = stream->Read<uint32>();
+ CountTexReplace = stream->Read<uint32>();
+ OffsetTexReplace = stream->Read<uint32>();
+ CountRenderFlags = stream->Read<uint32>();
+ OffsetRenderFlags = stream->Read<uint32>();
+ CountBoneLookup = stream->Read<uint32>();
+ OffsetBoneLookup = stream->Read<uint32>();
+ CountTexLookup = stream->Read<uint32>();
+ OffsetTexLookup = stream->Read<uint32>();
+ CountTexUnits = stream->Read<uint32>();
+ OffsetTexUnits = stream->Read<uint32>();
+ CountTransLookup = stream->Read<uint32>();
+ OffsetTransLookup = stream->Read<uint32>();
+ CountUvAnimLookup = stream->Read<uint32>();
+ OffsetUvAnimLookup = stream->Read<uint32>();
VertexBox[0] = Vector3::Read(stream);
VertexBox[1] = Vector3::Read(stream);
- count += fread(&VertexRadius, sizeof(float), 1, stream);
+ VertexRadius = stream->Read<float>();
BoundingBox[0] = Vector3::Read(stream);
BoundingBox[1] = Vector3::Read(stream);
- count += fread(&BoundingRadius, sizeof(float), 1, stream);
- count += fread(&CountBoundingTriangles, sizeof(uint32), 1, stream);
- count += fread(&OffsetBoundingTriangles, sizeof(uint32), 1, stream);
- count += fread(&CountBoundingVertices, sizeof(uint32), 1, stream);
- count += fread(&OffsetBoundingVertices, sizeof(uint32), 1, stream);
- count += fread(&CountBoundingNormals, sizeof(uint32), 1, stream);
- count += fread(&OffsetBoundingNormals, sizeof(uint32), 1, stream);
-
- if (count != 51)
- printf("ModelHeader::Read: Failed to read some data expected 51, read %d\n", count);
-
-}
-
-WorldModelHeader WorldModelHeader::Read(FILE* stream)
-{
- WorldModelHeader ret;
- int count = 0;
-
- count += fread(&ret.CountMaterials, sizeof(uint32), 1, stream);
- count += fread(&ret.CountGroups, sizeof(uint32), 1, stream);
- count += fread(&ret.CountPortals, sizeof(uint32), 1, stream);
- count += fread(&ret.CountLights, sizeof(uint32), 1, stream);
- count += fread(&ret.CountModels, sizeof(uint32), 1, stream);
- count += fread(&ret.CountDoodads, sizeof(uint32), 1, stream);
- count += fread(&ret.CountSets, sizeof(uint32), 1, stream);
- count += fread(&ret.AmbientColorUnk, sizeof(uint32), 1, stream);
- count += fread(&ret.WmoId, sizeof(uint32), 1, stream);
- ret.BoundingBox[0] = Vector3::Read(stream);
- ret.BoundingBox[1] = Vector3::Read(stream);
- count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream);
-
- if (count != 10)
- printf("WorldModelHeader::Read: Failed to read some data expected 10, read %d\n", count);
-
- return ret;
+ BoundingRadius = stream->Read<float>();
+ CountBoundingTriangles = stream->Read<uint32>();
+ OffsetBoundingTriangles = stream->Read<uint32>();
+ CountBoundingVertices = stream->Read<uint32>();
+ OffsetBoundingVertices = stream->Read<uint32>();
+ CountBoundingNormals = stream->Read<uint32>();
+ OffsetBoundingNormals = stream->Read<uint32>();
+}
+
+void WorldModelHeader::Read(Stream* stream)
+{
+ CountMaterials = stream->Read<uint32>();
+ CountGroups = stream->Read<uint32>();
+ CountPortals = stream->Read<uint32>();
+ CountLights = stream->Read<uint32>();
+ CountModels = stream->Read<uint32>();
+ CountDoodads = stream->Read<uint32>();
+ CountSets = stream->Read<uint32>();
+ AmbientColorUnk = stream->Read<uint32>();
+ WmoId = stream->Read<uint32>();
+ BoundingBox[0] = Vector3::Read(stream);
+ BoundingBox[1] = Vector3::Read(stream);
+ LiquidTypeRelated = stream->Read<uint32>();
}
-DoodadInstance DoodadInstance::Read(FILE* stream)
+DoodadInstance DoodadInstance::Read(Stream* stream)
{
DoodadInstance ret;
- int count = 0;
- count += fread(&ret.FileOffset, sizeof(uint32), 1, stream);
+ ret.FileOffset = stream->Read<uint32>();
ret.Position = Vector3::Read(stream);
- count += fread(&ret.QuatW, sizeof(float), 1, stream);
- count += fread(&ret.QuatX, sizeof(float), 1, stream);
- count += fread(&ret.QuatY, sizeof(float), 1, stream);
- count += fread(&ret.QuatZ, sizeof(float), 1, stream);
- count += fread(&ret.Scale, sizeof(float), 1, stream);
- count += fread(&ret.LightColor, sizeof(uint32), 1, stream);
-
- if (count != 7)
- printf("DoodadInstance::Read: Failed to read some data expected 7, read %d\n", count);
-
+ ret.QuatW = stream->Read<float>();
+ ret.QuatX = stream->Read<float>();
+ ret.QuatY = stream->Read<float>();
+ ret.QuatZ = stream->Read<float>();
+ ret.Scale = stream->Read<float>();
+ ret.LightColor = stream->Read<uint32>();
return ret;
}
-DoodadSet DoodadSet::Read(FILE* stream)
+DoodadSet DoodadSet::Read(Stream* stream)
{
DoodadSet ret;
- char name[21];
- int count = 0;
-
- count += fread(&name, sizeof(char), 20, stream);
- name[20] = '\0';
- ret.Name = name;
- count += fread(&ret.FirstInstanceIndex, sizeof(uint32), 1, stream);
- count += fread(&ret.CountInstances, sizeof(uint32), 1, stream);
- count += fread(&ret.UnknownZero, sizeof(uint32), 1, stream);
-
- if (count != 23)
- printf("DoodadSet::Read: Failed to read some data expected 23, read %d\n", count);
-
+ char* name = stream->Read(20);
+ ret.Name = std::string(name, 20);
+ delete[] name;
+ ret.FirstInstanceIndex = stream->Read<uint32>();
+ ret.CountInstances = stream->Read<uint32>();
+ ret.UnknownZero = stream->Read<uint32>();
+
return ret;
}
-LiquidHeader LiquidHeader::Read(FILE* stream)
+void LiquidHeader::Read(Stream* stream)
{
- LiquidHeader ret;
- int count = 0;
- count += fread(&ret.CountXVertices, sizeof(uint32), 1, stream);
- count += fread(&ret.CountYVertices, sizeof(uint32), 1, stream);
- count += fread(&ret.Width, sizeof(uint32), 1, stream);
- count += fread(&ret.Height, sizeof(uint32), 1, stream);
- ret.BaseLocation = Vector3::Read(stream);
- count += fread(&ret.MaterialId, sizeof(uint16), 1, stream);
-
- if (count != 5)
- printf("LiquidHeader::Read: Failed to read some data expected 5, read %d\n", count);
-
- return ret;
+ CountXVertices = stream->Read<uint32>();
+ CountYVertices = stream->Read<uint32>();
+ Width = stream->Read<uint32>();
+ Height = stream->Read<uint32>();
+ BaseLocation = Vector3::Read(stream);
+ MaterialId = stream->Read<uint16>();
}
-LiquidData LiquidData::Read(FILE* stream, LiquidHeader& header)
+void LiquidData::Read(Stream* stream, LiquidHeader& header)
{
- LiquidData ret;
- ret.HeightMap = new float*[header.CountXVertices];
+ CountXVertices = header.CountXVertices;
+ Width = header.Width;
+
+ HeightMap = new float*[header.CountXVertices];
for (uint32 i = 0; i < header.CountXVertices; ++i)
- ret.HeightMap[i] = new float[header.CountYVertices];
+ HeightMap[i] = new float[header.CountYVertices];
- ret.RenderFlags = new uint8*[header.Width];
+ RenderFlags = new uint8*[header.Width];
for (uint32 i = 0; i < header.Width; ++i)
- ret.RenderFlags[i] = new uint8[header.Height];
+ RenderFlags[i] = new uint8[header.Height];
for (uint32 y = 0; y < header.CountYVertices; y++)
{
for (uint32 x = 0; x < header.CountXVertices; x++)
{
- uint32 discard;
- float tmp;
- if (fread(&discard, sizeof(uint32), 1, stream) == 1 &&
- fread(&tmp, sizeof(float), 1, stream) == 1)
- {
- ret.HeightMap[x][y] = tmp;
- }
+ stream->Skip<uint32>();
+ HeightMap[x][y] = stream->Read<float>();
}
}
for (uint32 y = 0; y < header.Height; y++)
- {
for (uint32 x = 0; x < header.Width; x++)
- {
- uint8 tmp = 0;
- if (fread(&tmp, sizeof(uint8), 1, stream) == 1)
- ret.RenderFlags[x][y] = tmp;
- }
- }
-
- return ret;
+ RenderFlags[x][y] = stream->Read<uint8>();
}
-H2ORenderMask H2ORenderMask::Read(FILE* stream)
+H2ORenderMask H2ORenderMask::Read(Stream* stream)
{
H2ORenderMask ret;
- int32 count;
- if ((count = fread(&ret.Mask, sizeof(uint8), 8, stream)) != 8)
- printf("H2OHeader::Read: Failed to read some data expected 8, read %d\n", count);
+ stream->Read(ret.Mask, sizeof(uint8) * 8);
return ret;
}
@@ -497,38 +403,42 @@ bool MCNKLiquidData::IsWater(int x, int y, float height)
return false;
}
-H2OHeader H2OHeader::Read(FILE* stream)
+MCNKLiquidData::~MCNKLiquidData()
{
- H2OHeader ret;
- int count = 0;
- count += fread(&ret.OffsetInformation, sizeof(uint32), 1, stream);
- count += fread(&ret.LayerCount, sizeof(uint32), 1, stream);
- count += fread(&ret.OffsetRender, sizeof(uint32), 1, stream);
+ if (!Heights)
+ return;
- if (count != 3)
- printf("H2OHeader::Read: Failed to read some data expected 3, read %d\n", count);
+ for (uint32 i = 0; i < 9; ++i)
+ delete[] Heights[i];
+ delete[] Heights;
+ Heights = NULL;
+}
+H2OHeader H2OHeader::Read(Stream* stream)
+{
+ H2OHeader ret;
+
+ ret.OffsetInformation = stream->Read<uint32>();
+ ret.LayerCount = stream->Read<uint32>();
+ ret.OffsetRender = stream->Read<uint32>();
+
return ret;
}
-H2OInformation H2OInformation::Read(FILE* stream)
+H2OInformation H2OInformation::Read(Stream* stream)
{
H2OInformation ret;
- int count = 0;
- count += fread(&ret.LiquidType, sizeof(uint16), 1, stream);
- count += fread(&ret.Flags, sizeof(uint16), 1, stream);
- count += fread(&ret.HeightLevel1, sizeof(float), 1, stream);
- count += fread(&ret.HeightLevel2, sizeof(float), 1, stream);
- count += fread(&ret.OffsetX, sizeof(uint8), 1, stream);
- count += fread(&ret.OffsetY, sizeof(uint8), 1, stream);
- count += fread(&ret.Width, sizeof(uint8), 1, stream);
- count += fread(&ret.Height, sizeof(uint8), 1, stream);
- count += fread(&ret.OffsetMask2, sizeof(uint32), 1, stream);
- count += fread(&ret.OffsetHeightmap, sizeof(uint32), 1, stream);
-
- if (count != 10)
- printf("H2OInformation::Read: Failed to read some data expected 10, read %d\n", count);
-
+ ret.LiquidType = stream->Read<uint16>();
+ ret.Flags = stream->Read<uint16>();
+ ret.HeightLevel1 = stream->Read<float>();
+ ret.HeightLevel2 = stream->Read<float>();
+ ret.OffsetX = stream->Read<uint8>();
+ ret.OffsetY = stream->Read<uint8>();
+ ret.Width = stream->Read<uint8>();
+ ret.Height = stream->Read<uint8>();
+ ret.OffsetMask2 = stream->Read<uint32>();
+ ret.OffsetHeightmap = stream->Read<uint32>();
+
return ret;
}
@@ -541,24 +451,30 @@ char* Utils::GetPlainName(const char* FileName)
return (char*)FileName;
}
-WMOGroupHeader WMOGroupHeader::Read( FILE* stream )
+WMOGroupHeader WMOGroupHeader::Read(Stream* stream)
{
WMOGroupHeader ret;
- int count = 0;
- count += fread(&ret.OffsetGroupName, sizeof(uint32), 1, stream);
- count += fread(&ret.OffsetDescriptiveName, sizeof(uint32), 1, stream);
- count += fread(&ret.Flags, sizeof(uint32), 1, stream);
+ ret.OffsetGroupName = stream->Read<uint32>();
+ ret.OffsetDescriptiveName = stream->Read<uint32>();
+ ret.Flags = stream->Read<uint32>();
ret.BoundingBox[0] = Vector3::Read(stream);
ret.BoundingBox[1] = Vector3::Read(stream);
- count += fread(&ret.OffsetPortals, sizeof(uint32), 1, stream);
- count += fread(&ret.CountPortals, sizeof(uint32), 1, stream);
- count += fread(&ret.CountBatches, sizeof(uint16), 4, stream);
- count += fread(&ret.Fogs, sizeof(uint8), 4, stream);
- count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream);
- count += fread(&ret.WmoId, sizeof(uint32), 1, stream);
-
- if (count != 15)
- printf("WMOGroupHeader::Read: Failed to read some data expected 15, read %d\n", count);
-
+ ret.OffsetPortals = stream->Read<uint32>();
+ ret.CountPortals = stream->Read<uint32>();
+ stream->Read(ret.CountBatches, sizeof(uint16) * 4);
+ stream->Read(ret.Fogs, sizeof(uint8) * 4);
+ ret.LiquidTypeRelated = stream->Read<uint32>();
+ ret.WmoId = stream->Read<uint32>();
+
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;
+}
diff --git a/src/tools/mesh_extractor/Utils.h b/src/tools/mesh_extractor/Utils.h
index 612282f3e8f..8424d92baa9 100644
--- a/src/tools/mesh_extractor/Utils.h
+++ b/src/tools/mesh_extractor/Utils.h
@@ -27,6 +27,8 @@
#include "Define.h"
#include "Constants.h"
+#include "Stream.h"
+
#include <ace/Stack_Trace.h>
struct WorldModelDefinition;
@@ -59,7 +61,7 @@ struct Vector3
return Vector3(x * s, y * s, z * s);
}
- static Vector3 Read(FILE* file);
+ static Vector3 Read(Stream* file);
};
struct TilePos
@@ -100,7 +102,7 @@ public:
uint32 AreaId;
uint32 MapObjectRefs;
uint32 Holes;
- uint32* LowQualityTextureMap;
+ uint32 LowQualityTextureMap[4];
uint32 PredTex;
uint32 NumberEffectDoodad;
uint32 OffsetMCSE;
@@ -110,7 +112,7 @@ public:
Vector3 Position;
uint32 OffsetMCCV;
- void Read(FILE* stream);
+ void Read(Stream* stream);
};
class MHDR
@@ -130,7 +132,7 @@ public:
uint32 OffsetMH2O;
uint32 OffsetMTFX;
- void Read(FILE* stream);
+ void Read(Stream* stream);
};
class ModelHeader
@@ -187,7 +189,7 @@ public:
uint32 CountBoundingNormals;
uint32 OffsetBoundingNormals;
- void Read(FILE* stream);
+ void Read(Stream* stream);
};
class WorldModelHeader
@@ -206,7 +208,7 @@ public:
Vector3 BoundingBox[2];
uint32 LiquidTypeRelated;
- static WorldModelHeader Read(FILE* stream);
+ void Read(Stream* stream);
};
class DoodadInstance
@@ -223,7 +225,7 @@ public:
float Scale;
uint32 LightColor;
- static DoodadInstance Read(FILE* stream);
+ static DoodadInstance Read(Stream* stream);
};
class DoodadSet
@@ -235,13 +237,13 @@ public:
uint32 CountInstances;
uint32 UnknownZero;
- static DoodadSet Read(FILE* stream);
+ static DoodadSet Read(Stream* stream);
};
class LiquidHeader
{
public:
- LiquidHeader() {}
+ LiquidHeader() : CountXVertices(0), CountYVertices(0), Width(0), Height(0), BaseLocation(0,0,0), MaterialId(0) {}
uint32 CountXVertices;
uint32 CountYVertices;
uint32 Width;
@@ -249,22 +251,36 @@ public:
Vector3 BaseLocation;
uint16 MaterialId;
- static LiquidHeader Read(FILE* stream);
+ void Read(Stream* stream);
};
class LiquidData
{
public:
- LiquidData() {}
+ LiquidData() : HeightMap(NULL), RenderFlags(NULL), CountXVertices(0), Width(0) {}
+
+ ~LiquidData()
+ {
+ for (uint32 i = 0; i < CountXVertices; ++i)
+ delete[] HeightMap[i];
+ delete[] HeightMap;
+
+ for (uint32 i = 0; i < Width; ++i)
+ delete[] RenderFlags[i];
+ delete[] RenderFlags;
+ }
+
float** HeightMap;
uint8** RenderFlags;
+ uint32 CountXVertices;
+ uint32 Width;
- bool ShouldRender(int x, int y)
+ bool ShouldRender(int x, int y) const
{
return RenderFlags[x][y] != 0x0F;
}
- static LiquidData Read(FILE* stream, LiquidHeader& header);
+ void Read(Stream* stream, LiquidHeader& header);
};
class H2ORenderMask
@@ -278,14 +294,15 @@ public:
return (Mask[y] >> x & 1) != 0;
}
- static H2ORenderMask Read(FILE* stream);
+ static H2ORenderMask Read(Stream* stream);
};
class MCNKLiquidData
{
public:
- MCNKLiquidData() {}
+ MCNKLiquidData() : Heights(NULL) {}
MCNKLiquidData(float** heights, H2ORenderMask mask) : Heights(heights), Mask(mask) {}
+ ~MCNKLiquidData();
float** Heights;
H2ORenderMask Mask;
@@ -301,7 +318,7 @@ public:
uint32 LayerCount;
uint32 OffsetRender;
- static H2OHeader Read(FILE* stream);
+ static H2OHeader Read(Stream* stream);
};
class H2OInformation
@@ -319,7 +336,7 @@ public:
uint32 OffsetMask2;
uint32 OffsetHeightmap;
- static H2OInformation Read(FILE* stream);
+ static H2OInformation Read(Stream* stream);
};
class WMOGroupHeader
@@ -338,7 +355,7 @@ public:
uint32 LiquidTypeRelated;
uint32 WmoId;
- static WMOGroupHeader Read(FILE* stream);
+ static WMOGroupHeader Read(Stream* stream);
};
// Dummy class to act as an interface.
@@ -351,7 +368,7 @@ public:
};
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
-#define MMAP_VERSION 3
+#define MMAP_VERSION 5
struct MmapTileHeader
{
@@ -359,18 +376,13 @@ struct MmapTileHeader
uint32 dtVersion;
uint32 mmapVersion;
uint32 size;
- bool usesLiquids;
-
- MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
- mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
+ bool usesLiquids : 1;
};
class Utils
{
public:
- static void Reverse(char word[]);
- static std::string ReadString(FILE* file);
- static uint32 Size(FILE* file);
+ static void Reverse(std::string& str);
static Vector3 ToRecast(const Vector3& val );
static std::string GetAdtPath(const std::string& world, int x, int y);
static std::string FixModelPath(const std::string& path);
@@ -394,14 +406,15 @@ public:
return false;
return true;
}
- static std::string Replace( std::string str, const std::string& oldStr, const std::string& newStr );
- static void CreateDir( const std::string& Path );
- static void SaveToDisk(FILE* stream, const std::string& path);
- static Vector3 ToWoWCoords(const Vector3& vec );
- static std::string GetExtension( std::string path );
+ static std::string Replace(std::string str, const std::string& oldStr, const std::string& newStr);
+ static void CreateDir(const std::string& Path);
+ static void SaveToDisk(Stream* stream, const std::string& path);
+ static Vector3 ToWoWCoords(const Vector3& vec);
+ static std::string GetExtension( std::string path);
static char* GetPlainName(const char* FileName);
- static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate = true);
- static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false );
- static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate = true );
+ static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3 vec, bool translate = true);
+ static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false);
+ static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, const Vector3& vec, bool translate = true);
+ static void InitializeMmapTileHeader(MmapTileHeader& header);
};
#endif
diff --git a/src/tools/mesh_extractor/WDT.cpp b/src/tools/mesh_extractor/WDT.cpp
index 07aec95365e..c4afec32a63 100644
--- a/src/tools/mesh_extractor/WDT.cpp
+++ b/src/tools/mesh_extractor/WDT.cpp
@@ -20,6 +20,7 @@
#include "ChunkedData.h"
#include "Utils.h"
#include "WorldModelHandler.h"
+#include "Cache.h"
WDT::WDT(std::string file) : IsGlobalModel(false), IsValid(false), Model(NULL)
{
@@ -37,8 +38,8 @@ void WDT::ReadGlobalModel()
IsGlobalModel = true;
ModelDefinition = WorldModelDefinition::Read(defChunk->GetStream());
- ModelFile = Utils::ReadString(fileChunk->GetStream());
- Model = new WorldModelRoot(ModelFile);
+ ModelFile = fileChunk->GetStream()->ReadString();
+ Model = Cache->WorldModelCache.Get(ModelFile);
}
void WDT::ReadTileTable()
@@ -47,20 +48,14 @@ void WDT::ReadTileTable()
if (!chunk)
return;
IsValid = true;
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
for (int y = 0; y < 64; ++y)
{
for (int x = 0; x < 64; ++x)
{
const uint32 hasTileFlag = 0x1;
- uint32 flags;
- uint32 discard;
- int count = 0;
- count += fread(&flags, sizeof(uint32), 1, stream);
- count += fread(&discard, sizeof(uint32), 1, stream);
-
- if (count != 2)
- printf("WDT::ReadTileTable: Failed to read some data expected 2, read %d\n", count);
+ uint32 flags = stream->Read<uint32>();
+ stream->Skip<uint32>();
if (flags & hasTileFlag)
TileTable.push_back(TilePos(x, y));
@@ -69,9 +64,9 @@ void WDT::ReadTileTable()
}
}
-bool WDT::HasTile( int x, int y )
+bool WDT::HasTile( int x, int y ) const
{
- for (std::vector<TilePos>::iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr)
+ for (std::vector<TilePos>::const_iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr)
if (itr->X == x && itr->Y == y)
return true;
return false;
diff --git a/src/tools/mesh_extractor/WDT.h b/src/tools/mesh_extractor/WDT.h
index d1e8e30918d..0deb5830e75 100644
--- a/src/tools/mesh_extractor/WDT.h
+++ b/src/tools/mesh_extractor/WDT.h
@@ -36,8 +36,8 @@ public:
bool IsValid;
std::string ModelFile;
WorldModelDefinition ModelDefinition;
- WorldModelRoot* Model;
- bool HasTile(int x, int y);
+ WorldModelRoot const* Model;
+ bool HasTile(int x, int y) const;
private:
void ReadGlobalModel();
void ReadTileTable();
diff --git a/src/tools/mesh_extractor/WorldModelGroup.cpp b/src/tools/mesh_extractor/WorldModelGroup.cpp
index 6ea72d6edbe..3e16894ced6 100644
--- a/src/tools/mesh_extractor/WorldModelGroup.cpp
+++ b/src/tools/mesh_extractor/WorldModelGroup.cpp
@@ -20,14 +20,37 @@
#include "Chunk.h"
#include "Utils.h"
-WorldModelGroup::WorldModelGroup( std::string path, int groupIndex ) : GroupIndex(groupIndex), MOBA(NULL), IsBad(false), HasLiquidData(false)
+WorldModelGroup::WorldModelGroup(std::string path, int groupIndex) : SubData(NULL), GroupIndex(groupIndex), MOBA(NULL), MOBALength(0), HasLiquidData(false), IsBad(false)
{
Data = new ChunkedData(path);
- if (!Data->Stream)
+ if (!Data->_Stream)
{
IsBad = true;
return;
}
+ Load(path);
+}
+
+WorldModelGroup::WorldModelGroup(Stream* stream, std::string path, int groupIndex) : SubData(NULL), GroupIndex(groupIndex), MOBA(NULL), MOBALength(0), HasLiquidData(false), IsBad(false)
+{
+ Data = new ChunkedData(stream, stream->GetSize());
+ Load(path);
+}
+
+WorldModelGroup::~WorldModelGroup()
+{
+ // Temporarily delete the underlying stream, it is the same pointer for both Data and SubData.
+ // @TODO: Remove this code once the ChunkedData destructor properly releases _Stream
+ delete Data->_Stream;
+
+ delete Data;
+ delete SubData;
+ delete[] MOBA;
+
+}
+
+void WorldModelGroup::Load(std::string& path)
+{
Chunk* mainChunk = Data->GetChunkByName("MOGP");
int32 firstSub = mainChunk->FindSubChunkOffset("MOPY");
if (firstSub == -1)
@@ -35,8 +58,8 @@ WorldModelGroup::WorldModelGroup( std::string path, int groupIndex ) : GroupInde
Name = Utils::GetPlainName(path.c_str());
- FILE* stream = mainChunk->GetStream();
- fseek(stream, firstSub, SEEK_SET);
+ Stream* stream = mainChunk->GetStream();
+ stream->Seek(firstSub, SEEK_SET);
SubData = new ChunkedData(stream, mainChunk->Length - firstSub);
ReadHeader();
@@ -57,7 +80,7 @@ void WorldModelGroup::ReadNormals()
uint32 normalCount = chunk->Length / 12;
ASSERT(normalCount == Vertices.size() && "normalCount is different than the Vertices count");
Normals.reserve(normalCount);
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
for (uint32 i = 0; i < normalCount; i++)
Normals.push_back(Vector3::Read(stream));
}
@@ -69,9 +92,9 @@ void WorldModelGroup::ReadLiquid()
return;
HasLiquidData = true;
- FILE* stream = chunk->GetStream();
- LiquidDataHeader = LiquidHeader::Read(stream);
- LiquidDataGeometry = LiquidData::Read(stream, LiquidDataHeader);
+ Stream* stream = chunk->GetStream();
+ LiquidDataHeader.Read(stream);
+ LiquidDataGeometry.Read(stream, LiquidDataHeader);
}
void WorldModelGroup::ReadVertices()
@@ -82,7 +105,7 @@ void WorldModelGroup::ReadVertices()
uint32 verticeCount = chunk->Length / 12;
Vertices.reserve(verticeCount);
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
for (uint32 i = 0; i < verticeCount; i++)
Vertices.push_back(Vector3::Read(stream));
}
@@ -95,19 +118,13 @@ void WorldModelGroup::ReadTriangles()
uint32 triangleCount = chunk->Length / 6;
ASSERT(triangleCount == TriangleFlags.size() && "triangleCount != TriangleFlags.size()");
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
Triangles.reserve(triangleCount);
for (uint32 i = 0; i < triangleCount; i++)
{
- uint16 v0;
- uint16 v1;
- uint16 v2;
- int count = 0;
- count += fread(&v0, sizeof(uint16), 1, stream);
- count += fread(&v1, sizeof(uint16), 1, stream);
- count += fread(&v2, sizeof(uint16), 1, stream);
- if (count != 3)
- printf("WorldModelGroup::ReadMaterials: Error reading data, expected 3, read %d\n", count);
+ uint16 v0 = stream->Read<uint16>();
+ uint16 v1 = stream->Read<uint16>();
+ uint16 v2 = stream->Read<uint16>();
Triangles.push_back(Triangle<uint16>(Constants::TRIANGLE_TYPE_WMO, v0, v1, v2));
}
@@ -119,20 +136,15 @@ void WorldModelGroup::ReadMaterials()
if (!chunk)
return;
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
uint32 triangleCount = chunk->Length / 2;
TriangleFlags.reserve(triangleCount);
TriangleMaterials.reserve(triangleCount);
for (uint32 i = 0; i < triangleCount; i++)
{
- uint8 tmp;
- if (fread(&tmp, sizeof(uint8), 1, stream) != 1)
- printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n");
- TriangleFlags.push_back(tmp);
+ TriangleFlags.push_back(stream->Read<uint8>());
// Read again for material.
- if (fread(&tmp, sizeof(uint8), 1, stream) != 1)
- printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n");
- TriangleMaterials.push_back(tmp);
+ TriangleMaterials.push_back(stream->Read<uint8>());
}
}
@@ -142,7 +154,7 @@ void WorldModelGroup::ReadHeader()
if (!chunk)
return;
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
Header = WMOGroupHeader::Read(stream);
}
@@ -154,7 +166,5 @@ void WorldModelGroup::ReadBatches()
MOBALength = chunk->Length / 2;
MOBA = new uint16[MOBALength];
- uint32 count = (uint32)fread(MOBA, sizeof(uint16), MOBALength, chunk->GetStream());
- if (count != MOBALength)
- printf("WorldModelGroup::ReadBatches: Error reading data, expected %u, read %u\n", MOBALength, count);
+ chunk->GetStream()->Read(MOBA, sizeof(uint16) * MOBALength);
}
diff --git a/src/tools/mesh_extractor/WorldModelGroup.h b/src/tools/mesh_extractor/WorldModelGroup.h
index b3c2c2bd940..20d453ee028 100644
--- a/src/tools/mesh_extractor/WorldModelGroup.h
+++ b/src/tools/mesh_extractor/WorldModelGroup.h
@@ -24,6 +24,10 @@ class WorldModelGroup
{
public:
WorldModelGroup(std::string path, int groupIndex);
+ WorldModelGroup(Stream* stream, std::string path, int groupIndex);
+ ~WorldModelGroup();
+ void Load(std::string& path);
+
ChunkedData* Data;
ChunkedData* SubData;
int GroupIndex;
diff --git a/src/tools/mesh_extractor/WorldModelHandler.cpp b/src/tools/mesh_extractor/WorldModelHandler.cpp
index 7c0acbc38e4..18a90365c5b 100644
--- a/src/tools/mesh_extractor/WorldModelHandler.cpp
+++ b/src/tools/mesh_extractor/WorldModelHandler.cpp
@@ -21,27 +21,24 @@
#include "Cache.h"
#include "Model.h"
#include "Define.h"
+#include "Stream.h"
#include "G3D/Matrix4.h"
#include "G3D/Quat.h"
#include <cstdio>
-WorldModelDefinition WorldModelDefinition::Read( FILE* file )
+WorldModelDefinition WorldModelDefinition::Read(Stream* file)
{
WorldModelDefinition ret;
- int count = 0;
- count += fread(&ret.MwidIndex, sizeof(uint32), 1, file);
- count += fread(&ret.UniqueId, sizeof(uint32), 1, file);
+ ret.MwidIndex = file->Read<uint32>();
+ ret.UniqueId = file->Read<uint32>();
ret.Position = Vector3::Read(file);
ret.Rotation = Vector3::Read(file);
ret.UpperExtents = Vector3::Read(file);
ret.LowerExtents = Vector3::Read(file);
- count += fread(&ret.Flags, sizeof(uint16), 1, file);
- count += fread(&ret.DoodadSet, sizeof(uint16), 1, file);
- uint32 discard;
- count += fread(&discard, sizeof(uint32), 1, file);
-
- if (count != 5)
- printf("WorldModelDefinition::Read: Error reading data, expected 5, read %d\n", count);
+ ret.Flags = file->Read<uint16>();
+ ret.DoodadSet = file->Read<uint16>();
+ file->Read<uint32>(); // Discarded
+
return ret;
}
@@ -58,14 +55,12 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk )
return;
uint32 refCount = mcnk->Header.MapObjectRefs;
- FILE* stream = mcnk->Source->GetStream();
- fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
+ Stream* stream = mcnk->Source->GetStream();
+ stream->Seek(mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
// Start looping at the last Doodad Ref index
for (uint32 i = mcnk->Header.DoodadRefs; i < refCount; i++)
{
- int32 index;
- if (fread(&index, sizeof(int32), 1, stream) != 1)
- printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n");
+ int32 index = stream->Read<int32>();
if (index < 0 || uint32(index) >= _definitions->size())
continue;
@@ -80,12 +75,7 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk )
continue;
std::string path = (*_paths)[wmo.MwidIndex];
- WorldModelRoot* model = Cache->WorldModelCache.Get(path);
- if (!model)
- {
- model = new WorldModelRoot(path);
- Cache->WorldModelCache.Insert(path, model);
- }
+ WorldModelRoot const* model = Cache->WorldModelCache.Get(path);
Vertices.reserve(1000);
Triangles.reserve(1000);
@@ -93,15 +83,16 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk )
InsertModelGeometry(Vertices, Triangles, wmo, model);
}
// Restore the stream position
- fseek(stream, mcnk->Source->Offset, SEEK_SET);
+ stream->Seek(mcnk->Source->Offset, SEEK_SET);
}
-void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate )
+void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot const* root, bool translate )
{
- for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
+ for (std::vector<WorldModelGroup*>::const_iterator groupItr = root->Groups.begin(); groupItr != root->Groups.end(); ++groupItr)
{
+ WorldModelGroup const* group = *groupItr;
uint32 vertOffset = verts.size();
- for (std::vector<Vector3>::iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2)
+ for (std::vector<Vector3>::const_iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2)
{
Vector3 v = Utils::TransformDoodadVertex(def, *itr2, translate);
// If translate is false, then we were called directly from the TileBuilder to add data to it's _Geometry member, hence, we have to manually convert the vertices to Recast format.
@@ -111,8 +102,9 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v
for (uint32 i = 0; i < group->Triangles.size(); ++i)
{
// only include colliding tris
- if ((group->TriangleFlags[i] & 0x04) != 0 && group->TriangleMaterials[i] != 0xFF)
+ if ((group->TriangleFlags[i] & 0x04) != 0 || group->TriangleMaterials[i] == 0xFF)
continue;
+
Triangle<uint16> tri = group->Triangles[i];
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, tri.V0 + vertOffset, tri.V1 + vertOffset, tri.V2 + vertOffset));
}
@@ -132,38 +124,33 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v
for (std::vector<DoodadInstance>::iterator instance = instances.begin(); instance != instances.end(); ++instance)
{
- Model* model = Cache->ModelCache.Get(instance->File);
- if (!model)
- {
- model = new Model(instance->File);
- Cache->ModelCache.Insert(instance->File, model);
- }
+ Model const* model = Cache->ModelCache.Get(instance->File);
if (!model->IsCollidable)
continue;
int vertOffset = verts.size();
- for (std::vector<Vector3>::iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2)
+ for (std::vector<Vector3>::const_iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2)
{
Vector3 v = Utils::TransformDoodadVertex(def, Utils::TransformWmoDoodad(*instance, def, *itr2, false), translate);
verts.push_back(translate ? v : Utils::ToRecast(v));
}
- for (std::vector<Triangle<uint16> >::iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2)
+ for (std::vector<Triangle<uint16> >::const_iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2)
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, itr2->V0 + vertOffset, itr2->V1 + vertOffset, itr2->V2 + vertOffset));
}
- for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
+ for (std::vector<WorldModelGroup*>::const_iterator groupItr = root->Groups.begin(); groupItr != root->Groups.end(); ++groupItr)
{
+ WorldModelGroup const* group = *groupItr;
if (!group->HasLiquidData)
continue;
const LiquidHeader& liquidHeader = group->LiquidDataHeader;
- LiquidData& liquidDataGeometry = group->LiquidDataGeometry;
+ const LiquidData& liquidDataGeometry = group->LiquidDataGeometry;
for (uint32 y = 0; y < liquidHeader.Height; y++)
{
for (uint32 x = 0; x < liquidHeader.Width; x++)
{
-
if (!liquidDataGeometry.ShouldRender(x, y))
continue;
@@ -202,7 +189,7 @@ void WorldModelHandler::ReadDefinitions()
uint32 definitionCount = chunk->Length / definitionSize;
_definitions = new std::vector<WorldModelDefinition>;
_definitions->reserve(definitionCount);
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
for (uint32 i = 0; i < definitionCount; i++)
_definitions->push_back(WorldModelDefinition::Read(stream));
}
@@ -219,14 +206,13 @@ void WorldModelHandler::ReadModelPaths()
_paths->reserve(paths);
for (uint32 i = 0; i < paths; i++)
{
- FILE* stream = mwid->GetStream();
- fseek(stream, i * 4, SEEK_CUR);
- uint32 offset;
- if (fread(&offset, sizeof(uint32), 1, stream) != 1)
- printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n");
- FILE* dataStream = mwmo->GetStream();
- fseek(dataStream, offset + mwmo->Offset, SEEK_SET);
- _paths->push_back(Utils::ReadString(dataStream));
+ Stream* stream = mwid->GetStream();
+ stream->Seek(i * 4, SEEK_CUR);
+ uint32 offset = stream->Read<uint32>();
+
+ Stream* dataStream = mwmo->GetStream();
+ dataStream->Seek(offset + mwmo->Offset, SEEK_SET);
+ _paths->push_back(dataStream->ReadString());
}
}
diff --git a/src/tools/mesh_extractor/WorldModelHandler.h b/src/tools/mesh_extractor/WorldModelHandler.h
index dd030e4521f..ddc6f589147 100644
--- a/src/tools/mesh_extractor/WorldModelHandler.h
+++ b/src/tools/mesh_extractor/WorldModelHandler.h
@@ -39,7 +39,7 @@ public:
uint16 Flags;
uint16 DoodadSet;
- static WorldModelDefinition Read(FILE* file);
+ static WorldModelDefinition Read(Stream* file);
};
class WorldModelHandler : public ObjectDataHandler
@@ -50,8 +50,8 @@ public:
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32> > Triangles;
- bool IsSane() { return _definitions && _paths; }
- static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate = true);
+ bool IsSane() const { return _definitions && _paths; }
+ static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot const* root, bool translate = true);
protected:
void ProcessInternal(MapChunk* data);
private:
diff --git a/src/tools/mesh_extractor/WorldModelRoot.cpp b/src/tools/mesh_extractor/WorldModelRoot.cpp
index 4b6e4e189a4..cdeeec5ad26 100644
--- a/src/tools/mesh_extractor/WorldModelRoot.cpp
+++ b/src/tools/mesh_extractor/WorldModelRoot.cpp
@@ -18,6 +18,7 @@
#include "WorldModelRoot.h"
#include "ChunkedData.h"
#include "Utils.h"
+#include "MPQManager.h"
WorldModelRoot::WorldModelRoot( std::string path )
{
@@ -32,6 +33,10 @@ WorldModelRoot::WorldModelRoot( std::string path )
WorldModelRoot::~WorldModelRoot()
{
delete Data;
+ for (std::vector<WorldModelGroup*>::iterator group = Groups.begin(); group != Groups.end(); ++group)
+ delete *group;
+
+ Groups.clear();
}
void WorldModelRoot::ReadGroups()
@@ -42,9 +47,10 @@ void WorldModelRoot::ReadGroups()
{
char name[200];
sprintf(name, "%s_%03u.wmo", pathBase.c_str(), i);
- WorldModelGroup group(name, i);
- if (!group.IsBad)
- Groups.push_back(group);
+ Stream* stream = MPQHandler->GetFile(name);
+ if (!stream)
+ continue;
+ Groups.push_back(new WorldModelGroup(stream, name, i));
}
}
@@ -54,7 +60,7 @@ void WorldModelRoot::ReadDoodadSets()
if (!chunk)
return;
- FILE* stream = chunk->GetStream();
+ Stream* stream = chunk->GetStream();
ASSERT(chunk->Length / 32 == Header.CountSets && "chunk.Length / 32 == Header.CountSets");
DoodadSets.reserve(Header.CountSets);
for (uint32 i = 0; i < Header.CountSets; i++)
@@ -73,14 +79,14 @@ void WorldModelRoot::ReadDoodadInstances()
DoodadInstances.reserve(countInstances);
for (uint32 i = 0; i < countInstances; i++)
{
- FILE* stream = chunk->GetStream();
- fseek(stream, instanceSize * i, SEEK_CUR);
+ Stream* stream = chunk->GetStream();
+ stream->Seek(instanceSize * i, SEEK_CUR);
DoodadInstance instance = DoodadInstance::Read(stream);
- FILE* nameStream = nameChunk->GetStream();
+ Stream* nameStream = nameChunk->GetStream();
if (instance.FileOffset >= nameChunk->Length)
continue;
- fseek(nameStream, instance.FileOffset, SEEK_CUR);
- instance.File = Utils::ReadString(nameStream);
+ nameStream->Seek(instance.FileOffset, SEEK_CUR);
+ instance.File = nameStream->ReadString();
DoodadInstances.push_back(instance);
}
}
@@ -91,6 +97,6 @@ void WorldModelRoot::ReadHeader()
if (!chunk)
return;
- FILE* stream = chunk->GetStream();
- Header = WorldModelHeader::Read(stream);
+ Stream* stream = chunk->GetStream();
+ Header.Read(stream);
}
diff --git a/src/tools/mesh_extractor/WorldModelRoot.h b/src/tools/mesh_extractor/WorldModelRoot.h
index c2303ceafe4..7b1248246ca 100644
--- a/src/tools/mesh_extractor/WorldModelRoot.h
+++ b/src/tools/mesh_extractor/WorldModelRoot.h
@@ -34,7 +34,7 @@ public:
WorldModelHeader Header;
std::vector<DoodadInstance> DoodadInstances;
std::vector<DoodadSet> DoodadSets;
- std::vector<WorldModelGroup> Groups;
+ std::vector<WorldModelGroup*> Groups;
private:
void ReadGroups();
void ReadDoodadSets();