blob: 3c341a9a5d03344147087784fd187fe58cc0a70d [file] [log] [blame] [edit]
#include <string>
#include <cstring>
#include <memory>
#include <cstdlib>
#include "tilemap-test.hpp"
#include "assets.hpp"
using namespace blit;
TileMap* environment;
/* setup */
void init() {
blit::set_screen_mode(ScreenMode::lores);
screen.sprites = Surface::load(asset_platformer);
environment = new TileMap((uint8_t*)asset_tilemap, nullptr, Size(64, 64), screen.sprites);
}
float deg2rad(float a) {
return a * (pi / 180.0f);
}
uint32_t current_time;
static Mat3 dream(uint8_t y) {
float progress = (sinf(current_time / 2000.0f) + 1.0f) * 0.6f; // two second animation
progress = progress > 1.0f ? 1.0f : progress;
screen.alpha = progress * 255.0f;
float step = (current_time / 200.0f) + (y / 10.0f);
float x_offset = (sinf(step) * (cosf(step) * 50.0f)) * (1.0f - progress);
Mat3 transform = Mat3::translation(
Vec2(256, 156) + // offset to middle of world
Vec2(x_offset, 0) + // apply dream effect wave
Vec2(-80, -60) // transform to centre of framebuffer
);
return transform;
};
static Mat3 rotozoom(uint8_t y) {
float progress = (sinf(current_time / 2000.0f) + 1.0f) / 2.0f; // two second animation
float angle = (1.0f - progress) * 360.0f;
float scale = progress;
Mat3 transform = Mat3::identity();
transform *= Mat3::translation(Vec2(256, 156)); // offset to middle of world
transform *= Mat3::rotation(deg2rad(angle)); // apply rotation
transform *= Mat3::scale(Vec2(scale, scale)); // apply scaling
transform *= Mat3::translation(Vec2(-80, -60)); // transform to centre of framebuffer
return transform;
};
static Mat3 zoom(uint8_t y) {
float progress = (sinf(current_time / 1000.0f) + 1.0f) / 2.0f; // two second animation
float scale = progress;
Mat3 transform = Mat3::identity();
transform *= Mat3::translation(Vec2(256, 156)); // offset to middle of world
transform *= Mat3::scale(Vec2(scale, scale)); // apply zoom effect using scaling
transform *= Mat3::translation(Vec2(-80, -60)); // transform to centre of framebuffer
return transform;
};
static Mat3 perspective(uint8_t y) {
float progress = (sinf(current_time / 2000.0f) + 1.0f) / 2.0f; // two second animation
progress = progress > 1.0f ? 1.0f : progress;
screen.alpha = y + (255 - 120);
float scale = (y + 1) / 30.0f;
Mat3 transform = Mat3::identity();
transform *= Mat3::translation(Vec2(156, 130 + progress * 80.0f)); // offset to middle of world
transform *= Mat3::scale(Vec2(1.0f / scale, 1.0f / scale)); // apply scaling- increases with y to give a depth effect
transform *= Mat3::translation(Vec2(-80, -60)); // transform to centre of framebuffer
return transform;
};
static Mat3 water(uint8_t y) {
float step = (current_time / 200.0f) + (y / 10.0f);
float x_offset = (sinf(step) + sinf(step / 3.0f) + sinf(step * 2.0f)) * 2.0f;
Mat3 transform = Mat3::translation(
Vec2(156, 130) + // offset to middle of world
Vec2(x_offset, 0) + // apply a water ripple effect
Vec2(-80, -60) // transform to centre of framebuffer
);
return transform;
};
static Mat3 warp(uint8_t y) {
float step = (current_time / 1000.0f) + (y / 100.0f);
float x_offset = (sinf(step) * (cosf(step) * 50.0f));
float angle = sinf(current_time / 500.0f) * 50.0f;
Mat3 transform = Mat3::identity();
transform *= Mat3::translation(Vec2(140, 140)); // offset to middle of world
transform *= Mat3::translation(Vec2(x_offset, 0)); // apply dream effect wave
transform *= Mat3::rotation(deg2rad(angle)); // apply dream effect wave
transform *= Mat3::translation(Vec2(-80, -60)); // transform to centre of framebuffer
return transform;
};
static Mat3 ripple(uint8_t y) {
float step = (current_time / 250.0f) + (y / 25.0f);
float scale = (sinf(step) / 4.0f) + 1.0f;
Mat3 transform = Mat3::identity();
transform *= Mat3::translation(Vec2(256, 156)); // offset to middle of world
transform *= Mat3::scale(Vec2(scale, scale)); // apply dream effect wave
transform *= Mat3::translation(Vec2(-80, -60)); // transform to centre of framebuffer
return transform;
};
static Mat3 betamax(uint8_t y) {
float step = (current_time / 250.0f) + (y / 25.0f);
Point shake(0, 0);
int8_t scale = int8_t((sinf(step) + 1.0f) * 5);
if (scale > 0) {
shake = Point((blit::random() % scale) - scale / 2, (blit::random() % scale) - scale / 2);
}
Mat3 transform = Mat3::translation(
Vec2(256, 156) + // offset to middle of world
Vec2(shake) + // apply shake
Vec2(-80, -60) // transform to centre of framebuffer
);
return transform;
};
static Mat3 shake(uint8_t y) {
static uint32_t last_time = 0;
static Point shake(0, 0);
if (current_time != last_time) {
last_time = current_time;
uint8_t clamp = 20;
shake = Point(blit::random() % clamp, blit::random() % clamp);
float scale = sinf(current_time / 300.0f);
scale = scale < 0.0f ? 0.0f : scale;
shake *= scale;
}
Mat3 transform = Mat3::translation(
Vec2(256, 156) + // offset to middle of world
Vec2(shake) + // apply shake
Vec2(-80, -60) // transform to centre of framebuffer
);
return transform;
};
const std::function<Mat3(uint8_t)> effect_callbacks[]{
zoom,
dream,
ripple,
rotozoom,
warp,
perspective,
water,
betamax,
shake
};
const std::array<std::string, 9> effect_names{
"zoom",
"dream",
"ripple",
"rotozoom",
"warp",
"perspective",
"water",
"betamax",
"shake"
};
uint8_t effect = 0;
void render(uint32_t time_ms) {
current_time = time_ms;
screen.alpha = 255;
screen.pen = Pen(39, 39, 54);
screen.clear();
screen.alpha = 255;
screen.mask = nullptr;
uint32_t ms_start = now();
environment->draw(&screen, Rect(0, 0, 160, 120), effect_callbacks[effect]);
screen.alpha = 255;
for (auto i = 0u; i < effect_names.size(); i++) {
if (effect == i)
screen.pen = Pen(255, 255, 255);
else
screen.pen = Pen(255, 255, 255, 100);
screen.text(effect_names[i], minimal_font, Rect(5, 19 + (i * 10), 100, 10));
}
uint32_t ms_end = now();
/*
// draw FPS meter
screen.alpha = 255;
screen.pen = Pen(0, 0, 0);
screen.rectangle(Rect(1, 120 - 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, 120 - 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.pen = Pen(255, 255, 255);
screen.rectangle(Rect(0, 0, 320, 14));
screen.pen = Pen(0, 0, 0);
screen.text("Tilemap demo", minimal_font, Point(5, 4));
screen.watermark();
}
void update(uint32_t time) {
auto last_effect = uint8_t(effect_names.size() - 1);
if (buttons.pressed & Button::DPAD_DOWN) {
effect = effect == last_effect ? 0 : effect + 1;
}
if (buttons.pressed & Button::DPAD_UP) {
effect = effect == 0 ? last_effect : effect - 1;
}
}