refactor(Tools/MeshExtractor): remove meshextractor (#11569)

This commit is contained in:
IntelligentQuantum
2022-04-29 10:53:17 +04:30
committed by GitHub
parent 2bef6b497d
commit b62005a02f
45 changed files with 0 additions and 4947 deletions

View File

@@ -62,7 +62,6 @@ option(USE_COREPCH "Use precompiled headers when compiling servers"
option(WITH_WARNINGS "Show all warnings during compile" 0) option(WITH_WARNINGS "Show all warnings during compile" 0)
option(WITH_COREDEBUG "Include additional debug-code in core" 0) option(WITH_COREDEBUG "Include additional debug-code in core" 0)
option(WITH_PERFTOOLS "Enable compilation with gperftools libraries included" 0) option(WITH_PERFTOOLS "Enable compilation with gperftools libraries included" 0)
option(WITH_MESHEXTRACTOR "Build meshextractor (alpha)" 0)
option(WITHOUT_GIT "Disable the GIT testing routines" 0) option(WITHOUT_GIT "Disable the GIT testing routines" 0)
option(ENABLE_VMAP_CHECKS "Enable Checks relative to DisableMgr system on vmap" 1) option(ENABLE_VMAP_CHECKS "Enable Checks relative to DisableMgr system on vmap" 1)
option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0) option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0)

View File

@@ -14,7 +14,3 @@ add_subdirectory(map_extractor)
add_subdirectory(vmap4_assembler) add_subdirectory(vmap4_assembler)
add_subdirectory(vmap4_extractor) add_subdirectory(vmap4_extractor)
add_subdirectory(mmaps_generator) add_subdirectory(mmaps_generator)
if (WITH_MESHEXTRACTOR)
add_subdirectory(mesh_extractor)
endif()

View File

@@ -1,70 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ADT.h"
#include "DoodadHandler.h"
#include "LiquidHandler.h"
#include "WorldModelHandler.h"
ADT::ADT( std::string file, int x, int y ) : ObjectData(nullptr), Data(nullptr), HasObjectData(false),
_DoodadHandler(nullptr), _WorldModelHandler(nullptr), _LiquidHandler(nullptr), X(x), Y(y)
{
Data = new ChunkedData(file);
ObjectData = new ChunkedData(file);
if (ObjectData->Stream)
HasObjectData = true;
else
ObjectData = nullptr;
}
ADT::~ADT()
{
delete ObjectData;
delete Data;
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
delete *itr;
MapChunks.clear();
delete _DoodadHandler;
delete _WorldModelHandler;
delete _LiquidHandler;
}
void ADT::Read()
{
Header.Read(Data->GetChunkByName("MHDR")->GetStream());
MapChunks.reserve(16 * 16);
for (std::vector<Chunk*>::iterator itr = Data->Chunks.begin(); itr != Data->Chunks.end(); ++itr)
if ((*itr)->Name == "MCNK")
MapChunks.push_back(new MapChunk(this, *itr));
_LiquidHandler = new LiquidHandler(this);
// do this separate from map chunk initialization to access liquid data
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
(*itr)->GenerateTriangles();
_DoodadHandler = new DoodadHandler(this);
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
_DoodadHandler->ProcessMapChunk(*itr);
_WorldModelHandler = new WorldModelHandler(this);
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
_WorldModelHandler->ProcessMapChunk(*itr);
}

View File

@@ -1,49 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADT_H
#define ADT_H
#include "ChunkedData.h"
#include "MapChunk.h"
class DoodadHandler;
class WorldModelHandler;
class LiquidHandler;
class ADT
{
public:
ADT(std::string file, int x, int y);
~ADT();
void Read();
ChunkedData* ObjectData;
ChunkedData* Data;
std::vector<MapChunk*> MapChunks;
MHDR Header;
// Can we dispose of this?
bool HasObjectData;
DoodadHandler* _DoodadHandler;
WorldModelHandler* _WorldModelHandler;
LiquidHandler* _LiquidHandler;
int X;
int Y;
};
#endif

View File

@@ -1,49 +0,0 @@
#
# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
CollectSourceFiles(
${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE_SOURCES)
add_executable(MeshExtractor ${PRIVATE_SOURCES})
target_link_libraries(MeshExtractor
PRIVATE
acore-core-interface
PUBLIC
common
Recast
mpq)
# Group sources
GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
CollectIncludeDirectories(
${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC_INCLUDES)
target_include_directories(MeshExtractor
PUBLIC
${PUBLIC_INCLUDES}
PRIVATE
${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(MeshExtractor
PROPERTIES
FOLDER
"tools")
if( UNIX )
install(TARGETS MeshExtractor DESTINATION bin)
elseif( WIN32 )
install(TARGETS MeshExtractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()

View File

@@ -1,80 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CACHE_H
#define CACHE_H
#include "Define.h"
#include "Model.h"
#include "PolicyLock.h"
#include "WorldModelRoot.h"
#include <map>
#include <mutex>
#include <string>
template<class K, class T>
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)
{
std::lock_guard<std::mutex> guard(mutex);
if (_items.size() > FlushLimit)
Clear();
_items[key] = val;
}
T* Get(K key)
{
GUARD_RETURN(mutex, nullptr);
typename std::map<K, T*>::iterator itr = _items.find(key);
if (itr != _items.end())
return itr->second;
return nullptr;
}
void Clear()
{
for (typename std::map<K, T*>::iterator itr = _items.begin(); itr != _items.end(); ++itr)
delete itr->second;
_items.clear();
}
private:
std::map<K, T*> _items;
std::mutex mutex;
};
class CacheClass
{
public:
CacheClass() {}
GenericCache<std::string, Model> ModelCache;
GenericCache<std::string, WorldModelRoot> WorldModelCache;
void Clear()
{
ModelCache.Clear();
WorldModelCache.Clear();
}
};
extern CacheClass* Cache;
#endif

View File

@@ -1,48 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Chunk.h"
#include "Utils.h"
int32 Chunk::FindSubChunkOffset(std::string name)
{
// Reverse the name
name = std::string(name.rbegin(), name.rend());
if (name.size() != 4)
return -1;
FILE* stream = GetStream();
uint32 matched = 0;
while (uint32(ftell(stream)) < Utils::Size(stream))
{
char b = 0;
if (fread(&b, sizeof(char), 1, stream) != 1 || b != name[matched])
matched = 0;
else
++matched;
if (matched == 4)
return ftell(stream) - 4;
}
return -1;
}
FILE* Chunk::GetStream()
{
fseek(Stream, Offset, SEEK_SET);
return Stream;
}

View File

@@ -1,37 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHUNK_H
#define CHUNK_H
#include "Define.h"
#include <string>
class ChunkedData;
class Chunk
{
public:
Chunk(const char* name, uint32 length, uint32 offset, FILE* stream) : Name(name), Length(length), Offset(offset), Stream(stream) {}
int32 FindSubChunkOffset(std::string name);
FILE* GetStream();
std::string Name;
uint32 Length;
uint32 Offset;
FILE* Stream;
};
#endif

View File

@@ -1,91 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ChunkedData.h"
#include "MPQMgr.h"
#include "Utils.h"
#include <string>
ChunkedData::ChunkedData( FILE* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) :
Stream(stream)
{
if (!Stream)
return;
Load(maxLength, chunksHint);
}
ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ )
{
Stream = MPQHandler->GetFile(file);
if (!Stream)
return;
Load(0, chunksHint);
}
void ChunkedData::Load( uint32 maxLength, uint32 chunksHint )
{
if (!maxLength)
maxLength = Utils::Size(Stream);
Chunks.reserve(chunksHint);
uint32 baseOffset = ftell(Stream);
uint32 calcOffset = 0;
while ((calcOffset + baseOffset) < Utils::Size(Stream) && (calcOffset < maxLength))
{
char nameBytes[5];
uint32 read = fread(&nameBytes, sizeof(char), 4, Stream);
nameBytes[read] = '\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;
calcOffset += 8;
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);
}
}
int ChunkedData::GetFirstIndex( const std::string& name )
{
for (uint32 i = 0; i < Chunks.size(); ++i)
if (Chunks[i]->Name == name)
return i;
return -1;
}
Chunk* ChunkedData::GetChunkByName( const std::string& name )
{
for (uint32 i = 0; i < Chunks.size(); ++i)
if (Chunks[i]->Name == name)
return Chunks[i];
return nullptr;
}
ChunkedData::~ChunkedData()
{
for (std::vector<Chunk*>::iterator itr = Chunks.begin(); itr != Chunks.end(); ++itr)
delete *itr;
Chunks.clear();
if (Stream)
fclose(Stream);
}

View File

@@ -1,38 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHNK_H
#define CHNK_H
#include "Chunk.h"
#include <vector>
class ChunkedData
{
public:
ChunkedData(FILE* stream, uint32 maxLength, uint32 chunksHint = 300);
ChunkedData(const std::string& file, uint32 chunksHint = 300);
~ChunkedData();
int GetFirstIndex(const std::string& name);
Chunk* GetChunkByName(const std::string& name);
void Load(uint32 maxLength, uint32 chunksHint);
std::vector<Chunk*> Chunks;
FILE* Stream;
};
#endif

View File

@@ -1,75 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
class Constants
{
public:
enum TriangleType
{
TRIANGLE_TYPE_UNKNOWN,
TRIANGLE_TYPE_TERRAIN,
TRIANGLE_TYPE_WATER,
TRIANGLE_TYPE_DOODAD,
TRIANGLE_TYPE_WMO
};
enum PolyArea
{
POLY_AREA_TERRAIN = 1,
POLY_AREA_WATER = 2,
POLY_AREA_ROAD = 3,
POLY_AREA_DANGER = 4,
};
enum PolyFlag
{
POLY_FLAG_WALK = 1,
POLY_FLAG_SWIM = 2,
POLY_FLAG_FLIGHTMASTER = 4
};
enum ExtractFlags
{
EXTRACT_FLAG_DBC = 0x01,
EXTRACT_FLAG_MAPS = 0x02,
EXTRACT_FLAG_VMAPS = 0x04,
EXTRACT_FLAG_GOB_MODELS = 0x08,
EXTRACT_FLAG_MMAPS = 0x10,
EXTRACT_FLAG_TEST = 0x20,
EXTRACT_FLAG_ALLOWED = EXTRACT_FLAG_DBC | EXTRACT_FLAG_MAPS | EXTRACT_FLAG_VMAPS | EXTRACT_FLAG_GOB_MODELS | EXTRACT_FLAG_MMAPS | EXTRACT_FLAG_TEST
};
static const float TileSize;
static const float MaxXY;
static const float ChunkSize;
static const float UnitSize;
static const float Origin[];
static const float PI;
static const float MaxStandableHeight;
static bool ToWoWCoords;
static bool Debug;
static const char* VMAPMagic;
static const float BaseUnitDim;
static const int VertexPerMap;
static const int VertexPerTile;
static const int TilesPerMap;
};
#endif

View File

@@ -1,213 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ContinentBuilder.h"
#include "Cache.h"
#include "DetourCommon.h"
#include "DetourNavMesh.h"
#include "Recast.h"
#include "TileBuilder.h"
#include "Utils.h"
#include "WDT.h"
#include <thread>
class BuilderThread
{
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)
{
// this is for elevation
if (verts && vertCount)
rcCalcBounds(verts, vertCount, bmin, bmax);
else
{
bmin[1] = FLT_MIN;
bmax[1] = FLT_MAX;
}
// this is for width and depth
bmax[0] = (32 - int(tileX)) * Constants::TileSize;
bmax[2] = (32 - int(tileY)) * Constants::TileSize;
bmin[0] = bmax[0] - Constants::TileSize;
bmin[2] = bmax[2] - Constants::TileSize;
}
void ContinentBuilder::CalculateTileBounds()
{
for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr)
{
tileXMax = std::max(itr->X, tileXMax);
tileXMin = std::min(itr->X, tileXMin);
tileYMax = std::max(itr->Y, tileYMax);
tileYMin = std::min(itr->Y, tileYMin);
}
getTileBounds(tileXMax, tileYMax, nullptr, 0, bmin, bmax);
}
void ContinentBuilder::Build()
{
char buff[50];
sprintf(buff, "mmaps/%03u.mmap", MapId);
FILE* mmap = fopen(buff, "wb");
if (!mmap)
{
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
return;
}
CalculateTileBounds();
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);
TileBuilder* builder = new TileBuilder(this, Continent, 0, 0, MapId);
builder->AddGeometry(TileMap->Model, TileMap->ModelDefinition);
uint8* nav = builder->BuildInstance(params);
if (nav)
{
// Set some params for the navmesh
dtMeshHeader* header = (dtMeshHeader*)nav;
dtVcopy(params.orig, header->bmin);
params.tileWidth = header->bmax[0] - header->bmin[0];
params.tileHeight = header->bmax[2] - header->bmin[2];
params.maxTiles = 1;
params.maxPolys = header->polyCount;
fwrite(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
char buff[100];
sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, 0, 0);
FILE* 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;
}
MmapTileHeader mheader;
mheader.size = builder->DataSize;
fwrite(&mheader, sizeof(MmapTileHeader), 1, f);
fwrite(nav, sizeof(unsigned char), builder->DataSize, f);
fclose(f);
}
dtFree(nav);
delete builder;
}
else
{
params.maxPolys = 32768;
params.maxTiles = 4096;
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));
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)
{
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
std::this_thread::sleep_for(std::chrono::seconds(20));
}
}
}
Cache->Clear();
// Free memory
for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
{
(*_th)->wait();
delete *_th;
}
}

