// 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 // 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_char(ascii: u32, r: u32, c: u32) -> u32 { let idx = (clamp(ascii, 0x20u, 0x7Eu) - 0x20u) * 2u; let data = array( // 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[idx + (r / 4u)]; let shift = (3u - (r % 4u)) * 8u + (7u - c); return (word >> shift) & 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: 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; 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: 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))); }