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