librsmsx/libs/
graphics.rs

1use super::{
2    base_system::{BaseSystem, MSX_H, MSX_W1, MSX_W2},
3    vdp::{SCREEN0, SCREEN1, SCREEN2},
4};
5
6use std::cell::RefCell;
7
8use sdl3::{
9    pixels::{Color, PixelFormat},
10    render::{FRect, Texture},
11    surface::Surface,
12    sys::pixels::SDL_PixelFormat,
13};
14
15/// ARGB8888
16fn color_from_hex(pixel: u32) -> Color {
17    Color::from_u32(
18        unsafe { &PixelFormat::from_ll(SDL_PixelFormat::ARGB8888) },
19        pixel,
20    )
21}
22
23#[derive(Clone, Debug, Copy)]
24enum ActiveTexture {
25    Tex256,
26    Tex320,
27}
28
29#[derive(PartialEq)]
30pub enum GraphicsType {
31    None,
32    Normal,
33}
34
35impl GraphicsType {
36    pub fn create<'a>(self, quality: bool) -> GraphicsDriver<'a> {
37        match self {
38            GraphicsType::None => GraphicsDriver::None, //Rc::new(RefCell::new(NullGraphics::new(quality))),
39            GraphicsType::Normal => {
40                let surface256 = Surface::new(MSX_W2, MSX_H, unsafe {
41                    PixelFormat::from_ll(SDL_PixelFormat::RGB24)
42                })
43                .unwrap();
44                let surface320 = Surface::new(MSX_W1, MSX_H, unsafe {
45                    PixelFormat::from_ll(SDL_PixelFormat::RGB24)
46                })
47                .unwrap();
48                let colors = [
49                    color_from_hex(0xff000000),
50                    color_from_hex(0xff010101),
51                    color_from_hex(0xff3eb849),
52                    color_from_hex(0xff74d07d),
53                    color_from_hex(0xff5955e0),
54                    color_from_hex(0xff8076f1),
55                    color_from_hex(0xffb95e51),
56                    color_from_hex(0xff65dbef),
57                    color_from_hex(0xffdb6559),
58                    color_from_hex(0xffff897d),
59                    color_from_hex(0xffccc35e),
60                    color_from_hex(0xffded087),
61                    color_from_hex(0xff3aa241),
62                    color_from_hex(0xffb766b5),
63                    color_from_hex(0xffcccccc),
64                    color_from_hex(0xffffffff),
65                ];
66                let param = GraphicsDriverNormalParam {
67                    quality,
68                    surface256,
69                    surface320,
70                    active_texture: ActiveTexture::Tex256,
71                    x0: 0,
72                    y0: 0,
73                };
74                GraphicsDriver::Normal(colors, RefCell::new(param))
75            }
76        }
77    }
78}
79
80pub struct GraphicsDriverNormalParam<'a> {
81    quality: bool,
82    surface256: Surface<'a>,
83    surface320: Surface<'a>,
84    active_texture: ActiveTexture,
85    x0: i16,
86    y0: i16,
87}
88
89pub enum GraphicsDriver<'a> {
90    None,
91    Normal([Color; 16], RefCell<GraphicsDriverNormalParam<'a>>),
92}
93
94impl GraphicsDriver<'_> {
95    pub fn render(&self, sys: &mut BaseSystem) {
96        match &self {
97            GraphicsDriver::None => {}
98            GraphicsDriver::Normal(_colors, param) => {
99                let active_texture = param.borrow().active_texture;
100                let x0 = param.borrow().x0 as f32;
101                let y0 = param.borrow().y0 as f32;
102                match active_texture {
103                    ActiveTexture::Tex256 => {
104                        let canvas = sys.get_canvas();
105                        let texture_creator = canvas.texture_creator();
106                        let mut texture =
107                            Texture::from_surface(&param.borrow().surface256, &texture_creator)
108                                .unwrap();
109                        texture.set_scale_mode(if param.borrow().quality {
110                            sdl3::render::ScaleMode::Linear
111                        } else {
112                            sdl3::render::ScaleMode::Nearest
113                        });
114                        canvas.clear();
115                        canvas
116                            .copy(
117                                &texture,
118                                None,
119                                FRect {
120                                    x: x0,
121                                    y: y0,
122                                    w: x0 + MSX_W2 as f32,
123                                    h: y0 + MSX_H as f32,
124                                },
125                            )
126                            .unwrap();
127                    }
128                    ActiveTexture::Tex320 => {
129                        let canvas = sys.get_canvas();
130                        let texture_creator = canvas.texture_creator();
131                        let mut texture =
132                            Texture::from_surface(&param.borrow().surface256, &texture_creator)
133                                .unwrap();
134                        texture.set_scale_mode(if param.borrow().quality {
135                            sdl3::render::ScaleMode::Linear
136                        } else {
137                            sdl3::render::ScaleMode::Nearest
138                        });
139                        canvas.clear();
140                        canvas
141                            .copy(
142                                &texture,
143                                None,
144                                FRect {
145                                    x: x0,
146                                    y: y0,
147                                    w: x0 + MSX_W1 as f32,
148                                    h: y0 + MSX_H as f32,
149                                },
150                            )
151                            .unwrap();
152                    }
153                }
154            }
155        }
156    }
157    pub fn set_logical_resolution(&mut self, scr_mode: u8) {
158        match &self {
159            GraphicsDriver::None => {}
160            GraphicsDriver::Normal(_colors, param) => match scr_mode {
161                SCREEN0 => param.borrow_mut().active_texture = ActiveTexture::Tex320,
162                SCREEN2 => param.borrow_mut().active_texture = ActiveTexture::Tex256,
163                SCREEN1 => param.borrow_mut().active_texture = ActiveTexture::Tex256,
164                _ => panic!("setLogicalResolution: mode not supported"),
165            },
166        }
167    }
168    pub fn draw_pixel(&mut self, x: u32, y: u32, color: usize) {
169        match &self {
170            GraphicsDriver::None => {}
171            GraphicsDriver::Normal(colors, param) => {
172                let active_texture = param.borrow().active_texture;
173                match active_texture {
174                    ActiveTexture::Tex256 => {
175                        param.borrow_mut().surface256.with_lock_mut(|buffer| {
176                            let offset = y as usize * 3 * MSX_W2 as usize + x as usize * 3;
177                            buffer[offset] = colors[color].r;
178                            buffer[offset + 1] = colors[color].g;
179                            buffer[offset + 2] = colors[color].b;
180                        })
181                    }
182                    ActiveTexture::Tex320 => {
183                        param.borrow_mut().surface320.with_lock_mut(|buffer| {
184                            let offset = y as usize * 3 * MSX_W1 as usize + x as usize * 3;
185                            buffer[offset] = colors[color].r;
186                            buffer[offset + 1] = colors[color].g;
187                            buffer[offset + 2] = colors[color].b;
188                        })
189                    }
190                }
191            }
192        }
193    }
194}