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