blob: f63b61d7395e44df04ec76c90fab0cca9c62045c [file] [log] [blame] [edit]
#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);
}
}