Skip to content

Commit 3d0e0bf

Browse files
committed
Add a few new pixel formats
1 parent effae8e commit 3d0e0bf

File tree

3 files changed

+146
-23
lines changed

3 files changed

+146
-23
lines changed

core/src/util/pixfmt.rs

Lines changed: 129 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,71 @@ pub trait IntoPixel<T, F>: Sized {
1616
}
1717
}
1818

19-
/// Eight-bit channels in R,G,B order.
19+
/// Three eight-bit channels in R,G,B order.
20+
///
21+
/// Each channel has 2^8 = 256 distinct values, and each pixel takes three
22+
/// bytes of memory.
2023
#[derive(Copy, Clone, Default)]
2124
pub struct Rgb888;
22-
/// 5,6,5-bit channels in R,G,B order.
25+
/// Three channels with 5 bits for R, 6 bits for G, and 5 bits for B.
2326
#[derive(Copy, Clone, Default)]
2427
pub struct Rgb565;
28+
/// Three 5-bit channels plus one-bit alpha (1 = opaque, 0 = transparent).
29+
///
30+
/// Each color channel has 2^5 = 32 distinct values, and each pixel takes
31+
/// two bytes of memory.
32+
#[derive(Copy, Clone, Default)]
33+
pub struct Rgba5551;
2534

26-
/// Eight-bit channels in X,R,G,B order, where X is unused.
35+
/// Three eight-bit channels in x,R,G,B order, where x is unused.
36+
///
37+
/// Each channel has 2^8 = 256 distinct values, and each pixel takes
38+
/// four bytes of memory.
2739
#[derive(Copy, Clone, Default)]
2840
pub struct Xrgb8888;
29-
/// Eight-bit channels in R,G,B,A order.
41+
42+
/// Four eight-bit channels in R,G,B,A order.
43+
///
44+
/// Each channel has 2^8 = 256 distinct values, and each pixel takes
45+
/// four bytes of memory.
3046
#[derive(Copy, Clone, Default)]
3147
pub struct Rgba8888;
32-
/// Eight-bit channels in A,R,G,B order.
48+
49+
/// Four eight-bit channels in A,R,G,B order.
50+
///
51+
/// Each channel has 2^8 = 256 distinct values, and each pixel takes
52+
/// four bytes of memory.
3353
#[derive(Copy, Clone, Default)]
3454
pub struct Argb8888;
35-
/// Eight-bit channels in B,G,R,A order.
55+
56+
/// Four eight-bit channels in B,G,R,A order.
57+
///
58+
/// Each channel has 2^8 = 256 distinct values, and each pixel takes
59+
/// four bytes of memory.
3660
#[derive(Copy, Clone, Default)]
3761
pub struct Bgra8888;
3862

39-
/// Four-bit channels in R,G,B,A order.
63+
/// Four four-bit channels in R,G,B,A order.
64+
///
65+
/// Each channel has 2^4 = 16 distinct values, and the number of different
66+
/// RGB values is 2^12 = 4096. Each pixel takes two bytes.
4067
#[derive(Copy, Clone, Default)]
4168
pub struct Rgba4444;
4269

70+
/// Three channels with 3 bits for R and g and 2 bits for B.
71+
///
72+
/// Red and green have 2^3 = 8 and blue 2^2 = 4 distinct values. The number of
73+
/// different RGB values is 256, and each pixel takes a single byte.
74+
#[derive(Copy, Clone, Default)]
75+
pub struct Rgb332;
76+
77+
/// A single 8-bit luminance channel.
78+
#[derive(Copy, Clone, Default)]
79+
pub struct Lum8;
80+
4381
// Impls for Color3
4482

83+
// Rgb888
4584
impl IntoPixel<u32, Rgb888> for Color3 {
4685
fn into_pixel(self) -> u32 {
4786
let [r, g, b] = self.0;
@@ -55,22 +94,34 @@ impl IntoPixel<[u8; 3], Rgb888> for Color3 {
5594
}
5695
}
5796

97+
// Rgb565
5898
impl IntoPixel<u16, Rgb565> for Color3 {
99+
/// Packs `self` into a `u16` in `0bRRRRR_GGGGGG_BBBBB` format.
59100
fn into_pixel(self) -> u16 {
60101
let [r, g, b] = self.0;
61102
(r as u16 >> 3 & 0x1F) << 11
62103
| (g as u16 >> 2 & 0x3F) << 5
63104
| (b as u16 >> 3 & 0x1F)
64105
}
65106
}
66-
67107
impl IntoPixel<[u8; 2], Rgb565> for Color3 {
108+
/// Packs `self` into two bytes in `[0bGGG_BBBBB, 0bRRRRR_GGG]` format.
109+
// TODO is this correct?
68110
fn into_pixel(self) -> [u8; 2] {
69111
let c: u16 = self.into_pixel();
70112
c.to_ne_bytes()
71113
}
72114
}
73115

116+
// Rgb332
117+
impl IntoPixel<u8, Rgb332> for Color3 {
118+
/// Packs `self` into a single byte in `0bRRR_GGG_BB` format.
119+
fn into_pixel(self) -> u8 {
120+
let [r, g, b] = self.0;
121+
(r & 0b111_000_00) | (g >> 3 & 0b000_111_00) | (b >> 6)
122+
}
123+
}
124+
74125
// Impls for Color4
75126

76127
impl<F> IntoPixel<u32, F> for Color4
@@ -83,13 +134,26 @@ where
83134
}
84135
}
85136

