Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
ModelInstance.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 "ModelInstance.h"
7#include "WorldModel.h"
8#include "MapTree.h"
9#include "VMapDefinitions.h"
10
11using G3D::Vector3;
12using G3D::Ray;
13
14namespace VMAP
15{
17 {
18 iInvRot = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iRot.y/180.f, G3D::pi()*iRot.x/180.f, G3D::pi()*iRot.z/180.f).inverse();
19 iInvScale = 1.f/iScale;
20 }
21
22 bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const
23 {
24 if (!iModel)
25 {
26 //std::cout << "<object not loaded>\n";
27 return false;
28 }
29 float time = pRay.intersectionTime(iBound);
30 if (time == G3D::inf())
31 {
32// std::cout << "Ray does not hit '" << name << "'\n";
33
34 return false;
35 }
36// std::cout << "Ray crosses bound of '" << name << "'\n";
37/* std::cout << "ray from:" << pRay.origin().x << ", " << pRay.origin().y << ", " << pRay.origin().z
38 << " dir:" << pRay.direction().x << ", " << pRay.direction().y << ", " << pRay.direction().z
39 << " t/tmax:" << time << '/' << pMaxDist;
40 std::cout << "\nBound lo:" << iBound.low().x << ", " << iBound.low().y << ", " << iBound.low().z << " hi: "
41 << iBound.high().x << ", " << iBound.high().y << ", " << iBound.high().z << std::endl; */
42 // child bounds are defined in object space:
43 Vector3 p = iInvRot * (pRay.origin() - iPos) * iInvScale;
44 Ray modRay(p, iInvRot * pRay.direction());
45 float distance = pMaxDist * iInvScale;
46 bool hit = iModel->IntersectRay(modRay, distance, pStopAtFirstHit);
47 if (hit)
48 {
49 distance *= iScale;
50 pMaxDist = distance;
51 }
52 return hit;
53 }
54
55 void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo &info) const
56 {
57 if (!iModel)
58 {
59#ifdef VMAP_DEBUG
60 std::cout << "<object not loaded>\n";
61#endif
62 return;
63 }
64
65 // M2 files don't contain area info, only WMO files
66 if (flags & MOD_M2)
67 return;
68 if (!iBound.contains(p))
69 return;
70 // child bounds are defined in object space:
71 Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
72 Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
73 float zDist;
74 if (iModel->IntersectPoint(pModel, zDirModel, zDist, info))
75 {
76 Vector3 modelGround = pModel + zDist * zDirModel;
77 // Transform back to world space. Note that:
78 // Mat * vec == vec * Mat.transpose()
79 // and for rotation matrices: Mat.inverse() == Mat.transpose()
80 float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
81 if (info.ground_Z < world_Z)
82 {
83 info.ground_Z = world_Z;
84 info.adtId = adtId;
85 }
86 }
87 }
88
89 bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const
90 {
91 if (!iModel)
92 {
93#ifdef VMAP_DEBUG
94 std::cout << "<object not loaded>\n";
95#endif
96 return false;
97 }
98
99 // M2 files don't contain area info, only WMO files
100 if (flags & MOD_M2)
101 return false;
102 if (!iBound.contains(p))
103 return false;
104 // child bounds are defined in object space:
105 Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
106 Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
107 float zDist;
108 if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info))
109 {
110 Vector3 modelGround = pModel + zDist * zDirModel;
111 // Transform back to world space. Note that:
112 // Mat * vec == vec * Mat.transpose()
113 // and for rotation matrices: Mat.inverse() == Mat.transpose()
114 float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
115 if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection?
116 {
117 info.ground_Z = world_Z;
118 info.hitInstance = this;
119 return true;
120 }
121 }
122 return false;
123 }
124
125 bool ModelInstance::GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const
126 {
127 // child bounds are defined in object space:
128 Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
129 //Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
130 float zDist;
131 if (info.hitModel->GetLiquidLevel(pModel, zDist))
132 {
133 // calculate world height (zDist in model coords):
134 // assume WMO not tilted (wouldn't make much sense anyway)
135 liqHeight = zDist * iScale + iPos.z;
136 return true;
137 }
138 return false;
139 }
140
142 {
143 uint32 check = 0, nameLen;
144 check += fread(&spawn.flags, sizeof(uint32), 1, rf);
145 // EoF?
146 if (!check)
147 {
148 if (ferror(rf))
149 std::cout << "Error reading ModelSpawn!\n";
150 return false;
151 }
152 check += fread(&spawn.adtId, sizeof(uint16), 1, rf);
153 check += fread(&spawn.ID, sizeof(uint32), 1, rf);
154 check += fread(&spawn.iPos, sizeof(float), 3, rf);
155 check += fread(&spawn.iRot, sizeof(float), 3, rf);
156 check += fread(&spawn.iScale, sizeof(float), 1, rf);
157 bool has_bound = (spawn.flags & MOD_HAS_BOUND);
158 if (has_bound) // only WMOs have bound in MPQ, only available after computation
159 {
160 Vector3 bLow, bHigh;
161 check += fread(&bLow, sizeof(float), 3, rf);
162 check += fread(&bHigh, sizeof(float), 3, rf);
163 spawn.iBound = G3D::AABox(bLow, bHigh);
164 }
165 check += fread(&nameLen, sizeof(uint32), 1, rf);
166 if (check != uint32(has_bound ? 17 : 11))
167 {
168 std::cout << "Error reading ModelSpawn!\n";
169 return false;
170 }
171 char nameBuff[500];
172 if (nameLen > 500) // file names should never be that long, must be file error
173 {
174 std::cout << "Error reading ModelSpawn, file name too long!\n";
175 return false;
176 }
177 check = fread(nameBuff, sizeof(char), nameLen, rf);
178 if (check != nameLen)
179 {
180 std::cout << "Error reading ModelSpawn!\n";
181 return false;
182 }
183 spawn.name = std::string(nameBuff, nameLen);
184 return true;
185 }
186
187 bool ModelSpawn::writeToFile(FILE* wf, const ModelSpawn &spawn)
188 {
189 uint32 check=0;
190 check += fwrite(&spawn.flags, sizeof(uint32), 1, wf);
191 check += fwrite(&spawn.adtId, sizeof(uint16), 1, wf);
192 check += fwrite(&spawn.ID, sizeof(uint32), 1, wf);
193 check += fwrite(&spawn.iPos, sizeof(float), 3, wf);
194 check += fwrite(&spawn.iRot, sizeof(float), 3, wf);
195 check += fwrite(&spawn.iScale, sizeof(float), 1, wf);
196 bool has_bound = (spawn.flags & MOD_HAS_BOUND);
197 if (has_bound) // only WMOs have bound in MPQ, only available after computation
198 {
199 check += fwrite(&spawn.iBound.low(), sizeof(float), 3, wf);
200 check += fwrite(&spawn.iBound.high(), sizeof(float), 3, wf);
201 }
202 uint32 nameLen = spawn.name.length();
203 check += fwrite(&nameLen, sizeof(uint32), 1, wf);
204 if (check != uint32(has_bound ? 17 : 11)) return false;
205 check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf);
206 if (check != nameLen) return false;
207 return true;
208 }
209
210}
std::uint32_t uint32
Definition Define.h:77
std::uint16_t uint16
Definition Define.h:78
bool GetLiquidLevel(const G3D::Vector3 &pos, float &liqHeight) const
bool GetLocationInfo(const G3D::Vector3 &p, LocationInfo &info) const
void intersectPoint(const G3D::Vector3 &p, AreaInfo &info) const
G3D::Matrix3 iInvRot
WorldModel * iModel
bool GetLiquidLevel(const G3D::Vector3 &p, LocationInfo &info, float &liqHeight) const
bool intersectRay(const G3D::Ray &pRay, float &pMaxDist, bool pStopAtFirstHit) const
static bool readFromFile(FILE *rf, ModelSpawn &spawn)
std::string name
G3D::Vector3 iRot
G3D::Vector3 iPos
G3D::AABox iBound
static bool writeToFile(FILE *rw, const ModelSpawn &spawn)
@ MOD_HAS_BOUND
int32 adtId
Definition MapTree.h:83
float ground_Z
Definition MapTree.h:81
const GroupModel * hitModel
Definition MapTree.h:23
const ModelInstance * hitInstance
Definition MapTree.h:22