View File

@@ -1,47 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONT_BUILDER_H
#define CONT_BUILDER_H
#include "Define.h"
#include "WDT.h"
#include <string>
class ContinentBuilder
{
public:
ContinentBuilder(std::string continent, uint32 mapId, WDT* wdt, uint32 tn) :
Continent(continent), TileMap(wdt), MapId(mapId),
NumberOfThreads(tn), tileXMin(64), tileYMin(64), tileXMax(0), tileYMax(0)
{}
void Build();
void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax);
void CalculateTileBounds();
float bmin[3];
float bmax[3];
private:
std::string Continent;
WDT* TileMap;
uint32 MapId;
uint32 NumberOfThreads;
int tileXMin;
int tileYMin;
int tileXMax;
int tileYMax;
};
#endif

View File

@@ -1,87 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DBC.h"
#include "Define.h"
#include <cstdio>
DBC::DBC( FILE* stream ) : StringBlock(nullptr), 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);
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);
for (int i = 0; i < RecordCount; i++)
{
Record* rec = new Record(this);
Records.push_back(rec);
int size = 0;
for (int f = 0; f < Fields; f++)
{
if (size + 4 > RecordSize)
{
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);
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);
}
std::string DBC::GetStringByOffset( int offset )
{
int len = 0;
for (uint32 i = offset; i < StringBlockSize; i++)
{
if (!StringBlock[i])
{
len = (i - offset);
break;
}
}
char* d = new char[len + 1];
strcpy(d, (const char*)(StringBlock + offset));
d[len] = '\0';
std::string val = std::string(d);
delete [] d;
return val;
}
Record* DBC::GetRecordById( int id )
{
// we assume Id is index 0
for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr)
if ((*itr)->Values[0] == id)
return *itr;
return nullptr;
}

View File

@@ -1,70 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DBC_H
#define DBC_H
#include "Define.h"
#include <string>
#include <vector>
class Record;
class DBC
{
public:
DBC(FILE* stream);
std::string GetStringByOffset(int offset);
Record* GetRecordById(int id);
std::string Name;
std::vector<Record*> Records;
int RecordCount;
int Fields;
int RecordSize;
uint8* StringBlock;
uint32 StringBlockSize;
bool IsFaulty;
};
class Record
{
public:
Record(DBC* dbc) : Source(dbc) {}
DBC* Source;
std::vector<int> Values;
int operator[](int index)
{
return Values[index];
}
template <typename T>
T GetValue(int index)
{
return *(T*)(&Values[index]);
}
std::string Get<std::string>(int index)
{
return Source->GetStringByOffset(Values[index]);
}
};
#endif

View File

@@ -1,126 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DoodadHandler.h"
#include "Cache.h"
#include "Chunk.h"
#include "G3D/Matrix4.h"
#include "Model.h"
DoodadHandler::DoodadHandler( ADT* adt ) :
ObjectDataHandler(adt), _definitions(nullptr), _paths(nullptr)
{
Chunk* mddf = adt->ObjectData->GetChunkByName("MDDF");
if (mddf)
ReadDoodadDefinitions(mddf);
Chunk* mmid = adt->ObjectData->GetChunkByName("MMID");
Chunk* mmdx = adt->ObjectData->GetChunkByName("MMDX");
if (mmid && mmdx)
ReadDoodadPaths(mmid, mmdx);
}
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);
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);
if (index < 0 || uint32(index) >= _definitions->size())
continue;
DoodadDefinition doodad = (*_definitions)[index];
if (_drawn.find(doodad.UniqueId) != _drawn.end())
continue;
_drawn.insert(doodad.UniqueId);
if (doodad.MmidIndex >= _paths->size())
continue;
std::string path = (*_paths)[doodad.MmidIndex];
Model* model = Cache->ModelCache.Get(path);
if (!model)
{
model = new Model(path);
Cache->ModelCache.Insert(path, model);
}
if (!model->IsCollidable)
continue;
Vertices.reserve(refCount * model->Vertices.size() * 0.2);
Triangles.reserve(refCount * model->Triangles.size() * 0.2);
InsertModelGeometry(doodad, model);
}
// Restore the stream position
fseek(stream, mcnk->Source->Offset, SEEK_SET);
}
void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk )
{
int32 count = chunk->Length / 36;
_definitions = new std::vector<DoodadDefinition>;
_definitions->reserve(count);
FILE* stream = chunk->GetStream();
for (int i = 0; i < count; i++)
{
DoodadDefinition def;
def.Read(stream);
_definitions->push_back(def);
}
}
void DoodadHandler::ReadDoodadPaths( Chunk* id, Chunk* data )
{
int paths = id->Length / 4;
_paths = new std::vector<std::string>();
_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));
}
}
void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model* model)
{
uint32 vertOffset = Vertices.size();
for (std::vector<Vector3>::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)
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_DOODAD, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
}
DoodadHandler::~DoodadHandler()
{
delete _definitions;
delete _paths;
}

View File

@@ -1,78 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DOOADHNDL_H
#define DOOADHNDL_H
#include "Chunk.h"
#include "Model.h"
#include "ObjectDataHandler.h"
#include "Utils.h"
#include <set>
#include <vector>
class DoodadDefinition : public IDefinition
{
public:
uint32 MmidIndex;
uint32 UniqueId;
uint16 DecimalScale;
uint16 Flags;
virtual float Scale() const { return DecimalScale / 1024.0f; }
Vector3 FixCoords(Vector3& vec)
{
return Vector3(vec.z, vec.x, vec.y);
}
void Read(FILE* stream)
{
int count = 0;
count += fread(&MmidIndex, sizeof(uint32), 1, stream);
count += fread(&UniqueId, sizeof(uint32), 1, stream);
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);
}
};
class DoodadHandler : public ObjectDataHandler
{
public:
DoodadHandler(ADT* adt);
~DoodadHandler();
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
bool IsSane() { return _definitions && _paths; }
protected:
void ProcessInternal(MapChunk* chunk);
private:
void ReadDoodadDefinitions(Chunk* chunk);
void ReadDoodadPaths(Chunk* id, Chunk* data);
void InsertModelGeometry(const DoodadDefinition& def, Model* model);
std::set<uint32> _drawn;
std::vector<DoodadDefinition>* _definitions;
std::vector<std::string>* _paths;
};
#endif

View File

@@ -1,144 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Geometry.h"
#include "ADT.h"
#include "Constants.h"
#include "DoodadHandler.h"
#include "WorldModelHandler.h"
Geometry::Geometry() : Transform(false)
{
Vertices.reserve(10000);
Triangles.reserve(10000);
}
void Geometry::CalculateBoundingBox( float*& min, float*& max )
{
min = new float[3];
max = new float[3];
for (int i = 0; i < 3; ++i)
{
max[i] = std::numeric_limits<float>::min();
min[i] = std::numeric_limits<float>::max();
}
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
{
if (itr->x > max[0])
max[0] = itr->x;
if (itr->x < min[0])
min[0] = itr->x;
if (itr->y > max[1])
max[1] = itr->y;
if (itr->y < min[1])
min[1] = itr->y;
if (itr->z > max[2])
max[2] = itr->z;
if (itr->z < min[2])
min[2] = itr->z;
}
}
void Geometry::CalculateMinMaxHeight( float& min, float& max )
{
min = std::numeric_limits<float>::max();
max = std::numeric_limits<float>::min();
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
{
if (Transform)
{
if (itr->y < min)
min = itr->y;
if (itr->y > max)
max = itr->y;
}
else
{
if (itr->z < min)
min = itr->z;
if (itr->z > max)
max = itr->z;
}
}
}
void Geometry::AddData( std::vector<Vector3>& verts, std::vector<Triangle<uint32>>& tris )
{
uint32 vertOffset = Vertices.size();
for (std::vector<Vector3>::iterator itr = verts.begin(); itr != verts.end(); ++itr)
Vertices.push_back(Transform ? Utils::ToRecast(*itr) : *itr);
for (std::vector<Triangle<uint32>>::iterator itr = tris.begin(); itr != tris.end(); ++itr)
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 )
{
verts = new float[Vertices.size() * 3];
for (uint32 i = 0; i < Vertices.size(); ++i)
{
Vector3& vert = Vertices[i];
verts[(i * 3) + 0] = vert.x;
verts[(i * 3) + 1] = vert.y;
verts[(i * 3) + 2] = vert.z;
}
tris = new int[Triangles.size() * 3];
for (uint32 i = 0; i < Triangles.size(); ++i)
{
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;
}
areas = new uint8[Triangles.size()];
for (uint32 i = 0; i < Triangles.size(); i++)
{
switch (Triangles[i].Type)
{
case Constants::TRIANGLE_TYPE_WATER:
areas[i] = Constants::POLY_AREA_WATER;
break;
default:
areas[i] = Constants::POLY_AREA_TERRAIN;
break;
}
}
}
void Geometry::AddAdt( ADT* adt )
{
for (std::vector<MapChunk*>::iterator itr = adt->MapChunks.begin(); itr != adt->MapChunks.end(); ++itr)
{
std::vector<Triangle<uint32>> tmp;
tmp.reserve((*itr)->Triangles.size());
for (std::vector<Triangle<uint8>>::iterator itr2 = (*itr)->Triangles.begin(); itr2 != (*itr)->Triangles.end(); ++itr2)
tmp.push_back(Triangle<uint32>(itr2->Type, itr2->V0, itr2->V1, itr2->V2));
AddData((*itr)->Vertices, tmp);
}
if (!adt->_DoodadHandler->Triangles.empty())
AddData(adt->_DoodadHandler->Vertices, adt->_DoodadHandler->Triangles);
if (!adt->_WorldModelHandler->Triangles.empty())
AddData(adt->_WorldModelHandler->Vertices, adt->_WorldModelHandler->Triangles);
}

View File

@@ -1,40 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <vector>
#include "Utils.h"
class ADT;
class Geometry
{
public:
Geometry();
void CalculateBoundingBox(float*& min, float*& max);
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);
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
bool Transform;
};
#endif

View File

