void setup_particles() { int i; for (i = 0; i < NUM_NOZZLES; i++) { spawn_particle(i); } }
void psys_update(struct psys_emitter *em, float tm) { float dt, spawn_dt, spawn_tm; int i, spawn_count; struct psys_particle *p, pdummy; anm_time_t atm = ANM_SEC2TM(tm); if(!em->update) { fprintf(stderr, "psys_update called without an update callback\n"); abort(); } dt = tm - em->last_update; if(dt <= 0.0) { return; } psys_eval_attr(&em->attr, atm); /* how many particles to spawn for this interval ? */ em->spawn_acc += psys_get_cur_value(&em->attr.rate) * dt; if(em->spawn_acc >= 1.0) { spawn_count = em->spawn_acc; em->spawn_acc = fmod(em->spawn_acc, 1.0); } else { spawn_count = 0; } if(spawn_count) { spawn_dt = dt / (float)spawn_count; } spawn_tm = em->last_update; for(i=0; i<spawn_count; i++) { if(em->attr.max_particles >= 0 && em->pcount >= em->attr.max_particles) { break; } /* update emitter position for this spawning */ em->cur_pos = anm_get_position(&em->prs, ANM_SEC2TM(spawn_tm)); if(!(p = palloc())) { return; } if(spawn_particle(em, p) == -1) { pfree(p); } spawn_tm += spawn_dt; } /* update all particles */ p = em->plist; while(p) { em->update(em, p, tm, dt, em->upd_cls); p = p->next; } /* cleanup dead particles */ pdummy.next = em->plist; p = &pdummy; while(p->next) { if(p->next->life <= 0) { struct psys_particle *tmp = p->next; p->next = p->next->next; pfree(tmp); em->pcount--; } else { p = p->next; } } em->plist = pdummy.next; em->last_update = tm; }
void particles_simulation_system::advance_visible_streams_and_all_particles(camera_cone cone, const cosmos& cosmos, const augs::delta delta, interpolation_system& interp) { for (auto& particle_layer : particles) { for (auto& p : particle_layer) { p.integrate(delta.in_seconds()); } erase_remove(particle_layer, [](const resources::particle& a) { return a.lifetime_ms >= a.max_lifetime_ms; }); } cone.visible_world_area *= 2.5f; const auto targets = cosmos[cosmos.systems_temporary.get<dynamic_tree_system>().determine_visible_entities_from_camera(cone, components::dynamic_tree_node::tree_type::PARTICLE_EXISTENCES)]; for (const auto it : targets) { auto& cache = get_cache(it); const auto& existence = it.get<components::particles_existence>(); const bool should_rebuild_cache = cache.recorded_existence != existence; if (should_rebuild_cache) { randomization rng = existence.rng_seed; cache.recorded_existence = existence; cache.emission_instances.clear(); for (auto emission : (*existence.input.effect)) { emission.apply_modifier(existence.input.modifier); cache.emission_instances.push_back(emission_instance()); auto& target_stream = *cache.emission_instances.rbegin(); const auto var_v = rng.randval(emission.base_velocity_variation); //LOG("V: %x", var_v); target_stream.velocity.set(std::max(0.f, emission.base_velocity.first - var_v / 2), emission.base_velocity.second + var_v / 2); //LOG("Vl: %x Vu: %x", target_stream.velocity.first, target_stream.velocity.second); target_stream.stream_info = emission; target_stream.enable_streaming = true; target_stream.stream_lifetime_ms = 0.f; target_stream.angular_offset = rng.randval(emission.angular_offset); target_stream.target_spread = rng.randval(emission.spread_degrees); target_stream.target_particles_per_sec = rng.randval(emission.particles_per_sec); target_stream.swing_spread = rng.randval(emission.swing_spread); target_stream.swings_per_sec = rng.randval(emission.swings_per_sec); target_stream.min_swing_spread = rng.randval(emission.min_swing_spread); target_stream.min_swings_per_sec = rng.randval(emission.min_swings_per_sec); target_stream.max_swing_spread = rng.randval(emission.max_swing_spread); target_stream.max_swings_per_sec = rng.randval(emission.max_swings_per_sec); target_stream.stream_max_lifetime_ms = rng.randval(emission.stream_duration_ms); target_stream.stream_particles_to_spawn = rng.randval(emission.num_of_particles_to_spawn_initially); target_stream.swing_speed_change = rng.randval(emission.swing_speed_change_rate); target_stream.swing_spread_change = rng.randval(emission.swing_spread_change_rate); target_stream.fade_when_ms_remaining = rng.randval(emission.fade_when_ms_remaining); } } const auto& transform = it.viewing_transform(interp) + existence.current_displacement; randomization rng = cosmos.get_rng_seed_for(it) + cosmos.get_total_steps_passed(); bool should_destroy = true; for (auto& instance : cache.emission_instances) { const float stream_delta = std::min(delta.in_milliseconds(), instance.stream_max_lifetime_ms - instance.stream_lifetime_ms); instance.stream_lifetime_ms += stream_delta; if (instance.stream_lifetime_ms > instance.stream_max_lifetime_ms) { continue; } auto new_particles_to_spawn_by_time = instance.target_particles_per_sec * (stream_delta / 1000.f); instance.stream_particles_to_spawn += new_particles_to_spawn_by_time; instance.swings_per_sec += rng.randval(-instance.swing_speed_change, instance.swing_speed_change); instance.swing_spread += rng.randval(-instance.swing_spread_change, instance.swing_spread_change); if (instance.max_swing_spread > 0) { augs::clamp(instance.swing_spread, instance.min_swing_spread, instance.max_swing_spread); } if (instance.max_swings_per_sec > 0) { augs::clamp(instance.swings_per_sec, instance.min_swings_per_sec, instance.max_swings_per_sec); } const int to_spawn = static_cast<int>(std::floor(instance.stream_particles_to_spawn)); const auto segment_length = existence.distribute_within_segment_of_length; const vec2 segment_A = transform.pos + vec2().set_from_degrees(transform.rotation + 90).set_length(segment_length / 2); const vec2 segment_B = transform.pos - vec2().set_from_degrees(transform.rotation + 90).set_length(segment_length / 2); for (int i = 0; i < to_spawn; ++i) { const float t = (static_cast<float>(i) / to_spawn); const float time_elapsed = (1.f - t) * delta.in_seconds(); const vec2 segment_position = augs::interp(segment_A, segment_B, rng.randval(0.f, 1.f)); spawn_particle(rng, instance, segment_position, transform.rotation + instance.swing_spread * static_cast<float>(sin((instance.stream_lifetime_ms / 1000.f) * 2 * PI_f * instance.swings_per_sec)) , instance.target_spread, instance.stream_info).integrate(time_elapsed); instance.stream_particles_to_spawn -= 1.f; } } } }