// 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); // // 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 const ink_color = vec4f(1.0, 1.0, 0.0, 1.0); // yellow // Returns lit pixel (0 or 1) for ASCII code [0x20-0x7E], row r [0-7], col c [0-7]. // Encoding: 36 unique rows stored as a dictionary of 36 u8s. // Individual rows are 6-bit indices packed sequentially (760 rows * 6 bits = 4560 bits = 572 bytes + 1 sentinel). fn _dbg_char(ascii: u32, r: u32, c: u32) -> u32 { let clamp_ascii = clamp(ascii, 0x20u, 0x7Eu); let global_row = (clamp_ascii - 0x20u) * 8u + r; let start_bit = global_row * 6u; let byte_idx = start_bit / 8u; let bit_shift = start_bit % 8u; let dict = array( 0x70306000u, 0x78381808u, 0x1C6C0C34u, 0x32627C3Cu, 0x16664606u, 0x0E763656u, 0x7E3E1E6Eu, 0x6B3363FEu, 0xFF7F773Bu ); let bitstream = array( 0x00000000u, 0x51450000u, 0x00014014u, 0x00000492u, 0xC28A0000u, 0x00A29C29u, 0x81310345u, 0x24910056u, 0x00E48914u, 0xA061354Bu, 0x91450187u, 0x00000000u, 0x49249142u, 0x21490021u, 0x00914208u, 0x8C8CC480u, 0x51400004u, 0x0001456Cu, 0x40000000u, 0x00002451u, 0x0000006Cu, 0x40000000u, 0x20400051u, 0x00040914u, 0x9261648Cu, 0x52C500C4u, 0x01B14514u, 0x4508148Cu, 0x148C01B2u, 0x00C48118u, 0x9B3C8182u, 0xA41B0020u, 0x00C48105u, 0x92690246u, 0x205B00C4u, 0x00514514u, 0x9231248Cu, 0x248C00C4u, 0x00B08135u, 0x40005140u, 0x51400051u, 0x24514000u, 0x49409143u, 0xB0000031u, 0x0006C001u, 0x42042157u, 0x148C0171u, 0x00500508u, 0x1651648Cu, 0x230500C4u, 0x01249B49u, 0x9269249Au, 0x048C01A4u, 0x00C49041u, 0x52492559u, 0x041B0195u, 0x01B41069u, 0x1069041Bu, 0x048C0104u, 0x00C49259u, 0x926D2492u, 0x514C0124u, 0x00C14514u, 0x42082087u, 0x955200B5u, 0x0125595Du, 0x10410410u, 0x285D01B4u, 0x01D75D7Eu, 0x9259B612u, 0x248C0124u, 0x00C49249u, 0x1069249Au, 0x248C0104u, 0x00331249u, 0x5969249Au, 0x048C0125u, 0x00C48131u, 0x4514515Bu, 0x24920051u, 0x00C49249u, 0x12492492u, 0xD75D0053u, 0x01D8627Du, 0x8C14C492u, 0x24920124u, 0x00514531u, 0x0914205Bu, 0x924C01B4u, 0x00C24924u, 0x42149400u, 0x208C0000u, 0x00C08208u, 0x007552C4u, 0x00000000u, 0x8C000000u, 0x00002149u, 0xC0000000u, 0x00D48D04u, 0x9249A410u, 0xC00001A4u, 0x00C49048u, 0x9248D041u, 0xC00000D4u, 0x00C41B48u, 0x45685143u, 0xD0000051u, 0x30135248u, 0x9249A410u, 0xB0050124u, 0x00C14514u, 0x41041001u, 0x24103120u, 0x01255955u, 0x4514514Bu, 0xD00000C1u, 0x01D7E285u, 0x9249A000u, 0xC0000124u, 0x00C49248u, 0x9249A000u, 0xD0004106u, 0x04135248u, 0x1049A000u, 0xC0000104u, 0x00C04C40u, 0x4515B145u, 0x20000031u, 0x00D49249u, 0x12492000u, 0xD0000053u, 0x01589F75u, 0x05312000u, 0x20000123u, 0x30135249u, 0x4509B000u, 0x514301B2u, 0x0031455Cu, 0x45145145u, 0x51570051u, 0x0171450Cu, 0x00000818u, 0x00000000u, 0x00000000u, 0x00000000u ); let word_idx = byte_idx / 4u; let shift = (byte_idx % 4u) * 8u; let shift2 = 32u - (shift | select(0u, 16u, shift == 0u)); let w = ((bitstream[word_idx] >> shift) | (bitstream[word_idx + 1u] << shift2)) & 0xFFFFu; let row_idx = (w >> bit_shift) & 0x3Fu; let row_byte = (dict[row_idx / 4u] >> ((row_idx % 4u) * 8u)) & 0xFFu; return (row_byte >> c) & 1u; } // 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 (format: [-]DDD.DDD, 64×8 px) fn debug_f32(col: vec4f, pixel_pos: vec2f, origin: vec2f, value: f32) -> vec4f { let lp = pixel_pos - origin; if (lp.x < 0.0 || lp.x >= 64.0 || lp.y < 0.0 || lp.y >= 8.0) { return col; } let ix = u32(lp.x); let iy = u32(lp.y); let char_col = ix / 8u; let bit_col = ix % 8u; let neg = value < 0.0; let abs_val = min(abs(value), 999.999f); let int_part = u32(abs_val); let frac_s = min(u32((abs_val - f32(int_part)) * 1000.0 + 0.5), 999u); var ascii: u32; switch char_col { 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_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: vec4f, pixel_pos: vec2f, origin: vec2f, s: vec4u, len: u32) -> vec4f { 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))); }