File size: 5,948 Bytes
6be3052
 
 
 
 
 
 
 
 
 
 
 
 
 
12a0785
 
 
 
 
 
 
 
6be3052
12a0785
6be3052
12a0785
07389f9
6be3052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
07389f9
6be3052
 
 
 
12a0785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6be3052
 
 
 
 
 
 
 
 
 
 
 
 
 
12a0785
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! Strongly-typed render queue messages.
//!
//! Incremental replacement for the legacy command-type byte format.
//! Each `RenderMessage` variant replaces one (or more) of the legacy
//! `DrawXxxCmd` structs from `queue.rs`. Typed messages are stored
//! inline in the existing `RenderQueue._buffer` arena via
//! [`TypedRenderCmd`], so construction is free — no heap allocation.
//!
//! ## Migration strategy
//!
//! Producers switch from `rq.alloc::<DrawXxxCmd>()` + field fill to
//! `rq.push_typed(layer, RenderMessage::Xxx { ... })` one at a time.
//! The dispatcher (`queue_dispatch.rs`) handles both legacy and typed
//! commands simultaneously until all producers are migrated.
//!
//! ## Variable-length commands
//!
//! Commands with variable-length data (LineStrip, Polygon) allocate
//! their vertex arrays separately in the arena via
//! `RenderQueue::alloc_aux()` and store an explicit pointer in the
//! enum variant. This avoids layout coupling between the command and
//! its auxiliary data.

use crate::bitgrid::DisplayBitGrid;
use crate::fixed::Fixed;
use crate::render::display::vtable::TiledBitmapSource;
use crate::render::sprite::sprite_op::SpriteOp;

/// Sentinel `command_type` value for [`TypedRenderCmd`]. Sits outside
/// the legacy 0..=0xE range so the existing per-case dispatcher arms
/// are unaffected.
pub const COMMAND_TYPE_TYPED: u32 = 0x100;

/// Strongly-typed render queue message.
///
/// One variant per logical draw operation. Payloads use the project's
/// typed primitives (`Fixed`, typed pointers) where possible; fields
/// whose semantics are still ambiguous stay as raw `u32` with a comment.
///
/// Stored inline inside `RenderQueue._buffer` via [`TypedRenderCmd`].
/// The buffer is reset by WA at the start of each frame, same as the
/// legacy byte-format commands.
#[derive(Debug, Clone, Copy)]
pub enum RenderMessage {
    /// Replaces legacy types 4 (`DRAW_SPRITE_GLOBAL`) and 5
    /// (`DRAW_SPRITE_LOCAL`).
    ///
    /// `local` selects screen-space (`true`, dispatcher applies
    /// `rq_translate_coordinates`) vs world-space (`false`, position
    /// passed through directly).
    Sprite {
        local: bool,
        x: Fixed,
        y: Fixed,
        sprite: SpriteOp,
        /// Palette context — passed to `blit_sprite` as the last arg.
        /// Semantics vary by producer (palette pointer, animation index, etc.).
        palette: u32,
    },

    /// Replaces legacy type 0 (`DRAW_RECT`).
    FillRect {
        color: u32,
        x1: Fixed,
        y1: Fixed,
        x2: Fixed,
        y2: Fixed,
        /// Perspective clip reference Z (`cmd[7]` in legacy format).
        ref_z: i32,
    },

    /// Replaces legacy type 0xB (`DRAW_CROSSHAIR`).
    ///
    /// `ref_z` is always 0 in all known producers — omitted here,
    /// the dispatcher passes 0 directly.
    Crosshair {
        color_fg: u32,
        color_bg: u32,
        x: Fixed,
        y: Fixed,
    },

    /// Replaces legacy type 0xD (`DRAW_TILED_BITMAP`).
    TiledBitmap {
        x: Fixed,
        y: Fixed,
        source: *const TiledBitmapSource,
        /// Bit 0 forces destination X to 0.
        flags: u8,
    },

    /// Replaces legacy type 6 (`DRAW_SPRITE_OFFSET`).
    ///
    /// `ref_z` (first Z reference) is always 0 in all known producers —
    /// omitted here, the dispatcher passes 0 directly.
    SpriteOffset {
        flags: u32,
        x: Fixed,
        y: Fixed,
        /// Second Z reference for perspective clip (`cmd[6]` in legacy format).
        ref_z_2: i32,
        sprite: SpriteOp,
        palette: u32,
    },

    /// Replaces legacy type 1 (`DRAW_BITMAP_GLOBAL`).
    ///
    /// `src_x` is always 0 in all known producers — omitted here.
    BitmapGlobal {
        x: Fixed,
        y: Fixed,
        bitmap: *mut DisplayBitGrid,
        src_y: i32,
        src_w: i32,
        src_h: i32,
        flags: u32,
    },

    /// Replaces legacy type 2 (`DRAW_TEXTBOX_LOCAL`).
    ///
    /// `mode`, `ref_z`, `ref_z_2`, `src_x`, `src_y` are always 0 in
    /// all known producers — omitted here.
    TextboxLocal {
        x: Fixed,
        y: Fixed,
        bitmap: *mut DisplayBitGrid,
        src_w: i32,
        src_h: i32,
        flags: u32,
    },

    /// Replaces legacy type 8 (`DRAW_LINE_STRIP`).
    ///
    /// Vertex data is allocated separately via `RenderQueue::alloc_aux()`
    /// and referenced by the explicit `vertices` pointer.
    /// Each vertex is `[x: i32, y: i32, z: i32]` in Fixed16.
    LineStrip {
        count: u32,
        color: u32,
        /// Pointer to `count` vertices in the arena. Allocated via
        /// `alloc_aux()`, valid for the current frame only.
        vertices: *const [i32; 3],
    },

    /// Replaces legacy type 9 (`DRAW_POLYGON`).
    ///
    /// Vertex data is allocated separately via `RenderQueue::alloc_aux()`
    /// and referenced by the explicit `vertices` pointer.
    /// Each vertex is `[x: i32, y: i32, z: i32]` in Fixed16.
    Polygon {
        count: u32,
        color1: u32,
        color2: u32,
        /// Pointer to `count` vertices in the arena. Allocated via
        /// `alloc_aux()`, valid for the current frame only.
        vertices: *const [i32; 3],
    },
}

/// Wrapper that carries a [`RenderMessage`] inline in the render queue
/// buffer. The `command_type` / `layer` prefix matches the legacy
/// command layout so the dispatcher's sort-by-layer step works unchanged.
#[repr(C)]
pub struct TypedRenderCmd {
    /// Always [`COMMAND_TYPE_TYPED`].
    pub command_type: u32,
    /// Render layer — same semantics as the legacy commands' `layer` field.
    pub layer: u32,
    /// The typed payload.
    pub message: RenderMessage,
}

// Canary for buffer pressure — if this fires, revisit the size budget
// note in the plan (consider #[repr(u8)] discriminant or variant splitting).
const _: () = assert!(core::mem::size_of::<TypedRenderCmd>() <= 48);