57 FireworksWindow(
const std::string &data_root,
int width,
int height,
bool fullscreen,
bool enable_vsync)
62 setFont(data_root +
"/font.ttf", 24);
63 last_update_time = SDL_GetTicks();
67 if (
device != VK_NULL_HANDLE) {
70 point_batch.cleanup();
73 void event(SDL_Event &e)
override {
74 if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE) {
76 }
else if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_SPACE) {
77 trigger_random_explosion();
82 if (!has_active_particles()) {
83 printText(
"Explosion - Press Space to Trigger", 25, 25, SDL_Color{255, 64, 64, 255});
88 point_batch.resize(
this);
92 if (!ensure_resources()) {
96 const Uint32 current_time = SDL_GetTicks();
97 float delta_time =
static_cast<float>(current_time - last_update_time) / 1000.0f;
98 last_update_time = current_time;
99 delta_time = std::min(delta_time, 0.1f);
101 update_particles(delta_time);
104 point_batch.upload_vertices(vertices.data(), active_vertices);
105 point_batch.update_mvp(image_index, make_mvp());
106 point_batch.render(cmd, image_index);
110 bool ensure_resources() {
111 if (point_batch.
loaded()) {
120 data_root +
"/star.png",
121 data_root +
"/fireworks.vert.spv",
122 data_root +
"/fireworks.frag.spv",
124 point_batch.set_additive_blending(
true);
125 point_batch.set_depth_test_enabled(
false);
126 point_batch.set_depth_write_enabled(
false);
127 last_update_time = SDL_GetTicks();
131 void trigger_random_explosion() {
135 void trigger_explosion(
const glm::vec3 &origin) {
136 if (explosions.size() >= MAX_EXPLOSIONS) {
141 explosion.particles.resize(PARTICLES_PER_EXPLOSION);
142 for (Particle &particle : explosion.particles) {
143 reset_particle(particle, origin);
145 explosions.push_back(std::move(explosion));
148 void reset_particle(Particle &particle,
const glm::vec3 &origin)
const {
149 particle.position = origin;
150 particle.velocity = glm::sphericalRand(PARTICLE_SPEED);
152 particle.initial_lifetime = particle.
lifetime;
156 void update_particles(
float delta_time) {
157 for (Explosion &explosion : explosions) {
158 for (Particle &particle : explosion.particles) {
163 particle.position += particle.velocity * delta_time;
164 particle.color.a = particle.
lifetime;
168 std::erase_if(explosions, [](
const Explosion &explosion) {
169 return std::ranges::none_of(explosion.particles, [](
const Particle &particle) {
170 return particle.lifetime > 0.0f;
175 [[nodiscard]]
bool has_active_particles()
const {
176 return std::ranges::any_of(explosions, [](
const Explosion &explosion) {
177 return std::ranges::any_of(explosion.particles, [](
const Particle &particle) {
178 return particle.lifetime > 0.0f;
183 void write_vertices() {
185 for (
const Explosion &explosion : explosions) {
186 for (
const Particle &particle : explosion.particles) {
187 if (particle.
lifetime <= 0.0f || active_vertices >= vertices.size()) {
191 mxvk::PointSpriteVertex &vertex = vertices[active_vertices++];
192 vertex.
position[0] = particle.position.
x;
193 vertex.
position[1] = particle.position.
y;
194 vertex.
position[2] = particle.position.z;
196 vertex.
color[0] = particle.color.r;
197 vertex.
color[1] = particle.color.g;
198 vertex.
color[2] = particle.color.b;
199 vertex.
color[3] = particle.color.a;
204 [[nodiscard]] glm::mat4 make_mvp()
const {
206 const float aspect = extent.height > 0U ?
static_cast<float>(extent.width) /
static_cast<float>(extent.height) :
SCENE_REFERENCE_ASPECT;
208 float vertical_field_of_view = glm::radians(VERTICAL_FIELD_OF_VIEW_DEGREES);
209 if (aspect < SCENE_REFERENCE_ASPECT) {
211 vertical_field_of_view = 2.0f * std::atan(reference_half_width / aspect);
214 glm::mat4 projection = glm::perspective(vertical_field_of_view, aspect, 0.1f, 100.0f);
215 projection[1][1] *= -1.0f;
216 const glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
217 const glm::mat4 model(1.0f);
218 return projection * view * model;
221 std::string data_root{};
222 std::vector<Explosion> explosions{};
223 std::vector<mxvk::PointSpriteVertex> vertices{};
224 mxvk::VK_PointSpriteBatch point_batch{};
225 std::size_t active_vertices = 0;
226 Uint32 last_update_time = 0;
int main(int argc, char **argv)