87 lines
3.7 KiB
C
87 lines
3.7 KiB
C
// C translation of chunk5's 3D vertex pipeline: the vertex-emit
|
|
// family (ProcessVertex1/2, EmitPrimaryVertex), outcode classification
|
|
// (ClassifyVertex1/2), table perspective (ProjectVertex), the per-plane
|
|
// clippers (ClipVertex2ToLeft/Right/Top/Bottom, ClipVertex2ToFrustum,
|
|
// ClipBothVerticesToFrustum), the line emitter (EmitClippedLine), the
|
|
// 8-segment curve (SceneryOpEmitCurve) and the polygon fill kernel
|
|
// (PolygonScanFillSetup .. PolygonScanFillRow).
|
|
//
|
|
// All vertex state lives in the 64K RAM mirror at the chunk5 zero-page
|
|
// addresses named in chunk5Zp.h, so the routines here read and write
|
|
// the same cells the 6502 code does. The polygon working arrays
|
|
// (PrimVert*/SecVert* in chunk5) and the two auto-scale exponents are
|
|
// kept in Chunk5VertexStateT because nothing else in the image reads
|
|
// them and the FS2.1 image places them differently from the source.
|
|
//
|
|
// Rasterisation is delegated through Chunk5SinkT so the caller decides
|
|
// where pixels land (the port renders into its framebuffer).
|
|
|
|
#ifndef CHUNK5_VERTEX_H
|
|
#define CHUNK5_VERTEX_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#define CHUNK5_CURVE_SEGMENTS 8
|
|
|
|
typedef struct Chunk5VertexStateT {
|
|
uint8_t *ram;
|
|
} Chunk5VertexStateT;
|
|
|
|
// Rasterisation callbacks. Coordinates are chunk5 colour-pixel columns
|
|
// (0..139) and hires rows (0..191).
|
|
typedef struct Chunk5SinkT {
|
|
void (*plotColorPixel)(void *userData, int column, int row);
|
|
void (*drawColorLine)(void *userData, int col1, int row1, int col2, int row2);
|
|
void (*drawColorSpan)(void *userData, int rightColumn, int width, int row);
|
|
void (*setSpanColor)(void *userData, uint8_t sceneryCode);
|
|
void *userData;
|
|
} Chunk5SinkT;
|
|
|
|
// ClassifyVertex1 / ClassifyVertex2: outcode into $CA / $D3.
|
|
void chunk5ClassifyVertex1(uint8_t *ram);
|
|
void chunk5ClassifyVertex2(uint8_t *ram);
|
|
|
|
// ClipBothVerticesToFrustum: clip V1 against the lateral planes.
|
|
void chunk5ClipBothVerticesToFrustum(uint8_t *ram);
|
|
|
|
// ClipVertex2ToLeft/Top/Right/Bottom: move V2 onto the plane along the
|
|
// V1-V2 edge (with the overflow halve-and-retry).
|
|
void chunk5ClipVertex2ToBottom(uint8_t *ram);
|
|
void chunk5ClipVertex2ToLeft(uint8_t *ram);
|
|
void chunk5ClipVertex2ToRight(uint8_t *ram);
|
|
void chunk5ClipVertex2ToTop(uint8_t *ram);
|
|
// ClipVertex2ToFrustum: clip V2 against right/left/bottom/top planes
|
|
// in turn, reclassifying after each and stopping early when the
|
|
// segment is wholly outside.
|
|
void chunk5ClipVertex2ToFrustum(uint8_t *ram);
|
|
|
|
// SceneryOpEmitCurve body ($2B): reads both xform-B vertices at the
|
|
// scenery cursor $8B (advancing it by 9) and draws eight segments.
|
|
void chunk5EmitCurve(Chunk5VertexStateT *vs, const Chunk5SinkT *sink);
|
|
|
|
// EmitClippedLine: cull/clip/project V1->V2 and draw it, then restore
|
|
// V1 from V2 so the next segment chains.
|
|
void chunk5EmitClippedLine(uint8_t *ram, const Chunk5SinkT *sink);
|
|
|
|
|
|
|
|
// ProcessVertex1 / ProcessVertex2: transform the vertex at the scenery
|
|
// cursor into V1 / V2 (advancing the cursor) and either pool it
|
|
// (polygon mode) or classify + project it.
|
|
void chunk5ProcessVertex1(Chunk5VertexStateT *vs, bool xformA);
|
|
void chunk5ProcessVertex2(Chunk5VertexStateT *vs, bool xformA);
|
|
|
|
// ProjectVertex: table perspective divide of one camera-space vertex.
|
|
void chunk5ProjectVertex(int16_t x, int16_t y, int16_t z, uint8_t *outColumn, uint8_t *outRow);
|
|
void chunk5ProjectV1ToScreen(uint8_t *ram);
|
|
void chunk5ProjectV2ToScreen(uint8_t *ram);
|
|
|
|
// 16-bit little-endian helpers for the RAM mirror.
|
|
int16_t chunk5Read16(const uint8_t *ram, uint16_t addr);
|
|
void chunk5Write16(uint8_t *ram, uint16_t addr, int16_t value);
|
|
|
|
// Bind the vertex state to the RAM image.
|
|
void chunk5VertexStateInit(Chunk5VertexStateT *vs, uint8_t *ram);
|
|
|
|
#endif
|