@@ -1,119 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LiquidHandler.h"
#include "Utils.h"
LiquidHandler::LiquidHandler( ADT* adt ) : Source(adt)
{
HandleNewLiquid();
}
void LiquidHandler::HandleNewLiquid()
{
Chunk* chunk = Source->Data->GetChunkByName("MH2O");
if (!chunk)
return;
Vertices.reserve(1000);
Triangles.reserve(1000);
FILE* stream = chunk->GetStream();
H2OHeader header[256];
MCNKData.reserve(256);
for (int i = 0; i < 256; i++)
header[i] = H2OHeader::Read(stream);
for (int i = 0; i < 256; i++)
{
H2OHeader h = header[i];
if (h.LayerCount == 0)
{
// Need to fill in missing data with dummies.
MCNKData.push_back(MCNKLiquidData(nullptr, H2ORenderMask()));
continue;
}
fseek(stream, chunk->Offset + h.OffsetInformation, SEEK_SET);
H2OInformation information = H2OInformation::Read(stream);
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)
{
fseek(stream, 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);
uint32 size = std::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];
delete[] altMask;
}
fseek(stream, 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;
}
else
{
// Fill with ocean data
for (uint32 i = 0; i < 8; ++i)
renderMask.Mask[i] = 0xFF;
for (uint32 y = 0; y < 9; ++y)
for (uint32 x = 0; x < 9; ++x)
heights[x][y] = information.HeightLevel1;
}
MCNKData.push_back(MCNKLiquidData(heights, renderMask));
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
{
for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++)
{
if (!renderMask.ShouldRender(x, y))
continue;
MapChunk* mapChunk = Source->MapChunks[i];
Vector3 location = mapChunk->Header.Position;
location.y = location.y - (x * Constants::UnitSize);
location.x = location.x - (y * Constants::UnitSize);
location.z = heights[x][y];
uint32 vertOffset = Vertices.size();
Vertices.push_back(location);
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));
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));
}
}
}
}

View File

@@ -1,38 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIQUID_H
#define LIQUID_H
#include "ADT.h"
#include "Define.h"
#include "Utils.h"
#include <vector>
class LiquidHandler
{
public:
LiquidHandler(ADT* adt);
ADT* Source;
std::vector<Vector3> Vertices;
std::vector<Triangle<uint32>> Triangles;
std::vector<MCNKLiquidData> MCNKData;
private:
void HandleNewLiquid();
};
#endif

View File

@@ -1,140 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MPQ.h"
#include "MPQMgr.h"
#include <cstdio>
#include <deque>
MPQArchive::MPQArchive(const char* filename)
{
int result = libmpq__archive_open(&mpq_a, filename, -1);
printf("Opening %s\n", filename);
if (result)
{
switch (result)
{
case LIBMPQ_ERROR_OPEN :
printf("Error opening archive '%s': Does file really exist?\n", filename);
break;
case LIBMPQ_ERROR_FORMAT : /* bad file format */
printf("Error opening archive '%s': Bad file format\n", filename);
break;
case LIBMPQ_ERROR_SEEK : /* seeking in file failed */
printf("Error opening archive '%s': Seeking in file failed\n", filename);
break;
case LIBMPQ_ERROR_READ : /* Read error in archive */
printf("Error opening archive '%s': Read error in archive\n", filename);
break;
case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
break;
default:
printf("Error opening archive '%s': Unknown error\n", filename);
break;
}
}
GetFileListTo(Files);
}
void MPQArchive::close()
{
libmpq__archive_close(mpq_a);
}
MPQFile::MPQFile(const char* filename):
eof(false), buffer(0), pointer(0), size(0)
{
for (std::deque<MPQArchive*>::iterator i = MPQHandler->Archives.begin(); i != MPQHandler->Archives.end(); ++i)
{
mpq_archive* mpq_a = (*i)->mpq_a;
uint32_t filenum;
if (libmpq__file_number(mpq_a, filename, &filenum))
continue;
libmpq__off_t transferred;
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)
{
// printf("warning: file %s has size %d; cannot Read.\n", filename, size);
eof = true;
buffer = 0;
return;
}
buffer = new char[size];
//libmpq_file_getdata
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
/*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/
return;
}
eof = true;
buffer = 0;
}
size_t MPQFile::Read(void* dest, size_t bytes)
{
if (eof)
return 0;
size_t rpos = pointer + bytes;
if (rpos > size_t(size))
{
bytes = size - pointer;
eof = true;
}
memcpy(dest, &(buffer[pointer]), bytes);
pointer = rpos;
return bytes;
}
void MPQFile::seek(int offset)
{
pointer = offset;
eof = (pointer >= size);
}
void MPQFile::seekRelative(int offset)
{
pointer += offset;
eof = (pointer >= size);
}
void MPQFile::close()
{
delete[] buffer;
buffer = 0;
eof = true;
}
FILE* 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;
}

View File

@@ -1,108 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MPQ_H
#define MPQ_H
#include "Define.h"
#include "Errors.h"
#include "libmpq/mpq.h"
#include <ctype.h>
#include <deque>
#include <iostream>
#include <string>
#include <vector>
class MPQArchive
{
public:
mpq_archive_s* mpq_a;
std::vector<std::string> Files;
MPQArchive(const char* filename);
void close();
void GetFileListTo(std::vector<std::string>& filelist)
{
uint32_t filenum;
if (libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
libmpq__off_t size, transferred;
libmpq__file_unpacked_size(mpq_a, filenum, &size);
char* buffer = new char[size + 1];
buffer[size] = '\0';
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
char seps[] = "\n";
char* token;
token = strtok( buffer, seps );
uint32 counter = 0;
while ((token != nullptr) && (counter < size))
{
//cout << token << endl;
token[strlen(token) - 1] = 0;
std::string s = token;
filelist.push_back(s);
counter += strlen(token) + 2;
token = strtok(nullptr, seps);
}
delete[] buffer;
}
};
class MPQFile
{
//MPQHANDLE handle;
bool eof;
char* buffer;
libmpq__off_t pointer, size;
// disable copying
MPQFile(const MPQFile& /*f*/) {}
void operator=(const MPQFile& /*f*/) {}
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; }
char* getBuffer() { return buffer; }
char* getPointer() { return buffer + pointer; }
bool isEof() { return eof; }
void seek(int offset);
void seekRelative(int offset);
void close();
};
inline void flipcc(char* fcc)
{
char t;
t = fcc[0];
fcc[0] = fcc[3];
fcc[3] = t;
t = fcc[1];
fcc[1] = fcc[2];
fcc[2] = t;
}
#endif

View File

@@ -1,132 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MPQMgr.h"
#include "DBC.h"
#include "MPQ.h"
#include "Utils.h"
char const* MPQMgr::Files[] =
{
"common.MPQ",
"common-2.MPQ",
"expansion.MPQ",
"lichking.MPQ",
"patch.MPQ",
"patch-2.MPQ",
"patch-3.MPQ"
};
char const* MPQMgr::Languages[] = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
void MPQMgr::Initialize()
{
InitializeDBC();
uint32 size = sizeof(Files) / sizeof(char*);
for (uint32 i = 0; i < size; ++i)
{
MPQArchive* arc = new MPQArchive(std::string("Data/" + std::string(Files[i])).c_str());
Archives.push_front(arc); // MPQ files have to be transversed in reverse order to properly account for patched files
printf("Opened %s\n", Files[i]);
}
}
void MPQMgr::InitializeDBC()
{
BaseLocale = -1;
std::string fileName;
uint32 size = sizeof(Languages) / sizeof(char*);
MPQArchive* _baseLocale = nullptr;
for (uint32 i = 0; i < size; ++i)
{
std::string _fileName = "Data/" + std::string(Languages[i]) + "/locale-" + std::string(Languages[i]) + ".MPQ";
FILE* file = fopen(_fileName.c_str(), "rb");
if (file)
{
if (BaseLocale == -1)
{
BaseLocale = i;
_baseLocale = new MPQArchive(_fileName.c_str());
fileName = _fileName;
LocaleFiles[i] = _baseLocale;
}
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");
ABORT();
}
else
printf("Using default locale: %s\n", Languages[BaseLocale]);
}
FILE* MPQMgr::GetFile(const std::string& path )
{
GUARD_RETURN(mutex, nullptr);
MPQFile file(path.c_str());
if (file.isEof())
return nullptr;
return file.GetFileStream();
}
DBC* MPQMgr::GetDBC(const std::string& name )
{
std::string path = "DBFilesClient\\" + name + ".dbc";
return new DBC(GetFile(path));
}
FILE* MPQMgr::GetFileFrom(const std::string& path, MPQArchive* file )
{
GUARD_RETURN(mutex, nullptr);
mpq_archive* mpq_a = file->mpq_a;
uint32_t filenum;
if (libmpq__file_number(mpq_a, path.c_str(), &filenum))
return nullptr;
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)
return nullptr;
uint8* buffer = new uint8[size];
//libmpq_file_getdata
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);
delete[] buffer;
return ret;
}

View File

@@ -1,54 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MPQ_MANAGER_H
#define MPQ_MANAGER_H
#include "MPQ.h"
#include "PolicyLock.h"
#include <map>
#include <mutex>
#include <set>
class DBC;
class MPQMgr
{
public:
MPQMgr() {}
~MPQMgr() {}
void Initialize();
FILE* GetFile(const std::string& path);
FILE* GetFileFrom(const std::string& path, MPQArchive* file);
DBC* 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;
static char const* Files[];
static char const* Languages[];
protected:
void InitializeDBC();
private:
std::mutex mutex;
};
extern MPQMgr* MPQHandler;
#endif

View File

@@ -1,93 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MapChunk.h"
#include "ADT.h"
#include "LiquidHandler.h"
MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk)
{
FILE* stream = chunk->GetStream();
Header.Read(stream);
fseek(stream, chunk->Offset, SEEK_SET);
Index = Header.IndexX + Header.IndexY * 16;
GenerateVertices(stream);
}
void MapChunk::GenerateTriangles()
{
Triangles.reserve(256);
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
if (HasHole(Header.Holes, x / 2, y / 2))
continue;
uint32 topLeft = (17 * y) + x;
uint32 topRight = (17 * y) + x + 1;
uint32 bottomLeft = (17 * (y + 1)) + x;
uint32 bottomRight = (17 * (y + 1)) + x + 1;
uint32 center = (17 * y) + 9 + x;
Constants::TriangleType triangleType = Constants::TRIANGLE_TYPE_TERRAIN;
if (Adt->_LiquidHandler && !Adt->_LiquidHandler->MCNKData.empty())
{
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))
triangleType = Constants::TRIANGLE_TYPE_WATER;
}
Triangles.push_back(Triangle<uint8>(triangleType, topRight, topLeft, center));
Triangles.push_back(Triangle<uint8>(triangleType, topLeft, bottomLeft, center));
Triangles.push_back(Triangle<uint8>(triangleType, bottomLeft, bottomRight, center));
Triangles.push_back(Triangle<uint8>(triangleType, bottomRight, topRight, center));
}
}
}
void MapChunk::GenerateVertices( FILE* stream )
{
fseek(stream, Header.OffsetMCVT, SEEK_CUR);
Vertices.reserve(125);
for (int j = 0; j < 17; j++)
{
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");
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;
Vertices.push_back(vert);
}
}
// Restore stream position.
fseek(stream, Source->Offset, SEEK_SET);
}
bool MapChunk::HasHole( uint32 map, int x, int y )
{
return (map & 0x0000FFFF) & ((1 << x) << (y << 2));
}

View File

@@ -1,41 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MAPCHUNK_H
#define MAPCHUNK_H
#include "Chunk.h"
#include "Constants.h"
#include "Utils.h"
#include <vector>
class ADT;
class MapChunk
{
public:
MapChunk(ADT* _adt, Chunk* chunk);
void GenerateTriangles();
void GenerateVertices(FILE* stream);
static bool HasHole(uint32 map, int x, int y);
ADT* Adt;
Chunk* Source;
MapChunkHeader Header;
std::vector<Vector3> Vertices;
std::vector<Triangle<uint8>> Triangles;
int32 Index;
};
#endif

View File

