BosonX/src/render.cpp

141 lines
3.3 KiB
C++
Raw Normal View History

#define __BSD_VISIBLE 1
#include "level.h"
#include "render.h"
#include <math.h>
#include <azur/gint/render.h>
/* Angle span for a platform in the level cylinder */
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)
{
float fov_radians = RENDER_FOV * 3.14159 / 180;
return 2 * atanf(1 / fov_radians);
}
static vec2 alpha_rotations[PLATFORM_COUNT];
/* 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;
vec3 radius(0, RENDER_RADIUS, 0);
int angle_l = platform_id;
int angle_r = (platform_id + 1) % PLATFORM_COUNT;
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;
r.fl.z += z + RENDER_SECTION_LENGTH;
r.fr.z += z + RENDER_SECTION_LENGTH;
return r;
}
vec3 camera_project(struct camera *camera, vec3 u, vec2 screen_size)
{
u -= camera->pos;
if(u.z <= 0)
return u;
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;
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)
{
/* 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)
{
azrp_triangle(
(int)p1->x, (int)p1->y,
(int)p2->x, (int)p2->y,
(int)p3->x, (int)p3->y,
color);
}