chaos-drop/src/chaos-drop.h

180 lines
5.1 KiB
C
Raw Normal View History

/* 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>
#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
/* Viewport/virtual screen size, in pixels */
#define VWIDTH 198
#define VHEIGHT 112
/* Coordinate system
2023-04-22 22:11:16 +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 {
/* Horizontal FOV in degrees */
2023-04-22 22:11:16 +02:00
num fov;
/* Screen distance (see raytracing.cc for details on how this is chosen) */
2023-04-22 22:11:16 +02:00
num screen_distance;
/* 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;
/* 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;
/* (Game-specific) Targeted roll position (0..3) */
2023-04-23 00:16:59 +02:00
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. */
2023-04-23 10:26:17 +02:00
struct element_mirror {
num begin, end;
};
/* 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;
/* ARROW: arrow direction (same numbering as camera->roll_quadrant) */
uint16_t data;
2023-04-23 10:26:17 +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 {
/* Level name (usually just two digits) */
2023-04-23 13:49:12 +02:00
char const *name;
/* Depth at which the level is completed */
2023-04-23 13:49:12 +02:00
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) */
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;
};
/* 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
};
//---
// 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
/* 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);
/* 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
};