1 /*
2 * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
33 <http://www.gnu.org/licenses/>.
34
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Initial Code: Cyril Meynier
44 //
45 // Copyright (c) 1999-2001 ARKANE Studios SA. All rights reserved
46
47 /*!
48 * ARX FTL file loading and saving
49 * FTL files contains Optimised/Pre-computed versions of objects for faster loads
50 */
51
52 #include "graphics/data/FTL.h"
53
54 #include <cstdlib>
55 #include <cstring>
56
57 #include <boost/algorithm/string/case_conv.hpp>
58 #include <boost/static_assert.hpp>
59
60 #include "graphics/data/FTLFormat.h"
61 #include "graphics/data/TextureContainer.h"
62
63 #include "io/fs/FilePath.h"
64 #include "io/fs/FileStream.h"
65 #include "io/fs/Filesystem.h"
66 #include "io/resource/ResourcePath.h"
67 #include "io/resource/PakReader.h"
68 #include "io/Blast.h"
69 #include "io/Implode.h"
70 #include "io/IO.h"
71 #include "io/log/Logger.h"
72
73 #include "scene/Object.h"
74
75 #include "util/String.h"
76
77 using std::string;
78 using std::vector;
79
80 #ifdef BUILD_EDIT_LOADSAVE
81
ARX_FTL_Save(const fs::path & file,const EERIE_3DOBJ * obj)82 bool ARX_FTL_Save(const fs::path & file, const EERIE_3DOBJ * obj) {
83
84 LogWarning << "ARX_FTL_Save " << file;
85
86 if(!obj) {
87 return false;
88 }
89
90 // Generate File name/path and create it
91 fs::path gamefic = "game" / file;
92 gamefic.set_ext("ftl");
93
94 if(!fs::create_directories(gamefic.parent())) {
95 return false;
96 }
97
98 // Compute allocsize...
99 size_t allocsize = sizeof(ARX_FTL_PRIMARY_HEADER)
100 + 512 //checksum
101 + sizeof(ARX_FTL_SECONDARY_HEADER)
102 + sizeof(ARX_FTL_3D_DATA_HEADER)
103 + sizeof(EERIE_OLD_VERTEX) * obj->vertexlist.size()
104 + sizeof(EERIE_FACE_FTL) * obj->facelist.size()
105 + sizeof(Texture_Container_FTL) * obj->texturecontainer.size()
106 + sizeof(EERIE_ACTIONLIST_FTL) * obj->actionlist.size()
107 + 128000; // TODO just in case...
108
109 if(obj->nbgroups > 0) {
110 allocsize += sizeof(EERIE_GROUPLIST_FTL) * obj->nbgroups;
111 for(long i = 0; i < obj->nbgroups; i++) {
112 allocsize += sizeof(long) * obj->grouplist[i].indexes.size();
113 }
114 }
115
116 if(!obj->selections.empty()) {
117 allocsize += sizeof(EERIE_SELECTIONS_FTL) * obj->selections.size();
118 for(size_t i = 0; i < obj->selections.size(); i++) {
119 allocsize += sizeof(long) * obj->selections[i].selected.size();
120 }
121 }
122
123 if(obj->sdata && !obj->sdata->spheres.empty()) {
124 allocsize += sizeof(ARX_FTL_COLLISION_SPHERES_DATA_HEADER);
125 allocsize += sizeof(COLLISION_SPHERE_FTL) * obj->sdata->spheres.size();
126 }
127
128 if(obj->cdata) {
129 allocsize += sizeof(ARX_FTL_CLOTHES_DATA_HEADER);
130 allocsize += sizeof(CLOTHESVERTEX_FTL) * obj->cdata->nb_cvert;
131 allocsize += sizeof(EERIE_SPRINGS_FTL) * obj->cdata->springs.size();
132 }
133
134 // Finished computing allocsize Now allocate it...
135 char * dat = new char[allocsize];
136 size_t pos = 0;
137
138 memset(dat, 0, allocsize);
139
140 // Primary Header
141 {
142 ARX_FTL_PRIMARY_HEADER afph;
143
144 afph.ident[0] = 'F';
145 afph.ident[1] = 'T';
146 afph.ident[2] = 'L';
147 afph.ident[3] = '0';
148 afph.version = CURRENT_FTL_VERSION;
149
150 memcpy(dat + pos, &afph, sizeof(ARX_FTL_PRIMARY_HEADER));
151 pos += sizeof(ARX_FTL_PRIMARY_HEADER);
152 }
153
154 // Identification
155 char check[512];
156 HERMES_CreateFileCheck(file, check, 512, CURRENT_FTL_VERSION);
157 memcpy(dat + pos, check, 512);
158 pos += 512;
159
160 // Secondary Header
161 ARX_FTL_SECONDARY_HEADER*afsh = (ARX_FTL_SECONDARY_HEADER *)(dat + pos);
162 pos += sizeof(ARX_FTL_SECONDARY_HEADER);
163
164 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
165
166 // 3D Data
167 afsh->offset_3Ddata = pos; //-1;
168 ARX_FTL_3D_DATA_HEADER * af3Ddh = (ARX_FTL_3D_DATA_HEADER *)(dat + afsh->offset_3Ddata);
169 pos += sizeof(ARX_FTL_3D_DATA_HEADER);
170
171 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
172
173 af3Ddh->nb_vertex = obj->vertexlist.size();
174 af3Ddh->nb_faces = obj->facelist.size();
175 af3Ddh->nb_maps = obj->texturecontainer.size();
176 af3Ddh->nb_groups = obj->nbgroups;
177 af3Ddh->nb_action = obj->actionlist.size();
178 af3Ddh->nb_selections = obj->selections.size();
179 af3Ddh->origin = obj->origin;
180
181 // vertexes
182 if (af3Ddh->nb_vertex > 0) {
183 std::copy(obj->vertexlist.begin(), obj->vertexlist.end(), (EERIE_OLD_VERTEX*)(dat + pos));
184 pos += sizeof(EERIE_OLD_VERTEX) * obj->vertexlist.size();
185
186 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
187 }
188
189 // faces
190 if (af3Ddh->nb_faces > 0)
191 {
192 for (long ii = 0; ii < af3Ddh->nb_faces; ii++)
193 {
194 EERIE_FACE_FTL * eff = (EERIE_FACE_FTL *)(dat + pos);
195 eff->facetype = obj->facelist[ii].facetype;
196 eff->texid = obj->facelist[ii].texid;
197 eff->transval = obj->facelist[ii].transval;
198 eff->temp = obj->facelist[ii].temp;
199 eff->norm = obj->facelist[ii].norm;
200
201 for (long kk = 0; kk < IOPOLYVERT; kk++)
202 {
203 eff->nrmls[kk] = obj->facelist[ii].nrmls[kk];
204 eff->vid[kk] = obj->facelist[ii].vid[kk];
205 eff->u[kk] = obj->facelist[ii].u[kk];
206 eff->v[kk] = obj->facelist[ii].v[kk];
207 eff->ou[kk] = obj->facelist[ii].ou[kk];
208 eff->ov[kk] = obj->facelist[ii].ov[kk];
209 eff->rgb[kk] = 0;
210 }
211
212 pos += sizeof(EERIE_FACE_FTL);
213 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
214 }
215 }
216
217 // textures
218 for (long i = 0; i < af3Ddh->nb_maps; i++)
219 {
220 char ficc[256];
221 memset(ficc, 0, 256);
222
223 if (obj->texturecontainer[i])
224 strcpy(ficc, obj->texturecontainer[i]->m_texName.string().c_str());
225
226 memcpy(dat + pos, ficc, 256);
227 pos += 256;
228
229 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
230 }
231
232 // groups
233 if (af3Ddh->nb_groups > 0)
234 {
235 std::copy(obj->grouplist, obj->grouplist + obj->nbgroups, (EERIE_GROUPLIST_FTL*)(dat + pos));
236 pos += sizeof(EERIE_GROUPLIST_FTL) * af3Ddh->nb_groups;
237
238 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
239
240 for(int i = 0; i < af3Ddh->nb_groups; i++) {
241 if(!obj->grouplist[i].indexes.empty()) {
242 std::copy(obj->grouplist[i].indexes.begin(), obj->grouplist[i].indexes.end(), (s32*)(dat + pos));
243 pos += sizeof(s32) * obj->grouplist[i].indexes.size();
244 }
245 }
246 }
247
248 // actionpoints
249 if(af3Ddh->nb_action > 0) {
250 std::copy(obj->actionlist.begin(), obj->actionlist.end(), (EERIE_ACTIONLIST_FTL*)(dat + pos));
251 pos += sizeof(EERIE_ACTIONLIST_FTL) * af3Ddh->nb_action;
252
253 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
254 }
255
256 // selections
257 if (af3Ddh->nb_selections > 0)
258 {
259 std::copy(obj->selections.begin(), obj->selections.end(), (EERIE_SELECTIONS_FTL*)(dat + pos));
260 pos += sizeof(EERIE_SELECTIONS_FTL) * af3Ddh->nb_selections;
261
262 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
263
264 for (int i = 0; i < af3Ddh->nb_selections; i++) {
265 std::copy(obj->selections[i].selected.begin(), obj->selections[i].selected.end(), (s32*)(dat + pos));
266 pos += sizeof(s32) * obj->selections[i].selected.size();
267
268 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
269 }
270
271 strncpy(af3Ddh->name, obj->file.string().c_str(), sizeof(af3Ddh->name));
272 }
273
274 // Progressive DATA
275 afsh->offset_progressive_data = -1;
276
277
278 // Collision Spheres Data
279 if (obj->sdata && !obj->sdata->spheres.empty())
280 {
281 afsh->offset_collision_spheres = pos; //-1;
282 ARX_FTL_COLLISION_SPHERES_DATA_HEADER * afcsdh = (ARX_FTL_COLLISION_SPHERES_DATA_HEADER *)(dat + afsh->offset_collision_spheres);
283 pos += sizeof(ARX_FTL_COLLISION_SPHERES_DATA_HEADER);
284
285 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
286
287 afcsdh->nb_spheres = obj->sdata->spheres.size();
288
289 std::copy(obj->sdata->spheres.begin(), obj->sdata->spheres.end(), (COLLISION_SPHERE_FTL*)(dat + pos));
290 pos += sizeof(COLLISION_SPHERE_FTL) * obj->sdata->spheres.size();
291
292 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
293 }
294 else afsh->offset_collision_spheres = -1;
295
296
297 // Clothes DATA
298 if (obj->cdata == NULL)
299 {
300 afsh->offset_clothes_data = -1;
301 }
302 else
303 {
304 afsh->offset_clothes_data = pos;
305 ARX_FTL_CLOTHES_DATA_HEADER * afcdh = (ARX_FTL_CLOTHES_DATA_HEADER *)(dat + afsh->offset_clothes_data);
306
307 afcdh->nb_cvert = obj->cdata->nb_cvert;
308 afcdh->nb_springs = obj->cdata->springs.size();
309 pos += sizeof(ARX_FTL_CLOTHES_DATA_HEADER);
310
311 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
312
313 // now save cvert
314 std::copy(obj->cdata->cvert, obj->cdata->cvert + obj->cdata->nb_cvert, (CLOTHESVERTEX_FTL*)(dat + pos));
315 pos += sizeof(CLOTHESVERTEX_FTL) * obj->cdata->nb_cvert;
316
317 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
318
319 // now saves springs
320 std::copy(obj->cdata->springs.begin(), obj->cdata->springs.end(), (EERIE_SPRINGS_FTL*)(dat + pos));
321 pos += sizeof(EERIE_SPRINGS_FTL) * obj->cdata->springs.size();
322
323 if (pos > allocsize) LogError << ("Invalid Allocsize in ARX_FTL_Save");
324 }
325
326 afsh->offset_physics_box = -1;
327
328 afsh->offset_cylinder = -1;
329
330 // Now we can flush our cool FTL file to the hard drive
331
332 if(pos > allocsize) {
333 LogError << "Badly Allocated SaveBuffer... " << gamefic;
334 delete[] dat;
335 return false;
336 }
337
338 size_t cpr_pos = 0;
339 char * compressed = implodeAlloc(dat, pos, cpr_pos);
340 delete[] dat;
341
342 // Now Saving Whole Buffer
343 fs::ofstream ofs(gamefic, fs::fstream::out | fs::fstream::binary | fs::fstream::trunc);
344 if(!ofs.is_open()) {
345 LogError << "Unable to Open " << gamefic << " for Write...";
346 return false;
347 }
348
349 ofs.write(compressed, cpr_pos);
350 delete[] compressed;
351
352
353 if(ofs.fail()) {
354 LogError << "Unable to Write to " << gamefic;
355 return false;
356 }
357
358 return true;
359 }
360
361 #endif // BUILD_EDIT_LOADSAVE
362
363 // MESH cache structure definition & Globals
364 struct MCACHE_DATA {
365 res::path name;
366 char * data;
367 size_t size;
368 };
369 static vector<MCACHE_DATA> meshCache;
370
371 // Checks for Mesh file existence in cache
MCache_Get(const res::path & file)372 static long MCache_Get(const res::path & file) {
373
374 for(size_t i = 0; i < meshCache.size(); i++) {
375 if(meshCache[i].name == file) {
376 return i;
377 }
378 }
379
380 return -1;
381 }
382
383 // Pushes a Mesh In Mesh Cache
MCache_Push(const res::path & file,char * data,size_t size)384 static bool MCache_Push(const res::path & file, char * data, size_t size) {
385
386 if(MCache_Get(file) != -1) {
387 return false; // already cached
388 }
389
390 LogDebug(file << " #" << meshCache.size());
391
392 MCACHE_DATA newMesh;
393 newMesh.size = size;
394 newMesh.data = data;
395 newMesh.name = file;
396 meshCache.push_back(newMesh);
397
398 return true;
399 }
400
MCache_ClearAll()401 void MCache_ClearAll(){
402 for(vector<MCACHE_DATA>::iterator it = meshCache.begin(); it != meshCache.end(); ++it) {
403 free(it->data);
404 }
405
406 meshCache.clear();
407 }
408
409 // Retreives a Mesh File pointer from cache...
MCache_Pop(const res::path & file,size_t & size)410 static char * MCache_Pop(const res::path & file, size_t & size) {
411
412 long num = MCache_Get(file);
413 if(num == -1) {
414 return NULL;
415 }
416
417 size = meshCache[num].size;
418 return meshCache[num].data;
419 }
420
ARX_FTL_Load(const res::path & file)421 EERIE_3DOBJ * ARX_FTL_Load(const res::path & file) {
422
423 // Creates FTL file name
424 res::path filename = (res::path("game") / file).set_ext("ftl");
425
426 // Checks for FTL file existence
427 PakFile * pf = resources->getFile(filename);
428 if(!pf) {
429 return NULL;
430 }
431
432 size_t compressedSize = 0;
433 char * compressedData = MCache_Pop(filename, compressedSize);
434 LogDebug("File name check " << filename);
435
436 bool NOrelease = true;
437 if(!compressedData) {
438 compressedData = pf->readAlloc();
439 compressedSize = pf->size();
440 NOrelease = MCache_Push(filename, compressedData, compressedSize) ? 1 : 0;
441 }
442
443 if(!compressedData) {
444 LogError << "ARX_FTL_Load: error loading from PAK/cache " << filename;
445 return NULL;
446 }
447
448 size_t allocsize; // The size of the data TODO size ignored
449 char * dat = blastMemAlloc(compressedData, compressedSize, allocsize);
450 if(!dat) {
451 LogError << "ARX_FTL_Load: error decompressing " << filename;
452 return NULL;
453 }
454
455 if(!NOrelease) {
456 free(compressedData);
457 }
458
459 size_t pos = 0; // The position within the data
460
461 // Pointer to Primary Header
462 const ARX_FTL_PRIMARY_HEADER * afph = reinterpret_cast<const ARX_FTL_PRIMARY_HEADER *>(dat + pos);
463 pos += sizeof(ARX_FTL_PRIMARY_HEADER);
464
465 // Verify FTL file Signature
466 if(afph->ident[0] != 'F' || afph->ident[1] != 'T' || afph->ident[2] != 'L') {
467 LogError << "ARX_FTL_Load: wrong magic number in " << filename;
468 free(dat);
469 return NULL;
470 }
471
472 // Verify FTL file version
473 if(afph->version != CURRENT_FTL_VERSION) {
474 LogError << "ARX_FTL_Load: wring version " << afph->version << ", expected "
475 << CURRENT_FTL_VERSION << " in " << filename;
476 free(dat);
477 return NULL;
478 }
479
480 // Increases offset by checksum size
481 pos += 512;
482
483 // Pointer to Secondary Header
484 const ARX_FTL_SECONDARY_HEADER * afsh;
485 afsh = reinterpret_cast<const ARX_FTL_SECONDARY_HEADER *>(dat + pos);
486 if(afsh->offset_3Ddata == -1) {
487 LogError << "ARX_FTL_Load: error loading data from " << filename;
488 free(dat);
489 return NULL;
490 }
491 pos = afsh->offset_3Ddata;
492
493 // Available from here in whole function
494 EERIE_3DOBJ * obj = new EERIE_3DOBJ();
495
496 const ARX_FTL_3D_DATA_HEADER * af3Ddh;
497 af3Ddh = reinterpret_cast<const ARX_FTL_3D_DATA_HEADER *>(dat + pos);
498 pos += sizeof(ARX_FTL_3D_DATA_HEADER);
499
500 obj->vertexlist.resize(af3Ddh->nb_vertex);
501 obj->facelist.resize(af3Ddh->nb_faces);
502 obj->texturecontainer.resize(af3Ddh->nb_maps);
503 obj->nbgroups = af3Ddh->nb_groups;
504 obj->actionlist.resize(af3Ddh->nb_action);
505 obj->selections.resize(af3Ddh->nb_selections);
506 obj->origin = af3Ddh->origin;
507 obj->file = res::path::load(util::loadString(af3Ddh->name));
508
509 // Alloc'n'Copy vertices
510 if(!obj->vertexlist.empty()) {
511
512 // Copy the vertex data in
513 for(size_t ii = 0; ii < obj->vertexlist.size(); ii++) {
514
515 // Vertices stored as EERIE_OLD_VERTEX, copy in to new one
516 obj->vertexlist[ii] = *reinterpret_cast<const EERIE_OLD_VERTEX *>(dat + pos);
517 pos += sizeof(EERIE_OLD_VERTEX);
518
519 obj->vertexlist[ii].vert.color = 0xFF000000;
520 }
521
522 // Set the origin point of the mesh
523 obj->point0 = obj->vertexlist[obj->origin].v;
524
525 obj->vertexlist3 = obj->vertexlist;
526 }
527
528 // Alloc'n'Copy faces
529 if(!obj->facelist.empty()) {
530
531 // Copy the face data in
532 for(long ii = 0; ii < af3Ddh->nb_faces; ii++) {
533
534 const EERIE_FACE_FTL * eff = reinterpret_cast<const EERIE_FACE_FTL*>(dat + pos);
535 pos += sizeof(EERIE_FACE_FTL);
536
537 obj->facelist[ii].facetype = PolyType::load(eff->facetype);
538 obj->facelist[ii].texid = eff->texid;
539 obj->facelist[ii].transval = eff->transval;
540 obj->facelist[ii].temp = eff->temp;
541 obj->facelist[ii].norm = eff->norm;
542
543 // Copy in all the texture and normals data
544 BOOST_STATIC_ASSERT(IOPOLYVERT_FTL == IOPOLYVERT);
545 for(size_t kk = 0; kk < IOPOLYVERT_FTL; kk++) {
546 obj->facelist[ii].nrmls[kk] = eff->nrmls[kk];
547 obj->facelist[ii].vid[kk] = eff->vid[kk];
548 obj->facelist[ii].u[kk] = eff->u[kk];
549 obj->facelist[ii].v[kk] = eff->v[kk];
550 obj->facelist[ii].ou[kk] = eff->ou[kk];
551 obj->facelist[ii].ov[kk] = eff->ov[kk];
552 }
553
554 }
555 }
556
557 // Alloc'n'Copy textures
558 if(af3Ddh->nb_maps > 0) {
559
560 // Copy in the texture containers
561 for(long i = 0; i < af3Ddh->nb_maps; i++) {
562
563 const Texture_Container_FTL * tex;
564 tex = reinterpret_cast<const Texture_Container_FTL *>(dat + pos);
565 pos += sizeof(Texture_Container_FTL);
566
567 if(tex->name[0] == '\0') {
568 // Some object files contain textures with empty names
569 // Don't bother trying to load them as that will just generate an error message
570 obj->texturecontainer[i] = NULL;
571 } else {
572 // Create the texture and put it in the container list
573 res::path name = res::path::load(util::loadString(tex->name)).remove_ext();
574 obj->texturecontainer[i] = TextureContainer::Load(name, TextureContainer::Level);
575 }
576 }
577 }
578
579 // Alloc'n'Copy groups
580 if(obj->nbgroups > 0) {
581
582 // Alloc the grouplists
583 obj->grouplist = new EERIE_GROUPLIST[obj->nbgroups];
584
585 // Copy in the grouplist data
586 for(long i = 0 ; i < obj->nbgroups ; i++) {
587
588 const EERIE_GROUPLIST_FTL* group = reinterpret_cast<const EERIE_GROUPLIST_FTL *>(dat + pos);
589 pos += sizeof(EERIE_GROUPLIST_FTL);
590
591 obj->grouplist[i].name = boost::to_lower_copy(util::loadString(group->name));
592 obj->grouplist[i].origin = group->origin;
593 obj->grouplist[i].indexes.resize(group->nb_index);
594 obj->grouplist[i].siz = group->siz;
595
596 }
597
598 // Copy in the group index data
599 for(long i = 0; i < obj->nbgroups; i++) {
600 if(!obj->grouplist[i].indexes.empty()) {
601 size_t oldpos = pos;
602 pos += sizeof(s32) * obj->grouplist[i].indexes.size(); // Advance to the next index block
603 std::copy((const s32 *)(dat+oldpos), (const s32 *)(dat + pos), obj->grouplist[i].indexes.begin());
604 }
605 }
606 }
607
608 // Copy in the action points data
609 for(size_t i = 0 ; i < obj->actionlist.size(); i++) {
610 obj->actionlist[i] = *reinterpret_cast<const EERIE_ACTIONLIST_FTL *>(dat + pos);
611 pos += sizeof(EERIE_ACTIONLIST_FTL);
612 }
613
614 // Copy in the selections data
615 for(size_t i = 0 ; i < obj->selections.size(); i++) {
616
617 const EERIE_SELECTIONS_FTL * selection = reinterpret_cast<const EERIE_SELECTIONS_FTL *>(dat + pos);
618 pos += sizeof(EERIE_SELECTIONS_FTL);
619
620 obj->selections[i].name = boost::to_lower_copy(util::loadString(selection->name));
621 obj->selections[i].selected.resize(selection->nb_selected);
622 }
623
624 // Copy in the selections selected data
625 for(long i = 0; i < af3Ddh->nb_selections; i++) {
626 std::copy((const s32 *)(dat + pos), (const s32 *)(dat + pos) + obj->selections[i].selected.size(), obj->selections[i].selected.begin() );
627 pos += sizeof(s32) * obj->selections[i].selected.size(); // Advance to the next selection data block
628 }
629
630 obj->pbox = NULL; // Reset physics
631
632 // Alloc'n'Copy Collision Spheres Data
633 if(afsh->offset_collision_spheres != -1) {
634
635 // Cast to header
636 pos = afsh->offset_collision_spheres;
637 const ARX_FTL_COLLISION_SPHERES_DATA_HEADER * afcsdh;
638 afcsdh = reinterpret_cast<const ARX_FTL_COLLISION_SPHERES_DATA_HEADER*>(dat + pos);
639 pos += sizeof(ARX_FTL_COLLISION_SPHERES_DATA_HEADER);
640
641 // Alloc the collision sphere data object
642 obj->sdata = new COLLISION_SPHERES_DATA();
643 obj->sdata->spheres.resize(afcsdh->nb_spheres);
644
645 // Alloc the collision speheres
646 const COLLISION_SPHERE_FTL * begin = reinterpret_cast<const COLLISION_SPHERE_FTL *>(dat + pos);
647 pos += sizeof(COLLISION_SPHERE_FTL) * obj->sdata->spheres.size();
648 const COLLISION_SPHERE_FTL * end = reinterpret_cast<const COLLISION_SPHERE_FTL *>(dat + pos);
649 std::copy(begin, end, obj->sdata->spheres.begin());
650 }
651
652 // Alloc'n'Copy Progressive DATA
653 if(afsh->offset_progressive_data != -1) {
654 // Progressive data ignored.
655 }
656
657 // Alloc'n'Copy Clothes DATA
658 if(afsh->offset_clothes_data != -1) {
659
660 obj->cdata = new CLOTHES_DATA();
661
662 const ARX_FTL_CLOTHES_DATA_HEADER * afcdh;
663 afcdh = reinterpret_cast<const ARX_FTL_CLOTHES_DATA_HEADER*>(dat + afsh->offset_clothes_data);
664 obj->cdata->nb_cvert = (short)afcdh->nb_cvert;
665 obj->cdata->springs.resize(afcdh->nb_springs);
666 size_t pos = afsh->offset_clothes_data;
667 pos += sizeof(ARX_FTL_CLOTHES_DATA_HEADER);
668
669 // now load cvert
670 obj->cdata->cvert = new CLOTHESVERTEX[obj->cdata->nb_cvert];
671 obj->cdata->backup = new CLOTHESVERTEX[obj->cdata->nb_cvert];
672 std::copy(reinterpret_cast<const CLOTHESVERTEX_FTL *>(dat + pos), reinterpret_cast<const CLOTHESVERTEX_FTL *>(dat + pos) + obj->cdata->nb_cvert, obj->cdata->cvert);
673 memcpy(obj->cdata->backup, obj->cdata->cvert, sizeof(CLOTHESVERTEX)*obj->cdata->nb_cvert);
674 pos += sizeof(CLOTHESVERTEX_FTL) * obj->cdata->nb_cvert;
675
676 // now load springs
677 const EERIE_SPRINGS_FTL * begin = reinterpret_cast<const EERIE_SPRINGS_FTL *>(dat + pos);
678 pos += sizeof(EERIE_SPRINGS_FTL) * obj->cdata->springs.size();
679 const EERIE_SPRINGS_FTL * end = reinterpret_cast<const EERIE_SPRINGS_FTL *>(dat + pos);
680 std::copy(begin, end, obj->cdata->springs.begin());
681 }
682
683 // Free the loaded file memory
684 free(dat);
685
686 EERIE_OBJECT_CenterObjectCoordinates(obj);
687 EERIE_CreateCedricData(obj);
688 // Now we can release our cool FTL file
689 EERIE_Object_Precompute_Fast_Access(obj);
690
691 LogDebug("ARX_FTL_Load: loaded object " << filename);
692
693 return obj;
694 }
695