105 lines
3.0 KiB
C++
105 lines
3.0 KiB
C++
#define __BSD_VISIBLE 1
|
|
#include <math.h>
|
|
|
|
#include "render.h"
|
|
#include "game.h"
|
|
#include "util.h"
|
|
#include <azur/gint/render.h>
|
|
|
|
void camera::set_fov(num fov)
|
|
{
|
|
this->fov = fov;
|
|
|
|
float fov_radians = (float)fov * 3.14159 / 180;
|
|
float sd = 1 / tanf(fov_radians / 2);
|
|
this->_sd = num(sd);
|
|
}
|
|
|
|
void camera_track(struct camera *camera, struct player const *player)
|
|
{
|
|
camera->pos = player->pos() + player->up() * RENDER_EYE_HEIGHT;
|
|
camera->pos.z -= RENDER_CAMERA_BACK_DISTANCE;
|
|
|
|
camera->platform = player->platform;
|
|
if(player->jump_dir && player->jump_t >= TIME_ROTATION / 2)
|
|
camera->platform += player->jump_dir;
|
|
|
|
num angle = player->world_angle();
|
|
camera->angle_vector = vec2(num_cos(-angle), num_sin(-angle));
|
|
}
|
|
|
|
vec3 camera_project_point(struct camera *camera, vec3 u)
|
|
{
|
|
if(u.z < camera->pos.z + camera->near_plane())
|
|
return u;
|
|
|
|
u = vec_rotate_around_z(u - camera->pos, camera->angle_vector);
|
|
|
|
num f = camera->screen_distance() * (camera->screen_size.y / 2) / u.z;
|
|
u.x = u.x * f + camera->screen_size.x / 2;
|
|
u.y = -u.y * f + camera->screen_size.y / 2 ;
|
|
return u;
|
|
}
|
|
|
|
void camera_project_prect(struct camera *camera, struct prect *p)
|
|
{
|
|
/* Require the rectangle to be already clipped */
|
|
if(p->nl.z < camera->pos.z + camera->near_plane())
|
|
return;
|
|
|
|
vec2 half_screen(camera->screen_size.x / 2, camera->screen_size.y / 2);
|
|
|
|
p->nl = vec_rotate_around_z(p->nl - camera->pos, camera->angle_vector);
|
|
p->nr = vec_rotate_around_z(p->nr - camera->pos, camera->angle_vector);
|
|
p->fl = vec_rotate_around_z(p->fl - camera->pos, camera->angle_vector);
|
|
p->fr = vec_rotate_around_z(p->fr - camera->pos, camera->angle_vector);
|
|
|
|
/* We assume nl/nr have the same z, and so do fl/fr */
|
|
num f = camera->screen_distance() * half_screen.y;
|
|
num near_f = f / p->nl.z;
|
|
num far_f = f / p->fl.z;
|
|
|
|
p->nl.x = p->nl.x * near_f + half_screen.x;
|
|
p->nl.y = -p->nl.y * near_f + half_screen.y;
|
|
|
|
p->nr.x = p->nr.x * near_f + half_screen.x;
|
|
p->nr.y = -p->nr.y * near_f + half_screen.y;
|
|
|
|
p->fl.x = p->fl.x * far_f + half_screen.x;
|
|
p->fl.y = -p->fl.y * far_f + half_screen.y;
|
|
|
|
p->fr.x = p->fr.x * far_f + half_screen.x;
|
|
p->fr.y = -p->fr.y * far_f + half_screen.y;
|
|
}
|
|
|
|
int camera_platform_color(struct camera *camera, int platform_id)
|
|
{
|
|
/* Accounting for the full angle is too precise and results in weird
|
|
color jumps at different times across platforms, instead switch at half
|
|
movement. */
|
|
int dist = platform_id - camera->platform;
|
|
if(dist < 0)
|
|
dist += PLATFORM_COUNT;
|
|
dist = std::min(dist, PLATFORM_COUNT - dist);
|
|
|
|
int gray = 31 - 2 * dist;
|
|
return C_RGB(gray, gray, gray);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void render_dots(std::initializer_list<vec3> const &&points)
|
|
{
|
|
extern image_t img_dot;
|
|
|
|
for(auto p: points)
|
|
azrp_image((int)p.x - 2, (int)p.y - 2, &img_dot);
|
|
}
|