/* * Copyright (C) 2017-2019 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #include "particle-system.hpp" #include "../../game/curl-noise.hpp" ParticleSystem::ParticleSystem(ComponentManager* componentManager): System(componentManager), range(nullptr), material(nullptr) { batch.setTransform(Transform::getIdentity()); batch.setCullingEnabled(false); } ParticleSystem::~ParticleSystem() {} void ParticleSystem::resize(std::size_t count) { particles.resize(count); batch.resize(count); range = batch.addRange(); range->start = 0; range->length = particles.size(); range->material = material; while (!stack.empty()) stack.pop(); for (int i = 0; i < particles.size(); ++i) { Particle& particle = particles[i]; particle.life = 0.0f; particle.size = 0.0f; Billboard* billboard = batch.getBillboard(i); billboard->setDimensions(Vector2(particle.size)); billboard->resetTweens(); stack.push(i); } } void ParticleSystem::emit(const Vector3& position) { if (!stack.empty()) { std::size_t index = stack.top(); stack.pop(); Particle& particle = particles[index]; particle.life = frand(1.0f, 5.0f); particle.translation = position; particle.size = frand(0.01f, 0.2f); particle.speed = frand(2.0f, 3.0f); particle.direction = direction + Vector3(frand(-1, 1), 0, frand(-1, 1)) * 0.1f; particle.direction = glm::normalize(particle.direction); Billboard* billboard = batch.getBillboard(index); billboard->setTranslation(particle.translation); billboard->setRotation(Quaternion(1, 0, 0, 0)); billboard->setDimensions(Vector2(particle.size)); billboard->setTintColor(Vector4(1.0f)); billboard->resetTweens(); } } void ParticleSystem::update(float t, float dt) { if (stack.size() == particles.size()) { // Inactive return; } batch.reset(); const Vector3 wind = glm::normalize(Vector3(1.0f, 0.0f, -1.0f)) * 1.5f * dt; float frequency = 0.4f; Vector3 noiseOffset = Vector3(77.7f, 33.3f, 11.1f) * t * 0.01f; for (std::size_t i = 0; i < particles.size(); ++i) { Particle& particle = particles[i]; if (particle.life <= 0.0f) { continue; } Billboard* billboard = batch.getBillboard(i); bool reset = false; Vector3 smoke = curl(particle.translation, noiseOffset, frequency) * 8.0f; particle.translation += particle.direction * particle.speed * dt + smoke * dt + wind; particle.size += 0.1f * dt; particle.life -= dt; if (particle.life <= 0.0f) { particle.size = 0.0f; reset = true; stack.push(i); } billboard->setTranslation(particle.translation); billboard->setRotation(Quaternion(1, 0, 0, 0)); billboard->setDimensions(Vector2(particle.size)); billboard->setTintColor(Vector4(0.5f)); if (reset) { billboard->resetTweens(); } } } void ParticleSystem::setMaterial(Material* material) { this->material = material; if (range) { range->material = material; } } void ParticleSystem::setDirection(const Vector3& direction) { this->direction = direction; } void ParticleSystem::setLifeTime(float time) { this->lifeTime = time; } void ParticleSystem::setEmissionRate(float frequency) { this->emissionRate = frequency; }