| #include <string> |
| #include <cstring> |
| #include <memory> |
| #include <cstdlib> |
| |
| #include "particle.hpp" |
| |
| using namespace blit; |
| |
| |
| |
| /* setup */ |
| void init() { |
| blit::set_screen_mode(ScreenMode::hires); |
| } |
| |
| struct test_particle { |
| Vec2 pos; |
| Vec2 vel; |
| int age; |
| bool generated = false; |
| }; |
| |
| |
| struct smoke_particle : Particle { |
| float age_boost; |
| |
| smoke_particle(Vec2 pos, Vec2 vel, float age_boost) : Particle(pos, vel), age_boost(age_boost) {}; |
| }; |
| |
| Particle* generate_smoke() { |
| return new smoke_particle( |
| Vec2((rand() % 20) - 10, (rand() % 20) - 10), |
| Vec2(((rand() % 40) - 20) / 2, (rand() % 20) - 60), |
| (rand() % 3000) / 3000.0f |
| ); |
| } |
| |
| ParticleGenerator smoke_generator(150, 4000, generate_smoke); |
| |
| void render_smoke() { |
| for (auto p : smoke_generator.particles) { |
| smoke_particle *sp = static_cast<smoke_particle*>(p); |
| float age = sp->age + sp->age_boost; |
| int alpha = (255 - (age * 75.0f)) / 8.0f; |
| int radius = (age * 150.0f) / 16.0f; |
| screen.pen = Pen(255, 255, 255, alpha); |
| screen.circle(p->pos + Point(50, 240), radius); |
| } |
| } |
| |
| |
| void smoke_generate(test_particle &p) { |
| p.pos = Vec2((rand() % 20) - 10, (rand() % 20) - 10); |
| p.vel = Vec2(((rand() % 40) - 20) / 2, (rand() % 20) - 60); |
| p.age = rand() % 200; |
| p.generated = true; |
| }; |
| |
| void smoke(uint32_t time_ms) { |
| static test_particle s[150]; |
| static int generate_index = 0; |
| static uint32_t last_time_ms = time_ms; |
| |
| int elapsed_ms = time_ms - last_time_ms; |
| float td = (elapsed_ms) / 1000.0f; |
| |
| smoke_generate(s[generate_index++]); |
| if (generate_index >= 150) |
| generate_index = 0; |
| |
| float w = sinf(time_ms / 1000.0f) * 0.05f; |
| |
| for (auto &p : s) { |
| if (p.generated) { |
| p.pos += p.vel * td; |
| p.vel += Vec2(w, 0); |
| p.age++; |
| |
| int alpha = (255 - (p.age / 2)) / 8.0f; |
| int radius = (p.age) / 16.0f; |
| screen.pen = Pen(255, 255, 255, alpha); |
| screen.circle(p.pos + Point(50, 240), radius); |
| } |
| } |
| |
| |
| last_time_ms = time_ms; |
| }; |
| |
| |
| void spark_generate(test_particle &p) { |
| p.pos = Vec2((rand() % 10) - 5, -100); |
| p.vel = Vec2(((rand() % 40) - 20), (rand() % 80) - 70); |
| p.age = 0;// rand() % 255; |
| p.generated = true; |
| }; |
| |
| void spark(uint32_t time_ms) { |
| static test_particle s[500]; |
| static int generate_index = 0; |
| static uint32_t last_time_ms = time_ms; |
| |
| int elapsed_ms = time_ms - last_time_ms; |
| float td = (elapsed_ms) / 1000.0f; |
| |
| spark_generate(s[generate_index++]); |
| if (generate_index >= 500) |
| generate_index = 0; |
| |
| float w = sinf(time_ms / 1000.0f) * 0.05f; |
| |
| Vec2 gravity = Vec2(0, 9.8f * 2) * td; |
| |
| for (auto &p : s) { |
| if (p.generated) { |
| p.vel += gravity; |
| p.pos += p.vel * td; |
| if (p.pos.y > 0) |
| p.vel.y *= -0.7f; |
| p.age++; |
| |
| int a = p.age / 2; |
| int r = 255 - (p.age / 2); |
| int g = 255 - (a * 2); |
| g = g < 0 ? 0 : g; |
| int b = 255 - (a * 4); |
| b = b < 0 ? 0 : b; |
| |
| int bloom = (255 - a) / 64; |
| screen.pen = Pen(r, g, b, 16); |
| screen.circle(p.pos + Point(160, 240), bloom); |
| screen.pen = Pen(r, g, b, 16); |
| screen.circle(p.pos + Point(160, 240), bloom / 2); |
| |
| screen.pen = Pen(r, g, b); |
| screen.pixel(p.pos + Point(160, 240)); |
| |
| } |
| } |
| |
| last_time_ms = time_ms; |
| }; |
| |
| |
| void rain_generate(test_particle &p) { |
| p.pos = Vec2((rand() % 80) - 40, (rand() % 10) - 250); |
| p.vel = Vec2(0, 140); |
| p.age = 0;// rand() % 255; |
| p.generated = true; |
| }; |
| |
| Vec2 g = Vec2(0, 9.8 * 5); |
| |
| void rain(uint32_t time_ms) { |
| static test_particle s[200]; |
| static int generate_index = 0; |
| static uint32_t last_time_ms = time_ms; |
| |
| int elapsed_ms = time_ms - last_time_ms; |
| float td = (elapsed_ms) / 1000.0f; |
| |
| rain_generate(s[generate_index++]); |
| if (generate_index >= 200) |
| generate_index = 0; |
| |
| float w = sinf(time_ms / 1000.0f) * 0.05f; |
| |
| Vec2 gravity = g * td; |
| |
| for (auto &p : s) { |
| if (p.generated) { |
| p.vel += gravity; |
| p.pos += p.vel * td; |
| |
| int floor = -3; |
| if (p.pos.x > 20 && p.pos.x < 46) |
| floor = -33; |
| |
| if (p.pos.y >= floor) { |
| p.pos.y = floor; |
| float bounce = ((rand() % 10)) / 80.0f; |
| p.vel.y *= -bounce; |
| p.vel.x = ((rand() % 30) - 15); |
| } |
| p.age++; |
| |
| int a = p.age / 2; |
| int r = 150 - (a / 2); |
| int g = 150 - (a / 2); |
| int b = 255;// -(a * 4); |
| |
| if(p.vel.length() > 20) { |
| screen.pen = Pen(r, g, b, 100); |
| screen.pixel(p.pos + Point(270, 239)); |
| screen.pen = Pen(r, g, b, 160); |
| screen.pixel(p.pos + Point(270, 241)); |
| } |
| screen.pen = Pen(r, g, b, 180); |
| screen.pixel(p.pos + Point(270, 242)); |
| } |
| } |
| |
| last_time_ms = time_ms; |
| }; |
| |
| |
| |
| Particle* generate_basic_rain() { |
| return new Particle( |
| Vec2((std::rand() % 120) + 100, 0), |
| Vec2(0, 100) |
| ); |
| } |
| |
| ParticleGenerator basic_rain_generator(250, 4000, generate_basic_rain); |
| |
| void render_basic_rain() { |
| for (auto p : basic_rain_generator.particles) { |
| Particle *sp = static_cast<Particle*>(p); |
| if (sp->pos.y >= 239) { |
| sp->pos.y = 239; |
| } |
| screen.pen = Pen(128, 128, 255); |
| screen.pixel(sp->pos); |
| } |
| } |
| |
| uint32_t prev_buttons = blit::buttons; |
| |
| void render(uint32_t time_ms) { |
| if ((blit::buttons ^ prev_buttons) & blit::Button::A) { |
| blit::set_screen_mode(blit::lores); |
| } |
| else if ((blit::buttons ^ prev_buttons) & blit::Button::B) { |
| blit::set_screen_mode(blit::hires); |
| } |
| prev_buttons = blit::buttons; |
| |
| screen.pen = Pen(0, 0, 0, 255); |
| screen.clear(); |
| |
| //render_smoke(); |
| |
| uint32_t ms_start = now(); |
| spark(time_ms); |
| smoke(time_ms); |
| rain(time_ms); |
| //render_basic_rain(); |
| uint32_t ms_end = now(); |
| |
| // draw grid |
| screen.alpha = 255; |
| screen.pen = Pen(255, 255, 255); |
| screen.rectangle(Rect(0, 0, 320, 14)); |
| screen.pen = Pen(0, 0, 0); |
| screen.text("Rain demo", minimal_font, Point(5, 4)); |
| |
| /* screen.pen = Pen(255, 255, 255); |
| screen.text("Smoke:", minimal_font, point(10, 20)); |
| screen.text("Sparks:", minimal_font, point(120, 20)); |
| screen.text("Rain:", minimal_font, point(220, 20)); */ |
| |
| // draw FPS meter |
| /*screen.alpha = 255; |
| screen.pen = Pen(0, 0, 0); |
| screen.rectangle(rect(1, 240 - 10, 12, 9)); |
| screen.pen = Pen(255, 255, 255, 200); |
| std::string fms = std::to_string(ms_end - ms_start); |
| screen.text(fms, minimal_font, rect(3, 240 - 9, 10, 16)); |
| |
| int block_size = 4; |
| for (int i = 0; i < (ms_end - ms_start); i++) { |
| screen.pen = Pen(i * 5, 255 - (i * 5), 0); |
| screen.rectangle(rect(i * (block_size + 1) + 1 + 13, screen.bounds.h - block_size - 1, block_size, block_size)); |
| }*/ |
| |
| screen.watermark(); |
| } |
| |
| void update(uint32_t time_ms) { |
| // smoke_generator.update(time_ms); |
| basic_rain_generator.update(time_ms); |
| |
| if (pressed(Button::DPAD_LEFT)) { |
| g.rotate(0.1f); |
| } |
| } |