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