TrinityCore
Loading...
Searching...
No Matches
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, std::shared_ptr<WorldModel> model) : ModelMinimalData(spawn), iModel(std::move(model)), referencingTiles(0)
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(G3D::Vector3 const& 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
85 WorldModelLocationInfoQueryResult locationQueryResult;
86 if (iModel->GetLocationInfo(pModel, zDirModel, locationQueryResult))
87 {
88 Vector3 modelGround = pModel + locationQueryResult.distanceToModel * zDirModel;
89 // Transform back to world space. Note that:
90 // Mat * vec == vec * Mat.transpose()
91 // and for rotation matrices: Mat.inverse() == Mat.transpose()
92 float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
93 if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection?
94 {
95 info.rootId = locationQueryResult.rootId;
96 info.hitModel = locationQueryResult.hitModel;
97 info.ground_Z = world_Z;
98 return true;
99 }
100 }
101 return false;
102 }
103
104 bool ModelInstance::GetLiquidLevel(G3D::Vector3 const& p, GroupModel const* model, float& liqHeight) const
105 {
106 // child bounds are defined in object space:
107 Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
108 //Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
109 float zDist;
110 if (model->GetLiquidLevel(pModel, zDist))
111 {
112 // calculate world height (zDist in model coords):
113 liqHeight = (Vector3(pModel.x, pModel.y, zDist) * iInvRot * iScale + iPos).z;
114 return true;
115 }
116 return false;
117 }
118
120 {
121 uint32 check = 0, nameLen;
122 check += fread(&spawn.flags, sizeof(uint8), 1, rf);
123 // EoF?
124 if (!check)
125 {
126 if (ferror(rf))
127 std::cout << "Error reading ModelSpawn!\n";
128 return false;
129 }
130 check += fread(&spawn.adtId, sizeof(uint8), 1, rf);
131 check += fread(&spawn.ID, sizeof(uint32), 1, rf);
132 check += fread(&spawn.iPos, sizeof(float), 3, rf);
133 check += fread(&spawn.iRot, sizeof(float), 3, rf);
134 check += fread(&spawn.iScale, sizeof(float), 1, rf);
135 bool has_bound = (spawn.flags & MOD_HAS_BOUND) != 0;
136 if (has_bound) // only WMOs have bound in MPQ, only available after computation
137 {
138 Vector3 bLow, bHigh;
139 check += fread(&bLow, sizeof(float), 3, rf);
140 check += fread(&bHigh, sizeof(float), 3, rf);
141 spawn.iBound = G3D::AABox(bLow, bHigh);
142 }
143 check += fread(&nameLen, sizeof(uint32), 1, rf);
144 if (check != uint32(has_bound ? 17 : 11))
145 {
146 std::cout << "Error reading ModelSpawn!\n";
147 return false;
148 }
149 char nameBuff[500];
150 if (nameLen > 500) // file names should never be that long, must be file error
151 {
152 std::cout << "Error reading ModelSpawn, file name too long!\n";
153 return false;
154 }
155 check = fread(nameBuff, sizeof(char), nameLen, rf);
156 if (check != nameLen)
157 {
158 std::cout << "Error reading ModelSpawn!\n";
159 return false;
160 }
161 spawn.name = std::string(nameBuff, nameLen);
162 return true;
163 }
164
165 bool ModelSpawn::writeToFile(FILE* wf, ModelSpawn const& spawn)
166 {
167 uint32 check = 0;
168 check += fwrite(&spawn.flags, sizeof(uint8), 1, wf);
169 check += fwrite(&spawn.adtId, sizeof(uint8), 1, wf);
170 check += fwrite(&spawn.ID, sizeof(uint32), 1, wf);
171 check += fwrite(&spawn.iPos, sizeof(float), 3, wf);
172 check += fwrite(&spawn.iRot, sizeof(float), 3, wf);
173 check += fwrite(&spawn.iScale, sizeof(float), 1, wf);
174 bool has_bound = (spawn.flags & MOD_HAS_BOUND) != 0;
175 if (has_bound) // only WMOs have bound in MPQ, only available after computation
176 {
177 check += fwrite(&spawn.iBound.low(), sizeof(float), 3, wf);
178 check += fwrite(&spawn.iBound.high(), sizeof(float), 3, wf);
179 }
180 uint32 nameLen = spawn.name.length();
181 check += fwrite(&nameLen, sizeof(uint32), 1, wf);
182 if (check != uint32(has_bound ? 17 : 11)) return false;
183 check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf);
184 if (check != nameLen) return false;
185 return true;
186 }
187
188}
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
bool GetLiquidLevel(const G3D::Vector3 &pos, float &liqHeight) const
std::shared_ptr< WorldModel > iModel
bool GetLocationInfo(G3D::Vector3 const &p, LocationInfo &info) const
G3D::Matrix3 iInvRot
bool intersectRay(G3D::Ray const &pRay, float &pMaxDist, bool pStopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
bool GetLiquidLevel(G3D::Vector3 const &p, GroupModel const *model, float &liqHeight) const
@ MOD_HAS_BOUND
STL namespace.
GroupModel const * hitModel
Definition MapTree.h:36
static bool readFromFile(FILE *rf, ModelSpawn &spawn)
std::string name
G3D::Vector3 iRot
static bool writeToFile(FILE *rw, ModelSpawn const &spawn)