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