TrinityCore
Loading...
Searching...
No Matches
model.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "vmapexport.h"
19#include "Errors.h"
20#include "model.h"
21#include "StringFormat.h"
22#include "wmo.h"
23#include "adtfile.h"
24#include "cascfile.h"
25#include "VMapDefinitions.h"
26#include <G3D/Quat.h>
27#include <algorithm>
28#include <cstdio>
29#include <limits>
30
31extern std::shared_ptr<CASC::Storage> CascStorage;
32
33Model::Model(std::string &filename) : filename(filename), header(), vertices(nullptr), indices(nullptr)
34{
35}
36
38{
39 CASCFile f(CascStorage, filename.c_str());
40
41 if (f.isEof())
42 {
43 f.close();
44 // Do not show this error on console to avoid confusion, the extractor can continue working even if some models fail to load
45 //printf("Error loading model %s\n", filename.c_str());
46 return false;
47 }
48
49 _unload();
50
51 uint32 m2start = 0;
52 char const* ptr = f.getBuffer();
53 while (m2start + 4 < f.getSize() && memcmp(ptr, "MD20", 4) != 0)
54 {
55 ++m2start;
56 ++ptr;
57 if (m2start + sizeof(ModelHeader) > f.getSize())
58 return false;
59 }
60
61 memcpy(&header, f.getBuffer() + m2start, sizeof(ModelHeader));
64 {
65 f.seek(m2start);
69 for (uint32 i=0; i<header.nBoundingVertices; i++)
71 f.seek(m2start);
74 std::unique_ptr<uint16[]> tempindices = std::make_unique<uint16[]>(header.nBoundingTriangles);
75 f.read(tempindices.get(), header.nBoundingTriangles * 2);
76 std::copy_n(tempindices.get(), header.nBoundingTriangles, indices);
77 f.close();
78 }
79 else
80 {
81 //printf("not included %s\n", filename.c_str());
82 f.close();
83 return false;
84 }
85 return true;
86}
87
88bool Model::ConvertToVMAPModel(const char * outfilename)
89{
90 int N[12] = { };
91 FILE* output = fopen(outfilename, "wb");
92 if (!output)
93 {
94 printf("Can't create the output file '%s'\n", outfilename);
95 return false;
96 }
97 fwrite(VMAP::RAW_VMAP_MAGIC, 8, 1, output);
99 fwrite(&nVertices, sizeof(int), 1, output);
100 uint32 nofgroups = 1;
101 fwrite(&nofgroups, sizeof(uint32), 1, output);
102 fwrite(N, 4, 1, output);// RootWMOID
104 fwrite(&tcFlags, sizeof(ModelFlags), 1, output);
105 fwrite(N, 4 * 2, 1, output);// mogpFlags, groupWMOID
106 fwrite(&bounds, sizeof(AaBox3D), 1, output);//bbox, only needed for WMO currently
107 fwrite(N, 4, 1, output);// liquidflags
108 fwrite("GRP ", 4, 1, output);
109 uint32 branches = 1;
110 int wsize;
111 wsize = sizeof(branches) + sizeof(uint32) * branches;
112 fwrite(&wsize, sizeof(int), 1, output);
113 fwrite(&branches, sizeof(branches), 1, output);
115 fwrite(&nIndexes, sizeof(uint32), 1, output);
116 fwrite("INDX", 4, 1, output);
117 wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
118 fwrite(&wsize, sizeof(int), 1, output);
119 fwrite(&nIndexes, sizeof(uint32), 1, output);
120 if (nIndexes > 0)
121 {
122 for (uint32 i = 0; i < nIndexes; ++i)
123 {
124 if ((i % 3) - 1 == 0 && i + 1 < nIndexes)
125 {
126 uint32 tmp = indices[i];
127 indices[i] = indices[i + 1];
128 indices[i + 1] = tmp;
129 }
130 }
131 fwrite(indices, sizeof(uint32), nIndexes, output);
132 }
133
134 fwrite("VERT", 4, 1, output);
135 wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
136 fwrite(&wsize, sizeof(int), 1, output);
137 fwrite(&nVertices, sizeof(int), 1, output);
138 if (nVertices > 0)
139 {
140 for (uint32 vpos = 0; vpos < nVertices; ++vpos)
141 {
142 float tmp = vertices[vpos].y;
143 vertices[vpos].y = -vertices[vpos].z;
144 vertices[vpos].z = tmp;
145 }
146
147 fwrite(vertices, sizeof(float) * 3, nVertices, output);
148 }
149
150 fclose(output);
151
152 return true;
153}
154
156{
157 return Vec3D(v.x, v.z, -v.y);
158}
159
160void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 originalMapId, FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
161{
162 // scale factor - divide by 1024
163 float sc = doodadDef.Scale / 1024.0f;
164
165 Vec3D position = fixCoords(doodadDef.Position);
166
167 uint8 nameSet = 0;// not used for models
168 uint32 uniqueId = GenerateUniqueObjectId(doodadDef.UniqueId, 0, false);
169 uint8 tcflags = 0;
170 if (mapID != originalMapId)
171 tcflags |= MOD_PARENT_SPAWN;
172
173 //write Flags, NameSet, UniqueId, Pos, Rot, Scale, name
174 fwrite(&tcflags, sizeof(uint8), 1, pDirfile);
175 fwrite(&nameSet, sizeof(uint8), 1, pDirfile);
176 fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
177 fwrite(&position, sizeof(Vec3D), 1, pDirfile);
178 fwrite(&doodadDef.Rotation, sizeof(Vec3D), 1, pDirfile);
179 fwrite(&sc, sizeof(float), 1, pDirfile);
180 uint32 nlen = strlen(ModelInstName);
181 fwrite(&nlen, sizeof(uint32), 1, pDirfile);
182 fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
183
184 if (dirfileCache)
185 {
186 dirfileCache->emplace_back();
187 ADTOutputCache& cacheModelData = dirfileCache->back();
188 cacheModelData.Flags = tcflags & ~MOD_PARENT_SPAWN;
189 cacheModelData.Data.resize(
190 sizeof(uint8) + // nameSet
191 sizeof(uint32) + // uniqueId
192 sizeof(Vec3D) + // position
193 sizeof(Vec3D) + // doodadDef.Rotation
194 sizeof(float) + // sc
195 sizeof(uint32) + // nlen
196 nlen); // ModelInstName
197
198 uint8* cacheData = cacheModelData.Data.data();
199#define CACHE_WRITE(value, size, cnt, dest) memcpy(dest, value, size * cnt); dest += size * cnt;
200
201 CACHE_WRITE(&nameSet, sizeof(uint8), 1, cacheData);
202 CACHE_WRITE(&uniqueId, sizeof(uint32), 1, cacheData);
203 CACHE_WRITE(&position, sizeof(Vec3D), 1, cacheData);
204 CACHE_WRITE(&doodadDef.Rotation, sizeof(Vec3D), 1, cacheData);
205 CACHE_WRITE(&sc, sizeof(float), 1, cacheData);
206 CACHE_WRITE(&nlen, sizeof(uint32), 1, cacheData);
207 CACHE_WRITE(ModelInstName, sizeof(char), nlen, cacheData);
208 }
209}
210
211void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, bool isGlobalWmo, uint32 mapID, uint32 originalMapId,
212 FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
213{
214 if (doodadData.Sets.empty())
215 return;
216
217 G3D::Vector3 wmoPosition(wmo.Position.z, wmo.Position.x, wmo.Position.y);
218 G3D::Matrix3 wmoRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::toRadians(wmo.Rotation.y), G3D::toRadians(wmo.Rotation.x), G3D::toRadians(wmo.Rotation.z));
219
220 if (isGlobalWmo)
221 wmoPosition += G3D::Vector3(533.33333f * 32, 533.33333f * 32, 0.0f);
222
223 uint16 doodadId = 0;
224 auto extractSingleSet = [&](WMO::MODS const& doodadSetData)
225 {
226 for (uint16 doodadIndex : doodadData.References)
227 {
228 if (doodadIndex < doodadSetData.StartIndex ||
229 doodadIndex >= doodadSetData.StartIndex + doodadSetData.Count)
230 continue;
231
232 WMO::MODD const& doodad = doodadData.Spawns[doodadIndex];
233
234 std::string ModelInstName;
235 if (doodadData.Paths)
236 ModelInstName = &doodadData.Paths[doodad.NameIndex];
237 else if (doodadData.FileDataIds)
238 ModelInstName = Trinity::StringFormat("FILE{:08X}.xxx", doodadData.FileDataIds[doodad.NameIndex]);
239 else
240 ASSERT(false);
241
242 if (!ExtractSingleModel(ModelInstName))
243 continue;
244
245 uint32 nlen = ModelInstName.length();
246
247 ASSERT(doodadId < std::numeric_limits<uint16>::max());
248 ++doodadId;
249
250 G3D::Vector3 position = wmoPosition + (wmoRotation * G3D::Vector3(doodad.Position.x, doodad.Position.y, doodad.Position.z));
251
252 Vec3D rotation;
253 (G3D::Quat(doodad.Rotation.X, doodad.Rotation.Y, doodad.Rotation.Z, doodad.Rotation.W)
254 .toRotationMatrix() * wmoRotation)
255 .toEulerAnglesXYZ(rotation.z, rotation.x, rotation.y);
256
257 rotation.z = G3D::toDegrees(rotation.z);
258 rotation.x = G3D::toDegrees(rotation.x);
259 rotation.y = G3D::toDegrees(rotation.y);
260
261 uint8 nameSet = 0; // not used for models
262 uint32 uniqueId = GenerateUniqueObjectId(wmo.UniqueId, doodadId, false);
263 uint8 tcflags = 0;
264 if (mapID != originalMapId)
265 tcflags |= MOD_PARENT_SPAWN;
266
267 //write Flags, NameSet, UniqueId, Pos, Rot, Scale, name
268 fwrite(&tcflags, sizeof(uint8), 1, pDirfile);
269 fwrite(&nameSet, sizeof(uint8), 1, pDirfile);
270 fwrite(&uniqueId, sizeof(uint32), 1, pDirfile);
271 fwrite(&position, sizeof(Vec3D), 1, pDirfile);
272 fwrite(&rotation, sizeof(Vec3D), 1, pDirfile);
273 fwrite(&doodad.Scale, sizeof(float), 1, pDirfile);
274 fwrite(&nlen, sizeof(uint32), 1, pDirfile);
275 fwrite(ModelInstName.c_str(), sizeof(char), nlen, pDirfile);
276
277 if (dirfileCache)
278 {
279 dirfileCache->emplace_back();
280 ADTOutputCache& cacheModelData = dirfileCache->back();
281 cacheModelData.Flags = tcflags & ~MOD_PARENT_SPAWN;
282 cacheModelData.Data.resize(
283 sizeof(uint8) + // nameSet
284 sizeof(uint32) + // uniqueId
285 sizeof(Vec3D) + // position
286 sizeof(Vec3D) + // rotation
287 sizeof(float) + // doodad.Scale
288 sizeof(uint32) + // nlen
289 nlen); // ModelInstName
290
291 uint8* cacheData = cacheModelData.Data.data();
292 CACHE_WRITE(&nameSet, sizeof(uint8), 1, cacheData);
293 CACHE_WRITE(&uniqueId, sizeof(uint32), 1, cacheData);
294 CACHE_WRITE(&position, sizeof(Vec3D), 1, cacheData);
295 CACHE_WRITE(&rotation, sizeof(Vec3D), 1, cacheData);
296 CACHE_WRITE(&doodad.Scale, sizeof(float), 1, cacheData);
297 CACHE_WRITE(&nlen, sizeof(uint32), 1, cacheData);
298 CACHE_WRITE(ModelInstName.c_str(), sizeof(char), nlen, cacheData);
299 }
300 }
301 };
302
303 // first doodad set is always active
304 extractSingleSet(doodadData.Sets[0]);
305
306 if (wmo.DoodadSet != 0 && wmo.DoodadSet < doodadData.Sets.size())
307 extractSingleSet(doodadData.Sets[wmo.DoodadSet]);
308}
309
310#undef CACHE_WRITE
uint8_t uint8
Definition Define.h:156
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
#define ASSERT
Definition Errors.h:80
std::shared_ptr< CASC::Storage > CascStorage
Definition System.cpp:51
void seekRelative(int offset)
Definition cascfile.cpp:105
bool isEof()
Definition cascfile.h:45
void seek(int offset)
Definition cascfile.cpp:99
size_t read(void *dest, size_t bytes)
Definition cascfile.cpp:80
char * getBuffer()
Definition cascfile.h:43
size_t getSize()
Definition cascfile.h:41
void close()
Definition cascfile.cpp:111
Vec3D * vertices
Definition model.h:46
ModelHeader header
Definition model.h:45
std::string filename
Definition model.h:43
bool open()
Definition model.cpp:37
void _unload()
Definition model.h:36
AaBox3D bounds
Definition model.h:48
uint32 * indices
Definition model.h:47
Model(std::string &filename)
Definition model.cpp:33
bool ConvertToVMAPModel(char const *outfilename)
Definition model.cpp:88
Definition vec3d.h:22
float x
Definition vec3d.h:24
float y
Definition vec3d.h:24
float z
Definition vec3d.h:24
ExtractedModelData const * ExtractSingleModel(std::string &fname)
std::shared_ptr< CASC::Storage > CascStorage
Definition System.cpp:51
Vec3D fixCoordSystem(Vec3D const &v)
Definition model.cpp:155
#define CACHE_WRITE(value, size, cnt, dest)
Vec3D fixCoordSystem(Vec3D const &v)
Definition model.cpp:155
void Extract(ADT::MDDF const &doodadDef, char const *ModelInstName, uint32 mapID, uint32 originalMapId, FILE *pDirfile, std::vector< ADTOutputCache > *dirfileCache)
Definition model.cpp:160
void ExtractSet(WMODoodadData const &doodadData, ADT::MODF const &wmo, bool isGlobalWmo, uint32 mapID, uint32 originalMapId, FILE *pDirfile, std::vector< ADTOutputCache > *dirfileCache)
Definition model.cpp:211
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
const char RAW_VMAP_MAGIC[]
std::vector< uint8 > Data
Definition adtfile.h:56
uint8 Flags
Definition adtfile.h:55
uint32 UniqueId
Definition adtfile.h:31
Vec3D Position
Definition adtfile.h:32
Vec3D Rotation
Definition adtfile.h:33
uint16 Scale
Definition adtfile.h:34
Vec3D Rotation
Definition adtfile.h:43
uint32 UniqueId
Definition adtfile.h:41
Vec3D Position
Definition adtfile.h:42
uint16 DoodadSet
Definition adtfile.h:46
uint32 nBoundingVertices
uint32 nBoundingTriangles
AaBox3D collisionBox
uint32 ofsBoundingVertices
uint32 ofsBoundingTriangles
float X
Definition vec3d.h:75
float Z
Definition vec3d.h:75
float Y
Definition vec3d.h:75
float W
Definition vec3d.h:75
std::unordered_set< uint16 > References
Definition wmo.h:76
std::vector< WMO::MODS > Sets
Definition wmo.h:72
std::vector< WMO::MODD > Spawns
Definition wmo.h:75
std::unique_ptr< uint32[]> FileDataIds
Definition wmo.h:74
std::unique_ptr< char[]> Paths
Definition wmo.h:73
Quaternion Rotation
Definition wmo.h:61
uint32 NameIndex
Definition wmo.h:59
float Scale
Definition wmo.h:62
Vec3D Position
Definition wmo.h:60
uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId, bool isWmo)
ModelFlags
Definition vmapexport.h:36
@ MOD_PARENT_SPAWN
Definition vmapexport.h:30
static Vec3D fixCoords(Vec3D const &v)
Definition wmo.h:68