From 37d068e628a392b79620f5ed9e0ee6226b11cf47 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 20 Aug 2022 19:46:41 +0200 Subject: [PATCH] render: render distance 8, actually 28 FPS The previous 30 FPS was a lie; it forgot blatant problems with the computation. This is now fixed with 28 FPS on a full 10-side cylinder of render distance 8... which is definitely impressive at full resolution. Actual performance in game will be better due to way fewer platforms. --- src/main.cpp | 34 +++++++++++++++-- src/render.cpp | 100 +++++++++++++++++++++++++++++++++++++------------ src/render.h | 8 ++-- 3 files changed, 112 insertions(+), 30 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1e1c9e4..8739fdf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,10 +4,18 @@ #include #include #include +#include #include #include #include +#define RGB24(hex) \ + (((hex & 0xf80000) >> 8) | \ + ((hex & 0x00fc00) >> 5) | \ + ((hex & 0x0000f8) >> 3)) + +constexpr int bg = RGB24(0x49759f); + int main(void) { __printf_enable_fp(); @@ -19,9 +27,12 @@ int main(void) // azrp_shader_image_p4_configure(); azrp_shader_triangle_configure(); + render_init(); + level_t level = level_create(1); int volatile need_frame = 1; + int last_frame_us = 0; int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame)); timer_start(timer); @@ -33,8 +44,12 @@ int main(void) bool game_run = true; while(game_run) { + while(!need_frame) sleep(); + num dt = 1.0 / 30; t += dt; + prof_t perf_frame = prof_make(); + prof_enter_norec(perf_frame); level_update(&level); @@ -43,12 +58,15 @@ int main(void) //--- azrp_perf_clear(); - azrp_clear(C_WHITE); + azrp_clear(bg); struct camera camera; camera.pos = vec3(0, RENDER_CAMERA_DEPTH, 0); vec2 screen_size(DWIDTH, DHEIGHT); + prof_t perf_comp = prof_make(); + prof_enter_norec(perf_comp); + for(int depth = RENDER_SECTION_DISTANCE - 1; depth >= 0; depth--) { num z = depth * RENDER_SECTION_LENGTH - level_z; @@ -59,21 +77,24 @@ int main(void) struct prect p = render_platform_position(i, z); /* Near plane clipping */ - if(p.fl.z <= num(0.1) || p.fr.z <= num(0.1)) continue; + if(p.fl.z <= num(0.1)) continue; if(p.nl.z <= num(0.1)) p.nl.z = num(0.1); if(p.nr.z <= num(0.1)) p.nr.z = num(0.1); - camera_project_prect(&camera, &p, screen_size); + render_triangle(&p.nl, &p.fr, &p.fl, color); render_triangle(&p.fr, &p.nl, &p.nr, color); } } + prof_leave_norec(perf_comp); azrp_update(); drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE); - dprint(1, 210, C_BLACK, "render:%4d+%4dus level_z=%f", + dprint(4, 209, C_BLACK, "render:%4d+%4dus comp:%4dus(%02d FPS)", 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, (float)level_z); r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT); @@ -109,6 +130,11 @@ int main(void) level_z -= RENDER_SECTION_LENGTH; sections_passed++; } + + //--- + + prof_leave_norec(perf_frame); + last_frame_us = prof_time(perf_frame); } timer_stop(timer); diff --git a/src/render.cpp b/src/render.cpp index 75f45ec..49466de 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -10,6 +10,28 @@ static float get_alpha(void) return 2 * 3.14159 / PLATFORM_COUNT; } +num num_cos_dl(num a) +{ + num u = 1.0; + int p = 7; + for(p = 2 * p - 1; p >= 1; p -= 2) + u = num(1) - a * a / (p * p + p) * u; + return u; +} + +num num_cos(num a) +{ + if(a < 0) a = -a; + a = a % num(6.28319); + if(a > num(3.14159)) a -= num(6.28319); + return num_cos_dl(a); +} + +num num_sin(num a) +{ + return num_cos(a - num(1.57080)); +} + /* Get enlargement factor from FOV */ float get_near_plane(void) { @@ -17,31 +39,41 @@ float get_near_plane(void) return 2 * atanf(1 / fov_radians); } -vec3 vec_rotate_around_z(vec3 v, float angle) -{ - float sin_f, cos_f; - sincosf(angle, &sin_f, &cos_f); - num s=sin_f, c=cos_f; +static vec2 alpha_rotations[PLATFORM_COUNT]; - vec3 u; - u.x = c * v.x - s * v.y; - u.y = c * v.y + s * v.x; - u.z = v.z; - return u; +/* We can't use a constructor function because g++ already generates one which + uses the default 0-constructor and it would run after us, overriding the + computed values. */ +void render_init(void) +{ + float alpha = get_alpha(); + + for(int i = 0; i < PLATFORM_COUNT; i++) { + num angle = num(-alpha * i + (alpha / 2)); + alpha_rotations[i] = vec2(num_cos(angle), num_sin(angle)); + } +} + +vec3 vec_rotate_around_z(vec3 v, vec2 rotator) +{ + num c = rotator.x; + num s = rotator.y; + return vec3( + c * v.x - s * v.y, + c * v.y + s * v.x, + v.z); } struct prect render_platform_position(int platform_id, num z) { struct prect r; - float alpha = get_alpha(); vec3 radius(0, RENDER_RADIUS, 0); - /* +/- rather than -/+ because right-handed system */ - float angle_l = alpha * platform_id + (alpha / 2); - float angle_r = alpha * platform_id - (alpha / 2); + int angle_l = platform_id; + int angle_r = (platform_id + 1) % PLATFORM_COUNT; - r.nl = r.fl = vec_rotate_around_z(radius, angle_l); - r.nr = r.fr = vec_rotate_around_z(radius, angle_r); + r.nl = r.fl = vec_rotate_around_z(radius, alpha_rotations[angle_l]); + r.nr = r.fr = vec_rotate_around_z(radius, alpha_rotations[angle_r]); r.nl.z += z; r.nr.z += z; @@ -56,24 +88,46 @@ vec3 camera_project(struct camera *camera, vec3 u, vec2 screen_size) if(u.z <= 0) return u; - static float near_plane = get_near_plane(); + static num near_plane = get_near_plane(); int screen = screen_size.x < screen_size.y ? (int)screen_size.x / 2 : (int)screen_size.y / 2; - u.x = u.x * num(near_plane) * screen / u.z + screen_size.x / 2; - u.y = u.y * num(near_plane) * screen / u.z + screen_size.y / 2; + num f = near_plane * screen / u.z; + u.x = u.x * f + screen_size.x / 2; + u.y = u.y * f + screen_size.y / 2; return u; } void camera_project_prect(struct camera *camera, struct prect *p, vec2 screen_size) { - p->nl = camera_project(camera, p->nl, screen_size); - p->nr = camera_project(camera, p->nr, screen_size); - p->fl = camera_project(camera, p->fl, screen_size); - p->fr = camera_project(camera, p->fr, screen_size); + /* Require the rectangle to be already clipped */ + if(p->nl.z <= camera->pos.z) + return; + + static num near_plane = get_near_plane(); + + vec3 half_screen(screen_size.x / 2, screen_size.y / 2, 0); + int screen = half_screen.x < half_screen.y + ? (int)half_screen.x + : (int)half_screen.y; + + p->nl -= camera->pos; + p->nr -= camera->pos; + p->fl -= camera->pos; + p->fr -= camera->pos; + + /* We assume nl/nr have the same z, and so do fl/fr */ + num f = near_plane * screen; + num near_f = f / p->nl.z; + num far_f = f / p->fl.z; + + p->nl = p->nl * near_f + half_screen; + p->nr = p->nr * near_f + half_screen; + p->fl = p->fl * far_f + half_screen; + p->fr = p->fr * far_f + half_screen; } void render_triangle(vec3 *p1, vec3 *p2, vec3 *p3, int color) diff --git a/src/render.h b/src/render.h index 4ba9083..b5e1628 100644 --- a/src/render.h +++ b/src/render.h @@ -14,20 +14,22 @@ using namespace libnum; /* Section lengths, in world units */ #define RENDER_SECTION_LENGTH num(4.0) /* Number of sections visible in advance */ -#define RENDER_SECTION_DISTANCE 5 +#define RENDER_SECTION_DISTANCE 8 struct prect { vec3 nl, nr; /* Near left and near right points */ vec3 fl, fr; /* Far left and far right points */ }; -struct prect render_platform_position(int platform_id, num z); - /* We assume the camera is looking towards (0,0,z) */ struct camera { vec3 pos; }; +void render_init(void); + +struct prect render_platform_position(int platform_id, num z); + vec3 camera_project(struct camera *camera, vec3 u, vec2 screen_size); void camera_project_prect(struct camera *camera, struct prect *p,