@@ -1,485 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Cache.h"
#include "Constants.h"
#include "ContinentBuilder.h"
#include "DBC.h"
#include "MPQMgr.h"
#include "Model.h"
#include "WDT.h"
#include "DetourNavMesh.h"
#include "DetourNavMeshQuery.h"
#include "Recast.h"
#include <stdio.h>
#include <set>
MPQMgr* MPQHandler;
CacheClass* Cache;
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)
{
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())
{
if (Constants::Debug)
printf("Map %u will not be built.\n", mapId);
continue;
}
std::string name = (*itr)->Get<std::string>(1);
WDT wdt("World\\maps\\" + name + "\\" + name + ".wdt");
if (!wdt.IsValid)
{
printf("Could not find WDT data for map %u (%s)\n", mapId, name.c_str());
continue;
}
printf("Building %s MapId %u\n", name.c_str(), mapId);
ContinentBuilder builder(name, mapId, &wdt, threads);
builder.Build();
}
}
void ExtractDBCs()
{
printf("Extracting DBCs\n");
// Create the file system structure
std::string baseDBCPath = "dbc/";
Utils::CreateDir(baseDBCPath);
std::set<std::string> DBCFiles;
const size_t extLen = strlen(".dbc");
// 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);
const size_t folderLen = strlen("DBFilesClient\\");
// Iterate over all available locales
for (std::set<uint32>::iterator itr = MPQHandler->AvailableLocales.begin(); itr != MPQHandler->AvailableLocales.end(); ++itr)
{
printf("Extracting DBCs for locale %s\n", MPQMgr::Languages[*itr]);
std::string path = baseDBCPath;
if (*itr != uint32(MPQHandler->BaseLocale))
{
path += std::string(MPQMgr::Languages[*itr]) + "/";
Utils::CreateDir(path);
}
std::string component = "component.wow-" + std::string(MPQMgr::Languages[*itr]) + ".txt";
// Extract the component file
Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*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));
}
printf("DBC extraction finished!\n");
}
void ExtractGameobjectModels()
{
Constants::ToWoWCoords = true;
printf("Extracting GameObject models\n");
std::string baseBuildingsPath = "Buildings/";
std::string baseVmapsPath = "vmaps/";
Utils::CreateDir(baseVmapsPath);
Utils::CreateDir(baseBuildingsPath);
FILE* modelList = fopen((baseVmapsPath + "GameObjectModels.list").c_str(), "wb");
if (!modelList)
{
printf("Could not create file vmaps/GameObjectModels.list, please make sure that you have the write permissions in the folder\n");
return;
}
DBC* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo");
for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
{
std::string path = (*itr)->Get<std::string>(1);
std::string fileName = Utils::GetPlainName(path.c_str());
std::string extension = Utils::GetExtension(fileName);
// Convert the extension to lowercase
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
if (extension == "mdx" || extension == "m2")
{
fileName = Utils::FixModelPath(fileName);
Model model(path);
if (model.IsBad)
continue;
FILE* output = fopen((baseBuildingsPath + fileName).c_str(), "wb");
if (!output)
{
printf("Could not create file %s, please check that you have write permissions\n", (baseBuildingsPath + fileName).c_str());
continue;
}
// Placeholder for 0 values
int Nop[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
fwrite(Constants::VMAPMagic, 8, 1, output);
uint32 numVerts = model.Header.CountBoundingVertices;
fwrite(&numVerts, sizeof(uint32), 1, output);
uint32 numGroups = 1;
fwrite(&numGroups, sizeof(uint32), 1, output);
fwrite(Nop, 4 * 3, 1, output); // rootwmoid, flags, groupid
fwrite(Nop, sizeof(float), 3 * 2, output);//bbox, only needed for WMO currently
fwrite(Nop, 4, 1, output);// liquidflags
fwrite("GRP ", 4, 1, output);
uint32 branches = 1;
uint32 wsize = sizeof(branches) + sizeof(uint32) * branches;
fwrite(&wsize, sizeof(uint32), 1, output);
fwrite(&branches, sizeof(branches), 1, output);
uint32 numTris = model.Header.CountBoundingTriangles;
fwrite(&numTris, sizeof(uint32), 1, output);
fwrite("INDX", 4, 1, output);
wsize = sizeof(uint32) + sizeof(unsigned short) * numTris;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&numTris, sizeof(uint32), 1, output);
uint16* indices = new uint16[numTris];
if (numTris > 0)
{
uint32 i = 0;
for (std::vector<Triangle<uint16>>::iterator itr2 = model.Triangles.begin(); itr2 != model.Triangles.end(); ++itr2, ++i)
{
indices[i * 3 + 0] = itr2->V0;
indices[i * 3 + 1] = itr2->V1;
indices[i * 3 + 2] = itr2->V2;
}
fwrite(indices, sizeof(uint16), numTris, output);
}
fwrite("VERT", 4, 1, output);
wsize = sizeof(int) + sizeof(float) * 3 * numVerts;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&numVerts, sizeof(int), 1, output);
float* vertices = new float[numVerts * 3];
if (numVerts > 0)
{
uint32 i = 0;
for (std::vector<Vector3>::iterator itr2 = model.Vertices.begin(); itr2 != model.Vertices.end(); ++itr2, ++i)
{
vertices[i * 3 + 0] = itr2->x;
vertices[i * 3 + 1] = itr2->y;
vertices[i * 3 + 2] = itr2->z;
}
fwrite(vertices, sizeof(float), numVerts * 3, output);
}
fclose(output);
delete[] indices;
delete[] vertices;
uint32 displayId = (*itr)->Values[0];
uint32 pathLength = fileName.size();
fwrite(&displayId, sizeof(uint32), 1, modelList);
fwrite(&pathLength, sizeof(uint32), 1, modelList);
fwrite(fileName.c_str(), sizeof(char), pathLength, modelList);
}
else if (extension == "wmo")
{
WorldModelRoot model(path);
FILE* output = fopen((baseBuildingsPath + fileName).c_str(), "wb");
if (!output)
{
printf("Could not create file %s, please check that you have write permissions\n", (baseBuildingsPath + fileName).c_str());
continue;
}
fwrite(Constants::VMAPMagic, 1, 8, output);
uint32 numVertices = 0;
fwrite(&numVertices, sizeof(uint32), 1, output); // will be filled later
fwrite(&model.Header.CountGroups, sizeof(uint32), 1, output);
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)
{
const WMOGroupHeader& header = itr2->Header;
fwrite(&header.Flags, sizeof(uint32), 1, output);
fwrite(&header.WmoId, sizeof(uint32), 1, output);
fwrite(&header.BoundingBox[0], sizeof(uint32), 1, output);
fwrite(&header.BoundingBox[1], sizeof(uint32), 1, output);
uint32 LiquidFlags = itr2->HasLiquidData ? 1 : 0;
fwrite(&LiquidFlags, sizeof(uint32), 1, output);
fwrite(grp, sizeof(char), sizeof(grp), output);
uint32 k = 0;
uint32 mobaBatch = itr2->MOBALength / 12;
uint32* MobaEx = new uint32[mobaBatch * 4];
for (uint32 i = 8; i < itr2->MOBALength; i += 12)
MobaEx[k++] = itr2->MOBA[i];
int mobaSizeGrp = mobaBatch * 4 + 4;
fwrite(&mobaSizeGrp, 4, 1, output);
fwrite(&mobaBatch, 4, 1, output);
fwrite(MobaEx, 4, k, output);
delete[] MobaEx;
//@TODO: Finish this.
}
fclose(output);
}
}
fclose(modelList);
printf("GameObject models extraction finished!");
Constants::ToWoWCoords = false;
}
bool HandleArgs(int argc, char** argv, uint32& threads, std::set<uint32>& mapList, bool& debugOutput, uint32& extractFlags)
{
char* param = nullptr;
extractFlags = 0;
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--threads") == 0)
{
param = argv[++i];
if (!param)
return false;
threads = atoi(param);
printf("Using %u threads\n", threads);
}
else if (strcmp(argv[i], "--maps") == 0)
{
param = argv[++i];
if (!param)
return false;
char* copy = strdup(param);
char* token = strtok(copy, ",");
while (token)
{
mapList.insert(atoi(token));
token = strtok(nullptr, ",");
}
free(copy);
printf("Extracting only provided list of maps (%u).\n", uint32(mapList.size()));
}
else if (strcmp(argv[i], "--debug") == 0)
{
param = argv[++i];
if (!param)
return false;
debugOutput = atoi(param);
if (debugOutput)
printf("Output will contain debug information (.obj files)\n");
}
else if (strcmp(argv[i], "--extract") == 0)
{
param = argv[++i];
if (!param)
return false;
extractFlags = atoi(param);
if (!(extractFlags & Constants::EXTRACT_FLAG_ALLOWED)) // Tried to use an invalid flag
return false;
printf("Detected flags: \n");
printf("* Extract DBCs: %s\n", (extractFlags & Constants::EXTRACT_FLAG_DBC) ? "Yes" : "No");
printf("* Extract Maps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_MAPS) ? "Yes" : "No");
printf("* Extract VMaps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_VMAPS) ? "Yes" : "No");
printf("* Extract GameObject Models: %s\n", (extractFlags & Constants::EXTRACT_FLAG_GOB_MODELS) ? "Yes" : "No");
printf("* Extract MMaps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_MMAPS) ? "Yes" : "No");
}
}
return true;
}
void PrintUsage()
{
printf("MeshExtractor help.\n");
printf("* Use \"--threads <number>\" to specify <number> threads, default to 4 (Only available when extracting MMaps)\n");
printf("* Use \"--maps a,b,c,d,e\" to extract only the maps specified (Do not use spaces)\n");
printf("* Use \"--debug 1\" to generate debug information of the tiles (Only available when extracting MMaps)\n");
printf("* Use \"--extract X\" to extract the data specified by the flag X (Note: You can combine the flags with the bitwise OR operator |). Available flags are: \n");
{
printf("- %u to extract DBCs\n", Constants::EXTRACT_FLAG_DBC);
printf("- %u to extract Maps (Not yet implemented)\n", Constants::EXTRACT_FLAG_MAPS);
printf("- %u to extract VMaps (Not yet implemented)\n", Constants::EXTRACT_FLAG_VMAPS);
printf("- %u to extract GameObject models (Not yet finished, you need to run VMapAssembler on the extracted files)\n", Constants::EXTRACT_FLAG_GOB_MODELS);
printf("- %u to extract MMaps (Not yet finished)\n", Constants::EXTRACT_FLAG_MMAPS);
}
}
void LoadTile(dtNavMesh*& navMesh, const char* tile)
{
FILE* f = fopen(tile, "rb");
if (!f)
return;
MmapTileHeader header;
if (fread(&header, sizeof(MmapTileHeader), 1, f) != 1)
return;
uint8* nav = new uint8[header.size];
if (fread(nav, header.size, 1, f) != 1)
return;
navMesh->addTile(nav, header.size, DT_TILE_FREE_DATA, 0, nullptr);
fclose(f);
}
int main(int argc, char* argv[])
{
_setmaxstdio(2048);
uint32 threads = 4, extractFlags = 0;
std::set<uint32> mapIds;
if (!HandleArgs(argc, argv, threads, mapIds, Constants::Debug, extractFlags))
{
PrintUsage();
return -1;
}
if (extractFlags == 0)
{
printf("You must provide valid extract flags.\n");
PrintUsage();
return -1;
}
Cache = new CacheClass();
MPQHandler = new MPQMgr();
MPQHandler->Initialize();
if (extractFlags & Constants::EXTRACT_FLAG_DBC)
ExtractDBCs();
if (extractFlags & Constants::EXTRACT_FLAG_MMAPS)
ExtractMMaps(mapIds, threads);
if (extractFlags & Constants::EXTRACT_FLAG_GOB_MODELS)
ExtractGameobjectModels();
if (extractFlags & Constants::EXTRACT_FLAG_TEST)
{
float start[] = { 16226.200195f, 16257.000000f, 13.202200f };
float end[] = { 16245.725586f, 16382.465820f, 47.384956f };
//
float m_spos[3];
m_spos[0] = -start[1];
m_spos[1] = start[2];
m_spos[2] = -start[0];
//
float m_epos[3];
m_epos[0] = -end[1];
m_epos[1] = end[2];
m_epos[2] = -end[0];
//
dtQueryFilterExt m_filter;
m_filter.setIncludeFlags(Constants::POLY_AREA_ROAD | Constants::POLY_AREA_TERRAIN);
m_filter.setExcludeFlags(Constants::POLY_AREA_WATER);
//
float m_polyPickExt[3];
m_polyPickExt[0] = 2.5f;
m_polyPickExt[1] = 2.5f;
m_polyPickExt[2] = 2.5f;
//
dtPolyRef m_startRef;
dtPolyRef m_endRef;
FILE* mmap = fopen("mmaps/001.mmap", "rb");
dtNavMeshParams params;
int count = fread(&params, sizeof(dtNavMeshParams), 1, mmap);
fclose(mmap);
if (count != 1)
{
printf("main: Error reading from .mmap\n");
return 0;
}
dtNavMesh* navMesh = new dtNavMesh();
dtNavMeshQuery* navMeshQuery = new dtNavMeshQuery();
navMesh->init(&params);
for (int i = 0; i <= 32; ++i)
{
for (int j = 0; j <= 32; ++j)
{
char buff[100];
sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j);
LoadTile(navMesh, buff);
}
}
navMeshQuery->init(navMesh, 2048);
float nearestPt[3];
navMeshQuery->findNearestPoly(m_spos, m_polyPickExt, &m_filter, &m_startRef, nearestPt);
navMeshQuery->findNearestPoly(m_epos, m_polyPickExt, &m_filter, &m_endRef, nearestPt);
if ( !m_startRef || !m_endRef )
{
std::cerr << "Could not find any nearby poly's (" << m_startRef << "," << m_endRef << ")" << std::endl;
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);
int resultHopCount;
float* straightPath = new float[2048 * 3];
unsigned char* pathFlags = new unsigned char[2048];
dtPolyRef* pathRefs = new dtPolyRef[2048];
status = navMeshQuery->findStraightPath(m_spos, m_epos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048);
std::vector<Vector3> FinalPath;
FinalPath.reserve(resultHopCount);
for (int32 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;
}

View File

@@ -1,83 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Model.h"
#include "MPQMgr.h"
#include "Utils.h"
Model::Model( std::string path ) : IsCollidable(false), IsBad(false)
{
Stream = MPQHandler->GetFile(Utils::FixModelPath(path));
if (!Stream)
{
IsBad = true;
return;
}
Header.Read(Stream);
if (Header.OffsetBoundingNormals > 0 && Header.OffsetBoundingVertices > 0 &&
Header.OffsetBoundingTriangles > 0 && Header.BoundingRadius > 0.0f)
{
IsCollidable = true;
ReadVertices();
ReadBoundingNormals();
ReadBoundingTriangles();
}
}
Model::~Model()
{
if (Stream)
fclose(Stream);
}
void Model::ReadVertices()
{
fseek(Stream, Header.OffsetBoundingVertices, SEEK_SET);
Vertices.reserve(Header.CountBoundingVertices);
for (uint32 i = 0; i < Header.CountBoundingVertices; ++i)
{
Vertices.push_back(Vector3::Read(Stream));
if (Constants::ToWoWCoords)
Vertices[i] = Utils::ToWoWCoords(Vertices[i]);
}
}
void Model::ReadBoundingTriangles()
{
fseek(Stream, 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);
Triangles.push_back(tri);
}
}
void Model::ReadBoundingNormals()
{
fseek(Stream, Header.OffsetBoundingNormals, SEEK_SET);
Normals.reserve(Header.CountBoundingNormals);
for (uint32 i = 0; i < Header.CountBoundingNormals; i++)
Normals.push_back(Vector3::Read(Stream));
}

View File

@@ -1,40 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MODEL_H
#define MODEL_H
#include "Utils.h"
#include <vector>
class Model
{
public:
Model(std::string path);
~Model();
void ReadVertices();
void ReadBoundingTriangles();
void ReadBoundingNormals();
ModelHeader Header;
std::vector<Vector3> Vertices;
std::vector<Vector3> Normals;
std::vector<Triangle<uint16>> Triangles;
bool IsCollidable;
FILE* Stream;
bool IsBad;
};
#endif

View File

@@ -1,24 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ObjectDataHandler.h"
#include "ADT.h"
void ObjectDataHandler::ProcessMapChunk( MapChunk* chunk )
{
ProcessInternal(chunk);
}

View File

@@ -1,32 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ODATA_HNDL_H
#define ODATA_HNDL_H
#include "ADT.h"
#include "MapChunk.h"
class ObjectDataHandler
{
public:
ObjectDataHandler(ADT* _adt) : Source(_adt) {}
void ProcessMapChunk(MapChunk* chunk);
virtual void ProcessInternal(MapChunk* data) = 0;
ADT* Source;
};
#endif

View File

@@ -1,412 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TileBuilder.h"
#include "ADT.h"
#include "Cache.h"
#include "Constants.h"
#include "ContinentBuilder.h"
#include "DetourNavMeshBuilder.h"
#include "Geometry.h"
#include "Recast.h"
#include "RecastAlloc.h"
#include "Utils.h"
#include "WDT.h"
#include "WorldModelRoot.h"
TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId) :
World(world), X(x), Y(y), MapId(mapId), _Geometry(nullptr), DataSize(0), cBuilder(_cBuilder)
{
// Config for normal maps
memset(&Config, 0, sizeof(rcConfig));
Config.cs = Constants::TileSize / 1800.0f; // TileSize / voxelSize
Config.ch = 0.3f;
Config.minRegionArea = 36;
Config.mergeRegionArea = 144;
Config.walkableSlopeAngle = 50.0f;
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.maxEdgeLen = Config.walkableRadius * 8;
Config.borderSize = Config.walkableRadius + 8;
Config.tileSize = 1800;
Config.maxSimplificationError = 1.3f;
Config.maxVertsPerPoly = 6;
// Config for instances
memset(&InstanceConfig, 0, sizeof(rcConfig));
InstanceConfig.cs = 0.2f;
InstanceConfig.ch = 0.3f;
InstanceConfig.minRegionArea = 25;
InstanceConfig.mergeRegionArea = 100;
InstanceConfig.walkableSlopeAngle = 50.0f;
InstanceConfig.detailSampleDist = 3.0f;
InstanceConfig.detailSampleMaxError = 1.5f;
InstanceConfig.walkableClimb = 1.0f / InstanceConfig.ch;
InstanceConfig.walkableHeight = 2.1f / InstanceConfig.ch;
InstanceConfig.walkableRadius = 0.6f / InstanceConfig.cs;
InstanceConfig.maxEdgeLen = 8 * InstanceConfig.walkableRadius;
InstanceConfig.maxVertsPerPoly = 6;
InstanceConfig.maxSimplificationError = 1.25f;
InstanceConfig.borderSize = 0;
Context = new rcContext;
}
void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ )
{
bmin = new float[3];
bmax = new float[3];
bmin[0] = Constants::Origin[0] /*navMeshParams.orig[0]*/ + (Constants::TileSize * X);
bmin[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * Y);
bmax[0] = Constants::Origin[0] /*navMeshParams.orig[0]*/ + (Constants::TileSize * (X + 1));
bmax[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * (Y + 1));
}
void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def)
{
_Geometry = new Geometry();
_Geometry->Transform = true;
WorldModelHandler::InsertModelGeometry(_Geometry->Vertices, _Geometry->Triangles, def, root, false);
OutputDebugVertices();
}
uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams )
{
float* bmin = nullptr, *bmax = nullptr;
_Geometry->CalculateBoundingBox(bmin, bmax);
rcVcopy(InstanceConfig.bmax, bmax);
rcVcopy(InstanceConfig.bmin, bmin);
uint32 numVerts = _Geometry->Vertices.size();
uint32 numTris = _Geometry->Triangles.size();
float* vertices;
int* triangles;
uint8* areas;
_Geometry->GetRawData(vertices, triangles, areas);
// this sets the dimensions of the heightfield
rcCalcGridSize(InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, &InstanceConfig.width, &InstanceConfig.height);
rcHeightfield* hf = rcAllocHeightfield();
rcCreateHeightfield(Context, *hf, InstanceConfig.width, InstanceConfig.height, InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, InstanceConfig.ch);
rcClearUnwalkableTriangles(Context, InstanceConfig.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas);
rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, InstanceConfig.walkableClimb);
rcFilterLowHangingWalkableObstacles(Context, InstanceConfig.walkableClimb, *hf);
rcFilterLedgeSpans(Context, InstanceConfig.walkableHeight, InstanceConfig.walkableClimb, *hf);
rcFilterWalkableLowHeightSpans(Context, InstanceConfig.walkableHeight, *hf);
rcCompactHeightfield* chf = rcAllocCompactHeightfield();
rcBuildCompactHeightfield(Context, InstanceConfig.walkableHeight, InstanceConfig.walkableClimb, *hf, *chf);
rcErodeWalkableArea(Context, InstanceConfig.walkableRadius, *chf);
rcBuildDistanceField(Context, *chf);
rcBuildRegions(Context, *chf, InstanceConfig.borderSize, InstanceConfig.minRegionArea, InstanceConfig.minRegionArea);
rcContourSet* contours = rcAllocContourSet();
rcBuildContours(Context, *chf, InstanceConfig.maxSimplificationError, InstanceConfig.maxEdgeLen, *contours);
rcPolyMesh* pmesh = rcAllocPolyMesh();
rcBuildPolyMesh(Context, *contours, InstanceConfig.maxVertsPerPoly, *pmesh);
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
rcBuildPolyMeshDetail(Context, *pmesh, *chf, InstanceConfig.detailSampleDist, InstanceConfig.detailSampleMaxError, *dmesh);
// Set flags according to area types (e.g. Swim for Water)
for (int i = 0; i < pmesh->npolys; i++)
{
if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
pmesh->flags[i] = Constants::POLY_FLAG_WALK;
else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
}
dtNavMeshCreateParams params;
memset(&params, 0, sizeof(params));
// PolyMesh data
params.verts = pmesh->verts;
params.vertCount = pmesh->nverts;
params.polys = pmesh->polys;
params.polyAreas = pmesh->areas;
params.polyFlags = pmesh->flags;
params.polyCount = pmesh->npolys;
params.nvp = pmesh->nvp;
// PolyMeshDetail data
params.detailMeshes = dmesh->meshes;
params.detailVerts = dmesh->verts;
params.detailVertsCount = dmesh->nverts;
params.detailTris = dmesh->tris;
params.detailTriCount = dmesh->ntris;
rcVcopy(params.bmin, pmesh->bmin);
rcVcopy(params.bmax, pmesh->bmax);
// General settings
params.ch = InstanceConfig.ch;
params.cs = InstanceConfig.cs;
params.walkableClimb = InstanceConfig.walkableClimb * InstanceConfig.ch;
params.walkableHeight = InstanceConfig.walkableHeight * InstanceConfig.ch;
params.walkableRadius = InstanceConfig.walkableRadius * InstanceConfig.cs;
params.tileX = X;
params.tileY = Y;
params.tileLayer = 0;
params.buildBvTree = true;
rcVcopy(params.bmax, bmax);
rcVcopy(params.bmin, bmin);
// Offmesh-connection settings
params.offMeshConCount = 0; // none for now
rcFreeHeightField(hf);
rcFreeCompactHeightfield(chf);
rcFreeContourSet(contours);
delete vertices;
delete triangles;
delete areas;
delete bmin;
delete bmax;
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount)
{
// we have flat tiles with no actual geometry - don't build those, its useless
// keep in mind that we do output those into debug info
// drop tiles with only exact count - some tiles may have geometry while having less tiles
printf("No polygons to build on tile, skipping.\n");
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
return nullptr;
}
int navDataSize;
uint8* navData;
printf("Creating the navmesh with %i vertices, %i polys, %i triangles!\n", params.vertCount, params.polyCount, params.detailTriCount);
bool result = dtCreateNavMeshData(&params, &navData, &navDataSize);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
if (result)
{
printf("NavMesh created, size %i!\n", navDataSize);
DataSize = navDataSize;
return navData;
}
return nullptr;
}
uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
{
_Geometry = new Geometry();
_Geometry->Transform = true;
ADT* adt = new ADT(Utils::GetAdtPath(World, X, Y), X, Y);
adt->Read();
_Geometry->AddAdt(adt);
delete adt;
if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty())
return nullptr;
float* bmin = nullptr, *bmax = nullptr;
CalculateTileBounds(bmin, bmax, navMeshParams);
_Geometry->CalculateMinMaxHeight(bmin[1], bmax[1]);
// 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++)
{
// don't load main tile again
if (tx == X && ty == Y)
continue;
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)
{
delete _adt;
continue;
}
_adt->Read();
_Geometry->AddAdt(_adt);
delete _adt;
}
}
OutputDebugVertices();
uint32 numVerts = _Geometry->Vertices.size();
uint32 numTris = _Geometry->Triangles.size();
float* vertices;
int* triangles;
uint8* areas;
_Geometry->GetRawData(vertices, triangles, areas);
_Geometry->Vertices.clear();
_Geometry->Triangles.clear();
// add border
bmin[0] -= Config.borderSize * Config.cs;
bmin[2] -= Config.borderSize * Config.cs;
bmax[0] += Config.borderSize * Config.cs;
bmax[2] += Config.borderSize * Config.cs;
rcHeightfield* hf = rcAllocHeightfield();
int width = Config.tileSize + (Config.borderSize * 2);
rcCreateHeightfield(Context, *hf, width, width, bmin, bmax, Config.cs, Config.ch);
rcClearUnwalkableTriangles(Context, Config.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas);
rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, Config.walkableClimb);
rcFilterLowHangingWalkableObstacles(Context, Config.walkableClimb, *hf);
rcFilterLedgeSpans(Context, Config.walkableHeight, Config.walkableClimb, *hf);
rcFilterWalkableLowHeightSpans(Context, Config.walkableHeight, *hf);
rcCompactHeightfield* chf = rcAllocCompactHeightfield();
rcBuildCompactHeightfield(Context, Config.walkableHeight, Config.walkableClimb, *hf, *chf);
rcErodeWalkableArea(Context, Config.walkableRadius, *chf);
rcBuildDistanceField(Context, *chf);
rcBuildRegions(Context, *chf, Config.borderSize, Config.minRegionArea, Config.mergeRegionArea);
rcContourSet* contours = rcAllocContourSet();
rcBuildContours(Context, *chf, Config.maxSimplificationError, Config.maxEdgeLen, *contours);
rcPolyMesh* pmesh = rcAllocPolyMesh();
rcBuildPolyMesh(Context, *contours, Config.maxVertsPerPoly, *pmesh);
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh);
// Set flags according to area types (e.g. Swim for Water)
for (int i = 0; i < pmesh->npolys; i++)
{
if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
pmesh->flags[i] = Constants::POLY_FLAG_WALK;
else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
}
dtNavMeshCreateParams params;
memset(&params, 0, sizeof(params));
// PolyMesh data
params.verts = pmesh->verts;
params.vertCount = pmesh->nverts;
params.polys = pmesh->polys;
params.polyAreas = pmesh->areas;
params.polyFlags = pmesh->flags;
params.polyCount = pmesh->npolys;
params.nvp = pmesh->nvp;
// PolyMeshDetail data
params.detailMeshes = dmesh->meshes;
params.detailVerts = dmesh->verts;
params.detailVertsCount = dmesh->nverts;
params.detailTris = dmesh->tris;
params.detailTriCount = dmesh->ntris;
// General settings
params.ch = Config.ch;
params.cs = Config.cs;
params.walkableClimb = Config.walkableClimb * Config.ch;
params.walkableHeight = Config.walkableHeight * Config.ch;
params.walkableRadius = Config.walkableRadius * Config.cs;
params.tileX = X;
params.tileY = Y;
params.tileLayer = 0;
params.buildBvTree = true;
// Recalculate the bounds with the added geometry
float* bmin2 = nullptr, *bmax2 = nullptr;
CalculateTileBounds(bmin2, bmax2, navMeshParams);
bmin2[1] = bmin[1];
bmax2[1] = bmax[1];
rcVcopy(params.bmax, bmax2);
rcVcopy(params.bmin, bmin2);
// Offmesh-connection settings
params.offMeshConCount = 0; // none for now
rcFreeHeightField(hf);
rcFreeCompactHeightfield(chf);
rcFreeContourSet(contours);
delete vertices;
delete triangles;
delete areas;
delete bmin;
delete bmax;
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount)
{
// we have flat tiles with no actual geometry - don't build those, its useless
// keep in mind that we do output those into debug info
// drop tiles with only exact count - some tiles may have geometry while having less tiles
printf("[%02i, %02i] No polygons to build on tile, skipping.\n", X, Y);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
return nullptr;
}
int navDataSize;
uint8* navData;
printf("[%02i, %02i] Creating the navmesh with %i vertices, %i polys, %i triangles!\n", X, Y, params.vertCount, params.polyCount, params.detailTriCount);
bool result = dtCreateNavMeshData(&params, &navData, &navDataSize);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
if (result)
{
printf("[%02i, %02i] NavMesh created, size %i!\n", X, Y, navDataSize);
DataSize = navDataSize;
return navData;
}
return nullptr;
}
void TileBuilder::OutputDebugVertices()
{
if (Constants::Debug)
{
char buff[100];
sprintf(buff, "mmaps/%s_%02u%02u.obj", World.c_str(), Y, X);
FILE* debug = fopen(buff, "wb");
for (uint32 i = 0; i < _Geometry->Vertices.size(); ++i)
{
const Vector3& vector = _Geometry->Vertices[i];
fprintf(debug, "v %f %f %f\n", vector.x, vector.y, vector.z);
}
for (uint32 i = 0; i < _Geometry->Triangles.size(); ++i)
{
const Triangle<uint32>& triangle = _Geometry->Triangles[i];
fprintf(debug, "f %u %u %u\n", triangle.V0 + 1, triangle.V1 + 1, triangle.V2 + 1);
}
fclose(debug);
}
}
TileBuilder::~TileBuilder()
{
delete Context;
delete _Geometry;
}

