Skip to main content

evegfx/
display_list.rs

1//! Representations of display list commands.
2
3pub mod options;
4pub mod shape_builder;
5
6use crate::graphics::{Vertex2F, Vertex2II, RGB, RGBA};
7use crate::memory::{MainMem, MemoryRegion, Ptr};
8use core::fmt::Debug;
9
10/// Represents an EVE display list command.
11#[derive(Copy, Clone, PartialEq)]
12pub struct DLCmd(u32);
13
14impl DLCmd {
15    // The length of a display list command as stored in the EVE device's
16    // display list RAM.
17    pub const LENGTH: u32 = 4;
18
19    pub const DISPLAY: Self = OpCode::DISPLAY.build(0);
20    pub const END: Self = OpCode::END.build(0);
21    pub const CLEAR_ALL: Self = Self::clear(true, true, true);
22    pub const NOP: Self = OpCode::NOP.build(0);
23    pub const RESTORE_CONTEXT: Self = OpCode::RESTORE_CONTEXT.build(0);
24    pub const RETURN: Self = OpCode::RETURN.build(0);
25    pub const SAVE_CONTEXT: Self = OpCode::SAVE_CONTEXT.build(0);
26
27    /// Creates a command from the raw command word given as a `u32`. It's
28    /// the caller's responsibility to ensure that it's a valid encoding of
29    /// a real display list command.
30    pub const fn from_raw(raw: u32) -> Self {
31        Self(raw)
32    }
33
34    pub const fn as_raw(&self) -> u32 {
35        self.0
36    }
37
38    pub const fn alpha_test(func: options::TestFunc, ref_val: u8) -> Self {
39        OpCode::ALPHA_FUNC.build((func as u32) << 8 | (ref_val as u32))
40    }
41
42    pub const fn begin(prim: options::GraphicsPrimitive) -> Self {
43        OpCode::BEGIN.build(prim as u32)
44    }
45
46    pub const fn bitmap_cell(idx: u8) -> Self {
47        OpCode::CELL.build((idx & 0b111111) as u32)
48    }
49
50    pub const fn bitmap_ext_format(format: options::BitmapExtFormat) -> Self {
51        OpCode::BITMAP_EXT_FORMAT.build(format as u32)
52    }
53
54    pub const fn bitmap_handle(bmp: options::BitmapHandle) -> Self {
55        OpCode::BITMAP_HANDLE.build(bmp.0 as u32)
56    }
57
58    pub const fn bitmap_layout_l(
59        format: options::BitmapFormat,
60        line_stride: u16,
61        height: u16,
62    ) -> Self {
63        OpCode::BITMAP_LAYOUT.build(
64            (format as u32) << 19
65                | (line_stride as u32 & 0b1111111111) << 9
66                | (height as u32 & 0b111111111),
67        )
68    }
69
70    pub const fn bitmap_layout_h(line_stride: u16, height: u16) -> Self {
71        OpCode::BITMAP_LAYOUT_H.build((line_stride as u32 >> 10) << 2 | (height as u32 >> 10))
72    }
73
74    /// `bitmap_layout_pair` is a helper for calling both `bitmap_layout` and
75    /// `bitmap_layout_h` with the same values, in order to set all 12 of
76    /// the bits in the `line_stride` and `height` fields. Write the two
77    /// commands to consecutive positions in the display list.
78    pub const fn bitmap_layout_pair(
79        format: options::BitmapFormat,
80        line_stride: u16,
81        height: u16,
82    ) -> (Self, Self) {
83        (
84            Self::bitmap_layout_l(format, line_stride, height),
85            Self::bitmap_layout_h(line_stride, height),
86        )
87    }
88
89    const fn physical_bitmap_size(width: u16, height: u16) -> (u16, u16) {
90        (
91            if width < 2048 { width } else { 0 },
92            if height < 2048 { height } else { 0 },
93        )
94    }
95
96    pub const fn bitmap_size_l(
97        width: u16,
98        height: u16,
99        filter: options::BitmapSizeFilter,
100        wrap_x: options::BitmapWrapMode,
101        wrap_y: options::BitmapWrapMode,
102    ) -> Self {
103        let (p_width, p_height) = Self::physical_bitmap_size(width, height);
104        OpCode::BITMAP_SIZE.build(
105            (filter as u32) << 20
106                | (wrap_x as u32) << 19
107                | (wrap_y as u32) << 18
108                | (p_width as u32 & 0b111111111) << 9
109                | (p_height as u32 & 0b111111111),
110        )
111    }
112
113    pub const fn bitmap_size_h(width: u16, height: u16) -> Self {
114        let (p_width, p_height) = Self::physical_bitmap_size(width, height);
115        let p_width = ((p_width as u32) >> 9) & 0b11;
116        let p_height = ((p_height as u32) >> 9) & 0b11;
117        OpCode::BITMAP_SIZE_H.build(p_width << 2 | p_height)
118    }
119
120    /// `bitmap_size_pair` is a helper for calling both `bitmap_size` and
121    /// `bitmap_size_h` with the same values, in order to set all 13 of
122    /// the bits in the `width` and `height` fields. Write the two
123    /// commands to consecutive positions in the display list.
124    pub const fn bitmap_size_pair(
125        width: u16,
126        height: u16,
127        filter: options::BitmapSizeFilter,
128        wrap_x: options::BitmapWrapMode,
129        wrap_y: options::BitmapWrapMode,
130    ) -> (Self, Self) {
131        (
132            Self::bitmap_size_l(width, height, filter, wrap_x, wrap_y),
133            Self::bitmap_size_h(width, height),
134        )
135    }
136
137    /// Defines the address in main memory for the data for the
138    /// currently-selected bitmap handle.
139    pub fn bitmap_source<R: MemoryRegion + MainMem>(ptr: Ptr<R>) -> Self {
140        OpCode::BITMAP_SOURCE.build(ptr.to_raw())
141    }
142
143    pub fn bitmap_swizzle(swizzle: options::BitmapSwizzle) -> Self {
144        OpCode::BITMAP_SWIZZLE.build(swizzle.as_raw())
145    }
146
147    pub fn bitmap_transform_a(coeff: impl Into<options::MatrixCoeff>) -> Self {
148        let coeff: options::MatrixCoeff = coeff.into();
149        OpCode::BITMAP_TRANSFORM_A.build(coeff.to_raw())
150    }
151
152    pub fn bitmap_transform_b(coeff: impl Into<options::MatrixCoeff>) -> Self {
153        let coeff: options::MatrixCoeff = coeff.into();
154        OpCode::BITMAP_TRANSFORM_B.build(coeff.to_raw())
155    }
156
157    pub fn bitmap_transform_c(coeff: impl Into<options::MatrixCoeff>) -> Self {
158        let coeff: options::MatrixCoeff = coeff.into();
159        OpCode::BITMAP_TRANSFORM_C.build(coeff.to_raw())
160    }
161
162    pub fn bitmap_transform_d(coeff: impl Into<options::MatrixCoeff>) -> Self {
163        let coeff: options::MatrixCoeff = coeff.into();
164        OpCode::BITMAP_TRANSFORM_D.build(coeff.to_raw())
165    }
166
167    pub fn bitmap_transform_e(coeff: impl Into<options::MatrixCoeff>) -> Self {
168        let coeff: options::MatrixCoeff = coeff.into();
169        OpCode::BITMAP_TRANSFORM_E.build(coeff.to_raw())
170    }
171
172    pub fn bitmap_transform_f(coeff: impl Into<options::MatrixCoeff>) -> Self {
173        let coeff: options::MatrixCoeff = coeff.into();
174        OpCode::BITMAP_TRANSFORM_F.build(coeff.to_raw())
175    }
176
177    pub const fn blend_func(src: options::BlendFunc, dst: options::BlendFunc) -> Self {
178        OpCode::BLEND_FUNC.build((src as u32) << 3 | dst as u32)
179    }
180
181    pub fn call<R: crate::memory::DisplayListMem>(ptr: Ptr<R>) -> Self {
182        OpCode::CALL.build(ptr.to_raw_offset())
183    }
184
185    pub const fn clear(color: bool, stencil: bool, tag: bool) -> Self {
186        OpCode::CLEAR.build(
187            if color { 0b100 } else { 0b000 }
188                | if stencil { 0b010 } else { 0b000 }
189                | if tag { 0b001 } else { 0b000 },
190        )
191    }
192
193    pub const fn clear_color_rgb(color: RGB) -> Self {
194        OpCode::CLEAR_COLOR_RGB
195            .build((color.r as u32) << 16 | (color.g as u32) << 8 | (color.b as u32) << 0)
196    }
197
198    pub const fn clear_color_alpha(alpha: u8) -> Self {
199        OpCode::CLEAR_COLOR_A.build(alpha as u32)
200    }
201
202    pub const fn clear_color_rgba_pair(color: RGBA) -> (Self, Self) {
203        (
204            Self::clear_color_rgb(color.as_rgb()),
205            Self::clear_color_alpha(color.a),
206        )
207    }
208
209    pub const fn clear_stencil(v: u8) -> Self {
210        OpCode::CLEAR_STENCIL.build(v as u32)
211    }
212
213    pub const fn clear_tag(v: u8) -> Self {
214        OpCode::CLEAR_TAG.build(v as u32)
215    }
216
217    pub const fn color_alpha(alpha: u8) -> Self {
218        OpCode::COLOR_A.build(alpha as u32)
219    }
220
221    pub const fn color_mask(mask: options::ColorMask) -> Self {
222        OpCode::COLOR_MASK.build(mask.to_raw() as u32)
223    }
224
225    pub const fn color_rgb(color: RGB) -> Self {
226        OpCode::COLOR_RGB
227            .build((color.r as u32) << 16 | (color.g as u32) << 8 | (color.b as u32) << 0)
228    }
229
230    pub const fn display() -> Self {
231        Self::DISPLAY
232    }
233
234    pub const fn end() -> Self {
235        Self::END
236    }
237
238    pub fn jump<R: crate::memory::DisplayListMem>(ptr: Ptr<R>) -> Self {
239        OpCode::JUMP.build(ptr.to_raw_offset())
240    }
241
242    pub const fn command_from_macro(num: u8) -> Self {
243        const MASK: u32 = 0b1;
244        OpCode::MACRO.build(num as u32 & MASK)
245    }
246
247    pub const fn line_width(w: u16) -> Self {
248        OpCode::LINE_WIDTH.build((w & 0b111111111111) as u32)
249    }
250
251    pub const fn nop() -> Self {
252        Self::NOP
253    }
254
255    /// Defines the address in main memory for the palette data for index-based
256    /// bitmaps.
257    pub fn palette_source<R: MemoryRegion + MainMem>(ptr: Ptr<R>) -> Self {
258        OpCode::PALETTE_SOURCE.build(ptr.to_raw())
259    }
260
261    pub const fn point_size(size: u16) -> Self {
262        const MASK: u32 = 0b0000111111111111;
263        OpCode::POINT_SIZE.build(size as u32 & MASK)
264    }
265
266    pub const fn restore_context() -> Self {
267        Self::RESTORE_CONTEXT
268    }
269
270    pub const fn return_from_call() -> Self {
271        Self::RETURN
272    }
273
274    pub const fn save_context() -> Self {
275        Self::SAVE_CONTEXT
276    }
277
278    pub const fn scissor_size(dims: (u16, u16)) -> Self {
279        const MASK: u32 = 0b111111111111;
280        OpCode::SCISSOR_SIZE.build(((dims.0 as u32 & MASK) << 12) | (dims.1 as u32 & MASK))
281    }
282
283    pub fn scissor_pos(pos: impl Into<crate::graphics::ScissorPos>) -> Self {
284        let pos: crate::graphics::ScissorPos = pos.into();
285        let coords = pos.coords();
286        const MASK: u32 = 0b1111111111;
287        OpCode::SCISSOR_XY.build((coords.0 as u32 & MASK) << 10 | (coords.1 as u32 & MASK))
288    }
289
290    pub fn scissor_rect_pair(rect: impl Into<crate::graphics::ScissorRect>) -> (Self, Self) {
291        let rect: crate::graphics::ScissorRect = rect.into();
292        (
293            Self::scissor_pos(rect.top_left()),
294            Self::scissor_size(rect.size()),
295        )
296    }
297
298    pub const fn stencil_test(func: options::TestFunc, ref_val: u8, mask: u8) -> Self {
299        OpCode::STENCIL_FUNC.build((func as u32) << 16 | (ref_val as u32) << 8 | (mask as u32))
300    }
301
302    pub const fn stencil_mask(mask: u8) -> Self {
303        OpCode::STENCIL_MASK.build(mask as u32)
304    }
305
306    pub const fn stencil_op(fail: options::StencilOp, pass: options::StencilOp) -> Self {
307        OpCode::STENCIL_OP.build(((fail.to_raw() as u32) << 3) | (pass.to_raw() as u32))
308    }
309
310    pub const fn tag(v: u8) -> Self {
311        OpCode::TAG.build(v as u32)
312    }
313
314    pub const fn tag_mask(update: bool) -> Self {
315        OpCode::TAG_MASK.build(if update { 1 } else { 0 })
316    }
317
318    pub fn vertex_2f<Pos: Into<Vertex2F>>(pos: Pos) -> Self {
319        let pos: Vertex2F = pos.into();
320        OpCode::VERTEX2F.build((pos.x as u32) << 15 | (pos.y as u32))
321    }
322
323    pub fn vertex_2ii<Pos: Into<Vertex2II>>(pos: Pos) -> Self {
324        let pos: Vertex2II = pos.into();
325        OpCode::VERTEX2II.build((pos.x as u32) << 21 | (pos.y as u32) << 12)
326    }
327
328    pub const fn vertex_format(fmt: options::VertexFormat) -> Self {
329        OpCode::VERTEX_FORMAT.build(fmt.to_raw() as u32)
330    }
331
332    pub const fn vertex_translate_x(v: i16) -> Self {
333        OpCode::VERTEX_TRANSLATE_X.build(v as u16 as u32)
334    }
335
336    pub const fn vertex_translate_y(v: i16) -> Self {
337        OpCode::VERTEX_TRANSLATE_Y.build(v as u16 as u32)
338    }
339
340    pub const fn vertex_translate_pair(offset: (i16, i16)) -> (Self, Self) {
341        (
342            Self::vertex_translate_x(offset.0),
343            Self::vertex_translate_y(offset.1),
344        )
345    }
346}
347
348/// Trait implemented by objects that can append display list commands to
349/// a display list.
350///
351/// Implementers usually implement only `append_raw_command`, and take the
352/// default implementations of all of the other methods.
353pub trait Builder: Sized {
354    type Model: crate::models::Model;
355    type Error;
356
357    fn append_raw_command(&mut self, raw: u32) -> Result<(), Self::Error>;
358
359    fn append_command(&mut self, cmd: DLCmd) -> Result<(), Self::Error> {
360        self.append_raw_command(cmd.as_raw())
361    }
362
363    fn alpha_test(&mut self, func: options::TestFunc, ref_val: u8) -> Result<(), Self::Error> {
364        self.append_command(DLCmd::alpha_test(func, ref_val))
365    }
366
367    fn begin(&mut self, prim: options::GraphicsPrimitive) -> Result<(), Self::Error> {
368        self.append_command(DLCmd::begin(prim))
369    }
370
371    fn bitmap_cell(&mut self, idx: u8) -> Result<(), Self::Error> {
372        self.append_command(DLCmd::bitmap_cell(idx))
373    }
374
375    fn bitmap_ext_format(&mut self, format: options::BitmapExtFormat) -> Result<(), Self::Error> {
376        self.append_command(DLCmd::bitmap_ext_format(format))
377    }
378
379    fn bitmap_handle(&mut self, bmp: options::BitmapHandle) -> Result<(), Self::Error> {
380        self.append_command(DLCmd::bitmap_handle(bmp))
381    }
382
383    fn bitmap_layout_l(
384        &mut self,
385        format: options::BitmapFormat,
386        line_stride: u16,
387        height: u16,
388    ) -> Result<(), Self::Error> {
389        self.append_command(DLCmd::bitmap_layout_l(format, line_stride, height))
390    }
391
392    fn bitmap_layout_h(&mut self, line_stride: u16, height: u16) -> Result<(), Self::Error> {
393        self.append_command(DLCmd::bitmap_layout_h(line_stride, height))
394    }
395
396    fn bitmap_layout(
397        &mut self,
398        format: options::BitmapFormat,
399        line_stride: u16,
400        height: u16,
401    ) -> Result<(), Self::Error> {
402        let pair = DLCmd::bitmap_layout_pair(format, line_stride, height);
403        self.append_command(pair.0)?;
404        self.append_command(pair.1)
405    }
406
407    fn bitmap_size_l(
408        &mut self,
409        width: u16,
410        height: u16,
411        filter: options::BitmapSizeFilter,
412        wrap_x: options::BitmapWrapMode,
413        wrap_y: options::BitmapWrapMode,
414    ) -> Result<(), Self::Error> {
415        self.append_command(DLCmd::bitmap_size_l(width, height, filter, wrap_x, wrap_y))
416    }
417
418    fn bitmap_size_h(&mut self, width: u16, height: u16) -> Result<(), Self::Error> {
419        self.append_command(DLCmd::bitmap_size_h(width, height))
420    }
421
422    fn bitmap_size(
423        &mut self,
424        width: u16,
425        height: u16,
426        filter: options::BitmapSizeFilter,
427        wrap_x: options::BitmapWrapMode,
428        wrap_y: options::BitmapWrapMode,
429    ) -> Result<(), Self::Error> {
430        let pair = DLCmd::bitmap_size_pair(width, height, filter, wrap_x, wrap_y);
431        self.append_command(pair.0)?;
432        self.append_command(pair.1)
433    }
434
435    fn bitmap_swizzle(&mut self, swizzle: options::BitmapSwizzle) -> Result<(), Self::Error> {
436        self.append_command(DLCmd::bitmap_swizzle(swizzle))
437    }
438
439    fn bitmap_source(
440        &mut self,
441        ptr: Ptr<<<Self as Builder>::Model as crate::models::Model>::MainMem>,
442    ) -> Result<(), Self::Error> {
443        self.append_command(DLCmd::bitmap_source(ptr))
444    }
445
446    // A convenience wrapper around `bitmap_source`, `bitmap_layout`, and
447    // possibly `bitmap_ext_format` and `palette_source` if necessary, which
448    // associates the given bitmap with the bitmap handle most recently
449    // selected using `bitmap_handle`.
450    //
451    // This method does _not_ emit `bitmap_size` or `bitmap_size_h`, because
452    // a `Bitmap` object does not provide enough information to also set
453    // the `filter`, `wrap_x`, and `wrap_y` options.
454    //
455    // Current implementations of the graphics engine have a limited number
456    // of bits associated with the bitmap stride and height. If you pass an
457    // oversize bitmap then those values will be truncated, causing integer
458    // overflow.
459    fn bitmap_source_all(
460        &mut self,
461        bitmap: crate::graphics::Bitmap<
462            <<Self as Builder>::Model as crate::models::Model>::MainMem,
463        >,
464    ) -> Result<(), Self::Error> {
465        self.bitmap_source(bitmap.image_data)?;
466        let base_format: options::BitmapFormat = bitmap.format.into();
467        self.bitmap_layout(base_format, bitmap.stride as u16, bitmap.height as u16)?;
468        if base_format.needs_ext_format() {
469            self.bitmap_ext_format(bitmap.format)?;
470        }
471        if let Some(addr) = bitmap.palette_data {
472            self.palette_source(addr)?;
473        }
474        Ok(())
475    }
476
477    fn bitmap_transform_a(
478        &mut self,
479        coeff: impl Into<options::MatrixCoeff>,
480    ) -> Result<(), Self::Error> {
481        self.append_command(DLCmd::bitmap_transform_a(coeff))
482    }
483
484    fn bitmap_transform_b(
485        &mut self,
486        coeff: impl Into<options::MatrixCoeff>,
487    ) -> Result<(), Self::Error> {
488        self.append_command(DLCmd::bitmap_transform_b(coeff))
489    }
490
491    fn bitmap_transform_c(
492        &mut self,
493        coeff: impl Into<options::MatrixCoeff>,
494    ) -> Result<(), Self::Error> {
495        self.append_command(DLCmd::bitmap_transform_c(coeff))
496    }
497
498    fn bitmap_transform_d(
499        &mut self,
500        coeff: impl Into<options::MatrixCoeff>,
501    ) -> Result<(), Self::Error> {
502        self.append_command(DLCmd::bitmap_transform_d(coeff))
503    }
504
505    fn bitmap_transform_e(
506        &mut self,
507        coeff: impl Into<options::MatrixCoeff>,
508    ) -> Result<(), Self::Error> {
509        self.append_command(DLCmd::bitmap_transform_e(coeff))
510    }
511
512    fn bitmap_transform_f(
513        &mut self,
514        coeff: impl Into<options::MatrixCoeff>,
515    ) -> Result<(), Self::Error> {
516        self.append_command(DLCmd::bitmap_transform_f(coeff))
517    }
518
519    /// Appends six display list commands to set all six of the bitmap
520    /// transform matrix coefficients to match the given matrix.
521    fn bitmap_transform_matrix(
522        &mut self,
523        matrix: impl Into<options::Matrix3x2>,
524    ) -> Result<(), Self::Error> {
525        let matrix: options::Matrix3x2 = matrix.into();
526        self.append_command(DLCmd::bitmap_transform_a(matrix.0 .0))?;
527        self.append_command(DLCmd::bitmap_transform_b(matrix.0 .1))?;
528        self.append_command(DLCmd::bitmap_transform_c(matrix.0 .2))?;
529        self.append_command(DLCmd::bitmap_transform_d(matrix.1 .0))?;
530        self.append_command(DLCmd::bitmap_transform_e(matrix.1 .1))?;
531        self.append_command(DLCmd::bitmap_transform_f(matrix.1 .2))
532    }
533
534    fn blend_func(
535        &mut self,
536        src: options::BlendFunc,
537        dst: options::BlendFunc,
538    ) -> Result<(), Self::Error> {
539        self.append_command(DLCmd::blend_func(src, dst))
540    }
541
542    fn call(
543        &mut self,
544        addr: Ptr<<<Self as Builder>::Model as crate::models::Model>::DisplayListMem>,
545    ) -> Result<(), Self::Error> {
546        self.append_command(DLCmd::call(addr))
547    }
548
549    fn clear(&mut self, color: bool, stencil: bool, tag: bool) -> Result<(), Self::Error> {
550        self.append_command(DLCmd::clear(color, stencil, tag))
551    }
552
553    fn clear_all(&mut self) -> Result<(), Self::Error> {
554        self.append_command(DLCmd::CLEAR_ALL)
555    }
556
557    fn clear_color_rgb(&mut self, color: RGB) -> Result<(), Self::Error> {
558        self.append_command(DLCmd::clear_color_rgb(color))
559    }
560
561    fn clear_color_alpha(&mut self, alpha: u8) -> Result<(), Self::Error> {
562        self.append_command(DLCmd::clear_color_alpha(alpha))
563    }
564
565    fn clear_color_rgba(&mut self, color: RGBA) -> Result<(), Self::Error> {
566        let cmds = DLCmd::clear_color_rgba_pair(color);
567        self.append_command(cmds.0)?;
568        self.append_command(cmds.1)
569    }
570
571    fn clear_stencil(&mut self, v: u8) -> Result<(), Self::Error> {
572        self.append_command(DLCmd::clear_stencil(v))
573    }
574
575    fn clear_tag(&mut self, v: u8) -> Result<(), Self::Error> {
576        self.append_command(DLCmd::clear_tag(v))
577    }
578
579    fn color_rgb(&mut self, color: RGB) -> Result<(), Self::Error> {
580        self.append_command(DLCmd::color_rgb(color))
581    }
582
583    fn color_mask(&mut self, mask: options::ColorMask) -> Result<(), Self::Error> {
584        self.append_command(DLCmd::color_mask(mask))
585    }
586
587    fn color_alpha(&mut self, alpha: u8) -> Result<(), Self::Error> {
588        self.append_command(DLCmd::color_alpha(alpha))
589    }
590
591    fn display(&mut self) -> Result<(), Self::Error> {
592        self.append_command(DLCmd::DISPLAY)
593    }
594
595    /// Draw a graphics primitive of a particular type, with zero or vertices
596    /// defined in a closure.
597    ///
598    /// This is a helper wrapper around `begin`, followed by any vertices you
599    /// generate in your closure, followed by `end`.
600    fn draw(
601        &mut self,
602        prim: options::GraphicsPrimitive,
603        f: impl FnOnce(shape_builder::VertexBuilder<Self>) -> Result<(), Self::Error>,
604    ) -> Result<(), Self::Error> {
605        self.begin(prim)?;
606        let vb = shape_builder::VertexBuilder::new(self);
607        f(vb)?;
608        self.end()
609    }
610
611    /// Draw a graphics primitive of a particular type, with zero or vertices
612    /// defined in an iterator of vertices.
613    ///
614    /// This is a helper wrapper around `begin`, followed by any vertices
615    /// that the iterator produces, followed by `end`.
616    fn draw_iter(
617        &mut self,
618        prim: options::GraphicsPrimitive,
619        iter: impl core::iter::Iterator<Item = crate::graphics::Vertex2F>,
620    ) -> Result<(), Self::Error> {
621        self.begin(prim)?;
622        for v in iter {
623            self.vertex_2f(v)?;
624        }
625        self.end()
626    }
627
628    fn end(&mut self) -> Result<(), Self::Error> {
629        self.append_command(DLCmd::END)
630    }
631
632    fn command_from_macro(&mut self, num: u8) -> Result<(), Self::Error> {
633        self.append_command(DLCmd::command_from_macro(num))
634    }
635
636    fn jump(
637        &mut self,
638        addr: Ptr<<<Self as Builder>::Model as crate::models::Model>::DisplayListMem>,
639    ) -> Result<(), Self::Error> {
640        self.append_command(DLCmd::jump(addr))
641    }
642
643    fn line_width(&mut self, v: u16) -> Result<(), Self::Error> {
644        self.append_command(DLCmd::line_width(v))
645    }
646
647    fn nop(&mut self) -> Result<(), Self::Error> {
648        self.append_command(DLCmd::NOP)
649    }
650
651    fn palette_source(
652        &mut self,
653        ptr: Ptr<<<Self as Builder>::Model as crate::models::Model>::MainMem>,
654    ) -> Result<(), Self::Error> {
655        self.append_command(DLCmd::palette_source(ptr))
656    }
657
658    fn point_size(&mut self, size: u16) -> Result<(), Self::Error> {
659        self.append_command(DLCmd::point_size(size))
660    }
661
662    fn restore_context(&mut self) -> Result<(), Self::Error> {
663        self.append_command(DLCmd::RESTORE_CONTEXT)
664    }
665
666    fn return_from_call(&mut self) -> Result<(), Self::Error> {
667        self.append_command(DLCmd::RETURN)
668    }
669
670    fn save_context(&mut self) -> Result<(), Self::Error> {
671        self.append_command(DLCmd::SAVE_CONTEXT)
672    }
673
674    fn scissor_size(&mut self, dims: (u16, u16)) -> Result<(), Self::Error> {
675        self.append_command(DLCmd::scissor_size(dims))
676    }
677
678    fn scissor_pos(
679        &mut self,
680        pos: impl Into<crate::graphics::ScissorPos>,
681    ) -> Result<(), Self::Error> {
682        self.append_command(DLCmd::scissor_pos(pos))
683    }
684
685    fn scissor_rect(
686        &mut self,
687        rect: impl Into<crate::graphics::ScissorRect>,
688    ) -> Result<(), Self::Error> {
689        let pair = DLCmd::scissor_rect_pair(rect);
690        self.append_command(pair.0)?;
691        self.append_command(pair.1)
692    }
693
694    fn stencil_test(
695        &mut self,
696        func: options::TestFunc,
697        ref_val: u8,
698        mask: u8,
699    ) -> Result<(), Self::Error> {
700        self.append_command(DLCmd::stencil_test(func, ref_val, mask))
701    }
702
703    fn stencil_mask(&mut self, mask: u8) -> Result<(), Self::Error> {
704        self.append_command(DLCmd::stencil_mask(mask))
705    }
706
707    fn stencil_op(
708        &mut self,
709        fail: options::StencilOp,
710        pass: options::StencilOp,
711    ) -> Result<(), Self::Error> {
712        self.append_command(DLCmd::stencil_op(fail, pass))
713    }
714
715    fn tag(&mut self, v: u8) -> Result<(), Self::Error> {
716        self.append_command(DLCmd::tag(v))
717    }
718
719    fn tag_mask(&mut self, update: bool) -> Result<(), Self::Error> {
720        self.append_command(DLCmd::tag_mask(update))
721    }
722
723    fn vertex_2f<Pos: Into<Vertex2F>>(&mut self, pos: Pos) -> Result<(), Self::Error> {
724        self.append_command(DLCmd::vertex_2f(pos))
725    }
726
727    fn vertex_2ii<Pos: Into<Vertex2II>>(&mut self, pos: Pos) -> Result<(), Self::Error> {
728        self.append_command(DLCmd::vertex_2ii(pos))
729    }
730
731    fn vertex_format(&mut self, fmt: options::VertexFormat) -> Result<(), Self::Error> {
732        self.append_command(DLCmd::vertex_format(fmt))
733    }
734
735    fn vertex_translate_x(&mut self, v: i16) -> Result<(), Self::Error> {
736        self.append_command(DLCmd::vertex_translate_x(v))
737    }
738
739    fn vertex_translate_y(&mut self, v: i16) -> Result<(), Self::Error> {
740        self.append_command(DLCmd::vertex_translate_y(v))
741    }
742
743    fn vertex_translate(&mut self, offset: (i16, i16)) -> Result<(), Self::Error> {
744        let pair = DLCmd::vertex_translate_pair(offset);
745        self.append_command(pair.0)?;
746        self.append_command(pair.1)
747    }
748}
749
750/// An implementation of `Builder` that _only_ has the display
751/// list building functionality, wrapping another object that implements the
752/// trait, for situations where it would be inappropriate to use other
753/// functionality of the wrapped object while building a display list.
754pub struct JustBuilder<'a, W: Builder> {
755    w: &'a mut W,
756}
757
758impl<'a, W: Builder> JustBuilder<'a, W> {
759    fn new(w: &'a mut W) -> Self {
760        Self { w: w }
761    }
762}
763
764impl<'a, W: Builder> Builder for JustBuilder<'a, W> {
765    type Error = W::Error;
766    type Model = W::Model;
767
768    fn append_raw_command(&mut self, raw: u32) -> core::result::Result<(), W::Error> {
769        self.w.append_raw_command(raw)
770    }
771}
772
773pub fn just_builder<'a, W: Builder>(wrapped: &'a mut W) -> JustBuilder<'a, W> {
774    JustBuilder::new(wrapped)
775}
776
777/// Each command is encoded as a four-byte value. Converting to `u32` returns
778/// the raw encoding of the command, as it would be written into display
779/// list memory (endianness notwithstanding).
780impl Into<u32> for DLCmd {
781    fn into(self) -> u32 {
782        self.0
783    }
784}
785
786impl Debug for DLCmd {
787    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
788        write!(f, "DLCmd({:#010x})", self.0)
789    }
790}
791
792#[derive(Clone, Copy, PartialEq, Eq)]
793#[repr(u8)]
794#[allow(non_camel_case_types)]
795enum OpCode {
796    ALPHA_FUNC = 0x09,
797    BEGIN = 0x1F,
798    BITMAP_EXT_FORMAT = 0x2e,
799    BITMAP_HANDLE = 0x05,
800    BITMAP_LAYOUT = 0x07,
801    BITMAP_LAYOUT_H = 0x28,
802    BITMAP_SIZE = 0x08,
803    BITMAP_SIZE_H = 0x29,
804    BITMAP_SOURCE = 0x01,
805    BITMAP_SWIZZLE = 0x2f,
806    BITMAP_TRANSFORM_A = 0x15,
807    BITMAP_TRANSFORM_B = 0x16,
808    BITMAP_TRANSFORM_C = 0x17,
809    BITMAP_TRANSFORM_D = 0x18,
810    BITMAP_TRANSFORM_E = 0x19,
811    BITMAP_TRANSFORM_F = 0x1A,
812    BLEND_FUNC = 0x0b,
813    CALL = 0x1d,
814    CELL = 0x06,
815    CLEAR = 0x26,
816    CLEAR_COLOR_RGB = 0x02,
817    CLEAR_COLOR_A = 0x0F,
818    CLEAR_STENCIL = 0x11,
819    CLEAR_TAG = 0x12,
820    COLOR_A = 0x10,
821    COLOR_MASK = 0x20,
822    COLOR_RGB = 0x04,
823    DISPLAY = 0x00,
824    END = 0x21,
825    JUMP = 0x1e,
826    LINE_WIDTH = 0x0e,
827    MACRO = 0x25,
828    NOP = 0x2d,
829    PALETTE_SOURCE = 0x2a,
830    POINT_SIZE = 0x0d,
831    RESTORE_CONTEXT = 0x23,
832    RETURN = 0x24,
833    SAVE_CONTEXT = 0x22,
834    SCISSOR_SIZE = 0x1c,
835    SCISSOR_XY = 0x1b,
836    STENCIL_FUNC = 0x0a,
837    STENCIL_MASK = 0x13,
838    STENCIL_OP = 0x0c,
839    TAG = 0x03,
840    TAG_MASK = 0x14,
841    VERTEX2F = 0b01000000,  // This opcode is packed into the two MSB
842    VERTEX2II = 0b10000000, // This opcode is packed into the two MSB
843    VERTEX_FORMAT = 0x27,
844    VERTEX_TRANSLATE_X = 0x2b,
845    VERTEX_TRANSLATE_Y = 0x2c,
846}
847
848impl OpCode {
849    const fn shift(self) -> u32 {
850        (self as u32) << 24
851    }
852
853    const fn build(self, v: u32) -> DLCmd {
854        DLCmd::from_raw(self.shift() | v)
855    }
856}
857
858#[cfg(test)]
859mod tests {
860    use super::*;
861    use crate::models::testing::DisplayListMem as TestDisplayListMem;
862    use crate::models::testing::MainMem as TestMainMem;
863
864    #[test]
865    fn test_dlcmd() {
866        assert_eq!(
867            DLCmd::alpha_test(options::TestFunc::Greater, 254),
868            DLCmd::from_raw(0x090003fe),
869        );
870        assert_eq!(
871            DLCmd::alpha_test(options::TestFunc::Never, 0),
872            DLCmd::from_raw(0x09000000),
873        );
874        assert_eq!(
875            DLCmd::begin(options::GraphicsPrimitive::Bitmaps),
876            DLCmd::from_raw(0x1f000001),
877        );
878        assert_eq!(
879            DLCmd::begin(options::GraphicsPrimitive::Rects),
880            DLCmd::from_raw(0x1f000009),
881        );
882        assert_eq!(DLCmd::bitmap_cell(2), DLCmd::from_raw(0x06000002));
883        assert_eq!(
884            DLCmd::bitmap_ext_format(options::BitmapExtFormat::ARGB1555),
885            DLCmd::from_raw(0x2e000000),
886        );
887        assert_eq!(
888            DLCmd::bitmap_ext_format(options::BitmapExtFormat::ARGB4),
889            DLCmd::from_raw(0x2e000006),
890        );
891        assert_eq!(
892            DLCmd::bitmap_ext_format(options::BitmapExtFormat::TextVGA),
893            DLCmd::from_raw(0x2e00000a),
894        );
895        assert_eq!(
896            DLCmd::bitmap_handle(options::BitmapHandle::force_raw(0)),
897            DLCmd::from_raw(0x05000000),
898        );
899        assert_eq!(
900            DLCmd::bitmap_handle(options::BitmapHandle::force_raw(15)),
901            DLCmd::from_raw(0x0500000f),
902        );
903        assert_eq!(
904            DLCmd::bitmap_handle(options::BitmapHandle::force_raw(31)),
905            DLCmd::from_raw(0x0500001f),
906        );
907        assert_eq!(
908            DLCmd::bitmap_layout_l(options::BitmapFormat::ARGB4, 255, 255),
909            DLCmd::from_raw(0x0731feff),
910        );
911        assert_eq!(
912            DLCmd::bitmap_layout_l(options::BitmapFormat::ARGB4, 1024, 768),
913            DLCmd::from_raw(0x07300100),
914        );
915        assert_eq!(
916            DLCmd::bitmap_layout_h(255, 255),
917            DLCmd::from_raw(0x28000000)
918        );
919        assert_eq!(
920            DLCmd::bitmap_layout_h(1024, 768),
921            DLCmd::from_raw(0x28000004)
922        );
923        assert_eq!(
924            DLCmd::bitmap_layout_pair(options::BitmapFormat::ARGB4, 255, 255),
925            (DLCmd::from_raw(0x0731feff), DLCmd::from_raw(0x28000000)),
926        );
927        assert_eq!(
928            DLCmd::bitmap_layout_pair(options::BitmapFormat::ARGB4, 1024, 768),
929            (DLCmd::from_raw(0x07300100), DLCmd::from_raw(0x28000004)),
930        );
931        assert_eq!(
932            DLCmd::bitmap_swizzle(options::BitmapSwizzle::default()),
933            DLCmd::from_raw(0x2f000000 | 0b010011100101),
934        );
935        assert_eq!(
936            DLCmd::bitmap_size_l(
937                255,
938                255,
939                options::BitmapSizeFilter::Nearest,
940                options::BitmapWrapMode::Border,
941                options::BitmapWrapMode::Border
942            ),
943            DLCmd::from_raw(0x0801feff),
944        );
945        assert_eq!(
946            DLCmd::bitmap_size_l(
947                2048,
948                2048,
949                options::BitmapSizeFilter::Nearest,
950                options::BitmapWrapMode::Border,
951                options::BitmapWrapMode::Border
952            ),
953            DLCmd::from_raw(0x08000000),
954        );
955        assert_eq!(
956            DLCmd::bitmap_size_l(
957                1024,
958                768,
959                options::BitmapSizeFilter::Nearest,
960                options::BitmapWrapMode::Border,
961                options::BitmapWrapMode::Border
962            ),
963            DLCmd::from_raw(0x08000100),
964        );
965        assert_eq!(
966            DLCmd::bitmap_size_l(
967                1,
968                1,
969                options::BitmapSizeFilter::Bilinear,
970                options::BitmapWrapMode::Border,
971                options::BitmapWrapMode::Border
972            ),
973            DLCmd::from_raw(0x08100201),
974        );
975        assert_eq!(
976            DLCmd::bitmap_size_l(
977                1,
978                1,
979                options::BitmapSizeFilter::Nearest,
980                options::BitmapWrapMode::Repeat,
981                options::BitmapWrapMode::Border
982            ),
983            DLCmd::from_raw(0x08080201),
984        );
985        assert_eq!(
986            DLCmd::bitmap_size_l(
987                1,
988                1,
989                options::BitmapSizeFilter::Nearest,
990                options::BitmapWrapMode::Border,
991                options::BitmapWrapMode::Repeat
992            ),
993            DLCmd::from_raw(0x08040201),
994        );
995        assert_eq!(
996            DLCmd::bitmap_size_pair(
997                255,
998                255,
999                options::BitmapSizeFilter::Nearest,
1000                options::BitmapWrapMode::Border,
1001                options::BitmapWrapMode::Border
1002            ),
1003            (DLCmd::from_raw(0x0801feff), DLCmd::from_raw(0x29000000))
1004        );
1005        assert_eq!(
1006            DLCmd::bitmap_size_pair(
1007                2048,
1008                2048,
1009                options::BitmapSizeFilter::Nearest,
1010                options::BitmapWrapMode::Border,
1011                options::BitmapWrapMode::Border
1012            ),
1013            (DLCmd::from_raw(0x08000000), DLCmd::from_raw(0x29000000)),
1014        );
1015        assert_eq!(
1016            DLCmd::bitmap_size_pair(
1017                1024,
1018                768,
1019                options::BitmapSizeFilter::Nearest,
1020                options::BitmapWrapMode::Border,
1021                options::BitmapWrapMode::Border
1022            ),
1023            (DLCmd::from_raw(0x08000100), DLCmd::from_raw(0x29000009)),
1024        );
1025        assert_eq!(
1026            DLCmd::bitmap_size_pair(
1027                3 * 256,
1028                3 * 240,
1029                options::BitmapSizeFilter::Nearest,
1030                options::BitmapWrapMode::Repeat,
1031                options::BitmapWrapMode::Repeat
1032            ),
1033            (
1034                DLCmd::from_raw(0b00001000_000_0_1_1_100000000_011010000),
1035                DLCmd::from_raw(0b00101001_00000000000000000000_01_01)
1036            )
1037        );
1038        assert_eq!(
1039            DLCmd::bitmap_source(Ptr::<TestMainMem>::new(0x20)),
1040            DLCmd::from_raw(0x01000020),
1041        );
1042        assert_eq!(DLCmd::bitmap_transform_a(1), DLCmd::from_raw(0x15000100));
1043        assert_eq!(DLCmd::bitmap_transform_b(0.5), DLCmd::from_raw(0x16014000));
1044        assert_eq!(DLCmd::bitmap_transform_c(1.5), DLCmd::from_raw(0x17000180));
1045        assert_eq!(DLCmd::bitmap_transform_d(-1), DLCmd::from_raw(0x1800ff00));
1046        assert_eq!(DLCmd::bitmap_transform_e(-1.5), DLCmd::from_raw(0x1900fe80));
1047        assert_eq!(
1048            DLCmd::bitmap_transform_f(options::MatrixCoeff::new_8_8(2, 3)),
1049            DLCmd::from_raw(0x1a000203)
1050        );
1051        assert_eq!(
1052            DLCmd::blend_func(
1053                options::BlendFunc::SrcAlpha,
1054                options::BlendFunc::OneMinusDstAlpha
1055            ),
1056            DLCmd::from_raw(0x0b000015)
1057        );
1058        assert_eq!(
1059            DLCmd::call(TestDisplayListMem::ptr(4)),
1060            DLCmd::from_raw(0x1d000004)
1061        );
1062        assert_eq!(DLCmd::clear_stencil(5), DLCmd::from_raw(0x11000005));
1063        assert_eq!(DLCmd::clear_tag(6), DLCmd::from_raw(0x12000006));
1064        assert_eq!(DLCmd::color_alpha(8), DLCmd::from_raw(0x10000008));
1065        assert_eq!(
1066            DLCmd::color_mask(core::default::Default::default()),
1067            DLCmd::from_raw(0x2000000f)
1068        );
1069        assert_eq!(
1070            DLCmd::color_rgb(crate::graphics::RGB { r: 9, g: 8, b: 7 }),
1071            DLCmd::from_raw(0x04090807)
1072        );
1073        assert_eq!(DLCmd::line_width(4094), DLCmd::from_raw(0x0e000ffe));
1074        assert_eq!(DLCmd::scissor_size((10, 8)), DLCmd::from_raw(0x1c00a008));
1075        assert_eq!(DLCmd::scissor_pos((10, 8)), DLCmd::from_raw(0x1b002808));
1076        assert_eq!(
1077            DLCmd::stencil_test(options::TestFunc::Greater, 254, 2),
1078            DLCmd::from_raw(0x0a03fe02),
1079        );
1080        assert_eq!(
1081            DLCmd::stencil_test(options::TestFunc::Never, 0, 4),
1082            DLCmd::from_raw(0x0a000004),
1083        );
1084        assert_eq!(DLCmd::stencil_mask(4), DLCmd::from_raw(0x13000004));
1085        assert_eq!(
1086            DLCmd::stencil_op(options::StencilOp::Keep, options::StencilOp::Replace),
1087            DLCmd::from_raw(0x0c00000a),
1088        );
1089        assert_eq!(DLCmd::tag(4), DLCmd::from_raw(0x03000004));
1090        assert_eq!(DLCmd::tag_mask(true), DLCmd::from_raw(0x14000001));
1091        assert_eq!(DLCmd::tag_mask(false), DLCmd::from_raw(0x14000000));
1092        assert_eq!(
1093            DLCmd::vertex_format(options::VertexFormat::Sixteenth),
1094            DLCmd::from_raw(0x27000004)
1095        );
1096        assert_eq!(DLCmd::vertex_translate_x(2), DLCmd::from_raw(0x2b000002));
1097        assert_eq!(DLCmd::vertex_translate_y(4), DLCmd::from_raw(0x2c000004));
1098    }
1099}