1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3
4 This file is part of Aquaria.
5
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program 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.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "../BBGE/MathFunctions.h"
22
23 #include "Hair.h"
24 #include "DSQ.h"
25
26 // nodes = 40
27 // segmentLength = 3
Hair(int nodes,float segmentLength,float hairWidth)28 Hair::Hair(int nodes, float segmentLength, float hairWidth) : RenderObject()
29 {
30 this->segmentLength = segmentLength;
31 this->hairWidth = hairWidth;
32
33 cull = false;
34
35 hairNodes.resize(nodes);
36 // nodes: 20 length: 6
37 //segmentLength = 3;
38 for (int i = 0; i < hairNodes.size(); i++)
39 {
40 float perc = (float(i)/(float(hairNodes.size())));
41 if (perc < 0)
42 perc = 0;
43 hairNodes[i].percent = 1.0f-perc;
44 hairNodes[i].position = hairNodes[i].originalPosition = hairNodes[i].defaultPosition = Vector(0, i*segmentLength, 0);
45 }
46 }
47
exertWave(float dt)48 void Hair::exertWave(float dt)
49 {
50 /*
51 Vector diff = headPos - position;
52 Vector diff2;
53 if (!isFlippedHorizontal())
54 diff2 = diff.getPerpendicularLeft();
55 else
56 diff2 = diff.getPerpendicularRight();
57
58 Vector diff3 = position - headPos;
59 float len =diff2.getLength2D();
60 diff3.setLength2D(len);
61
62 hairTimer += dt;
63 while (hairTimer > 2.0f)
64 {
65 hairTimer -= 2.0f;
66 }
67 float useTimer = hairTimer;
68 if (useTimer > 1.0f)
69 useTimer = 1.0f - (hairTimer-1);
70 float frc = 0.5;
71 diff = (diff2*(frc*(1.0f-(useTimer*0.5f))) + diff3*(frc);
72
73 diff.setLength2D(400);
74 //if (!vel.isLength2DIn(10))
75 exertForce(diff, dt);
76 */
77 }
78
exertGravityWave(float dt)79 void Hair::exertGravityWave(float dt)
80 {
81 /*
82 Vector diff = headPos - position;
83 Vector diff2;
84 if (!isFlippedHorizontal())
85 diff2 = diff.getPerpendicularLeft();
86 else
87 diff2 = diff.getPerpendicularRight();
88
89 Vector diff3 = position - headPos;
90 float len =diff2.getLength2D();
91 diff3.setLength2D(len);
92
93 hairTimer += dt;
94 while (hairTimer > 2.0f)
95 {
96 hairTimer -= 2.0f;
97 }
98 float useTimer = hairTimer;
99 if (useTimer > 1.0f)
100 useTimer = 1.0f - (hairTimer-1);
101 float frc = 0.333333;
102 diff = (diff2*(frc*(1.0f-(useTimer*0.5f))) + diff3*(frc) + Vector(0,len)*(frc*(0.5f+useTimer*0.5f)));
103
104 diff.setLength2D(400);
105 //if (!vel.isLength2DIn(10))
106 exertForce(diff, dt);
107 */
108 }
109
setHeadPosition(const Vector & vec)110 void Hair::setHeadPosition(const Vector &vec)
111 {
112 hairNodes[0].position = vec;
113 }
114
getHairNode(int idx)115 HairNode *Hair::getHairNode(int idx)
116 {
117 HairNode *h = 0;
118 int sz = hairNodes.size();
119 if (!(idx < 0 || idx >= sz))
120 {
121 h = &hairNodes[idx];
122 }
123 return h;
124 }
125
onRender()126 void Hair::onRender()
127 {
128 #ifdef BBGE_BUILD_OPENGL
129 //glDisable(GL_CULL_FACE);
130
131 glBegin(GL_QUAD_STRIP);
132 float texBits = 1.0f / (hairNodes.size()-1);
133 //float height2 = 2.5f;
134 Vector pl, pr;
135 for (int i = 0; i < hairNodes.size(); i++)
136 {
137 //glNormal3f( 0.0f, 0.0f, 1.0f);
138
139 if (i != hairNodes.size()-1)
140 {
141 Vector diffVec = hairNodes[i+1].position - hairNodes[i].position;
142 diffVec.setLength2D(hairWidth);
143 pl = diffVec.getPerpendicularLeft();
144 pr = diffVec.getPerpendicularRight();
145 }
146
147 /*
148 if (hairNodes[i].problem)
149 {
150 glColor3f(1,0,0);
151 }
152 else
153 glColor3f(1,1,1);
154 */
155
156
157 glTexCoord2f(0, texBits*i);
158 glVertex3f(hairNodes[i].position.x + pl.x, hairNodes[i].position.y + pl.y, 0);
159 glTexCoord2f(1, texBits*i);
160 glVertex3f( hairNodes[i].position.x + pr.x, hairNodes[i].position.y + pr.y, 0);
161
162 //float angle = 0;
163 /*
164 float angle = 0;
165 if (i < hairNodes.size()-1)
166 {
167 MathFunctions::calculateAngleBetweenVectorsInDegrees(hairNodes[i+1].position, hairNodes[i].position, angle);
168 angle += 90;
169 angle = (angle*PI)/180.0f;
170 }
171 */
172 /*
173 glTexCoord2f(0, 1-texBits*i);
174 glVertex3f(hairNodes[i].position.x -sinf(angle)*hairWidth, hairNodes[i].position.y + cosf(angle)*height2, 0);
175 glTexCoord2f(1, 1-texBits*i);
176 glVertex3f( hairNodes[i].position.x + sinf(angle)*hairWidth, hairNodes[i].position.y + cosf(angle)*height2, 0);
177 */
178 }
179 glEnd();
180
181 /*
182 glColor3f(1,1,1);
183 for (int i = 0; i < hairNodes.size(); i++)
184 {
185 std::ostringstream os;
186 os << hairNodes[i].angleDiff;
187 core->print(hairNodes[i].position.x, hairNodes[i].position.y, os.str().c_str(), 6);
188 }
189
190 */
191 //glEnable(GL_CULL_FACE);
192 #endif
193 }
194
onUpdate(float dt)195 void Hair::onUpdate(float dt)
196 {
197 RenderObject::onUpdate(dt);
198 /*
199 // straighten hair
200 if (hairNodes.size()>2)
201 {
202 Vector d1 = hairNodes[1].position - hairNodes[0].position;
203 for (int i = 2; i < hairNodes.size(); i++)
204 {
205 Vector d2 = hairNodes[i].position - hairNodes[i-1].position;
206
207 Vector wantPos = hairNodes[i-1].position + d1;
208
209 float perc = 1.0f-float(i)/float(hairNodes.size());
210 hairNodes[i].position += (wantPos - hairNodes[i].position)*dt*(40 * perc);
211 //Vector d1 = hairNodes[i-1].position - hairNodes[i-2].position;
212 //Vector d2 = hairNodes[i].position - hairNodes[i-1].position;
213 //float prod = d1.dot2D(d2);
214 ////if (prod < 0.5f)
215 //{
216 // d1.setLength2D(segmentLength);
217 //
218 // Vector wantPos = (hairNodes[i-1].position + d1)*0.5f + hairNodes[i].position*0.5f;
219 // hairNodes[i].position += (wantPos - hairNodes[i].position)*dt*10;
220 // break;
221 //}
222 }
223 }
224 */
225 }
226
updatePositions()227 void Hair::updatePositions()
228 {
229 BBGE_PROF(Hair_updatePositions);
230 //int minLength = 1;
231 /*
232 Vector accum;
233 for (int i = 1; i < hairNodes.size(); i++)
234 {
235 Vector diff = hairNodes[i].position - hairNodes[i-1].position;
236 accum += diff;
237 }
238 accum /= float(hairNodes.size()-1);
239 */
240 for (int i = 1; i < hairNodes.size(); i++)
241 {
242 Vector diff = hairNodes[i].position - hairNodes[i-1].position;
243 /*
244 if (diff.getLength2D() < 1)
245 {
246 diff = accum;
247 }
248 */
249 /*
250 if (diff.getLength2D() <= 1)
251 {
252 diff = hairNodes[i].position - hairNodes[0].position;
253 }
254 */
255
256 if (diff.getLength2D() < segmentLength)
257 {
258 diff.setLength2D(segmentLength);
259 hairNodes[i].position = hairNodes[i-1].position + diff;
260 }
261 else if (diff.getLength2D() > segmentLength)
262 {
263 //diff |= segmentLength;
264 diff.setLength2D(segmentLength);
265 hairNodes[i].position = hairNodes[i-1].position + diff;
266 }
267
268
269 /*
270 if (i > 1)
271 {
272 Vector d1 = hairNodes[i-1].position - hairNodes[i-2].position;
273 Vector d2 = hairNodes[i].position - hairNodes[i-1].position;
274 float prod = d1.dot2D(d2);
275 float a1 = 0, a2 = 0;
276 float maxAngle = 0.3;
277 MathFunctions::calculateAngleBetweenVectorsInRadians(d1, Vector(0,0,0), a1);
278 MathFunctions::calculateAngleBetweenVectorsInRadians(d2, Vector(0,0,0), a2);
279 float a = a2 - a1;
280 hairNodes[i].angleDiff = a;
281 if (fabsf(a) > maxAngle)
282 {
283
284 float len = d2.getLength2D();
285 //d2 = d1;
286 Vector dt1 = d1;
287 Vector dt2 = d1;
288 dt1.rotate2D(-maxAngle);
289 dt2.rotate2D(maxAngle);
290
291 //if (a < 0)
292 // d2.rotate2D(-maxAngle);
293 //else
294 // d2.rotate2D(maxAngle);
295
296 //d2.setLength2D(len);
297 //hairNodes[i].position = hairNodes[i-1].position + d2;
298
299 dt1 = hairNodes[i-1].position + dt1;
300 dt2 = hairNodes[i-1].position + dt2;
301 if ((hairNodes[i].position - dt1).getSquaredLength2D() < (hairNodes[i].position - dt2).getSquaredLength2D())
302 {
303 hairNodes[i].position = dt1;
304 }
305 else
306 hairNodes[i].position = dt2;
307 hairNodes[i].problem = true;
308 }
309 else
310 {
311 hairNodes[i].problem = false;
312 }
313 }
314 */
315
316 /*
317 int diffLength = segmentLength * 2;
318 Vector accum;
319 int c=0;
320 for (int j = 0; j < hairNodes.size(); j++)
321 {
322 if (j != i && j != i-1 && j != i+1)
323 {
324 Vector diff = hairNodes[i].position - hairNodes[j].position;
325
326 if (diff.getLength2D() < diffLength)
327 {
328 diff.setLength2D(diffLength);
329 //hairNodes[i].position = hairNodes[j].position + diff;
330 accum += hairNodes[j].position + diff;
331 c++;
332 //break;
333 }
334 }
335 }
336
337 if (!accum.isZero())
338 {
339 accum /= c;
340
341 //hairNodes[i].position = (hairNodes[i].position + accum)*0.5f;
342 hairNodes[i].position = accum;
343 }
344 */
345
346 /*
347 if (i > 1)
348 {
349 Vector d1 = hairNodes[i-1].position - hairNodes[i-2].position;
350 Vector d2 = hairNodes[i].position - hairNodes[i-1].position;
351 float prod = d1.dot2D(d2);
352 if (prod < -0.5f)
353 {
354 //d1.setLength2D(d2.getLength2D());
355 Vector wantPos = hairNodes[i-1].position + d1;
356 hairNodes[i].position = wantPos;//hairNodes[i].position*0.75f + wantPos*0.25f;
357 //
358 //d2 = (d2 + d1)*0.5f;
359 //hairNodes[i].position = hairNodes[i-1].position + d1;
360 }
361 }
362 */
363 /*
364 if (i > 1)
365 {
366 //float a1,a2;
367 float a1=0;
368 // MathFunctions::calculateAngleBetweenVectorsInRadians(hairNodes[i].position, hairNodes[i-1].position, a1);
369
370 MathFunctions::calculateAngleBetweenVectorsInRadians(hairNodes[i-1].position, hairNodes[i-2].position, a1);
371
372 Vector d1 = hairNodes[i-1].position - hairNodes[i-2].position;
373 Vector d2 = hairNodes[i].position - hairNodes[i-1].position;
374
375 float a=0;
376 MathFunctions::calculateAngleBetweenVectorsInRadians(d2, d1, a);
377 //float d = a2 - a1, c=PI/2;
378
379 float c=PI/2;
380 float d=0;
381
382 bool adjust = 0;
383 if (a > c)
384 {
385 d = a1 + c;
386 adjust = 1;
387 }
388 else if (a < -c)
389 {
390 d = a1 - c;
391 adjust = -1;
392 }
393 if (adjust)
394 {
395 Vector add(sinf(d), cosf(d));
396 add.setLength2D(d2.getLength2D());
397 hairNodes[i].position = hairNodes[i-1].position + add;
398 }
399 //Vector diff2 = hairNodes[i-1] - hairNodes[i-2].position;
400
401 //hairNodes[i].position = hairNodes[i-1].position + diff;
402 }
403 */
404 /*
405 if (i < hairNodes.size()-1)
406 {
407 Vector diff2 = hairNodes[i+1].position - hairNodes[i].position;
408 float a=0,c=PI/2;
409 bool adjust = false;
410 MathFunctions::calculateAngleBetweenVectorsInRadians(hairNodes[i+1].position, hairNodes[i].position, a);
411 if (a > c)
412 {
413 a = c;
414 adjust = true;
415 }
416 else if (a < -c)
417 {
418 a = -c;
419 adjust = true;
420 }
421 if (adjust)
422 {
423 Vector add(sinf(a), cosf(a));
424 add *= diff2.getLength2D();
425 hairNodes[i+1].position = hairNodes[i].position + add;
426 }
427 }
428 */
429 /*
430 else if (diff.getLength2D() < minLength)
431 {
432 */
433 /*
434 diff.setLength2D(minLength);
435 hairNodes[i].position = hairNodes[i-1].position + diff;
436 */
437 //}
438 }
439
440
441 }
442
returnToDefaultPositions(float dt)443 void Hair::returnToDefaultPositions(float dt)
444 {
445 for (int i = 0; i < hairNodes.size(); i++)
446 {
447 Vector mov = hairNodes[i].defaultPosition - hairNodes[i].position;
448 if (!mov.isLength2DIn(2))
449 {
450 if (mov.x != 0 || mov.y != 0)
451 {
452 mov *= dt;
453 hairNodes[i].position += mov;
454 }
455 }
456 }
457 }
458
exertForce(const Vector & force,float dt,int usePerc)459 void Hair::exertForce(const Vector &force, float dt, int usePerc)
460 {
461
462 for (int i = hairNodes.size()-1; i >= 1; i--)
463 {
464 switch (usePerc)
465 {
466 case 0:
467 hairNodes[i].position += force*dt*hairNodes[i].percent;
468 break;
469 case 1:
470 hairNodes[i].position += force*dt*(1.0f-hairNodes[i].percent);
471 break;
472 case 2:
473 default:
474 hairNodes[i].position += force*dt;
475 break;
476 }
477 /*
478 Vector diff = hairNodes[i].position - hairNodes[i-1].position;
479
480 if (diff.getSquaredLength2D() > sqr(segmentLength))
481 {
482 diff |= segmentLength;
483 hairNodes[i].position = hairNodes[i-1].position + diff;
484 }
485 */
486 }
487 }
488
489