==> include/mesh/abi/view_doom.h <==1/* @ajax/mesh-abi-view-doom: programs/doom's view: a DDA raycaster's pose, map, columns and show region.
2 *
3 * Part of alpha-c-mesh, a C port of alpha-rust-mesh (README.md says from where). */
4#ifndef MESH_ABI_VIEW_DOOM_H
5#define MESH_ABI_VIEW_DOOM_H
6
7#include <stdbool.h>
8#include <stddef.h>
9#include <stdint.h>
10#include "mesh/abi/placement.h"
11
12/* A view region, (offset, bytes): PLACE_STATE's and PLACE_OUT's entries. */
13typedef struct {
14 uint32_t off;
15 uint32_t len;
16} mesh_doom_region;
17
18/* programs/doom: a DDA raycaster, one lane per column, 4 tasks a frame
19 * (arg b: columns 32 b .. 32 b + 31). The pose lives in the view: the
20 * frame's arg-0 task drains the input queue (keys w s a d q e) into it, with
21 * wall collision, then publishes D_POSE_T = its ticket + 1; args 1..3 wait for
22 * it (tickets of one batch are consecutive), at most POSE_WAIT_NS, then render
23 * (a timeout bumps counter C_STALLS). */
24#define MESH_DOOM_WIDTH 128u
25#define MESH_DOOM_D_POS_X 0x00u /* f32 x 6: pos x y, dir x y, plane x y */
26#define MESH_DOOM_D_POS_Y 0x04u
27#define MESH_DOOM_D_DIR_X 0x08u
28#define MESH_DOOM_D_DIR_Y 0x0cu
29#define MESH_DOOM_D_PLANE_X 0x10u
30#define MESH_DOOM_D_PLANE_Y 0x14u
31#define MESH_DOOM_D_ROWS 0x18u /* f32 screen rows (heights are in rows) */
32#define MESH_DOOM_D_MAX_STEPS 0x1cu /* u32 DDA steps at most */
33#define MESH_DOOM_D_FRAME 0x20u /* u32 frames begun (arg-0 tasks) */
34#define MESH_DOOM_D_POSE_T 0x24u /* u32 ticket + 1 of the last pose update */
35#define MESH_DOOM_D_KEYS 0x28u /* u32 keys applied */
36#define MESH_DOOM_D_MAP 0x100u /* u32 x 256, row-major 16x16, 0 empty else kind 1..7 */
37#define MESH_DOOM_D_HEIGHT 0x1000u /* f32 x WIDTH */
38#define MESH_DOOM_D_KIND 0x1400u /* u32 x WIDTH */
39#define MESH_DOOM_D_SIDE 0x1800u /* u32 x WIDTH */
40#define MESH_DOOM_D_DIST 0x1c00u /* f32 x WIDTH */
41/* Placement (manifest `place = "split"`, mesh-abi v2 "placement"): the
42 * state meshd moves between the machines is the pose, rows, max steps
43 * and frame (0x0..0x24), D_KEYS and the map; D_POSE_T stays each
44 * machine's own (it holds that machine's tickets). The output is the
45 * four column arrays, task arg b writing columns 32 b .. 32 b + 31 of
46 * each. meshd's frame-matched copy is at D_SHOW (SH_*): buffer k holds
47 * the arrays concatenated, from show_data(k): heights, kinds, sides, dists. */
48#define MESH_DOOM_PLACE_STATE_LEN 3
49extern const mesh_doom_region MESH_DOOM_PLACE_STATE[3];
50#define MESH_DOOM_PLACE_OUT_LEN 4
51extern const mesh_doom_region MESH_DOOM_PLACE_OUT[4];
52#define MESH_DOOM_OUT_BYTES ((uint32_t)(16 * MESH_DOOM_WIDTH))
53#define MESH_DOOM_D_SHOW 0x2000u
54#define MESH_DOOM_SHOW_HEIGHT 0u
55#define MESH_DOOM_SHOW_KIND ((uint32_t)(4 * MESH_DOOM_WIDTH))
56#define MESH_DOOM_SHOW_SIDE ((uint32_t)(8 * MESH_DOOM_WIDTH))
57#define MESH_DOOM_SHOW_DIST ((uint32_t)(12 * MESH_DOOM_WIDTH))
58/* The view; the input queue (manifest `input = 64`) sits at its end. */
59#define MESH_DOOM_VIEW_BYTES 0x4000u
60/* The snapshot prefix: everything up to the end of the show region. */
61#define MESH_DOOM_SNAP_BYTES ((uint32_t)(MESH_DOOM_D_SHOW + MESH_SH_DATA + 2 * MESH_DOOM_OUT_BYTES)) /* = D_SHOW + show_bytes(OUT_BYTES) */
62#define MESH_DOOM_INPUT_BYTES 64u
63#define MESH_DOOM_ROWS 48.0f
64#define MESH_DOOM_MAX_STEPS 64u
65#define MESH_DOOM_POSE_WAIT_NS UINT64_C(100000000)
66#define MESH_DOOM_KEYS "wsadqe"
67#define MESH_DOOM_KEYS_LEN 6
68/* Movement: MOVE cells a key, turns of 10 degrees (cos, sin as f32
69 * constants, so the GPU and a CPU reference agree bitwise), a ~66 degree
70 * field of view, and RADIUS kept from walls. */
71#define MESH_DOOM_MOVE 0.25f
72#define MESH_DOOM_TURN_COS 0.9848077f /* cos(10 deg), correctly rounded */
73#define MESH_DOOM_TURN_SIN 0.17364818f /* sin(10 deg) */
74#define MESH_DOOM_PLANE 0.66f
75#define MESH_DOOM_RADIUS 0.2f
76/* The start pose: the open hall in the lower half, looking up (-y). */
77#define MESH_DOOM_START_LEN 6
78extern const float MESH_DOOM_START[6];
79/* 16x16, row-major (y rows, x columns); digits are wall kinds 1..7, '.' empty. */
80#define MESH_DOOM_MAP_LEN 16
81/* rows of 16 cells; [17] leaves room for the NUL of C strings */
82extern const char MESH_DOOM_MAP[16][17];
83/* Counters: 0 frames, 1 keys, 2 stalls (a pose wait timed out), 3
84 * follows (OP_FOLLOW parts rendered on the owner's pose: split, system 1). */
85#define MESH_DOOM_C_FRAMES 0u
86#define MESH_DOOM_C_KEYS 1u
87#define MESH_DOOM_C_STALLS 2u
88#define MESH_DOOM_C_FOLLOWS 3u
89
90/* Buffer k's data in the view. */
91static inline uint32_t mesh_doom_show_data(uint32_t k) { return MESH_DOOM_D_SHOW + (uint32_t)MESH_SH_DATA + k * MESH_DOOM_OUT_BYTES; }
92/* MAP's cell (x, y): its wall kind 1..9, or 0 when empty. */
93static inline uint32_t mesh_doom_map_cell(size_t x, size_t y) {
94 char c = MESH_DOOM_MAP[y][x];
95 return c >= '1' && c <= '9' ? (uint32_t)(c - '0') : 0;
96}
97
98/* The Rust const asserts that only involve this package. */
99_Static_assert(MESH_DOOM_D_DIST + 4 * MESH_DOOM_WIDTH + 0x10 + MESH_DOOM_INPUT_BYTES <= MESH_DOOM_VIEW_BYTES, "doom::D_DIST + 4 * doom::WIDTH + 0x10 + doom::INPUT_BYTES <= doom::VIEW_BYTES");
100_Static_assert(MESH_DOOM_D_MAP + 4 * 256 <= MESH_DOOM_D_HEIGHT, "doom::D_MAP + 4 * 256 <= doom::D_HEIGHT");
101_Static_assert(MESH_DOOM_D_KEYS + 4 <= MESH_DOOM_D_MAP, "doom::D_KEYS + 4 <= doom::D_MAP");
102_Static_assert((MESH_DOOM_WIDTH % 32 == 0), "doom::WIDTH.is_multiple_of(32)");
103_Static_assert(MESH_DOOM_D_DIST + 4 * MESH_DOOM_WIDTH <= MESH_DOOM_D_SHOW, "doom::D_DIST + 4 * doom::WIDTH <= doom::D_SHOW");
104_Static_assert(MESH_DOOM_SNAP_BYTES == 0x3100, "doom::SNAP_BYTES == 0x3100");
105_Static_assert(MESH_DOOM_SNAP_BYTES + 0x10 + MESH_DOOM_INPUT_BYTES <= MESH_DOOM_VIEW_BYTES, "doom::SNAP_BYTES + 0x10 + doom::INPUT_BYTES <= doom::VIEW_BYTES");
106
107#endif