247 lines
7.3 KiB
C
247 lines
7.3 KiB
C
/* Chaos Drop: A classic falling game incorporating raytracing */
|
|
|
|
#pragma once
|
|
|
|
#define __BSD_VISIBLE 1
|
|
#include <math.h>
|
|
|
|
#include <num/num.h>
|
|
#include <num/vec.h>
|
|
#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. */
|
|
#define HALF_SCREEN_HEIGHT 2
|
|
/* Viewport/virtual screen size, in pixels */
|
|
#define VWIDTH 198
|
|
#define VHEIGHT 112
|
|
|
|
/* Coordinate system
|
|
|
|
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. */
|
|
struct camera {
|
|
/* Horizontal FOV in degrees */
|
|
num fov;
|
|
/* Screen distance (see raytracing.cc for details on how this is chosen) */
|
|
num screen_distance;
|
|
|
|
/* Camera position in world space */
|
|
vec3 pos;
|
|
/* Angles of rotation */
|
|
float yaw, pitch, roll;
|
|
num cos_r, sin_r;
|
|
num cos_p, sin_p;
|
|
num cos_y, sin_y;
|
|
/* Corresponding directions, in world coordinates. This forms a local
|
|
coordinate system (which is only used ever for ray generation) */
|
|
vec3 forward, right, up;
|
|
|
|
/* (Game-specific) Targeted roll position (0..3) */
|
|
int roll_quadrant;
|
|
};
|
|
|
|
/* 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. */
|
|
struct element_mirror {
|
|
num begin, end;
|
|
};
|
|
/* Object plane intersecting the chute. */
|
|
enum element_plane_type {
|
|
ELEMENT_PLANE_DAMAGE,
|
|
ELEMENT_PLANE_ARROW,
|
|
ELEMENT_PLANE_INVIS,
|
|
ELEMENT_PLANE_DEATH,
|
|
};
|
|
struct element_plane {
|
|
num y;
|
|
uint32_t shape;
|
|
uint16_t type;
|
|
/* ARROW: arrow direction (same numbering as camera->roll_quadrant) */
|
|
uint16_t data;
|
|
};
|
|
/* Tutorial text or sarcastic commentary. */
|
|
struct element_text {
|
|
num begin, end;
|
|
char const *str;
|
|
};
|
|
/* Additional full-screen visual effect. */
|
|
struct element_vfx {
|
|
num begin, end;
|
|
int effect;
|
|
};
|
|
|
|
struct level {
|
|
/* Level name (usually just two digits) */
|
|
char const *name;
|
|
/* Depth at which the level is completed */
|
|
num finish;
|
|
|
|
/* 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) */
|
|
|
|
int mirror_count;
|
|
struct element_mirror *mirrors;
|
|
|
|
int plane_count;
|
|
struct element_plane *planes;
|
|
|
|
int text_count;
|
|
struct element_text *texts;
|
|
|
|
int vfx_count;
|
|
struct element_vfx *vfxs;
|
|
};
|
|
|
|
/* Total number of levels. */
|
|
int level_count(void);
|
|
/* Get a level by ID. */
|
|
struct level const *level_get(int id);
|
|
/* 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
|
|
//---
|
|
|
|
struct game {
|
|
/* Camera (including player position) */
|
|
struct camera *camera;
|
|
/* Neon cycle specification - independent from level */
|
|
num16 neon_position;
|
|
num16 neon_period;
|
|
|
|
/* Current level and its level number. When level is NULL and/or level_id is
|
|
negative, we are in the main menu. */
|
|
struct level const *level;
|
|
int level_id;
|
|
/* Current position within level's element arrays */
|
|
int mirror_index;
|
|
int plane_index;
|
|
int text_index;
|
|
int vfx_index;
|
|
/* Corresponding elements (these are the only active elements) */
|
|
struct element_mirror *mirror;
|
|
struct element_plane *plane;
|
|
struct element_text *text;
|
|
struct element_vfx *vfx;
|
|
/* A dynamic plane y value; mostly redundant from plane->y, used to optimize
|
|
away some checks during collisions with the plane */
|
|
num plane_collision[2];
|
|
|
|
/* Distance traversed within the current level */
|
|
num depth;
|
|
|
|
/* Number of blank frames to show (for death transitions) */
|
|
int blank_frames;
|
|
|
|
/* Cursor position within the main menu */
|
|
int menu_cursor;
|
|
};
|
|
|
|
/* Check whether we are in the main menu. */
|
|
bool game_in_menu(struct game const *game);
|
|
/* Transition to the main menu. */
|
|
void game_load_menu(struct game *game);
|
|
/* Transition to a level. */
|
|
void game_load_level(struct game *game, int index, int blank_frames);
|
|
/* Restart current level. */
|
|
void game_restart_level(struct game *g, int blank_frames);
|
|
/* Go the previous level (or menu if currently at the first level). */
|
|
void game_prev_level_or_menu(struct game *g);
|
|
/* Go the next level (or menu if currently at the last level). */
|
|
void game_next_level_or_menu(struct game *g);
|
|
/* Return the plane currently in collision with the player, if any, or NULL. */
|
|
const struct element_plane *game_plane_collision(struct game const *g);
|
|
/* Advancee in level by unloading passed elements and loading incoming ones.
|
|
Check game_plane_collision() before calling this function. */
|
|
void game_advance_in_level(struct game *g);
|
|
|
|
//---
|
|
// Raytracing
|
|
//---
|
|
|
|
/* Core function. Renders an image of the provided game; renders lines
|
|
[y_start ... y_start+y_height) on the specified VRAM fragment. */
|
|
void render_fragment(struct game const *game, uint16_t *fragment,
|
|
int y_start, int y_height);
|
|
|
|
/* Azur shader wrapping the raytracing function. */
|
|
void cd_raytrace(struct game const *game);
|
|
/* Shader configuration function, must be called at initialization and after
|
|
any scale change. */
|
|
void cd_raytrace_configure(void);
|
|
|
|
//---
|
|
// Other shaders
|
|
//---
|
|
|
|
/* Basic full-screen visual effects */
|
|
enum {
|
|
CD_VFX_DARKEN = 0,
|
|
CD_VFX_WHITEN = 1,
|
|
CD_VFX_INVERT = 2,
|
|
};
|
|
|
|
/* Apply a visual effect to the entire screen */
|
|
void cd_vfx(int effect);
|
|
/* Shader configuration function for cd_vfx() */
|
|
void cd_vfx_configure(void);
|
|
|
|
//=== Input management ===//
|
|
|
|
struct input {
|
|
bool left, left_trigger;
|
|
bool right, right_trigger;
|
|
bool up, up_trigger;
|
|
bool down, down_trigger;
|
|
bool OPTN;
|
|
bool roll_left;
|
|
bool roll_right;
|
|
bool RESET_LEVEL;
|
|
bool PREV_LEVEL;
|
|
bool NEXT_LEVEL;
|
|
bool enter;
|
|
};
|