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 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999 ARKANE Studios SA. All rights reserved
46 
47 #include "scene/Object.h"
48 
49 #include <cstdio>
50 
51 #include <boost/algorithm/string/case_conv.hpp>
52 #include <boost/algorithm/string/predicate.hpp>
53 
54 #include "core/Config.h"
55 #include "core/Core.h"
56 
57 #include "game/Entity.h"
58 #include "game/EntityManager.h"
59 
60 #include "graphics/GraphicsTypes.h"
61 #include "graphics/Math.h"
62 #include "graphics/data/Progressive.h"
63 #include "graphics/data/FTL.h"
64 #include "graphics/data/TextureContainer.h"
65 
66 #include "io/fs/FilePath.h"
67 #include "io/fs/SystemPaths.h"
68 #include "io/resource/ResourcePath.h"
69 #include "io/resource/PakReader.h"
70 #include "io/log/Logger.h"
71 
72 #include "physics/Clothes.h"
73 #include "physics/Box.h"
74 #include "physics/CollisionShapes.h"
75 
76 #include "scene/LinkedObject.h"
77 #include "scene/GameSound.h"
78 #include "scene/ObjectFormat.h"
79 #include "scene/Interactive.h"
80 #include "scene/Light.h"
81 
82 #include "util/String.h"
83 
84 using std::sprintf;
85 using std::min;
86 using std::max;
87 using std::string;
88 using std::vector;
89 
90 void EERIE_RemoveCedricData(EERIE_3DOBJ * eobj);
91 
92 void Clear3DScene(EERIE_3DSCENE	* eerie);
93 
GetGroupOriginByName(const EERIE_3DOBJ * eobj,const string & text)94 long GetGroupOriginByName(const EERIE_3DOBJ * eobj, const string & text) {
95 
96 	if(!eobj) {
97 		return -1;
98 	}
99 
100 	for(long i = 0; i < eobj->nbgroups; i++) {
101 		if(eobj->grouplist[i].name == text) {
102 			return eobj->grouplist[i].origin;
103 		}
104 	}
105 
106 	return -1;
107 }
108 
GetActionPointIdx(const EERIE_3DOBJ * eobj,const string & text)109 long GetActionPointIdx(const EERIE_3DOBJ * eobj, const string & text) {
110 
111 	if(!eobj) {
112 		return -1;
113 	}
114 
115 	for(vector<EERIE_ACTIONLIST>::const_iterator i = eobj->actionlist.begin();
116 	    i != eobj->actionlist.end(); ++i) {
117 		if(i->name == text) {
118 			return i->idx;
119 		}
120 	}
121 
122 	return -1;
123 }
124 
GetActionPointGroup(const EERIE_3DOBJ * eobj,long idx)125 long GetActionPointGroup(const EERIE_3DOBJ * eobj, long idx) {
126 
127 	if(!eobj) {
128 		return -1;
129 	}
130 
131 	for(long i = eobj->nbgroups - 1; i >= 0; i--) {
132 		const vector<long> & indices = eobj->grouplist[i].indexes;
133 		for(size_t j = 0; j < indices.size(); j++){
134 			if(indices[j] == idx) {
135 				return i;
136 			}
137 		}
138 	}
139 
140 	return -1;
141 }
142 
EERIE_Object_Precompute_Fast_Access(EERIE_3DOBJ * eerie)143 void EERIE_Object_Precompute_Fast_Access(EERIE_3DOBJ * eerie) {
144 
145 	if(!eerie) return;
146 
147 	long lVRight		=	GetActionPointIdx(eerie, "v_right");
148 	long lURight		=	GetActionPointIdx(eerie, "u_right");
149 	long lViewAttach	=	GetActionPointIdx(eerie, "view_attach") ;
150 	long lPrimAttach	=	GetActionPointIdx(eerie, "primary_attach");
151 	long lLeftAttach	=	GetActionPointIdx(eerie, "left_attach");
152 
153 	eerie->fastaccess.V_right = checked_range_cast<short>(lVRight);
154 	eerie->fastaccess.U_right = checked_range_cast<short>(lURight);
155 	eerie->fastaccess.view_attach = checked_range_cast<short>(lViewAttach);
156 	eerie->fastaccess.primary_attach = checked_range_cast<short>(lPrimAttach);
157 	eerie->fastaccess.left_attach = checked_range_cast<short>(lLeftAttach);
158 
159 
160 	long lWeapAttach				=	GetActionPointIdx(eerie, "weapon_attach");
161 	long lSecAttach					=	GetActionPointIdx(eerie, "secondary_attach");
162 	long lJaw						=	EERIE_OBJECT_GetGroup(eerie, "jaw");
163 	long lMouthAll					=	EERIE_OBJECT_GetGroup(eerie, "mouth all");
164 
165 	eerie->fastaccess.weapon_attach		=	checked_range_cast<short>(lWeapAttach);
166 	eerie->fastaccess.secondary_attach	=	checked_range_cast<short>(lSecAttach);
167 	eerie->fastaccess.jaw_group			=	checked_range_cast<short>(lJaw);
168 	eerie->fastaccess.mouth_group		=	checked_range_cast<short>(lMouthAll);
169 
170 
171 	if (eerie->fastaccess.mouth_group == -1)
172 		eerie->fastaccess.mouth_group_origin = -1;
173 	else
174 	{
175 		long lMouthOrigin = eerie->grouplist[eerie->fastaccess.mouth_group].origin;
176 		eerie->fastaccess.mouth_group_origin = checked_range_cast<short>(lMouthOrigin);
177 	}
178 
179 	long lHeadGroup					=	EERIE_OBJECT_GetGroup(eerie, "head");
180 	eerie->fastaccess.head_group	=	checked_range_cast<short>(lHeadGroup);
181 
182 	if (eerie->fastaccess.head_group == -1)
183 		eerie->fastaccess.head_group_origin = -1;
184 	else
185 	{
186 		long lHeadOrigin  = eerie->grouplist[eerie->fastaccess.head_group].origin;
187 		eerie->fastaccess.head_group_origin = checked_range_cast<short>(lHeadOrigin);
188 	}
189 
190 
191 	long lFire = GetActionPointIdx(eerie, "fire");
192 	long lCarryAttach = GetActionPointIdx(eerie, "carry_attach");
193 	long lHead = EERIE_OBJECT_GetSelection(eerie, "head");
194 	long lChest = EERIE_OBJECT_GetSelection(eerie, "chest");
195 	long lLeggings = EERIE_OBJECT_GetSelection(eerie, "leggings") ;
196 
197 	eerie->fastaccess.fire = checked_range_cast<short>(lFire);
198 	eerie->fastaccess.carry_attach = checked_range_cast<short>(lCarryAttach);
199 	eerie->fastaccess.sel_head = checked_range_cast<short>(lHead);
200 	eerie->fastaccess.sel_chest = checked_range_cast<short>(lChest);
201 	eerie->fastaccess.sel_leggings = checked_range_cast<short>(lLeggings);
202 }
203 
ReleaseAnim(EERIE_ANIM * ea)204 void ReleaseAnim(EERIE_ANIM * ea) {
205 
206 	if(!ea) {
207 		return;
208 	}
209 
210 	if(ea->frames) {
211 		for(long i = 0; i < ea->nb_key_frames; i++) {
212 			ARX_SOUND_Free(ea->frames[i].sample);
213 		}
214 		free(ea->frames);
215 	}
216 
217 	free(ea->groups);
218 	free(ea->voidgroups);
219 	free(ea);
220 }
221 
GetTimeBetweenKeyFrames(EERIE_ANIM * ea,long f1,long f2)222 float GetTimeBetweenKeyFrames(EERIE_ANIM * ea, long f1, long f2)
223 {
224 	if (!ea) return 0;
225 
226 	if (f1 < 0) return 0;
227 
228 	if (f1 > ea->nb_key_frames - 1) return 0;
229 
230 	if (f2 < 0) return 0;
231 
232 	if (f2 > ea->nb_key_frames - 1) return 0;
233 
234 	float time = 0;
235 
236 	for (long kk = f1 + 1; kk <= f2; kk++)
237 	{
238 		time += ea->frames[kk].time;
239 	}
240 
241 	return time;
242 }
243 
244 template <class T>
allocStructZero(size_t n=1)245 static T * allocStructZero(size_t n = 1) {
246 	T * result = (T*)malloc(n * sizeof(T));
247 	memset(result, 0, n * sizeof(T));
248 	return result;
249 }
250 
251 template <class T>
copyStruct(const T * src,size_t n=1)252 static T * copyStruct(const T * src, size_t n = 1) {
253 	T * result = (T*)malloc(n * sizeof(T));
254 	memcpy(result, src, sizeof(T) * n);
255 	return result;
256 }
257 
TheaToEerie(const char * adr,size_t size,const res::path & file)258 EERIE_ANIM * TheaToEerie(const char * adr, size_t size, const res::path & file) {
259 
260 	(void)size; // TODO use size
261 
262 	LogDebug("Loading animation file " << file);
263 
264 	size_t pos = 0;
265 
266 	EERIE_ANIM * eerie = allocStructZero<EERIE_ANIM>();
267 
268 	const THEA_HEADER * th = reinterpret_cast<const THEA_HEADER *>(adr + pos);
269 	if(th->version < 2014) {
270 		LogError << "Invalid TEA Version " << th->version << " in " << file;
271 		free(eerie);
272 		return NULL;
273 	}
274 	pos += sizeof(THEA_HEADER);
275 
276 	LogDebug("TEA header size: " << sizeof(THEA_HEADER));
277 	LogDebug("Identity " << th->identity);
278 	LogDebug("Version - " << th->version << "  Frames " << th->nb_frames
279 	         << "  Groups " << th->nb_groups << "  KeyFrames " << th->nb_key_frames);
280 
281 	eerie->nb_groups = th->nb_groups;
282 	eerie->nb_key_frames = th->nb_key_frames;
283 
284 	eerie->frames = allocStructZero<EERIE_FRAME>(th->nb_key_frames);
285 	eerie->groups = allocStructZero<EERIE_GROUP>(th->nb_key_frames * th->nb_groups);
286 	eerie->voidgroups = allocStructZero<unsigned char>(th->nb_groups);
287 
288 	eerie->anim_time = 0.f;
289 
290 	// Go For Keyframes read
291 	for(long i = 0; i < th->nb_key_frames; i++) {
292 		LogDebug("Loading keyframe " << i);
293 
294 		THEA_KEYFRAME_2015 kf2015;
295 		const THEA_KEYFRAME_2015 * tkf2015;
296 		if(th->version >= 2015) {
297 			LogDebug(" New keyframe version THEA_KEYFRAME_2015:" << sizeof(THEA_KEYFRAME_2015));
298 			tkf2015 = reinterpret_cast<const THEA_KEYFRAME_2015 *>(adr + pos);
299 			pos += sizeof(THEA_KEYFRAME_2015);
300 		} else {
301 			LogDebug(" Old keyframe version THEA_KEYFRAME:" << sizeof(THEA_KEYFRAME));
302 			const THEA_KEYFRAME * tkf = reinterpret_cast<const THEA_KEYFRAME *>(adr + pos);
303 			pos += sizeof(THEA_KEYFRAME);
304 			memset(&kf2015, 0, sizeof(THEA_KEYFRAME_2015));
305 			kf2015.num_frame = tkf->num_frame;
306 			kf2015.flag_frame = tkf->flag_frame;
307 			kf2015.master_key_frame = tkf->master_key_frame;
308 			kf2015.key_frame = tkf->key_frame;
309 			kf2015.key_move = tkf->key_move;
310 			kf2015.key_orient = tkf->key_orient;
311 			kf2015.key_morph = tkf->key_morph;
312 			kf2015.time_frame = tkf->time_frame;
313 			tkf2015 = &kf2015;
314 		}
315 
316 		eerie->frames[i].master_key_frame = tkf2015->master_key_frame;
317 		eerie->frames[i].num_frame = tkf2015->num_frame;
318 
319 		long lKeyOrient = tkf2015->key_orient;
320 		long lKeyMove = tkf2015->key_move;
321 		eerie->frames[i].f_rotate = checked_range_cast<short>(lKeyOrient);
322 		eerie->frames[i].f_translate = checked_range_cast<short>(lKeyMove);
323 
324 		s32 time_frame = tkf2015->num_frame * 1000;
325 		eerie->frames[i].time = time_frame * (1.f/24);
326 		eerie->anim_time += time_frame;
327 		eerie->frames[i].flag = tkf2015->flag_frame;
328 
329 		LogDebug(" pos " << pos << " - NumFr " << eerie->frames[i].num_frame
330 		         << " MKF " << tkf2015->master_key_frame << " THEA_KEYFRAME " << sizeof(THEA_KEYFRAME)
331 		         << " TIME " << (float)(eerie->frames[i].time / 1000.f) << "s -Move " << tkf2015->key_move
332 		         << " Orient " << tkf2015->key_orient << " Morph " << tkf2015->key_morph);
333 
334 		// Is There a Global translation ?
335 		if(tkf2015->key_move != 0) {
336 
337 			const THEA_KEYMOVE * tkm = reinterpret_cast<const THEA_KEYMOVE *>(adr + pos);
338 			pos += sizeof(THEA_KEYMOVE);
339 
340 			LogDebug(" -> move x " << tkm->x << " y " << tkm->y << " z " << tkm->z
341 			         << " THEA_KEYMOVE:" << sizeof(THEA_KEYMOVE));
342 
343 			eerie->frames[i].translate = *tkm;
344 		}
345 
346 		// Is There a Global Rotation ?
347 		if(tkf2015->key_orient != 0) {
348 			pos += 8; // THEO_ANGLE
349 
350 			const ArxQuat * quat = reinterpret_cast<const ArxQuat *>(adr + pos);
351 			pos += sizeof(ArxQuat);
352 
353 			LogDebug(" -> rotate x " << quat->x << " y " << quat->y << " z " << quat->z
354 			         << " w " << quat->w << " ArxQuat:" << sizeof(ArxQuat));
355 
356 			eerie->frames[i].quat = *quat;
357 		}
358 
359 		// Is There a Global Morph ? (IGNORED!)
360 		if(tkf2015->key_morph != 0) {
361 			pos += 16; // THEA_MORPH
362 		}
363 
364 		// Now go for Group Rotations/Translations/scaling for each GROUP
365 		for(long j = 0; j < th->nb_groups; j++) {
366 
367 			const THEO_GROUPANIM * tga = reinterpret_cast<const THEO_GROUPANIM *>(adr + pos);
368 			pos += sizeof(THEO_GROUPANIM);
369 
370 			EERIE_GROUP * eg = &eerie->groups[j + i * th->nb_groups];
371 			eg->key = tga->key_group;
372 			eg->quat = tga->Quaternion;
373 			eg->translate = tga->translate;
374 			eg->zoom = tga->zoom;
375 		}
376 
377 		// Now Read Sound Data included in this frame
378 		s32 num_sample = *reinterpret_cast<const s32 *>(adr + pos);
379 		pos += sizeof(s32);
380 		LogDebug(" -> num_sample " << num_sample << " s32:" << sizeof(s32));
381 
382 		eerie->frames[i].sample = -1;
383 		if(num_sample != -1) {
384 
385 			const THEA_SAMPLE * ts = reinterpret_cast<const THEA_SAMPLE *>(adr + pos);
386 			pos += sizeof(THEA_SAMPLE);
387 			pos += ts->sample_size;
388 
389 			LogDebug(" -> sample " << ts->sample_name << " size " << ts->sample_size
390 			         << " THEA_SAMPLE:" << sizeof(THEA_SAMPLE));
391 
392 			eerie->frames[i].sample = ARX_SOUND_Load(res::path::load(util::loadString(ts->sample_name)));
393 		}
394 
395 		pos += 4; // num_sfx
396 	}
397 
398 	for(long i = 0; i < th->nb_key_frames; i++) {
399 
400 		if(!eerie->frames[i].f_translate) {
401 
402 			long k = i;
403 			while((k >= 0) && (!eerie->frames[k].f_translate)) {
404 				k--;
405 			}
406 
407 			long j = i;
408 			while((j < th->nb_key_frames) && (!eerie->frames[j].f_translate)) {
409 				j++;
410 			}
411 
412 			if((j < th->nb_key_frames) && (k >= 0)) {
413 				float r1 = GetTimeBetweenKeyFrames(eerie, k, i);
414 				float r2 = GetTimeBetweenKeyFrames(eerie, i, j);
415 				float tot = 1.f / (r1 + r2);
416 				r1 *= tot;
417 				r2 *= tot;
418 				eerie->frames[i].translate = eerie->frames[j].translate * r1 + eerie->frames[k].translate * r2;
419 			}
420 		}
421 
422 		if(!eerie->frames[i].f_rotate) {
423 
424 			long k = i;
425 			while((k >= 0) && (!eerie->frames[k].f_rotate)) {
426 				k--;
427 			}
428 
429 			long j = i;
430 			while ((j < th->nb_key_frames) && (!eerie->frames[j].f_rotate)) {
431 				j++;
432 			}
433 
434 			if ((j < th->nb_key_frames) && (k >= 0)) {
435 				float r1 = GetTimeBetweenKeyFrames(eerie, k, i);
436 				float r2 = GetTimeBetweenKeyFrames(eerie, i, j);
437 				float tot = 1.f / (r1 + r2);
438 				r1 *= tot;
439 				r2 *= tot;
440 				// TODO use overloaded operators
441 				eerie->frames[i].quat.w = eerie->frames[j].quat.w * r1 + eerie->frames[k].quat.w * r2;
442 				eerie->frames[i].quat.x = eerie->frames[j].quat.x * r1 + eerie->frames[k].quat.x * r2;
443 				eerie->frames[i].quat.y = eerie->frames[j].quat.y * r1 + eerie->frames[k].quat.y * r2;
444 				eerie->frames[i].quat.z = eerie->frames[j].quat.z * r1 + eerie->frames[k].quat.z * r2;
445 			}
446 		}
447 	}
448 
449 	for(long i = 0; i < th->nb_key_frames; i++) {
450 		eerie->frames[i].f_translate = true;
451 		eerie->frames[i].f_rotate = true;
452 	}
453 
454 	// Sets Flag for voidgroups (unmodified groups for whole animation)
455 	for(long i = 0; i < eerie->nb_groups; i++) {
456 
457 		bool voidd = true;
458 		for(long j = 0; j < eerie->nb_key_frames; j++) {
459 			long pos = i + (j * eerie->nb_groups);
460 
461 			if((eerie->groups[pos].quat.x != 0.f)
462 			   || (eerie->groups[pos].quat.y != 0.f)
463 			   || (eerie->groups[pos].quat.z != 0.f)
464 			   || (eerie->groups[pos].quat.w != 1.f)
465 			   || eerie->groups[pos].translate != Vec3f::ZERO
466 			   || eerie->groups[pos].zoom != Vec3f::ZERO) {
467 				voidd = false;
468 				break;
469 			}
470 		}
471 
472 		if(voidd) {
473 			eerie->voidgroups[i] = 1;
474 		}
475 	}
476 
477 	eerie->anim_time = th->nb_frames * 1000.f * (1.f/24);
478 	if(eerie->anim_time < 1) {
479 		eerie->anim_time = 1;
480 	}
481 
482 	LogDebug("Finished Conversion TEA -> EERIE - " << (eerie->anim_time / 1000) << " seconds");
483 
484 	return eerie;
485 }
486 
MakeUserFlag(TextureContainer * tc)487 void MakeUserFlag(TextureContainer * tc) {
488 
489 	if(tc == NULL) {
490 		return;
491 	}
492 
493 	const string & tex = tc->m_texName.string();
494 
495 	if(boost::contains(tex, "npc_")) {
496 		tc->userflags |= POLY_LATE_MIP;
497 	}
498 
499 	if(boost::contains(tex, "nocol")) {
500 		tc->userflags |= POLY_NOCOL;
501 	}
502 
503 	if(boost::contains(tex, "climb")) {
504 		tc->userflags |= POLY_CLIMB;
505 	}
506 
507 	if(boost::contains(tex, "fall")) {
508 		tc->userflags |= POLY_FALL;
509 	}
510 
511 	if(boost::contains(tex, "lava")) {
512 		tc->userflags |= POLY_LAVA;
513 	}
514 
515 	if(boost::contains(tex, "water") || boost::contains(tex, "spider_web")) {
516 		tc->userflags |= POLY_WATER;
517 		tc->userflags |= POLY_TRANS;
518 	} else if(boost::contains(tex, "[metal]")) {
519 		tc->userflags |= POLY_METAL;
520 	}
521 
522 }
523 
524 #ifdef BUILD_EDIT_LOADSAVE
525 
ReCreateUVs(EERIE_3DOBJ * eerie)526 static void ReCreateUVs(EERIE_3DOBJ * eerie) {
527 
528 	if(eerie->texturecontainer.empty()) {
529 		return;
530 	}
531 
532 	for(size_t i = 0; i < eerie->facelist.size(); i++) {
533 
534 		if(eerie->facelist[i].texid == -1) {
535 			continue;
536 		}
537 
538 		TextureContainer * tex = eerie->texturecontainer[eerie->facelist[i].texid];
539 		Vec2f scale = (tex) ? Vec2f(1.f / tex->m_dwWidth, 1.f / tex->m_dwHeight) : (Vec2f::ONE / 256);
540 
541 		eerie->facelist[i].u[0] = (float)eerie->facelist[i].ou[0] * scale.x;
542 		eerie->facelist[i].u[1] = (float)eerie->facelist[i].ou[1] * scale.x;
543 		eerie->facelist[i].u[2] = (float)eerie->facelist[i].ou[2] * scale.x;
544 		eerie->facelist[i].v[0] = (float)eerie->facelist[i].ov[0] * scale.y;
545 		eerie->facelist[i].v[1] = (float)eerie->facelist[i].ov[1] * scale.y;
546 		eerie->facelist[i].v[2] = (float)eerie->facelist[i].ov[2] * scale.y;
547 	}
548 }
549 
loadObjectData(EERIE_3DOBJ * eerie,const char * adr,size_t * poss,long version)550 static void loadObjectData(EERIE_3DOBJ * eerie, const char * adr, size_t * poss, long version) {
551 
552 	LogWarning << "loadObjectData";
553 
554 	size_t pos = *poss;
555 
556 	const THEO_OFFSETS * to = reinterpret_cast<const THEO_OFFSETS *>(adr + pos);
557 	pos += sizeof(THEO_OFFSETS);
558 
559 	const THEO_NB * tn = reinterpret_cast<const THEO_NB *>(adr + pos);
560 
561 	LogDebug("Nb Vertex " << tn->nb_vertex << " Nb Action Points " << tn->nb_action_point
562 	         << " Nb Lines " << tn->nb_lines);
563 	LogDebug("Nb Faces " << tn->nb_faces << " Nb Groups " << tn->nb_groups);
564 
565 	eerie->vertexlist.resize(tn->nb_vertex);
566 	eerie->facelist.resize(tn->nb_faces);
567 	eerie->nbgroups = tn->nb_groups;
568 	eerie->actionlist.resize(tn->nb_action_point);
569 
570 	eerie->ndata = NULL;
571 	eerie->pdata = NULL;
572 	eerie->cdata = NULL;
573 	eerie->sdata = NULL;
574 
575 	eerie->vertexlist3.resize(tn->nb_vertex);
576 
577 	if(tn->nb_groups == 0) {
578 		eerie->grouplist = NULL;
579 	} else {
580 		eerie->grouplist = new EERIE_GROUPLIST[tn->nb_groups];
581 	}
582 
583 	// read vertices
584 
585 	pos = to->vertex_seek;
586 
587 	if(tn->nb_vertex > 65535) {
588 		LogError << ("Warning Vertex Number Too High...");
589 	}
590 
591 	for(long i = 0; i < tn->nb_vertex; i++) {
592 		const THEO_VERTEX * ptv = reinterpret_cast<const THEO_VERTEX *>(adr + pos);
593 		pos += sizeof(THEO_VERTEX);
594 		eerie->vertexlist[i].v = ptv->pos;
595 		eerie->cub.xmin = min(eerie->cub.xmin, ptv->pos.x);
596 		eerie->cub.xmax = max(eerie->cub.xmax, ptv->pos.x);
597 		eerie->cub.ymin = min(eerie->cub.ymin, ptv->pos.y);
598 		eerie->cub.ymax = max(eerie->cub.ymax, ptv->pos.y);
599 		eerie->cub.zmin = min(eerie->cub.zmin, ptv->pos.z);
600 		eerie->cub.zmax = max(eerie->cub.zmax, ptv->pos.z);
601 	}
602 
603 	// Lecture des FACES THEO
604 	pos = to->faces_seek;
605 
606 	for(long i = 0; i < tn->nb_faces; i++) {
607 
608 		THEO_FACES_3006 tf3006;
609 		const THEO_FACES_3006 * ptf3006;
610 		if(version >= 3006) {
611 			ptf3006 = reinterpret_cast<const THEO_FACES_3006 *>(adr + pos);
612 			pos += sizeof(THEO_FACES_3006);
613 		} else {
614 			memset(&tf3006, 0, sizeof(THEO_FACES_3006));
615 			const THEO_FACES * ptf = reinterpret_cast<const THEO_FACES *>(adr + pos);
616 			pos += sizeof(THEO_FACES);
617 			tf3006.color = ptf->color;
618 			tf3006.index1 = ptf->index1;
619 			tf3006.index2 = ptf->index2;
620 			tf3006.index3 = ptf->index3;
621 			tf3006.ismap = ptf->ismap;
622 			tf3006.liste_uv = ptf->liste_uv;
623 			tf3006.element_uv = ptf->element_uv;
624 			tf3006.num_map = ptf->num_map;
625 			tf3006.tile_x = ptf->tile_x;
626 			tf3006.tile_y = ptf->tile_y;
627 			tf3006.user_tile_x = ptf->user_tile_x;
628 			tf3006.user_tile_y = ptf->user_tile_y;
629 			tf3006.flag = ptf->flag;
630 			tf3006.collision_type = ptf->collision_type;
631 			tf3006.rgb = ptf->rgb;
632 			tf3006.rgb1 = ptf->rgb1;
633 			tf3006.rgb2 = ptf->rgb2;
634 			tf3006.rgb3 = ptf->rgb3;
635 			tf3006.double_side = ptf->double_side;
636 			tf3006.transparency = ptf->transparency;
637 			tf3006.trans = ptf->trans;
638 			ptf3006 = &tf3006;
639 		}
640 
641 		eerie->facelist[i].vid[0] = (unsigned short)ptf3006->index1;
642 		eerie->facelist[i].vid[1] = (unsigned short)ptf3006->index2;
643 		eerie->facelist[i].vid[2] = (unsigned short)ptf3006->index3;
644 
645 		s32 num_map = ((size_t)ptf3006->num_map >= eerie->texturecontainer.size()) ? -1 : ptf3006->num_map;
646 
647 		if(ptf3006->ismap) {
648 			eerie->facelist[i].texid = (short)num_map;
649 			eerie->facelist[i].facetype = POLY_NO_SHADOW;
650 
651 			if(num_map >= 0 && eerie->texturecontainer[num_map] && (eerie->texturecontainer[num_map]->userflags & POLY_NOCOL)) {
652 				eerie->facelist[i].facetype |= POLY_NOCOL;
653 			}
654 		} else if(ptf3006->rgb) {
655 			eerie->facelist[i].texid = -1;
656 		} else {
657 			eerie->facelist[i].texid = -1;
658 		}
659 
660 		switch(ptf3006->flag) {
661 			case 0:
662 				eerie->facelist[i].facetype |= POLY_GLOW;
663 				break;
664 			case 1:
665 				eerie->facelist[i].facetype |= POLY_NO_SHADOW;
666 				break;
667 			case 4:
668 				eerie->facelist[i].facetype |= POLY_METAL;
669 				break;
670 			case 10:
671 				eerie->facelist[i].facetype |= POLY_NOPATH;
672 				break;
673 			case 11:
674 				eerie->facelist[i].facetype |= POLY_CLIMB;
675 				break;
676 			case 12:
677 				eerie->facelist[i].facetype |= POLY_NOCOL;
678 				break;
679 			case 13:
680 				eerie->facelist[i].facetype |= POLY_NODRAW;
681 				break;
682 			case 14:
683 				eerie->facelist[i].facetype |= POLY_PRECISE_PATH;
684 				break;
685 			case 16:
686 				eerie->facelist[i].facetype |= POLY_NO_CLIMB;
687 				break;
688 		}
689 
690 		eerie->facelist[i].ou[0] = (short)ptf3006->liste_uv.u1;
691 		eerie->facelist[i].ov[0] = (short)ptf3006->liste_uv.v1;
692 		eerie->facelist[i].ou[1] = (short)ptf3006->liste_uv.u2;
693 		eerie->facelist[i].ov[1] = (short)ptf3006->liste_uv.v2;
694 		eerie->facelist[i].ou[2] = (short)ptf3006->liste_uv.u3;
695 		eerie->facelist[i].ov[2] = (short)ptf3006->liste_uv.v3;
696 
697 		if(ptf3006->double_side) {
698 			eerie->facelist[i].facetype |= POLY_DOUBLESIDED;
699 		}
700 
701 		if(ptf3006->transparency > 0) {
702 			if(ptf3006->transparency == 2) {
703 				// NORMAL TRANS 0.00001 to 0.999999
704 				if(ptf3006->trans < 1.f) {
705 					eerie->facelist[i].facetype |= POLY_TRANS;
706 					eerie->facelist[i].transval = ptf3006->trans;
707 				}
708 			}
709 			else if (ptf3006->transparency == 1) {
710 				if(ptf3006->trans < 0.f) {
711 					// SUBTRACTIVE -0.000001 to -0.999999
712 					eerie->facelist[i].facetype |= POLY_TRANS;
713 					eerie->facelist[i].transval = ptf3006->trans;
714 				} else {
715 					// ADDITIVE 1.000001 to 1.9999999
716 					eerie->facelist[i].facetype |= POLY_TRANS;
717 					eerie->facelist[i].transval = ptf3006->trans + 1.f;
718 				}
719 			} else {
720 				// MULTIPLICATIVE 2.000001 to 2.9999999
721 				eerie->facelist[i].facetype |= POLY_TRANS;
722 				eerie->facelist[i].transval = ptf3006->trans + 2.f;
723 			}
724 		}
725 
726 		if(eerie->facelist[i].texid != -1 && !eerie->texturecontainer.empty() && eerie->texturecontainer[eerie->facelist[i].texid] != NULL) {
727 
728 			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_TRANS) {
729 				if(!(eerie->facelist[i].facetype & POLY_TRANS)) {
730 					eerie->facelist[i].facetype |= POLY_TRANS;
731 					eerie->facelist[i].transval = ptf3006->trans;
732 				}
733 			}
734 
735 			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_WATER) {
736 				eerie->facelist[i].facetype |= POLY_WATER;
737 			}
738 
739 			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_LAVA) {
740 				eerie->facelist[i].facetype |= POLY_LAVA;
741 			}
742 
743 			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_FALL) {
744 				eerie->facelist[i].facetype |= POLY_FALL;
745 			}
746 
747 			if(eerie->texturecontainer[eerie->facelist[i].texid]->userflags & POLY_CLIMB) {
748 				eerie->facelist[i].facetype |= POLY_CLIMB;
749 			}
750 		}
751 
752 	}
753 
754 	// Groups Data
755 	pos = to->groups_seek;
756 
757 	for(long i = 0; i < tn->nb_groups; i++) {
758 
759 		THEO_GROUPS_3011 tg3011;
760 		const THEO_GROUPS_3011 * ptg3011;
761 		if(version >= 3011) {
762 			ptg3011 = reinterpret_cast<const THEO_GROUPS_3011 *>(adr + pos);
763 			pos += sizeof(THEO_GROUPS_3011);
764 		} else {
765 			const THEO_GROUPS * ltg = reinterpret_cast<const THEO_GROUPS *>(adr + pos);
766 			pos += sizeof(THEO_GROUPS);
767 			memset(&tg3011, 0, sizeof(THEO_GROUPS_3011));
768 			tg3011.origin = ltg->origin;
769 			tg3011.nb_index = ltg->nb_index;
770 			ptg3011 = &tg3011;
771 		}
772 
773 		eerie->grouplist[i].origin = ptg3011->origin;
774 		eerie->grouplist[i].indexes.resize(ptg3011->nb_index);
775 
776 		std::copy((const long*)(adr + pos), (const long*)(adr + pos) + ptg3011->nb_index, eerie->grouplist[i].indexes.begin());
777 		pos += ptg3011->nb_index * sizeof(long);
778 
779 		eerie->grouplist[i].name = boost::to_lower_copy(util::loadString(adr + pos, 256));
780 		pos += 256;
781 		eerie->grouplist[i].siz = 0.f;
782 
783 		for(long o = 0; o < ptg3011->nb_index; o++) {
784 			eerie->grouplist[i].siz = max(eerie->grouplist[i].siz,
785 			                              fdist(eerie->vertexlist[eerie->grouplist[i].origin].v,
786 			                                           eerie->vertexlist[eerie->grouplist[i].indexes[o]].v));
787 		}
788 
789 		eerie->grouplist[i].siz = ffsqrt(eerie->grouplist[i].siz) * (1.f/16);
790 
791 	}
792 
793 	// SELECTIONS
794 	s32 THEO_nb_selected = *reinterpret_cast<const s32 *>(adr + pos);
795 	pos += sizeof(s32);
796 
797 	eerie->selections.resize(THEO_nb_selected);
798 	for(long i = 0; i < THEO_nb_selected; i++) {
799 
800 		const THEO_SELECTED * pts = reinterpret_cast<const THEO_SELECTED *>(adr + pos);
801 		pos += sizeof(THEO_SELECTED);
802 
803 		eerie->selections[i].name = boost::to_lower_copy(util::loadString(pts->name));
804 		eerie->selections[i].selected.resize(pts->nb_index);
805 
806 		if(pts->nb_index > 0) {
807 			std::copy((const long*)(adr + pos), (const long*)(adr + pos) + pts->nb_index, eerie->selections[i].selected.begin());
808 			pos += sizeof(long) * pts->nb_index;
809 		}
810 	}
811 
812 	// Theo Action Points Read
813 	pos = to->action_point_seek;
814 
815 	for(long i = 0; i < tn->nb_action_point; i++) {
816 
817 		const THEO_ACTION_POINT * ptap = reinterpret_cast<const THEO_ACTION_POINT *>(adr + pos);
818 		pos += sizeof(THEO_ACTION_POINT);
819 
820 		eerie->actionlist[i].act = ptap->action;
821 		eerie->actionlist[i].sfx = ptap->num_sfx;
822 		eerie->actionlist[i].idx = ptap->vert_index;
823 		eerie->actionlist[i].name = boost::to_lower_copy(util::loadString(ptap->name));
824 	}
825 
826 	eerie->angle = Anglef::ZERO;
827 	eerie->pos = Vec3f::ZERO;
828 
829 	// Now Interpret Extra Data chunk
830 	pos = to->extras_seek + 4;
831 
832 	if(version >= 3005) {
833 
834 		const THEO_EXTRA_DATA_3005 * pted3005 = reinterpret_cast<const THEO_EXTRA_DATA_3005 *>(adr + pos);
835 		pos += sizeof(THEO_EXTRA_DATA_3005);
836 
837 		eerie->pos = pted3005->pos;
838 
839 		eerie->angle.a = (float)(pted3005->angle.alpha & 0xfff) * THEO_ROTCONVERT;
840 		eerie->angle.b = (float)(pted3005->angle.beta & 0xfff) * THEO_ROTCONVERT;
841 		eerie->angle.g = (float)(pted3005->angle.gamma & 0xfff) * THEO_ROTCONVERT;
842 
843 		eerie->point0 = eerie->vertexlist[pted3005->origin_index].v;
844 		eerie->origin = pted3005->origin_index;
845 
846 		eerie->quat = pted3005->quat;
847 
848 	} else {
849 
850 		const THEO_EXTRA_DATA * pted = reinterpret_cast<const THEO_EXTRA_DATA *>(adr + pos);
851 		pos += sizeof(THEO_EXTRA_DATA);
852 
853 		eerie->pos = pted->pos;
854 
855 		eerie->angle.a = (float)(pted->angle.alpha & 0xfff) * THEO_ROTCONVERT;
856 		eerie->angle.b = (float)(pted->angle.beta & 0xfff) * THEO_ROTCONVERT;
857 		eerie->angle.g = (float)(pted->angle.gamma & 0xfff) * THEO_ROTCONVERT;
858 
859 		eerie->point0 = eerie->vertexlist[pted->origin_index].v;
860 		eerie->origin = pted->origin_index;
861 
862 	}
863 
864 	*poss = pos;
865 
866 	eerie->vertexlist3 = eerie->vertexlist;
867 	ReCreateUVs(eerie);
868 	EERIE_Object_Precompute_Fast_Access(eerie);
869 }
870 
ScnToEerie(const char * adr,size_t size,const res::path & fic)871 static EERIE_3DSCENE * ScnToEerie(const char * adr, size_t size, const res::path & fic) {
872 
873 	(void)size; // TODO use size
874 
875 	LogDebug("Loading Scene " << fic);
876 
877 	size_t pos = 0;
878 
879 	EERIE_3DSCENE * seerie = allocStructZero<EERIE_3DSCENE>();
880 	Clear3DScene(seerie);
881 
882 	const TSCN_HEADER * psth = reinterpret_cast<const TSCN_HEADER *>(adr + pos);
883 	pos += sizeof(TSCN_HEADER);
884 
885 	LogDebug("SCNtoEERIE " << fic << " Version " << psth->version << " Nb Textures " << psth->nb_maps);
886 
887 	if(psth->version < 3008 || psth->version > 3024) {
888 		LogError << "ScnToEerie: invalid version in " << fic << ": found " << psth->version
889 		         << " expected 3008 to 3024";
890 		free(seerie);
891 		return NULL;
892 	}
893 
894 	seerie->nbtex = psth->nb_maps;
895 
896 	const res::path temp = "graph/obj3d/textures";
897 
898 	if(psth->type_write == 0) {
899 
900 		seerie->texturecontainer = allocStructZero<TextureContainer *>(psth->nb_maps);
901 
902 		for(long i = 0; i < psth->nb_maps; i++) {
903 
904 			const THEO_TEXTURE * tt = reinterpret_cast<const THEO_TEXTURE *>(adr + pos);
905 			pos += sizeof(THEO_TEXTURE);
906 
907 			res::path mapsname = temp / res::path::load(util::loadString(tt->texture_name)).remove_ext();
908 			seerie->texturecontainer[i] = TextureContainer::Load(mapsname, TextureContainer::Level);
909 		}
910 
911 	} else {
912 
913 		if((psth->type_write & SAVE_MAP_BMP) || (psth->type_write & SAVE_MAP_TGA)) {
914 
915 			seerie->texturecontainer = allocStructZero<TextureContainer *>(psth->nb_maps);
916 
917 			for(long i = 0; i < psth->nb_maps; i++) {
918 
919 				res::path name;
920 				if(psth->version >= 3019) {
921 					const THEO_SAVE_MAPS_IN_3019 * tsmi3019 = reinterpret_cast<const THEO_SAVE_MAPS_IN_3019 *>(adr + pos);
922 					pos += sizeof(THEO_SAVE_MAPS_IN_3019);
923 					name = res::path::load(util::loadString(tsmi3019->texture_name)).remove_ext();
924 				} else {
925 					const THEO_SAVE_MAPS_IN * tsmi = reinterpret_cast<const THEO_SAVE_MAPS_IN *>(adr + pos);
926 					pos += sizeof(THEO_SAVE_MAPS_IN);
927 					name = res::path::load(util::loadString(tsmi->texture_name)).remove_ext();
928 				}
929 
930 				if(!name.empty()) {
931 					seerie->texturecontainer[i] = TextureContainer::Load(temp / name, TextureContainer::Level);
932 				}
933 			}
934 		}
935 	}
936 
937 	// read objects
938 	pos = psth->object_seek;
939 
940 	s32 nbo = *reinterpret_cast<const s32 *>(adr + pos);
941 	pos += sizeof(s32);
942 
943 	seerie->nbobj = nbo;
944 	seerie->objs = allocStructZero<EERIE_3DOBJ *>(nbo);
945 
946 	seerie->point0 = Vec3f::repeat(-999999999999.f);
947 
948 	long id = 0;
949 
950 	for(long i = 0; i < nbo; i++) {
951 
952 		const TSCN_OBJHEADER * ptoh = reinterpret_cast<const TSCN_OBJHEADER *>(adr + pos);
953 		pos += sizeof(TSCN_OBJHEADER);
954 
955 		seerie->objs[id] = new EERIE_3DOBJ();
956 		// TODO most is done in the constructor already
957 		seerie->objs[id]->clear();
958 
959 		seerie->objs[id]->texturecontainer.resize(seerie->nbtex);
960 		std::copy(seerie->texturecontainer, seerie->texturecontainer + seerie->nbtex, seerie->objs[id]->texturecontainer.begin());
961 
962 		long objVersion;
963 		if(psth->version < 3013) {
964 			objVersion = 3004;
965 		} else if(psth->version < 3015) {
966 			objVersion = 3005;
967 		} else if(psth->version < 3019) {
968 			objVersion = 3006;
969 		} else if(psth->version < 3023) {
970 			objVersion = 3008;
971 		} else {
972 			objVersion = 3011;
973 		}
974 		loadObjectData(seerie->objs[id], adr, &pos, objVersion);
975 
976 		seerie->cub.xmin = min(seerie->cub.xmin, seerie->objs[id]->cub.xmin + seerie->objs[id]->pos.x);
977 		seerie->cub.xmax = max(seerie->cub.xmax, seerie->objs[id]->cub.xmax + seerie->objs[id]->pos.x);
978 		seerie->cub.ymin = min(seerie->cub.ymin, seerie->objs[id]->cub.ymin + seerie->objs[id]->pos.y);
979 		seerie->cub.ymax = max(seerie->cub.ymax, seerie->objs[id]->cub.ymax + seerie->objs[id]->pos.y);
980 		seerie->cub.zmin = min(seerie->cub.zmin, seerie->objs[id]->cub.zmin + seerie->objs[id]->pos.z);
981 		seerie->cub.zmax = max(seerie->cub.zmax, seerie->objs[id]->cub.zmax + seerie->objs[id]->pos.z);
982 
983 		string name = boost::to_lower_copy(util::loadString(ptoh->object_name));
984 		if(name == "map_origin") {
985 			seerie->point0 = seerie->objs[id]->point0 + seerie->objs[id]->pos;
986 			delete seerie->objs[id];
987 			seerie->nbobj--;
988 			id--;
989 		} else {
990 			seerie->objs[id]->name = name;
991 		}
992 
993 		id++;
994 
995 		pos = ptoh->next_obj;
996 	}
997 
998 	pos = psth->light_seek; // ambient
999 
1000 	pos += sizeof(SavedColor); // ignore ambient color
1001 
1002 	s32 nbl = *reinterpret_cast<const s32 *>(adr + pos);
1003 	pos += sizeof(s32);
1004 
1005 	seerie->light = NULL;
1006 	seerie->nblight = nbl;
1007 
1008 	for(long i = 0; i < nbl; i++) {
1009 
1010 		TSCN_LIGHT_3024 sl3024;
1011 		const TSCN_LIGHT_3024 * tsl3024;
1012 
1013 		if(psth->version >= 3024) {
1014 			tsl3024 = reinterpret_cast<const TSCN_LIGHT_3024 *>(adr + pos);
1015 			pos += sizeof(TSCN_LIGHT_3024);
1016 		} else if(psth->version >= 3019) {
1017 			const TSCN_LIGHT_3019 * tsl3019 = reinterpret_cast<const TSCN_LIGHT_3019 *>(adr + pos);
1018 			pos += sizeof(TSCN_LIGHT_3019);
1019 			memset(&sl3024, 0, sizeof(TSCN_LIGHT_3024));
1020 			sl3024.red = tsl3019->red;
1021 			sl3024.green = tsl3019->green;
1022 			sl3024.blue = tsl3019->blue;
1023 			sl3024.pos = tsl3019->pos;
1024 			sl3024.hotspot = tsl3019->hotspot;
1025 			sl3024.falloff = tsl3019->falloff;
1026 			sl3024.intensity = tsl3019->intensity;
1027 			tsl3024 = &sl3024;
1028 		} else {
1029 			const TSCN_LIGHT * tsl = reinterpret_cast<const TSCN_LIGHT *>(adr + pos);
1030 			pos += sizeof(TSCN_LIGHT);
1031 			memset(&sl3024, 0, sizeof(TSCN_LIGHT_3024));
1032 			sl3024.red = tsl->red;
1033 			sl3024.green = tsl->green;
1034 			sl3024.blue = tsl->blue;
1035 			sl3024.pos = tsl->pos;
1036 			sl3024.hotspot = tsl->hotspot;
1037 			sl3024.falloff = tsl->falloff;
1038 			sl3024.intensity = tsl->intensity;
1039 			tsl3024 = &sl3024;
1040 		}
1041 
1042 		EERIE_LIGHT light;
1043 
1044 		light.rgb.r = (float)tsl3024->red * ( 1.0f / 255 );
1045 		light.rgb.g = (float)tsl3024->green * ( 1.0f / 255 );
1046 		light.rgb.b = (float)tsl3024->blue * ( 1.0f / 255 );
1047 		light.pos = tsl3024->pos;
1048 		light.fallstart = (float)tsl3024->hotspot;
1049 		light.fallend = (float)tsl3024->falloff;
1050 
1051 		float t = light.fallend - light.fallstart;
1052 		if(t < 150.f) {
1053 			light.fallend += 150.f - t;
1054 		}
1055 
1056 		light.intensity = (float)tsl3024->intensity;
1057 		light.exist = 1;
1058 		light.treat = 1;
1059 		light.selected = 0;
1060 		light.type = 0;
1061 		EERIE_LIGHT_GlobalAdd(&light);
1062 	}
1063 
1064 	return seerie;
1065 }
1066 
ReleaseScene(EERIE_3DSCENE * scene)1067 static void ReleaseScene(EERIE_3DSCENE * scene) {
1068 
1069 	free(scene->texturecontainer), scene->texturecontainer = NULL;
1070 
1071 	for(long i = 0; i < scene->nbobj; i++) {
1072 		delete scene->objs[i];
1073 	}
1074 
1075 	free(scene->objs), scene->objs = NULL;
1076 	free(scene->texturecontainer), scene->texturecontainer = NULL;
1077 
1078 	if(scene->light) {
1079 		for(long i = 0; i < scene->nblight; i++) {
1080 			free(scene->light[i]), scene->light[i] = NULL;
1081 		}
1082 		free(scene->light), scene->light = NULL;
1083 	}
1084 
1085 	free(scene);
1086 }
1087 
ReleaseMultiScene(EERIE_MULTI3DSCENE * ms)1088 void ReleaseMultiScene(EERIE_MULTI3DSCENE * ms) {
1089 
1090 	if(ms) {
1091 		for(long i = 0; i < ms->nb_scenes; i++) {
1092 			ReleaseScene(ms->scenes[i]);
1093 			ms->scenes[i] = NULL;
1094 		}
1095 	}
1096 
1097 	free(ms);
1098 }
1099 
PAK_MultiSceneToEerie_Impl(const res::path & dirr)1100 static EERIE_MULTI3DSCENE * PAK_MultiSceneToEerie_Impl(const res::path & dirr) {
1101 
1102 	EERIE_MULTI3DSCENE * es = allocStructZero<EERIE_MULTI3DSCENE>();
1103 
1104 	LastLoadedScene = dirr;
1105 
1106 	PakDirectory * dir = resources->getDirectory(dirr);
1107 	if(dir) {
1108 		bool loaded = false;
1109 		for(PakDirectory::files_iterator i = dir->files_begin(); i != dir->files_end(); i++) {
1110 			if(!res::path(i->first).has_ext("scn")) {
1111 				continue;
1112 			}
1113 
1114 			char * adr = i->second->readAlloc();
1115 			if(adr) {
1116 				es->scenes[es->nb_scenes] = ScnToEerie(adr, i->second->size(), dirr);
1117 				es->nb_scenes++;
1118 				free(adr);
1119 			} else {
1120 				LogError << "Could not read scene " << dirr << '/' << i->first;
1121 			}
1122 
1123 			loaded = true;
1124 		}
1125 		if(!loaded) {
1126 			LogWarning << "Empty multiscene: " << dirr;
1127 		}
1128 	} else {
1129 		LogWarning << "Multiscene not found: " << dirr;
1130 	}
1131 
1132 	es->cub.xmax = -9999999999.f;
1133 	es->cub.xmin = 9999999999.f;
1134 	es->cub.ymax = -9999999999.f;
1135 	es->cub.ymin = 9999999999.f;
1136 	es->cub.zmax = -9999999999.f;
1137 	es->cub.zmin = 9999999999.f;
1138 
1139 	for(long i = 0; i < es->nb_scenes; i++) {
1140 		es->cub.xmax = max(es->cub.xmax, es->scenes[i]->cub.xmax);
1141 		es->cub.xmin = min(es->cub.xmin, es->scenes[i]->cub.xmin);
1142 		es->cub.ymax = max(es->cub.ymax, es->scenes[i]->cub.ymax);
1143 		es->cub.ymin = min(es->cub.ymin, es->scenes[i]->cub.ymin);
1144 		es->cub.zmax = max(es->cub.zmax, es->scenes[i]->cub.zmax);
1145 		es->cub.zmin = min(es->cub.zmin, es->scenes[i]->cub.zmin);
1146 		es->pos = es->scenes[i]->pos;
1147 
1148 		if((es->scenes[i]->point0.x != -999999999999.f) &&
1149 		   (es->scenes[i]->point0.y != -999999999999.f) &&
1150 		   (es->scenes[i]->point0.z != -999999999999.f)) {
1151 			es->point0 = es->scenes[i]->point0;
1152 		}
1153 	}
1154 
1155 	if(es->nb_scenes == 0) {
1156 		free(es);
1157 		return NULL;
1158 	}
1159 
1160 	return es;
1161 }
1162 
PAK_MultiSceneToEerie(const res::path & dirr)1163 EERIE_MULTI3DSCENE * PAK_MultiSceneToEerie(const res::path & dirr) {
1164 
1165 	LogDebug("Loading Multiscene " << dirr);
1166 
1167 	EERIE_MULTI3DSCENE * em = NULL;
1168 
1169 	em = PAK_MultiSceneToEerie_Impl(dirr);
1170 
1171 	EERIEPOLY_Compute_PolyIn();
1172 	return em;
1173 }
1174 
1175 #endif // BUILD_EDIT_LOADSAVE
1176 
1177 //-----------------------------------------------------------------------------------------------------
1178 // Warning Clear3DObj/Clear3DScene don't release Any pointer Just Clears Structures
clear()1179 void EERIE_3DOBJ::clear() {
1180 
1181 		point0 = pos = Vec3f::ZERO;
1182 		angle = Anglef::ZERO;
1183 
1184 		origin = 0;
1185 		ident = 0;
1186 		nbgroups = 0;
1187 		drawflags = 0;
1188 
1189 		vertexlocal = NULL;
1190 		vertexlist.clear();
1191 		vertexlist3.clear();
1192 
1193 		facelist.clear();
1194 		grouplist = NULL;
1195 		texturecontainer.clear();
1196 
1197 		originaltextures = NULL;
1198 		linked = NULL;
1199 
1200 		// TODO Default constructor
1201 		quat.x = quat.y = quat.z = quat.w = 0;
1202 		nblinked = 0;
1203 
1204 		pbox = 0;
1205 		pdata = 0;
1206 		ndata = 0;
1207 		cdata = 0;
1208 		sdata = 0;
1209 
1210 		fastaccess.view_attach = 0;
1211 		fastaccess.primary_attach = 0;
1212 		fastaccess.left_attach = 0;
1213 		fastaccess.weapon_attach = 0;
1214 		fastaccess.secondary_attach = 0;
1215 		fastaccess.mouth_group = 0;
1216 		fastaccess.jaw_group = 0;
1217 		fastaccess.head_group_origin = 0;
1218 		fastaccess.head_group = 0;
1219 		fastaccess.mouth_group_origin = 0;
1220 		fastaccess.V_right = 0;
1221 		fastaccess.U_right = 0;
1222 		fastaccess.fire = 0;
1223 		fastaccess.sel_head = 0;
1224 		fastaccess.sel_chest = 0;
1225 		fastaccess.sel_leggings = 0;
1226 		fastaccess.carry_attach = 0;
1227 		fastaccess.padding_ = 0;
1228 
1229 		c_data = 0;
1230 
1231 	cub.xmin = cub.ymin = cub.zmin = std::numeric_limits<float>::max();
1232 	cub.xmax = cub.ymax = cub.zmax = std::numeric_limits<float>::min();
1233 }
1234 
Clear3DScene(EERIE_3DSCENE * eerie)1235 void Clear3DScene(EERIE_3DSCENE * eerie) {
1236 
1237 	if(eerie == NULL) {
1238 		return;
1239 	}
1240 
1241 	memset(eerie, 0, sizeof(EERIE_3DSCENE));
1242 	eerie->cub.xmin = eerie->cub.ymin = eerie->cub.zmin = std::numeric_limits<float>::max();
1243 	eerie->cub.xmax = eerie->cub.ymax = eerie->cub.zmax = std::numeric_limits<float>::min();
1244 }
1245 
1246 // TODO move to destructor?
~EERIE_3DOBJ()1247 EERIE_3DOBJ::~EERIE_3DOBJ() {
1248 
1249 	free(originaltextures), originaltextures = NULL;
1250 
1251 	if(ndata) {
1252 		KillNeighbours(this);
1253 	}
1254 
1255 	if(pdata) {
1256 		KillProgressiveData(this);
1257 	}
1258 
1259 	if(cdata) {
1260 		KillClothesData(this);
1261 	}
1262 
1263 	EERIE_RemoveCedricData(this);
1264 	EERIE_PHYSICS_BOX_Release(this);
1265 	EERIE_COLLISION_SPHERES_Release(this);
1266 
1267 	delete[] grouplist;
1268 	free(linked);
1269 }
1270 
Eerie_Copy(const EERIE_3DOBJ * obj)1271 EERIE_3DOBJ * Eerie_Copy(const EERIE_3DOBJ * obj) {
1272 
1273 	EERIE_3DOBJ * nouvo = new EERIE_3DOBJ();
1274 
1275 	nouvo->vertexlist = obj->vertexlist;
1276 
1277 	nouvo->vertexlist3 = obj->vertexlist3;
1278 
1279 	nouvo->linked = NULL;
1280 	nouvo->ndata = NULL;
1281 	nouvo->pbox = NULL;
1282 	nouvo->pdata = NULL;
1283 	nouvo->cdata = NULL;
1284 	nouvo->sdata = NULL;
1285 	nouvo->c_data = NULL;
1286 	nouvo->vertexlocal = NULL;
1287 
1288 	nouvo->angle = obj->angle;
1289 	nouvo->pos = obj->pos;
1290 	nouvo->cub.xmax = obj->cub.xmax;
1291 	nouvo->cub.xmin = obj->cub.xmin;
1292 	nouvo->cub.ymax = obj->cub.ymax;
1293 	nouvo->cub.ymin = obj->cub.ymin;
1294 	nouvo->cub.zmax = obj->cub.zmax;
1295 	nouvo->cub.zmin = obj->cub.zmin;
1296 	nouvo->drawflags = obj->drawflags;
1297 
1298 	if ( !obj->file.empty() )
1299 		nouvo->file = obj->file;
1300 
1301 	nouvo->ident = obj->ident;
1302 
1303 	if ( !obj->name.empty() )
1304 		nouvo->name = obj->name;
1305 
1306 	nouvo->origin = obj->origin;
1307 	nouvo->point0 = obj->point0;
1308 	Quat_Copy(&nouvo->quat, &obj->quat);
1309 
1310 
1311 	if (obj->ndata)
1312 	{
1313 		nouvo->ndata = copyStruct(obj->ndata, obj->vertexlist.size());
1314 	}
1315 	else nouvo->ndata = NULL;
1316 
1317 	nouvo->facelist = obj->facelist;
1318 
1319 	if (obj->nbgroups) {
1320 		nouvo->nbgroups = obj->nbgroups;
1321 		nouvo->grouplist = new EERIE_GROUPLIST[obj->nbgroups];
1322 		std::copy(obj->grouplist, obj->grouplist + obj->nbgroups, nouvo->grouplist);
1323 	}
1324 
1325 	nouvo->actionlist = obj->actionlist;
1326 
1327 	nouvo->selections = obj->selections;
1328 
1329 	nouvo->texturecontainer = obj->texturecontainer;
1330 
1331 	memcpy(&nouvo->fastaccess, &obj->fastaccess, sizeof(EERIE_FASTACCESS));
1332 	EERIE_CreateCedricData(nouvo);
1333 
1334 	if (obj->pbox)
1335 	{
1336 		nouvo->pbox = allocStructZero<PHYSICS_BOX_DATA>();
1337 		nouvo->pbox->nb_physvert = obj->pbox->nb_physvert;
1338 		nouvo->pbox->stopcount = 0;
1339 		nouvo->pbox->radius = obj->pbox->radius;
1340 
1341 		nouvo->pbox->vert = copyStruct(obj->pbox->vert, obj->pbox->nb_physvert);
1342 	}
1343 
1344 	nouvo->linked = NULL;
1345 	nouvo->nblinked = 0;
1346 	nouvo->originaltextures = NULL;
1347 	return nouvo;
1348 }
1349 
EERIE_OBJECT_GetSelection(const EERIE_3DOBJ * obj,const string & selname)1350 long EERIE_OBJECT_GetSelection(const EERIE_3DOBJ * obj, const string & selname) {
1351 
1352 	if(!obj) {
1353 		return -1;
1354 	}
1355 
1356 	for(size_t i = 0; i < obj->selections.size(); i++) {
1357 		if(obj->selections[i].name == selname) {
1358 			return i;
1359 		}
1360 	}
1361 
1362 	return -1;
1363 }
1364 
EERIE_OBJECT_GetGroup(const EERIE_3DOBJ * obj,const string & groupname)1365 long EERIE_OBJECT_GetGroup(const EERIE_3DOBJ * obj, const string & groupname) {
1366 
1367 	if(!obj) {
1368 		return -1;
1369 	}
1370 
1371 	for(long i = 0; i < obj->nbgroups; i++) {
1372 		if(obj->grouplist[i].name == groupname) {
1373 			return i;
1374 		}
1375 	}
1376 
1377 	return -1;
1378 }
1379 
AddIdxToBone(EERIE_BONE * bone,long idx)1380 void AddIdxToBone(EERIE_BONE * bone, long idx)
1381 {
1382 	bone->idxvertices = (long *)realloc(bone->idxvertices, sizeof(long) * (bone->nb_idxvertices + 1));
1383 
1384 	if (bone->idxvertices)
1385 	{
1386 		bone->idxvertices[bone->nb_idxvertices] = idx;
1387 		bone->nb_idxvertices++;
1388 	}
1389 }
1390 //-----------------------------------------------------------------------------------------------------
GetFather(EERIE_3DOBJ * eobj,long origin,long startgroup)1391 long GetFather(EERIE_3DOBJ * eobj, long origin, long startgroup)
1392 {
1393 	for (long i = startgroup; i >= 0; i--)
1394 	{
1395 		for (size_t j = 0; j < eobj->grouplist[i].indexes.size(); j++)
1396 		{
1397 			if (eobj->grouplist[i].indexes[j] == origin)
1398 			{
1399 				return i;
1400 			}
1401 		}
1402 	}
1403 
1404 	return -1;
1405 }
1406 
EERIE_RemoveCedricData(EERIE_3DOBJ * eobj)1407 void EERIE_RemoveCedricData(EERIE_3DOBJ * eobj) {
1408 
1409 	if(!eobj || !eobj->c_data) {
1410 		return;
1411 	}
1412 
1413 	for(long i = 0; i < eobj->c_data->nb_bones; i++) {
1414 		free(eobj->c_data->bones[i].idxvertices), eobj->c_data->bones[i].idxvertices = NULL;
1415 	}
1416 
1417 	delete[] eobj->c_data->bones, eobj->c_data->bones = NULL;
1418 	delete eobj->c_data, eobj->c_data = NULL;
1419 	delete[] eobj->vertexlocal, eobj->vertexlocal = NULL;
1420 }
1421 
EERIE_CreateCedricData(EERIE_3DOBJ * eobj)1422 void EERIE_CreateCedricData(EERIE_3DOBJ * eobj) {
1423 
1424 	eobj->c_data = new EERIE_C_DATA();
1425 	memset(eobj->c_data, 0, sizeof(EERIE_C_DATA));
1426 
1427 	if (eobj->nbgroups <= 0) // If no groups were specified
1428 	{
1429 		// Make one bone
1430 		eobj->c_data->nb_bones = 1;
1431 		eobj->c_data->bones = new EERIE_BONE[eobj->c_data->nb_bones];
1432 		memset(eobj->c_data->bones, 0, sizeof(EERIE_BONE)*eobj->c_data->nb_bones);
1433 
1434 		// Add all vertices to the bone
1435 		for (size_t i = 0; i < eobj->vertexlist.size(); i++)
1436 			AddIdxToBone(&eobj->c_data->bones[0], i);
1437 
1438 		// Initialize the bone
1439 		Quat_Init(&eobj->c_data->bones[0].quatinit);
1440 		Quat_Init(&eobj->c_data->bones[0].quatanim);
1441 		eobj->c_data->bones[0].scaleinit = Vec3f::ZERO;
1442 		eobj->c_data->bones[0].scaleanim = Vec3f::ZERO;
1443 		eobj->c_data->bones[0].transinit = Vec3f::ZERO;
1444 		eobj->c_data->bones[0].transinit_global = eobj->c_data->bones[0].transinit;
1445 		eobj->c_data->bones[0].original_group = NULL;
1446 		eobj->c_data->bones[0].father = -1;
1447 	}
1448 	else // Groups were specified
1449 	{
1450 		// Alloc the bones
1451 		eobj->c_data->nb_bones = eobj->nbgroups;
1452 		eobj->c_data->bones = new EERIE_BONE[eobj->c_data->nb_bones];
1453 		// TODO memset -> use constructor instead
1454 		memset(eobj->c_data->bones, 0, sizeof(EERIE_BONE)*eobj->c_data->nb_bones);
1455 
1456 		bool * temp = new bool[eobj->vertexlist.size()];
1457 		memset(temp, 0, eobj->vertexlist.size());
1458 
1459 		for (long i = eobj->nbgroups - 1; i >= 0; i--)
1460 		{
1461 			EERIE_VERTEX * v_origin = &eobj->vertexlist[eobj->grouplist[i].origin];
1462 
1463 			for (size_t j = 0; j < eobj->grouplist[i].indexes.size(); j++)
1464 			{
1465 				if (!temp[eobj->grouplist[i].indexes[j]])
1466 				{
1467 					temp[eobj->grouplist[i].indexes[j]] = true;
1468 					AddIdxToBone(&eobj->c_data->bones[i], eobj->grouplist[i].indexes[j]);
1469 				}
1470 			}
1471 
1472 			Quat_Init(&eobj->c_data->bones[i].quatinit);
1473 			Quat_Init(&eobj->c_data->bones[i].quatanim);
1474 			eobj->c_data->bones[i].scaleinit = Vec3f::ZERO;
1475 			eobj->c_data->bones[i].scaleanim = Vec3f::ZERO;
1476 			eobj->c_data->bones[i].transinit = Vec3f(v_origin->v.x, v_origin->v.y, v_origin->v.z);
1477 			eobj->c_data->bones[i].transinit_global = eobj->c_data->bones[i].transinit;
1478 			eobj->c_data->bones[i].original_group = &eobj->grouplist[i];
1479 			eobj->c_data->bones[i].father = GetFather(eobj, eobj->grouplist[i].origin, i - 1);
1480 		}
1481 
1482 		delete[] temp;
1483 
1484 		// Try to correct lonely vertex
1485 		for (size_t i = 0; i < eobj->vertexlist.size(); i++)
1486 		{
1487 			long ok = 0;
1488 
1489 			for (long j = 0; j < eobj->nbgroups; j++)
1490 			{
1491 				for (size_t k = 0; k < eobj->grouplist[j].indexes.size(); k++)
1492 				{
1493 					if ((size_t)eobj->grouplist[j].indexes[k] == i)
1494 					{
1495 						ok = 1;
1496 						break;
1497 					}
1498 				}
1499 
1500 				if (ok)
1501 					break;
1502 			}
1503 
1504 			if (!ok)
1505 			{
1506 				AddIdxToBone(&eobj->c_data->bones[0], i);
1507 			}
1508 		}
1509 
1510 		for(long i = eobj->nbgroups - 1; i >= 0; i--) {
1511 			if(eobj->c_data->bones[i].father >= 0) {
1512 				long father = eobj->c_data->bones[i].father;
1513 				eobj->c_data->bones[i].transinit -= eobj->c_data->bones[father].transinit;
1514 			}
1515 			eobj->c_data->bones[i].transinit_global = eobj->c_data->bones[i].transinit;
1516 		}
1517 
1518 	}
1519 
1520 	/* Build proper mesh */
1521 	{
1522 		EERIE_C_DATA* obj = eobj->c_data;
1523 
1524 
1525 		for (long i = 0; i != obj->nb_bones; i++)
1526 		{
1527 			EERIE_QUAT	qt1;
1528 
1529 			if (obj->bones[i].father >= 0)
1530 			{
1531 				/* Rotation*/
1532 				Quat_Copy(&qt1, &obj->bones[i].quatinit);
1533 				Quat_Multiply(&obj->bones[i].quatanim, &obj->bones[obj->bones[i].father].quatanim, &qt1);
1534 				/* Translation */
1535 				TransformVertexQuat(&obj->bones[obj->bones[i].father].quatanim, &obj->bones[i].transinit, &obj->bones[i].transanim);
1536 				obj->bones[i].transanim = obj->bones[obj->bones[i].father].transanim + obj->bones[i].transanim;
1537 			}
1538 			else
1539 			{
1540 				/* Rotation*/
1541 				Quat_Copy(&obj->bones[i].quatanim, &obj->bones[i].quatinit);
1542 				/* Translation */
1543 				obj->bones[i].transanim = obj->bones[i].transinit;
1544 			}
1545 			obj->bones[i].scaleanim = Vec3f::ONE;
1546 		}
1547 
1548 		eobj->vertexlocal = new EERIE_3DPAD[eobj->vertexlist.size()];
1549 		// TODO constructor is better than memset
1550 		memset(eobj->vertexlocal, 0, sizeof(EERIE_3DPAD)*eobj->vertexlist.size());
1551 
1552 		for (long i = 0; i != obj->nb_bones; i++) {
1553 			Vec3f vector = obj->bones[i].transanim;
1554 
1555 			for (int v = 0; v != obj->bones[i].nb_idxvertices; v++) {
1556 
1557 				long idx = obj->bones[i].idxvertices[v];
1558 				const EERIE_VERTEX & inVert = eobj->vertexlist[idx];
1559 				EERIE_3DPAD & outVert = eobj->vertexlocal[idx];
1560 
1561 				Vec3f temp = inVert.v - vector;
1562 				TransformInverseVertexQuat(&obj->bones[i].quatanim, &temp, &temp);
1563 				outVert.x = temp.x, outVert.y = temp.y, outVert.z = temp.z;
1564 			}
1565 		}
1566 	}
1567 }
1568 
1569 #ifdef BUILD_EDIT_LOADSAVE
1570 
1571 // Converts a Theo Object to an EERIE object
TheoToEerie(const char * adr,long size,const res::path & texpath,const res::path & fic)1572 static EERIE_3DOBJ * TheoToEerie(const char * adr, long size, const res::path & texpath, const res::path & fic) {
1573 
1574 	LogWarning << "TheoToEerie " << fic;
1575 
1576 	if(!adr) {
1577 		return NULL;
1578 	}
1579 
1580 	res::path txpath = texpath.empty() ? "graph/obj3d/textures" : texpath;
1581 
1582 	if(size < 10) {
1583 		return NULL;
1584 	}
1585 
1586 	size_t pos = 0;
1587 
1588 	const THEO_HEADER * pth = reinterpret_cast<const THEO_HEADER *>(adr + pos);
1589 	pos += sizeof(THEO_HEADER);
1590 
1591 	if (pth->version < 3003 || pth->version > 3011) {
1592 		LogError << "TheoToEerie: invalid version in " << fic << ": found " << pth->version
1593 		         << " expected 3004 to 3011";
1594 		return NULL;
1595 	}
1596 
1597 	EERIE_3DOBJ * eerie = new EERIE_3DOBJ;
1598 	eerie->clear();
1599 
1600 	eerie->file = fic;
1601 
1602 	if(pth->type_write == 0) {
1603 		// read the texture
1604 
1605 		LogError <<  "WARNING object " << fic << " SAVE MAP IN OBJECT = INVALID... Using Dummy Textures...";
1606 
1607 		eerie->texturecontainer.resize(pth->nb_maps);
1608 		for(long i = 0; i < pth->nb_maps; i++) {
1609 			pos += sizeof(THEO_TEXTURE);
1610 			eerie->texturecontainer[i] = GetAnyTexture();
1611 		}
1612 
1613 	} else {
1614 
1615 		if((pth->type_write & SAVE_MAP_BMP) || (pth->type_write & SAVE_MAP_TGA)) {
1616 
1617 			eerie->texturecontainer.resize(pth->nb_maps);
1618 			for(long i = 0; i < pth->nb_maps; i++) {
1619 
1620 				res::path name;
1621 				if(pth->version >= 3008) {
1622 					const THEO_SAVE_MAPS_IN_3019 * tsmi3019 = reinterpret_cast<const THEO_SAVE_MAPS_IN_3019 *>(adr + pos);
1623 					pos += sizeof(THEO_SAVE_MAPS_IN_3019);
1624 					name = res::path::load(util::loadString(tsmi3019->texture_name)).remove_ext();
1625 				} else {
1626 					const THEO_SAVE_MAPS_IN * tsmi = reinterpret_cast<const THEO_SAVE_MAPS_IN *>(adr + pos);
1627 					pos += sizeof(THEO_SAVE_MAPS_IN);
1628 					name = res::path::load(util::loadString(tsmi->texture_name)).remove_ext();
1629 				}
1630 
1631 				if(!name.empty()) {
1632 					eerie->texturecontainer[i] = TextureContainer::Load(txpath / name, TextureContainer::Level);
1633 				}
1634 			}
1635 		}
1636 	}
1637 
1638 	pos = pth->object_seek;
1639 	loadObjectData(eerie, adr, &pos, pth->version);
1640 	eerie->angle = Anglef::ZERO;
1641 	eerie->pos = Vec3f::ZERO;
1642 
1643 	// NORMALS CALCULATIONS
1644 	Vec3f nrml;
1645 	Vec3f nrrr;
1646 	float count;
1647 	long j, j2;
1648 
1649 	//Compute Faces Areas
1650 	for(size_t i = 0; i < eerie->facelist.size(); i++) {
1651 		const Vec3f & p0 = eerie->vertexlist[eerie->facelist[i].vid[0]].v;
1652 		const Vec3f & p1 = eerie->vertexlist[eerie->facelist[i].vid[1]].v;
1653 		const Vec3f & p2 = eerie->vertexlist[eerie->facelist[i].vid[2]].v;
1654 		eerie->facelist[i].temp = dist((p0 + p1) * .5f, p2) * dist(p0, p1) * .5f;
1655 	}
1656 
1657 	for (size_t i = 0; i < eerie->facelist.size(); i++)
1658 	{
1659 		CalcObjFaceNormal(
1660 		    &eerie->vertexlist[eerie->facelist[i].vid[0]].v,
1661 		    &eerie->vertexlist[eerie->facelist[i].vid[1]].v,
1662 		    &eerie->vertexlist[eerie->facelist[i].vid[2]].v,
1663 		    &eerie->facelist[i]
1664 		);
1665 		float area = eerie->facelist[i].temp;
1666 
1667 		for (j = 0; j < 3; j++)
1668 		{
1669 			float mod = area * area;
1670 			nrrr = nrml = eerie->facelist[i].norm * mod;
1671 			count = mod;
1672 
1673 			for (size_t i2 = 0; i2 < eerie->facelist.size(); i2++)
1674 			{
1675 				if (i != i2)
1676 				{
1677 					float area2 = eerie->facelist[i].temp;
1678 
1679 					for (j2 = 0; j2 < 3; j2++)
1680 					{
1681 						if (closerThan(eerie->vertexlist[eerie->facelist[i2].vid[j2]].v, eerie->vertexlist[eerie->facelist[i].vid[j]].v, .1f))
1682 						{
1683 							mod = (area2 * area2);
1684 							nrml += eerie->facelist[i2].norm * mod;
1685 							count += mod;
1686 						}
1687 					}
1688 				}
1689 			}
1690 
1691 			count = 1.f / count;
1692 			eerie->vertexlist[eerie->facelist[i].vid[j]].vert.p = nrml * count;
1693 		}
1694 	}
1695 
1696 	for(size_t i = 0; i < eerie->facelist.size(); i++) {
1697 		for(j = 0; j < 3; j++) {
1698 			eerie->vertexlist[eerie->facelist[i].vid[j]].norm = eerie->vertexlist[eerie->facelist[i].vid[j]].vert.p;
1699 		}
1700 	}
1701 
1702 	// Apply Normals Spherical correction for NPC head
1703 	long neck_orgn = GetGroupOriginByName(eerie, "neck");
1704 	long head_idx = EERIE_OBJECT_GetGroup(eerie, "head");
1705 
1706 	if ((head_idx >= 0) && (neck_orgn >= 0))
1707 	{
1708 		Vec3f center = Vec3f::ZERO;
1709 		Vec3f origin = eerie->vertexlist[neck_orgn].v;
1710 		float count = (float)eerie->grouplist[head_idx].indexes.size();
1711 
1712 		if (count > 0.f)
1713 		{
1714 			for(size_t idx = 0 ; idx < eerie->grouplist[head_idx].indexes.size(); idx++) {
1715 				center += eerie->vertexlist[ eerie->grouplist[head_idx].indexes[idx] ].v;
1716 			}
1717 
1718 			center = (center * (1.f / count) + origin + origin) * (1.0f / 3);
1719 			float max_threshold = dist(origin, center);
1720 
1721 			for (size_t i = 0; i < eerie->grouplist[head_idx].indexes.size(); i++)
1722 			{
1723 				EERIE_VERTEX * ev = &eerie->vertexlist[eerie->grouplist[head_idx].indexes[i]];
1724 				float d = dist(ev->v, origin);
1725 				float factor = 1.f;
1726 
1727 				if (d < max_threshold)
1728 				{
1729 					factor = d / max_threshold;
1730 				}
1731 
1732 				float ifactor = 1.f - factor;
1733 				Vec3f fakenorm;
1734 				fakenorm = ev->v - center;
1735 				fakenorm.normalize();
1736 				ev->norm = ev->norm * ifactor + fakenorm * factor;
1737 				ev->norm.normalize();
1738 			}
1739 		}
1740 	}
1741 
1742 	// NORMALS CALCULATIONS END
1743 	//***********************************************************
1744 
1745 	EERIE_LINKEDOBJ_InitData(eerie);
1746 	eerie->c_data = NULL;
1747 	EERIE_CreateCedricData(eerie);
1748 	return eerie;
1749 }
1750 
GetExistingEerie(const res::path & file)1751 static EERIE_3DOBJ * GetExistingEerie(const res::path & file) {
1752 
1753 	for(size_t i = 1; i < entities.size(); i++) {
1754 		if(entities[i] != NULL && !entities[i]->tweaky && entities[i]->obj) {
1755 			EERIE_3DOBJ * obj = entities[i]->obj;
1756 			if(!obj->originaltextures && entities[i]->obj->file == file) {
1757 				return entities[i]->obj;
1758 			}
1759 		}
1760 	}
1761 
1762 	return NULL;
1763 }
1764 
1765 #endif
1766 
TheoToEerie_Fast(const res::path & texpath,const res::path & file,bool pbox)1767 static EERIE_3DOBJ * TheoToEerie_Fast(const res::path & texpath, const res::path & file, bool pbox) {
1768 
1769 	EERIE_3DOBJ * ret = ARX_FTL_Load(file);
1770 	if(ret) {
1771 		if(pbox) {
1772 			EERIE_PHYSICS_BOX_Create(ret);
1773 		}
1774 		return ret;
1775 	}
1776 
1777 #ifndef BUILD_EDIT_LOADSAVE
1778 	ARX_UNUSED(texpath);
1779 #else
1780 
1781 	ret = GetExistingEerie(file);
1782 	if(ret) {
1783 		ret = Eerie_Copy(ret);
1784 	}
1785 
1786 	if(!ret) {
1787 
1788 		size_t size = 0;
1789 		char * adr = resources->readAlloc(file, size);
1790 		if(!adr) {
1791 			LogWarning << "Object not found: " << file;
1792 			return NULL;
1793 		}
1794 
1795 		ret = TheoToEerie(adr, size, texpath, file);
1796 		if(!ret) {
1797 			free(adr);
1798 			return NULL;
1799 		}
1800 
1801 		EERIE_OBJECT_CenterObjectCoordinates(ret);
1802 		free(adr);
1803 	}
1804 
1805 	CreateNeighbours(ret);
1806 	EERIEOBJECT_AddClothesData(ret);
1807 	KillNeighbours(ret);
1808 
1809 	if(ret->cdata) {
1810 		EERIE_COLLISION_SPHERES_Create(ret); // Must be out of the Neighbours zone
1811 	}
1812 
1813 	if(pbox) {
1814 		EERIE_PHYSICS_BOX_Create(ret);
1815 	}
1816 
1817 	ARX_FTL_Save(fs::paths.user / file.string(), ret);
1818 
1819 #endif // BUILD_EDIT_LOADSAVE
1820 
1821 	return ret;
1822 }
1823 
loadObject(const res::path & file,bool pbox)1824 EERIE_3DOBJ * loadObject(const res::path & file, bool pbox) {
1825 	return TheoToEerie_Fast("graph/obj3d/textures", file, pbox);
1826 }
1827 
LoadTheObj(const res::path & file,const res::path & texpath)1828 EERIE_3DOBJ * LoadTheObj(const res::path & file, const res::path & texpath) {
1829 	return TheoToEerie_Fast(file.parent() / texpath, file, true);
1830 }
1831 
1832 // TODO why is this in EERIEobject
1833 ACTIONSTRUCT actions[MAX_ACTIONS];
RemoveAllBackgroundActions()1834 void RemoveAllBackgroundActions()
1835 {
1836 	memset(actions, 0, sizeof(ACTIONSTRUCT)*MAX_ACTIONS);
1837 
1838 	for(size_t i = 0; i < MAX_ACTIONS; i++) actions[i].dl = -1;
1839 }
1840 
EERIE_OBJECT_CenterObjectCoordinates(EERIE_3DOBJ * ret)1841 void EERIE_OBJECT_CenterObjectCoordinates(EERIE_3DOBJ * ret)
1842 {
1843 	if (!ret) return;
1844 
1845 	Vec3f offset = ret->vertexlist[ret->origin].v;
1846 
1847 	if ((offset.x == 0) && (offset.y == 0) && (offset.z == 0))
1848 		return;
1849 
1850 	LogWarning << "NOT CENTERED " << ret->file;
1851 
1852 	for(size_t i = 0; i < ret->vertexlist.size(); i++) {
1853 		ret->vertexlist[i].v -= offset;
1854 		ret->vertexlist[i].vert.p -= offset;
1855 		ret->vertexlist3[i].v -= offset;
1856 		ret->vertexlist3[i].vert.p -= offset;
1857 		ret->vertexlist3[i].v -= offset;
1858 		ret->vertexlist3[i].vert.p -= offset;
1859 	}
1860 
1861 	ret->point0 -= offset;
1862 }
1863