2022-08-20 16:32:37 +02:00
|
|
|
#include "level.h"
|
|
|
|
#include "generator.h"
|
2022-08-20 16:31:49 +02:00
|
|
|
#include "render.h"
|
2022-08-27 14:03:44 +02:00
|
|
|
#include "game.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "log.h"
|
2022-09-03 16:42:53 +02:00
|
|
|
#include "menu.h"
|
2022-08-27 14:03:44 +02:00
|
|
|
|
2022-08-20 11:51:24 +02:00
|
|
|
#include <gint/display.h>
|
|
|
|
#include <gint/keyboard.h>
|
|
|
|
#include <gint/timer.h>
|
2022-08-27 14:03:44 +02:00
|
|
|
#include <gint/clock.h>
|
2022-08-20 19:46:41 +02:00
|
|
|
#include <gint/cpu.h>
|
2022-08-20 11:51:24 +02:00
|
|
|
#include <azur/gint/render.h>
|
|
|
|
#include <gint/drivers/r61524.h>
|
2022-08-20 16:31:49 +02:00
|
|
|
#include <fxlibc/printf.h>
|
2022-09-03 16:42:53 +02:00
|
|
|
#include <gint/gint.h>
|
2022-08-20 16:31:49 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
int play_level(int level_id)
|
2022-08-20 11:51:24 +02:00
|
|
|
{
|
2022-08-27 14:03:44 +02:00
|
|
|
struct game game;
|
|
|
|
struct camera *camera = &game.camera;
|
|
|
|
struct player *player = &game.player;
|
|
|
|
|
|
|
|
game.level = level_create(level_id);
|
|
|
|
game.t = 0.0;
|
|
|
|
game.sections_passed = 0;
|
|
|
|
game.debug.footer = false;
|
|
|
|
|
|
|
|
camera->set_fov(120.0);
|
|
|
|
camera->screen_size = vec2(DWIDTH, DHEIGHT);
|
|
|
|
|
|
|
|
player->z = 0.0;
|
|
|
|
player->vz = 4.0;
|
|
|
|
player->platform = 0;
|
|
|
|
player->stance = player::Running;
|
|
|
|
player->jump_dir = 0;
|
|
|
|
player->jump_t = 0.0;
|
|
|
|
|
|
|
|
/* FPS regulation setup */
|
2022-08-20 17:55:41 +02:00
|
|
|
int volatile need_frame = 1;
|
2022-08-20 19:46:41 +02:00
|
|
|
int last_frame_us = 0;
|
2022-08-20 11:51:24 +02:00
|
|
|
int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame));
|
|
|
|
timer_start(timer);
|
2022-08-20 17:55:41 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
camera_track(camera, player);
|
|
|
|
log_printf("platform distance: %s\n", str(space_platform_distance()));
|
|
|
|
log_printf("player: at %s\n", str(player->pos()));
|
|
|
|
log_printf("camera: at %s, screen distance %s, platform %d, "
|
|
|
|
"angle vector %s\n",
|
|
|
|
str(camera->pos),
|
|
|
|
str(camera->screen_distance()),
|
|
|
|
camera->platform,
|
|
|
|
str(camera->angle_vector));
|
2022-08-20 22:40:03 +02:00
|
|
|
|
2022-08-20 16:31:49 +02:00
|
|
|
bool game_run = true;
|
|
|
|
while(game_run) {
|
2022-08-20 19:46:41 +02:00
|
|
|
while(!need_frame) sleep();
|
2022-08-20 21:43:02 +02:00
|
|
|
need_frame = 0;
|
2022-08-20 19:46:41 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
//======= Initial data updates =======//
|
|
|
|
|
2022-08-20 17:55:41 +02:00
|
|
|
num dt = 1.0 / 30;
|
2022-08-27 14:03:44 +02:00
|
|
|
game.t += dt;
|
2022-08-20 19:46:41 +02:00
|
|
|
prof_t perf_frame = prof_make();
|
|
|
|
prof_enter_norec(perf_frame);
|
2022-08-20 11:51:24 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
level_update(&game.level);
|
|
|
|
camera_track(camera, player);
|
2022-08-20 11:51:24 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
//======= Rendering =======//
|
2022-08-20 17:55:41 +02:00
|
|
|
|
2022-08-20 15:18:14 +02:00
|
|
|
azrp_perf_clear();
|
2022-08-27 14:03:44 +02:00
|
|
|
azrp_clear(RGB24(0x49759f));
|
2022-08-20 16:31:49 +02:00
|
|
|
|
2022-08-20 19:46:41 +02:00
|
|
|
prof_t perf_comp = prof_make();
|
|
|
|
prof_enter_norec(perf_comp);
|
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
for(int depth = RENDER_DISTANCE - 1; depth >= 0; depth--) {
|
|
|
|
num z = (game.sections_passed + depth) * SECTION_LENGTH;
|
|
|
|
struct section *s = &game.level.section_buffer[depth];
|
2022-08-20 17:55:41 +02:00
|
|
|
|
|
|
|
for(int i = 0; i < PLATFORM_COUNT; i++) {
|
2022-08-20 21:43:02 +02:00
|
|
|
/* Set this to get the full tunnel test */
|
|
|
|
constexpr bool full_tunnel = false;
|
2022-08-24 20:40:21 +02:00
|
|
|
/* Set this to get the OG full tunnel coloring */
|
|
|
|
constexpr bool og_coloring = false;
|
|
|
|
|
2022-08-20 21:43:02 +02:00
|
|
|
int color = C_WHITE;
|
|
|
|
|
2022-08-24 20:40:21 +02:00
|
|
|
if(!full_tunnel && s->platforms[i].type != PLATFORM_WHITE)
|
|
|
|
continue;
|
|
|
|
if(og_coloring) {
|
2022-08-27 14:03:44 +02:00
|
|
|
int j = i + depth + game.sections_passed;
|
|
|
|
int gray = (j % PLATFORM_COUNT) * 31 / PLATFORM_COUNT;
|
2022-08-20 21:43:02 +02:00
|
|
|
color = C_RGB(gray, gray, gray);
|
|
|
|
}
|
|
|
|
else {
|
2022-08-27 14:03:44 +02:00
|
|
|
color = camera_platform_color(&game.camera, i);
|
2022-08-20 21:43:02 +02:00
|
|
|
}
|
2022-08-20 17:55:41 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
struct prect p = space_platform_position(i, z);
|
2022-08-20 17:55:41 +02:00
|
|
|
/* Near plane clipping */
|
2022-08-27 14:03:44 +02:00
|
|
|
num near = camera->pos.z + camera->near_plane();
|
|
|
|
if(p.fl.z <= near) continue;
|
|
|
|
if(p.nl.z <= near) p.nl.z = near;
|
|
|
|
if(p.nr.z <= near) p.nr.z = near;
|
|
|
|
camera_project_prect(&game.camera, &p);
|
2022-08-20 19:46:41 +02:00
|
|
|
|
2022-08-20 17:55:41 +02:00
|
|
|
render_triangle(&p.nl, &p.fr, &p.fl, color);
|
|
|
|
render_triangle(&p.fr, &p.nl, &p.nr, color);
|
2022-08-27 14:03:44 +02:00
|
|
|
|
2022-08-20 17:55:41 +02:00
|
|
|
}
|
2022-08-20 16:31:49 +02:00
|
|
|
}
|
2022-08-27 14:03:44 +02:00
|
|
|
|
|
|
|
/* Render player */
|
2022-09-03 16:42:53 +02:00
|
|
|
vec3 player_dot = camera_project_point(
|
|
|
|
&game.camera,
|
|
|
|
player->pos()
|
|
|
|
);
|
|
|
|
render_sprite({ player_dot }, player->anim());
|
2022-08-27 14:03:44 +02:00
|
|
|
|
2022-08-20 19:46:41 +02:00
|
|
|
prof_leave_norec(perf_comp);
|
2022-08-20 11:51:24 +02:00
|
|
|
azrp_update();
|
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
if(game.debug.footer) {
|
2022-08-20 21:43:02 +02:00
|
|
|
drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE);
|
|
|
|
dprint(4, 209, C_BLACK, "render:%4d+%4dus comp:%4dus FPS:%02d",
|
|
|
|
prof_time(azrp_perf_render) - prof_time(azrp_perf_r61524),
|
|
|
|
prof_time(azrp_perf_r61524),
|
|
|
|
prof_time(perf_comp),
|
|
|
|
last_frame_us ? 1000000 / last_frame_us : 0);
|
|
|
|
r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT);
|
|
|
|
}
|
2022-08-20 11:51:24 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
//======= Input =======//
|
2022-08-20 16:31:49 +02:00
|
|
|
|
|
|
|
key_event_t ev;
|
|
|
|
while((ev = pollevent()).type != KEYEV_NONE) {
|
2022-08-27 14:03:44 +02:00
|
|
|
if(ev.type == KEYEV_UP || ev.type == KEYEV_HOLD)
|
2022-08-20 16:31:49 +02:00
|
|
|
continue;
|
2022-08-27 14:03:44 +02:00
|
|
|
int key = ev.key;
|
2022-08-20 16:31:49 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
if(key == KEY_EXIT || key == KEY_MENU)
|
2022-08-20 16:31:49 +02:00
|
|
|
game_run = false;
|
2022-08-27 14:03:44 +02:00
|
|
|
if(key == KEY_OPTN)
|
|
|
|
game.debug.footer = !game.debug.footer;
|
|
|
|
if(key == KEY_F1) {
|
|
|
|
game.level = level_create(1);
|
|
|
|
level_update(&game.level);
|
|
|
|
}
|
|
|
|
if(key == KEY_F2) {
|
|
|
|
game.level = level_create(2);
|
|
|
|
level_update(&game.level);
|
2022-08-20 21:43:02 +02:00
|
|
|
}
|
2022-08-27 14:03:44 +02:00
|
|
|
if(key == KEY_F3) {
|
|
|
|
game.level = level_create(3);
|
|
|
|
level_update(&game.level);
|
2022-08-20 21:43:02 +02:00
|
|
|
}
|
2022-08-27 14:03:44 +02:00
|
|
|
if(key == KEY_LEFT && !player->airborne()) {
|
|
|
|
player->stance = player::Jumping;
|
|
|
|
player->jump_dir = -1;
|
|
|
|
player->jump_t = 0.0;
|
|
|
|
player->jump_key = key;
|
2022-09-03 16:42:53 +02:00
|
|
|
player->frame = 0;
|
2022-08-20 21:43:02 +02:00
|
|
|
}
|
2022-08-27 14:03:44 +02:00
|
|
|
if((key == KEY_UP || key == KEY_SHIFT) && !player->airborne()) {
|
|
|
|
player->stance = player::Jumping;
|
|
|
|
player->jump_dir = 0;
|
|
|
|
player->jump_t = 0.0;
|
|
|
|
player->jump_key = key;
|
2022-09-03 16:42:53 +02:00
|
|
|
player->frame = 0;
|
2022-08-20 23:08:30 +02:00
|
|
|
}
|
2022-08-27 14:03:44 +02:00
|
|
|
if(key == KEY_RIGHT && !player->airborne()) {
|
|
|
|
player->stance = player::Jumping;
|
|
|
|
player->jump_dir = +1;
|
|
|
|
player->jump_t = 0.0;
|
|
|
|
player->jump_key = key;
|
2022-09-03 16:42:53 +02:00
|
|
|
player->frame = 0;
|
2022-08-20 23:08:30 +02:00
|
|
|
}
|
2022-08-20 16:31:49 +02:00
|
|
|
}
|
2022-08-20 17:55:41 +02:00
|
|
|
|
|
|
|
if(!game_run) break;
|
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
//======= Simulation =======//
|
2022-08-20 17:55:41 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
player->z += player->vz * dt;
|
|
|
|
|
|
|
|
/* Increase player's height during the ascending part of a jump */
|
|
|
|
if(player->stance == player::Jumping) {
|
|
|
|
player->height += JUMP_SPEED * dt;
|
|
|
|
player->jump_t += dt;
|
|
|
|
|
|
|
|
/* Release the jump after the max time has elapsed */
|
|
|
|
if(player->jump_t > TIME_JUMP_THRUST_MAX)
|
|
|
|
player->stance = player::Falling;
|
|
|
|
/* Also do it if the key has been released */
|
|
|
|
if(player->jump_t > TIME_JUMP_THRUST_MIN
|
|
|
|
&& !keydown(player->jump_key))
|
|
|
|
player->stance = player::Falling;
|
|
|
|
}
|
|
|
|
/* TODO: Apply gravity properly */
|
|
|
|
else if(player->stance == player::Falling) {
|
|
|
|
player->height -= GRAVITY_STRENGTH * dt;
|
|
|
|
player->jump_t += dt;
|
2022-08-20 17:55:41 +02:00
|
|
|
}
|
2022-08-20 19:46:41 +02:00
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
/* Update the current platform number after rotation */
|
|
|
|
if(player->airborne()) {
|
|
|
|
if(player->jump_t > TIME_ROTATION && player->jump_dir) {
|
|
|
|
int p = player->platform + player->jump_dir;
|
2022-08-20 23:08:30 +02:00
|
|
|
p = (p + PLATFORM_COUNT) % PLATFORM_COUNT;
|
2022-08-27 14:03:44 +02:00
|
|
|
player->platform = p;
|
|
|
|
player->jump_dir = 0;
|
2022-08-20 23:08:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
/* TODO: Reset jump after contact on platforms, not distance */
|
|
|
|
if(player->airborne()) {
|
|
|
|
if(player->height <= 0) {
|
|
|
|
player->stance = player::Running;
|
|
|
|
player->jump_dir = 0;
|
|
|
|
player->jump_t = 0.0;
|
|
|
|
player->height = 0;
|
|
|
|
player->jump_key = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Eliminate dead platforms so new ones can be generated. We include
|
|
|
|
the camera's distance in the calculation because we only remove
|
|
|
|
platforms that have been passed *and* are now invisible. */
|
|
|
|
while(player->z - RENDER_CAMERA_BACK_DISTANCE >
|
|
|
|
(game.sections_passed + 1) * SECTION_LENGTH) {
|
|
|
|
level_advance(&game.level);
|
|
|
|
game.sections_passed++;
|
|
|
|
}
|
2022-08-20 19:46:41 +02:00
|
|
|
|
|
|
|
prof_leave_norec(perf_frame);
|
|
|
|
last_frame_us = prof_time(perf_frame);
|
2022-08-20 11:51:24 +02:00
|
|
|
}
|
|
|
|
|
2022-08-20 17:55:41 +02:00
|
|
|
timer_stop(timer);
|
2022-08-20 16:31:49 +02:00
|
|
|
return 0;
|
2022-08-20 11:51:24 +02:00
|
|
|
}
|
2022-08-27 14:03:44 +02:00
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
2022-09-03 16:42:53 +02:00
|
|
|
int level;
|
|
|
|
|
2022-08-27 14:03:44 +02:00
|
|
|
__printf_enable_fp();
|
|
|
|
prof_init();
|
|
|
|
game_init();
|
|
|
|
|
|
|
|
#if LOG_USB_ENABLE
|
|
|
|
dclear(C_WHITE);
|
|
|
|
dtext_opt(DWIDTH/2, DHEIGHT/2, C_BLACK, C_NONE, DTEXT_CENTER, DTEXT_MIDDLE,
|
|
|
|
"Waiting for USB log...", -1);
|
|
|
|
dupdate();
|
|
|
|
log_init(true);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
azrp_config_scale(1);
|
|
|
|
azrp_shader_clear_configure();
|
|
|
|
azrp_shader_image_p8_configure();
|
2022-09-03 16:42:53 +02:00
|
|
|
azrp_shader_image_p4_configure();
|
2022-08-27 14:03:44 +02:00
|
|
|
azrp_shader_triangle_configure();
|
|
|
|
|
2022-09-03 16:42:53 +02:00
|
|
|
while (1) {
|
|
|
|
if (menu_title() != 0) {
|
|
|
|
gint_osmenu();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while (menu_select_level(&level) >= 0) {
|
|
|
|
play_level(level);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2022-08-27 14:03:44 +02:00
|
|
|
}
|