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