summaryrefslogtreecommitdiff
path: root/src/shaders/debug
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-03-08 11:48:31 +0100
committerskal <pascal.massimino@gmail.com>2026-03-08 11:48:31 +0100
commitc43addd93191db1ed3e79af7e065004f7c52bf48 (patch)
tree21b3eca6e37536ef8bd55d1b61f07d1d6bd1b58a /src/shaders/debug
parentba7ea27ddee4398afa98a0e45b9e227bbcfae906 (diff)
feat: extend debug_print with full ASCII and debug_str()
- Replace _dbg_pixel() with _dbg_char(ascii, r, c) covering printable ASCII 0x20-0x7E (95 glyphs, C64-style 8x8 bitmaps) - Update debug_f32() to use ASCII codes directly - Add debug_str(col, pos, origin, s: vec4u, len) for rendering up to 16 chars packed 4-per-u32 big-endian handoff(Claude): debug_print now supports full ASCII strings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/shaders/debug')
-rw-r--r--src/shaders/debug/debug_print.wgsl284
1 files changed, 250 insertions, 34 deletions
diff --git a/src/shaders/debug/debug_print.wgsl b/src/shaders/debug/debug_print.wgsl
index ee9b107..22b5838 100644
--- a/src/shaders/debug/debug_print.wgsl
+++ b/src/shaders/debug/debug_print.wgsl
@@ -1,41 +1,222 @@
-// Debug print utility: renders a f32 value at a pixel position using 8×8 C64 font.
+// Debug print utility: renders f32 values and ASCII strings using an 8×8 C64-style font.
// Include: #include "debug/debug_print"
//
// Usage:
// col = debug_f32(col, pos.xy, vec2f(10.0, 10.0), my_value);
+// col = debug_str(col, pos.xy, vec2f(10.0, 20.0), vec4u(0x48454C4Cu, 0x4F000000u, 0u, 0u), 5u);
//
-// Format: [-]DDD.DDD (8 chars × 8px wide = 64×8 pixel area)
-// Range: -999.999 to 999.999
+// debug_f32 format : [-]DDD.DDD (8 chars × 8px wide = 64×8 pixel area)
+// range -999.999 to 999.999
+// debug_str format : up to 16 printable ASCII chars packed in a vec4u
+// each component holds 4 chars (MSB = leftmost char)
+// e.g. "Hi!" -> vec4u(0x48692100u, 0u, 0u, 0u), 3u
-// Returns the lit pixel (0 or 1) for glyph g, pixel row r [0-7], column c [0-7].
-// Glyphs: 0-9 = digits, 10 = '-', 11 = '.', 12 = ' '
+// Returns lit pixel (0 or 1) for ASCII code [0x20-0x7E], row r [0-7], col c [0-7].
// Encoding: 2 u32s per glyph; hi covers rows 0-3, lo covers rows 4-7.
-// Within each u32, row r occupies bits [(3-r%4)*8 + 7 : (3-r%4)*8].
-fn _dbg_pixel(g: u32, r: u32, c: u32) -> u32 {
- let data = array<u32, 26>(
- 0x3C666E76u, 0x66663C00u, // '0'
- 0x18381818u, 0x18187E00u, // '1'
- 0x3C66060Cu, 0x18307E00u, // '2'
- 0x3C66061Cu, 0x06663C00u, // '3'
- 0x0C1C2C4Cu, 0x7E0C0C00u, // '4'
- 0x7E607C06u, 0x06663C00u, // '5'
- 0x1C30607Cu, 0x66663C00u, // '6'
- 0x7E060C18u, 0x18181800u, // '7'
- 0x3C66663Cu, 0x66663C00u, // '8'
- 0x3C66663Eu, 0x060C3800u, // '9'
- 0x0000007Eu, 0x00000000u, // '-'
- 0x00000000u, 0x00181800u, // '.'
- 0x00000000u, 0x00000000u, // ' '
+// Within each u32, row r occupies bits [(3-r%4)*8+7 : (3-r%4)*8].
+fn _dbg_char(ascii: u32, r: u32, c: u32) -> u32 {
+ let idx = (clamp(ascii, 0x20u, 0x7Eu) - 0x20u) * 2u;
+ let data = array<u32, 190>(
+ // 0x20 ' '
+ 0x00000000u, 0x00000000u,
+ // 0x21 '!'
+ 0x18181818u, 0x00180000u,
+ // 0x22 '"'
+ 0x66660000u, 0x00000000u,
+ // 0x23 '#'
+ 0x36367F36u, 0x7F363600u,
+ // 0x24 '$'
+ 0x183E603Cu, 0x067C1800u,
+ // 0x25 '%'
+ 0x62660C18u, 0x30664600u,
+ // 0x26 '&'
+ 0x386C6876u, 0xDCCC7600u,
+ // 0x27 "'"
+ 0x18183000u, 0x00000000u,
+ // 0x28 '('
+ 0x0C183030u, 0x30180C00u,
+ // 0x29 ')'
+ 0x30180C0Cu, 0x0C183000u,
+ // 0x2A '*'
+ 0x00663CFFu, 0x3C660000u,
+ // 0x2B '+'
+ 0x0018187Eu, 0x18180000u,
+ // 0x2C ','
+ 0x00000000u, 0x00181830u,
+ // 0x2D '-'
+ 0x0000007Eu, 0x00000000u,
+ // 0x2E '.'
+ 0x00000000u, 0x00181800u,
+ // 0x2F '/'
+ 0x00060C18u, 0x30600000u,
+ // 0x30 '0'
+ 0x3C666E76u, 0x66663C00u,
+ // 0x31 '1'
+ 0x18381818u, 0x18187E00u,
+ // 0x32 '2'
+ 0x3C66060Cu, 0x18307E00u,
+ // 0x33 '3'
+ 0x3C66061Cu, 0x06663C00u,
+ // 0x34 '4'
+ 0x0C1C2C4Cu, 0x7E0C0C00u,
+ // 0x35 '5'
+ 0x7E607C06u, 0x06663C00u,
+ // 0x36 '6'
+ 0x1C30607Cu, 0x66663C00u,
+ // 0x37 '7'
+ 0x7E060C18u, 0x18181800u,
+ // 0x38 '8'
+ 0x3C66663Cu, 0x66663C00u,
+ // 0x39 '9'
+ 0x3C66663Eu, 0x060C3800u,
+ // 0x3A ':'
+ 0x00181800u, 0x00181800u,
+ // 0x3B ';'
+ 0x00181800u, 0x00181830u,
+ // 0x3C '<'
+ 0x0E183060u, 0x30180E00u,
+ // 0x3D '='
+ 0x00007E00u, 0x007E0000u,
+ // 0x3E '>'
+ 0x70180C06u, 0x0C187000u,
+ // 0x3F '?'
+ 0x3C66060Cu, 0x18001800u,
+ // 0x40 '@'
+ 0x3C666E6Au, 0x6E603C00u,
+ // 0x41 'A'
+ 0x183C6666u, 0x7E666600u,
+ // 0x42 'B'
+ 0x7C66667Cu, 0x66667C00u,
+ // 0x43 'C'
+ 0x3C666060u, 0x60663C00u,
+ // 0x44 'D'
+ 0x786C6666u, 0x666C7800u,
+ // 0x45 'E'
+ 0x7E60607Cu, 0x60607E00u,
+ // 0x46 'F'
+ 0x7E60607Cu, 0x60606000u,
+ // 0x47 'G'
+ 0x3C66606Eu, 0x66663C00u,
+ // 0x48 'H'
+ 0x6666667Eu, 0x66666600u,
+ // 0x49 'I'
+ 0x3C181818u, 0x18183C00u,
+ // 0x4A 'J'
+ 0x1E0C0C0Cu, 0x0C6C3800u,
+ // 0x4B 'K'
+ 0x666C7870u, 0x786C6600u,
+ // 0x4C 'L'
+ 0x60606060u, 0x60607E00u,
+ // 0x4D 'M'
+ 0xC6EEFED6u, 0xC6C6C600u,
+ // 0x4E 'N'
+ 0x66767E6Eu, 0x66666600u,
+ // 0x4F 'O'
+ 0x3C666666u, 0x66663C00u,
+ // 0x50 'P'
+ 0x7C66667Cu, 0x60606000u,
+ // 0x51 'Q'
+ 0x3C666666u, 0x663C0E00u,
+ // 0x52 'R'
+ 0x7C66667Cu, 0x786C6600u,
+ // 0x53 'S'
+ 0x3C66603Cu, 0x06663C00u,
+ // 0x54 'T'
+ 0x7E181818u, 0x18181800u,
+ // 0x55 'U'
+ 0x66666666u, 0x66663C00u,
+ // 0x56 'V'
+ 0x66666666u, 0x663C1800u,
+ // 0x57 'W'
+ 0xC6C6C6D6u, 0xFEEEC600u,
+ // 0x58 'X'
+ 0x66663C18u, 0x3C666600u,
+ // 0x59 'Y'
+ 0x6666663Cu, 0x18181800u,
+ // 0x5A 'Z'
+ 0x7E060C18u, 0x30607E00u,
+ // 0x5B '['
+ 0x3C303030u, 0x30303C00u,
+ // 0x5C '\'
+ 0x00603018u, 0x0C060000u,
+ // 0x5D ']'
+ 0x3C0C0C0Cu, 0x0C0C3C00u,
+ // 0x5E '^'
+ 0x10386CC6u, 0x00000000u,
+ // 0x5F '_'
+ 0x00000000u, 0x000000FFu,
+ // 0x60 '`'
+ 0x30180C00u, 0x00000000u,
+ // 0x61 'a'
+ 0x00003C06u, 0x3E663E00u,
+ // 0x62 'b'
+ 0x60607C66u, 0x66667C00u,
+ // 0x63 'c'
+ 0x00003C66u, 0x60663C00u,
+ // 0x64 'd'
+ 0x06063E66u, 0x66663E00u,
+ // 0x65 'e'
+ 0x00003C66u, 0x7E603C00u,
+ // 0x66 'f'
+ 0x0E18187Cu, 0x18181800u,
+ // 0x67 'g'
+ 0x00003E66u, 0x663E063Cu,
+ // 0x68 'h'
+ 0x60607C66u, 0x66666600u,
+ // 0x69 'i'
+ 0x18003818u, 0x18183C00u,
+ // 0x6A 'j'
+ 0x06000606u, 0x0606663Cu,
+ // 0x6B 'k'
+ 0x6060666Cu, 0x786C6600u,
+ // 0x6C 'l'
+ 0x38181818u, 0x18183C00u,
+ // 0x6D 'm'
+ 0x0000C6EEu, 0xFED6C600u,
+ // 0x6E 'n'
+ 0x00007C66u, 0x66666600u,
+ // 0x6F 'o'
+ 0x00003C66u, 0x66663C00u,
+ // 0x70 'p'
+ 0x00007C66u, 0x667C6060u,
+ // 0x71 'q'
+ 0x00003E66u, 0x663E0606u,
+ // 0x72 'r'
+ 0x00007C66u, 0x60606000u,
+ // 0x73 's'
+ 0x00003C60u, 0x3C063C00u,
+ // 0x74 't'
+ 0x18187E18u, 0x18180E00u,
+ // 0x75 'u'
+ 0x00006666u, 0x66663E00u,
+ // 0x76 'v'
+ 0x00006666u, 0x663C1800u,
+ // 0x77 'w'
+ 0x0000C6C6u, 0xD6FE6C00u,
+ // 0x78 'x'
+ 0x0000663Cu, 0x183C6600u,
+ // 0x79 'y'
+ 0x00006666u, 0x663E063Cu,
+ // 0x7A 'z'
+ 0x00007E0Cu, 0x18307E00u,
+ // 0x7B '{'
+ 0x0E181870u, 0x18180E00u,
+ // 0x7C '|'
+ 0x18181818u, 0x18181800u,
+ // 0x7D '}'
+ 0x7018180Eu, 0x18187000u,
+ // 0x7E '~'
+ 0x76DC0000u, 0x00000000u,
);
- let word = data[g * 2u + (r / 4u)];
+ let word = data[idx + (r / 4u)];
let shift = (3u - (r % 4u)) * 8u + (7u - c);
return (word >> shift) & 1u;
}
-// Overlays printed value onto col, returning updated RGB.
+// Overlays a f32 value onto col, returning updated RGB.
// pixel_pos : @builtin(position).xy
// origin : top-left corner of text in screen pixels
-// value : f32 to display
+// value : f32 to display (format: [-]DDD.DDD, 64×8 px)
fn debug_f32(col: vec3f, pixel_pos: vec2f, origin: vec2f, value: f32) -> vec3f {
let ink_color = vec3f(1.0, 1.0, 0.0); // yellow
let lp = pixel_pos - origin;
@@ -52,16 +233,51 @@ fn debug_f32(col: vec3f, pixel_pos: vec2f, origin: vec2f, value: f32) -> vec3f {
let int_part = u32(abs_val);
let frac_s = min(u32((abs_val - f32(int_part)) * 1000.0 + 0.5), 999u);
- var g: u32;
+ var ascii: u32;
switch char_col {
- case 0u: { g = select(12u, 10u, neg); } // sign
- case 1u: { g = (int_part / 100u) % 10u; } // hundreds
- case 2u: { g = (int_part / 10u) % 10u; } // tens
- case 3u: { g = int_part % 10u; } // ones
- case 4u: { g = 11u; } // '.'
- case 5u: { g = (frac_s / 100u) % 10u; } // tenths
- case 6u: { g = (frac_s / 10u) % 10u; } // hundredths
- default: { g = frac_s % 10u; } // thousandths
+ case 0u: { ascii = select(0x20u, 0x2Du, neg); } // ' ' or '-'
+ case 1u: { ascii = 0x30u + (int_part / 100u) % 10u; } // hundreds
+ case 2u: { ascii = 0x30u + (int_part / 10u) % 10u; } // tens
+ case 3u: { ascii = 0x30u + int_part % 10u; } // ones
+ case 4u: { ascii = 0x2Eu; } // '.'
+ case 5u: { ascii = 0x30u + (frac_s / 100u) % 10u; } // tenths
+ case 6u: { ascii = 0x30u + (frac_s / 10u) % 10u; } // hundredths
+ default: { ascii = 0x30u + frac_s % 10u; } // thousandths
}
- return mix(col, ink_color, f32(_dbg_pixel(g, iy, bit_col)));
+ return mix(col, ink_color, f32(_dbg_char(ascii, iy, bit_col)));
+}
+
+// Overlays an ASCII string onto col, returning updated RGB.
+// pixel_pos : @builtin(position).xy
+// origin : top-left corner of text in screen pixels
+// s : up to 16 chars packed as 4 bytes per u32, big-endian
+// s.x = chars 0-3, s.y = chars 4-7, s.z = chars 8-11, s.w = chars 12-15
+// len : number of characters to render (1-16)
+//
+// Example — "Hello" (5 chars, ASCII 0x48 0x65 0x6C 0x6C 0x6F):
+// debug_str(col, pos.xy, origin, vec4u(0x48656C6Cu, 0x6F000000u, 0u, 0u), 5u)
+fn debug_str(col: vec3f, pixel_pos: vec2f, origin: vec2f, s: vec4u, len: u32) -> vec3f {
+ let ink_color = vec3f(1.0, 1.0, 0.0); // yellow
+ let lp = pixel_pos - origin;
+ let max_w = f32(len * 8u);
+ if (lp.x < 0.0 || lp.x >= max_w || lp.y < 0.0 || lp.y >= 8.0) {
+ return col;
+ }
+ let ix = u32(lp.x);
+ let iy = u32(lp.y);
+ let char_idx = ix / 8u;
+ let bit_col = ix % 8u;
+
+ // Extract byte from packed vec4u (big-endian: MSB = leftmost char)
+ let word_idx = char_idx / 4u;
+ let byte_pos = 3u - (char_idx % 4u); // shift in bytes within the u32
+ var packed: u32;
+ switch word_idx {
+ case 0u: { packed = s.x; }
+ case 1u: { packed = s.y; }
+ case 2u: { packed = s.z; }
+ default: { packed = s.w; }
+ }
+ let ascii = (packed >> (byte_pos * 8u)) & 0xFFu;
+ return mix(col, ink_color, f32(_dbg_char(ascii, iy, bit_col)));
}