1 // I N C L U D E S ////////////////////////////////////////////////////////////
2 
3 #include "eye_candy.h"
4 #include "math_cache.h"
5 #include "effect_wind.h"
6 #include "../textures.h"
7 
8 namespace ec
9 {
10 
11 	const float range_scalar = 1.0;
12 
13 	// C L A S S   F U N C T I O N S //////////////////////////////////////////////
14 
WindParticle(Effect * _effect,ParticleMover * _mover,const Vec3 _pos,const Vec3 _velocity,const color_t hue_adjust,const color_t saturation_adjust,const coord_t scalar,const coord_t _min_height,const coord_t _max_height,const WindEffect::WindType _type)15 	WindParticle::WindParticle(Effect* _effect, ParticleMover* _mover,
16 		const Vec3 _pos, const Vec3 _velocity, const color_t hue_adjust,
17 		const color_t saturation_adjust, const coord_t scalar,
18 		const coord_t _min_height, const coord_t _max_height,
19 		const WindEffect::WindType _type) :
20 		Particle(_effect, _mover, _pos, _velocity)
21 	{
22 		state = 0;
23 		flare_max = 1.0;
24 		flare_exp = 1.0;
25 		flare_frequency = 1.0;
26 		min_height = _min_height;
27 		max_height = _max_height;
28 		type = _type;
29 		angle_t angle, rise;
30 		color_t hue = 0.0, saturation = 0.0, value = 0.0;
31 		switch (type)
32 		{
33 			case WindEffect::LEAVES:
34 			{
35 				hue = 0.0 + randcolor(0.08);
36 				saturation = 0.5 + randcolor(0.4);
37 				value = 0.35 + randcolor(0.20);
38 				size = 0.08 * scalar;
39 				alpha = 1.0;
40 				subtype = rand() % 3; // Store it in case we need it later -- say, for a texture.
41 				switch (subtype)
42 				{
43 					case 0: // Maple
44 					{
45 						angle = randangle(30 * (PI / 180)) + (240 * (PI / 180));
46 						rise = randangle(30 * (PI / 180)) + (-10 * (PI / 180));
47 						rotation_axes[0] = Vec3(sin(angle) * cos(rise),
48 							sin(rise), cos(angle) * cos(rise));
49 						axis_weights[0] = (sin(rise) + 0.2) * (randangle(0.3) + 0.85);
50 						angle = -randangle(30 * (PI / 180)) + (120 * (PI / 180));
51 						rise = randangle(30 * (PI / 180)) + (-10 * (PI / 180));
52 						rotation_axes[1] = Vec3(sin(angle) * cos(rise),
53 							sin(rise), cos(angle) * cos(rise));
54 						axis_weights[1] = (sin(rise) + 0.2) * (randangle(0.3) + 0.85);
55 						angle = randangle(30 * (PI / 180)) + (165 * (PI / 180));
56 						rise = randangle(30 * (PI / 180)) + (-10 * (PI / 180));
57 						rotation_axes[2] = Vec3(sin(angle) * cos(rise),
58 							sin(rise), cos(angle) * cos(rise));
59 						axis_weights[2] = (sin(rise) + 0.2) * (randangle(0.3) + 1.0);
60 						break;
61 					}
62 					case 1: // Oak
63 					{
64 						angle = randangle(30 * (PI / 180)) + (220 * (PI / 180));
65 						rise = randangle(40 * (PI / 180)) + (-12 * (PI / 180));
66 						rotation_axes[0] = Vec3(sin(angle) * cos(rise),
67 							sin(rise), cos(angle) * cos(rise));
68 						axis_weights[0] = (sin(rise) + 0.2) * (randangle(0.2) + 0.5);
69 						angle = -randangle(30 * (PI / 180)) + (140 * (PI / 180));
70 						rise = randangle(40 * (PI / 180)) + (-12 * (PI / 180));
71 						rotation_axes[1] = Vec3(sin(angle) * cos(rise),
72 							sin(rise), cos(angle) * cos(rise));
73 						axis_weights[1] = (sin(rise) + 0.2) * (randangle(0.2) + 0.5);
74 						angle = randangle(20 * (PI / 180)) + (170 * (PI / 180));
75 						rise = randangle(20 * (PI / 180)) + (-7 * (PI / 180));
76 						rotation_axes[2] = Vec3(sin(angle) * cos(rise),
77 							sin(rise), cos(angle) * cos(rise));
78 						axis_weights[2] = (sin(rise) + 0.2) * (randangle(0.3) + 1.0);
79 						break;
80 					}
81 					case 2: // Ash
82 					{
83 						angle = randangle(30 * (PI / 180)) + (200 * (PI / 180));
84 						rise = randangle(40 * (PI / 180)) + (-12 * (PI / 180));
85 						rotation_axes[0] = Vec3(sin(angle) * cos(rise),
86 							sin(rise), cos(angle) * cos(rise));
87 						axis_weights[0] = (sin(rise) + 0.2) * (randangle(0.15) + 0.3);
88 						angle = -randangle(30 * (PI / 180)) + (160 * (PI / 180));
89 						rise = randangle(40 * (PI / 180)) + (-12 * (PI / 180));
90 						rotation_axes[1] = Vec3(sin(angle) * cos(rise),
91 							sin(rise), cos(angle) * cos(rise));
92 						axis_weights[1] = (sin(rise) + 0.2) * (randangle(0.15) + 0.3);
93 						angle = randangle(20 * (PI / 180)) + (170 * (PI / 180));
94 						rise = randangle(15 * (PI / 180)) + (-6 * (PI / 180));
95 						rotation_axes[2] = Vec3(sin(angle) * cos(rise),
96 							sin(rise), cos(angle) * cos(rise));
97 						axis_weights[2] = (sin(rise) + 0.2) * (randangle(0.3) + 1.0);
98 						break;
99 					}
100 				}
101 				break;
102 			}
103 			case WindEffect::FLOWER_PETALS:
104 			{
105 				hue = 0.0;
106 				saturation = 0.41 + randcolor(0.26);
107 				value = 0.6;
108 				size = (0.035 + randangle(0.025)) * scalar;
109 				alpha = 0.9;
110 
111 				angle = randangle(60 * (PI / 180)) + (210 * (PI / 180));
112 				rise = randangle(60 * (PI / 180)) + (-20 * (PI / 180));
113 				rotation_axes[0] = Vec3(sin(angle) * cos(rise), sin(rise),
114 					cos(angle) * cos(rise));
115 				axis_weights[0] = (sin(rise) + 0.2) * (randangle(0.3) + 0.5);
116 				angle = -randangle(60 * (PI / 180)) + (90 * (PI / 180));
117 				rise = randangle(60 * (PI / 180)) + (-20 * (PI / 180));
118 				rotation_axes[1] = Vec3(sin(angle) * cos(rise), sin(rise),
119 					cos(angle) * cos(rise));
120 				axis_weights[1] = (sin(rise) + 0.2) * (randangle(0.3) + 0.5);
121 				angle = randangle(60 * (PI / 180)) + (150 * (PI / 180));
122 				rise = randangle(60 * (PI / 180)) + (-20 * (PI / 180));
123 				rotation_axes[2] = Vec3(sin(angle) * cos(rise), sin(rise),
124 					cos(angle) * cos(rise));
125 				axis_weights[2] = (sin(rise) + 0.2) * (randangle(0.3) + 0.5);
126 				break;
127 			}
128 			case WindEffect::SNOW:
129 			{
130 				hue = 0.67;
131 				saturation = 0.05;
132 				value = 0.85 + randcolor(0.15);
133 				size = (0.006 + randcolor(0.004)) * scalar;
134 				alpha = 0.7;
135 
136 				angle = 240 * (PI / 180);
137 				rotation_axes[0] = Vec3(sin(angle), 0.0, cos(angle));
138 				axis_weights[2] = randangle(0.1) + 0.5;
139 				angle = 120 * (PI / 180);
140 				rotation_axes[1] = Vec3(sin(angle), 0.0, cos(angle));
141 				axis_weights[2] = randangle(0.1) + 0.5;
142 				angle = 180 * (PI / 180);
143 				rotation_axes[2] = Vec3(sin(angle), 0.0, cos(angle));
144 				axis_weights[2] = randangle(0.1) + 0.5;
145 				break;
146 			}
147 		}
148 
149 		//  std::cout << this << ", " << pos << ": " << "Leaf created." <<
150 		//  std::endl;
151 
152 		/*
153 		 // Normalize axis weights
154 		 percent_t sum = 0;
155 		 for (int i = 0; i < 3; i++)
156 		 coord_t distance_squared = (camera - *(e->pos)).magnitude_squared();
157 		 sum += axis_weights[i];
158 		 for (int i = 0; i < 3; i++)
159 		 axis_weights[i] /= sum;
160 		 */
161 		hue += hue_adjust;
162 		if (hue > 1.0)
163 			hue -= 1.0;
164 		saturation = std::min(1.0f, saturation * saturation_adjust);
165 		hsv_to_rgb(hue, saturation, value, color[0], color[1], color[2]);
166 	}
167 
idle(const Uint64 delta_t)168 	bool WindParticle::idle(const Uint64 delta_t)
169 	{
170 		if (effect->recall)
171 			return false;
172 
173 		WindEffect* wind_effect = (WindEffect*)effect;
174 		const Uint64 age = get_time() - born;
175 		const interval_t usec = delta_t / 1000000.0;
176 		const Vec3 cur_wind = get_wind_vec();
177 
178 		//  std::cout << "Wind vec: " << cur_wind.magnitude() << ", " << cur_wind << std::endl;
179 		float divisor;
180 		switch (type)
181 		{
182 			case WindEffect::LEAVES:
183 			{
184 				divisor = 100000;
185 				break;
186 			}
187 			case WindEffect::FLOWER_PETALS:
188 			{
189 				divisor = 200000;
190 				break;
191 			}
192 			case WindEffect::SNOW:
193 			{
194 				divisor = 300000;
195 				break;
196 			}
197 			default: // Should never reach.
198 			{
199 				divisor = 0;
200 				break;
201 			}
202 		}
203 
204 		const float scalar = std::pow(0.5f, (interval_t)delta_t
205 			/ divisor);
206 		velocity = velocity * scalar + cur_wind * (1.0 - scalar);
207 
208 		if (pos.y < min_height)
209 		{
210 			velocity /= ((min_height - pos.y + 1.0) * 8);
211 			pos.y = min_height;
212 			if (!(rand() % 3))
213 				velocity.y = -velocity.y * 1.5;
214 		}
215 		else
216 		{
217 			pos.y -= 0.4 * usec;
218 			if (pos.y < min_height)
219 				pos.y = min_height;
220 		}
221 
222 		//  std::cout << "Pos: " << pos << std::endl;
223 		//  std::cout << "Velocity: " << velocity.magnitude() << ", " << velocity << std::endl;
224 
225 		if (!state)
226 		{
227 			if (age > 50000000)
228 			{
229 				//      std::cout << this << ": Too old." << std::endl;
230 				state = 1;
231 			}
232 
233 			if ((pos - base->center).planar_magnitude_squared()
234 				> MAX_DRAW_DISTANCE_SQUARED * 2)
235 			{
236 				//      std::cout << this << ": " << pos << " too far from " << base->center << std::endl;
237 				state = 1;
238 			}
239 		}
240 
241 		if (state == 0)
242 		{
243 			if (pos.y > max_height)
244 				velocity.y -= delta_t / 2000000.0;
245 
246 			Vec3 shifted_pos = pos - wind_effect->center;
247 			const coord_t radius= std::sqrt(square(shifted_pos.x) + square(shifted_pos.z));
248 			const angle_t angle = atan2(shifted_pos.x, shifted_pos.z);
249 			const coord_t max_radius =
250 				wind_effect->bounding_range->get_radius(angle);
251 			if (radius > max_radius)
252 			{ // Pass it off to a neighboring effect.
253 				if (wind_effect->neighbors.size() == 0)
254 				{
255 					state = 1;
256 					return true;
257 				}
258 				std::vector<WindEffect::WindNeighbor>::iterator iter;
259 				for (iter = wind_effect->neighbors.begin(); iter != wind_effect->neighbors.end(); ++iter)
260 				{
261 					if ((angle > iter->start_angle) && (angle <= iter->end_angle))
262 						break;
263 				}
264 				if (iter == wind_effect->neighbors.end())
265 					iter = wind_effect->neighbors.begin();
266 				if (iter->neighbor == NULL)
267 				{
268 					state = 1;
269 					return true;
270 				}
271 				effect->particles.erase(this);
272 				effect = iter->neighbor;
273 				effect->particles[this] = true;
274 			}
275 		}
276 		else
277 		{
278 			pos.y += delta_t / 800000.0;
279 			if (pos.y > max_height * 2)
280 			{
281 				//      std::cout << this << ": " << pos << " too high." << std::endl;
282 				return false;
283 			}
284 		}
285 
286 		// Rotate the blowing object.
287 		angle_t rot_scalar;
288 		switch (type)
289 		{
290 			case WindEffect::LEAVES:
291 			{
292 				rot_scalar = 2.0;
293 				break;
294 			}
295 			case WindEffect::FLOWER_PETALS:
296 			{
297 				rot_scalar = 3.5;
298 				break;
299 			}
300 			case WindEffect::SNOW:
301 			{
302 				rot_scalar = 30.0;
303 				break;
304 			}
305 			default: // Should never reach.
306 			{
307 				rot_scalar = 0;
308 				break;
309 			}
310 		}
311 		if (pos.y >= min_height + 0.05)
312 		{
313 			for (int i = 0; i < 3; i++)
314 			{
315 				const angle_t rot = rot_scalar * randangle(10.0) * usec * axis_weights[i]
316 					* (rotation_axes[i].dot(cur_wind)) * (3.0 + velocity.y)
317 					+ randangle(0.6) * usec;
318 				Quaternion cur_rotation;
319 				cur_rotation.from_axis_and_angle(rotation_axes[i], rot);
320 				quaternion *= cur_rotation;
321 			}
322 		}
323 
324 		return true;
325 	}
326 
get_texture()327 	Uint32 WindParticle::get_texture() // Shouldn't be needed.  But just in case...
328 	{
329 		switch (type)
330 		{
331 			case WindEffect::LEAVES:
332 				switch (subtype)
333 				{
334 					case 0: // Maple
335 						return base->get_texture(EC_LEAF_MAPLE);
336 					case 1: // Oak
337 						return base->get_texture(EC_LEAF_OAK);
338 					case 2: // Ash
339 						return base->get_texture(EC_LEAF_ASH);
340 					default: // Should never reach.
341 						return 0;
342 				}
343 			case WindEffect::FLOWER_PETALS:
344 				return base->get_texture(EC_PETAL);
345 			case WindEffect::SNOW:
346 				return base->get_texture(EC_SNOWFLAKE);
347 			default: // Should never reach.
348 				return 0;
349 		}
350 
351 		return 0; // Control should never reach here.
352 	}
353 
get_burn() const354 	float WindParticle::get_burn() const
355 	{
356 		return 0.0f;
357 	}
358 
get_wind_vec() const359 	Vec3 WindParticle::get_wind_vec() const
360 	{
361 		const WindEffect* e = (WindEffect*)effect;
362 		const float time_offset = (float)((unsigned short)(get_time() / 10000))
363 			* PI / 2000.0; // Translation: Convert to milliseconds, truncate the higher-order digits, convert to a float, make it wraparound in radians, and scale it down some.
364 		const unsigned short individual_offset =
365 			(unsigned short)(uintptr_t)(void*)(this); // Based on the memory address in order to give each particle a unique bias.
366 		srand(individual_offset);
367 		const float offset= randfloat() * 0.5;
368 
369 		const coord_t x = 1.0 * sin(offset + pos.x * 0.5283 + pos.z * 0.7111
370 			+ time_offset * 0.6817) * sin(offset + pos.x * 1.2019 + pos.z
371 			* 0.5985 + time_offset * 1.5927) * e->max_adjust / (fabs(pos.y
372 			- e->center.y) + 1);
373 		const coord_t y = 1.0 * sin(offset + pos.x * 0.4177 + pos.z * 1.3127
374 			+ time_offset * 1.1817) * sin(offset + pos.x * 0.5828 + pos.z
375 			* 0.6888 + time_offset * 2.1927) * e->max_adjust * 2.0;
376 		const coord_t z = 1.0 * sin(offset + pos.x * 1.1944 + pos.z * 0.9960
377 			+ time_offset * 1.6817) * sin(offset + pos.x * 0.6015 + pos.z
378 			* 1.4809 + time_offset * 1.4927) * e->max_adjust / (fabs(pos.y
379 			- e->center.y) + 1);
380 
381 		//  Vec3 random_component;
382 		//  random_component.randomize(max_adjust / 4);
383 		//  std::cout << this << ",\t" << pos << ",\t" << velocity << ":\t" << Vec3(x, y, z) << ",\t" << (e->overall_wind + Vec3(x, y, z)) << std::endl;
384 		//  std::cout << "  **\t" << offset << ",\t" << (pos.x * 1.9283) << ",\t" << (pos.z * 2.4111) << ",\t" << (time_offset * 2.2817) << " =>\t" << sin(offset + pos.x * 1.9283 + pos.z * 2.4111 + time_offset * 2.2817) << std::endl;
385 		//  std::cout << "  **\t" << offset << ",\t" << (pos.x * 3.4019) << ",\t" << (pos.z * 2.0985) << ",\t" << (time_offset * 4.1927) << " =>\t" << sin(offset + pos.x * 3.4019 + pos.z * 2.0985 + time_offset * 4.1927) << std::endl;
386 		return e->overall_wind + Vec3(x, y, z);// + random_component;
387 	}
388 
WindEffect(EyeCandy * _base,bool * _dead,Vec3 * _pos,std::vector<ec::Obstruction * > * _obstructions,const color_t _hue_adjust,const color_t _saturation_adjust,const coord_t _scalar,const float _density,BoundingRange * _bounding_range,const WindType _type,const Vec3 _prevailing_wind)389 	WindEffect::WindEffect(EyeCandy* _base, bool* _dead, Vec3* _pos,
390 		std::vector<ec::Obstruction*>* _obstructions, const color_t _hue_adjust,
391 		const color_t _saturation_adjust, const coord_t _scalar,
392 		const float _density, BoundingRange* _bounding_range,
393 		const WindType _type, const Vec3 _prevailing_wind)
394 	{
395 		if (EC_DEBUG)
396 			std::cout << "WindEffect (" << this << ") created." << std::endl;
397 		base = _base;
398 		dead = _dead;
399 		pos = _pos;
400 		center = *pos;
401 		obstructions = _obstructions;
402 		type = _type;
403 		hue_adjust = _hue_adjust;
404 		saturation_adjust = _saturation_adjust;
405 		scalar = _scalar;
406 		prevailing_wind = _prevailing_wind;
407 		overall_wind = prevailing_wind;
408 		max_adjust = 0.2 + prevailing_wind.magnitude() * 0.5;
409 		overall_wind_adjust = Vec3(0.0, 0.0, 0.0);
410 		bounding_range = _bounding_range;
411 		bounds = bounding_range;
412 		mover = new GradientMover(this);
413 		spawner = new FilledBoundingSpawner(_bounding_range, pos, &(base->center), range_scalar);
414 		//  max_LOD1_count = (int)(spawner->get_area() * _density * 1.0) / 10;
415 		//  std::cout << "2: " <<  hue_adjust << " / " << saturation_adjust << " / " << scalar << " / " << _density << std::endl;
416 		max_LOD1_count = (int)(MAX_DRAW_DISTANCE_SQUARED * PI * _density
417 			* range_scalar * 2.0) / 25;
418 		LOD = base->last_forced_LOD;
419 		count = LOD * max_LOD1_count;
420 		switch (type)
421 		{
422 			case LEAVES:
423 			{
424 				count *= 1;
425 				break;
426 			}
427 			case FLOWER_PETALS:
428 			{
429 				count *= 3;
430 				break;
431 			}
432 			case SNOW:
433 			{
434 				count *= 8;
435 				break;
436 			}
437 		}
438 	}
439 
~WindEffect()440 	WindEffect::~WindEffect()
441 	{
442 		delete mover;
443 		delete spawner;
444 		if (EC_DEBUG)
445 			std::cout << "WindEffect (" << this << ") destroyed." << std::endl;
446 	}
447 
set_pass_off(std::vector<Effect * > pass_off_to)448 	void WindEffect::set_pass_off(std::vector<Effect*> pass_off_to)
449 	{
450 		std::vector<WindEffect*> new_vec;
451 		for (auto effect: pass_off_to)
452 			new_vec.push_back((WindEffect*)effect);
453 		set_pass_off(new_vec);
454 	}
455 
set_pass_off(std::vector<WindEffect * > pass_off_to)456 	void WindEffect::set_pass_off(std::vector<WindEffect*> pass_off_to)
457 	{
458 		// Get the max extents for each neighbor.
459 		for (auto eff: pass_off_to)
460 		{
461 			WindNeighbor n;
462 			n.neighbor = eff;
463 			const coord_t dist = (center - eff->center).magnitude();
464 			const angle_t angle = center.angle_to(eff->center);
465 			const angle_t opposite_angle = remainderf(angle + PI, 2 * PI);
466 			const coord_t radius1 = bounding_range->get_radius(angle);
467 			const coord_t radius2 =
468 				eff->bounding_range->get_radius(opposite_angle);
469 			if (dist > radius1 + radius2)
470 				continue;
471 
472 			angle_t angle_shift = 0.01;
473 			angle_t start_angle = angle - angle_shift;
474 			for (;; angle_shift += 0.01, start_angle -= 0.01)
475 			{
476 				if (start_angle < 0)
477 					start_angle += 2 * PI;
478 				const percent_t distance_penalty = cos(angle_shift);
479 				const coord_t radius1 = bounding_range->get_radius(angle);
480 				const coord_t radius2 =
481 					eff->bounding_range->get_radius(opposite_angle);
482 				const coord_t newdist = (radius1 + radius2) / distance_penalty;
483 				if (dist < newdist)
484 					break;
485 			}
486 			n.start_angle = start_angle;
487 			if (n.start_angle < 0)
488 				n.start_angle += 2 * PI;
489 
490 			angle_shift = 0.01;
491 			float end_angle = angle - angle_shift;
492 			for (;; angle_shift += 0.01, end_angle += 0.01)
493 			{
494 				if (end_angle >= 2 * PI)
495 					end_angle -= 2 * PI;
496 				const percent_t distance_penalty = cos(angle_shift);
497 				const coord_t radius1 = bounding_range->get_radius(angle);
498 				const coord_t radius2 =
499 					eff->bounding_range->get_radius(opposite_angle);
500 				const coord_t newdist = (radius1 + radius2) / distance_penalty;
501 				if (dist < newdist)
502 					break;
503 			}
504 			n.end_angle = end_angle;
505 			if (n.end_angle >= 2 * PI)
506 				n.end_angle -= 2 * PI;
507 
508 			neighbors.push_back(n);
509 		}
510 
511 		// Eliminate overlap and insert nulls between extents that don't reach each other.
512 		if (neighbors.size())
513 		{
514 			WindNeighbor* previous = &(*(neighbors.begin() + (neighbors.size()
515 				- 1)));
516 			for (int i = 0; i < (int)neighbors.size(); i++)
517 			{
518 				std::vector<WindNeighbor>::iterator iter = neighbors.begin() + i;
519 				WindNeighbor* current = &(*iter);
520 				angle_t end_angle = previous->end_angle;
521 				if (end_angle - current->start_angle > PI)
522 					end_angle -= 2 * PI;
523 				if (end_angle > current->start_angle)
524 				{ // Narrow down the angles.
525 					angle_t average = (end_angle + current->start_angle) / 2;
526 					if (average < 0)
527 						average += 2 * PI;
528 					previous->end_angle = average;
529 					current->start_angle = average;
530 				}
531 				else
532 				{ // Insert a null
533 					WindNeighbor n;
534 					n.neighbor = NULL;
535 					n.start_angle = previous->end_angle;
536 					n.end_angle = current->start_angle;
537 					neighbors.insert(iter, n);
538 					i++;
539 				}
540 				previous = current;
541 			}
542 		}
543 
544 		// Spawn leaves
545 		for (int i = count - (int)particles.size(); i >= 0; i--)
546 		{
547 			Vec3 coords = spawner->get_new_coords();
548 			if (coords.x == -32768.0)
549 				continue;
550 			coords += base->center + Vec3(0.0, 0.05, 0.0);
551 			Vec3 velocity;
552 			velocity.randomize(max_adjust / 4);
553 			velocity.y /= 2;
554 			Particle
555 				* p =
556 					new WindParticle(this, mover, coords, velocity, hue_adjust, saturation_adjust, scalar, center.y + 0.05, center.y + 1.0, type);
557 			if (!base->push_back_particle(p))
558 				break;
559 		}
560 	}
561 
idle(const Uint64 usec)562 	bool WindEffect::idle(const Uint64 usec)
563 	{
564 		if ((recall) && (particles.size() == 0))
565 			return false;
566 
567 		if (recall)
568 			return true;
569 
570 		center = *pos;
571 
572 		Vec3 velocity_shift;
573 		velocity_shift.randomize();
574 		velocity_shift.y /= 2;
575 		velocity_shift.normalize(0.00004 * 4 * std::sqrt(usec));
576 		overall_wind_adjust += velocity_shift;
577 		const coord_t magnitude = overall_wind_adjust.magnitude();
578 		if (magnitude > max_adjust * 3.5)
579 		{
580 			//    std::cout << "Adjusting down." << std::endl;
581 			overall_wind_adjust /= (magnitude / (max_adjust * 3.5));
582 		}
583 		//  std::cout << "Wind adjust: " << overall_wind_adjust.magnitude() << ", " << overall_wind_adjust << std::endl;
584 
585 		if (fabs(overall_wind_adjust.y) > 0.15)
586 			overall_wind_adjust.y *= std::pow(0.5f, usec / 300000.0f);
587 
588 		overall_wind = prevailing_wind + overall_wind_adjust;
589 
590 		count = LOD * max_LOD1_count;
591 		switch (type)
592 		{
593 			case LEAVES:
594 			{
595 				count *= 1;
596 				break;
597 			}
598 			case FLOWER_PETALS:
599 			{
600 				count *= 3;
601 				break;
602 			}
603 			case SNOW:
604 			{
605 				count *= 8;
606 				break;
607 			}
608 		}
609 
610 		for (int i = count - (int)particles.size(); i >= 0; i--)
611 		{
612 			Vec3 coords = spawner->get_new_coords();
613 			if (coords.x == -32768.0)
614 				continue;
615 			//    std::cout << coords << ", ";
616 			coords += base->center + Vec3(0.0, 0.05, 0.0);
617 			//    std::cout << coords << std::endl;
618 			Vec3 velocity;
619 			velocity.randomize(max_adjust / 2);
620 			velocity.y /= 2;
621 			Particle
622 				* p =
623 					new WindParticle(this, mover, coords, velocity, hue_adjust, saturation_adjust, scalar, center.y + 0.05, center.y + 4.0, type);
624 			if (!base->push_back_particle(p))
625 			{
626 				break;
627 			}
628 		}
629 
630 		return true;
631 	}
632 
633 ///////////////////////////////////////////////////////////////////////////////
634 
635 }
636 ;
637 
638