// 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 #include #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