diff --git a/src/game.h b/src/game.h index 77c0b23..6c6c14b 100644 --- a/src/game.h +++ b/src/game.h @@ -34,6 +34,8 @@ struct player void get_anim(struct anim **anim, int *frame); /* Current animation frame (fractional for variable animation speed). */ num frame; + /* Current blue platform animation state */ + num blueanim; /* Whether the player is airborne. */ bool airborne() const { return this->stance != Running; } diff --git a/src/main.cpp b/src/main.cpp index b845e2d..5b72289 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -106,6 +106,7 @@ int play_level(int level_id) player->vz = 3.0; player->platform = 0; player->stance = player::Falling; + player->blueanim = 0.0; player->jump_dir = 0; player->jump_t = 0.0; player->height = 1.0; @@ -132,6 +133,13 @@ int play_level(int level_id) camera->platform, str(camera->angle_vector)); + if(level_id == 4) { + player->energy_percent = 350.0; + player->height = num(-10.0); + game.t_death = num(10.0); + level_update(&game.level, num(350.0)); + } + bool game_run = true; while(game_run) { while(!need_frame) sleep(); @@ -305,6 +313,20 @@ int play_level(int level_id) standing_on->falling = true; } + /* Blue platform animation progress */ + if(standing_on && standing_on->type == PLATFORM_BLUE) { + player->blueanim += dt; + if(player->blueanim >= num(2.0)) + player->blueanim -= num(2.0); + } + else if(player->blueanim > 0) { + if(player->blueanim < num(2.0)) + player->blueanim = num(2.0); + player->blueanim += dt; + if(player->blueanim >= num(2.5)) + player->blueanim = 0; + } + for(auto &p: game.level.platform_buffer) { if(p.type == PLATFORM_RED && p.falling) { p.height -= PLATFORM_FALL_SPEED * dt; diff --git a/src/render.cpp b/src/render.cpp index 66a3c30..c02c2df 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -5,6 +5,7 @@ #include "game.h" #include "util.h" #include +#include void camera::set_fov(num fov) { @@ -119,7 +120,7 @@ static void gradient(uint32_t RGB1, uint32_t RGB2, uint16_t *gradient, int N) void render_init(void) { /* Generate a gradient ramp for blue platforms */ - gradient(0x5090d0, 0x2060b0, blue_ramp, 32); + gradient(0x56a3ef, 0x25c5ba, blue_ramp, 32); } uint16_t render_color_blue_platform(num t) @@ -169,6 +170,18 @@ void render_anim_frame(int x, int y, struct anim *anim, int frame) anim->frames[frame]); } +void render_anim_frame_palette(int x, int y, struct anim *anim, int frame, + uint16_t const *palette) +{ + image_t img = *anim->frames[frame]; + img.palette = (uint16_t *)palette; + + azrp_image( + x + anim->x_offsets[frame] - anim->x_anchor, + y + anim->y_offsets[frame] - anim->y_anchor, + &img); +} + static bool render_energy_str_glyph_params(int size, int c, int *ix, int *w) { size = (size >= 1 && size <= 3) ? size-1 : 0; @@ -229,55 +242,66 @@ void render_energy_str(int x, int y, int halign, int size, char const *str) } } -void render_effect_bpp(image_t **image, num t) +static void render_effect_bpp_internal(image_t **image, num16 t) { - enum { BPP_PARTICLE = 0x81 }; static uint16_t bpp_palette[] = { - [0] = RGB24(0xff00ff), /* alpha */ - [BPP_PARTICLE-0x80] = RGB24(0x5090d0), + RGB24(0xff00ff), /* alpha */ + C_WHITE, }; - static int const bpp_W = 34; + static int const bpp_W = 35; static int const bpp_H = 68; if(!*image) { *image = image_alloc(bpp_W, bpp_H, IMAGE_P8_RGB565A); + if(!*image) + return; image_set_palette(*image, bpp_palette, 2, false); } - image_clear(*image); uint8_t *pixels = (uint8_t *)(*image)->data; - for(int i = 0; i < 24; i++) { - /* Particule #i appears after i 32-th of a second */ - num start = num(i) / 32; + for(int i = 0; i < 32; i++) { + /* Particule #i is visible from t=i/32 until t=i/32+1. Local time + variable is normalized to 0..1. */ + num16 start = num16(i) / 32; if(t < start) continue; - num16 local_time = num16(2 * ((t - start) % num(0.5))); - // if(local_time < num16(0) || local_time >= num16(1)) - // abort(); + num16 local_time = (t - start) % num16(1); - int x0_int = (23 * i) % (bpp_W - 2); + int x0_int = (bpp_W / 2 - 17) + (((967 * i) >> 4) & 31); + /* 0+(...)&31 => [0,31] = [0,W-3] */ num16 x0 = num16(x0_int); - num16 y0 = num16(bpp_H - 3 - ((37 * i) & 15)); + num16 y0 = num16(bpp_H - 4 - ((37 * i) & 15)); /* [H-19, H-4] */ - num16 vx = num16(bpp_W / 2 - x0_int) / 4; + num16 vx = num16(bpp_W / 2 - x0_int) / 2; num16 x = x0 + vx * local_time; - num16 y = y0 - (bpp_H - 18) * local_time; + num16 y = y0 - (bpp_H - 19) * local_time; /* (0, H-4] */ - for(int dy = 0; dy <= 3; dy++) - for(int dx = 0; dx <= 3; dx++) { + int size = 4 - (y.ifloor() >> 4); + + for(int dy = 0; dy <= size; dy++) + for(int dx = 0; dx <= size; dx++) { // if((unsigned)((int)y + dy) >= bpp_H) // abort(); // if((unsigned)((int)x + dx) >= bpp_W) // abort(); - pixels[((int)y + dy) * (*image)->stride + (int)x + dx] = - BPP_PARTICLE; + pixels[((int)y + dy) * (*image)->stride + (int)x + dx] = 0x81; } } } +void render_effect_bpp(image_t **image, num global_t) +{ + /* Time within the animation (loops every second). Two segments: + - t = [0..1) for the animation startup (particles appear progressively) + - t = [1..2) for the loop (all particles visible) */ + num16 t = num16(global_t).frac() + num16(global_t >= 1); + + return render_effect_bpp_internal(image, t); +} + void render_effect_dp(int x, int y, int count, num t, int color) { for(int i = 0; i < count; i++) { @@ -353,7 +377,6 @@ void render_game(struct game &game, prof_t *perf_comp) struct player *player = &game.player; vec3 player_dot = camera_project_point(&game.camera, player->pos()); bool alive = (player->stance != player::Collided); - struct platform *standing_on = game_platform_under_player(&game, player); char energy_str[32]; sprintf(energy_str, "%.2f%%", (float)player->energy_percent); @@ -373,17 +396,33 @@ void render_game(struct game &game, prof_t *perf_comp) struct anim *player_anim; int player_frame; player->get_anim(&player_anim, &player_frame); - render_anim_frame((int)player_dot.x, (int)player_dot.y, - player_anim, player_frame); - if(standing_on && standing_on->type == PLATFORM_BLUE) { + /* Make a bluer palette palette when running on blue platforms */ + uint16_t palette[16]; + int blue_tint_alpha = 0; + if(player->blueanim > 0) { + num t = (player->blueanim >= 2) + ? (num(2.5) - player->blueanim) / 2 + : min(player->blueanim, num(0.25)); + blue_tint_alpha = (t * 96).ifloor(); + } + for(int i = 0; i < 16; i++) { + palette[i] = render_blend( + player_anim->frames[player_frame]->palette[i], + RGB24(0xb0d0f0), blue_tint_alpha); + } + + render_anim_frame_palette((int)player_dot.x, (int)player_dot.y, + player_anim, player_frame, palette); + + if(player->blueanim > 0) { prof_enter(game.perf.effect_bpp); - render_effect_bpp(&_effect_bpp, game.t); + render_effect_bpp(&_effect_bpp, player->blueanim); azrp_image((int)player_dot.x - _effect_bpp->width / 2, (int)player_dot.y - _effect_bpp->height + 2, _effect_bpp); prof_leave(game.perf.effect_bpp); - } + } /* Render energy score */ azrp_rect(DWIDTH-100, 4, 96, 20, AZRP_RECT_DARKEN); @@ -466,6 +505,16 @@ void render_game(struct game &game, prof_t *perf_comp) // TODO: Level-specific particle trace animation color? shader_ptrace(xe, ye, C_RGB(24, 24, 8), game.level.bgcolor, game.player.energy_percent >= 100, t_endscreen - num(0.6)); + + /* + // Debugging overflows on BPP effect + static num16 t = 0; + render_effect_bpp_internal(&_effect_bpp, t); + t.v = (t.v + 1) & 511; + azrp_image(azrp_width / 2 - _effect_bpp->width / 2, + azrp_height / 2 - _effect_bpp->height + 2, + _effect_bpp); + */ } } diff --git a/src/settings.h b/src/settings.h index 2b3c085..8815fa5 100644 --- a/src/settings.h +++ b/src/settings.h @@ -38,7 +38,7 @@ using namespace libnum; /* Vertical FOV, in degrees */ #define RENDER_FOV 120.0 /* Height of camera above the player's feet, in world units */ -#define RENDER_EYE_HEIGHT num(1.0) +#define RENDER_EYE_HEIGHT num(1.15) /* Number of sections visible in advance */ #define RENDER_DISTANCE 8 /* Distance between the player and the camera */