2023-04-23 23:31:24 +02:00
|
|
|
/* Chaos Drop: A classic falling game incorporating raytracing */
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#define __BSD_VISIBLE 1
|
|
|
|
#include <math.h>
|
2023-04-22 22:11:16 +02:00
|
|
|
|
|
|
|
#include <num/num.h>
|
|
|
|
#include <num/vec.h>
|
2023-04-23 23:31:24 +02:00
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
//--
|
|
|
|
// World and camera
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* World boundaries (on each side; the tube is thus 8x8). The size doesn't
|
|
|
|
matter for modeling purposes but this value is chosen to facilitate low-
|
|
|
|
precision computations with num16. */
|
|
|
|
#define WORLD_SIZE 4
|
|
|
|
/* Size, in world space, that half of the virtual screen's height should
|
|
|
|
occupy. Larger values will push the virtual screen away from the camera.
|
|
|
|
Mathematically any positive value would work. This value is again chosen to
|
|
|
|
improve the precision of num16 computations. */
|
2023-04-22 22:11:16 +02:00
|
|
|
#define HALF_SCREEN_HEIGHT 2
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Viewport/virtual screen size, in pixels */
|
|
|
|
#define VWIDTH 198
|
|
|
|
#define VHEIGHT 112
|
|
|
|
|
|
|
|
/* Coordinate system
|
2023-04-22 22:11:16 +02:00
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
The world is a drop chute, arranged horizontally to fit Azur's standard
|
|
|
|
coordinate system. Coordinates are right-handed, with the following
|
|
|
|
orientation looking forward (down the chute):
|
|
|
|
|
|
|
|
z
|
|
|
|
^
|
|
|
|
|
|
|
|
|
y (x)---> x
|
|
|
|
|
|
|
|
There is no player-centered coordinate system since we do all the raytracing
|
|
|
|
in the world space. */
|
2023-04-22 22:11:16 +02:00
|
|
|
struct camera {
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Horizontal FOV in degrees */
|
2023-04-22 22:11:16 +02:00
|
|
|
num fov;
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Screen distance (see raytracing.cc for details on how this is chosen) */
|
2023-04-22 22:11:16 +02:00
|
|
|
num screen_distance;
|
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Camera position in world space */
|
2023-04-22 22:11:16 +02:00
|
|
|
vec3 pos;
|
|
|
|
/* Angles of rotation */
|
|
|
|
float yaw, pitch, roll;
|
|
|
|
num cos_r, sin_r;
|
|
|
|
num cos_p, sin_p;
|
|
|
|
num cos_y, sin_y;
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Corresponding directions, in world coordinates. This forms a local
|
|
|
|
coordinate system (which is only used ever for ray generation) */
|
2023-04-22 22:11:16 +02:00
|
|
|
vec3 forward, right, up;
|
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
/* (Game-specific) Targeted roll position (0..3) */
|
2023-04-23 00:16:59 +02:00
|
|
|
int roll_quadrant;
|
|
|
|
};
|
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Set the camera's horizontal FOV in degrees. */
|
|
|
|
void camera_set_fov(struct camera *camera, float fov_degrees);
|
|
|
|
/* Compute the tranformation matrix that turns coordinates relative to the
|
|
|
|
camera into world coordinates. */
|
|
|
|
mat3 camera_camera2world_matrix(struct camera const *camera);
|
|
|
|
/* Update camera's internal variables after modifying the angles. */
|
|
|
|
void camera_update_angles(struct camera *camera);
|
|
|
|
/* Determines whether the camera is rolling. This function returns true only
|
|
|
|
during an initial portion of the roll animation. It returns false as soon as
|
|
|
|
the player should be allowed to roll again. */
|
|
|
|
bool camera_rolling(struct camera const *camera);
|
|
|
|
/* Perform rolling by bringing the roll angle closer to the targeted roll
|
|
|
|
position. How much closer is controlled by 0 < snap_factor ≤ 1. With
|
|
|
|
snap_factor=1, the roll snaps instantly. Any other constant value gives an
|
|
|
|
exponential snap. */
|
|
|
|
void camera_roll(struct camera *camera, float snap_factor);
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Game levels
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* Mirror along the left and right walls. */
|
2023-04-23 10:26:17 +02:00
|
|
|
struct element_mirror {
|
|
|
|
num begin, end;
|
|
|
|
};
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Object plane intersecting the chute. */
|
2023-04-23 10:26:17 +02:00
|
|
|
enum element_plane_type {
|
|
|
|
ELEMENT_PLANE_DAMAGE,
|
|
|
|
ELEMENT_PLANE_ARROW,
|
2023-04-23 15:54:45 +02:00
|
|
|
ELEMENT_PLANE_INVIS,
|
2023-04-23 10:26:17 +02:00
|
|
|
};
|
|
|
|
struct element_plane {
|
|
|
|
num y;
|
|
|
|
uint32_t shape;
|
|
|
|
uint16_t type;
|
2023-04-23 23:31:24 +02:00
|
|
|
/* ARROW: arrow direction (same numbering as camera->roll_quadrant) */
|
|
|
|
uint16_t data;
|
2023-04-23 10:26:17 +02:00
|
|
|
};
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Tutorial text or sarcastic commentary. */
|
2023-04-23 10:26:17 +02:00
|
|
|
struct element_text {
|
|
|
|
num begin, end;
|
|
|
|
char const *str;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct level {
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Level name (usually just two digits) */
|
2023-04-23 13:49:12 +02:00
|
|
|
char const *name;
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Depth at which the level is completed */
|
2023-04-23 13:49:12 +02:00
|
|
|
num finish;
|
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Lists of elements, all of which should be sorted by increasing order of
|
|
|
|
begin/y members (and only one element of each type should exist for each
|
|
|
|
value of y; if there are multiple, only the first will be shown) */
|
|
|
|
|
2023-04-23 10:26:17 +02:00
|
|
|
int mirror_count;
|
|
|
|
struct element_mirror *mirrors;
|
|
|
|
|
|
|
|
int plane_count;
|
|
|
|
struct element_plane *planes;
|
|
|
|
|
|
|
|
int text_count;
|
|
|
|
struct element_text *texts;
|
|
|
|
};
|
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Check whether world coordinates x/z would collide with an object plane of
|
|
|
|
the provided shape. */
|
|
|
|
bool level_plane_collides(num16 x, num16 z, uint32_t shape);
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Dynamic world information
|
|
|
|
//---
|
|
|
|
|
2023-04-23 00:16:59 +02:00
|
|
|
struct world {
|
|
|
|
num16 neon_position;
|
|
|
|
num16 neon_period;
|
|
|
|
|
2023-04-23 10:26:17 +02:00
|
|
|
/* Current objects */
|
|
|
|
num depth;
|
|
|
|
struct element_mirror *mirror;
|
|
|
|
struct element_plane *plane;
|
|
|
|
struct element_text *text;
|
|
|
|
int mirror_index;
|
|
|
|
int plane_index;
|
|
|
|
int text_index;
|
2023-04-22 22:11:16 +02:00
|
|
|
};
|
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
//---
|
|
|
|
// Raytracing
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* Core function. Renders an image of the provided world through the provided
|
|
|
|
camera. Renders lines [y_start ... y_start+y_height) on the specified VRAM
|
|
|
|
fragment. */
|
2023-04-23 00:16:59 +02:00
|
|
|
void render_fragment(struct camera const *camera, struct world const *world,
|
|
|
|
uint16_t *fragment, int y_start, int y_height);
|
2023-04-22 22:11:16 +02:00
|
|
|
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Azur shader wrapping the raytracing function. */
|
2023-04-23 00:16:59 +02:00
|
|
|
void cd_raytrace(struct camera const *camera, struct world const *world);
|
2023-04-23 23:31:24 +02:00
|
|
|
/* Shader configuration function, must be called at initialization and after
|
|
|
|
any scale change. */
|
2023-04-22 22:11:16 +02:00
|
|
|
void cd_raytrace_configure(void);
|
|
|
|
|
|
|
|
//=== Input management ===//
|
|
|
|
|
|
|
|
struct input {
|
2023-04-23 18:41:39 +02:00
|
|
|
bool left, left_trigger;
|
|
|
|
bool right, right_trigger;
|
|
|
|
bool up, up_trigger;
|
|
|
|
bool down, down_trigger;
|
2023-04-22 22:11:16 +02:00
|
|
|
bool OPTN;
|
2023-04-23 15:54:45 +02:00
|
|
|
bool roll_left;
|
|
|
|
bool roll_right;
|
|
|
|
bool RESET_LEVEL;
|
|
|
|
bool PREV_LEVEL;
|
|
|
|
bool NEXT_LEVEL;
|
2023-04-23 18:41:39 +02:00
|
|
|
bool enter;
|
2023-04-22 22:11:16 +02:00
|
|
|
};
|