Advertisement
Kitomas

work for 2025-04-25 (1/5)

Apr 25th, 2025
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 37.02 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"gdi_maze_game_2025-04-25\src\kit_utils\draw\draw_textf.cpp":
  4. #include <public_stuff.hpp>
  5. #ifdef _DRAW_TEXTF_USED
  6.  
  7.  
  8.  
  9. #if TEXT_FMT_BUFFER_LEN < 2
  10.   #error "TEXT_FMT_BUFFER_LEN must be >= 2"
  11. #endif
  12.  
  13. #define FMT_BUFFER d_tf_fmt_buffer
  14. static char d_tf_fmt_buffer[ TEXT_FMT_BUFFER_LEN ];
  15.  
  16.  
  17.  
  18.  
  19.  
  20. #define ERR_RECT TEXT_ERROR_RECT
  21.  
  22. Rect2d get_text_rectf(const char* str_fmt, s32 x, s32 y,
  23.                       bool use_negative_position_margin,
  24.                       const Color8* font, ...)
  25. {
  26.   va_list va;
  27.   va_start(va, font); // Since font is the last named variable
  28.  
  29.   s32 result = vsnPrintf(FMT_BUFFER, sizeof(FMT_BUFFER)-1, str_fmt, va);
  30.   FMT_BUFFER[ sizeof(FMT_BUFFER)-1 ] = 0; // Manual null-terminator just in case
  31.  
  32.   va_end(va);
  33.  
  34.   if(result < 0) return ERR_RECT;
  35.  
  36.   return get_text_rect(FMT_BUFFER, x, y, use_negative_position_margin, font);
  37.  
  38. }
  39.  
  40.  
  41.  
  42.  
  43.  
  44. Rect2d get_text_rectvf(const char* str_fmt, s32 x, s32 y, va_list va,
  45.                        bool use_negative_position_margin, const Color8* font)
  46. {
  47.   s32 result = vsnPrintf(FMT_BUFFER, sizeof(FMT_BUFFER)-1, str_fmt, va);
  48.   FMT_BUFFER[ sizeof(FMT_BUFFER)-1 ] = 0; // Manual null-terminator just in case
  49.  
  50.   if(result < 0) return ERR_RECT;
  51.  
  52.   return get_text_rect(FMT_BUFFER, x, y, use_negative_position_margin, font);
  53.  
  54. }
  55.  
  56.  
  57.  
  58.  
  59.  
  60. // Draws the current contents of the built-in destination buffer
  61. Rect2d draw_current_textf_buffer(s32 x, s32 y, u32 maxLength,
  62.                                  bool use_negative_position_margin,
  63.                                  const Color8* font, Color8* dst)
  64. {
  65.   maxLength = (!maxLength) ? sizeof(FMT_BUFFER)-1
  66.                            : MIN(maxLength, sizeof(FMT_BUFFER)-1);
  67.  
  68.   return draw_text(FMT_BUFFER, x, y, maxLength,
  69.                    use_negative_position_margin, font, dst);
  70.  
  71. }
  72.  
  73.  
  74.  
  75.  
  76.  
  77. Rect2d draw_textf(const char* str_fmt, s32 x, s32 y, u32 maxLength,
  78.                   bool use_negative_position_margin,
  79.                   const Color8* font, Color8* dst, ...)
  80. {
  81.   va_list va;
  82.   va_start(va, dst); // Since dst is the last named variable
  83.  
  84.   s32 result = vsnPrintf(FMT_BUFFER, sizeof(FMT_BUFFER)-1, str_fmt, va);
  85.   FMT_BUFFER[ sizeof(FMT_BUFFER)-1 ] = 0; // Manual null-terminator just in case
  86.  
  87.   va_end(va);
  88.  
  89.   if(result < 0) return ERR_RECT;
  90.  
  91.  
  92.  
  93.   maxLength = (!maxLength) ? sizeof(FMT_BUFFER)-1
  94.                            : MIN(maxLength, sizeof(FMT_BUFFER)-1);
  95.  
  96.   return draw_text(FMT_BUFFER, x, y, maxLength,
  97.                    use_negative_position_margin, font, dst);
  98.  
  99. }
  100.  
  101.  
  102.  
  103.  
  104.  
  105. #endif
  106. /******************************************************************************/
  107. /******************************************************************************/
  108. //"gdi_maze_game_2025-04-25\src\kit_utils\draw\draw_vslice.cpp":
  109. #include <public_stuff.hpp>
  110. #ifdef DRAW_VSLICE_USED
  111.  
  112. #define CHECK_BOUNDS 0
  113.  
  114.  
  115.  
  116. // Rounds a number to the nearest value,
  117. // (Only works if _x is positive!)
  118. #ifndef   POS_RND
  119. #define   POS_RND(_x) (s32)( (_x) + 0.5f )
  120. #endif /* POS_RND */
  121.  
  122.  
  123.  
  124. static Color8 tex_missing[8 + 2*2] = {2,2, 0,0,0,0,0,0,
  125.   0b00000000, 0b11000111,
  126.   0b11000111, 0b00000000,
  127. };
  128.  
  129.  
  130.  
  131.  
  132.  
  133. // Sretches a vertical column of the source's pixels,
  134. // using nearest-neighbor interpolation
  135. // (Does not take bitmap offsets into account!)
  136. void draw_vslice(s32  dst_x, f32 height,
  137.                  f32 _src_x, const Color8* src,
  138.                  Color8* dst)
  139. {
  140.   if(u32(dst_x) >= CANVAS_W) return;
  141.   if(dst == nullptr) return;
  142.  
  143.   if(src == nullptr) src = tex_missing;
  144.  
  145.   const s32 src_w  =  s32(src[0].v);
  146.   const f32 src_h  =  f32(src[1].v);
  147.   const s32 src_x  =  s32( CLAMP(_src_x, 0.0f, 1.0f) * (f32(src_w)-0.0001f) );
  148.  
  149. #if defined(_DEBUG) && CHECK_BOUNDS==1
  150.   const Color8* dst_start = dst;
  151.   const Color8* dst_end   = dst + CANVAS_W*CANVAS_H;
  152. #endif
  153.  
  154.  
  155.  
  156.   s32 src_y_lo = 0;
  157.   s32 src_y_hi = src_h-1;
  158.  
  159.   height = MAX(height, 0.0f);
  160.  
  161.   if(height > 1.0f){
  162.     const s32 src_height_pix = POS_RND((1.0f/height) * (src_h/2));
  163.     src_y_lo = s32(src_h/2)   - src_height_pix;
  164.     src_y_hi = s32(src_h/2)-1 + src_height_pix;
  165.   }
  166.  
  167.   const f32 src_span  =  f32(src_y_hi - src_y_lo + 1);
  168.  
  169.  
  170.  
  171.   height = MIN(height, 1.0f);
  172.   const s32 dst_height_pix = POS_RND(height * f32(CANVAS_H/2));
  173.  
  174.   const s32 dst_y_lo  =  (CANVAS_H/2)   - dst_height_pix;
  175.   const s32 dst_y_hi  =  (CANVAS_H/2)-1 + dst_height_pix;
  176.   const s32 dst_span  =  (dst_y_hi - dst_y_lo + 0);
  177.  
  178.  
  179.  
  180.   src += 8;
  181.   src += src_x;
  182.   dst += dst_x + dst_y_lo*CANVAS_W;
  183.  
  184.   // +1 to make sure tex_mul is always slightly below 1.0f
  185.   f32 tex_add = 1.0f/(dst_span+1);
  186.   f32 tex_mul = 0;
  187.  
  188.  
  189.  
  190.   const s32 upper_limit = dst_span*CANVAS_W;
  191.  
  192.  
  193.   for(s32 y=0; y<=upper_limit; y+=CANVAS_W){
  194.     Color8* pix = dst+y;
  195.  
  196.     #if defined(_DEBUG) && CHECK_BOUNDS==1
  197.     if(pix < dst_start  ||  pix >= dst_end){
  198.       _printf("ATTEMPTED TO WRITE BEYOND DST: (%p, %p, %p)\n",
  199.               pix, dst_start, dst_end); continue;
  200.     }
  201.     #endif
  202.  
  203.  
  204.     s32 src_y = s32( src_y_lo + src_span*tex_mul );
  205.     tex_mul += tex_add;
  206.  
  207.  
  208.     #if defined(_DEBUG) && CHECK_BOUNDS==1
  209.     if(src_y < 0  ||  src_y >= src_h){
  210.       _printf("ATTEMPTED TO READ BEYOND SRC! (%i, %i, %i)\n",
  211.               src_y, src_y_lo, src_y_hi); continue;
  212.     }
  213.     #endif
  214.  
  215.  
  216.     *pix = src[src_y * src_w];
  217.  
  218.   }
  219.  
  220. }
  221.  
  222.  
  223.  
  224.  
  225.  
  226. #endif
  227. /******************************************************************************/
  228. /******************************************************************************/
  229. //"gdi_maze_game_2025-04-25\src\kit_utils\draw\fill_rect.cpp":
  230. #include <public_stuff.hpp>
  231. #ifdef FILL_RECT_USED
  232.  
  233.  
  234.  
  235. // dst's length must be >= the length of pixels (CANVAS_W*CANVAS_H)
  236. void fill_rect(s32 x, s32 y,
  237.                s32 w, s32 h,
  238.                Color8 color,
  239.                Color8* dst)
  240. {
  241.   if(!w || !h) return;
  242.  
  243.   if(x >= CANVAS_W) return;
  244.   if(y >= CANVAS_H) return;
  245.  
  246.   if(x <= -w) return;
  247.   if(y <= -h) return;
  248.  
  249.  
  250.  
  251.   const s32 x_start  =  MAX(x, 0);
  252.   const s32 y_start  =  MAX(y, 0);
  253.  
  254.   const s32 x_end  =  MIN(x+w, CANVAS_W);
  255.   const s32 y_end  =  MIN(y+h, CANVAS_H);
  256.  
  257.   const s32 row_advance  =  CANVAS_W - (x_end-x_start);
  258.  
  259.   --dst; // -1 so pre-increment can be used
  260.   dst  +=  MIN(x_start, CANVAS_W-1);
  261.   dst  +=  MIN(y_start, CANVAS_H-1) * CANVAS_W;
  262.  
  263.  
  264.  
  265.   for(y=y_start; y<y_end; ++y){
  266.     for(x=x_start; x<x_end; ++x)
  267.       (++dst)->v = color.v;
  268.  
  269.     dst += row_advance;
  270.  
  271.   }
  272.  
  273. }
  274.  
  275.  
  276.  
  277.  
  278.  
  279. #endif
  280. /******************************************************************************/
  281. /******************************************************************************/
  282. //"gdi_maze_game_2025-04-25\src\kit_utils\draw\fill_tri.cpp":
  283. // THESE FUNCTIONS ARE NOT THREAD-SAFE,
  284. // SINCE THE SAME EDGE BUFFERS ARE USED BETWEEN CALLS
  285. #include <public_stuff.hpp>
  286.  
  287. #include <algorithm>
  288. #include <cmath>
  289.  
  290.  
  291.  
  292.  
  293.  
  294. // Returns the middle part of x(y) = x0 + ((x1-x0)/(y1-y0)) * (y - y0)
  295. static inline f32 _getInterpConstant(Fpoint2d& p0, Fpoint2d& p1){
  296.   f32 divisor = p1.y-p0.y;
  297.   if(divisor == 0) divisor = 0.000001f; // Prevents divide-by-zero
  298.   return (p1.x-p0.x)/divisor;
  299. }
  300.  
  301. #define _INTERP(_y, _p0, _constant) ( (_p0).x + (_constant) * ((_y)-(_p0.y)) )
  302. #define _INTERP_AC(_y) _INTERP(_y, a, aci)
  303. #define _INTERP_AB(_y) _INTERP(_y, a, abi)
  304. #define _INTERP_BC(_y) _INTERP(_y, b, bci)
  305.  
  306.  
  307.  
  308. static inline Fpoint2d _round_and_convert(Fpoint3d in){
  309.   Fpoint2d out;
  310.   out.x = roundf(in.x);
  311.   out.y = roundf(in.y);
  312.  
  313.   return out;
  314.  
  315. }
  316.  
  317.  
  318.  
  319. // Fpoint2d cross product's magnitude (I think?)
  320. static inline f32 _Fp2d_crossmag(const Fpoint2d& a,
  321.                                  const Fpoint2d& b,
  322.                                  const Fpoint2d& origin = {0,0})
  323. {
  324.   const Fpoint2d oa = { a.x-origin.y, a.y-origin.y };
  325.   const Fpoint2d ob = { b.x-origin.y, b.y-origin.y };
  326.  
  327.   return (oa.x*ob.y) - (oa.y*ob.x);
  328.  
  329. }
  330.  
  331.  
  332.  
  333.  
  334. /*
  335. Point2d edges_start[CANVAS_H]; // .y is for the scanline index
  336. Point2d edges_end[CANVAS_H];   // .y is unused
  337. u32 edges_count;
  338.  
  339.  
  340.  
  341.  
  342.  
  343. static ATTR_NOINLINE void _interpolate_triangle(const Fpoint3d* verts,
  344.                                                 const Triangle& tri)
  345. {
  346.   edges_count = 0; // Initialize number of rows to 0
  347.  
  348.   // z isn't needed here, so convert to Fpoint2d,
  349.   // while also aligning to the nearest pixel boundary
  350.   Fpoint2d a = _round_and_convert(verts[tri.a]);
  351.   Fpoint2d b = _round_and_convert(verts[tri.b]);
  352.   Fpoint2d c = _round_and_convert(verts[tri.c]);
  353.  
  354.   // Sort points vertically, so that a & c are top and bottom respectively
  355.   if(a.y > c.y) std::swap(a, c);
  356.   if(a.y > b.y) std::swap(a, b);
  357.   if(b.y > c.y) std::swap(b, c);
  358.  
  359.  
  360.  
  361.   // Return early if triangle's points are completely off-screen horizontally
  362.   if( (a.x < 0  &&  b.x < 0  &&  c.x < 0) ||
  363.       (a.x>=CANVAS_W && b.x>=CANVAS_W && c.x>=CANVAS_W) )
  364.   {
  365.     return;
  366.   }
  367.  
  368.   // Return early if triangle's points are completely off-screen vertically
  369.   // (Points are sorted vertically, so only c.y and a.y need to be checked)
  370.   if(c.y < 0  ||  a.y >= CANVAS_H) return;
  371.  
  372.  
  373.  
  374.   // 'Is point b on the left or right side of line ac
  375.   // (as it appears on-screen)?'
  376.   const bool isRightBend = _Fp2d_crossmag(a, b, c) > 0;
  377.  
  378.   // Precalculate interpolation constants
  379.   const f32 aci = _getInterpConstant(a, c);
  380.   const f32 abi = _getInterpConstant(a, b);
  381.   const f32 bci = _getInterpConstant(b, c);
  382.  
  383.  
  384.  
  385.   // Interpolate edges of the triangle
  386.  
  387.   // Prevents south edge trim if last row was off-screen
  388.   bool lastRowOffScreen = false;
  389.  
  390.  
  391.   // Triangle is a single scanline tall (just a horizontal line)!
  392.   if(a.y == c.y){
  393.     // (Since the south edge is trimmed, this is likely redundant,
  394.     // as this line would never be drawn in the first place!
  395.     s32 a_x = (s32)a.x,  a_y = (s32)a.y;
  396.     s32 b_x = (s32)b.x;
  397.     s32 c_x = (s32)c.x;
  398.  
  399.     edges_start[edges_count].x = MIN3(a_x, b_x, c_x);
  400.     edges_start[edges_count].y = a_y;
  401.     edges_end  [edges_count].x = MAX3(a_x, b_x, c_x);
  402.     edges_count = (edges_start[edges_count].x < CANVAS_W) &&
  403.                   (edges_end  [edges_count].x >= 0);
  404.  
  405.  
  406.  
  407.   // Triangle is >1 scanline(s) tall
  408.   } else {
  409.     #define skip_row \
  410.       { if(!lastRowOffScreen && (yi == (abc_max-1))){ lastRowOffScreen = true; } continue; }
  411.  
  412.     #define ab_max abc_max // Aliases for consistency
  413.     #define bc_max abc_max
  414.  
  415.     f32 abc_max;
  416.     Point2d* rows_ac;
  417.     Point2d* rows_abc;
  418.  
  419.     // Line ac is edge start
  420.     if(isRightBend){
  421.       rows_ac  = edges_start;
  422.       rows_abc = edges_end;
  423.  
  424.     // Line ac is edge end (so swap start and end)
  425.     } else {
  426.       rows_ac  = edges_end;
  427.       rows_abc = edges_start;
  428.  
  429.     }
  430.  
  431.  
  432.  
  433.     // If b.y < 1, nothing from a to b-1 would render
  434.     if(b.y > 0){
  435.       ab_max  =  MIN(b.y, CANVAS_H);
  436.  
  437.       for(f32 yi=MAX(a.y,0); yi<ab_max; ++yi){
  438.         // edges_start accessed directly for its y component
  439.         edges_start[edges_count].y = (s32)yi;
  440.  
  441.         // a -> c,  a -> b
  442.         rows_ac [edges_count].x = (s32)_INTERP_AC(yi);
  443.         rows_abc[edges_count].x = (s32)_INTERP_AB(yi);
  444.         if(edges_start[edges_count].x >= CANVAS_W) skip_row; // If start is past screen
  445.         if(edges_end  [edges_count].x <  0       ) skip_row; // If end is before screen
  446.         ++edges_count; // Only increment edges_count if scanline is valid to draw on
  447.  
  448.       }
  449.  
  450.     }
  451.  
  452.  
  453.  
  454.     // If b.y >= CANVAS_H, everything from b to c is hidden
  455.     if(b.y < CANVAS_H){
  456.       bc_max  =  MIN(c.y+1, CANVAS_H); //c.y+1 so the for-loop includes c.y
  457.  
  458.       for(f32 yi=MAX(b.y,0); yi<bc_max; ++yi){
  459.         // edges_start accessed directly for its y component
  460.         edges_start[edges_count].y = (s32)yi;
  461.  
  462.         // a -> c,  b -> c
  463.         rows_ac [edges_count].x = (s32)_INTERP_AC(yi);
  464.         rows_abc[edges_count].x = (s32)_INTERP_BC(yi);
  465.         if(edges_start[edges_count].x >= CANVAS_W) skip_row; // If start is past screen
  466.         if(edges_end  [edges_count].x <  0       ) skip_row; // If end is before screen
  467.         ++edges_count; // Only increment edges_count if scanline is valid to draw on
  468.  
  469.       }
  470.  
  471.     }
  472.  
  473.  
  474.   }
  475.  
  476.  
  477.  
  478.   // (Trimming the south-east edge should prevent overdraw)
  479.   // Trim south edge unless the last row OR c.y is off-screen
  480.   if(!lastRowOffScreen && (c.y < CANVAS_H))
  481.     edges_count  =  MAX(edges_count-1, 0);
  482.  
  483.   // Clip triangle width to target screen space, and trim east edge
  484.   for(u32 row=0; row<edges_count; ++row){
  485.     edges_start[row].x  =  MAX(edges_start[row].x,   0);
  486.     edges_end  [row].x  =  MIN(edges_end  [row].x-1, CANVAS_W-1);
  487.   }
  488.  
  489. }
  490.  
  491.  
  492.  
  493.  
  494.  
  495. const static Triangle tri = { 0, 1, 2 };
  496.  
  497. void fill_tri(f32 x_0, f32 y_0,
  498.               f32 x_1, f32 y_1,
  499.               f32 x_2, f32 y_2,
  500.               Color8 color)
  501. {
  502.   Fpoint3d verts[3];
  503.   verts[0] = {x_0, y_0};
  504.   verts[1] = {x_1, y_1};
  505.   verts[2] = {x_2, y_2};
  506.  
  507.   _interpolate_triangle(verts, tri);
  508.  
  509.  
  510.  
  511.   // For each row of triangle
  512.   for(u32 row=0; row<edges_count; ++row){
  513.     #if defined(_DEBUG) && 0
  514.       if(     edges_start[row].y <  0       ){ _printf("y<0\n" ); continue; }
  515.       else if(edges_start[row].y >= CANVAS_H){ _printf("y>=w\n"); continue; }
  516.     #endif
  517.  
  518.     s32 y_pos = edges_start[row].y * CANVAS_W;
  519.     s32 start = edges_start[row].x + y_pos;
  520.     s32 end   = edges_end  [row].x + y_pos;
  521.  
  522.     // For each column of row
  523.     for(s32 i=start; i<=end; ++i)
  524.       pixels[i].v = color.v;
  525.  
  526.   }
  527.  
  528. }
  529.  
  530.  
  531.  
  532.  
  533.  
  534. void fill_tris(const Fpoint3d* verts,
  535.                const Triangle* tris, u32 tris_len)
  536. {
  537.   if(verts == nullptr) return;
  538.   if(tris  == nullptr) return;
  539.   if(tris_len == 0) return;
  540.  
  541.  
  542.  
  543.   // For each triangle
  544.   for(u32 tri=0; tri<tris_len; ++tri){
  545.     _interpolate_triangle(verts, tris[tri]);
  546.  
  547.     Color8 color = tris[tri].color;
  548.  
  549.     // For each row of triangle
  550.     for(u32 row=0; row<edges_count; ++row){
  551.       s32 y_pos = edges_start[row].y * CANVAS_W;
  552.       s32 start = edges_start[row].x + y_pos;
  553.       s32 end   = edges_end  [row].x + y_pos;
  554.  
  555.       // For each column of row
  556.       for(s32 i=start; i<=end; ++i)
  557.         pixels[i].v = color.v;
  558.  
  559.     }
  560.  
  561.   }
  562.  
  563. }
  564.  
  565.  
  566.  
  567.  
  568.  
  569. void fill_tris2(const Fpoint3d* verts, const Triangle* tris,
  570.                 const u32*    indices, u32      indices_len)
  571. {
  572.   if(verts   == nullptr) return;
  573.   if(tris    == nullptr) return;
  574.   if(indices == nullptr) return;
  575.   if(indices_len == 0) return;
  576.  
  577.  
  578.  
  579.   // For each triangle
  580.   for(u32 index=0; index<indices_len; ++index){
  581.     const Triangle& tri  =  tris[ indices[index] ];
  582.  
  583.     _interpolate_triangle(verts, tri);
  584.  
  585.     Color8 color = tri.color;
  586.  
  587.     // For each row of triangle
  588.     for(u32 row=0; row<edges_count; ++row){
  589.       s32 y_pos = edges_start[row].y * CANVAS_W;
  590.       s32 start = edges_start[row].x + y_pos;
  591.       s32 end   = edges_end  [row].x + y_pos;
  592.  
  593.       // For each column of row
  594.       for(s32 i=start; i<=end; ++i)
  595.         pixels[i].v = color.v;
  596.  
  597.     }
  598.  
  599.   }
  600.  
  601. }
  602. */
  603. /******************************************************************************/
  604. /******************************************************************************/
  605. //"gdi_maze_game_2025-04-25\src\kit_utils\draw\font_pico8.cpp":
  606. #include <public_stuff.hpp>
  607. #ifdef FONT_PICO8_USED
  608.  
  609.  
  610.  
  611. // This is how pixels are stored. Each bit corresponds to
  612. // one pixel of a given char. the pixels storage order is as follows:
  613. //
  614. // -----
  615. // |CDE|
  616. // |9AB|
  617. // |678|
  618. // |345|
  619. // |012|
  620. // -----
  621. //
  622. // For example, a char with the data of "0b111100110000010" would look like:
  623. //
  624. // ----- (A question mark)
  625. // |###|
  626. // |..#|
  627. // |.##|
  628. // |...|
  629. // |.#.|
  630. // -----
  631. //
  632. // Glyphs are 3x5 pixels each, first char is 32 (' '), 96 chars in total.
  633. // This means that this font has data for chars 32-127, and nothing more
  634. //
  635. // (96-1 is used here, to make it so that if you have a font that takes up
  636. //  all 256 chars, it will still fit into a byte (2^8-1 = 255, not 256).)
  637. u8 font_pico8_packed[184] = { 3, 5, 32, 96-1, // 184B
  638.   0b00000000, 0b00000000, 0b01000001, 0b00010010,
  639.   0b10000000, 0b10110110, 0b11101111, 0b10101011,
  640.   0b01111011, 0b01101111, 0b11000100, 0b10111110,
  641.   0b11011011, 0b00000000, 0b01000100, 0b01001010,
  642.   0b00100010, 0b10010001, 0b01010100, 0b01110101,
  643.   0b00010101, 0b10111010, 0b00010000, 0b00000001,
  644.   0b00000000, 0b00001110, 0b00000100, 0b00000000,
  645.   0b00100010, 0b10001001, 0b01101111, 0b11111011,
  646.   0b01001011, 0b11011010, 0b01110011, 0b11111110,
  647.   0b00111100, 0b01001111, 0b10111110, 0b00111101,
  648.   0b10011111, 0b10111111, 0b11001111, 0b01001001,
  649.   0b11110010, 0b11101111, 0b01111011, 0b11110010,
  650.   0b00111101, 0b00000100, 0b00100001, 0b10000010,
  651.   0b01000000, 0b01000101, 0b11000100, 0b01110001,
  652.   0b01000100, 0b01010100, 0b00000100, 0b11110011,
  653.   0b01001110, 0b10101011, 0b11110110, 0b11111101,
  654.   0b10111011, 0b11011110, 0b01001001, 0b11111100,
  655.   0b10110110, 0b01111011, 0b10010110, 0b00100111,
  656.   0b11001011, 0b11011111, 0b11000100, 0b11101101,
  657.   0b11011011, 0b01001011, 0b11111010, 0b00100100,
  658.   0b10111101, 0b01011101, 0b11111011, 0b00100100,
  659.   0b01101001, 0b11111011, 0b10110111, 0b11101101,
  660.   0b11010110, 0b11010110, 0b11001001, 0b01111011,
  661.   0b10101111, 0b01010101, 0b10111011, 0b01111110,
  662.   0b01111100, 0b00101100, 0b01001001, 0b01110111,
  663.   0b11011011, 0b11101010, 0b01101101, 0b11111111,
  664.   0b10110110, 0b10101101, 0b11011010, 0b11110011,
  665.   0b11101101, 0b00100011, 0b01111110, 0b01001001,
  666.   0b01000110, 0b01001001, 0b00110001, 0b01001001,
  667.   0b00000011, 0b10101000, 0b00001110, 0b00000000,
  668.   0b00000000, 0b10010100, 0b10111110, 0b11000111,
  669.   0b10111011, 0b11100001, 0b11001001, 0b10110001,
  670.   0b01110110, 0b01111000, 0b01110110, 0b00100100,
  671.   0b00111011, 0b11011110, 0b00011100, 0b01111101,
  672.   0b10001011, 0b01001011, 0b11000111, 0b10100100,
  673.   0b10100011, 0b01011101, 0b11110001, 0b00100100,
  674.   0b01101000, 0b01111111, 0b10110100, 0b00011101,
  675.   0b11010110, 0b00011010, 0b01111001, 0b00001111,
  676.   0b10101111, 0b01000010, 0b11010111, 0b01100011,
  677.   0b10001100, 0b00100001, 0b11101001, 0b01110000,
  678.   0b01011011, 0b11101000, 0b00101101, 0b11111110,
  679.   0b00010110, 0b10101101, 0b10001010, 0b11110011,
  680.   0b11000101, 0b11000011, 0b11000011, 0b10011010,
  681.   0b00101100, 0b01001001, 0b10011010, 0b10101100,
  682.   0b00100001, 0b00100111, 0b01011110, 0b00000001,
  683. };
  684.  
  685. // This is where it unpacks to. It has the same ordering of pixels,
  686. // except instead of 1 bit per pixel, it's 1 byte.
  687. //
  688. // For example, every 15 bytes is the next char, so to find the address of
  689. // a given char, you'd basically do:
  690. // "&font_pico8[15 * char_value]"
  691. // OR
  692. // (font_pico8 + (15 * char_value))
  693. //
  694. // The first 4 bytes are: char_width, char_height, transparency, (reserved)
  695. Color8 font_pico8[4 + 3*5 * 256]; // 3844B
  696.  
  697.  
  698.  
  699.  
  700.  
  701. #endif
  702. /******************************************************************************/
  703. /******************************************************************************/
  704. //"gdi_maze_game_2025-04-25\src\kit_utils\draw\unpack_font.cpp":
  705. #include <public_stuff.hpp>
  706. #ifdef UNPACK_FONT_USED
  707.  
  708.  
  709.  
  710. bool unpack_font(Color8* dst, const u8* src,
  711.                  Color8 fontColor,
  712.                  Color8 transparencyColor)
  713. {
  714.   if(!dst || !src) return false;
  715.  
  716.   u32 w        = dst[0].v = src[0];
  717.   u32 h        = dst[1].v = src[1];
  718.   u32 first               = src[2];
  719.   u32 numchars            = src[3];
  720.  
  721.   dst[2]   = transparencyColor;
  722.   dst[3].v = 0; // (Reserved)
  723.  
  724.   // Initialize all pixels to the transparent color
  725.   memSet(&dst[4].v, transparencyColor.v, w*h*256);
  726.  
  727.  
  728.  
  729.   // Due to the fact the value in src is only a single byte wide,
  730.   // this value must be incremented to get the real value, since if
  731.   // the font has all 256 chars, only 255 of them can be written otherwise.
  732.   ++numchars;
  733.  
  734.   u32 size = w*h;
  735.  
  736.   dst += 4 + size*first; // Seek to first pixel of unpacked font data
  737.   src += 4;              // Seek to start of packed font data
  738.  
  739.  
  740.  
  741.   u32 i = 0;
  742.  
  743.   for(u32 c=0; c<numchars; ++c)
  744.   for(u32 p=0; p<    size; ++p)
  745.   {
  746.     dst[i] = (is_bit_set(src, i)) ? fontColor : transparencyColor;
  747.     ++i;
  748.   }
  749.  
  750.  
  751.  
  752.   return true;
  753.  
  754. }
  755.  
  756.  
  757.  
  758.  
  759.  
  760. #endif
  761. /******************************************************************************/
  762. /******************************************************************************/
  763. //"gdi_maze_game_2025-04-25\src\kit_utils\misc\is_bit_set.cpp":
  764. #include <public_stuff.hpp>
  765.  
  766.  
  767.  
  768. bool is_bit_set(const void* buffer, u32 which_bit){
  769.   union {
  770.     u32 value;
  771.     struct {
  772.       u32 bit  :  3;
  773.       u32 byte : 29;
  774.     };
  775.   } _which_bit;
  776.  
  777.   _which_bit.value = which_bit;
  778.  
  779.   return 1&(  (((u8*)buffer)[_which_bit.byte])  >>  _which_bit.bit  );
  780.  
  781. }
  782. /******************************************************************************/
  783. /******************************************************************************/
  784. //"gdi_maze_game_2025-04-25\src\kit_utils\misc\kit_misc.cpp":
  785. #include <public_stuff.hpp>
  786.  
  787.  
  788.  
  789. #ifdef FRAND_USED
  790. #include <stdlib.h>
  791.  
  792.  
  793.  
  794. #if RAND_MAX == 32767
  795.   #define GET_FRAND_VALUE(cast) ( (cast)(rand()<<15|rand())/0x3FFFFFFF )
  796.  
  797. #elif RAND_MAX == 2147483647
  798.   #define GET_FRAND_VALUE(cast) ( (cast)rand()/0x7FFFFFFF )
  799.  
  800. #else
  801.   #error "no definition of GET_FRAND_VALUE() available for current RAND_MAX"
  802.  
  803. #endif
  804.  
  805.  
  806.  
  807. f64 frand(){ //0.0f -> 1.0f
  808.   return GET_FRAND_VALUE(f64);
  809. }
  810.  
  811. f64 frand2(){ //-1.0f -> 1.0f
  812.   return GET_FRAND_VALUE(f64)*2.0f - 1.0f;
  813. }
  814.  
  815. f32 frandf(){ //0.0f -> 1.0f
  816.   return GET_FRAND_VALUE(f32);
  817. }
  818.  
  819. f32 frandf2(){ //-1.0f -> 1.0f
  820.   return GET_FRAND_VALUE(f32)*2.0f - 1.0f;
  821. }
  822.  
  823. #endif
  824.  
  825.  
  826.  
  827. //...
  828. /******************************************************************************/
  829. /******************************************************************************/
  830. //"gdi_maze_game_2025-04-25\src\kit_utils\misc\print_event.cpp":
  831. #include <public_stuff.hpp>
  832. #ifdef PRINT_EVENT_USED
  833. #ifdef _DEBUG
  834.  
  835.  
  836.  
  837. static char key_evt_text[][5] = { // EVENT_KEY_?
  838.   "NULL",
  839.   "CHAR",
  840.   "UP",
  841.   "DOWN",
  842. };
  843.  
  844. static char mouse_evt_text[][7] = { // EVENT_MOUSE_?
  845.   "NULL",
  846.   "MOVED",
  847.   "HWHEEL",
  848.   "VWHEEL",
  849.   "UP",
  850.   "DOWN",
  851. };
  852.  
  853. static char cursor_evt_text[][9] = { // EVENT_CURSOR_?
  854.   "NULL",
  855.   "TRAPPED",
  856.   "RELEASED",
  857. };
  858.  
  859.  
  860.  
  861.  
  862.  
  863. void print_event(Event& evt){
  864.   u16 subevent = SUBEVENT_ID(evt.type);
  865.  
  866.  
  867.  
  868.   switch(EVENT_ID(evt.type)){
  869.     case EVENT_NULL:
  870.     {
  871.       _printf("EVENT_NULL = {\n");
  872.       _printf("  .type      = EVENT_NULL,\n");
  873.       _printf("  .timestamp = %llu,\n", evt.common.timestamp);
  874.     } break;
  875.  
  876.  
  877.  
  878.     case EVENT_COMMON:
  879.     {
  880.       _printf("EVENT_COMMON = {\n");
  881.       _printf("  .type      = EVENT_COMMON,\n");
  882.       _printf("  .timestamp = %llu,\n", evt.common.timestamp);
  883.     } break;
  884.  
  885.  
  886.  
  887.     case EVENT_QUIT:
  888.     {
  889.       _printf("EVENT_COMMON = {\n");
  890.       _printf("  .type      = EVENT_COMMON,\n");
  891.       _printf("  .timestamp = %llu,\n", evt.common.timestamp);
  892.     } break;
  893.  
  894.  
  895.  
  896.     case EVENT_KEY:
  897.     {
  898.       _printf("EVENT_KEY = {\n");
  899.       _printf("  .type      = EVENT_KEY_%s,\n", key_evt_text[subevent]);
  900.       _printf("  .timestamp = %llu,\n\n", evt.key.timestamp);
  901.       _printf("  .kmods     = 0x%04X = {\n", evt.key.kmods);
  902.       _printf("    .lshift    = %i,\n", evt.key.sym.kmod.lshift);
  903.       _printf("    .rshift    = %i,\n", evt.key.sym.kmod.rshift);
  904.       _printf("    .lctrl     = %i,\n", evt.key.sym.kmod.lctrl);
  905.       _printf("    .rctrl     = %i,\n", evt.key.sym.kmod.rctrl);
  906.       _printf("    .lalt      = %i,\n", evt.key.sym.kmod.lalt);
  907.       _printf("    .ralt      = %i,\n", evt.key.sym.kmod.ralt);
  908.       _printf("    .lgui      = %i,\n", evt.key.sym.kmod.lgui);
  909.       _printf("    .rgui      = %i,\n", evt.key.sym.kmod.rgui);
  910.       _printf("    .numlock   = %i,\n", evt.key.sym.kmod.numlock);
  911.       _printf("    .capslock  = %i,\n", evt.key.sym.kmod.capslock);
  912.       _printf("    .altgraph  = %i,\n", evt.key.sym.kmod.altgraph);
  913.       _printf("    .scrollock = %i,\n", evt.key.sym.kmod.scrollock);
  914.       _printf("  }\n\n");
  915.       _printf("  .pkey    = 0x%02X,\n", evt.key.pkey);
  916.       _printf("  .vkey    = 0x%02X,\n", evt.key.vkey);
  917.       _printf("  .pressed = %s,\n", BOOL_STR(evt.key.pressed));
  918.       _printf("  .ischar  = %s,\n", BOOL_STR(evt.key.ischar));
  919.       _printf("  .repeat  = %s,\n", BOOL_STR(evt.key.repeat));
  920.     } break;
  921.  
  922.  
  923.  
  924.     case EVENT_MOUSE:
  925.     {
  926.       _printf("EVENT_MOUSE = {\n");
  927.       _printf("  .type      = EVENT_MOUSE_%s,\n\n", mouse_evt_text[subevent]);
  928.       _printf("  .button    = 0x%02X,\n", evt.mouse.button);
  929.       _printf("  .pressed   = %s,\n", BOOL_STR(evt.mouse.pressed));
  930.       _printf("  .dblClick  = %s,\n\n", BOOL_STR(evt.mouse.dblClick));
  931.       _printf("  .timestamp = %llu,\n\n", evt.mouse.timestamp);
  932.       _printf("  .x         = %5.2f,\n", evt.mouse.x);
  933.       _printf("  .y         = %5.2f,\n", evt.mouse.y);
  934.       _printf("  .dx        = %5.2f,\n", evt.mouse.dx);
  935.       _printf("  .dy        = %5.2f,\n", evt.mouse.dy);
  936.     } break;
  937.  
  938.  
  939.  
  940.     case EVENT_CURSOR:
  941.     {
  942.       _printf("EVENT_CURSOR = {\n");
  943.       _printf("  .type      = EVENT_CURSOR_%s,\n", cursor_evt_text[subevent]);
  944.       _printf("  .timestamp = %llu,\n", evt.common.timestamp);
  945.     } break;
  946.  
  947.  
  948.  
  949.     default:
  950.     {
  951.       _printf("EVENT_UNKNOWN = {\n");
  952.       _printf("  .type      = 0x%08X,\n", evt.type);
  953.       _printf("  .timestamp = %llu,\n", evt.common.timestamp);
  954.     }
  955.  
  956.  
  957.  
  958.   }
  959.  
  960.  
  961.  
  962.   _printf("}\n");
  963.  
  964. }
  965.  
  966.  
  967.  
  968.  
  969.  
  970. #endif /* _DEBUG */
  971. #endif /* PRINT_EVENT_USED */
  972. /******************************************************************************/
  973. /******************************************************************************/
  974. //"gdi_maze_game_2025-04-25\src\kit_utils\misc\snPrintf.cpp":
  975. #include <public_stuff.hpp>
  976.  
  977. #undef snprintf
  978. #undef vsnprintf
  979.  
  980. #define STB_SPRINTF_IMPLEMENTATION
  981. #include "../../../dep/stb_sprintf.h"
  982.  
  983.  
  984.  
  985.  
  986.  
  987. s32 snPrintf(char* str_dst, size_t len_max, const char* str_fmt, ...){
  988.   va_list va;
  989.   va_start(va, str_fmt);
  990.  
  991.   s32 result = 0;
  992.  
  993.   if(len_max > 0  &&  len_max <= INT_MAX){
  994.     result = stbsp_vsnprintf(str_dst, (int)len_max, str_fmt, va);
  995.   } else {
  996.     result = stbsp_vsprintf(str_dst, str_fmt, va);
  997.   }
  998.  
  999.   va_end(va);
  1000.  
  1001.   return result;
  1002.  
  1003. }
  1004.  
  1005.  
  1006.  
  1007. s32 vsnPrintf(char* str_dst, size_t len_max, const char* str_fmt, va_list va){
  1008.   if(len_max > 0  &&  len_max <= INT_MAX){
  1009.     return stbsp_vsnprintf(str_dst, (int)len_max, str_fmt, va);
  1010.  
  1011.   } else {
  1012.     return stbsp_vsprintf(str_dst, str_fmt, va);
  1013.  
  1014.   }
  1015.  
  1016. }
  1017. /******************************************************************************/
  1018. /******************************************************************************/
  1019. //"gdi_maze_game_2025-04-25\src\kit_utils\sound\AudioData.cpp":
  1020. #include <public_stuff.hpp>
  1021.  
  1022. #ifdef SOUND_STUFF_USED
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028. void AudioDataHeader::printHeader(const char* name){
  1029.   if(name != nullptr){ _printf("%s = {\n", name); }
  1030.   else               { _printf("%p = {\n", this); }
  1031. #ifdef _DEBUG
  1032.   _printf("  ->magic         = \"%.4s\"; (0x%08X)\n", (char*)&magic, magic);
  1033.  
  1034.  
  1035.   const char* fmt_txt = "?";
  1036.   switch(format){
  1037.     case SMPFMT_U8    : fmt_txt = "U8";     break;
  1038.     case SMPFMT_S8    : fmt_txt = "S8";     break;
  1039.  
  1040.     case SMPFMT_U16LSB: fmt_txt = "U16LSB"; break;
  1041.     case SMPFMT_S16LSB: fmt_txt = "S16LSB"; break;
  1042.     case SMPFMT_S24LSB: fmt_txt = "S24LSB"; break;
  1043.     case SMPFMT_S32LSB: fmt_txt = "S32LSB"; break;
  1044.     case SMPFMT_F32LSB: fmt_txt = "F32LSB"; break;
  1045.     case SMPFMT_F64LSB: fmt_txt = "F64LSB"; break;
  1046.  
  1047.     case SMPFMT_U16MSB: fmt_txt = "U16MSB"; break;
  1048.     case SMPFMT_S16MSB: fmt_txt = "S16MSB"; break;
  1049.     case SMPFMT_S24MSB: fmt_txt = "S24MSB"; break;
  1050.     case SMPFMT_S32MSB: fmt_txt = "S32MSB"; break;
  1051.     case SMPFMT_F32MSB: fmt_txt = "F32MSB"; break;
  1052.     case SMPFMT_F64MSB: fmt_txt = "F64MSB"; break;
  1053.  
  1054.     default           : fmt_txt = "UNKNOWN";
  1055.   }
  1056.  
  1057.   _printf("  ->format        = SMPFMT_%s; (0x%04X)\n", fmt_txt, format);
  1058.  
  1059.  
  1060.   _printf("  ->headerSize    = %u;\n", headerSize);
  1061.   _printf("  ->dataSize      = %llu;\n", dataSize);
  1062.   _printf("  ->loopStart     = %llu;\n", loopStart);
  1063.   _printf("  ->loopEnd       = %llu;\n", loopEnd);
  1064.   _printf("  ->numSamples    = %llu;\n", numSamples);
  1065.   _printf("  ->sampleRate    = %u;\n", sampleRate);
  1066.   _printf("  ->bitRate       = %u;\n", bitRate);
  1067.   _printf("  ->loopCount     = %u;\n", loopCount);
  1068.   _printf("  ->channels      = %u;\n", channels);
  1069.   _printf("  ->_reserved     = %u;\n", _reserved);
  1070.   _printf("  ->fmt_version   = %u;\n", fmt_version);
  1071.   _printf("  ->mode          = %u;\n", mode);
  1072.   _printf("  ->metadata_type = %u;\n", metadata_type);
  1073.   _printf("  ->samples       = %p;\n", samples);
  1074.   _printf("  ->userdata      = %p;\n", userdata);
  1075.   _printf("};");
  1076.  
  1077.  
  1078. #else
  1079.   _printf("  (AudioDataHeader::printHeader() is not available in release build!)\n}\n");
  1080.  
  1081.  
  1082. #endif /* _DEBUG */
  1083. }
  1084.  
  1085.  
  1086.  
  1087.  
  1088.  
  1089. bool AudioData::_allocate_hdr(u16 headerSize, u64 dataSize){
  1090.   if(hdr) return false;
  1091.  
  1092.   if(headerSize < sizeof(AudioDataHeader)) return false;
  1093.  
  1094.   hdr = (AudioDataHeader*)mem_alloc(headerSize+dataSize);
  1095.  
  1096.   if(hdr == nullptr) return false;
  1097.  
  1098.   mem_set(hdr, 0, headerSize+dataSize);
  1099.  
  1100.  
  1101.   hdr->magic      = KPM_FILE_SIG;
  1102.  
  1103.   hdr->headerSize = headerSize;
  1104.   hdr->dataSize   = dataSize;
  1105.  
  1106.   hdr->samples    = (u8*)hdr + hdr->headerSize;
  1107.  
  1108.  
  1109.   return true;
  1110.  
  1111. }
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117. AudioData::AudioData(AudioSampleFormatEnum format,
  1118.                      u64 numSamples, u16 channels, u32 sampleRate)
  1119. {
  1120.   if(hdr) return;
  1121.  
  1122.   const u64 dataSize = GET_AUDIO_BYTESIZE(format)*numSamples*channels;
  1123.  
  1124.   if(!_allocate_hdr(sizeof(AudioDataHeader), dataSize)) return;
  1125.  
  1126.   // (Redundant assignments are commented out here)
  1127.  
  1128. //hdr->magic         = KPM_FILE_SIG;
  1129.   hdr->format        = format;
  1130. //hdr->headerSize    = sizeof(AudioDataHeader);
  1131. //hdr->dataSize      = dataSize;
  1132.  
  1133. //hdr->loopStart     = 0;
  1134.   hdr->loopEnd       = numSamples;
  1135.  
  1136.   hdr->numSamples    = numSamples;
  1137.   hdr->sampleRate    = sampleRate;
  1138.   hdr->bitRate       = GET_AUDIO_BITSIZE(format)*sampleRate*channels;
  1139.  
  1140. //hdr->loopCount     = 0;
  1141.   hdr->channels      = channels;
  1142. //hdr->_reserved     = 0;
  1143.   hdr->fmt_version   = 1; // 1 indicates the version kit_sdl2 uses
  1144. //hdr->mode          = 0; // PCM or float data
  1145. //hdr->metadata_type = 0; // No metadata
  1146.  
  1147. //hdr->samples       = (u8*)hdr + hdr->headerSize;
  1148. //hdr->userdata      = nullptr;
  1149.  
  1150. }
  1151.  
  1152.  
  1153.  
  1154.  
  1155.  
  1156. #ifdef AUDIODATA_FILELOAD_USED
  1157.  
  1158. #define KPCM_FILE_SIG 0x4D43506B //.kpm's old file signature
  1159.  
  1160. AudioData::AudioData(const char* filePath,
  1161.                      AudioDataLoaderCallback callback)
  1162. {
  1163.   if(hdr) return;
  1164.  
  1165.   if(filePath == nullptr) return;
  1166.  
  1167.   if(!fileio_exists(filePath)) return;
  1168.  
  1169.  
  1170.  
  1171.   AudioDataHeader* _hdr;
  1172.  
  1173.   if(callback == nullptr){ // Load .kpm file
  1174.     size_t fileSize;
  1175.     _hdr = (AudioDataHeader*)fileio_read(filePath, &fileSize);
  1176.     if(_hdr == nullptr) return;
  1177.  
  1178.     // Check for the current and old version of .kpm's file signature
  1179.     // (but only if the fileSize is enough for a u32)
  1180.     if(fileSize >= sizeof(u32)  &&
  1181.        (_hdr->magic != KPM_FILE_SIG  &&  _hdr->magic != KPCM_FILE_SIG))
  1182.     {
  1183.       _free_hdr_copy: mem_free(&_hdr); return;
  1184.     }
  1185.     else if(fileSize < sizeof(AudioDataHeader)) goto _free_hdr_copy;
  1186.  
  1187. /*
  1188.     if(_hdr->magic != KIT_MAGIC_KPM) throw "magic != KIT_MAGIC_KPM";
  1189.  
  1190.     if(!isFormatValid(_hdr->format)) throw "format is invalid";
  1191.  
  1192.     if(_hdr->headerSize < sizeof(AudioDataHeader)) throw "headerSize < sizeof(AudioDataHeader)";
  1193.  
  1194.     if(_hdr->dataSize != (fileSize-_hdr->headerSize)) throw "dataSize is invalid";
  1195.  
  1196.     //(channels are checked before numSamples to prevent divide-by-zero exceptions)
  1197.     if(_hdr->channels!=1 && _hdr->channels!=2) throw "audio is neither mono nor stereo";
  1198.  
  1199.     //(numSamples is checked before loopStart/loopEnd, as their checks rely upon numSamples)
  1200.     if(_hdr->numSamples != (_hdr->dataSize/KIT_ASTREAM_FMT_BYTESIZE(_hdr->format))/_hdr->channels) throw "numSamples is invalid";
  1201.  
  1202.     if(_hdr->loopStart >= _hdr->numSamples) throw "loopStart >= numSamples";
  1203.  
  1204.     if(_hdr->loopEnd > _hdr->numSamples) throw "loopEnd > numSamples";
  1205.  
  1206.     if(_hdr->sampleRate < 1000) throw "sampleRate < 1000";
  1207.  
  1208.     if(_hdr->bitRate != _hdr->sampleRate*_hdr->channels*KIT_ASTREAM_FMT_BITSIZE(_hdr->format)) throw "bitRate is invalid";
  1209.  
  1210.     if(_hdr->bitRemainder != 0) throw "bitRemainder != 0";
  1211.  
  1212.     if(_hdr->mode != 0) throw "only mode 0 kPCM files are currently supported";
  1213. */
  1214.  
  1215.     // The only difference between 0 and 1 is that bitsPerSample is offset by -1
  1216.     if(_hdr->fmt_version == 0) ++_hdr->format;
  1217.  
  1218.     _hdr->magic       = KPM_FILE_SIG; // If it was previously kPCM, now it is kPxM
  1219.     _hdr->fmt_version = 1;
  1220.  
  1221.  
  1222.   } else {
  1223.     _hdr = callback(filePath);
  1224.     if(_hdr == nullptr) return;
  1225.  
  1226.  
  1227.   }
  1228.  
  1229.  
  1230.  
  1231.   size_t totalSize = _hdr->headerSize + _hdr->dataSize;
  1232.   hdr = (AudioDataHeader*)mem_alloc(totalSize);
  1233.   if(hdr == nullptr){ mem_free(&_hdr); return; }
  1234.  
  1235.   mem_copy(hdr, _hdr, totalSize);
  1236.   mem_free(&_hdr);
  1237.  
  1238.   hdr->samples = (u8*)hdr + hdr->headerSize;
  1239.  
  1240. }
  1241.  
  1242. #endif /* AUDIODATA_FILELOAD_USED */
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248. AudioData::~AudioData(){
  1249.   mem_free(&hdr);
  1250. }
  1251.  
  1252.  
  1253.  
  1254.  
  1255.  
  1256. #ifdef AUDIODATA_SAVEAUDIO_USED
  1257.  
  1258. bool AudioData::saveAudio(const char* filePath,
  1259.                           AudioDataSaverCallback callback)
  1260. {
  1261.   if(hdr == nullptr) return false;
  1262.   if(filePath == nullptr) return false;
  1263.  
  1264.   if(callback == nullptr){ //save .kpm
  1265.     if(!fileio_write(filePath, hdr, hdr->headerSize+hdr->dataSize))
  1266.       return false;
  1267.   } else {
  1268.     if(!callback(filePath, *hdr))
  1269.       return false;
  1270.   }
  1271.  
  1272.   return true;
  1273.  
  1274. }
  1275.  
  1276. #endif
  1277.  
  1278.  
  1279.  
  1280.  
  1281.  
  1282. #ifdef AUDIODATA_CONVERTFORMAT_USED
  1283.  
  1284. static bool _fmt_is_valid(u16 fmt){
  1285.   switch(fmt){
  1286.     case SMPFMT_U8 :
  1287.     case SMPFMT_S8 :
  1288.     case SMPFMT_U16:
  1289.     case SMPFMT_S16:
  1290.     case SMPFMT_S24:
  1291.     case SMPFMT_S32:
  1292.     case SMPFMT_F32:
  1293.     case SMPFMT_F64: return  true; // Lol
  1294.     default:         return false;
  1295.   }
  1296. }
  1297.  
  1298. // = 2^(bits-1)
  1299. #define ABS_S8_MIN         (128) //ABS_Sx_MIN is a horrible name for this,
  1300. #define ABS_S16_MIN      (32768)  //but it's the name i chose within 10 seconds
  1301. #define ABS_S24_MIN    (8388608)  //(so i may or may not change it, idk)
  1302. #define ABS_S32_MIN (2147483648)
  1303.  
  1304. struct _s24 { u8 a, b, c; } //mostly for memory alignment purposes
  1305. ATTR_PACKED; //(explicitly pack just in case; probably unnecessary)
  1306.  
  1307. union _s24u {
  1308.   _s24 v;
  1309.    s32 n : 24;
  1310.   inline _s24u(_s24 _v) : v(_v) {}
  1311.   inline _s24u(s32  _n) : n(_n&0x7FFFFF) {}
  1312. };
  1313.  
  1314. static inline f64 frm_s24(_s24 x){ return (f64)_s24u(x).n/ABS_S24_MIN; }
  1315.  
  1316. static inline _s24 to_s24(f64 x){ return _s24u((s32)(x*0x7FFFFF)).v; }
  1317.  
  1318.  
  1319.  
  1320. bool AudioData::convertFormat(AudioSampleFormatEnum format){
  1321.   if(hdr == nullptr) return false;
  1322.  
  1323.   if(hdr->format == format) return true;
  1324.  
  1325.   if(!_fmt_is_valid(hdr->format)) return false;
  1326.  
  1327.   if(!_fmt_is_valid(format)) return false;
  1328.  
  1329.  
  1330.  
  1331.   u64 totalSamples = hdr->numSamples*hdr->channels;
  1332.  
  1333.   u64    dataSize = GET_AUDIO_BYTESIZE(format)*totalSamples;
  1334.   u32     bitRate = GET_AUDIO_BITSIZE(format)*hdr->sampleRate*hdr->channels;
  1335.  
  1336.  
  1337.  
  1338.   mem_Wrapper temp_samples(totalSamples*sizeof(f64));
  1339.   f64*  tmp = (f64*)temp_samples.ptr;
  1340.   void* smp = hdr->samples;
  1341.  
  1342.   #define FOR_TS_BRK(x) for(u64 i=0; i<totalSamples; ++i){ x; } break
  1343.   #define SMPCAST(_type) (  ((_type*)smp)[i]  )
  1344.   #define FRM_CONV(_type, _scaling_factor, _modifier) \
  1345.     (  ((f64)SMPCAST(_type) _modifier) _scaling_factor  )
  1346.  
  1347.   // Convert all source samples to 64-bit floats
  1348.   switch(hdr->format){
  1349.     case SMPFMT_U8 : FOR_TS_BRK(  tmp[i] = FRM_CONV(u8 , /ABS_S8_MIN ,   -128)  );
  1350.     case SMPFMT_S8 : FOR_TS_BRK(  tmp[i] = FRM_CONV(s8 , /ABS_S8_MIN ,       )  );
  1351.     case SMPFMT_U16: FOR_TS_BRK(  tmp[i] = FRM_CONV(u16, /ABS_S16_MIN, -32768)  );
  1352.     case SMPFMT_S16: FOR_TS_BRK(  tmp[i] = FRM_CONV(s16, /ABS_S16_MIN,       )  );
  1353.     case SMPFMT_S24: FOR_TS_BRK(  tmp[i] = frm_s24(SMPCAST(_s24))               );
  1354.     case SMPFMT_S32: FOR_TS_BRK(  tmp[i] = FRM_CONV(s32, /ABS_S32_MIN,       )  );
  1355.     case SMPFMT_F32: FOR_TS_BRK(  tmp[i] = FRM_CONV(f32,             ,       )  );
  1356.     case SMPFMT_F64: mem_copy(tmp, smp, hdr->dataSize); break;
  1357.   }
  1358.  
  1359.  
  1360.  
  1361.   //resize header to match destination format's dataSize
  1362.   if(!mem_realloc(&hdr, hdr->headerSize+dataSize)) return false;
  1363.  
  1364.   //update relevant header values
  1365.   hdr->format       = format;
  1366.   hdr->dataSize     = dataSize;
  1367.   hdr->bitRate      = bitRate;
  1368.   hdr->samples      = (u8*)hdr + hdr->headerSize;
  1369.  
  1370.   smp = hdr->samples;
  1371.  
  1372.  
  1373.  
  1374.   #define TO_CONV(_type, _scl_fct, _mod) (  (_type)( tmp[i] _scl_fct _mod )  )
  1375.  
  1376.   //convert the f64 samples to the desired format
  1377.   switch(hdr->format){ //(hdr->format = format now)
  1378.     case SMPFMT_U8 : FOR_TS_BRK(  SMPCAST( u8 ) = TO_CONV(u8 , *  127,   +128)  );
  1379.     case SMPFMT_S8 : FOR_TS_BRK(  SMPCAST( s8 ) = TO_CONV(s8 , *  127,       )  );
  1380.     case SMPFMT_U16: FOR_TS_BRK(  SMPCAST( u16) = TO_CONV(u16, *32767, +32768)  );
  1381.     case SMPFMT_S16: FOR_TS_BRK(  SMPCAST( s16) = TO_CONV(s16, *32767,       )  );
  1382.     case SMPFMT_S24: FOR_TS_BRK(  SMPCAST(_s24) = to_s24(tmp[i])                );
  1383.     case SMPFMT_S32: FOR_TS_BRK(  SMPCAST( s32) = TO_CONV(s32, *0x7FFFFFFF,  )  );
  1384.     case SMPFMT_F32: FOR_TS_BRK(  SMPCAST( f32) = TO_CONV(f32,            ,  )  );
  1385.     case SMPFMT_F64: mem_copy(smp, tmp, hdr->dataSize); break;
  1386.   }
  1387.  
  1388.  
  1389.  
  1390.   return true;
  1391.  
  1392. }
  1393.  
  1394. #endif
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400. #endif
  1401.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement