1 // I N C L U D E S ////////////////////////////////////////////////////////////
2 
3 #include <SDL.h>
4 #include <SDL_image.h>
5 #include <errno.h>
6 
7 #include "eye_candy.h"
8 #include "../platform.h"
9 #ifdef CLUSTER_INSIDES
10 #include "../cluster.h"
11 #endif
12 #include "../io/elfilewrapper.h"
13 #include "../textures.h"
14 #include "../load_gl_extensions.h"
15 #include "../weather.h"
16 
17 namespace ec
18 {
19 
20 	namespace
21 	{
22 
23 		const float scale_u = 1023.0f / (1024.0f * 1024.0f);
24 		const float scale_v = 511.0f / (512.0f * 512.0f);
25 		const float offset_u = 0.5f / 1024.0f;
26 		const float offset_v = 0.5f / 512.0f;
27 
28 		#include "eye_candy.tat"
29 
30 		#define BUILD_TEXTURE_COORDINATES(u, v, u_size, v_size)	\
31 			u, v, u + u_size, v, u + u_size, v + v_size, u, v + v_size,
32 
33 		#define BUILD_EYE_CANDY_TEXTURE_COORDINATES(index, img, name, x, y, w, h)	\
34 			BUILD_TEXTURE_COORDINATES(x * scale_u + offset_u, y * scale_v + offset_v, w * scale_u, h * scale_v)
35 
36 		const float texture_coordinates[] =
37 		{
38 			LIST_EYE_CANDY_ATLAS(BUILD_EYE_CANDY_TEXTURE_COORDINATES)
39 			0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f
40 		};
41 
get_texture_coordinates(const Uint32 texture,const Uint32 index)42 		const float* get_texture_coordinates(const Uint32 texture, const Uint32 index)
43 		{
44 			return &texture_coordinates[texture * 8 + index * 2];
45 		}
46 
get_texture_index(const TextureEnum type)47 		Uint32 get_texture_index(const TextureEnum type)
48 		{
49 			switch (type)
50 			{
51 				case EC_CRYSTAL:
52 					return randint(3);
53 				case EC_FLARE:
54 					return randint(3) + 3;
55 				case EC_INVERSE:
56 					return randint(4) + 6;
57 				case EC_SHIMMER:
58 					return randint(3) + 10;
59 				case EC_SIMPLE:
60 					return 13;
61 				case EC_TWINFLARE:
62 					return randint(5) + 14;
63 				case EC_VOID:
64 					return randint(3) + 19;
65 				case EC_WATER:
66 					return randint(4) + 22;
67 				case EC_LEAF_ASH:
68 					return 26;
69 				case EC_LEAF_MAPLE:
70 					return 27;
71 				case EC_LEAF_OAK:
72 					return 28;
73 				case EC_PETAL:
74 					return 29;
75 				case EC_SNOWFLAKE:
76 					return 30;
77 			}
78 
79 			return 31;
80 		}
81 
get_texture_coordinate(const float burn)82 		float get_texture_coordinate(const float burn)
83 		{
84 			return 0.25f + burn * 0.5f;
85 		}
86 
87 	}
88 
89 	// G L O B A L S //////////////////////////////////////////////////////////////
90 
91 	MathCache math_cache;
92 	std::vector<Obstruction*> null_obstructions;
93 	bool ec_error_status = false;
94 	Logger logger;
95 
96 	// C L A S S   F U N C T I O N S //////////////////////////////////////////////
97 
draw_particle(const coord_t size,const Uint32 texture,const color_t r,const color_t g,const color_t b,const alpha_t alpha,const Vec3 pos,const alpha_t burn)98 	void Effect::draw_particle(const coord_t size,
99 		const Uint32 texture, const color_t r, const color_t g,
100 		const color_t b, const alpha_t alpha, const Vec3 pos,
101 		const alpha_t burn)
102 	{
103 		Vec3 corner[4];
104 		Uint32 i, index;
105 
106 		corner[0] = Vec3(pos - base->corner_offset1 * size);
107 		corner[1] = Vec3(pos + base->corner_offset2 * size);
108 		corner[2] = Vec3(pos + base->corner_offset1 * size);
109 		corner[3] = Vec3(pos - base->corner_offset2 * size);
110 
111 		for (i = 0; i < 4; i++)
112 		{
113 			index = particle_count * 4 + i;
114 
115 			buffer[index * 10 + 0] = r;
116 			buffer[index * 10 + 1] = g;
117 			buffer[index * 10 + 2] = b;
118 			buffer[index * 10 + 3] = alpha;
119 			buffer[index * 10 + 4] = corner[i].x;
120 			buffer[index * 10 + 5] = corner[i].y;
121 			buffer[index * 10 + 6] = corner[i].z;
122 			buffer[index * 10 + 7] = get_texture_coordinates(texture, i)[0];
123 			buffer[index * 10 + 8] = get_texture_coordinates(texture, i)[1];
124 			buffer[index * 10 + 9] = get_texture_coordinate(burn);
125 		}
126 
127 		particle_count++;
128 	}
129 
build_particle_buffer(const Uint64 time_diff)130 	void Effect::build_particle_buffer(const Uint64 time_diff)
131 	{
132 		std::map<Particle*, bool>::const_iterator iter;
133 		const Vec3 center(base->center);
134 		Uint32 size;
135 
136 		particle_count = 0;
137 
138 		particle_max_count = particles.size() * (1 + motion_blur_points);
139 
140 		if (particle_max_count == 0)
141 		{
142 			return;
143 		}
144 
145 		particle_max_count = (particle_max_count + 0xF) & 0xFFFFFFF0;
146 		size = particle_max_count * 40 * sizeof(float);
147 
148 		if (particle_vertex_buffer.get_size() < size)
149 		{
150 			particle_vertex_buffer.bind(el::hbt_vertex);
151 
152 			particle_vertex_buffer.set_size(el::hbt_vertex, size,
153 				el::hbut_dynamic_draw);
154 		}
155 
156 		particle_vertex_buffer.bind(el::hbt_vertex);
157 
158 		buffer = static_cast<float*>(particle_vertex_buffer.map(
159 			el::hbt_vertex, el::hbat_write_only));
160 
161 		if (bounds)
162 		{
163 			for (const auto& iter: particles)
164 			{
165 				Particle* p = iter.first;
166 				const coord_t dist_squared = (p->pos - center).magnitude_squared();
167 				if (dist_squared < MAX_DRAW_DISTANCE_SQUARED)
168 					p->draw(time_diff);
169 			}
170 		}
171 		else
172 		{
173 			for (const auto& iter: particles)
174 			{
175 				Particle* p = iter.first;
176 				p->draw(time_diff);
177 			}
178 		}
179 
180 		particle_vertex_buffer.unmap(el::hbt_vertex);
181 	}
182 
draw_particle_buffer()183 	void Effect::draw_particle_buffer()
184 	{
185 		if (particle_count <= 0)
186 		{
187 			return;
188 		}
189 
190 		particle_vertex_buffer.bind(el::hbt_vertex);
191 
192 		glEnableClientState(GL_VERTEX_ARRAY);
193 		glEnableClientState(GL_COLOR_ARRAY);
194 
195 		glColorPointer(4, GL_FLOAT, 10 * sizeof(float), nullptr);
196 		glVertexPointer(3, GL_FLOAT, 10 * sizeof(float), reinterpret_cast<void*>(4 * sizeof(float)));
197 
198 		ELglClientActiveTextureARB(GL_TEXTURE0);
199 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
200 		glTexCoordPointer(2, GL_FLOAT, 10 * sizeof(float), reinterpret_cast<void*>(7 * sizeof(float)));
201 
202 		ELglClientActiveTextureARB(GL_TEXTURE1);
203 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
204 		glTexCoordPointer(1, GL_FLOAT, 10 * sizeof(float), reinterpret_cast<void*>(9 * sizeof(float)));
205 
206 		glDrawArrays(GL_QUADS, 0, particle_count * 4);
207 
208 		glDisableClientState(GL_VERTEX_ARRAY);
209 		glDisableClientState(GL_COLOR_ARRAY);
210 		ELglClientActiveTextureARB(GL_TEXTURE1);
211 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
212 		ELglClientActiveTextureARB(GL_TEXTURE0);
213 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
214 	}
215 
~Shape()216 	Shape::~Shape()
217 	{
218 	}
219 
draw()220 	void Shape::draw()
221 	{
222 		if (!base->draw_shapes)
223 			return;
224 
225 		glColor4f(color.x, color.y, color.z, alpha);
226 
227 		glPushMatrix();
228 		glTranslated(pos.x, pos.y, pos.z);
229 		base->set_shape_texture_combiner(1.0f);
230 
231 		vertex_buffer.bind(el::hbt_vertex);
232 		index_buffer.bind(el::hbt_index);
233 
234 		glEnableClientState(GL_VERTEX_ARRAY);
235 		glEnableClientState(GL_NORMAL_ARRAY);
236 
237 		ELglMultiTexCoord1f(GL_TEXTURE1, get_texture_coordinate(1.0f));
238 		glNormalPointer(GL_FLOAT, 3 * sizeof(float),
239 			reinterpret_cast<void*>(vertex_count * 3 * sizeof(float)));
240 		glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr);
241 
242 		glDrawElements(GL_TRIANGLES, facet_count * 3, GL_UNSIGNED_SHORT, 0);
243 
244 		glDisableClientState(GL_VERTEX_ARRAY);
245 		glDisableClientState(GL_NORMAL_ARRAY);
246 
247 		base->set_particle_texture_combiner();
248 		glPopMatrix();
249 	}
250 
CaplessCylinder(EyeCandy * _base,const Vec3 _start,const Vec3 _end,const Vec3 _color,const alpha_t _alpha,const coord_t _radius,const int polys)251 	CaplessCylinder::CaplessCylinder(EyeCandy* _base, const Vec3 _start,
252 		const Vec3 _end, const Vec3 _color, const alpha_t _alpha,
253 		const coord_t _radius, const int polys) :
254 		Shape(_base)
255 	{
256 		float* vertices;
257 		float* normals;
258 		GLushort* facets;
259 		Uint32 size;
260 		radius = _radius;
261 		start = _start;
262 		end = _end;
263 		orig_start = _start;
264 		orig_end = _end;
265 		pos = (start + end) / 2;
266 		start -= pos;
267 		end -= pos;
268 		color = _color;
269 		alpha = _alpha;
270 
271 		Vec3 normalized = start;
272 		normalized.normalize();
273 
274 		const int subdivisions = ((polys - 1) / 2) + 1;
275 		vertex_count = subdivisions * 2;
276 		if (vertex_count == 0)
277 		{
278 			return;
279 		}
280 
281 		size = 6 * sizeof(float) * vertex_count;
282 
283 		if (vertex_buffer.get_size() < size)
284 		{
285 			vertex_buffer.bind(el::hbt_vertex);
286 
287 			vertex_buffer.set_size(el::hbt_vertex, size,
288 				el::hbut_dynamic_draw);
289 		}
290 
291 		vertex_buffer.bind(el::hbt_vertex);
292 		vertices = static_cast<float*>(vertex_buffer.map(el::hbt_vertex,
293 			el::hbat_write_only));
294 		normals = &vertices[vertex_count * 3];
295 
296 		// Get the coordinates.
297 		const angle_t radian_increment = 2 * PI / subdivisions;
298 		int i = 0;
299 		for (angle_t rad = 0; rad < 2 * PI - 0.0001; rad += radian_increment,
300 			i++)
301 		{
302 			vertices[i * 3] = end.x + radius * (cos(rad) * normalized.z
303 				+ sin(rad) * normalized.y);
304 			vertices[i * 3 + 1] = end.y + radius * (cos(rad) * normalized.x
305 				+ sin(rad) * normalized.z);
306 			vertices[i * 3 + 2] = end.z + radius * (cos(rad) * normalized.y
307 				+ sin(rad) * normalized.x);
308 			normals[i * 3] = cos(rad) * normalized.z + sin(rad) * normalized.y;
309 			normals[i * 3 + 1] = cos(rad) * normalized.x + sin(rad)
310 				* normalized.z;
311 			normals[i * 3 + 2] = cos(rad) * normalized.y + sin(rad)
312 				* normalized.x;
313 			vertices[i * 3 + subdivisions * 3] = start.x + radius * (cos(rad
314 				- radian_increment / 2) * normalized.z + sin(rad
315 				- radian_increment / 2) * normalized.y);
316 			vertices[i * 3 + 1 + subdivisions * 3] = start.y + radius
317 				* (cos(rad - radian_increment / 2) * normalized.x + sin(rad
318 					- radian_increment / 2) * normalized.z);
319 			vertices[i * 3 + 2 + subdivisions * 3] = start.z + radius
320 				* (cos(rad - radian_increment / 2) * normalized.y + sin(rad
321 					- radian_increment / 2) * normalized.x);
322 			normals[i * 3 + subdivisions * 3] = cos(rad - radian_increment / 2)
323 				* normalized.z + sin(rad - radian_increment / 2) * normalized.y;
324 			normals[i * 3 + subdivisions * 3 + 1] = cos(rad - radian_increment
325 				/ 2) * normalized.x + sin(rad - radian_increment / 2)
326 				* normalized.z;
327 			normals[i * 3 + subdivisions * 3 + 2] = cos(rad - radian_increment
328 				/ 2) * normalized.y + sin(rad - radian_increment / 2)
329 				* normalized.x;
330 		}
331 
332 		vertex_buffer.unmap(el::hbt_vertex);
333 		vertex_buffer.unbind(el::hbt_vertex);
334 
335 		facet_count = subdivisions * 2;
336 		size = 3 * sizeof(GLushort) * facet_count;
337 
338 		if (index_buffer.get_size() < size)
339 		{
340 			index_buffer.bind(el::hbt_index);
341 
342 			index_buffer.set_size(el::hbt_index, size,
343 				el::hbut_dynamic_draw);
344 		}
345 
346 		index_buffer.bind(el::hbt_index);
347 		facets = static_cast<GLushort*>(index_buffer.map(el::hbt_index,
348 			el::hbat_write_only));
349 
350 		// Add in the sides.
351 		for (int i = 0; i < subdivisions; i++)
352 		{
353 			facets[i * 6] = i;
354 			facets[i * 6 + 1] = i + subdivisions;
355 			facets[i * 6 + 2] = i + subdivisions + 1;
356 			facets[i * 6 + 3] = i + subdivisions + 1;
357 			facets[i * 6 + 4] = i + 1;
358 			facets[i * 6 + 5] = i;
359 		}
360 
361 		// Wraparound.
362 		facets[(subdivisions - 1) * 6 + 2] = subdivisions;
363 		facets[(subdivisions - 1) * 6 + 3] = subdivisions;
364 		facets[(subdivisions - 1) * 6 + 4] = 0;
365 		index_buffer.unmap(el::hbt_index);
366 		index_buffer.unbind(el::hbt_index);
367 	}
368 
Cylinder(EyeCandy * _base,const Vec3 _start,const Vec3 _end,const Vec3 _color,const alpha_t _alpha,const coord_t _radius,const int polys)369 	Cylinder::Cylinder(EyeCandy* _base, const Vec3 _start, const Vec3 _end,
370 		const Vec3 _color, const alpha_t _alpha, const coord_t _radius,
371 		const int polys) :
372 		Shape(_base)
373 	{
374 		float* vertices;
375 		float* normals;
376 		GLushort* facets;
377 		Uint32 size;
378 		radius = _radius;
379 		start = _start;
380 		end = _end;
381 		orig_start = _start;
382 		orig_end = _end;
383 		pos = (start + end) / 2;
384 		start -= pos;
385 		end -= pos;
386 		color = _color;
387 		alpha = _alpha;
388 
389 		Vec3 normalized = start;
390 		normalized.normalize();
391 
392 		const int subdivisions = ((polys - 1) / 4) + 1;
393 		vertex_count = subdivisions * 4 + 2; //+2 is for the centerpoints of the caps.
394 		if (vertex_count == 0)
395 		{
396 			return;
397 		}
398 
399 		size = 6 * sizeof(float) * vertex_count;
400 
401 		if (vertex_buffer.get_size() < size)
402 		{
403 			vertex_buffer.bind(el::hbt_vertex);
404 
405 			vertex_buffer.set_size(el::hbt_vertex, size,
406 				el::hbut_dynamic_draw);
407 		}
408 
409 		vertex_buffer.bind(el::hbt_vertex);
410 		vertices = static_cast<float*>(vertex_buffer.map(el::hbt_vertex,
411 			el::hbat_write_only));
412 		normals = &vertices[vertex_count * 3];
413 
414 		// Get the coordinates.
415 		const angle_t radian_increment = 2 * PI / subdivisions;
416 		int i = 0;
417 		for (angle_t rad = 0; rad < 2 * PI - 0.0001; rad += radian_increment,
418 			i++)
419 		{
420 			vertices[i * 3] = end.x + radius * (cos(rad) * normalized.z
421 				+ sin(rad) * normalized.y);
422 			vertices[i * 3 + 1] = end.y + radius * (cos(rad) * normalized.x
423 				+ sin(rad) * normalized.z);
424 			vertices[i * 3 + 2] = end.z + radius * (cos(rad) * normalized.y
425 				+ sin(rad) * normalized.x);
426 			normals[i * 3] = normalized.x;
427 			normals[i * 3 + 1] = normalized.y;
428 			normals[i * 3 + 2] = normalized.z;
429 			vertices[i * 3 + subdivisions * 3] = start.x + radius * (cos(rad
430 				- radian_increment / 2) * normalized.z + sin(rad
431 				- radian_increment / 2) * normalized.y);
432 			vertices[i * 3 + 1 + subdivisions * 3] = start.y + radius
433 				* (cos(rad - radian_increment / 2) * normalized.x + sin(rad
434 					- radian_increment / 2) * normalized.z);
435 			vertices[i * 3 + 2 + subdivisions * 3] = start.z + radius
436 				* (cos(rad - radian_increment / 2) * normalized.y + sin(rad
437 					- radian_increment / 2) * normalized.x);
438 			normals[i * 3 + subdivisions * 3] = -normalized.x;
439 			normals[i * 3 + 1 + subdivisions * 3] = -normalized.y;
440 			normals[i * 3 + 2 + subdivisions * 3] = -normalized.z;
441 			vertices[i * 3 + subdivisions * 6] = vertices[i * 3];
442 			vertices[i * 3 + subdivisions * 6 + 1] = vertices[i * 3 + 1];
443 			vertices[i * 3 + subdivisions * 6 + 2] = vertices[i * 3 + 2];
444 			normals[i * 3 + subdivisions * 6] = cos(rad) * normalized.z
445 				+ sin(rad) * normalized.y;
446 			normals[i * 3 + subdivisions * 6 + 1] = cos(rad) * normalized.x
447 				+ sin(rad) * normalized.z;
448 			normals[i * 3 + subdivisions * 6 + 2] = cos(rad) * normalized.y
449 				+ sin(rad) * normalized.x;
450 			vertices[i * 3 + subdivisions * 9]
451 				= vertices[i * 3 + subdivisions * 3];
452 			vertices[i * 3 + subdivisions * 9 + 1]
453 				= vertices[i * 3 + subdivisions * 3 + 1];
454 			vertices[i * 3 + subdivisions * 9 + 2]
455 				= vertices[i * 3 + subdivisions * 3 + 2];
456 			normals[i * 3 + subdivisions * 9] = cos(rad - radian_increment / 2)
457 				* normalized.z + sin(rad - radian_increment / 2) * normalized.y;
458 			normals[i * 3 + subdivisions * 9 + 1] = cos(rad - radian_increment
459 				/ 2) * normalized.x + sin(rad - radian_increment / 2)
460 				* normalized.z;
461 			normals[i * 3 + subdivisions * 9 + 2] = cos(rad - radian_increment
462 				/ 2) * normalized.y + sin(rad - radian_increment / 2)
463 				* normalized.x;
464 		}
465 
466 		// Don't forget the centerpoints of the caps.
467 		vertices[subdivisions * 12] = end.x;
468 		vertices[subdivisions * 12 + 1] = end.y;
469 		vertices[subdivisions * 12 + 2] = end.z;
470 		normals[subdivisions * 12] = normalized.x;
471 		normals[subdivisions * 12 + 1] = normalized.y;
472 		normals[subdivisions * 12 + 2] = normalized.z;
473 		vertices[subdivisions * 12 + 3] = start.x;
474 		vertices[subdivisions * 12 + 4] = start.y;
475 		vertices[subdivisions * 12 + 5] = start.z;
476 		normals[subdivisions * 12 + 3] = -normalized.x;
477 		normals[subdivisions * 12 + 4] = -normalized.y;
478 		normals[subdivisions * 12 + 5] = -normalized.z;
479 
480 		vertex_buffer.unmap(el::hbt_vertex);
481 		vertex_buffer.unbind(el::hbt_vertex);
482 
483 		facet_count = subdivisions * 4;
484 		size = 3 * sizeof(GLushort) * facet_count;
485 
486 		if (index_buffer.get_size() < size)
487 		{
488 			index_buffer.bind(el::hbt_index);
489 
490 			index_buffer.set_size(el::hbt_index, size,
491 				el::hbut_dynamic_draw);
492 		}
493 
494 		index_buffer.bind(el::hbt_index);
495 		facets = static_cast<GLushort*>(index_buffer.map(el::hbt_index,
496 			el::hbat_write_only));
497 
498 		// First, add in the caps.
499 		for (int i = 0; i < subdivisions; i++)
500 		{
501 			facets[i * 3] = subdivisions * 4;
502 			facets[i * 3 + 1] = i;
503 			facets[i * 3 + 2] = i + 1;
504 			facets[i * 3 + subdivisions * 3] = subdivisions * 4 + 1;
505 			facets[i * 3 + 1 + subdivisions * 3] = i + subdivisions;
506 			facets[i * 3 + 2 + subdivisions * 3] = i + 1 + subdivisions;
507 		}
508 		// Wraparound.
509 		facets[(subdivisions - 1) * 3 + 2] = 0;
510 		facets[(subdivisions - 1) * 3 + 2 + subdivisions * 3] = subdivisions;
511 
512 		// Now, add in the sides.
513 		for (int i = 0; i < subdivisions; i++)
514 		{
515 			facets[subdivisions * 3 * 2 + i * 6] = i + subdivisions * 2;
516 			facets[subdivisions * 3 * 2 + i * 6 + 1] = i + subdivisions * 3;
517 			facets[subdivisions * 3 * 2 + i * 6 + 2] = i + subdivisions * 3 + 1;
518 			facets[subdivisions * 3 * 2 + i * 6 + 3] = i + subdivisions * 3 + 1;
519 			facets[subdivisions * 3 * 2 + i * 6 + 4] = i + subdivisions * 2 + 1;
520 			facets[subdivisions * 3 * 2 + i * 6 + 5] = i + subdivisions * 2;
521 		}
522 
523 		// Wraparound.
524 		facets[subdivisions * 3 * 2 + (subdivisions - 1) * 6 + 2] = subdivisions * 3;
525 		facets[subdivisions * 3 * 2 + (subdivisions - 1) * 6 + 3] = subdivisions * 3;
526 		facets[subdivisions * 3 * 2 + (subdivisions - 1) * 6 + 4] = subdivisions * 2;
527 		index_buffer.unmap(el::hbt_index);
528 		index_buffer.unbind(el::hbt_index);
529 	}
530 
Sphere(EyeCandy * _base,const Vec3 _pos,const Vec3 _color,const alpha_t _alpha,const coord_t _radius,const int polys)531 	Sphere::Sphere(EyeCandy* _base, const Vec3 _pos, const Vec3 _color,
532 		const alpha_t _alpha, const coord_t _radius, const int polys) :
533 		Shape(_base)
534 	{
535 		float* vertices;
536 		float* normals;
537 		GLushort* facets;
538 		Uint32 size;
539 		radius = _radius;
540 		pos = _pos;
541 		color = _color;
542 		alpha = _alpha;
543 
544 		// Start with an octahedron.
545 		typedef std::pair<angle_t, angle_t> SphericalCoord;
546 		std::vector<SphericalCoord> spherical_vertices;
547 
548 		spherical_vertices.push_back(SphericalCoord(0.0, 0.0));
549 		spherical_vertices.push_back(SphericalCoord(0.0, PI * 0.5));
550 		spherical_vertices.push_back(SphericalCoord(PI * 0.5, PI * 0.5));
551 		spherical_vertices.push_back(SphericalCoord(PI, PI * 0.5));
552 		spherical_vertices.push_back(SphericalCoord(PI * 1.5, PI * 0.5));
553 		spherical_vertices.push_back(SphericalCoord(0.0, PI));
554 
555 		std::vector<Facet> spherical_facets;
556 		spherical_facets.push_back(Facet(0, 1, 2));
557 		spherical_facets.push_back(Facet(0, 2, 3));
558 		spherical_facets.push_back(Facet(0, 3, 4));
559 		spherical_facets.push_back(Facet(0, 4, 1));
560 		spherical_facets.push_back(Facet(5, 1, 4));
561 		spherical_facets.push_back(Facet(5, 2, 1));
562 		spherical_facets.push_back(Facet(5, 3, 2));
563 		spherical_facets.push_back(Facet(5, 4, 3));
564 
565 		// Tesselate it until we've reached our subdivision limit.
566 		while ((int)spherical_facets.size() < polys)
567 		{
568 			std::vector<Facet> spherical_facets2;
569 			for (const auto& facet: spherical_facets)
570 			{
571 				const int p1_index = facet.f[0];
572 				const int p2_index = facet.f[1];
573 				const int p3_index = facet.f[2];
574 				const SphericalCoord p1(spherical_vertices[p1_index]);
575 				const SphericalCoord p2(spherical_vertices[p2_index]);
576 				const SphericalCoord p3(spherical_vertices[p3_index]);
577 				coord_t p4, q4;
578 				average_points(p1.first, p2.first, p1.second, p2.second, p4, q4);
579 				const int p4_index = (int)spherical_vertices.size();
580 				spherical_vertices.push_back(SphericalCoord(p4, q4));
581 				coord_t p5, q5;
582 				average_points(p2.first, p3.first, p2.second, p3.second, p5, q5);
583 				const int p5_index = (int)spherical_vertices.size();
584 				spherical_vertices.push_back(SphericalCoord(p5, q5));
585 				coord_t p6, q6;
586 				average_points(p3.first, p1.first, p3.second, p1.second, p6, q6);
587 				const int p6_index = (int)spherical_vertices.size();
588 				spherical_vertices.push_back(SphericalCoord(p6, q6));
589 				spherical_facets2.push_back(Facet(p1_index, p4_index, p6_index));
590 				spherical_facets2.push_back(Facet(p2_index, p5_index, p4_index));
591 				spherical_facets2.push_back(Facet(p3_index, p6_index, p5_index));
592 				spherical_facets2.push_back(Facet(p4_index, p5_index, p6_index));
593 			}
594 			spherical_facets = spherical_facets2;
595 		}
596 
597 		// Convert spherical to rectangular.
598 		vertex_count = (int)spherical_vertices.size();
599 		if (vertex_count == 0)
600 		{
601 			return;
602 		}
603 
604 		size = 6 * sizeof(float) * vertex_count;
605 
606 		if (vertex_buffer.get_size() < size)
607 		{
608 			vertex_buffer.bind(el::hbt_vertex);
609 
610 			vertex_buffer.set_size(el::hbt_vertex, size,
611 				el::hbut_dynamic_draw);
612 		}
613 
614 		vertex_buffer.bind(el::hbt_vertex);
615 		vertices = static_cast<float*>(vertex_buffer.map(el::hbt_vertex,
616 			el::hbat_write_only));
617 		normals = &vertices[vertex_count * 3];
618 
619 		for (int i = 0; i < vertex_count; i++)
620 		{
621 			const coord_t p = spherical_vertices[i].first;
622 			const coord_t q = spherical_vertices[i].second;
623 			normals[i * 3] = sin(p) * sin(q);
624 			normals[i * 3 + 1] = cos(q);
625 			normals[i * 3 + 2] = cos(p) * sin(q);
626 			vertices[i * 3] = normals[i * 3] * radius;
627 			vertices[i * 3 + 1] = normals[i * 3 + 1] * radius;
628 			vertices[i * 3 + 2] = normals[i * 3 + 2] * radius;
629 		}
630 		vertex_buffer.unmap(el::hbt_vertex);
631 		vertex_buffer.unbind(el::hbt_vertex);
632 
633 		// Convert facets to OpenGL-suitable array.
634 		facet_count = (int)spherical_facets.size();
635 		size = 3 * sizeof(GLushort) * facet_count;
636 
637 		if (index_buffer.get_size() < size)
638 		{
639 			index_buffer.bind(el::hbt_index);
640 
641 			index_buffer.set_size(el::hbt_index, size,
642 				el::hbut_dynamic_draw);
643 		}
644 
645 		index_buffer.bind(el::hbt_index);
646 		facets = static_cast<GLushort*>(index_buffer.map(el::hbt_index,
647 			el::hbat_write_only));
648 		for (int i = 0; i < facet_count; i++)
649 		{
650 			facets[i * 3] = spherical_facets[i].f[0];
651 			facets[i * 3 + 1] = spherical_facets[i].f[1];
652 			facets[i * 3 + 2] = spherical_facets[i].f[2];
653 		}
654 		index_buffer.unmap(el::hbt_index);
655 		index_buffer.unbind(el::hbt_index);
656 	}
657 
average_points(const coord_t p1_first,const coord_t p2_first,const coord_t p1_second,const coord_t p2_second,coord_t & p,coord_t & q)658 	void Sphere::average_points(const coord_t p1_first, const coord_t p2_first,
659 		const coord_t p1_second, const coord_t p2_second, coord_t& p, coord_t& q)
660 	{
661 		if ((fabs(p2_second) < 0.00001) || (fabs(p2_second - PI) < 0.00001))
662 			p = p1_first;
663 		else if ((fabs(p1_second) < 0.00001)
664 			|| (fabs(p1_second - PI) < 0.00001))
665 			p = p2_first;
666 		else if (fabs(p1_first - p2_first) > PI)
667 		{
668 			p = (p1_first + p2_first - 2 * PI) / 2;
669 			if (p < 0)
670 				p += 2 * PI;
671 		}
672 		else
673 			p = (p1_first + p2_first) / 2;
674 
675 		q = (p1_second + p2_second) / 2;
676 	}
677 
CaplessCylinders(EyeCandy * _base,const std::vector<CaplessCylinderItem> & items)678 	CaplessCylinders::CaplessCylinders(EyeCandy* _base,
679 		const std::vector<CaplessCylinderItem> &items)
680 	{
681 		CaplessCylindersVertex* vertices;
682 		GLushort* facets;
683 		Vec3 start, end, pos, color;
684 		float radius, alpha;
685 		Uint32 idx, count, face_index, vertex_index, size;
686 
687 		base = _base;
688 
689 		count = items.size();
690 
691 		vertex_count = 0;
692 		facet_count = 0;
693 
694 		for (idx = 0; idx < count; idx++)
695 		{
696 			const int subdivisions = ((items[idx].polys - 1) / 2) + 1;
697 			vertex_count += subdivisions * 2;
698 			facet_count += subdivisions * 2;
699 		}
700 
701 		if ((vertex_count == 0) || (facet_count == 0))
702 		{
703 			return;
704 		}
705 
706 		size = sizeof(CaplessCylindersVertex) * vertex_count;
707 
708 		if (vertex_buffer.get_size() < size)
709 		{
710 			vertex_buffer.bind(el::hbt_vertex);
711 
712 			vertex_buffer.set_size(el::hbt_vertex, size,
713 				el::hbut_dynamic_draw);
714 		}
715 
716 		vertex_buffer.bind(el::hbt_vertex);
717 		vertices = static_cast<CaplessCylindersVertex*>(vertex_buffer.map(el::hbt_vertex, el::hbat_write_only));
718 
719 		size = 3 * sizeof(GLushort) * facet_count;
720 
721 		if (index_buffer.get_size() < size)
722 		{
723 			index_buffer.bind(el::hbt_index);
724 
725 			index_buffer.set_size(el::hbt_index, size,
726 				el::hbut_dynamic_draw);
727 		}
728 
729 		index_buffer.bind(el::hbt_index);
730 		facets = static_cast<GLushort*>(index_buffer.map(el::hbt_index,
731 			el::hbat_write_only));
732 
733 		face_index = 0;
734 		vertex_index = 0;
735 
736 		for (idx = 0; idx < count; idx++)
737 		{
738 			radius = items[idx].radius;
739 			start = items[idx].start;
740 			end = items[idx].end;
741 			pos = (start + end) / 2;
742 			color = items[idx].color;
743 			alpha = items[idx].alpha;
744 
745 			Vec3 normalized = start - pos;
746 			normalized.normalize();
747 
748 			const int subdivisions = ((items[idx].polys - 1) / 2) + 1;
749 			vertex_count = subdivisions * 2;
750 
751 			// Get the coordinates.
752 			const angle_t radian_increment = 2 * PI / subdivisions;
753 			int i = 0;
754 			for (angle_t rad = 0; rad < 2 * PI - 0.0001;
755 				rad += radian_increment, i++)
756 			{
757 				vertices[vertex_index + i].r = static_cast<GLubyte>(color.x * 255.0f + 0.5f);
758 				vertices[vertex_index + i].g = static_cast<GLubyte>(color.y * 255.0f + 0.5f);
759 				vertices[vertex_index + i].b = static_cast<GLubyte>(color.z * 255.0f + 0.5f);
760 				vertices[vertex_index + i].a = static_cast<GLubyte>(alpha * 255.0f + 0.5f);
761 
762 				vertices[vertex_index + i].x = end.x + radius * (cos(rad) * normalized.z
763 					+ sin(rad) * normalized.y);
764 				vertices[vertex_index + i].y = end.y + radius * (cos(rad) * normalized.x
765 					+ sin(rad) * normalized.z);
766 				vertices[vertex_index + i].z = end.z + radius * (cos(rad) * normalized.y
767 					+ sin(rad) * normalized.x);
768 				vertices[vertex_index + i].nx = cos(rad) * normalized.z
769 					+ sin(rad) * normalized.y;
770 				vertices[vertex_index + i].ny = cos(rad) * normalized.x
771 					+ sin(rad) * normalized.z;
772 				vertices[vertex_index + i].nz = cos(rad) * normalized.y
773 					+ sin(rad) * normalized.x;
774 
775 				vertices[vertex_index + i + subdivisions].r = static_cast<GLubyte>(color.x * 255.0f + 0.5f);
776 				vertices[vertex_index + i + subdivisions].g = static_cast<GLubyte>(color.y * 255.0f + 0.5f);
777 				vertices[vertex_index + i + subdivisions].b = static_cast<GLubyte>(color.z * 255.0f + 0.5f);
778 				vertices[vertex_index + i + subdivisions].a = static_cast<GLubyte>(alpha * 255.0f + 0.5f);
779 
780 				vertices[vertex_index + i + subdivisions].x = start.x + radius * (cos(rad
781 					- radian_increment / 2) * normalized.z + sin(rad
782 					- radian_increment / 2) * normalized.y);
783 				vertices[vertex_index + i + subdivisions].y = start.y + radius
784 					* (cos(rad - radian_increment / 2) * normalized.x + sin(rad
785 						- radian_increment / 2) * normalized.z);
786 				vertices[vertex_index + i + subdivisions].z = start.z + radius
787 					* (cos(rad - radian_increment / 2) * normalized.y + sin(rad
788 						- radian_increment / 2) * normalized.x);
789 				vertices[vertex_index + i + subdivisions].nx = cos(rad - radian_increment / 2)
790 					* normalized.z + sin(rad - radian_increment / 2) * normalized.y;
791 				vertices[vertex_index + i + subdivisions].ny = cos(rad - radian_increment
792 					/ 2) * normalized.x + sin(rad - radian_increment / 2)
793 					* normalized.z;
794 				vertices[vertex_index + i + subdivisions].nz = cos(rad - radian_increment
795 					/ 2) * normalized.y + sin(rad - radian_increment / 2)
796 					* normalized.x;
797 			}
798 
799 			// Add in the sides.
800 			for (int i = 0; i < subdivisions; i++)
801 			{
802 				facets[(face_index + i) * 6] = vertex_index + i;
803 				facets[(face_index + i) * 6 + 1] = vertex_index + i + subdivisions;
804 				facets[(face_index + i) * 6 + 2] = vertex_index + i + subdivisions + 1;
805 				facets[(face_index + i) * 6 + 3] = vertex_index + i + subdivisions + 1;
806 				facets[(face_index + i) * 6 + 4] = vertex_index + i + 1;
807 				facets[(face_index + i) * 6 + 5] = vertex_index + i;
808 			}
809 
810 			// Wraparound.
811 			facets[(face_index + (subdivisions - 1)) * 6 + 2] = vertex_index + subdivisions;
812 			facets[(face_index + (subdivisions - 1)) * 6 + 3] = vertex_index + subdivisions;
813 			facets[(face_index + (subdivisions - 1)) * 6 + 4] = vertex_index + 0;
814 
815 			vertex_index += subdivisions * 2;
816 			face_index += subdivisions;
817 		}
818 
819 		vertex_buffer.unmap(el::hbt_vertex);
820 		vertex_buffer.unbind(el::hbt_vertex);
821 
822 		index_buffer.unmap(el::hbt_index);
823 		index_buffer.unbind(el::hbt_index);
824 	}
825 
draw(const float alpha_scale)826 	void CaplessCylinders::draw(const float alpha_scale)
827 	{
828 		if (!base->draw_shapes)
829 			return;
830 
831 		base->set_shape_texture_combiner(alpha_scale);
832 
833 		vertex_buffer.bind(el::hbt_vertex);
834 		index_buffer.bind(el::hbt_index);
835 
836 		glEnableClientState(GL_VERTEX_ARRAY);
837 		glEnableClientState(GL_NORMAL_ARRAY);
838 		glEnableClientState(GL_COLOR_ARRAY);
839 
840 		ELglMultiTexCoord1f(GL_TEXTURE1, get_texture_coordinate(1.0f));
841 		glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(CaplessCylindersVertex),
842 			reinterpret_cast<void*>(6 * sizeof(float)));
843 		glNormalPointer(GL_FLOAT, sizeof(CaplessCylindersVertex),
844 			reinterpret_cast<void*>(3 * sizeof(float)));
845 		glVertexPointer(3, GL_FLOAT, sizeof(CaplessCylindersVertex), nullptr);
846 
847 		glDrawElements(GL_TRIANGLES, facet_count * 3, GL_UNSIGNED_SHORT, 0);
848 
849 		glDisableClientState(GL_VERTEX_ARRAY);
850 		glDisableClientState(GL_NORMAL_ARRAY);
851 		glDisableClientState(GL_COLOR_ARRAY);
852 
853 		base->set_particle_texture_combiner();
854 	}
855 
Obstruction(const coord_t _max_distance,const coord_t _force)856 	Obstruction::Obstruction(const coord_t _max_distance, const coord_t _force)
857 	{
858 		max_distance = _max_distance;
859 		max_distance_squared = square(max_distance);
860 		force = _force;
861 	}
862 
get_force_gradient(Particle & p) const863 	Vec3 SimpleCylinderObstruction::get_force_gradient(Particle& p) const
864 	{ //Vertical cylinder, infinite height.
865 		const Vec3 translated_pos = p.pos - *(pos);
866 
867 		const coord_t distsquared= square(translated_pos.x) + square(translated_pos.z);
868 		if (distsquared < max_distance_squared)
869 		{
870 			p.pos -= p.velocity * (p.base->time_diff / 1000000.0) * 0.5;
871 			return translated_pos * (force / (distsquared + 0.0001));
872 		}
873 		else
874 			return Vec3(0.0, 0.0, 0.0);
875 	}
876 
get_force_gradient(Particle & p) const877 	Vec3 CappedSimpleCylinderObstruction::get_force_gradient(Particle& p) const
878 	{ //Vertical cylinder, infinite height.
879 		const Vec3 translated_pos = p.pos - *(pos);
880 
881 		if ((p.pos.y < bottom) || (p.pos.y > top))
882 			return Vec3(0.0, 0.0, 0.0);
883 
884 		const coord_t distsquared= square(translated_pos.x) + square(translated_pos.z);
885 		if (distsquared < max_distance_squared)
886 		{
887 			p.pos -= p.velocity * (p.base->time_diff / 1000000.0) * 0.5;
888 			return translated_pos * (force / (distsquared + 0.0001));
889 		}
890 		else
891 			return Vec3(0.0, 0.0, 0.0);
892 	}
893 
CylinderObstruction(Vec3 * _start,Vec3 * _end,const coord_t _max_distance,const coord_t _force)894 	CylinderObstruction::CylinderObstruction(Vec3* _start, Vec3* _end,
895 		const coord_t _max_distance, const coord_t _force) :
896 		Obstruction(_max_distance, _force)
897 	{
898 		start = _start;
899 		end = _end;
900 		length_vec = *end - *start; // Assume that this doesn't change.
901 		length_vec_mag = length_vec.magnitude();
902 	}
903 	;
904 
get_force_gradient(Particle & p) const905 	Vec3 CylinderObstruction::get_force_gradient(Particle& p) const
906 	{
907 		Vec3 v_offset;
908 		const Vec3 v1 = p.pos - *start;
909 		angle_t dotprod1;
910 		if ((dotprod1 = length_vec.dot(v1)) <= 0)
911 			v_offset = v1;
912 		else if (length_vec_mag <= dotprod1)
913 			v_offset = p.pos - *end;
914 		else
915 		{
916 			const coord_t scalar = dotprod1 / length_vec_mag;
917 			v_offset = *start + (length_vec * scalar);
918 		}
919 		const coord_t distsquared = v_offset.magnitude_squared();
920 
921 		if (distsquared < max_distance_squared)
922 		{
923 			p.pos -= p.velocity * (p.base->time_diff / 1000000.0) * 0.5;
924 			return v_offset * (force / (distsquared + 0.0001));
925 		}
926 		else
927 			return Vec3(0.0, 0.0, 0.0);
928 	}
929 
get_force_gradient(Particle & p) const930 	Vec3 SphereObstruction::get_force_gradient(Particle& p) const
931 	{
932 		const Vec3 translated_pos = p.pos - *(pos);
933 
934 		const coord_t distsquared= square(translated_pos.x) + square(translated_pos.y) + square(translated_pos.z);
935 		if (distsquared < square(max_distance))
936 		{
937 			p.pos -= p.velocity * (p.base->time_diff / 1000000.0) * 0.5;
938 			return translated_pos * (force / (distsquared + 0.0001));
939 		}
940 		else
941 			return Vec3(0.0, 0.0, 0.0);
942 	}
943 
get_force_gradient(Particle & p) const944 	Vec3 BoxObstruction::get_force_gradient(Particle& p) const
945 	{ // Arbitrary-rotation box.
946 		const Vec3 translated_pos = p.pos - *center;
947 
948 		// Is it anywhere close?
949 		const coord_t distsquared = translated_pos.planar_magnitude_squared();
950 		if (distsquared >= max_distance_squared)
951 			return Vec3(0.0, 0.0, 0.0); // Nope.
952 
953 		// So, it's close.  Is it actually bounded?
954 		const float s_rx = *sin_rot_x;
955 		const float c_rx = *cos_rot_x;
956 		const float s_ry = *sin_rot_y;
957 		const float c_ry = *cos_rot_y;
958 		const float s_rz = *sin_rot_z;
959 		const float c_rz = *cos_rot_z;
960 
961 		Vec3 roty_position;
962 		roty_position.x = translated_pos.z * s_ry + translated_pos.x * c_ry;
963 		roty_position.y = translated_pos.y;
964 		roty_position.z = translated_pos.z * c_ry - translated_pos.x * s_ry;
965 
966 		Vec3 rotx_position;
967 		rotx_position.x = roty_position.x;
968 		rotx_position.y = roty_position.y * c_rx - roty_position.z * s_rx;
969 		rotx_position.z = roty_position.y * s_rx + roty_position.z * c_rx;
970 
971 		Vec3 rotz_position;
972 		rotz_position.x = rotx_position.x * c_rz - rotx_position.y * s_rz;
973 		rotz_position.y = rotx_position.x * s_rz + rotx_position.y * c_rz;
974 		rotz_position.z = rotx_position.z;
975 
976 		//  std::cout << position << " | " << translated_pos << " | " << rotz_position << std::endl;
977 
978 		if ((rotz_position.x < start.x) || (rotz_position.y < start.y)
979 			|| (rotz_position.z < start.z) || (rotz_position.x > end.x)
980 			|| (rotz_position.y > end.y) || (rotz_position.z > end.z))
981 		{
982 			//    if ((start - end).magnitude_squared() > 60.0)
983 			//    {
984 			//      if (translated_pos.magnitude_squared() < 150.0)
985 			//    if ((center->x > 41.74) && (center->x < 41.75))
986 			//        std::cout << "B1: " << p.pos << ", " << translated_pos << ", " << rotz_position << ": " << start << ", " << end << ": " << Vec3(0.0, 0.0, 0.0) << std::endl;
987 			//    }
988 			/*
989 			 glColor4f(0.0, 1.0, 0.0, 1.0);
990 			 glBegin(GL_TRIANGLES);
991 			 glVertex3f(center->x, center->y, center->z);
992 			 glVertex3f(center->x, 0, center->z);
993 			 glVertex3f(p.pos.x, p.pos.y, p.pos.z);
994 			 glEnd();
995 
996 			 glColor4f(0.0, 0.0, 1.0, 0.2);
997 			 glBegin(GL_QUADS);
998 			 glVertex3f(start.x, start.y, start.z);
999 			 glVertex3f(end.x, start.y, start.z);
1000 			 glVertex3f(end.x, end.y, start.z);
1001 			 glVertex3f(start.x, end.y, start.z);
1002 			 glVertex3f(start.x, start.y, start.z);
1003 			 glVertex3f(end.x, start.y, start.z);
1004 			 glVertex3f(end.x, start.y, end.z);
1005 			 glVertex3f(start.x, start.y, end.z);
1006 			 glVertex3f(start.x, start.y, end.z);
1007 			 glVertex3f(start.x, end.y, end.z);
1008 			 glVertex3f(start.x, end.y, start.z);
1009 			 glVertex3f(start.x, start.y, start.z);
1010 			 glVertex3f(start.x, start.y, end.z);
1011 			 glVertex3f(end.x, start.y, end.z);
1012 			 glVertex3f(end.x, end.y, end.z);
1013 			 glVertex3f(start.x, end.y, end.z);
1014 			 glVertex3f(start.x, end.y, start.z);
1015 			 glVertex3f(end.x, end.y, start.z);
1016 			 glVertex3f(end.x, end.y, end.z);
1017 			 glVertex3f(start.x, end.y, end.z);
1018 			 glVertex3f(end.x, start.y, end.z);
1019 			 glVertex3f(end.x, end.y, end.z);
1020 			 glVertex3f(end.x, end.y, start.z);
1021 			 glVertex3f(end.x, start.y, start.z);
1022 			 glEnd();
1023 
1024 			 if (distsquared < 0.1)
1025 			 std::cout << p.pos << ", " << translated_pos << ", " << rotz_position << " : " << *center << " / " << start << ", " << end << std::endl;
1026 			 */
1027 			return Vec3(0.0, 0.0, 0.0);
1028 		}
1029 		else
1030 		{
1031 			p.pos -= p.velocity * (p.base->time_diff / 1000000.0) * 0.5;
1032 
1033 			Vec3 ret;
1034 			ret.x = 3 * force * (rotz_position.x - midpoint.x) / size.x;
1035 			ret.y = 3 * force * (rotz_position.y - start.y) / square(size.y + 0.7);
1036 			ret.z = 3 * force * (rotz_position.z - midpoint.z) / size.z;
1037 
1038 			const float s_rx2 = *sin_rot_x2;
1039 			const float c_rx2 = *cos_rot_x2;
1040 			const float s_ry2 = *sin_rot_y2;
1041 			const float c_ry2 = *cos_rot_y2;
1042 			const float s_rz2 = *sin_rot_z2;
1043 			const float c_rz2 = *cos_rot_z2;
1044 
1045 			Vec3 rotz_ret;
1046 			rotz_ret.x = ret.x * c_rz2 - ret.y * s_rz2;
1047 			rotz_ret.y = ret.x * s_rz2 + ret.y * c_rz2;
1048 			rotz_ret.z = ret.z;
1049 
1050 			Vec3 rotx_ret;
1051 			rotx_ret.x = rotz_ret.x;
1052 			rotx_ret.y = rotz_ret.y * c_rx2 - rotz_ret.z * s_rx2;
1053 			rotx_ret.z = rotz_ret.y * s_rx2 + rotz_ret.z * c_rx2;
1054 
1055 			Vec3 roty_ret;
1056 			roty_ret.x = rotx_ret.z * s_ry2 + rotx_ret.x * c_ry2;
1057 			roty_ret.y = rotx_ret.y;
1058 			roty_ret.z = rotx_ret.z * c_ry2 - rotx_ret.x * s_ry2;
1059 
1060 			//    if ((center->x > 41.74) && (center->x < 41.75))
1061 			//      std::cout << "B2: " << p.pos << ", " << translated_pos << ", " << rotz_position << ": " << (*center) << ": " << start << ", " << end << ": " << ret << ", " << roty_ret << std::endl;
1062 			/*
1063 			 glColor4f(1.0, 0.0, 0.0, 1.0);
1064 			 glBegin(GL_TRIANGLES);
1065 			 glVertex3f(center->x, center->y, center->z);
1066 			 glVertex3f(center->x, 0.2, center->z);
1067 			 glVertex3f(center->x + roty_ret.x, center->y + roty_ret.y, center->z + roty_ret.z);
1068 			 glEnd();
1069 			 */
1070 			return roty_ret;
1071 		}
1072 		// get rid of compiler warning, this code should never be reached
1073 		return Vec3(0.0, 0.0, 0.0);
1074 	}
1075 
PolarCoordElement(const coord_t _frequency,const coord_t _offset,const coord_t _scalar,const coord_t _power)1076 	PolarCoordElement::PolarCoordElement(const coord_t _frequency,
1077 		const coord_t _offset, const coord_t _scalar, const coord_t _power)
1078 	{
1079 		frequency = _frequency;
1080 		offset = _offset;
1081 		scalar = _scalar;
1082 		power = _power;
1083 	}
1084 
get_radius(const angle_t angle) const1085 	coord_t PolarCoordElement::get_radius(const angle_t angle) const
1086 	{
1087 		const angle_t temp_cos = cos((angle + offset) * frequency);
1088 		coord_t ret = std::pow(fabsf(temp_cos), power)
1089 			* scalar + scalar;
1090 		ret = copysign(ret, temp_cos);
1091 		return ret;
1092 	}
1093 
Particle(Effect * _effect,ParticleMover * _mover,const Vec3 _pos,const Vec3 _velocity,const coord_t _size)1094 	Particle::Particle(Effect* _effect, ParticleMover* _mover, const Vec3 _pos,
1095 		const Vec3 _velocity, const coord_t _size)
1096 	{
1097 		effect = _effect;
1098 		base = effect->base;
1099 		cur_motion_blur_point = 0;
1100 		motion_blur = new ParticleHistory[effect->motion_blur_points];
1101 		for (int i = 0; i < effect->motion_blur_points; i++)
1102 			motion_blur[i].alpha = 0;
1103 		mover = _mover;
1104 		pos = _pos;
1105 		velocity = _velocity;
1106 		energy = mover->calculate_energy(*this);
1107 		born = get_time();
1108 		mover->attachParticle(this);
1109 		size = _size;
1110 	}
1111 
~Particle()1112 	Particle::~Particle()
1113 	{
1114 		delete[] motion_blur;
1115 		if (mover)
1116 			mover->detachParticle(this);
1117 	}
1118 	;
1119 
draw(const Uint64 usec)1120 	void Particle::draw(const Uint64 usec)
1121 	{
1122 		alpha_t burn = get_burn();
1123 		alpha_t tempalpha = alpha;
1124 
1125 		coord_t tempsize = base->billboard_scalar * size;
1126 		tempsize *= flare();
1127 
1128 		assert(std::isfinite(burn));
1129 		assert(std::isfinite(tempalpha));
1130 		assert(std::isfinite(base->billboard_scalar));
1131 		assert(std::isfinite(size));
1132 		assert(std::isfinite(tempsize));
1133 
1134 		Uint32 texture = get_texture(); // Always hires, since we're not checking distance.
1135 
1136 		effect->draw_particle(tempsize, texture, color[0], color[1],
1137 			color[2], tempalpha, pos, burn);
1138 
1139 		if (effect->motion_blur_points > 0)
1140 		{
1141 			const alpha_t faderate = std::pow(
1142 				effect->motion_blur_fade_rate, (float)usec / 1000000);
1143 
1144 			for (int i = 0; i < effect->motion_blur_points; i++)
1145 				effect->draw_particle(motion_blur[i].size,
1146 					motion_blur[i].texture,
1147 					motion_blur[i].color[0],
1148 					motion_blur[i].color[1],
1149 					motion_blur[i].color[2],
1150 					motion_blur[i].alpha,
1151 					motion_blur[i].pos, burn);
1152 
1153 			motion_blur[cur_motion_blur_point] = ParticleHistory(
1154 				tempsize, texture, color[0], color[1], color[2],
1155 				alpha, pos);
1156 			cur_motion_blur_point++;
1157 
1158 			for (int i = 0; i < effect->motion_blur_points; i++)
1159 				motion_blur[i].alpha *= faderate;
1160 
1161 			if (cur_motion_blur_point == effect->motion_blur_points)
1162 				cur_motion_blur_point = 0;
1163 		}
1164 	}
1165 
flare() const1166 	coord_t Particle::flare() const
1167 	{
1168 		float exp_base, tmp;
1169 
1170 		assert(flare_frequency);
1171 
1172 		if (flare_max == 1.0)
1173 		{
1174 			return 1.0;
1175 		}
1176 
1177 #ifdef DEBUG_NANS
1178 		//  std::cout << "Beginning test." << std::endl;
1179 		if (!pos.is_valid())
1180 		std::cout << "ERROR: Invalid particle " << this << ": pos=" << pos << "; velocity=" << velocity << "; effect=" << effect << std::endl;
1181 #endif
1182 		assert(pos.is_valid());
1183 
1184 		const short offset = (short)uintptr_t(&alpha); //Unique to the particle.
1185 
1186 		tmp = offset;
1187 
1188 		if (pos.is_valid())
1189 		{
1190 			tmp += pos.x + pos.y + pos.z;
1191 		}
1192 
1193 		exp_base = fabs(sin(tmp / flare_frequency));
1194 
1195 		const coord_t exp = std::pow(exp_base, flare_exp);
1196 		const coord_t flare_val = 1.0 / (exp + 0.00001);
1197 		if (!std::isfinite(flare_val))
1198 			return 1.0;
1199 		else if (flare_val > flare_max)
1200 			return flare_max;
1201 		else
1202 			return flare_val;
1203 	}
1204 
ParticleMover(Effect * _effect)1205 	ParticleMover::ParticleMover(Effect* _effect)
1206 	{
1207 		effect = _effect;
1208 		base = effect->base;
1209 	}
1210 
vec_shift(const Vec3 src,const Vec3 dest,const percent_t percent) const1211 	Vec3 ParticleMover::vec_shift(const Vec3 src, const Vec3 dest,
1212 		const percent_t percent) const
1213 	{
1214 #if 0	// Slow but clear version.  Consider this a comment.
1215 		const coord_t magnitude = src.magnitude();
1216 		Vec3 ret = nonpreserving_vec_shift(src, dest, percent);
1217 		ret.normalize(magnitude);
1218 #else	// Fast but obfuscated
1219 		const coord_t magnitude_squared = src.magnitude_squared();
1220 		Vec3 ret = nonpreserving_vec_shift(src, dest, percent);
1221 		ret /= std::sqrt(ret.magnitude_squared() / magnitude_squared);
1222 #endif
1223 		return ret;
1224 	}
1225 
vec_shift_amount(const Vec3 src,const Vec3 dest,const coord_t amount) const1226 	Vec3 ParticleMover::vec_shift_amount(const Vec3 src, const Vec3 dest,
1227 		const coord_t amount) const
1228 	{
1229 		const Vec3 diff = dest - src;
1230 		const coord_t magnitude = diff.magnitude();
1231 		if (magnitude > amount)
1232 			return dest;
1233 		const percent_t percent = magnitude / amount;
1234 		return vec_shift(src, dest, percent);
1235 	}
1236 
nonpreserving_vec_shift(const Vec3 src,const Vec3 dest,const percent_t percent) const1237 	Vec3 ParticleMover::nonpreserving_vec_shift(const Vec3 src,
1238 		const Vec3 dest, const percent_t percent) const
1239 	{
1240 		return (dest - src) * percent + src * (1.0 - percent);
1241 	}
1242 
nonpreserving_vec_shift_amount(const Vec3 src,const Vec3 dest,const coord_t amount) const1243 	Vec3 ParticleMover::nonpreserving_vec_shift_amount(const Vec3 src,
1244 		const Vec3 dest, const coord_t amount) const
1245 	{
1246 		const Vec3 diff = dest - src;
1247 		const coord_t magnitude = diff.magnitude();
1248 		if (magnitude > amount)
1249 			return dest;
1250 		const percent_t percent = magnitude / amount;
1251 		return nonpreserving_vec_shift(src, dest, percent);
1252 	}
1253 
move(Particle & p,Uint64 usec)1254 	void GradientMover::move(Particle& p, Uint64 usec)
1255 	{
1256 		const coord_t scalar = usec / 1000000.0;
1257 		Vec3 gradient_velocity = p.velocity + get_force_gradient(p) * scalar;
1258 		if (gradient_velocity.magnitude_squared() > 10000.0)
1259 			gradient_velocity.normalize(100.0);
1260 		p.velocity = gradient_velocity + get_obstruction_gradient(p) * scalar;
1261 #if 0	// Slow but clear version.  Consider this a comment.
1262 		p.velocity.normalize(gradient_velocity.magnitude() + 0.000001);
1263 #else	// Fast but obfuscated
1264 		p.velocity /= std::sqrt(p.velocity.magnitude_squared() / (gradient_velocity.magnitude_squared() + 0.000001));
1265 #endif
1266 		p.pos += p.velocity * scalar;
1267 	}
1268 
get_force_gradient(Particle & p) const1269 	Vec3 GradientMover::get_force_gradient(Particle& p) const
1270 	{
1271 		return Vec3(0.0, 0.0, 0.0);
1272 	}
1273 
get_force_gradient(Particle & p) const1274 	Vec3 SmokeMover::get_force_gradient(Particle& p) const
1275 	{
1276 		return Vec3(0.0, 0.2 * strength, 0.0);
1277 	}
1278 
get_force_gradient(Particle & p) const1279 	Vec3 SpiralMover::get_force_gradient(Particle& p) const
1280 	{
1281 		Vec3 shifted_pos = p.pos - *center;
1282 		return Vec3(shifted_pos.z * spiral_speed - shifted_pos.x * pinch_rate,
1283 			0.0, shifted_pos.x * spiral_speed - shifted_pos.z * pinch_rate);
1284 	}
1285 
get_radius(const angle_t angle) const1286 	coord_t PolarCoordsBoundingRange::get_radius(const angle_t angle) const
1287 	{
1288 		float radius = 0.0;
1289 		for (const auto& elem: elements)
1290 			radius += elem.get_radius(angle);
1291 		return radius;
1292 	}
1293 
get_radius(const angle_t angle) const1294 	coord_t SmoothPolygonBoundingRange::get_radius(const angle_t angle) const
1295 	{
1296 		const float angle2 = (angle < 0 ? angle + 2 * PI : angle);
1297 		std::vector<SmoothPolygonElement>::const_iterator lower, upper;
1298 		lower = elements.begin() + (elements.size() - 1);
1299 		for (upper = elements.begin(); upper != elements.end(); ++upper)
1300 		{
1301 			if (upper->angle >= angle2)
1302 				break;
1303 			lower = upper;
1304 		}
1305 		if (upper == elements.end())
1306 			upper = elements.begin();
1307 		float upper_percent;
1308 		if (upper->angle > lower->angle)
1309 			upper_percent = (angle2 - lower->angle) / (upper->angle
1310 				- lower->angle);
1311 		else if (angle2 > lower->angle)
1312 			upper_percent = (angle2 - lower->angle) / (upper->angle + 2 * PI
1313 				- lower->angle);
1314 		else
1315 			upper_percent = (angle2 + 2 * PI - lower->angle) / (upper->angle
1316 				+ 2 * PI - lower->angle);
1317 		return upper_percent * upper->radius + (1.0 - upper_percent)
1318 			* lower->radius;
1319 	}
1320 
BoundingMover(Effect * _effect,const Vec3 _center_pos,BoundingRange * _bounding_range,const coord_t _force)1321 	BoundingMover::BoundingMover(Effect* _effect, const Vec3 _center_pos,
1322 		BoundingRange* _bounding_range, const coord_t _force) :
1323 		GradientMover(_effect)
1324 	{
1325 		center_pos = _center_pos;
1326 		bounding_range = _bounding_range;
1327 		force = _force;
1328 	}
1329 
get_force_gradient(Particle & p) const1330 	Vec3 BoundingMover::get_force_gradient(Particle& p) const
1331 	{
1332 		Vec3 shifted_pos = p.pos - center_pos;
1333 		const coord_t radius= std::sqrt(square(shifted_pos.x) + square(shifted_pos.z));
1334 		const angle_t angle = atan2(shifted_pos.x, shifted_pos.z);
1335 		const coord_t max_radius = bounding_range->get_radius(angle);
1336 		if (radius > max_radius)
1337 		{
1338 			const coord_t diff = (radius - max_radius) / radius;
1339 			return -shifted_pos * diff;
1340 		}
1341 		else
1342 			return Vec3(0.0, 0.0, 0.0);
1343 	}
1344 
get_force_gradient(Particle & p) const1345 	Vec3 SimpleGravityMover::get_force_gradient(Particle& p) const
1346 	{
1347 		return Vec3(0.0, -1.6, 0.0);
1348 	}
1349 
get_obstruction_gradient(Particle & p) const1350 	Vec3 GradientMover::get_obstruction_gradient(Particle& p) const
1351 	{ //Unlike normal force gradients, obstruction gradients are used in a magnitude-preserving fashion.
1352 		Vec3 ret(0.0, 0.0, 0.0);
1353 		for (auto obstruction: *effect->obstructions)
1354 			ret += obstruction->get_force_gradient(p);
1355 		return ret;
1356 	}
1357 
GravityMover(Effect * _effect,Vec3 * _center)1358 	GravityMover::GravityMover(Effect* _effect, Vec3* _center) :
1359 		GradientMover(_effect)
1360 	{
1361 		mass = 2e10;
1362 		max_gravity = 20.0;
1363 		gravity_center_ptr = _center;
1364 		gravity_center = *gravity_center_ptr;
1365 		old_gravity_center = gravity_center;
1366 	}
1367 
GravityMover(Effect * _effect,Vec3 * _center,const energy_t _mass)1368 	GravityMover::GravityMover(Effect* _effect, Vec3* _center,
1369 		const energy_t _mass) :
1370 		GradientMover(_effect)
1371 	{
1372 		mass = _mass;
1373 		max_gravity = mass / 1e9;
1374 		gravity_center_ptr = _center;
1375 		gravity_center = *gravity_center_ptr;
1376 		old_gravity_center = gravity_center;
1377 	}
1378 
set_gravity_center(Vec3 * _gravity_center)1379 	void GravityMover::set_gravity_center(Vec3* _gravity_center)
1380 	{
1381 		gravity_center_ptr = _gravity_center;
1382 	}
1383 
move(Particle & p,Uint64 usec)1384 	void GravityMover::move(Particle& p, Uint64 usec)
1385 	{
1386 		old_gravity_center = gravity_center;
1387 		gravity_center = *gravity_center_ptr;
1388 
1389 		if (usec >= base->max_usec_per_particle_move)
1390 			usec = base->max_usec_per_particle_move;
1391 
1392 		const coord_t dist = gravity_dist(p, gravity_center);
1393 		if (gravity_center != old_gravity_center)
1394 		{
1395 			const coord_t old_dist = gravity_dist(p, old_gravity_center);
1396 			p.energy += G * mass * (dist - old_dist);
1397 		}
1398 		Vec3 gravity_vec(gravity_center.x - p.pos.x,
1399 			gravity_center.y - p.pos.y, gravity_center.z - p.pos.z);
1400 
1401 		// Simulated point gravity sources tend to promote extreme forces that, even if you fix the energy balance, will throw off angles.  Cancel them out.
1402 		energy_t scalar = G * mass / square(dist) + 0.00001;
1403 
1404 		scalar = std::min(scalar, max_gravity);
1405 		gravity_vec.normalize(scalar);
1406 		p.pos += p.velocity * ((coord_t)usec / 1000000.0);
1407 		p.velocity += gravity_vec * ((coord_t)usec / 1000000.0);
1408 
1409 		// Simulated point gravity sources tend to create/destroy energy when a particle passes near the center.  Cancel it out.
1410 		const energy_t velocity_energy = calculate_velocity_energy(p);
1411 		const energy_t new_energy = G * mass * dist + velocity_energy;
1412 		const energy_t energy_difference = p.energy - new_energy;
1413 		const energy_t new_velocity_energy = velocity_energy
1414 			+ energy_difference;
1415 		if (new_velocity_energy >= 0)
1416 		{
1417 #if 0	// Slow but clear.  Consider this a comment.
1418 			const coord_t new_velocity = std::sqrt(2.0 * new_velocity_energy);
1419 			if (new_velocity)
1420 			p.velocity.normalize(new_velocity + 0.000001);
1421 			else
1422 			p.velocity = Vec3(0.0, 0.0, 0.0);
1423 #else	// Fast but obfuscated
1424 			const coord_t new_velocity_squared = 2.0 * new_velocity_energy;
1425 			if (std::abs(new_velocity_squared) > 0.00001)
1426 				p.velocity /= std::sqrt(p.velocity.magnitude_squared() / new_velocity_squared + 0.000001);
1427 			else
1428 				p.velocity = Vec3(0.0, 0.0, 1.0);
1429 #endif
1430 		}
1431 
1432 		// Factor in the force gradient, if any.
1433 		Vec3 gradient_velocity = p.velocity + get_force_gradient(p);
1434 		Vec3 obstruction_velocity = gradient_velocity
1435 			+ get_obstruction_gradient(p);
1436 		const coord_t grad_mag_squared = gradient_velocity.magnitude_squared();
1437 #if 0	// Slow but clear.  Consider this a comment.
1438 		if (grad_mag_squared)
1439 		obstruction_velocity.normalize(gradient_velocity.magnitude() + 0.00001);
1440 		else
1441 		obstruction_velocity = Vec3(0.0, 0.0, 0.0);
1442 #else	// Fast but obfuscated.
1443 		if (std::abs(grad_mag_squared) > 0.00001)
1444 			obstruction_velocity /= std::sqrt(obstruction_velocity.magnitude_squared() / (grad_mag_squared + 0.00001) + 0.00001);
1445 		else
1446 			obstruction_velocity = Vec3(0.0, 0.0, 1.0);
1447 #endif
1448 		const coord_t obstruction_velocity_energy = 0.5
1449 			* obstruction_velocity.magnitude_squared();
1450 		p.energy += obstruction_velocity_energy - new_velocity_energy;
1451 		p.velocity = obstruction_velocity;
1452 	}
1453 
calculate_velocity_energy(const Particle & p) const1454 	energy_t GravityMover::calculate_velocity_energy(const Particle& p) const
1455 	{
1456 		return 0.5 * p.velocity.magnitude_squared();
1457 	}
1458 
calculate_position_energy(const Particle & p) const1459 	energy_t GravityMover::calculate_position_energy(const Particle& p) const
1460 	{
1461 		return G * mass * gravity_dist(p, gravity_center);
1462 	}
1463 
gravity_dist(const Particle & p,const Vec3 & center) const1464 	coord_t GravityMover::gravity_dist(const Particle& p, const Vec3& center) const
1465 	{
1466 		return std::sqrt(square(p.pos.x - center.x) + square(p.pos.y - center.y) + square(p.pos.z - center.z));
1467 	}
1468 
calculate_energy(const Particle & p) const1469 	energy_t GravityMover::calculate_energy(const Particle& p) const
1470 	{
1471 		return calculate_velocity_energy(p) + calculate_position_energy(p);
1472 	}
1473 
get_new_coords(const Vec3 & pos)1474 	Vec3 IFSLinearElement::get_new_coords(const Vec3& pos)
1475 	{
1476 		return (pos * inv_scale) + (center * scale);
1477 	}
1478 
get_new_coords(const Vec3 & pos)1479 	Vec3 IFSSinusoidalElement::get_new_coords(const Vec3& pos)
1480 	{
1481 		const Vec3 result(sin(pos.x * scalar.x + offset.x) * scalar2.x,
1482 			sin(pos.y * scalar.y + offset.y) * scalar2.y, sin(pos.z * scalar.z
1483 				+ offset.z) * scalar2.z);
1484 		return (pos * inv_scale) + (result * scale);
1485 	}
1486 
get_new_coords(const Vec3 & pos)1487 	Vec3 IFSSphericalElement::get_new_coords(const Vec3& pos)
1488 	{
1489 		const coord_t r = pos.magnitude();
1490 		const Vec3 result((pos.x + numerator_adjust.x) / (r
1491 			+ denominator_adjust.x), (pos.y + numerator_adjust.y) / (r
1492 			+ denominator_adjust.y), (pos.z + numerator_adjust.z) / (r
1493 			+ denominator_adjust.z));
1494 		return (pos * inv_scale) + (result * scale);
1495 	}
1496 
get_new_coords(const Vec3 & pos)1497 	Vec3 IFSRingElement::get_new_coords(const Vec3& pos)
1498 	{
1499 		const coord_t r= std::sqrt(square(pos.x) + square(pos.z));
1500 		const Vec3 result((pos.x + numerator_adjust.x) / (r
1501 			+ denominator_adjust.x), 0.0, (pos.z + numerator_adjust.z) / (r
1502 			+ denominator_adjust.z));
1503 		return (pos * inv_scale) + (result * scale);
1504 	}
1505 
get_new_coords(const Vec3 & pos)1506 	Vec3 IFSSwirlElement::get_new_coords(const Vec3& pos)
1507 	{
1508 		const coord_t r = pos.magnitude();
1509 		const angle_t theta_x = atan2(pos.z, pos.y);
1510 		const angle_t theta_y = atan2(pos.x, pos.z);
1511 		const angle_t theta_z = atan2(pos.y, pos.x);
1512 		const Vec3 result(r * cos(theta_x + r), r * cos(theta_y + r), r
1513 			* cos(theta_z + r));
1514 		return (pos * inv_scale) + (result * scale);
1515 	}
1516 
get_new_coords(const Vec3 & pos)1517 	Vec3 IFS2DSwirlElement::get_new_coords(const Vec3& pos)
1518 	{
1519 		const coord_t r= std::sqrt(square(pos.x) + square(pos.z));
1520 		const angle_t theta_x = atan(pos.z);
1521 		const angle_t theta_z = atan(pos.x);
1522 		const Vec3 result(r * cos(theta_x + r), 0.0, r * cos(theta_z + r));
1523 		return (pos * inv_scale) + (result * scale);
1524 	}
1525 
get_new_coords(const Vec3 & pos)1526 	Vec3 IFSHorseshoeElement::get_new_coords(const Vec3& pos)
1527 	{
1528 		const coord_t r = pos.magnitude();
1529 		const angle_t theta_x = atan2(pos.z, pos.y + 0.0000001f);
1530 		const angle_t theta_y = atan2(pos.x, pos.z + 0.0000001f);
1531 		const angle_t theta_z = atan2(pos.y, pos.x + 0.0000001f);
1532 		const Vec3 result(r * cos(2 * theta_x), r * cos(2 * theta_y), r * cos(2 * theta_z));
1533 		return (pos * inv_scale) + (result * scale);
1534 	}
1535 
get_new_coords(const Vec3 & pos)1536 	Vec3 IFS2DHorseshoeElement::get_new_coords(const Vec3& pos)
1537 	{
1538 		const coord_t r = pos.magnitude();
1539 		const angle_t theta_x = atan(pos.z);
1540 		const angle_t theta_z = atan(pos.y);
1541 		const Vec3 result(r * cos(2 * theta_x), 0.0, r * cos(2 * theta_z));
1542 		return (pos * inv_scale) + (result * scale);
1543 	}
1544 
IFSParticleSpawner(const int count,const coord_t size)1545 	IFSParticleSpawner::IFSParticleSpawner(const int count, const coord_t size)
1546 	{
1547 		generate(count, Vec3(size, size, size));
1548 		pos = Vec3(0.0, 0.0, 0.0);
1549 	}
1550 
IFSParticleSpawner(const int count,const Vec3 scale)1551 	IFSParticleSpawner::IFSParticleSpawner(const int count, const Vec3 scale)
1552 	{
1553 		generate(count, scale);
1554 		pos = Vec3(0.0, 0.0, 0.0);
1555 	}
1556 
~IFSParticleSpawner()1557 	IFSParticleSpawner::~IFSParticleSpawner()
1558 	{
1559 		for (auto elem: ifs_elements)
1560 			delete elem;
1561 	}
1562 
generate(const int count,const Vec3 scale)1563 	void IFSParticleSpawner::generate(const int count, const Vec3 scale)
1564 	{
1565 		for (int i = 0; i < count; i++)
1566 		{
1567 			Vec3 v;
1568 			v.randomize();
1569 			v.x *= scale.x;
1570 			v.y *= scale.y;
1571 			v.z *= scale.z;
1572 			ifs_elements.push_back(new IFSLinearElement(v, randcoord()));
1573 		}
1574 	}
1575 
get_new_coords()1576 	Vec3 IFSParticleSpawner::get_new_coords()
1577 	{
1578 		pos = ifs_elements[randint((int)ifs_elements.size())]->get_new_coords(pos);
1579 		if (!pos.is_valid())
1580 			pos = Vec3(0.0, 0.0, 0.0);
1581 		return pos;
1582 	}
1583 
get_new_coords()1584 	Vec3 FilledSphereSpawner::get_new_coords()
1585 	{
1586 		Vec3 ret;
1587 		ret.randomize();
1588 		ret *= randcoord_non_zero() * radius;
1589 		return ret;
1590 	}
1591 
get_new_coords()1592 	Vec3 FilledEllipsoidSpawner::get_new_coords()
1593 	{
1594 		Vec3 ret;
1595 		ret.randomize();
1596 		ret *= randcoord_non_zero();
1597 		ret.x *= radius.x;
1598 		ret.y *= radius.y;
1599 		ret.z *= radius.z;
1600 
1601 		return ret;
1602 	}
1603 
get_new_coords()1604 	Vec3 HollowSphereSpawner::get_new_coords()
1605 	{
1606 		Vec3 ret;
1607 		ret.randomize();
1608 		ret *= radius;
1609 
1610 		return ret;
1611 	}
1612 
get_new_coords()1613 	Vec3 HollowEllipsoidSpawner::get_new_coords()
1614 	{
1615 		Vec3 ret;
1616 		ret.randomize();
1617 		ret.x *= radius.x;
1618 		ret.y *= radius.y;
1619 		ret.z *= radius.z;
1620 
1621 		return ret;
1622 	}
1623 
get_new_coords()1624 	Vec3 FilledDiscSpawner::get_new_coords()
1625 	{
1626 		const angle_t angle= randangle(2 * PI);
1627 		const coord_t scale = (1.0 - square(randcoord())) * radius;
1628 		const Vec3 ret(scale * sin(angle), 0.0, scale * cos(angle));
1629 		return ret;
1630 	}
1631 
get_new_coords()1632 	Vec3 HollowDiscSpawner::get_new_coords()
1633 	{
1634 		const angle_t angle= randangle(2 * PI);
1635 		const Vec3 ret(radius * sin(angle), 0.0, radius * cos(angle));
1636 		return ret;
1637 	}
1638 
get_new_coords()1639 	Vec3 FilledBoundingSpawner::get_new_coords()
1640 	{
1641 		Vec3 cur_pos;
1642 		const Vec3 camera_center_difference = *center - *base_center;
1643 		//  int i;
1644 		//  for (i = 0; i < 30; i++)
1645 		{
1646 			const angle_t angle= randangle(2 * PI);
1647 			const coord_t scalar= randcoord() * MAX_DRAW_DISTANCE * range_scalar;
1648 			cur_pos = Vec3(sin(angle) * scalar, 0.0, cos(angle) * scalar);
1649 			const angle_t angle_to_center = atan2(cur_pos.x, cur_pos.z);
1650 			const coord_t radius = bounding_range->get_radius(angle_to_center);
1651 			//    std::cout << cur_pos << " - " << camera_center_difference << ".magnitude_squared() (" << (cur_pos - camera_center_difference).magnitude_squared() << ") < " << square(radius) << std::endl;
1652 			//    if ((cur_pos - camera_center_difference).magnitude_squared() < square(radius))
1653 			if ((cur_pos - camera_center_difference).magnitude_squared()
1654 				> square(radius))
1655 				//      break;
1656 				return Vec3(-32768.0, 0.0, 0.0);
1657 		}
1658 		//  if (i == 10)
1659 		//    return Vec3(-32768.0, 0.0, 0.0);
1660 		//  else
1661 		return cur_pos;
1662 	}
1663 
get_area() const1664 	coord_t FilledBoundingSpawner::get_area() const
1665 	{ // Not 100% accurate, but goot enough.  :)
1666 		coord_t avg_radius = 0;
1667 		for (float f = 0; f < 2 * PI; f += (2 * PI / 256.0))
1668 			avg_radius += bounding_range->get_radius(f);
1669 		avg_radius /= 256.0;
1670 		return PI * square(avg_radius);
1671 	}
1672 
get_new_coords()1673 	Vec3 NoncheckingFilledBoundingSpawner::get_new_coords()
1674 	{
1675 		const angle_t angle= randangle(2 * PI);
1676 		const coord_t radius = bounding_range->get_radius(angle);
1677 		const coord_t scalar= std::sqrt(randcoord());
1678 		return Vec3(sin(angle) * scalar * radius, 0.0, cos(angle) * scalar
1679 			* radius);
1680 	}
1681 
get_area() const1682 	coord_t NoncheckingFilledBoundingSpawner::get_area() const
1683 	{ // Not 100% accurate, but goot enough.  :)
1684 		coord_t avg_radius = 0;
1685 		for (float f = 0; f < 2 * PI; f += (2 * PI / 256.0))
1686 			avg_radius += bounding_range->get_radius(f);
1687 		avg_radius /= 256.0;
1688 		return PI * square(avg_radius);
1689 	}
1690 
get_new_coords()1691 	Vec3 HollowBoundingSpawner::get_new_coords()
1692 	{
1693 		const angle_t angle= randangle(2 * PI);
1694 		const coord_t radius = bounding_range->get_radius(angle);
1695 		return Vec3(sin(angle) * radius, 0.0, cos(angle) * radius);
1696 	}
1697 
get_area() const1698 	coord_t HollowBoundingSpawner::get_area() const
1699 	{ // Not 100% accurate, but goot enough.  :)
1700 		coord_t avg_radius = 0;
1701 		for (float f = 0; f < 2 * PI; f += (2 * PI / 256.0))
1702 			avg_radius += bounding_range->get_radius(f);
1703 		avg_radius /= 256.0;
1704 		return PI * square(avg_radius);
1705 	}
1706 
EyeCandy()1707 	EyeCandy::EyeCandy()
1708 	{
1709 		set_thresholds(10000, 13, 37);
1710 		max_usec_per_particle_move = 100000;
1711 		sprite_scalar = 0.11;
1712 		max_point_size = 500.0;
1713 		lighting_scalar = 1000.0;
1714 		light_estimate = 0.0;
1715 		use_lights = true;
1716 		billboard_scalar = 0.2;
1717 		width = 800;
1718 		height = 600;
1719 		temp_sprite_scalar = sprite_scalar * height;
1720 		last_forced_LOD = 10;
1721 		framerate = 100.0;
1722 		max_fps = 255.0;
1723 		draw_shapes = true;
1724 	}
1725 
EyeCandy(int _max_particles)1726 	EyeCandy::EyeCandy(int _max_particles)
1727 	{
1728 		set_thresholds(_max_particles, 13, 37);
1729 		max_usec_per_particle_move = 100000;
1730 		sprite_scalar = 0.11;
1731 		max_point_size = 500.0;
1732 		lighting_scalar = 1000.0;
1733 		light_estimate = 0.0;
1734 		use_lights = true;
1735 		billboard_scalar = 0.2;
1736 		width = 800;
1737 		height = 600;
1738 		temp_sprite_scalar = sprite_scalar * height;
1739 		last_forced_LOD = 10;
1740 		framerate = 100.0;
1741 		max_fps = 255.0;
1742 		draw_shapes = true;
1743 	}
1744 
~EyeCandy()1745 	EyeCandy::~EyeCandy()
1746 	{
1747 		for (auto particle: particles)
1748 			delete particle;
1749 		for (auto effect: effects)
1750 			delete effect;
1751 		for (auto light: lights)
1752 			glDisable(light);
1753 	}
1754 
set_thresholds(const int _max_particles,const float min_framerate,const float max_framerate)1755 	void EyeCandy::set_thresholds(const int _max_particles,
1756 		const float min_framerate, const float max_framerate)
1757 	{
1758 		max_particles = _max_particles;
1759 		const float range = max_framerate - min_framerate;
1760 		LOD_9_threshold = max_particles * 73 / 100;
1761 		LOD_8_threshold = max_particles * 76 / 100;
1762 		LOD_7_threshold = max_particles * 79 / 100;
1763 		LOD_6_threshold = max_particles * 82 / 100;
1764 		LOD_5_threshold = max_particles * 85 / 100;
1765 		LOD_4_threshold = max_particles * 88 / 100;
1766 		LOD_3_threshold = max_particles * 91 / 100;
1767 		LOD_2_threshold = max_particles * 94 / 100;
1768 		LOD_1_threshold = max_particles * 97 / 100;
1769 		LOD_10_time_threshold = min_framerate + range * (9.0 / 9.0);
1770 		LOD_9_time_threshold = min_framerate + range * (8.0 / 9.0);
1771 		LOD_8_time_threshold = min_framerate + range * (7.0 / 9.0);
1772 		LOD_7_time_threshold = min_framerate + range * (6.0 / 9.0);
1773 		LOD_6_time_threshold = min_framerate + range * (5.0 / 9.0);
1774 		LOD_5_time_threshold = min_framerate + range * (4.0 / 9.0);
1775 		LOD_4_time_threshold = min_framerate + range * (3.0 / 9.0);
1776 		LOD_3_time_threshold = min_framerate + range * (2.0 / 9.0);
1777 		LOD_2_time_threshold = min_framerate + range * (1.0 / 9.0);
1778 		LOD_1_time_threshold = min_framerate + range * (0.0 / 9.0);
1779 		//  allowable_particles_to_add = max_particles;
1780 	}
1781 
get_texture(const TextureEnum type) const1782 	Uint32 EyeCandy::get_texture(const TextureEnum type) const
1783 	{
1784 		return get_texture_index(type);
1785 	}
1786 
set_particle_texture_combiner()1787 	void EyeCandy::set_particle_texture_combiner()
1788 	{
1789 		ELglActiveTextureARB(GL_TEXTURE1);
1790 
1791 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1792 
1793 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1794 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1795 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1796 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
1797 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
1798 		glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
1799 
1800 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1801 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1802 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1803 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE1);
1804 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1805 		glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
1806 
1807 		ELglActiveTextureARB(GL_TEXTURE0);
1808 
1809 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1810 
1811 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1812 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1813 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1814 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0);
1815 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1816 		glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
1817 
1818 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1819 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1820 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1821 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE0);
1822 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1823 		glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
1824 	}
1825 
set_shape_texture_combiner(const float alpha_scale)1826 	void EyeCandy::set_shape_texture_combiner(const float alpha_scale)
1827 	{
1828 		float color[4];
1829 
1830 		color[0] = alpha_scale;
1831 		color[1] = alpha_scale;
1832 		color[2] = alpha_scale;
1833 		color[3] = alpha_scale;
1834 
1835 		ELglActiveTextureARB(GL_TEXTURE1);
1836 
1837 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1838 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
1839 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1840 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1841 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
1842 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
1843 		glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
1844 
1845 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1846 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1847 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1848 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE1);
1849 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1850 		glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
1851 
1852 		ELglActiveTextureARB(GL_TEXTURE0);
1853 
1854 		glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR, color);
1855 
1856 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1857 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
1858 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
1859 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1860 
1861 		glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
1862 
1863 		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1864 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
1865 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1866 		glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
1867 		glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
1868 		glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
1869 	}
1870 
load_textures()1871 	void EyeCandy::load_textures()
1872 	{
1873 		// Load the textures.
1874 		texture_atlas = load_texture_cached("./textures/eye_candy.dds", tt_atlas);
1875 		texture_burn = load_texture_cached("./textures/eye_candy_burn.dds", tt_atlas);
1876 	}
1877 
push_back_effect(Effect * e)1878 	void EyeCandy::push_back_effect(Effect* e)
1879 	{
1880 		effects.push_back(e);
1881 	}
1882 
push_back_particle(Particle * p)1883 	bool EyeCandy::push_back_particle(Particle* p)
1884 	{
1885 		if /*(*/((int)particles.size() >= max_particles)/* || (!allowable_particles_to_add))*/
1886 		{
1887 			delete p;
1888 			return false;
1889 		}
1890 		else
1891 		{
1892 			particles.push_back(p);
1893 			p->effect->register_particle(p);
1894 			light_estimate += p->estimate_light_level();
1895 			//    allowable_particles_to_add--;
1896 			return true;
1897 		}
1898 	}
1899 
start_draw()1900 	void EyeCandy::start_draw()
1901 	{
1902 		glDisable(GL_LIGHTING);
1903 		glEnable(GL_TEXTURE_2D);
1904 		glEnable(GL_BLEND);
1905 		glEnable(GL_COLOR_MATERIAL);
1906 		glEnable(GL_DEPTH_TEST);
1907 		glDepthMask(false);
1908 		float modelview[16];
1909 		glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
1910 
1911 		const Vec3 right(modelview[0], modelview[4], modelview[8]);
1912 		const Vec3 up(modelview[1], modelview[5], modelview[9]);
1913 		corner_offset1 = (right + up) * billboard_scalar;
1914 		corner_offset2 = (right - up) * billboard_scalar;
1915 
1916 		glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1917 
1918 		ELglActiveTextureARB(GL_TEXTURE0);
1919 		glEnable(GL_TEXTURE_2D);
1920 		bind_texture(texture_atlas);
1921 
1922 		ELglActiveTextureARB(GL_TEXTURE1);
1923 		glEnable(GL_TEXTURE_2D);
1924 		bind_texture(texture_burn);
1925 
1926 		set_particle_texture_combiner();
1927 
1928 #ifndef MAP_EDITOR
1929 		/* Fog hurts blending with 5 color blending
1930 		 * (red, green, blue, alpha and burn)
1931 		 */
1932 		if (use_fog)
1933 		{
1934 			glDisable(GL_FOG);
1935 		}
1936 #endif
1937 	}
1938 
end_draw()1939 	void EyeCandy::end_draw()
1940 	{
1941 		ELglActiveTextureARB(GL_TEXTURE1);
1942 		glDisable(GL_TEXTURE_2D);
1943 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1944 
1945 		ELglActiveTextureARB(GL_TEXTURE0);
1946 		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1947 
1948 #ifndef MAP_EDITOR
1949 		if (use_fog)
1950 		{
1951 			glEnable(GL_FOG);
1952 		}
1953 #endif
1954 		glColor4f(1.0, 1.0, 1.0, 1.0);
1955 		glDisable(GL_BLEND);
1956 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1957 		glDepthMask(true);
1958 		glDisable(GL_COLOR_MATERIAL);
1959 		glEnable(GL_LIGHTING);
1960 	}
1961 
draw()1962 	void EyeCandy::draw()
1963 	{
1964 		if (ec_error_status)
1965 			return;
1966 
1967 		start_draw();
1968 
1969 		Uint32 i, count;
1970 
1971 		count = effects.size();
1972 
1973 		// Draw effects (any special drawing functionality) and their particles.
1974 		for (i = 0; i < count; i++)
1975 		{
1976 			Effect* e = effects[i];
1977 
1978 			if (e->active)
1979 			{
1980 				e->draw(time_diff);
1981 				e->draw_particle_buffer();
1982 			}
1983 		}
1984 
1985 		el::HardwareBuffer::unbind(el::hbt_index);
1986 		el::HardwareBuffer::unbind(el::hbt_vertex);
1987 
1988 		end_draw();
1989 		// Draw lights.
1990 		if ((use_lights) && (particles.size() > 0))
1991 		{
1992 			while (light_particles.size() < lights.size())
1993 				light_particles.push_back(std::pair<Particle*, float>(particles[randint((int)particles.size())], 0.0));
1994 			for (int i = 0; i < (int)light_particles.size(); i++)
1995 			{
1996 				Particle* p = light_particles[i].first;
1997 				if (p->get_light_level() < 0.00005)
1998 				{
1999 					int j;
2000 					for (j = 0; j < 40; j++)
2001 					{
2002 						light_particles[i] = std::pair<Particle*, float>(*(particles.begin() + randint((int)particles.size())), 0.0);
2003 						Particle* p = light_particles[i].first;
2004 						if (p->get_light_level()> 0.0001)
2005 						break;
2006 					}
2007 					if (j == 40)
2008 						continue;
2009 				}
2010 
2011 				light_particles[i].second += time_diff / 100000.0;
2012 				if (light_particles[i].second >= 1.0)
2013 					light_particles[i].second = 1.0;
2014 
2015 				const light_t light_level = p->get_light_level() * light_particles[i].second;
2016 				const GLenum light_id = lights[i];
2017 				const GLfloat light_pos[4] =
2018 					{	p->pos.x, p->pos.y, p->pos.z, 1.0};
2019 				const light_t brightness = light_estimate * lighting_scalar * light_level;
2020 				const GLfloat light_color[4] =
2021 					{	p->color[0] * brightness, p->color[1] * brightness, p->color[2] * brightness, 0.0};
2022 				glEnable(light_id);
2023 				glLightfv(light_id, GL_POSITION, light_pos);
2024 				glLightfv(light_id, GL_DIFFUSE, light_color);
2025 			}
2026 			for (int i = (int)light_particles.size(); i < (int)lights.size(); i++)
2027 				glDisable(lights[i]);
2028 		}
2029 		else
2030 		{
2031 			for (int i = 0; i < (int)lights.size(); i++)
2032 			glDisable(lights[i]); // Save the graphics card some work when rendering the rest of the scene, ne? :)
2033 		}
2034 	}
2035 
idle()2036 		void EyeCandy::idle()
2037 		{
2038 			if (ec_error_status)
2039 			return;
2040 
2041 			const Uint64 cur_time = get_time();
2042 			if (time_diff < 10)
2043 			time_diff = 10;
2044 
2045 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2046 			short cluster = get_actor_cluster ();
2047 #endif
2048 			for (int i = 0; i < (int)effects.size(); )
2049 			{
2050 				std::vector<Effect*>::iterator iter = effects.begin() + i;
2051 				Effect* e = *iter;
2052 
2053 				//    std::cout << e << ": " << e->get_expire_time() << ", " << cur_time << std::endl;
2054 				if (e->get_expire_time() < cur_time)
2055 				{
2056 					e->recall = true;
2057 				}
2058 
2059 				Vec3 shifted_pos = *(e->pos) - center;
2060 				coord_t distance_squared = shifted_pos.planar_magnitude_squared();
2061 				//    std::cout << e << ": " << center << ", " << *e->pos << ": " << (center - *(e->pos)).magnitude_squared() << " <? " << MAX_DRAW_DISTANCE_SQUARED << std::endl;
2062 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2063 				bool same_cluster = e->belongsToCluster (cluster);
2064 #endif
2065 				if (!e->active)
2066 				{
2067 					if (e->bounds)
2068 					{
2069 						const angle_t angle = atan2(shifted_pos.x, shifted_pos.z);
2070 						if (distance_squared < MAX_DRAW_DISTANCE_SQUARED + e->bounds->get_radius(angle)
2071 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2072 						&& same_cluster
2073 #endif
2074 						)
2075 						{
2076 							if (EC_DEBUG)
2077 							std::cout << "Activating effect(2) " << e << " (" << distance_squared << " < " << (MAX_DRAW_DISTANCE_SQUARED + e->bounds->get_radius(angle)) << ")" << std::endl;
2078 							e->active = true;
2079 						}
2080 						else if (!e->recall)
2081 						{
2082 							i++;
2083 							continue;
2084 						}
2085 					}
2086 					else
2087 					{
2088 						if (distance_squared < MAX_DRAW_DISTANCE_SQUARED
2089 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2090 						&& same_cluster
2091 #endif
2092 						)
2093 						{
2094 							if (EC_DEBUG)
2095 							std::cout << "Activating effect " << e << " (" << distance_squared << " < " << MAX_DRAW_DISTANCE_SQUARED << ")" << std::endl;
2096 							e->active = true;
2097 						}
2098 						else if (!e->recall)
2099 						{
2100 							i++;
2101 							continue;
2102 						}
2103 					}
2104 				}
2105 				else
2106 				{
2107 					if (e->bounds)
2108 					{
2109 						const angle_t angle = atan2(shifted_pos.x, shifted_pos.z);
2110 						if (distance_squared > e->bounds->get_radius(angle) + MAX_DRAW_DISTANCE_SQUARED
2111 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2112 						|| !same_cluster
2113 #endif
2114 						)
2115 						{
2116 							if (EC_DEBUG)
2117 							std::cout << "Deactivating effect(2) " << e << " (" << distance_squared << " > " << e->bounds->get_radius(angle) + MAX_DRAW_DISTANCE_SQUARED << ": " << *(e->pos) << ", " << center << ", " << e->bounds->get_radius(angle)
2118 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2119 								<< ", " << same_cluster
2120 #endif
2121 							  	<< ")" << std::endl;
2122 							e->active = false;
2123 						}
2124 					}
2125 					else
2126 					{
2127 						if (distance_squared > MAX_DRAW_DISTANCE_SQUARED
2128 #if defined CLUSTER_INSIDES && !defined MAP_EDITOR
2129 						|| !same_cluster
2130 #endif
2131 						)
2132 						{
2133 							if (e->get_type() != EC_MISSILE) // don't deactivate missed missiles
2134 
2135 							{
2136 								if (EC_DEBUG)
2137 								std::cout << "Deactivating effect " << e << " (" << distance_squared << " > " << MAX_DRAW_DISTANCE_SQUARED << ")" << std::endl;
2138 								e->active = false;
2139 							}
2140 						}
2141 					}
2142 				}
2143 
2144 				const bool ret = e->idle(time_diff);
2145 				if (!ret)
2146 				{
2147 					e->recall = true;
2148 					effects.erase(iter);
2149 					delete e;
2150 				}
2151 				else
2152 				i++;
2153 			}
2154 
2155 			// If we're nearing our particle limit, lower our level of detail.
2156 			float change_LOD;
2157 			if (particles.size() < LOD_9_threshold)
2158 			change_LOD = 10.0;
2159 			else if (particles.size() < LOD_8_threshold)
2160 			change_LOD = 10 - float(particles.size() - LOD_9_threshold) / float(LOD_8_threshold - LOD_9_threshold);
2161 			else if (particles.size() < LOD_7_threshold)
2162 			change_LOD = 9.0 - float(particles.size() - LOD_8_threshold) / float(LOD_7_threshold - LOD_8_threshold);
2163 			else if (particles.size() < LOD_6_threshold)
2164 			change_LOD = 8.0 - float(particles.size() - LOD_7_threshold) / float(LOD_6_threshold - LOD_7_threshold);
2165 			else if (particles.size() < LOD_5_threshold)
2166 			change_LOD = 7.0 - float(particles.size() - LOD_6_threshold) / float(LOD_5_threshold - LOD_6_threshold);
2167 			else if (particles.size() < LOD_4_threshold)
2168 			change_LOD = 6.0 - float(particles.size() - LOD_5_threshold) / float(LOD_4_threshold - LOD_5_threshold);
2169 			else if (particles.size() < LOD_3_threshold)
2170 			change_LOD = 5.0 - float(particles.size() - LOD_4_threshold) / float(LOD_3_threshold - LOD_4_threshold);
2171 			else if (particles.size() < LOD_2_threshold)
2172 			change_LOD = 4.0 - float(particles.size() - LOD_3_threshold) / float(LOD_2_threshold - LOD_3_threshold);
2173 			else if (particles.size() < LOD_1_threshold)
2174 			change_LOD = 3.0 - float(particles.size() - LOD_2_threshold) / float(LOD_1_threshold - LOD_2_threshold);
2175 			else if ((int)particles.size() < max_particles)
2176 			change_LOD = 2.0 - float(particles.size() - LOD_1_threshold) / float(max_particles - LOD_1_threshold);
2177 			else
2178 			change_LOD = 1.0;
2179 
2180 			float change_LOD2;
2181 			if (framerate >= LOD_10_time_threshold)
2182 			change_LOD2 = 10.0;
2183 			else if (framerate >= LOD_9_time_threshold)
2184 			change_LOD2 = 10.0 - float(framerate - LOD_9_time_threshold) / float(LOD_10_time_threshold - LOD_9_time_threshold);
2185 			else if (framerate >= LOD_8_time_threshold)
2186 			change_LOD2 = 9.0 - float(framerate - LOD_8_time_threshold) / float(LOD_9_time_threshold - LOD_8_time_threshold);
2187 			else if (framerate >= LOD_7_time_threshold)
2188 			change_LOD2 = 8.0 - float(framerate - LOD_7_time_threshold) / float(LOD_8_time_threshold - LOD_7_time_threshold);
2189 			else if (framerate >= LOD_6_time_threshold)
2190 			change_LOD2 = 7.0 - float(framerate - LOD_6_time_threshold) / float(LOD_7_time_threshold - LOD_6_time_threshold);
2191 			else if (framerate >= LOD_5_time_threshold)
2192 			change_LOD2 = 6.0 - float(framerate - LOD_5_time_threshold) / float(LOD_6_time_threshold - LOD_5_time_threshold);
2193 			else if (framerate >= LOD_4_time_threshold)
2194 			change_LOD2 = 5.0 - float(framerate - LOD_4_time_threshold) / float(LOD_5_time_threshold - LOD_4_time_threshold);
2195 			else if (framerate >= LOD_3_time_threshold)
2196 			change_LOD2 = 4.0 - float(framerate - LOD_3_time_threshold) / float(LOD_4_time_threshold - LOD_3_time_threshold);
2197 			else if (framerate >= LOD_2_time_threshold)
2198 			change_LOD2 = 3.0 - float(framerate - LOD_2_time_threshold) / float(LOD_3_time_threshold - LOD_2_time_threshold);
2199 			else if (framerate >= LOD_1_time_threshold)
2200 			change_LOD2 = 2.0 - float(framerate - LOD_1_time_threshold) / float(LOD_2_time_threshold - LOD_1_time_threshold);
2201 			else
2202 			change_LOD2 = 1.0;
2203 
2204 			//  std::cout << framerate << ", " << LOD_10_time_threshold << " : " << last_forced_LOD << ": " << change_LOD << " / " << change_LOD2 << " (" << particles.size() << ")" << std::endl;
2205 
2206 			if (change_LOD> change_LOD2) //Pick whichever one is lower.
2207 			change_LOD = change_LOD2;
2208 
2209 			for (auto effect: effects)
2210 				effect->request_LOD(change_LOD);
2211 
2212 			const float particle_cleanout_rate = (1.0 - std::pow(0.5f, 5.0f / (framerate * square(change_LOD))));
2213 			//  std::cout << (1.0 / particle_cleanout_rate) << std::endl;
2214 			float counter = randfloat();
2215 			for (int i = 0; i < (int)particles.size(); ) //Iterate using an int, not an iterator, because we may be adding/deleting entries, and that messes up iterators.
2216 
2217 			{
2218 				std::vector<Particle*>::iterator iter = particles.begin() + i;
2219 				Particle* p = *iter;
2220 
2221 				counter -= particle_cleanout_rate;
2222 				if (counter < 0) // Kill off a random particle.
2223 
2224 				{
2225 					counter++;
2226 					if ((p->deletable()) && (!p->effect->active))
2227 					{
2228 						particles.erase(iter);
2229 						for (int j = 0; j < (int)light_particles.size(); )
2230 						{
2231 							std::vector< std::pair<Particle*, light_t> >::iterator iter2 = light_particles.begin() + j;
2232 							if (iter2->first == p)
2233 							{
2234 								light_particles.erase(iter2);
2235 								continue;
2236 							}
2237 							j++;
2238 						}
2239 						p->effect->unregister_particle(p);
2240 						light_estimate -= p->estimate_light_level();
2241 						delete p;
2242 					}
2243 
2244 					i++;
2245 					continue;
2246 				}
2247 
2248 				if ((!p->effect->active) && (!p->effect->recall))
2249 				{
2250 					i++;
2251 					continue;
2252 				}
2253 
2254 				p->mover->move(*p, time_diff);
2255 				const bool ret = p->idle(time_diff);
2256 				if (!ret)
2257 				{
2258 					iter = particles.begin() + i; //Why the heck do I need to redo this just because I've push_back'ed entries to the vector in idle()?  :P  Makes no sense.  My best guess: array resizing.
2259 					particles.erase(iter);
2260 					for (int j = 0; j < (int)light_particles.size(); )
2261 					{
2262 						std::vector< std::pair<Particle*, light_t> >::iterator iter2 = light_particles.begin() + j;
2263 						if (iter2->first == p)
2264 						{
2265 							light_particles.erase(iter2);
2266 							continue;
2267 						}
2268 						j++;
2269 					}
2270 					p->effect->unregister_particle(p);
2271 					light_estimate -= p->estimate_light_level();
2272 					delete p;
2273 				}
2274 				else
2275 				i++;
2276 			}
2277 			last_forced_LOD = (Uint16)round(change_LOD);
2278 
2279 			//  allowable_particles_to_add = 1 + (int)(particles.size() * 0.00005 * time_diff / 1000000.0 * (max_particles - particles.size()) * change_LOD);
2280 			//  std::cout << "Current: " << particles.size() << "; Allowable new: " << allowable_particles_to_add << std::endl;
2281 			Uint32 i, count;
2282 
2283 			count = effects.size();
2284 
2285 			for (i = 0; i < count; i++)
2286 			{
2287 				Effect* e = effects[i];
2288 
2289 				if (e->active)
2290 				{
2291 					e->build_particle_buffer(time_diff);
2292 				}
2293 			}
2294 
2295 			el::HardwareBuffer::unbind(el::hbt_index);
2296 			el::HardwareBuffer::unbind(el::hbt_vertex);
2297 		}
2298 
add_light(GLenum light_id)2299 		void EyeCandy::add_light(GLenum light_id)
2300 		{
2301 			glDisable(light_id);
2302 			lights.push_back(light_id);
2303 			GLfloat light_pos[4] =
2304 			{	0.0, 0.0, 0.0, 1.0};
2305 			const GLfloat light_white[4] =
2306 			{	0.0, 0.0, 0.0, 0.0};
2307 			glLightfv(light_id, GL_SPECULAR, light_white);
2308 			glLightfv(light_id, GL_POSITION, light_pos);
2309 			glLightf(light_id, GL_LINEAR_ATTENUATION, 1.0);
2310 		}
2311 
2312 		// F U N C T I O N S //////////////////////////////////////////////////////////
2313 
get_time()2314 		Uint64 get_time()
2315 		{
2316 #if defined(_WIN32) || defined(_WIN64)
2317 			FILETIME ft;
2318 			GetSystemTimeAsFileTime(&ft);
2319 			Uint64 ret = ft.dwHighDateTime;
2320 			ret <<= 32;
2321 			ret |= ft.dwLowDateTime;
2322 			ret /= 10;
2323 			return ret;
2324 #else
2325 			struct timeval t;
2326 			gettimeofday(&t, NULL);
2327 			return ((Uint64)t.tv_sec)*1000000ul + (Uint64)t.tv_usec;
2328 #endif
2329 		}
2330 
hsv_to_rgb(const color_t h,const color_t s,const color_t v,color_t & r,color_t & g,color_t & b)2331 		void hsv_to_rgb(const color_t h, const color_t s, const color_t v, color_t& r, color_t& g, color_t& b)
2332 		{
2333 			if(!s) // Greyscale
2334 
2335 			{
2336 				r = g = b = v;
2337 				return;
2338 			}
2339 
2340 			const color_t float_sector = h * 6;
2341 			const int sector = (int)floor(float_sector);
2342 			const float sector_percent = float_sector - sector;
2343 			const float inv_sector_percent = 1.0 - sector_percent;
2344 			const float p = v * (1 - s);
2345 			const float q = v * (1 - s * sector_percent);
2346 			const float t = v * (1 - s * inv_sector_percent);
2347 			switch (sector)
2348 			{
2349 				case 0:
2350 				{
2351 					r = v;
2352 					g = t;
2353 					b = p;
2354 					break;
2355 				}
2356 				case 1:
2357 				{
2358 					r = q;
2359 					g = v;
2360 					b = p;
2361 					break;
2362 				}
2363 				case 2:
2364 				{
2365 					r = p;
2366 					g = v;
2367 					b = t;
2368 					break;
2369 				}
2370 				case 3:
2371 				{
2372 					r = p;
2373 					g = q;
2374 					b = v;
2375 					break;
2376 				}
2377 				case 4:
2378 				{
2379 					r = t;
2380 					g = p;
2381 					b = v;
2382 					break;
2383 				}
2384 				default:
2385 				{
2386 					r = v;
2387 					g = p;
2388 					b = q;
2389 					break;
2390 				}
2391 			}
2392 		}
2393 
2394 		///////////////////////////////////////////////////////////////////////////////
2395 
2396 	};
2397 
2398