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