View File

@@ -1,51 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TILE_BUILD_H
#define TILE_BUILD_H
#include "Recast.h"
#include <string>
#include "Geometry.h"
#include "WorldModelRoot.h"
class ContinentBuilder;
class WDT;
class TileBuilder
{
public:
TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId);
~TileBuilder();
void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams);
uint8* BuildTiled(dtNavMeshParams& navMeshParams);
uint8* BuildInstance(dtNavMeshParams& navMeshParams);
void AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def);
void OutputDebugVertices();
std::string World;
int X;
int Y;
int MapId;
rcConfig Config;
rcConfig InstanceConfig;
rcContext* Context;
Geometry* _Geometry;
uint32 DataSize;
ContinentBuilder* cBuilder;
};
#endif

View File

@@ -1,563 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Utils.h"
#include "Constants.h"
#include "G3D/Matrix4.h"
#include "G3D/Quat.h"
#include "WorldModelHandler.h"
#include <cstring>
#ifdef _WIN32
#include "direct.h"
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
const float Constants::TileSize = 533.0f + (1 / 3.0f);
const float Constants::MaxXY = 32.0f * Constants::TileSize;
const float Constants::ChunkSize = Constants::TileSize / 16.0f;
const float Constants::UnitSize = Constants::ChunkSize / 8.0f;
const float Constants::Origin[] = { -Constants::MaxXY, 0.0f, -Constants::MaxXY };
const float Constants::PI = 3.1415926f;
const float Constants::MaxStandableHeight = 1.5f;
const char* Constants::VMAPMagic = "VMAP044";
bool Constants::ToWoWCoords = false;
bool Constants::Debug = false;
const float Constants::BaseUnitDim = 0.533333f;
const int Constants::VertexPerMap = (Constants::TileSize / Constants::BaseUnitDim) + 0.5f;
const int Constants::VertexPerTile = 40;
const int Constants::TilesPerMap = Constants::VertexPerMap / Constants::VertexPerTile;
void Utils::CreateDir( const std::string& Path )
{
#ifdef _WIN32
_mkdir( Path.c_str());
#else
mkdir( Path.c_str(), 0777 );
#endif
}
void Utils::Reverse(char word[])
{
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;
}
Vector3 Utils::ToRecast(const Vector3& val )
{
return Vector3(-val.y, val.z, -val.x);
}
std::string Utils::GetAdtPath(const std::string& world, int x, int y )
{
return "World\\Maps\\" + world + "\\" + world + "_" + Utils::ToString(x) + "_" + Utils::ToString(y) + ".adt";
}
std::string Utils::FixModelPath(const std::string& path )
{
return Utils::GetPathBase(path) + ".M2";
}
Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate)
{
// Sources of information:
/// http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18&oldid=3715
// This function applies to both external doodads and WMOs
// Rotate our Doodad vertex
G3D::Matrix4 rot = G3D::Matrix3::fromEulerAnglesXYZ(Utils::ToRadians(def.Rotation.z), Utils::ToRadians(-def.Rotation.x), Utils::ToRadians(def.Rotation.y + 180));
Vector3 ret = Utils::VectorTransform(vec, rot);
// And finally scale and translate it to our origin
ret = ret * def.Scale();
if (translate)
ret = ret + Vector3(Constants::MaxXY - def.Position.z, Constants::MaxXY - def.Position.x, def.Position.y);
return ret;
}
Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate )
{
G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW);
Vector3 ret = Utils::VectorTransform(vec, G3D::Matrix4(quat.toRotationMatrix()));
ret = ret * (inst.Scale / 1024.0f);
if (translate)
ret = ret + Vector3(Constants::MaxXY - inst.Position.z, Constants::MaxXY - inst.Position.x, inst.Position.y);
return ret;
}
float Utils::ToRadians( float degrees )
{
return Constants::PI * degrees / 180.0f;
}
Vector3 Utils::VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal )
{
G3D::Vector3 ret(vec.x, vec.y, vec.z);
ret = matrix.homoMul(ret, normal ? 0 : 1);
return Vector3(ret.x, ret.y, ret.z);
}
std::string Utils::GetPathBase(const std::string& path )
{
size_t lastIndex = path.find_last_of(".");
if (lastIndex != std::string::npos)
return path.substr(0, lastIndex);
return path;
}
Vector3 Vector3::Read( FILE* 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;
}
Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate)
{
if (Utils::Distance(height, 0.0f) > 0.5f)
basePosition.z = 0.0f;
return Utils::TransformDoodadVertex(def, basePosition + Vector3(x * Constants::UnitSize, y * Constants::UnitSize, height), translate);
}
float Utils::Distance( float x, float y )
{
return std::sqrt(x * x + y * y);
}
std::string Utils::Replace( std::string str, const std::string& oldStr, const std::string& newStr )
{
size_t pos = 0;
while ((pos = str.find(oldStr, pos)) != std::string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
return str;
}
void Utils::SaveToDisk( FILE* 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);
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;
}
// 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);
fclose(disk);
return;
}
// Close the filestream
fclose(disk);
fclose(stream);
// Free the used memory
delete[] data;
}
Vector3 Utils::ToWoWCoords(const Vector3& vec )
{
return Vector3(-vec.z, -vec.x, vec.y);
}
std::string Utils::GetExtension( std::string path )
{
std::string::size_type idx = path.rfind('.');
std::string extension = "";
if (idx != std::string::npos)
extension = path.substr(idx + 1);
return extension;
}
void MapChunkHeader::Read(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);
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);
}
void MHDR::Read(FILE* 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);
}
void ModelHeader::Read(FILE* stream)
{
int count = 0;
count += fread(&Magic, sizeof(char), 4, stream);
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);
VertexBox[0] = Vector3::Read(stream);
VertexBox[1] = Vector3::Read(stream);
count += fread(&VertexRadius, sizeof(float), 1, stream);
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;
}
DoodadInstance DoodadInstance::Read(FILE* stream)
{
DoodadInstance ret;
int count = 0;
count += fread(&ret.FileOffset, sizeof(uint32), 1, stream);
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);
return ret;
}
DoodadSet DoodadSet::Read(FILE* 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);
return ret;
}
LiquidHeader LiquidHeader::Read(FILE* 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;
}
LiquidData LiquidData::Read(FILE* stream, LiquidHeader& header)
{
LiquidData ret;
ret.HeightMap = new float*[header.CountXVertices];
for (uint32 i = 0; i < header.CountXVertices; ++i)
ret.HeightMap[i] = new float[header.CountYVertices];
ret.RenderFlags = new uint8*[header.Width];
for (uint32 i = 0; i < header.Width; ++i)
ret.RenderFlags[i] = new uint8[header.Height];
for (uint32 y = 0; y < header.CountYVertices; y++)
{
for (uint32 x = 0; x < header.CountXVertices; x++)
{
uint32 discard;
float tmp;
if (fread(&discard, sizeof(uint32), 1, stream) == 1 &&
fread(&tmp, sizeof(float), 1, stream) == 1)
{
ret.HeightMap[x][y] = tmp;
}
}
}
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;
}
H2ORenderMask H2ORenderMask::Read(FILE* 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);
return ret;
}
bool MCNKLiquidData::IsWater(int x, int y, float height)
{
if (!Heights)
return false;
if (!Mask.ShouldRender(x, y))
return false;
float diff = Heights[x][y] - height;
if (diff > Constants::MaxStandableHeight)
return true;
return false;
}
H2OHeader H2OHeader::Read(FILE* stream)
{
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 (count != 3)
printf("H2OHeader::Read: Failed to read some data expected 3, read %d\n", count);
return ret;
}
H2OInformation H2OInformation::Read(FILE* 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);
return ret;
}
char* Utils::GetPlainName(const char* FileName)
{
char* temp;
if ((temp = (char*)strrchr(FileName, '\\')) != nullptr)
FileName = temp + 1;
return (char*)FileName;
}
WMOGroupHeader WMOGroupHeader::Read( FILE* 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.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);
return ret;
}

