OregonCore  revision fb2a440-git
Your Favourite TBC server
M2Stores.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of the OregonCore 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 "Console.h"
19 #include "DBCStores.h"
20 #include "M2Structure.h"
21 #include "M2Stores.h"
22 #include "Common.h"
23 #include "Log.h"
24 #include "World.h"
25 #include <fstream>
26 #include <iostream>
27 #include <iomanip>
28 
29 std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
30 
31 // Convert the geomoetry from a spline value, to an actual WoW XYZ
32 G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector)
33 {
34  G3D::Vector3 work;
35  float x = basePosition->x + splineVector->x;
36  float y = basePosition->y + splineVector->y;
37  float z = basePosition->z + splineVector->z;
38  float const distance = sqrt((x * x) + (y * y));
39  float angle = std::atan2(x, y) - DBCPosition->w;
40 
41  if (angle < 0)
42  angle += 2 * float(M_PI);
43 
44  work.x = DBCPosition->x + (distance * sin(angle));
45  work.y = DBCPosition->y + (distance * cos(angle));
46  work.z = DBCPosition->z + z;
47  return work;
48 }
49 
50 // Number of cameras not used. Multiple cameras never used
51 bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry)
52 {
53  char const* buffer = reinterpret_cast<char const*>(header);
54 
55  FlyByCameraCollection cameras;
56  FlyByCameraCollection targetcam;
57 
58  G3D::Vector4 DBCData;
59  DBCData.x = dbcentry->Origin.X;
60  DBCData.y = dbcentry->Origin.Y;
61  DBCData.z = dbcentry->Origin.Z;
62  DBCData.w = dbcentry->OriginFacing;
63 
64  // Extract Target positions
65  if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
66  return false;
67  uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + cam->target_positions.timestamps.offset_elements);
68  M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + cam->target_positions.values.offset_elements);
69 
70  // Read the data for this set
72  for (uint32 i = 0; i < cam->target_positions.timestamps.number; ++i)
73  {
74  if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
75  return false;
76  // Translate co-ordinates
77  G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0);
78 
79  // Add to vector
80  FlyByCamera thisCam;
81  thisCam.timeStamp = targTimestamps[i];
82  thisCam.locations.x = newPos.x;
83  thisCam.locations.y = newPos.y;
84  thisCam.locations.z = newPos.z;
85  thisCam.locations.w = 0.0f;
86  targetcam.push_back(thisCam);
87  targPositions++;
88  currPos += sizeof(M2SplineKey<G3D::Vector3>);
89  }
90 
91  // Extract Camera positions for this set
92  if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
93  return false;
94  uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + cam->positions.timestamps.offset_elements);
95  M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + cam->positions.values.offset_elements);
96 
97  // Read the data for this set
98  currPos = cam->positions.values.offset_elements;
99  for (uint32 i = 0; i < cam->positions.timestamps.number; ++i)
100  {
101  if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
102  return false;
103  // Translate co-ordinates
104  G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0);
105 
106  // Add to vector
107  FlyByCamera thisCam;
108  thisCam.timeStamp = posTimestamps[i];
109  thisCam.locations.x = newPos.x;
110  thisCam.locations.y = newPos.y;
111  thisCam.locations.z = newPos.z;
112 
113  if (targetcam.size() > 0)
114  {
115  // Find the target camera before and after this camera
116  FlyByCamera lastTarget;
117  FlyByCamera nextTarget;
118 
119  // Pre-load first item
120  lastTarget = targetcam[0];
121  nextTarget = targetcam[0];
122  for (uint32 j = 0; j < targetcam.size(); ++j)
123  {
124  nextTarget = targetcam[j];
125  if (targetcam[j].timeStamp > posTimestamps[i])
126  break;
127 
128  lastTarget = targetcam[j];
129  }
130 
131  float x = lastTarget.locations.x;
132  float y = lastTarget.locations.y;
133  float z = lastTarget.locations.z;
134 
135  // Now, the timestamps for target cam and position can be different. So, if they differ we interpolate
136  if (lastTarget.timeStamp != posTimestamps[i])
137  {
138  uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp;
139  uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp;
140  float xDiff = nextTarget.locations.x - lastTarget.locations.x;
141  float yDiff = nextTarget.locations.y - lastTarget.locations.y;
142  float zDiff = nextTarget.locations.z - lastTarget.locations.z;
143  x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget)));
144  y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget)));
145  z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget)));
146  }
147  float xDiff = x - thisCam.locations.x;
148  float yDiff = y - thisCam.locations.y;
149  thisCam.locations.w = std::atan2(yDiff, xDiff);
150 
151  if (thisCam.locations.w < 0)
152  thisCam.locations.w += 2 * float(M_PI);
153  }
154 
155  cameras.push_back(thisCam);
156  positions++;
157  currPos += sizeof(M2SplineKey<G3D::Vector3>);
158  }
159 
160  sFlyByCameraStore[dbcentry->ID] = cameras;
161  return true;
162 }
163 
164 void LoadM2Cameras(std::string const& dataPath)
165 {
166  sFlyByCameraStore.clear();
167 
168  uint32 oldMSTime = getMSTime();
169  for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i)
170  {
171  if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i))
172  {
173  std::string filename = dataPath;
174  filename.append(dbcentry->Model);
175 
176  // Replace slashes
177  std::replace(filename.begin(), filename.end(), '\\', '/');
178 
179  // Replace mdx to .m2
180  size_t loc = filename.find(".mdx");
181  if (loc != std::string::npos)
182  filename.replace(loc, 4, ".m2");
183 
184  std::ifstream m2file(filename.c_str(), std::ios::in | std::ios::binary);
185  if (!m2file.is_open())
186  continue;
187 
188  // Get file size
189  m2file.seekg(0, std::ios::end);
190  std::streamoff const fileSize = m2file.tellg();
191 
192  // Reject if not at least the size of the header
193  if (static_cast<uint32 const>(fileSize) < sizeof(M2Header))
194  {
195  error_log("Camera file %s is damaged. File is smaller than header size", filename.c_str());
196  m2file.close();
197  continue;
198  }
199 
200  // Read 4 bytes (signature)
201  m2file.seekg(0, std::ios::beg);
202  char fileCheck[5];
203  m2file.read(fileCheck, 4);
204  fileCheck[4] = 0;
205 
206  // Check file has correct magic (MD20)
207  if (strcmp(fileCheck, "MD20"))
208  {
209  error_log("Camera file %s is damaged. File identifier not found", filename.c_str());
210  m2file.close();
211  continue;
212  }
213 
214  // Now we have a good file, read it all into a vector of char's, then close the file.
215  std::vector<char> buffer(fileSize);
216  m2file.seekg(0, std::ios::beg);
217  if (!m2file.read(buffer.data(), fileSize))
218  {
219  m2file.close();
220  continue;
221  }
222  m2file.close();
223 
224  // Read header
225  M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data());
226 
227  if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32 const>(fileSize))
228  {
229  error_log("server.loading", "Camera file %s is damaged. Camera references position beyond file end (header)", filename.c_str());
230  continue;
231  }
232 
233  // Get camera(s) - Main header, then dump them.
234  M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
235  if (!readCamera(cam, fileSize, header, dbcentry))
236  error_log("Camera file %s is damaged. Camera references position beyond file end (camera)", filename.c_str());
237  }
238  }
239 }
uint32 offset_elements
Definition: M2Structure.h:127
G3D::Vector4 locations
Definition: M2Stores.h:27
uint32_t number
Definition: M2Structure.h:126
G3D::Vector3 TranslateLocation(G3D::Vector4 const *DBCPosition, G3D::Vector3 const *basePosition, G3D::Vector3 const *splineVector)
Definition: M2Stores.cpp:32
std::unordered_map< uint32, FlyByCameraCollection > sFlyByCameraStore
Definition: M2Stores.cpp:29
bool readCamera(M2Camera const *cam, uint32 buffSize, M2Header const *header, CinematicCameraEntry const *dbcentry)
Definition: M2Stores.cpp:51
uint32 getMSTime()
Definition: Timer.h:32
std::vector< FlyByCamera > FlyByCameraCollection
Definition: M2Stores.h:30
uint32 ofsCameras
Definition: M2Structure.h:115
DBCPosition3D Origin
Definition: DBCStructure.h:192
DBCStorage< CinematicCameraEntry > sCinematicCameraStore(CinematicCameraEntryfmt)
G3D::Vector3 target_position_base
Definition: M2Structure.h:147
uint32 timeStamp
Definition: M2Stores.h:26
#define error_log
Definition: Log.h:202
M2Array values
Definition: M2Structure.h:135
void LoadM2Cameras(std::string const &dataPath)
Definition: M2Stores.cpp:164
M2Track target_positions
Definition: M2Structure.h:146
ACE_UINT32 uint32
Definition: Define.h:71
M2Track positions
Definition: M2Structure.h:144
M2Array timestamps
Definition: M2Structure.h:134
G3D::Vector3 position_base
Definition: M2Structure.h:145