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 ARKANE Studios SA. All rights reserved
46
47 #include "physics/Clothes.h"
48
49 #include <cstring>
50
51 #include "graphics/data/MeshManipulation.h"
52 #include "graphics/Math.h"
53
54 using std::vector;
55
56 #define MOLLESS_USEGRAVITY 1
57 #define MOLLESS_USEDAMPING 1
58 #define MOLLESS_DEFAULT_DAMPING 0.1f
59 #define SPHEREMUL 48.f;
60 #define MOLLESS_COLLISION_NONE 0
61 #define MOLLESS_COLLISION_PENETRATING 1
62 #define MOLLESS_COLLISION_COLLIDING 2
63
MOLLESS_Clear(EERIE_3DOBJ * obj,long flag)64 void MOLLESS_Clear(EERIE_3DOBJ * obj, long flag) {
65
66 if ((obj) && (obj->cdata)) {
67 for (long i = 0; i < obj->cdata->nb_cvert; i++) {
68 CLOTHESVERTEX * cv = &obj->cdata->cvert[i];
69 cv->velocity = Vec3f::ZERO;
70 cv->force = Vec3f::ZERO;
71 if(!(flag & 1)) {
72 cv->coll = -1;
73 cv->t_pos = cv->pos = obj->vertexlist[cv->idx].v;
74 } else {
75 cv->t_pos = cv->pos;
76 }
77 }
78 }
79 }
80
AddSpring(EERIE_3DOBJ * obj,short vert1,short vert2,float constant,float damping,long type)81 void AddSpring(EERIE_3DOBJ * obj, short vert1, short vert2, float constant, float damping, long type) {
82
83 if (vert1 == -1 || vert2 == -1 || vert1 == vert2) {
84 return;
85 }
86
87 for(vector<EERIE_SPRINGS>::const_iterator i = obj->cdata->springs.begin(); i < obj->cdata->springs.end(); ++i) {
88 if((i->startidx == vert1 && i->endidx == vert2) || (i->startidx == vert2 && i->endidx == vert1)) {
89 return;
90 }
91 }
92
93 EERIE_SPRINGS newSpring;
94 newSpring.startidx = vert1;
95 newSpring.endidx = vert2;
96 newSpring.restlength = dist(obj->cdata->cvert[vert1].pos, obj->cdata->cvert[vert2].pos);
97 newSpring.constant = constant;
98 newSpring.damping = damping;
99 newSpring.type = type;
100
101 obj->cdata->springs.push_back(newSpring);
102 }
103
GetIDXVert(EERIE_3DOBJ * obj,short num)104 short GetIDXVert(EERIE_3DOBJ * obj, short num)
105 {
106 for (short i = 0; i < obj->cdata->nb_cvert; i++)
107 {
108 if (obj->cdata->cvert[i].idx == num) return i;
109 }
110
111 return -1;
112 }
113
114 //*************************************************************************************
115 // Creates Clothes Data Structure for an object.
116 //*************************************************************************************
EERIEOBJECT_AddClothesData(EERIE_3DOBJ * obj)117 void EERIEOBJECT_AddClothesData(EERIE_3DOBJ * obj)
118 {
119 long sel = -1;
120 long selmounocol = -1;
121
122 for(size_t i = 0; i < obj->selections.size(); i++) { // TODO iterator
123 if(obj->selections[i].name == "mou") {
124 sel = i;
125 break;
126 }
127 }
128
129 for(size_t i = 0; i < obj->selections.size(); i++) { // TODO iterator
130 if(obj->selections[i].name == "mounocol") {
131 selmounocol = i;
132 break;
133 }
134 }
135
136 if (sel == -1) return;
137
138 if (obj->selections[sel].selected.size() > 0)
139 {
140 obj->cdata = new CLOTHES_DATA();
141
142 obj->cdata->nb_cvert = (short)obj->selections[sel].selected.size();
143 obj->cdata->cvert = new CLOTHESVERTEX[obj->cdata->nb_cvert];
144 memset(obj->cdata->cvert, 0, sizeof(CLOTHESVERTEX)*obj->cdata->nb_cvert);
145
146 obj->cdata->backup = new CLOTHESVERTEX[obj->cdata->nb_cvert];
147 memset(obj->cdata->backup, 0, sizeof(CLOTHESVERTEX)*obj->cdata->nb_cvert);
148 }
149
150
151 // There is a Mollesse (TM) (C) Selection
152 if (obj->selections[sel].selected.size() > 0)
153 {
154 for (int i = 0; i < obj->cdata->nb_cvert; i++)
155 {
156 obj->cdata->cvert[i].idx = (short)obj->selections[sel].selected[i];
157 obj->cdata->cvert[i].pos = obj->vertexlist[obj->cdata->cvert[i].idx].v;
158 obj->cdata->cvert[i].t_pos = obj->vertexlist[obj->cdata->cvert[i].idx].v;
159 obj->cdata->cvert[i].mass = 0.5f;
160
161 if ((selmounocol != -1) && (IsInSelection(obj, obj->selections[sel].selected[i], selmounocol) >= 0))
162 {
163
164 obj->cdata->cvert[i].flags = CLOTHES_FLAG_NORMAL | CLOTHES_FLAG_NOCOL;
165 }
166 else
167 obj->cdata->cvert[i].flags = CLOTHES_FLAG_NORMAL;
168
169 obj->cdata->cvert[i].coll = -1;
170 }
171
172 for (int i = 0; i < obj->cdata->nb_cvert; i++)
173 {
174
175 for (long j = 0; j < obj->ndata[obj->cdata->cvert[i].idx].nb_Nvertex; j++)
176 {
177 short vert = obj->ndata[obj->cdata->cvert[i].idx].Nvertex[j];
178
179 if (IsInSelection(obj, vert, sel) >= 0)
180 {
181 AddSpring(obj, (short)i, (short)GetIDXVert(obj, vert), 11.f, 0.3f, 0);
182 }
183 else
184 {
185 obj->cdata->cvert[i].flags |= CLOTHES_FLAG_FIX;
186 obj->cdata->cvert[i].coll = -2;
187 obj->cdata->cvert[i].mass = 0.f;
188 }
189 }
190 }
191
192 // Adds more springs (shear)
193 for (int i = 0; i < obj->cdata->nb_cvert; i++)
194 {
195 for (long j = 0; j < obj->ndata[obj->cdata->cvert[i].idx].nb_Nvertex; j++)
196 {
197 short vert = obj->ndata[obj->cdata->cvert[i].idx].Nvertex[j];
198
199 if (vert == obj->cdata->cvert[i].idx) continue; // Cannot add a spring between 1 node :p
200
201 if (IsInSelection(obj, vert, sel) >= 0)
202 {
203 float distance = distSqr(obj->vertexlist[obj->cdata->cvert[i].idx].v,
204 obj->vertexlist[vert].v) * square(1.2f);
205
206 // We springed it in the previous part of code
207 for (long k = 0; k < obj->ndata[vert].nb_Nvertex; k++)
208 {
209 short ver = obj->ndata[vert].Nvertex[k];
210
211 if (IsInSelection(obj, ver, sel) >= 0) // This time we have one !
212 {
213 if (ver == obj->cdata->cvert[i].idx) continue;
214 float distance2 = distSqr(obj->vertexlist[obj->cdata->cvert[i].idx].v,
215 obj->vertexlist[ver].v);
216
217 if (distance2 < distance)
218 {
219 AddSpring(obj, (short)i, (short)GetIDXVert(obj, ver), 4.2f, 0.7f, 1);
220 }
221 }
222 }
223 }
224 }
225 }
226
227 // Adds more springs (bend)
228 for (int i = 0; i < obj->cdata->nb_cvert; i++)
229 {
230 for (long j = 0; j < obj->ndata[obj->cdata->cvert[i].idx].nb_Nvertex; j++)
231 {
232 short vert = obj->ndata[obj->cdata->cvert[i].idx].Nvertex[j];
233
234 if (vert == obj->cdata->cvert[i].idx) continue; // Cannot add a spring between 1 node :p
235
236 if (IsInSelection(obj, vert, sel) >= 0)
237 {
238 // We springed it in the previous part of code
239 for (long k = 0; k < obj->ndata[vert].nb_Nvertex; k++)
240 {
241 short ver = obj->ndata[vert].Nvertex[k];
242
243 if (IsInSelection(obj, ver, sel) >= 0) // This time we have one !
244 {
245 float distance = distSqr(obj->vertexlist[obj->cdata->cvert[i].idx].v,
246 obj->vertexlist[ver].v) * square(1.2f);
247
248 for (long k2 = 0; k2 < obj->ndata[ver].nb_Nvertex; k2++)
249 {
250 short ve = obj->ndata[ver].Nvertex[k];
251
252 if (ve == vert) continue;
253
254 if (IsInSelection(obj, ve, sel) >= 0) // This time we have one !
255 {
256 if (obj->cdata->cvert[(short)GetIDXVert(obj, ve)].flags & CLOTHES_FLAG_FIX) continue;
257
258 float distance2 = distSqr(obj->vertexlist[obj->cdata->cvert[i].idx].v,
259 obj->vertexlist[ve].v);
260
261 if ((distance2 > distance) && (distance2 < distance * square(2.f)))
262 {
263 AddSpring(obj, (short)i, (short)GetIDXVert(obj, ve), 2.2f, 0.9f, 2);
264 }
265
266 }
267 }
268 }
269 }
270 }
271 }
272 }
273
274 }
275 }
276
KillClothesData(EERIE_3DOBJ * obj)277 void KillClothesData(EERIE_3DOBJ * obj) {
278
279 if(!obj || !obj->cdata) {
280 return;
281 }
282
283 delete[] obj->cdata->cvert, obj->cdata->cvert = NULL;
284 delete[] obj->cdata->backup, obj->cdata->backup = NULL;
285 delete obj->cdata, obj->cdata = NULL;
286 }
287