View File

@@ -1,403 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UTILS_H
#define UTILS_H
#include <cstdio>
#include <sstream>
#include <string>
#include "DetourNavMesh.h"
#include "G3D/Matrix4.h"
#include "Constants.h"
#include "Define.h"
struct WorldModelDefinition;
class DoodadDefinition;
class DoodadInstance;
#define ASSERT(assertion) { if (!(assertion)) {fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)nullptr) = 0; } }
struct Vector3
{
Vector3() {}
Vector3(float X, float Y, float Z) : x(X), y(Y), z(Z) {}
float x;
float y;
float z;
Vector3 operator +(Vector3 const& other) const
{
return Vector3(x + other.x, y + other.y, z + other.z);
}
Vector3 operator -(Vector3 const& other) const
{
return Vector3(x - other.x, y - other.y, z - other.z);
}
template<typename T>
Vector3 operator *(T s) const
{
return Vector3(x * s, y * s, z * s);
}
static Vector3 Read(FILE* file);
};
struct TilePos
{
TilePos(int x, int y) : X(x), Y(y) {}
int X;
int Y;
};
template<typename T>
struct Triangle
{
Triangle() {}
Triangle(Constants::TriangleType type, T v0, T v1, T v2) : V0(v0), V1(v1), V2(v2), Type(type) {}
T V0;
T V1;
T V2;
Constants::TriangleType Type;
};
class MapChunkHeader
{
public:
MapChunkHeader() {}
uint32 Flags;
uint32 IndexX;
uint32 IndexY;
uint32 Layers;
uint32 DoodadRefs;
uint32 OffsetMCVT;
uint32 OffsetMCNR;
uint32 OffsetMCLY;
uint32 OffsetMCRF;
uint32 OffsetMCAL;
uint32 SizeMCAL;
uint32 OffsetMCSH;
uint32 SizeMCSH;
uint32 AreaId;
uint32 MapObjectRefs;
uint32 Holes;
uint32* LowQualityTextureMap;
uint32 PredTex;
uint32 NumberEffectDoodad;
uint32 OffsetMCSE;
uint32 SoundEmitters;
uint32 OffsetMCLQ;
uint32 SizeMCLQ;
Vector3 Position;
uint32 OffsetMCCV;
void Read(FILE* stream);
};
class MHDR
{
public:
MHDR() {}
uint32 Flags;
uint32 OffsetMCIN;
uint32 OffsetMTEX;
uint32 OffsetMMDX;
uint32 OffsetMMID;
uint32 OffsetMWMO;
uint32 OffsetMWID;
uint32 OffsetMDDF;
uint32 OffsetMODF;
uint32 OffsetMFBO;
uint32 OffsetMH2O;
uint32 OffsetMTFX;
void Read(FILE* stream);
};
class ModelHeader
{
public:
char Magic[5];
uint32 Version;
uint32 LengthModelName;
uint32 OffsetName;
uint32 ModelFlags;
uint32 CountGlobalSequences;
uint32 OffsetGlobalSequences;
uint32 CountAnimations;
uint32 OffsetAnimations;
uint32 CountAnimationLookup;
uint32 OffsetAnimationLookup;
uint32 CountBones;
uint32 OffsetBones;
uint32 CountKeyBoneLookup;
uint32 OffsetKeyBoneLookup;
uint32 CountVertices;
uint32 OffsetVertices;
uint32 CountViews;
uint32 CountColors;
uint32 OffsetColors;
uint32 CountTextures;
uint32 OffsetTextures;
uint32 CountTransparency;
uint32 OffsetTransparency;
uint32 CountUvAnimation;
uint32 OffsetUvAnimation;
uint32 CountTexReplace;
uint32 OffsetTexReplace;
uint32 CountRenderFlags;
uint32 OffsetRenderFlags;
uint32 CountBoneLookup;
uint32 OffsetBoneLookup;
uint32 CountTexLookup;
uint32 OffsetTexLookup;
uint32 CountTexUnits;
uint32 OffsetTexUnits;
uint32 CountTransLookup;
uint32 OffsetTransLookup;
uint32 CountUvAnimLookup;
uint32 OffsetUvAnimLookup;
Vector3 VertexBox[2];
float VertexRadius;
Vector3 BoundingBox[2];
float BoundingRadius;
uint32 CountBoundingTriangles;
uint32 OffsetBoundingTriangles;
uint32 CountBoundingVertices;
uint32 OffsetBoundingVertices;
uint32 CountBoundingNormals;
uint32 OffsetBoundingNormals;
void Read(FILE* stream);
};
class WorldModelHeader
{
public:
WorldModelHeader() {}
uint32 CountMaterials;
uint32 CountGroups;
uint32 CountPortals;
uint32 CountLights;
uint32 CountModels;
uint32 CountDoodads;
uint32 CountSets;
uint32 AmbientColorUnk;
uint32 WmoId;
Vector3 BoundingBox[2];
uint32 LiquidTypeRelated;
static WorldModelHeader Read(FILE* stream);
};
class DoodadInstance
{
public:
DoodadInstance() {}
uint32 FileOffset;
std::string File;
Vector3 Position;
float QuatW;
float QuatX;
float QuatY;
float QuatZ;
float Scale;
uint32 LightColor;
static DoodadInstance Read(FILE* stream);
};
class DoodadSet
{
public:
DoodadSet() {}
std::string Name;
uint32 FirstInstanceIndex;
uint32 CountInstances;
uint32 UnknownZero;
static DoodadSet Read(FILE* stream);
};
class LiquidHeader
{
public:
LiquidHeader() {}
uint32 CountXVertices;
uint32 CountYVertices;
uint32 Width;
uint32 Height;
Vector3 BaseLocation;
uint16 MaterialId;
static LiquidHeader Read(FILE* stream);
};
class LiquidData
{
public:
LiquidData() {}
float** HeightMap;
uint8** RenderFlags;
bool ShouldRender(int x, int y)
{
return RenderFlags[x][y] != 0x0F;
}
static LiquidData Read(FILE* stream, LiquidHeader& header);
};
class H2ORenderMask
{
public:
H2ORenderMask() {}
uint8 Mask[8];
bool ShouldRender(int x, int y)
{
return (Mask[y] >> x & 1) != 0;
}
static H2ORenderMask Read(FILE* stream);
};
class MCNKLiquidData
{
public:
MCNKLiquidData() {}
MCNKLiquidData(float** heights, H2ORenderMask mask) : Heights(heights), Mask(mask) {}
float** Heights;
H2ORenderMask Mask;
bool IsWater(int x, int y, float height);
};
class H2OHeader
{
public:
H2OHeader() {}
uint32 OffsetInformation;
uint32 LayerCount;
uint32 OffsetRender;
static H2OHeader Read(FILE* stream);
};
class H2OInformation
{
public:
H2OInformation() {}
uint16 LiquidType;
uint16 Flags;
float HeightLevel1;
float HeightLevel2;
uint8 OffsetX;
uint8 OffsetY;
uint8 Width;
uint8 Height;
uint32 OffsetMask2;
uint32 OffsetHeightmap;
static H2OInformation Read(FILE* stream);
};
class WMOGroupHeader
{
public:
WMOGroupHeader() {}
uint32 OffsetGroupName;
uint32 OffsetDescriptiveName;
uint32 Flags;
Vector3 BoundingBox[2];
uint32 OffsetPortals;
uint32 CountPortals;
uint16 CountBatches[4];
uint8 Fogs[4];
uint32 LiquidTypeRelated;
uint32 WmoId;
static WMOGroupHeader Read(FILE* stream);
};
// Dummy class to act as an interface.
class IDefinition
{
public:
Vector3 Position;
Vector3 Rotation;
virtual float Scale() const { return 1.0f; };
};
struct MmapTileHeader
{
uint32 mmapMagic;
uint32 dtVersion;
uint32 mmapVersion;
uint32 size;
bool usesLiquids;
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
};
class Utils
{
public:
static void Reverse(char word[]);
static std::string ReadString(FILE* file);
static uint32 Size(FILE* file);
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);
/// They say its better to declare template functions in the header files.
template <typename T>
static std::string ToString(T val)
{
std::stringstream ss;
ss << val;
return ss.str();
}
static float ToRadians(float degrees);
static std::string GetPathBase(const std::string& path);
static Vector3 GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int /*x*/, int /*y*/, bool translate = true);
static float Distance(float x, float y);
template<typename T>
static bool IsAllZero(T* arr, uint32 size)
{
for (uint32 i = 0; i < size; ++i)
if (arr[i])
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 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 );
};
#endif