137+
/*
138+
impl<T, F> IntoPixel<T, F> for Color4
139+
where
140+
Color3: IntoPixel<T, F>,
141+
{
142+
fn into_pixel(self) -> T {
143+
self.to_rgb().into_pixel()
144+
}
145+
}*/
146+
147+
// Xrgb8888
86148
impl IntoPixel<u32, Xrgb8888> for Color4 {
87149
fn into_pixel(self) -> u32 {
88150
let [r, g, b, _] = self.0;
89151
// From [0x00, 0xRR, 0xGG, 0xBB] to 0x00_RR_GG_BB -> big-endian!
90152
u32::from_be_bytes([0, r, g, b])
91153
}
92154
}
155+
156+
// Rgba8888 and permutations
93157
impl IntoPixel<[u8; 4], Rgba8888> for Color4 {
94158
fn into_pixel(self) -> [u8; 4] {
95159
self.0
@@ -107,11 +171,8 @@ impl IntoPixel<[u8; 4], Bgra8888> for Color4 {
107171
[b, g, r, a]
108172
}
109173
}
110-
impl IntoPixel<[u8; 3], Rgb888> for Color4 {
111-
fn into_pixel(self) -> [u8; 3] {
112-
[self.r(), self.g(), self.b()]
113-
}
114-
}
174+
175+
// Rgba4444
115176
impl IntoPixel<[u8; 2], Rgba4444> for Color4 {
116177
fn into_pixel(self) -> [u8; 2] {
117178
let c: u16 = self.into_pixel_fmt(Rgba4444);
@@ -125,18 +186,41 @@ impl IntoPixel<u16, Rgba4444> for Color4 {
125186
r << 12 | g << 8 | b << 4 | a
126187
}
127188
}
128-
impl IntoPixel<u16, Rgb565> for Color4 {
189+
190+
// Rgba 5551
191+
impl IntoPixel<u16, Rgba5551> for Color4 {
192+
/// Packs `self` into a `u16` in a `0bRRRRR_GGGGG_BBBBB_A` format.
193+
/// The alpha value `0xFF` is considered opaque, any other value
194+
/// fully transparent.
129195
fn into_pixel(self) -> u16 {
130-
self.to_rgb().into_pixel()
196+
let [r, g, b, a] = self.0;
197+
(r as u16 >> 3 & 0x1F) << 11
198+
| (g as u16 >> 3 & 0x1F) << 6
199+
| (b as u16 >> 3 & 0x1F) << 1
200+
| (a == 0xFF) as u16
131201
}
132202
}
133-
impl IntoPixel<[u8; 2], Rgb565> for Color4 {
203+
impl IntoPixel<[u8; 2], Rgba5551> for Color4 {
134204
fn into_pixel(self) -> [u8; 2] {
135-
let c: u16 = self.into_pixel_fmt(Rgb565);
205+
let c: u16 = self.into_pixel_fmt(Rgba5551);
136206
c.to_ne_bytes()
137207
}
138208
}
139209

210+
// Rgb332
211+
impl IntoPixel<u8, Rgb332> for Color4 {
212+
/// Packs `self` into a single byte in `0bRRR_GGG_BB` format.
213+
fn into_pixel(self) -> u8 {
214+
self.to_rgb().into_pixel()
215+
}
216+
}
217+
impl IntoPixel<[u8; 1], Rgb332> for Color4 {
218+
/// Packs `self` into a single byte in `0bRRR_GGG_BB` format.
219+
fn into_pixel(self) -> [u8; 1] {
220+
[self.into_pixel()]
221+
}
222+
}
223+
140224
#[cfg(test)]
141225
mod tests {
142226
use crate::math::{rgb, rgba};
@@ -160,6 +244,15 @@ mod tests {
160244
assert_eq!(pix, [0b000_00010, 0b01000_001]);
161245
}
162246

247+
#[test]
248+
fn color3_to_rgb332() {
249+
let pix: u8 = rgb(0xFF, 0x00, 0xFF).into_pixel();
250+
assert_eq!(pix, 0b111_000_11, "bits: {pix:b}");
251+
252+
let pix: u8 = rgb(0x00, 0x0FF, 0x00).into_pixel();
253+
assert_eq!(pix, 0b000_111_00, "bits: {pix:b}");
254+
}
255+
163256
#[test]
164257
fn color4_to_rgba8888() {
165258
let col = rgba(0x11u8, 0x22, 0x33, 0x44);
@@ -199,4 +292,23 @@ mod tests {
199292
let pix: u16 = COL4.into_pixel_fmt(Rgba4444);
200293
assert_eq!(pix, 0x1234);
201294
}
295+
296+
#[test]
297+
fn color4_to_rgba5551_u16() {
298+
let pix: u16 = rgba(0x40u8, 0x20, 0x10, 0).into_pixel_fmt(Rgba5551);
299+
assert_eq!(pix, 0b01000_00100_00010_0_u16, "bits: {pix:b}");
300+
let pix: u16 = rgba(0x40u8, 0x20, 0x10, 0x80).into_pixel_fmt(Rgba5551);
301+
assert_eq!(pix, 0b01000_00100_00010_0_u16, "bits: {pix:b}");
302+
let pix: u16 = rgba(0x40u8, 0x20, 0x10, 0xFF).into_pixel_fmt(Rgba5551);
303+
assert_eq!(pix, 0b01000_00100_00010_1_u16, "bits: {pix:b}");
304+
}
305+
306+
#[test]
307+
fn color4_to_rgba5551_2u8() {
308+
let pix: [u8; 2] = rgba(0x40u8, 0x20, 0x10, 0).into_pixel_fmt(Rgba5551);
309+
assert_eq!(pix, [0b00_00010_0, 0b01000_001]);
310+
let pix: [u8; 2] =
311+
rgba(0x40u8, 0x20, 0x10, 0xFF).into_pixel_fmt(Rgba5551);
312+
assert_eq!(pix, [0b00_00010_1, 0b01000_001]);
313+
}
202314
}

demos/src/bin/crates.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ use re::core::render::{
99
scene::Obj,
1010
tex::SamplerClamp,
1111
};
12-
// Try also Rgb565 or Rgba4444
12+
// Try also Rgb565, Rgba4444, or Rgb332
1313
use re::core::util::{pixfmt::Rgba8888, pnm::read_pnm};
14-
1514
use re::front::sdl2::Window;
1615
use re::geom::solids::{Build, Cube};
1716

front/src/sdl2.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use sdl2::{
1111
video::{FullscreenType, Window as SdlWindow, WindowBuildError},
1212
};
1313

14+
use super::{Frame, dims};
1415
use retrofire_core::math::{Color4, Vary};
1516
use retrofire_core::render::{
1617
Colorbuf, Context, FragmentShader, Target, raster::Scanline,
@@ -19,11 +20,9 @@ use retrofire_core::render::{
1920
use retrofire_core::util::{
2021
Dims,
2122
buf::{AsMutSlice2, Buf2, MutSlice2},
22-
pixfmt::{IntoPixel, Rgb565, Rgba4444, Rgba8888},
23+
pixfmt::*,
2324
};
2425

25-
use super::{Frame, dims};
26-
2726
/// Helper trait to support different pixel format types.
2827
pub trait PixelFmt: Copy + Default {
2928
type Pixel: AsRef<[u8]> + Copy + Sized;
@@ -104,7 +103,12 @@ impl<'t, PF: PixelFmt> Builder<'t, PF> {
104103
}
105104
/// Sets the framebuffer pixel format.
106105
///
107-
/// Supported formats are [`Rgba8888`], [`Rgb565`], and [`Rgba4444`].
106+
/// Currently supported formats are
107+
/// * [`Rgba8888`],
108+
/// * [`Rgba5551`],
109+
/// * [`Rgba4444`],
110+
/// * [`Rgb565`], and
111+
/// * [`Rgb332`].
108112
pub fn pixel_fmt(mut self, fmt: PF) -> Self {
109113
self.pixfmt = fmt;
110114
self
@@ -265,6 +269,14 @@ impl PixelFmt for Rgba4444 {
265269
type Pixel = [u8; 2];
266270
const SDL_FMT: PixelFormatEnum = PixelFormatEnum::RGBA4444;
267271
}
272+
impl PixelFmt for Rgba5551 {
273+
type Pixel = [u8; 2];
274+
const SDL_FMT: PixelFormatEnum = PixelFormatEnum::RGBA5551;
275+
}
276+
impl PixelFmt for Rgb332 {
277+
type Pixel = [u8; 1];
278+
const SDL_FMT: PixelFormatEnum = PixelFormatEnum::RGB332;
279+
}
268280

269281
impl<'a, PF, const N: usize> Target for Framebuf<'a, PF>
270282
where

0 commit comments

Comments
 (0)