TrinityCore
WorldModel.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 "WorldModel.h"
19#include "VMapDefinitions.h"
20#include "MapTree.h"
21#include "ModelInstance.h"
22#include "ModelIgnoreFlags.h"
23
24using G3D::Vector3;
25using G3D::Ray;
26
27template<> struct BoundsTrait<VMAP::GroupModel>
28{
29 static void getBounds(const VMAP::GroupModel& obj, G3D::AABox& out) { out = obj.GetBound(); }
30};
31
32namespace VMAP
33{
34 bool IntersectTriangle(MeshTriangle const& tri, std::vector<Vector3>::const_iterator points, G3D::Ray const& ray, float& distance)
35 {
36 static const float EPS = 1e-5f;
37
38 // See RTR2 ch. 13.7 for the algorithm.
39
40 const Vector3 e1 = points[tri.idx1] - points[tri.idx0];
41 const Vector3 e2 = points[tri.idx2] - points[tri.idx0];
42 const Vector3 p(ray.direction().cross(e2));
43 const float a = e1.dot(p);
44
45 if (std::fabs(a) < EPS) {
46 // Determinant is ill-conditioned; abort early
47 return false;
48 }
49
50 const float f = 1.0f / a;
51 const Vector3 s(ray.origin() - points[tri.idx0]);
52 const float u = f * s.dot(p);
53
54 if ((u < 0.0f) || (u > 1.0f)) {
55 // We hit the plane of the m_geometry, but outside the m_geometry
56 return false;
57 }
58
59 const Vector3 q(s.cross(e1));
60 const float v = f * ray.direction().dot(q);
61
62 if ((v < 0.0f) || ((u + v) > 1.0f)) {
63 // We hit the plane of the triangle, but outside the triangle
64 return false;
65 }
66
67 const float t = f * e2.dot(q);
68
69 if ((t > 0.0f) && (t < distance))
70 {
71 // This is a new hit, closer than the previous one
72 distance = t;
73
74 /* baryCoord[0] = 1.0 - u - v;
75 baryCoord[1] = u;
76 baryCoord[2] = v; */
77
78 return true;
79 }
80 // This hit is after the previous hit, so ignore it
81 return false;
82 }
83
85 {
86 public:
87 TriBoundFunc(std::vector<Vector3>& vert): vertices(vert.begin()) { }
88 void operator()(MeshTriangle const& tri, G3D::AABox& out) const
89 {
90 G3D::Vector3 lo = vertices[tri.idx0];
91 G3D::Vector3 hi = lo;
92
93 lo = (lo.min(vertices[tri.idx1])).min(vertices[tri.idx2]);
94 hi = (hi.max(vertices[tri.idx1])).max(vertices[tri.idx2]);
95
96 out = G3D::AABox(lo, hi);
97 }
98 protected:
99 const std::vector<Vector3>::const_iterator vertices;
100 };
101
102 // ===================== WmoLiquid ==================================
103
104 WmoLiquid::WmoLiquid(uint32 width, uint32 height, Vector3 const& corner, uint32 type) :
105 iTilesX(width), iTilesY(height), iCorner(corner), iType(type)
106 {
107 if (width && height)
108 {
109 iHeight = new float[(width + 1) * (height + 1)];
110 iFlags = new uint8[width * height];
111 }
112 else
113 {
114 iHeight = new float[1];
115 iFlags = nullptr;
116 }
117 }
118
119 WmoLiquid::WmoLiquid(WmoLiquid const& other) : iHeight(nullptr), iFlags(nullptr)
120 {
121 *this = other; // use assignment operator...
122 }
123
125 {
126 delete[] iHeight;
127 delete[] iFlags;
128 }
129
131 {
132 if (this == &other)
133 return *this;
134 iTilesX = other.iTilesX;
135 iTilesY = other.iTilesY;
136 iCorner = other.iCorner;
137 iType = other.iType;
138 delete[] iHeight;
139 delete[] iFlags;
140 if (other.iHeight)
141 {
142 iHeight = new float[(iTilesX+1)*(iTilesY+1)];
143 memcpy(iHeight, other.iHeight, (iTilesX+1)*(iTilesY+1)*sizeof(float));
144 }
145 else
146 iHeight = nullptr;
147 if (other.iFlags)
148 {
149 iFlags = new uint8[iTilesX * iTilesY];
150 memcpy(iFlags, other.iFlags, iTilesX * iTilesY);
151 }
152 else
153 iFlags = nullptr;
154 return *this;
155 }
156
157 bool WmoLiquid::GetLiquidHeight(Vector3 const& pos, float& liqHeight) const
158 {
159 // simple case
160 if (!iFlags)
161 {
162 liqHeight = iHeight[0];
163 return true;
164 }
165
166 float tx_f = (pos.x - iCorner.x) / LIQUID_TILE_SIZE;
167 uint32 tx = uint32(tx_f);
168 if (tx_f < 0.0f || tx >= iTilesX)
169 return false;
170 float ty_f = (pos.y - iCorner.y) / LIQUID_TILE_SIZE;
171 uint32 ty = uint32(ty_f);
172 if (ty_f < 0.0f || ty >= iTilesY)
173 return false;
174
175 // check if tile shall be used for liquid level
176 // checking for 0x08 *might* be enough, but disabled tiles always are 0x?F:
177 if ((iFlags[tx + ty * iTilesX] & 0x0F) == 0x0F)
178 return false;
179
180 // (dx, dy) coordinates inside tile, in [0, 1]^2
181 float dx = tx_f - (float)tx;
182 float dy = ty_f - (float)ty;
183
184 /* Tesselate tile to two triangles (not sure if client does it exactly like this)
185
186 ^ dy
187 |
188 1 x---------x (1, 1)
189 | (b) / |
190 | / |
191 | / |
192 | / (a) |
193 x---------x---> dx
194 0 1
195 */
196
197 uint32 const rowOffset = iTilesX + 1;
198 if (dx > dy) // case (a)
199 {
200 float sx = iHeight[tx+1 + ty * rowOffset] - iHeight[tx + ty * rowOffset];
201 float sy = iHeight[tx+1 + (ty+1) * rowOffset] - iHeight[tx+1 + ty * rowOffset];
202 liqHeight = iHeight[tx + ty * rowOffset] + dx * sx + dy * sy;
203 }
204 else // case (b)
205 {
206 float sx = iHeight[tx+1 + (ty+1) * rowOffset] - iHeight[tx + (ty+1) * rowOffset];
207 float sy = iHeight[tx + (ty+1) * rowOffset] - iHeight[tx + ty * rowOffset];
208 liqHeight = iHeight[tx + ty * rowOffset] + dx * sx + dy * sy;
209 }
210 return true;
211 }
212
214 {
215 return 2 * sizeof(uint32) +
216 sizeof(Vector3) +
217 sizeof(uint32) +
218 (iFlags ? ((iTilesX + 1) * (iTilesY + 1) * sizeof(float) + iTilesX * iTilesY) : sizeof(float));
219 }
220
222 {
223 bool result = false;
224 if (fwrite(&iTilesX, sizeof(uint32), 1, wf) == 1 &&
225 fwrite(&iTilesY, sizeof(uint32), 1, wf) == 1 &&
226 fwrite(&iCorner, sizeof(Vector3), 1, wf) == 1 &&
227 fwrite(&iType, sizeof(uint32), 1, wf) == 1)
228 {
229 if (iTilesX && iTilesY)
230 {
231 uint32 size = (iTilesX + 1) * (iTilesY + 1);
232 if (fwrite(iHeight, sizeof(float), size, wf) == size)
233 {
234 size = iTilesX * iTilesY;
235 result = fwrite(iFlags, sizeof(uint8), size, wf) == size;
236 }
237 }
238 else
239 result = fwrite(iHeight, sizeof(float), 1, wf) == 1;
240 }
241
242 return result;
243 }
244
245 bool WmoLiquid::readFromFile(FILE* rf, WmoLiquid*& out)
246 {
247 bool result = false;
248 WmoLiquid* liquid = new WmoLiquid();
249
250 if (fread(&liquid->iTilesX, sizeof(uint32), 1, rf) == 1 &&
251 fread(&liquid->iTilesY, sizeof(uint32), 1, rf) == 1 &&
252 fread(&liquid->iCorner, sizeof(Vector3), 1, rf) == 1 &&
253 fread(&liquid->iType, sizeof(uint32), 1, rf) == 1)
254 {
255 if (liquid->iTilesX && liquid->iTilesY)
256 {
257 uint32 size = (liquid->iTilesX + 1) * (liquid->iTilesY + 1);
258 liquid->iHeight = new float[size];
259 if (fread(liquid->iHeight, sizeof(float), size, rf) == size)
260 {
261 size = liquid->iTilesX * liquid->iTilesY;
262 liquid->iFlags = new uint8[size];
263 result = fread(liquid->iFlags, sizeof(uint8), size, rf) == size;
264 }
265 }
266 else
267 {
268 liquid->iHeight = new float[1];
269 result = fread(liquid->iHeight, sizeof(float), 1, rf) == 1;
270 }
271 }
272
273 if (!result)
274 delete liquid;
275 else
276 out = liquid;
277
278 return result;
279 }
280
281 void WmoLiquid::getPosInfo(uint32& tilesX, uint32& tilesY, G3D::Vector3& corner) const
282 {
283 tilesX = iTilesX;
284 tilesY = iTilesY;
285 corner = iCorner;
286 }
287
288 // ===================== GroupModel ==================================
289
291 iBound(other.iBound), iMogpFlags(other.iMogpFlags), iGroupWMOID(other.iGroupWMOID),
292 vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(nullptr)
293 {
294 if (other.iLiquid)
295 iLiquid = new WmoLiquid(*other.iLiquid);
296 }
297
298 void GroupModel::setMeshData(std::vector<Vector3>& vert, std::vector<MeshTriangle>& tri)
299 {
300 vertices.swap(vert);
301 triangles.swap(tri);
302 TriBoundFunc bFunc(vertices);
303 meshTree.build(triangles, bFunc);
304 }
305
307 {
308 bool result = true;
309 uint32 chunkSize, count;
310
311 if (result && fwrite(&iBound, sizeof(G3D::AABox), 1, wf) != 1) result = false;
312 if (result && fwrite(&iMogpFlags, sizeof(uint32), 1, wf) != 1) result = false;
313 if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) result = false;
314
315 // write vertices
316 if (result && fwrite("VERT", 1, 4, wf) != 4) result = false;
317 count = vertices.size();
318 chunkSize = sizeof(uint32) + sizeof(Vector3) * count;
319 if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
320 if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
321 if (!count) // models without (collision) geometry end here, unsure if they are useful
322 return result;
323 if (result && fwrite(&vertices[0], sizeof(Vector3), count, wf) != count) result = false;
324
325 // write triangle mesh
326 if (result && fwrite("TRIM", 1, 4, wf) != 4) result = false;
327 count = triangles.size();
328 chunkSize = sizeof(uint32) + sizeof(MeshTriangle) * count;
329 if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
330 if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
331 if (result && fwrite(&triangles[0], sizeof(MeshTriangle), count, wf) != count) result = false;
332
333 // write mesh BIH
334 if (result && fwrite("MBIH", 1, 4, wf) != 4) result = false;
335 if (result) result = meshTree.writeToFile(wf);
336
337 // write liquid data
338 if (result && fwrite("LIQU", 1, 4, wf) != 4) result = false;
339 if (!iLiquid)
340 {
341 chunkSize = 0;
342 if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
343 return result;
344 }
345 chunkSize = iLiquid->GetFileSize();
346 if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
347 if (result) result = iLiquid->writeToFile(wf);
348
349 return result;
350 }
351
353 {
354 char chunk[8];
355 bool result = true;
356 uint32 chunkSize = 0;
357 uint32 count = 0;
358 triangles.clear();
359 vertices.clear();
360 delete iLiquid;
361 iLiquid = nullptr;
362
363 if (result && fread(&iBound, sizeof(G3D::AABox), 1, rf) != 1) result = false;
364 if (result && fread(&iMogpFlags, sizeof(uint32), 1, rf) != 1) result = false;
365 if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) result = false;
366
367 // read vertices
368 if (result && !readChunk(rf, chunk, "VERT", 4)) result = false;
369 if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
370 if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
371 if (!count) // models without (collision) geometry end here, unsure if they are useful
372 return result;
373 if (result) vertices.resize(count);
374 if (result && fread(&vertices[0], sizeof(Vector3), count, rf) != count) result = false;
375
376 // read triangle mesh
377 if (result && !readChunk(rf, chunk, "TRIM", 4)) result = false;
378 if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
379 if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
380 if (result) triangles.resize(count);
381 if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) result = false;
382
383 // read mesh BIH
384 if (result && !readChunk(rf, chunk, "MBIH", 4)) result = false;
385 if (result) result = meshTree.readFromFile(rf);
386
387 // write liquid data
388 if (result && !readChunk(rf, chunk, "LIQU", 4)) result = false;
389 if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
390 if (result && chunkSize > 0)
391 result = WmoLiquid::readFromFile(rf, iLiquid);
392 return result;
393 }
394
396 {
397 GModelRayCallback(std::vector<MeshTriangle> const& tris, const std::vector<Vector3> &vert):
398 vertices(vert.begin()), triangles(tris.begin()), hit(false) { }
399 bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool /*pStopAtFirstHit*/)
400 {
401 hit = IntersectTriangle(triangles[entry], vertices, ray, distance) || hit;
402 return hit;
403 }
404 std::vector<Vector3>::const_iterator vertices;
405 std::vector<MeshTriangle>::const_iterator triangles;
406 bool hit;
407 };
408
409 bool GroupModel::IntersectRay(G3D::Ray const& ray, float& distance, bool stopAtFirstHit) const
410 {
411 if (triangles.empty())
412 return false;
413
415 meshTree.intersectRay(ray, callback, distance, stopAtFirstHit);
416 return callback.hit;
417 }
418
419 bool GroupModel::IsInsideObject(Vector3 const& pos, Vector3 const& down, float& z_dist) const
420 {
421 if (triangles.empty() || !iBound.contains(pos))
422 return false;
423 Vector3 rPos = pos - 0.1f * down;
424 float dist = G3D::finf();
425 G3D::Ray ray(rPos, down);
426 bool hit = IntersectRay(ray, dist, false);
427 if (hit)
428 z_dist = dist - 0.1f;
429 return hit;
430 }
431
432 bool GroupModel::GetLiquidLevel(Vector3 const& pos, float& liqHeight) const
433 {
434 if (iLiquid)
435 return iLiquid->GetLiquidHeight(pos, liqHeight);
436 return false;
437 }
438
440 {
441 if (iLiquid)
442 return iLiquid->GetType();
443 return 0;
444 }
445
446 // ===================== WorldModel ==================================
447
448 void WorldModel::setGroupModels(std::vector<GroupModel>& models)
449 {
450 groupModels.swap(models);
451 groupTree.build(groupModels, BoundsTrait<GroupModel>::getBounds, 1);
452 }
453
455 {
456 WModelRayCallBack(std::vector<GroupModel> const& mod): models(mod.begin()), hit(false) { }
457 bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool pStopAtFirstHit)
458 {
459 bool result = models[entry].IntersectRay(ray, distance, pStopAtFirstHit);
460 if (result)
461 hit = true;
462 return hit;
463 }
464 std::vector<GroupModel>::const_iterator models;
465 bool hit;
466 };
467
468 bool WorldModel::IntersectRay(G3D::Ray const& ray, float& distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
469 {
470 // If the caller asked us to ignore certain objects we should check flags
471 if ((ignoreFlags & ModelIgnoreFlags::M2) != ModelIgnoreFlags::Nothing)
472 {
473 // M2 models are not taken into account for LoS calculation if caller requested their ignoring.
474 if (IsM2())
475 return false;
476 }
477
478 // small M2 workaround, maybe better make separate class with virtual intersection funcs
479 // in any case, there's no need to use a bound tree if we only have one submodel
480 if (groupModels.size() == 1)
481 return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit);
482
484 groupTree.intersectRay(ray, isc, distance, stopAtFirstHit);
485 return isc.hit;
486 }
487
489 public:
490 WModelAreaCallback(std::vector<GroupModel> const& vals, Vector3 const& down) :
491 prims(vals.begin()), hit(vals.end()), minVol(G3D::finf()), zDist(G3D::finf()), zVec(down) { }
492 std::vector<GroupModel>::const_iterator prims;
493 std::vector<GroupModel>::const_iterator hit;
494 float minVol;
495 float zDist;
496 Vector3 zVec;
497 void operator()(Vector3 const& point, uint32 entry)
498 {
499 float group_Z;
500 //float pVol = prims[entry].GetBound().volume();
501 //if (pVol < minVol)
502 //{
503 /* if (prims[entry].iBound.contains(point)) */
504 if (prims[entry].IsInsideObject(point, zVec, group_Z))
505 {
506 //minVol = pVol;
507 //hit = prims + entry;
508 if (group_Z < zDist)
509 {
510 zDist = group_Z;
511 hit = prims + entry;
512 }
513#ifdef VMAP_DEBUG
514 GroupModel const& gm = prims[entry];
515 printf("%10u %8X %7.3f, %7.3f, %7.3f | %7.3f, %7.3f, %7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(),
516 gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z,
517 gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z);
518#endif
519 }
520 //}
521 //std::cout << "trying to intersect '" << prims[entry].name << "'\n";
522 }
523 };
524
525 bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const
526 {
527 if (groupModels.empty())
528 return false;
529
530 WModelAreaCallback callback(groupModels, down);
531 groupTree.intersectPoint(p, callback);
532 if (callback.hit != groupModels.end())
533 {
534 info.rootId = RootWMOID;
535 info.hitModel = &(*callback.hit);
536 dist = callback.zDist;
537 return true;
538 }
539 return false;
540 }
541
542 bool WorldModel::writeFile(const std::string& filename)
543 {
544 FILE* wf = fopen(filename.c_str(), "wb");
545 if (!wf)
546 return false;
547
548 uint32 chunkSize, count;
549 bool result = fwrite(VMAP_MAGIC, 1, 8, wf) == 8;
550 if (result && fwrite("WMOD", 1, 4, wf) != 4) result = false;
551 chunkSize = sizeof(uint32) + sizeof(uint32);
552 if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
553 if (result)
554 {
556 if (fwrite(&flags, sizeof(uint32), 1, wf) != 1) result = false;
557 }
558 if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) result = false;
559
560 // write group models
561 count = groupModels.size();
562 if (count)
563 {
564 if (result && fwrite("GMOD", 1, 4, wf) != 4) result = false;
565 //chunkSize = sizeof(uint32)+ sizeof(GroupModel)*count;
566 //if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
567 if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
568 for (uint32 i = 0; i < groupModels.size() && result; ++i)
569 result = groupModels[i].writeToFile(wf);
570
571 // write group BIH
572 if (result && fwrite("GBIH", 1, 4, wf) != 4) result = false;
573 if (result) result = groupTree.writeToFile(wf);
574 }
575
576 fclose(wf);
577 return result;
578 }
579
580 bool WorldModel::readFile(const std::string& filename)
581 {
582 FILE* rf = fopen(filename.c_str(), "rb");
583 if (!rf)
584 return false;
585
586 bool result = true;
587 uint32 chunkSize = 0;
588 uint32 count = 0;
589 char chunk[8]; // Ignore the added magic header
590 if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) result = false;
591
592 if (result && !readChunk(rf, chunk, "WMOD", 4)) result = false;
593 if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
594 if (result)
595 {
597 if (fread(&flags, sizeof(flags), 1, rf) == 1)
598 Flags = flags;
599 else
600 result = false;
601 }
602 if (result && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) result = false;
603
604 // read group models
605 if (result && readChunk(rf, chunk, "GMOD", 4))
606 {
607 //if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
608
609 if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
610 if (result) groupModels.resize(count);
611 //if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false;
612 for (uint32 i = 0; i < count && result; ++i)
613 result = groupModels[i].readFromFile(rf);
614
615 // read group BIH
616 if (result && !readChunk(rf, chunk, "GBIH", 4)) result = false;
617 if (result) result = groupTree.readFromFile(rf);
618 }
619
620 fclose(rf);
621 return result;
622 }
623}
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
#define LIQUID_TILE_SIZE
void build(PrimArray const &primitives, BoundsFunc &getBounds, uint32 leafSize=3, bool printStats=false)
bool writeToFile(FILE *wf) const
bool readFromFile(FILE *rf)
void intersectPoint(const G3D::Vector3 &p, IsectCallback &intersectCallback) const
void intersectRay(const G3D::Ray &r, RayCallback &intersectCallback, float &maxDist, bool stopAtFirst=false) const
constexpr std::underlying_type_t< T > AsUnderlyingType() const
Definition: EnumFlag.h:122
std::vector< G3D::Vector3 > vertices
Definition: WorldModel.h:108
uint32 GetLiquidType() const
Definition: WorldModel.cpp:439
bool readFromFile(FILE *rf)
Definition: WorldModel.cpp:352
uint32 GetMogpFlags() const
Definition: WorldModel.h:99
WmoLiquid * iLiquid
Definition: WorldModel.h:111
uint32 GetWmoID() const
Definition: WorldModel.h:100
std::vector< MeshTriangle > triangles
Definition: WorldModel.h:109
bool GetLiquidLevel(const G3D::Vector3 &pos, float &liqHeight) const
Definition: WorldModel.cpp:432
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const
Definition: WorldModel.cpp:409
bool writeToFile(FILE *wf)
Definition: WorldModel.cpp:306
const G3D::AABox & GetBound() const
Definition: WorldModel.h:98
void setMeshData(std::vector< G3D::Vector3 > &vert, std::vector< MeshTriangle > &tri)
pass mesh data to object and create BIH. Passed vectors get get swapped with old geometry!
Definition: WorldModel.cpp:298
uint32 iGroupWMOID
Definition: WorldModel.h:107
G3D::AABox iBound
Definition: WorldModel.h:105
bool IsInsideObject(const G3D::Vector3 &pos, const G3D::Vector3 &down, float &z_dist) const
Definition: WorldModel.cpp:419
void operator()(MeshTriangle const &tri, G3D::AABox &out) const
Definition: WorldModel.cpp:88
const std::vector< Vector3 >::const_iterator vertices
Definition: WorldModel.cpp:99
TriBoundFunc(std::vector< Vector3 > &vert)
Definition: WorldModel.cpp:87
std::vector< GroupModel >::const_iterator hit
Definition: WorldModel.cpp:493
WModelAreaCallback(std::vector< GroupModel > const &vals, Vector3 const &down)
Definition: WorldModel.cpp:490
std::vector< GroupModel >::const_iterator prims
Definition: WorldModel.cpp:492
void operator()(Vector3 const &point, uint32 entry)
Definition: WorldModel.cpp:497
uint32 iTilesY
Definition: WorldModel.h:72
G3D::Vector3 iCorner
the lower corner
Definition: WorldModel.h:73
void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const
Definition: WorldModel.cpp:281
uint32 iType
liquid type
Definition: WorldModel.h:74
uint32 GetFileSize()
Definition: WorldModel.cpp:213
float * iHeight
(tilesX + 1)*(tilesY + 1) height values
Definition: WorldModel.h:75
uint32 iTilesX
number of tiles in x direction, each
Definition: WorldModel.h:71
bool GetLiquidHeight(G3D::Vector3 const &pos, float &liqHeight) const
Definition: WorldModel.cpp:157
uint32 GetType() const
Definition: WorldModel.h:60
uint8 * iFlags
info if liquid tile is used
Definition: WorldModel.h:76
static bool readFromFile(FILE *rf, WmoLiquid *&liquid)
Definition: WorldModel.cpp:245
WmoLiquid & operator=(WmoLiquid const &other)
Definition: WorldModel.cpp:130
bool writeToFile(FILE *wf)
Definition: WorldModel.cpp:221
EnumFlag< ModelFlags > Flags
Definition: WorldModel.h:133
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
Definition: WorldModel.cpp:468
bool readFile(const std::string &filename)
Definition: WorldModel.cpp:580
bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, GroupLocationInfo &info) const
Definition: WorldModel.cpp:525
void setGroupModels(std::vector< GroupModel > &models)
pass group models to WorldModel and create BIH. Passed vector is swapped with old geometry!
Definition: WorldModel.cpp:448
bool IsM2() const
Definition: WorldModel.h:128
bool writeFile(const std::string &filename)
Definition: WorldModel.cpp:542
std::vector< GroupModel > groupModels
Definition: WorldModel.h:135
constexpr std::size_t size()
Definition: UpdateField.h:796
bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len)
bool IntersectTriangle(MeshTriangle const &tri, std::vector< Vector3 >::const_iterator points, G3D::Ray const &ray, float &distance)
Definition: WorldModel.cpp:34
const char VMAP_MAGIC[]
ModelFlags
Definition: WorldModel.h:38
static void getBounds(const VMAP::GroupModel &obj, G3D::AABox &out)
Definition: WorldModel.cpp:29
std::vector< MeshTriangle >::const_iterator triangles
Definition: WorldModel.cpp:405
bool operator()(G3D::Ray const &ray, uint32 entry, float &distance, bool)
Definition: WorldModel.cpp:399
GModelRayCallback(std::vector< MeshTriangle > const &tris, const std::vector< Vector3 > &vert)
Definition: WorldModel.cpp:397
std::vector< Vector3 >::const_iterator vertices
Definition: WorldModel.cpp:404
const GroupModel * hitModel
Definition: MapTree.h:35
bool operator()(G3D::Ray const &ray, uint32 entry, float &distance, bool pStopAtFirstHit)
Definition: WorldModel.cpp:457
std::vector< GroupModel >::const_iterator models
Definition: WorldModel.cpp:464
WModelRayCallBack(std::vector< GroupModel > const &mod)
Definition: WorldModel.cpp:456