chaos-drop/src/chaos-drop.h

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;
};