1 #include <algorithm>
2 #include "xr_object.h"
3 #include "xr_object_format.h"
4 #include "xr_motion.h"
5 #include "xr_bone.h"
6 #include "xr_mesh.h"
7 #include "xr_surface.h"
8 #include "xr_reader.h"
9 #include "xr_writer.h"
10 #include "xr_file_system.h"
11 #include "xr_string_utils.h"
12 #include "xr_utils.h"
13 #include "xr_name_gen.h"
14
15 using namespace xray_re;
16
xr_object()17 xr_object::xr_object(): m_flags(EOF_STATIC),
18 m_owner_name("unknown"), m_creation_time(0),
19 m_modif_name("unknown"), m_modified_time(0),
20 m_surface_factory(0)
21 {
22 m_position.set();
23 m_rotation.set();
24 }
25
xr_object(const xr_surface_factory * surface_factory)26 xr_object::xr_object(const xr_surface_factory* surface_factory):
27 m_flags(EOF_STATIC),
28 m_owner_name("unknown"), m_creation_time(0),
29 m_modif_name("unknown"), m_modified_time(0),
30 m_surface_factory(surface_factory)
31 {
32 m_position.set();
33 m_rotation.set();
34 }
35
~xr_object()36 xr_object::~xr_object()
37 {
38 delete_elements(m_surfaces);
39 delete_elements(m_meshes);
40 delete_elements(m_bones);
41 delete_elements(m_motions);
42 delete_elements(m_partitions);
43 }
44
clear()45 void xr_object::clear()
46 {
47 m_flags = EOF_STATIC;
48 m_owner_name = "unknown";
49 m_creation_time = 0;
50 m_modif_name = "unknown";
51 m_modified_time = 0;
52 clear_container(m_surfaces);
53 clear_container(m_meshes);
54 clear_container(m_bones);
55 clear_container(m_motions);
56 clear_container(m_partitions);
57 }
58
setup_bones()59 void xr_object::setup_bones()
60 {
61 uint16_t bone_id = 0;
62 for (xr_bone_vec_it it = m_bones.begin(), end = m_bones.end();
63 it != end; ++it, ++bone_id) {
64 (*it)->setup(bone_id, *this);
65 }
66 }
67
calculate_bind()68 void xr_object::calculate_bind()
69 {
70 for (xr_bone_vec_it it = m_bones.begin(), end = m_bones.end(); it != end; ++it) {
71 if ((*it)->is_root()) {
72 (*it)->calculate_bind(fmatrix().identity());
73 break;
74 }
75 }
76 }
77
root_bone() const78 const xr_bone* xr_object::root_bone() const
79 {
80 for (xr_bone_vec_cit it = m_bones.begin(), end = m_bones.end(); it != end; ++it) {
81 if ((*it)->is_root())
82 return *it;
83 }
84 return 0;
85 }
86
setup_partitions()87 void xr_object::setup_partitions()
88 {
89 uint16_t part_id = 0;
90 for (xr_partition_vec_it it = m_partitions.begin(),
91 end = m_partitions.end(); it != end; ++it) {
92 (*it)->setup(part_id++);
93 }
94 }
95
96 struct read_mesh {
97 xr_object& object;
read_meshread_mesh98 read_mesh(xr_object& _object): object(_object) {}
operator ()read_mesh99 void operator()(xr_mesh*& mesh, xr_reader& r) {
100 mesh = new xr_mesh;
101 mesh->load(r, object);
102 }
103 };
104
105 struct read_partition_0 {
106 xr_bone_vec& all_bones;
read_partition_0read_partition_0107 read_partition_0(xr_bone_vec& _all_bones): all_bones(_all_bones) {}
operator ()read_partition_0108 void operator()(xr_partition*& part, xr_reader& r) {
109 part = new xr_partition;
110 part->load_0(r, all_bones);
111 }
112 };
113
load_object(xr_reader & r)114 void xr_object::load_object(xr_reader& r)
115 {
116 uint16_t version;
117 if (!r.r_chunk<uint16_t>(EOBJ_CHUNK_VERSION, version))
118 xr_not_expected();
119 xr_assert(version == EOBJ_VERSION);
120
121 if (!r.r_chunk<uint32_t>(EOBJ_CHUNK_FLAGS, m_flags))
122 xr_not_expected();
123
124 if (r.find_chunk(EOBJ_CHUNK_USERDATA)) {
125 r.r_sz(m_userdata);
126 r.debug_find_chunk();
127 }
128
129 if (r.find_chunk(EOBJ_CHUNK_LOD_REF)) {
130 r.r_sz(m_lod_ref);
131 r.debug_find_chunk();
132 }
133
134 if (r.find_chunk(EOBJ_CHUNK_SURFACES_2)) {
135 r.r_seq(r.r_u32(), m_surfaces, xr_reader::f_r_new<xr_surface>(&xr_surface::load_2));
136 r.debug_find_chunk();
137 } else if (r.find_chunk(EOBJ_CHUNK_SURFACES_1)) {
138 r.r_seq(r.r_u32(), m_surfaces, xr_reader::f_r_new<xr_surface>(&xr_surface::load_1));
139 r.debug_find_chunk();
140 } else if (r.find_chunk(EOBJ_CHUNK_SURFACES_0)) {
141 r.r_seq(r.r_u32(), m_surfaces, xr_reader::f_r_new<xr_surface>(&xr_surface::load_0));
142 r.debug_find_chunk();
143 if (r.find_chunk(EOBJ_CHUNK_SHADERS_0)) {
144 for (xr_surface_vec_it it = m_surfaces.begin(), end = m_surfaces.end();
145 it != end; ++it) {
146 (*it)->cshader() = r.skip_sz();
147 }
148 r.debug_find_chunk();
149 }
150 } else {
151 xr_not_expected();
152 }
153
154 xr_reader* s = r.open_chunk(EOBJ_CHUNK_MESHES);
155 if (s) {
156 s->r_chunks(m_meshes, read_mesh(*this));
157 r.close_chunk(s);
158 }
159
160 s = r.open_chunk(EOBJ_CHUNK_BONES_1);
161 if (s) {
162 s->r_chunks(m_bones, xr_reader::f_r_new<xr_bone>(&xr_bone::load_1));
163 r.close_chunk(s);
164 } else if (r.find_chunk(EOBJ_CHUNK_BONES_0)) {
165 s->r_seq(r.r_u32(), m_bones, xr_reader::f_r_new<xr_bone>(&xr_bone::load_0));
166 r.debug_find_chunk();
167 }
168 setup_bones();
169 if (r.find_chunk(EOBJ_CHUNK_MOTIONS)) {
170 r.r_seq(r.r_u32(), m_motions, xr_reader::f_r_new<xr_skl_motion>(&xr_skl_motion::load));
171 r.debug_find_chunk();
172 }
173 if (r.find_chunk(EOBJ_CHUNK_MOTION_REFS)) {
174 r.r_sz(m_motion_refs);
175 r.debug_find_chunk();
176 }
177 if (r.find_chunk(EOBJ_CHUNK_PARTITIONS_0)) {
178 r.r_seq(r.r_u32(), m_partitions, read_partition_0(m_bones));
179 r.debug_find_chunk();
180 } else if (r.find_chunk(EOBJ_CHUNK_PARTITIONS_1)) {
181 r.r_seq(r.r_u32(), m_partitions, xr_reader::f_r_new<xr_partition>(&xr_partition::load_1));
182 r.debug_find_chunk();
183 }
184 if (r.find_chunk(EOBJ_CHUNK_TRANSFORM)) {
185 r.r_fvector3(m_position);
186 r.r_fvector3(m_rotation);
187 r.debug_find_chunk();
188 }
189 if (r.find_chunk(EOBJ_CHUNK_REVISION)) {
190 r.r_sz(m_owner_name);
191 m_creation_time = r.r_u32();
192 r.r_sz(m_modif_name);
193 m_modified_time = r.r_u32();
194 r.debug_find_chunk();
195 }
196 }
197
load_object(const char * path)198 bool xr_object::load_object(const char* path)
199 {
200 xr_file_system& fs = xr_file_system::instance();
201 xr_reader* r = fs.r_open(path);
202 if (r == 0)
203 return false;
204 bool status = false;
205 xr_reader* s = r->open_chunk(EOBJ_CHUNK_MAIN);
206 if (s) {
207 try {
208 load_object(*s);
209 status = true;
210 } catch (xr_error) {
211 clear();
212 }
213 r->close_chunk(s);
214 }
215 fs.r_close(r);
216 return status;
217 }
218
save_object(xr_writer & w) const219 void xr_object::save_object(xr_writer& w) const
220 {
221 w.w_chunk<uint16_t>(EOBJ_CHUNK_VERSION, EOBJ_VERSION);
222
223 w.w_chunk(EOBJ_CHUNK_USERDATA, m_userdata);
224
225 w.w_chunk(EOBJ_CHUNK_LOD_REF, m_lod_ref);
226
227 w.w_chunk<uint32_t>(EOBJ_CHUNK_FLAGS, m_flags);
228
229 w.open_chunk(EOBJ_CHUNK_MESHES);
230 w.w_chunks(m_meshes, xr_writer::f_w_const<xr_mesh>(&xr_mesh::save));
231 w.close_chunk();
232
233 w.open_chunk(EOBJ_CHUNK_SURFACES_2);
234 w.w_size_u32(m_surfaces.size());
235 w.w_seq(m_surfaces, xr_writer::f_w_const<xr_surface>(&xr_surface::save));
236 w.close_chunk();
237
238 if (!m_bones.empty()) {
239 w.open_chunk(EOBJ_CHUNK_BONES_1);
240 w.w_chunks(m_bones, xr_writer::f_w_const<xr_bone>(&xr_bone::save));
241 w.close_chunk();
242 }
243 if (!m_motions.empty()) {
244 w.open_chunk(EOBJ_CHUNK_MOTIONS);
245 w.w_size_u32(m_motions.size());
246 w.w_seq(m_motions, xr_writer::f_w_const<xr_skl_motion>(&xr_skl_motion::save));
247 w.close_chunk();
248 }
249 if (!m_motion_refs.empty()) {
250 w.w_chunk(EOBJ_CHUNK_MOTION_REFS, m_motion_refs);
251 }
252 if (!m_partitions.empty()) {
253 w.open_chunk(EOBJ_CHUNK_PARTITIONS_1);
254 w.w_size_u32(m_partitions.size());
255 w.w_seq(m_partitions, xr_writer::f_w_const<xr_partition>(&xr_partition::save));
256 w.close_chunk();
257 }
258 if (m_flags & EOF_DYNAMIC) {
259 w.open_chunk(EOBJ_CHUNK_TRANSFORM);
260 w.w_fvector3(m_position);
261 w.w_fvector3(m_rotation);
262 w.close_chunk();
263 }
264
265 w.open_chunk(EOBJ_CHUNK_REVISION);
266 w.w_sz(m_owner_name);
267 w.w_u32(m_creation_time);
268 w.w_sz(m_modif_name);
269 w.w_u32(m_modified_time);
270 w.close_chunk();
271 }
272
save_object(const char * path) const273 bool xr_object::save_object(const char* path) const
274 {
275 xr_memory_writer* w = new xr_memory_writer();
276 w->open_chunk(EOBJ_CHUNK_MAIN);
277 save_object(*w);
278 w->close_chunk();
279 bool status = w->save_to(path);
280 delete w;
281 return status;
282 }
283
save_object(const char * path,const std::string & name) const284 bool xr_object::save_object(const char* path, const std::string& name) const
285 {
286 xr_memory_writer* w = new xr_memory_writer();
287 w->open_chunk(EOBJ_CHUNK_MAIN);
288 save_object(*w);
289 w->close_chunk();
290 bool status = w->save_to(path, name);
291 delete w;
292 return status;
293 }
294
load_bones(xr_reader & r)295 void xr_object::load_bones(xr_reader& r)
296 {
297 r.r_chunks(m_bones, xr_reader::f_r_new<xr_bone>(&xr_bone::load_data));
298 if (r.find_chunk(EOBJ_CHUNK_PARTITIONS_1)) {
299 r.r_seq(r.r_u32(), m_partitions, xr_reader::f_r_new<xr_partition>(&xr_partition::load_1));
300 r.debug_find_chunk();
301 }
302 }
303
load_bones(const char * path)304 bool xr_object::load_bones(const char* path)
305 {
306 xr_file_system& fs = xr_file_system::instance();
307 xr_reader* r = fs.r_open(path);
308 if (r == 0)
309 return false;
310 bool status = false;
311 try {
312 load_bones(*r);
313 status = true;
314 } catch (xr_error) {
315 clear();
316 }
317 fs.r_close(r);
318 return status;
319 }
320
save_bones(xr_writer & w) const321 void xr_object::save_bones(xr_writer& w) const
322 {
323 w.w_chunks(m_bones, xr_writer::f_w_const<xr_bone>(&xr_bone::save_data));
324 w.open_chunk(EOBJ_CHUNK_PARTITIONS_1);
325 w.w_size_u32(m_partitions.size());
326 w.w_seq(m_partitions, xr_writer::f_w_const<xr_partition>(&xr_partition::save));
327 w.close_chunk();
328 }
329
save_bones(const char * path) const330 bool xr_object::save_bones(const char* path) const
331 {
332 xr_memory_writer* w = new xr_memory_writer();
333 save_bones(*w);
334 bool status = w->save_to(path);
335 delete w;
336 return status;
337 }
338
load_skls(xr_reader & r)339 void xr_object::load_skls(xr_reader& r)
340 {
341 r.r_seq(r.r_u32(), m_motions, xr_reader::f_r_new<xr_skl_motion>(&xr_skl_motion::load));
342 }
343
load_skls(const char * path)344 bool xr_object::load_skls(const char* path)
345 {
346 xr_file_system& fs = xr_file_system::instance();
347 xr_reader* r = fs.r_open(path);
348 if (r == 0)
349 return false;
350 bool status = false;
351 try {
352 load_skls(*r);
353 status = true;
354 } catch (xr_error) {
355 clear();
356 }
357 fs.r_close(r);
358 return status;
359 }
360
save_skls(xr_writer & w) const361 void xr_object::save_skls(xr_writer& w) const
362 {
363 w.w_size_u32(m_motions.size());
364 w.w_seq(m_motions, xr_writer::f_w_const<xr_skl_motion>(&xr_skl_motion::save));
365 }
366
save_skls(const char * path) const367 bool xr_object::save_skls(const char* path) const
368 {
369 xr_memory_writer* w = new xr_memory_writer();
370 save_skls(*w);
371 bool status = w->save_to(path);
372 delete w;
373 return status;
374 }
375
operator ()surface_name_pred376 struct surface_name_pred { bool operator()(const xr_surface* l, const xr_surface* r) const {
377 return l->name() < r->name();
378 }};
379
denominate_surfaces()380 void xr_object::denominate_surfaces()
381 {
382 for (xr_surface_vec_it it = m_surfaces.begin(), end = m_surfaces.end(); it != end; ++it) {
383 xr_surface* surface = *it;
384 const std::string& texture = surface->texture();
385 std::string::size_type pos = texture.rfind('\\');
386 if (pos == std::string::npos)
387 pos = 0;
388 else
389 ++pos;
390 std::string& name = surface->name();
391 name.reserve(texture.size() - pos + 3);
392 for (std::string::const_iterator it1 = texture.begin() + pos,
393 end1 = texture.end(); it1 != end1; ++it1) {
394 int c = *it1;
395 name.push_back(std::isalnum(c) ? char(std::tolower(c)) : '_');
396 }
397 name += "_S";
398 }
399 std::sort(m_surfaces.begin(), m_surfaces.end(), surface_name_pred());
400 char suffix[8];
401 for (xr_surface_vec_it it = m_surfaces.begin(), end = m_surfaces.end(); it != end;) {
402 const std::string& name = (*it)->name();
403 for (unsigned i = 1; ++it != end && (*it)->name() == name; ++i) {
404 xr_snprintf(suffix, sizeof(suffix), "%u", i);
405 (*it)->name() += suffix;
406 }
407 }
408 }
409
denominate()410 void xr_object::denominate()
411 {
412 denominate_surfaces();
413 xr_name_gen name("mesh", false);
414 for (xr_mesh_vec_it it = m_meshes.begin(), end = m_meshes.end(); it != end; ++it, name.next())
415 (*it)->name().assign(name.get()).append("Shape");
416 }
417
to_object()418 void xr_object::to_object() {}
419
attach(const xr_raw_surface & raw_surface)420 xr_surface* xr_object::attach(const xr_raw_surface& raw_surface)
421 {
422 xr_surface*& surface = m_raw_surfaces[raw_surface];
423 if (surface == 0) {
424 surface = m_surface_factory ?
425 m_surface_factory->create_surface(raw_surface) :
426 create_surface(raw_surface);
427 xr_assert(surface);
428 m_surfaces.push_back(surface);
429 }
430 return surface;
431 }
432
create_surface(const xr_raw_surface & raw_surface) const433 xr_surface* xr_object::create_surface(const xr_raw_surface& raw_surface) const { return 0; }
434
find_surface(const std::string & name)435 xr_surface* xr_object::find_surface(const std::string& name) { return find_by_name(m_surfaces, name); }
find_mesh(const std::string & name)436 xr_mesh* xr_object::find_mesh(const std::string& name) { return find_by_name(m_meshes, name); }
find_bone(const std::string & name)437 xr_bone* xr_object::find_bone(const std::string& name) { return find_by_name(m_bones, name); }
find_partition(const std::string & name)438 xr_partition* xr_object::find_partition(const std::string& name) { return find_by_name(m_partitions, name); }
find_motion(const std::string & name)439 xr_skl_motion* xr_object::find_motion(const std::string& name) { return find_by_name(m_motions, name); }
440