View File

@@ -1,77 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WDT.h"
#include "Chunk.h"
#include "ChunkedData.h"
#include "Utils.h"
#include "WorldModelHandler.h"
WDT::WDT(std::string file) : IsGlobalModel(false), IsValid(false), Model(nullptr)
{
Data = new ChunkedData(file, 2);
ReadTileTable();
ReadGlobalModel();
}
void WDT::ReadGlobalModel()
{
Chunk* fileChunk = Data->GetChunkByName("MWMO");
Chunk* defChunk = Data->GetChunkByName("MODF");
if (!fileChunk || !defChunk)
return;
IsGlobalModel = true;
ModelDefinition = WorldModelDefinition::Read(defChunk->GetStream());
ModelFile = Utils::ReadString(fileChunk->GetStream());
Model = new WorldModelRoot(ModelFile);
}
void WDT::ReadTileTable()
{
Chunk* chunk = Data->GetChunkByName("MAIN");
if (!chunk)
return;
IsValid = true;
FILE* 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);
if (flags & hasTileFlag)
TileTable.push_back(TilePos(x, y));
}
}
}
bool WDT::HasTile( int x, int y )
{
for (std::vector<TilePos>::iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr)
if (itr->X == x && itr->Y == y)
return true;
return false;
}

View File

@@ -1,46 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WDT_H
#define WDT_H
#include <string>
#include <vector>
#include "ChunkedData.h"
#include "WorldModelHandler.h"
#include "WorldModelRoot.h"
#include "Utils.h"
class WDT
{
public:
WDT(std::string file);
ChunkedData* Data;
std::vector<TilePos> TileTable;
bool IsGlobalModel;
bool IsValid;
std::string ModelFile;
WorldModelDefinition ModelDefinition;
WorldModelRoot* Model;
bool HasTile(int x, int y);
private:
void ReadGlobalModel();
void ReadTileTable();
};
#endif

View File

