1 /*
2 * Copyright 2011-2012 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-2000 ARKANE Studios SA. All rights reserved
46
47 #include "graphics/data/MeshManipulation.h"
48
49 #include <stddef.h>
50 #include <cstring>
51 #include <cstdlib>
52 #include <algorithm>
53 #include <string>
54 #include <vector>
55
56 #include "game/Entity.h"
57
58 #include "graphics/BaseGraphicsTypes.h"
59 #include "graphics/GraphicsTypes.h"
60 #include "graphics/Vertex.h"
61 #include "graphics/data/Mesh.h"
62 #include "graphics/data/TextureContainer.h"
63 #include "graphics/effects/DrawEffects.h"
64
65 #include "io/resource/PakReader.h"
66 #include "io/log/Logger.h"
67
68 #include "math/MathFwd.h"
69 #include "math/Vector3.h"
70
71 #include "platform/Platform.h"
72
73 #include "scene/Object.h"
74
75 using std::max;
76 using std::string;
77 using std::vector;
78
EERIE_MESH_TWEAK_Skin(EERIE_3DOBJ * obj,const res::path & s1,const res::path & s2)79 void EERIE_MESH_TWEAK_Skin(EERIE_3DOBJ * obj, const res::path & s1, const res::path & s2) {
80
81 LogDebug("Tweak Skin " << s1 << " " << s2);
82
83 if ( obj == NULL || s1.empty() || s2.empty() )
84 {
85 LogError << "Tweak Skin got NULL Pointer";
86 return;
87 }
88
89 LogDebug("Tweak Skin " << s1 << " " << s2);
90
91 res::path skintochange = "graph/obj3d/textures" / s1;
92
93 res::path skinname = "graph/obj3d/textures" / s2;
94 TextureContainer * tex = TextureContainer::Load(skinname);
95
96 if (obj->originaltextures == NULL)
97 {
98 obj->originaltextures = (char *)malloc(256 * obj->texturecontainer.size());
99 memset(obj->originaltextures, 0, 256 * obj->texturecontainer.size());
100
101 for (size_t i = 0; i < obj->texturecontainer.size(); i++)
102 {
103 if (obj->texturecontainer[i])
104 strcpy(obj->originaltextures + 256 * i, obj->texturecontainer[i]->m_texName.string().c_str());
105
106 }
107 }
108
109 if ((tex != NULL) && (obj->originaltextures != NULL))
110 {
111 for (size_t i = 0; i < obj->texturecontainer.size(); i++)
112 {
113 if ((strstr(obj->originaltextures + 256 * i, skintochange.string().c_str())))
114 {
115 skintochange = obj->texturecontainer[i]->m_texName;
116 break;
117 }
118 }
119
120 TextureContainer * tex2 = TextureContainer::Find(skintochange);
121 if (tex2)
122 {
123 for (size_t i = 0; i < obj->texturecontainer.size(); i++)
124 {
125 if (obj->texturecontainer[i] == tex2)
126 obj->texturecontainer[i] = tex;
127 }
128 }
129 }
130 }
131
IsInSelection(const EERIE_3DOBJ * obj,long vert,long tw)132 long IsInSelection(const EERIE_3DOBJ * obj, long vert, long tw) {
133
134 if (obj == NULL) return -1;
135
136 if (tw < 0) return -1;
137
138 if (vert < 0) return -1;
139
140 for (size_t i = 0; i < obj->selections[tw].selected.size(); i++)
141 {
142 if (obj->selections[tw].selected[i] == vert)
143 return i;
144 }
145
146 return -1;
147 }
148
GetEquivalentVertex(const EERIE_3DOBJ * obj,const EERIE_VERTEX * vert)149 static long GetEquivalentVertex(const EERIE_3DOBJ * obj, const EERIE_VERTEX * vert) {
150
151 for (size_t i = 0; i < obj->vertexlist.size(); i++)
152 {
153 if ((obj->vertexlist[i].v.x == vert->v.x)
154 && (obj->vertexlist[i].v.y == vert->v.y)
155 && (obj->vertexlist[i].v.z == vert->v.z))
156 return i;
157 }
158
159 return -1;
160 }
161
ObjectAddVertex(EERIE_3DOBJ * obj,const EERIE_VERTEX * vert)162 static long ObjectAddVertex(EERIE_3DOBJ * obj, const EERIE_VERTEX * vert) {
163
164 for (size_t i = 0; i < obj->vertexlist.size(); i++)
165 {
166 if ((obj->vertexlist[i].v.x == vert->v.x)
167 && (obj->vertexlist[i].v.y == vert->v.y)
168 && (obj->vertexlist[i].v.z == vert->v.z))
169 return i;
170 }
171
172 obj->vertexlist.push_back(*vert);
173 return (obj->vertexlist.size() - 1);
174 }
175
GetActionPoint(const EERIE_3DOBJ * obj,const char * name)176 static long GetActionPoint(const EERIE_3DOBJ * obj, const char * name) {
177
178 if (!obj) return -1;
179
180 for (size_t n = 0; n < obj->actionlist.size(); n++)
181 { // TODO iterator
182 if(obj->actionlist[n].name == name) {
183 return obj->actionlist[n].idx;
184 }
185 }
186
187 return -1;
188 }
189
ObjectAddFace(EERIE_3DOBJ * obj,const EERIE_FACE * face,const EERIE_3DOBJ * srcobj)190 static long ObjectAddFace(EERIE_3DOBJ * obj, const EERIE_FACE * face, const EERIE_3DOBJ * srcobj) {
191
192 for (size_t i = 0; i < obj->facelist.size(); i++) // Check Already existing faces
193 {
194 if ((obj->vertexlist[obj->facelist[i].vid[0]].v.x == srcobj->vertexlist[face->vid[0]].v.x)
195 && (obj->vertexlist[obj->facelist[i].vid[1]].v.x == srcobj->vertexlist[face->vid[1]].v.x)
196 && (obj->vertexlist[obj->facelist[i].vid[2]].v.x == srcobj->vertexlist[face->vid[2]].v.x)
197 && (obj->vertexlist[obj->facelist[i].vid[0]].v.y == srcobj->vertexlist[face->vid[0]].v.y)
198 && (obj->vertexlist[obj->facelist[i].vid[1]].v.y == srcobj->vertexlist[face->vid[1]].v.y)
199 && (obj->vertexlist[obj->facelist[i].vid[2]].v.y == srcobj->vertexlist[face->vid[2]].v.y)
200 && (obj->vertexlist[obj->facelist[i].vid[0]].v.z == srcobj->vertexlist[face->vid[0]].v.z)
201 && (obj->vertexlist[obj->facelist[i].vid[1]].v.z == srcobj->vertexlist[face->vid[1]].v.z)
202 && (obj->vertexlist[obj->facelist[i].vid[2]].v.z == srcobj->vertexlist[face->vid[2]].v.z)
203 )
204
205 return -1;
206 }
207
208 long f0, f1, f2;
209 f0 = ObjectAddVertex(obj, &srcobj->vertexlist[face->vid[0]]);
210 f1 = ObjectAddVertex(obj, &srcobj->vertexlist[face->vid[1]]);
211 f2 = ObjectAddVertex(obj, &srcobj->vertexlist[face->vid[2]]);
212
213 if ((f1 == -1) || (f2 == -1) || (f0 == -1)) return -1;
214
215
216 obj->facelist.push_back(*face);
217
218 obj->facelist.back().vid[0] = (unsigned short)f0;
219 obj->facelist.back().vid[1] = (unsigned short)f1;
220 obj->facelist.back().vid[2] = (unsigned short)f2;
221 obj->facelist.back().texid = 0;
222
223 for (size_t i = 0; i < obj->texturecontainer.size(); i++)
224 {
225 if (0 <= face->texid && (size_t)face->texid < srcobj->texturecontainer.size() && obj->texturecontainer[i] == srcobj->texturecontainer[face->texid])
226 {
227 obj->facelist.back().texid = (short)i;
228 break;
229 }
230 }
231
232 return (obj->facelist.size() - 1);
233 }
234
ObjectAddAction(EERIE_3DOBJ * obj,const string & name,long act,long sfx,const EERIE_VERTEX * vert)235 static long ObjectAddAction(EERIE_3DOBJ * obj, const string & name, long act,
236 long sfx, const EERIE_VERTEX * vert) {
237
238 long newvert = ObjectAddVertex(obj, vert);
239
240 if (newvert < 0) return -1;
241
242 long j = 0;
243 for(vector<EERIE_ACTIONLIST>::iterator i = obj->actionlist.begin();
244 i != obj->actionlist.end(); ++i) {
245 if(i->name == name) {
246 return j;
247 }
248 j++;
249 }
250
251 obj->actionlist.push_back(EERIE_ACTIONLIST());
252
253 EERIE_ACTIONLIST & action = obj->actionlist.back();
254
255 action.name = name;
256 action.act = act;
257 action.sfx = sfx;
258 action.idx = newvert;
259
260 return (obj->actionlist.size() - 1);
261 }
262
ObjectAddMap(EERIE_3DOBJ * obj,TextureContainer * tc)263 long ObjectAddMap(EERIE_3DOBJ * obj, TextureContainer * tc) {
264
265 if (tc == NULL) return -1;
266
267 for (size_t i = 0; i < obj->texturecontainer.size(); i++)
268 {
269 if (obj->texturecontainer[i] == tc)
270 return i;
271 }
272
273 obj->texturecontainer.push_back(tc);
274
275 return (obj->texturecontainer.size() - 1);
276 }
277
AddVertexToGroup(EERIE_3DOBJ * obj,long group,const EERIE_VERTEX * vert)278 static void AddVertexToGroup(EERIE_3DOBJ * obj, long group, const EERIE_VERTEX * vert) {
279
280 for (size_t i = 0; i < obj->vertexlist.size(); i++)
281 {
282 if ((obj->vertexlist[i].v.x == vert->v.x)
283 && (obj->vertexlist[i].v.y == vert->v.y)
284 && (obj->vertexlist[i].v.z == vert->v.z))
285 {
286 AddVertexIdxToGroup(obj, group, i);
287 }
288 }
289 }
290
AddVertexIdxToGroup(EERIE_3DOBJ * obj,long group,long val)291 void AddVertexIdxToGroup(EERIE_3DOBJ * obj, long group, long val) {
292
293 for(size_t i = 0; i < obj->grouplist[group].indexes.size(); i++) {
294 if(obj->grouplist[group].indexes[i] == val) {
295 return;
296 }
297 }
298
299 obj->grouplist[group].indexes.push_back(val);
300 }
301
ObjectAddSelection(EERIE_3DOBJ * obj,long numsel,long vidx)302 static void ObjectAddSelection(EERIE_3DOBJ * obj, long numsel, long vidx) {
303
304 for (size_t i = 0; i < obj->selections[numsel].selected.size(); i++)
305 {
306 if (obj->selections[numsel].selected[i] == vidx) return;
307 }
308
309 obj->selections[numsel].selected.push_back(vidx);
310 }
311
CreateIntermediaryMesh(const EERIE_3DOBJ * obj1,const EERIE_3DOBJ * obj2,long tw)312 static EERIE_3DOBJ * CreateIntermediaryMesh(const EERIE_3DOBJ * obj1, const EERIE_3DOBJ * obj2, long tw) {
313
314 long tw1 = -1;
315 long tw2 = -1;
316 long iw1 = -1;
317 long jw1 = -1;
318 long sel_head1 = -1;
319 long sel_head2 = -1;
320 long sel_torso1 = -1;
321 long sel_torso2 = -1;
322 long sel_legs1 = -1;
323 long sel_legs2 = -1;
324
325 // First we retreive selection groups indexes
326 for(size_t i = 0; i < obj1->selections.size(); i++) { // TODO iterator
327 if(obj1->selections[i].name == "head") {
328 sel_head1 = i;
329 } else if(obj1->selections[i].name == "chest") {
330 sel_torso1 = i;
331 } else if(obj1->selections[i].name == "leggings") {
332 sel_legs1 = i;
333 }
334 }
335
336 for(size_t i = 0; i < obj2->selections.size(); i++) { // TODO iterator
337 if(obj2->selections[i].name == "head") {
338 sel_head2 = i;
339 } else if(obj2->selections[i].name == "chest") {
340 sel_torso2 = i;
341 } else if(obj2->selections[i].name == "leggings") {
342 sel_legs2 = i;
343 }
344 }
345
346 if (sel_head1 == -1) return NULL;
347
348 if (sel_head2 == -1) return NULL;
349
350 if (sel_torso1 == -1) return NULL;
351
352 if (sel_torso2 == -1) return NULL;
353
354 if (sel_legs1 == -1) return NULL;
355
356 if (sel_legs2 == -1) return NULL;
357
358 if (tw == TWEAK_HEAD)
359 {
360 tw1 = sel_head1;
361 tw2 = sel_head2;
362 iw1 = sel_torso1;
363 jw1 = sel_legs1;
364 }
365
366 if (tw == TWEAK_TORSO)
367 {
368 tw1 = sel_torso1;
369 tw2 = sel_torso2;
370 iw1 = sel_head1;
371 jw1 = sel_legs1;
372 }
373
374 if (tw == TWEAK_LEGS)
375 {
376 tw1 = sel_legs1;
377 tw2 = sel_legs2;
378 iw1 = sel_torso1;
379 jw1 = sel_head1;
380 }
381
382 if ((tw1 == -1) || (tw2 == -1)) return NULL;
383
384 // Now Retreives Tweak Action Points
385 {
386 long idx_head1, idx_head2;
387 long idx_torso1, idx_torso2;
388
389 idx_head1 = GetActionPoint(obj1, "head2chest");
390
391 if (idx_head1 < 0) return NULL;
392
393 idx_head2 = GetActionPoint(obj2, "head2chest");
394
395 if (idx_head2 < 0) return NULL;
396
397 idx_torso1 = GetActionPoint(obj1, "chest2leggings");
398
399 if (idx_torso1 < 0) return NULL;
400
401 idx_torso2 = GetActionPoint(obj2, "chest2leggings");
402
403 if (idx_torso2 < 0) return NULL;
404 }
405
406 // copy vertices
407 vector<EERIE_VERTEX> obj1vertexlist2 = obj1->vertexlist;
408 vector<EERIE_VERTEX> obj2vertexlist2 = obj2->vertexlist;
409
410 // Work will contain the Tweaked object
411 EERIE_3DOBJ * work = new EERIE_3DOBJ();
412 work->pos = obj1->pos;
413 work->angle = obj1->angle;
414
415 // ident will be the same as original object obj1
416 work->ident = obj1->ident;
417
418 // We reset all data to create a fresh object
419 memcpy(&work->cub, &obj1->cub, sizeof(CUB3D));
420 memcpy(&work->quat, &obj1->quat, sizeof(EERIE_QUAT));
421
422 // Linked objects are linked to this object.
423 if (obj1->nblinked > obj2->nblinked)
424 {
425 work->linked = (EERIE_LINKED *)malloc(obj1->nblinked * sizeof(EERIE_LINKED));
426 memcpy(work->linked, obj1->linked, obj1->nblinked * sizeof(EERIE_LINKED));
427 work->nblinked = obj1->nblinked;
428 }
429 else if (obj2->nblinked > 0)
430 {
431 work->linked = (EERIE_LINKED *)malloc(obj2->nblinked * sizeof(EERIE_LINKED));
432 memcpy(work->linked, obj2->linked, obj2->nblinked * sizeof(EERIE_LINKED));
433 work->nblinked = obj2->nblinked;
434 }
435 else
436 {
437 work->linked = NULL;
438 work->nblinked = 0;
439 }
440
441 // Is the origin of object in obj1 or obj2 ? Retreives it for work object
442 if(IsInSelection(obj1, obj1->origin, tw1) != -1) {
443 work->point0 = obj2->point0;
444 work->origin = ObjectAddVertex(work, &obj2vertexlist2[obj2->origin]);
445 } else {
446 work->point0 = obj1->point0;
447 work->origin = ObjectAddVertex(work, &obj1vertexlist2[obj1->origin]);
448 }
449
450 // Recreate Action Points included in work object.for Obj1
451 for (size_t i = 0; i < obj1->actionlist.size(); i++)
452 {
453 if ((IsInSelection(obj1, obj1->actionlist[i].idx, iw1) != -1)
454 || (IsInSelection(obj1, obj1->actionlist[i].idx, jw1) != -1)
455 || obj1->actionlist[i].name == "head2chest"
456 || obj1->actionlist[i].name == "chest2leggings") {
457 ObjectAddAction(work, obj1->actionlist[i].name, obj1->actionlist[i].act,
458 obj1->actionlist[i].sfx, &obj1vertexlist2[obj1->actionlist[i].idx]);
459 }
460 }
461
462 // Do the same for Obj2
463 for (size_t i = 0; i < obj2->actionlist.size(); i++)
464 {
465 if ((IsInSelection(obj2, obj2->actionlist[i].idx, tw2) != -1)
466 || obj2->actionlist[i].name == "head2chest"
467 || obj2->actionlist[i].name == "chest2leggings") {
468 ObjectAddAction(work, obj2->actionlist[i].name, obj2->actionlist[i].act,
469 obj2->actionlist[i].sfx, &obj2vertexlist2[obj2->actionlist[i].idx]);
470 }
471 }
472
473 // Recreate Vertex using Obj1 Vertexes
474 for (size_t i = 0; i < obj1->vertexlist.size(); i++)
475 {
476 if ((IsInSelection(obj1, i, iw1) != -1)
477 || (IsInSelection(obj1, i, jw1) != -1))
478 {
479 ObjectAddVertex(work, &obj1vertexlist2[i]);
480 }
481 }
482
483 // The same for Obj2
484 for (size_t i = 0; i < obj2->vertexlist.size(); i++)
485 {
486 if (IsInSelection(obj2, i, tw2) != -1)
487 {
488 ObjectAddVertex(work, &obj2vertexlist2[i]);
489 }
490 }
491
492
493 // Look in Faces for forgotten Vertexes... AND
494 // Re-Create TextureContainers Infos
495 // We look for texturecontainers included in the future tweaked object
496 TextureContainer * tc = NULL;
497
498 for (size_t i = 0; i < obj1->facelist.size(); i++)
499 {
500 if (((IsInSelection(obj1, obj1->facelist[i].vid[0], iw1) != -1)
501 || (IsInSelection(obj1, obj1->facelist[i].vid[0], jw1) != -1))
502 && ((IsInSelection(obj1, obj1->facelist[i].vid[1], iw1) != -1)
503 || (IsInSelection(obj1, obj1->facelist[i].vid[1], jw1) != -1))
504 && ((IsInSelection(obj1, obj1->facelist[i].vid[2], iw1) != -1)
505 || (IsInSelection(obj1, obj1->facelist[i].vid[2], jw1) != -1))
506 )
507 {
508
509 if (obj1->facelist[i].texid != -1)
510 if (tc != obj1->texturecontainer[obj1->facelist[i].texid])
511 {
512 tc = obj1->texturecontainer[obj1->facelist[i].texid];
513 ObjectAddMap(work, tc);
514 }
515
516 ObjectAddFace(work, &obj1->facelist[i], obj1);
517 }
518 }
519
520 for (size_t i = 0; i < obj2->facelist.size(); i++)
521 {
522 if ((IsInSelection(obj2, obj2->facelist[i].vid[0], tw2) != -1)
523 || (IsInSelection(obj2, obj2->facelist[i].vid[1], tw2) != -1)
524 || (IsInSelection(obj2, obj2->facelist[i].vid[2], tw2) != -1))
525 {
526
527 if (obj2->facelist[i].texid != -1)
528 if (tc != obj2->texturecontainer[obj2->facelist[i].texid])
529 {
530 tc = obj2->texturecontainer[obj2->facelist[i].texid];
531 ObjectAddMap(work, tc);
532 }
533
534 ObjectAddFace(work, &obj2->facelist[i], obj2);
535 }
536 }
537
538 // Recreate Groups
539 work->nbgroups = max(obj1->nbgroups, obj2->nbgroups);
540 work->grouplist = new EERIE_GROUPLIST[work->nbgroups];
541
542 for (long k = 0; k < obj1->nbgroups; k++)
543 {
544 work->grouplist[k].name = obj1->grouplist[k].name;
545 long v = GetEquivalentVertex(work, &obj1vertexlist2[obj1->grouplist[k].origin]);
546
547 if (v >= 0)
548 {
549 work->grouplist[k].siz = obj1->grouplist[k].siz;
550
551 if ((IsInSelection(obj1, obj1->grouplist[k].origin, iw1) != -1)
552 || (IsInSelection(obj1, obj1->grouplist[k].origin, jw1) != -1))
553 work->grouplist[k].origin = v;
554 }
555 }
556
557 for (int k = 0; k < obj2->nbgroups; k++)
558 {
559 if (k >= obj1->nbgroups)
560 {
561 work->grouplist[k].name = obj2->grouplist[k].name;
562
563 }
564
565 long v = GetEquivalentVertex(work, &obj2vertexlist2[obj2->grouplist[k].origin]);
566
567 if (v >= 0)
568 {
569 work->grouplist[k].siz = obj2->grouplist[k].siz;
570
571 if (IsInSelection(obj2, obj2->grouplist[k].origin, tw2) != -1)
572 work->grouplist[k].origin = v;
573 }
574 }
575
576 // Recreate Selection Groups (only the 3 selections needed to reiterate MeshTweaking !)
577 work->selections.resize(3);
578 work->selections[0].name = "head";
579 work->selections[1].name = "chest";
580 work->selections[2].name = "leggings";
581
582 // Re-Creating sel_head
583 if (tw == TWEAK_HEAD)
584 {
585 for(size_t l = 0; l < obj2->selections[sel_head2].selected.size(); l++) {
586 EERIE_VERTEX temp;
587 temp.v = obj2vertexlist2[obj2->selections[sel_head2].selected[l]].v;
588 long t = GetEquivalentVertex(work, &temp);
589
590 if (t != -1)
591 {
592 ObjectAddSelection(work, 0, t);
593 }
594 }
595 }
596 else for (size_t l = 0; l < obj1->selections[sel_head1].selected.size(); l++)
597 {
598 EERIE_VERTEX temp;
599 temp.v = obj1vertexlist2[obj1->selections[sel_head1].selected[l]].v;
600 long t = GetEquivalentVertex(work, &temp);
601
602 if (t != -1)
603 {
604 ObjectAddSelection(work, 0, t);
605 }
606 }
607
608 // Re-Create sel_torso
609 if (tw == TWEAK_TORSO)
610 {
611 for (size_t l = 0; l < obj2->selections[sel_torso2].selected.size(); l++)
612 {
613 EERIE_VERTEX temp;
614 temp.v = obj2vertexlist2[obj2->selections[sel_torso2].selected[l]].v;
615 long t = GetEquivalentVertex(work, &temp);
616
617 if (t != -1)
618 {
619 ObjectAddSelection(work, 1, t);
620 }
621 }
622 }
623 else for (size_t l = 0; l < obj1->selections[sel_torso1].selected.size(); l++)
624 {
625 EERIE_VERTEX temp;
626 temp.v = obj1vertexlist2[obj1->selections[sel_torso1].selected[l]].v;
627 long t = GetEquivalentVertex(work, &temp);
628
629 if (t != -1)
630 {
631 ObjectAddSelection(work, 1, t);
632 }
633 }
634
635 // Re-Create sel_legs
636 if (tw == TWEAK_LEGS)
637 {
638 for (size_t l = 0; l < obj2->selections[sel_legs2].selected.size(); l++)
639 {
640 EERIE_VERTEX temp;
641 temp.v = obj2vertexlist2[obj2->selections[sel_legs2].selected[l]].v;
642 long t = GetEquivalentVertex(work, &temp);
643
644 if (t != -1)
645 {
646 ObjectAddSelection(work, 2, t);
647 }
648 }
649 }
650 else for (size_t l = 0; l < obj1->selections[sel_legs1].selected.size(); l++)
651 {
652 EERIE_VERTEX temp;
653 temp.v = obj1vertexlist2[obj1->selections[sel_legs1].selected[l]].v;
654 long t = GetEquivalentVertex(work, &temp);
655
656 if (t != -1)
657 {
658 ObjectAddSelection(work, 2, t);
659 }
660 }
661
662 //Now recreates other selections...
663 for (size_t i = 0; i < obj1->selections.size(); i++) {
664
665 if (EERIE_OBJECT_GetSelection(work, obj1->selections[i].name) == -1)
666 {
667 long num = work->selections.size();
668 work->selections.resize(num + 1);
669 work->selections[num].name = obj1->selections[i].name;
670
671 for (size_t l = 0; l < obj1->selections[i].selected.size(); l++)
672 {
673 EERIE_VERTEX temp;
674 temp.v = obj1vertexlist2[obj1->selections[i].selected[l]].v;
675 long t = GetEquivalentVertex(work, &temp);
676
677 if (t != -1)
678 {
679 ObjectAddSelection(work, num, t);
680 }
681 }
682
683 long ii = EERIE_OBJECT_GetSelection(obj2, obj1->selections[i].name);
684
685 if (ii != -1)
686 for (size_t l = 0; l < obj2->selections[ii].selected.size(); l++)
687 {
688 EERIE_VERTEX temp;
689 temp.v = obj2vertexlist2[obj2->selections[ii].selected[l]].v;
690 long t = GetEquivalentVertex(work, &temp);
691
692 if (t != -1)
693 {
694 ObjectAddSelection(work, num, t);
695 }
696 }
697 }
698 }
699
700 for (size_t i = 0; i < obj2->selections.size(); i++) {
701
702 if (EERIE_OBJECT_GetSelection(work, obj2->selections[i].name) == -1)
703 {
704 long num = work->selections.size();
705 work->selections.resize(num + 1);
706 work->selections[num].name = obj2->selections[i].name;
707
708 for (size_t l = 0; l < obj2->selections[i].selected.size(); l++)
709 {
710 EERIE_VERTEX temp;
711 temp.v = obj2vertexlist2[obj2->selections[i].selected[l]].v;
712 long t = GetEquivalentVertex(work, &temp);
713
714 if (t != -1)
715 {
716 ObjectAddSelection(work, num, t);
717 }
718 }
719 }
720 }
721
722 // Recreate Animation-groups vertex
723 for (long i = 0; i < obj1->nbgroups; i++)
724 {
725 for (size_t j = 0; j < obj1->grouplist[i].indexes.size(); j++)
726 {
727 AddVertexToGroup(work, i, &obj1vertexlist2[obj1->grouplist[i].indexes[j]]);
728 }
729 }
730
731 for (long i = 0; i < obj2->nbgroups; i++)
732 {
733 for (size_t j = 0; j < obj2->grouplist[i].indexes.size(); j++)
734 {
735 AddVertexToGroup(work, i, &obj2vertexlist2[obj2->grouplist[i].indexes[j]]);
736 }
737 }
738
739 work->vertexlist3 = work->vertexlist;
740
741 return work;
742 }
743
EERIE_MESH_TWEAK_Do(Entity * io,TweakType tw,const res::path & path)744 void EERIE_MESH_TWEAK_Do(Entity * io, TweakType tw, const res::path & path) {
745
746 res::path ftl_file = ("game" / path).set_ext("ftl");
747
748 if ((!resources->getFile(ftl_file)) && (!resources->getFile(path))) return;
749
750 if (!tw) return;
751
752 if (io == NULL) return;
753
754 if (io->obj == NULL) return;
755
756 if(path.empty() && tw == TWEAK_REMOVE) {
757
758 if(io->tweaky) {
759 delete io->obj;
760 io->obj = io->tweaky;
761 EERIE_Object_Precompute_Fast_Access(io->obj);
762 io->tweaky = NULL;
763 }
764
765 return;
766 }
767
768 EERIE_3DOBJ * tobj = NULL;
769 EERIE_3DOBJ * result = NULL;
770 EERIE_3DOBJ * result2 = NULL;
771
772 {
773 tobj = loadObject(path);
774
775 if (!tobj) return;
776
777 switch (tw)
778 {
779 case (u32)TWEAK_HEAD | (u32)TWEAK_TORSO | (u32)TWEAK_LEGS:
780
781 if (!io->tweaky)
782 io->tweaky = io->obj;
783 else delete
784 io->obj;
785
786 io->obj = tobj;
787 return;
788 break;
789 case (u32)TWEAK_HEAD | (u32)TWEAK_TORSO:
790 result2 = CreateIntermediaryMesh(io->obj, tobj, TWEAK_HEAD);
791 result = CreateIntermediaryMesh(result2, tobj, TWEAK_TORSO);
792 delete result2;
793 break;
794 case (u32)TWEAK_TORSO | (u32)TWEAK_LEGS:
795 result2 = CreateIntermediaryMesh(io->obj, tobj, TWEAK_TORSO);
796 result = CreateIntermediaryMesh(result2, tobj, TWEAK_LEGS);
797 delete result2;
798 break;
799 case (u32)TWEAK_HEAD | (u32)TWEAK_LEGS:
800 result = CreateIntermediaryMesh(tobj, io->obj, TWEAK_TORSO);
801 break;
802 default:
803 result = CreateIntermediaryMesh(io->obj, tobj, tw);
804 break;
805 }
806
807 if(!result) {
808 delete tobj;
809 return;
810 }
811
812 result->pdata = NULL;
813 result->cdata = NULL;
814
815 if (io->tweaky == NULL) io->tweaky = io->obj;
816 else if (io->tweaky != io->obj)
817 delete io->obj;
818
819 io->obj = result;
820 EERIE_Object_Precompute_Fast_Access(io->obj);
821 }
822
823 EERIE_CreateCedricData(io->obj);
824
825 if (io)
826 {
827 io->lastanimtime = 0;
828 io->nb_lastanimvertex = 0;
829 }
830
831 delete tobj;
832 }
833