@@ -1,160 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldModelGroup.h"
#include "Chunk.h"
#include "ChunkedData.h"
#include "Utils.h"
WorldModelGroup::WorldModelGroup( std::string path, int groupIndex ) : GroupIndex(groupIndex), MOBA(nullptr), IsBad(false), HasLiquidData(false)
{
Data = new ChunkedData(path);
if (!Data->Stream)
{
IsBad = true;
return;
}
Chunk* mainChunk = Data->GetChunkByName("MOGP");
int32 firstSub = mainChunk->FindSubChunkOffset("MOPY");
if (firstSub == -1)
return;
Name = Utils::GetPlainName(path.c_str());
FILE* stream = mainChunk->GetStream();
fseek(stream, firstSub, SEEK_SET);
SubData = new ChunkedData(stream, mainChunk->Length - firstSub);
ReadHeader();
ReadMaterials();
ReadTriangles();
ReadVertices();
ReadNormals();
ReadLiquid();
ReadBatches();
}
void WorldModelGroup::ReadNormals()
{
Chunk* chunk = SubData->GetChunkByName("MONR");
if (!chunk)
return;
uint32 normalCount = chunk->Length / 12;
ASSERT(normalCount == Vertices.size() && "normalCount is different than the Vertices count");
Normals.reserve(normalCount);
FILE* stream = chunk->GetStream();
for (uint32 i = 0; i < normalCount; i++)
Normals.push_back(Vector3::Read(stream));
}
void WorldModelGroup::ReadLiquid()
{
Chunk* chunk = SubData->GetChunkByName("MLIQ");
if (!chunk)
return;
HasLiquidData = true;
FILE* stream = chunk->GetStream();
LiquidDataHeader = LiquidHeader::Read(stream);
LiquidDataGeometry = LiquidData::Read(stream, LiquidDataHeader);
}
void WorldModelGroup::ReadVertices()
{
Chunk* chunk = SubData->GetChunkByName("MOVT");
if (!chunk)
return;
uint32 verticeCount = chunk->Length / 12;
Vertices.reserve(verticeCount);
FILE* stream = chunk->GetStream();
for (uint32 i = 0; i < verticeCount; i++)
Vertices.push_back(Vector3::Read(stream));
}
void WorldModelGroup::ReadTriangles()
{
Chunk* chunk = SubData->GetChunkByName("MOVI");
if (!chunk)
return;
uint32 triangleCount = chunk->Length / 6;
ASSERT(triangleCount == TriangleFlags.size() && "triangleCount != TriangleFlags.size()");
FILE* 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);
Triangles.push_back(Triangle<uint16>(Constants::TRIANGLE_TYPE_WMO, v0, v1, v2));
}
}
void WorldModelGroup::ReadMaterials()
{
Chunk* chunk = SubData->GetChunkByName("MOPY");
if (!chunk)
return;
FILE* 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);
// 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);
}
}
void WorldModelGroup::ReadHeader()
{
Chunk* chunk = Data->GetChunkByName("MOGP");
if (!chunk)
return;
FILE* stream = chunk->GetStream();
Header = WMOGroupHeader::Read(stream);
}
void WorldModelGroup::ReadBatches()
{
Chunk* chunk = Data->GetChunkByName("MOBA");
if (!chunk)
return;
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);
}

View File

@@ -1,55 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMOGROUP_H
#define WMOGROUP_H
#include "ChunkedData.h"
#include "Utils.h"
class WorldModelGroup
{
public:
WorldModelGroup(std::string path, int groupIndex);
ChunkedData* Data;
ChunkedData* SubData;
int GroupIndex;
std::string Name;
WMOGroupHeader Header;
std::vector<uint8> TriangleFlags;
std::vector<uint8> TriangleMaterials;
std::vector<Triangle<uint16>> Triangles;
std::vector<Vector3> Vertices;
std::vector<Vector3> Normals;
// @ToDo: Research.
uint16* MOBA;
uint32 MOBALength;
bool HasLiquidData;
bool IsBad;
LiquidHeader LiquidDataHeader;
LiquidData LiquidDataGeometry;
private:
void ReadNormals();
void ReadLiquid();
void ReadVertices();
void ReadTriangles();
void ReadMaterials();
void ReadHeader();
void ReadBatches();
};
#endif

View File

@@ -1,234 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldModelHandler.h"
#include "Cache.h"
#include "Chunk.h"
#include "Define.h"
#include "G3D/Matrix4.h"
#include "G3D/Quat.h"
#include "Model.h"
#include "WorldModelRoot.h"
#include <cstdio>
WorldModelDefinition WorldModelDefinition::Read( FILE* file )
{
WorldModelDefinition ret;
int count = 0;
count += fread(&ret.MwidIndex, sizeof(uint32), 1, file);
count += fread(&ret.UniqueId, sizeof(uint32), 1, file);
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);
return ret;
}
WorldModelHandler::WorldModelHandler( ADT* adt ) : ObjectDataHandler(adt), _definitions(nullptr), _paths(nullptr)
{
ReadModelPaths();
ReadDefinitions();
}
void WorldModelHandler::ProcessInternal( MapChunk* mcnk )
{
if (!IsSane())
return;
uint32 refCount = mcnk->Header.MapObjectRefs;
FILE* stream = mcnk->Source->GetStream();
fseek(stream, 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");
if (index < 0 || uint32(index) >= _definitions->size())
continue;
WorldModelDefinition wmo = (*_definitions)[index];
if (_drawn.find(wmo.UniqueId) != _drawn.end())
continue;
_drawn.insert(wmo.UniqueId);
if (wmo.MwidIndex >= _paths->size())
continue;
std::string path = (*_paths)[wmo.MwidIndex];
WorldModelRoot* model = Cache->WorldModelCache.Get(path);
if (!model)
{
model = new WorldModelRoot(path);
Cache->WorldModelCache.Insert(path, model);
}
Vertices.reserve(1000);
Triangles.reserve(1000);
InsertModelGeometry(Vertices, Triangles, wmo, model);
}
// Restore the stream position
fseek(stream, mcnk->Source->Offset, SEEK_SET);
}
void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32>>& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate )
{
for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
{
uint32 vertOffset = verts.size();
for (std::vector<Vector3>::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.
verts.push_back(translate ? v : Utils::ToRecast(v)); // Transform the vertex to world space
}
for (uint32 i = 0; i < group->Triangles.size(); ++i)
{
// only include colliding tris
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));
}
}
if (def.DoodadSet < root->DoodadSets.size())
{
DoodadSet set = root->DoodadSets[def.DoodadSet];
std::vector<DoodadInstance> instances;
instances.reserve(set.CountInstances);
for (uint32 i = set.FirstInstanceIndex; i < (set.CountInstances + set.FirstInstanceIndex); i++)
{
if (i >= root->DoodadInstances.size())
break;
instances.push_back(root->DoodadInstances[i]);
}
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);
}
if (!model->IsCollidable)
continue;
int vertOffset = verts.size();
for (std::vector<Vector3>::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)
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)
{
if (!group->HasLiquidData)
continue;
const LiquidHeader& liquidHeader = group->LiquidDataHeader;
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;
uint32 vertOffset = verts.size();
Vector3 v1 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x][y], x, y, translate);
Vector3 v2 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x + 1][y], x + 1, y, translate);
Vector3 v3 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x][y + 1], x, y + 1, translate);
Vector3 v4 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
liquidDataGeometry.HeightMap[x + 1][y + 1], x + 1, y + 1, translate);
verts.push_back(translate ? v1 : Utils::ToRecast(v1));
verts.push_back(translate ? v2 : Utils::ToRecast(v2));
verts.push_back(translate ? v3 : Utils::ToRecast(v3));
verts.push_back(translate ? v4 : Utils::ToRecast(v4));
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset + 2, vertOffset + 1));
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1));
}
}
}
}
}
void WorldModelHandler::ReadDefinitions()
{
Chunk* chunk = Source->ObjectData->GetChunkByName("MODF");
if (!chunk)
return;
const int32 definitionSize = 64;
uint32 definitionCount = chunk->Length / definitionSize;
_definitions = new std::vector<WorldModelDefinition>;
_definitions->reserve(definitionCount);
FILE* stream = chunk->GetStream();
for (uint32 i = 0; i < definitionCount; i++)
_definitions->push_back(WorldModelDefinition::Read(stream));
}
void WorldModelHandler::ReadModelPaths()
{
Chunk* mwid = Source->ObjectData->GetChunkByName("MWID");
Chunk* mwmo = Source->ObjectData->GetChunkByName("MWMO");
if (!mwid || !mwmo)
return;
uint32 paths = mwid->Length / 4;
_paths = new std::vector<std::string>;
_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));
}
}
WorldModelHandler::~WorldModelHandler()
{
delete _definitions;
delete _paths;
}

View File

@@ -1,64 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMODEL_HNDL_H
#define WMODEL_HNDL_H
#include "Define.h"
#include "ObjectDataHandler.h"
#include "Utils.h"
#include "WorldModelRoot.h"
#include <set>
#include <vector>
class ADT;
struct WorldModelDefinition : public IDefinition
{
public:
WorldModelDefinition() {}
uint32 MwidIndex;
uint32 UniqueId;
Vector3 UpperExtents;
Vector3 LowerExtents;
uint16 Flags;
uint16 DoodadSet;
static WorldModelDefinition Read(FILE* file);
};
class WorldModelHandler : public ObjectDataHandler
{
public:
WorldModelHandler(ADT* adt);
~WorldModelHandler();
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);
protected:
void ProcessInternal(MapChunk* data);
private:
void ReadDefinitions();
void ReadModelPaths();
std::set<uint32> _drawn;
std::vector<WorldModelDefinition>* _definitions;
std::vector<std::string>* _paths;
};
#endif

View File

@@ -1,96 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldModelRoot.h"
#include "ChunkedData.h"
#include "Utils.h"
WorldModelRoot::WorldModelRoot( std::string path )
{
Data = new ChunkedData(path);
Path = path;
ReadHeader();
ReadGroups();
ReadDoodadInstances();
ReadDoodadSets();
}
WorldModelRoot::~WorldModelRoot()
{
delete Data;
}
void WorldModelRoot::ReadGroups()
{
std::string pathBase = Utils::GetPathBase(Path);
Groups.reserve(Header.CountGroups);
for (uint32 i = 0; i < Header.CountGroups; i++)
{
char name[200];
sprintf(name, "%s_%03u.wmo", pathBase.c_str(), i);
WorldModelGroup group(name, i);
if (!group.IsBad)
Groups.push_back(group);
}
}
void WorldModelRoot::ReadDoodadSets()
{
Chunk* chunk = Data->GetChunkByName("MODS");
if (!chunk)
return;
FILE* 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++)
DoodadSets.push_back(DoodadSet::Read(stream));
}
void WorldModelRoot::ReadDoodadInstances()
{
Chunk* chunk = Data->GetChunkByName("MODD");
Chunk* nameChunk = Data->GetChunkByName("MODN");
if (!chunk || !nameChunk)
return;
const uint32 instanceSize = 40;
uint32 countInstances = chunk->Length / instanceSize;
DoodadInstances.reserve(countInstances);
for (uint32 i = 0; i < countInstances; i++)
{
FILE* stream = chunk->GetStream();
fseek(stream, instanceSize * i, SEEK_CUR);
DoodadInstance instance = DoodadInstance::Read(stream);
FILE* nameStream = nameChunk->GetStream();
if (instance.FileOffset >= nameChunk->Length)
continue;
fseek(nameStream, instance.FileOffset, SEEK_CUR);
instance.File = Utils::ReadString(nameStream);
DoodadInstances.push_back(instance);
}
}
void WorldModelRoot::ReadHeader()
{
Chunk* chunk = Data->GetChunkByName("MOHD");
if (!chunk)
return;
FILE* stream = chunk->GetStream();
Header = WorldModelHeader::Read(stream);
}

View File

@@ -1,44 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMOROOT_H
#define WMOROOT_H
#include <string>
#include <vector>
#include "ChunkedData.h"
#include "Utils.h"
#include "WorldModelGroup.h"
class WorldModelRoot
{
public:
WorldModelRoot(std::string path);
~WorldModelRoot();
std::string Path;
ChunkedData* Data;
WorldModelHeader Header;
std::vector<DoodadInstance> DoodadInstances;
std::vector<DoodadSet> DoodadSets;
std::vector<WorldModelGroup> Groups;
private:
void ReadGroups();
void ReadDoodadSets();
void ReadDoodadInstances();
void ReadHeader();
};
#endif

View File

@@ -1,6 +0,0 @@
Experimental mesh extractor.
Original work in C# by stschake
Thanks to:
Subv
~
For helping in the porting to C++