Advertisement
Kitomas

2024-07-19 (1/13)

Jul 19th, 2024
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.75 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"kit_w32\src\kit_win32\kit_BitmapFont.cpp":
  4. #include "_kit_common_shared.hpp"
  5.  
  6. #define KIT_INVALID_BITMAPFONT _kit_invalid_bitmapfont
  7.  
  8. #define KIT_IS_INVALID_BITMAPFONT (!_valid && !_constructing)
  9.  
  10.  
  11. namespace kit {
  12.  
  13. static const char _kit_invalid_bitmapfont[] = "invalid bitmap font";
  14.  
  15.  
  16.  
  17.  
  18. void BitmapFont::_constructFromMemory(Bitmap* fontAtlas,
  19.                                       const s16* stepLengths, s16  newlineLen,
  20.                                       const shape::spoint* offsets, bool verticalNewline)
  21. {
  22.   _type = KIT_CLASSTYPE_BITMAPFONT;
  23.  
  24.   //check if fontAtlas is valid
  25.   if(fontAtlas == nullptr)
  26.     throw "fontAtlas = nullptr";
  27.   if(!KIT_IS_CLASS_TYPE(fontAtlas, KIT_CLASSTYPE_BITMAP))
  28.     throw "*fontAtlas is not a Bitmap";
  29.   if(!KIT_IS_CLASS_VALID(fontAtlas))
  30.     throw "*fontAtlas is invalid";
  31.  
  32.   _fontAtlas = fontAtlas;
  33.  
  34.  
  35.   shape::point atlasSize = _fontAtlas->getSize();
  36.  
  37.   if((atlasSize.x%16) || (atlasSize.y%16)) throw "(atlas size % 16) != 0";
  38.  
  39.   _glyphSrc.w = atlasSize.x/16 - 1; //-1 to account for alignment pixel
  40.   _glyphSrc.h = atlasSize.y/16 - 1;
  41.  
  42.   if(_glyphSrc.w > 32767) throw "glyph width > 32767";
  43.   if(_glyphSrc.h > 32767) throw "glyph height > 32767";
  44.  
  45.   //(_glyphDst is set every time putChar() is called)
  46.  
  47.   _glyphScale.x = 1.0f;
  48.   _glyphScale.y = 1.0f;
  49.  
  50.  
  51.   _verticalNewline = verticalNewline;
  52.   //_glyphSrc.?+1 for a bit of default spacing
  53.    //(has nothing to do with alignment pixels)
  54.   s16 defStep    = (verticalNewline) ? _glyphSrc.w+1 : _glyphSrc.h+1;
  55.   s16 defNewline = (verticalNewline) ? _glyphSrc.h+1 : _glyphSrc.w+1;
  56.  
  57.  
  58.   if(offsets != nullptr) memory::copy(_offsets, offsets, sizeof(shape::spoint)*256);
  59.   else                   memory::set( _offsets, 0, sizeof(shape::spoint)*256);
  60.  
  61.   _newlineLen = (newlineLen != -32768) ? newlineLen : defNewline;
  62.  
  63.   if(stepLengths != nullptr){
  64.     memory::copy(_stepLengths, stepLengths, 256);
  65.   } else {
  66.     //if stepLengths is not given, fill in _stepLengths with default values
  67.     for(s32 i=0; i<256; ++i) _stepLengths[i] = defStep;
  68.     _stepLengths[0x7F] = 0; //control code prefix should be length 0
  69.     _stepLengths['\b'] = -defStep;  //backspace should actually go back a space
  70.     _stepLengths['\t'] = defStep*2; //change to *4 if needed
  71.   }
  72.  
  73.  
  74.   _valid = true;
  75.   _constructing = false;
  76. }
  77.  
  78.  
  79.  
  80.  
  81. //loads a bitmap from an image file
  82. BitmapFont::BitmapFont(const char* filePath, Window* blit_dst, bool directAccess,
  83.                        const s16* stepLengths, s16  newlineLen,
  84.                        const shape::spoint* offsets, bool verticalNewline)
  85. {
  86.   Bitmap* fontAtlas = new Bitmap(filePath, blit_dst, directAccess);
  87.  
  88.  
  89.   try {
  90.     _constructFromMemory(fontAtlas, stepLengths, newlineLen,
  91.                          offsets, verticalNewline);
  92.  
  93.   } catch(const char* errorText){
  94.     delete fontAtlas;
  95.     throw errorText;
  96.  
  97.   }
  98. }
  99.  
  100.  
  101.  
  102.  
  103. BitmapFont::~BitmapFont(){
  104.   if(!_valid) return;
  105.   _valid = false;
  106.  
  107.   //iirc deleting on a nullptr should be fine
  108.   if(!_fromMemory) delete _fontAtlas;
  109. }
  110.  
  111.  
  112.  
  113.  
  114. //might break if you have a lot of negative step length chars
  115. shape::point BitmapFont::getStringSize(const char* str, size_t maxLen){
  116.   if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
  117.  
  118.   shape::point strSize(0,0);
  119.   shape::point strSizeTmp(0,0);
  120.   maxLen = strnlen_s(str, (maxLen) ? maxLen+1 : KIT_U32_MAX);
  121.  
  122.  
  123.   if(_verticalNewline){
  124.     for(size_t c=0; c<maxLen; ++c){
  125.       char chr = str[c];
  126.       if(!chr) break;
  127.  
  128.       switch(chr){
  129.       case '\n':
  130.         if(strSize.x < strSizeTmp.x) strSize.x = strSizeTmp.x;
  131.         strSizeTmp.x  = 0;
  132.         strSizeTmp.y += (s32)(_newlineLen * _glyphScale.y);
  133.         break;
  134.       default:
  135.         strSizeTmp.x += (s32)(_stepLengths[chr] * _glyphScale.x);
  136.       }
  137.     }
  138.  
  139.  
  140.   } else { //horizontal newline
  141.     for(size_t c=0; c<maxLen; ++c){
  142.       char chr = str[c];
  143.       if(!chr) break;
  144.  
  145.       switch(chr){
  146.       case '\n':
  147.         if(strSize.y < strSizeTmp.y) strSize.y = strSizeTmp.y;
  148.         strSizeTmp.x += (s32)(_newlineLen * _glyphScale.x);
  149.         strSizeTmp.y  = 0;
  150.         break;
  151.       default:
  152.         strSizeTmp.y += (s32)(_stepLengths[chr] * _glyphScale.y);
  153.       }
  154.     }
  155.  
  156.  
  157.   }
  158.  
  159.  
  160.   if(strSize.x < strSizeTmp.x) strSize.x = strSizeTmp.x;
  161.   if(strSize.y < strSizeTmp.y) strSize.y = strSizeTmp.y;
  162.   strSize.x = MAX(0, strSize.x);
  163.   strSize.y = MAX(0, strSize.y);
  164.  
  165.   return strSize;
  166. }
  167.  
  168.  
  169.  
  170.  
  171. shape::point BitmapFont::setScale(float x, float y){
  172.   if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
  173.  
  174.   _glyphScale.x = MAX(0.0f, x);
  175.   _glyphScale.y = MAX(0.0f, y);
  176.  
  177.   shape::point newGlyphSize;
  178.   newGlyphSize.x = (s32)(_glyphSrc.w * _glyphScale.x);
  179.   newGlyphSize.y = (s32)(_glyphSrc.h * _glyphScale.y);
  180.  
  181.   return newGlyphSize;
  182. }
  183.  
  184.  
  185.  
  186.  
  187. void BitmapFont::putChar(s32 x, s32 y, char chr){
  188.   if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
  189.   //127 is the control code prefix; don't draw anything
  190.   if((chr&=0x7F) == 0x7F) return;
  191.  
  192.  
  193.   u8 uchr = chr; //now we can play with another 128 chars :D
  194.   //(_glyphSrc+1 to account for alignment pixel)
  195.   _glyphSrc.x = ( uchr&15 ) * (_glyphSrc.w+1); //lo nybble of char selects column
  196.   _glyphSrc.y = ( uchr>>4 ) * (_glyphSrc.h+1); //hi nybble of char selects row
  197.  
  198.   ++_glyphSrc.x; //account for alignment pixel (again)
  199.   ++_glyphSrc.y;
  200.  
  201.  
  202.   _glyphDst.x = x + _offsets[uchr].x;
  203.   _glyphDst.y = y + _offsets[uchr].y;
  204.   _glyphDst.w = (s32)(_glyphSrc.w * _glyphScale.x);
  205.   _glyphDst.h = (s32)(_glyphSrc.h * _glyphScale.y);
  206.  
  207.  
  208.   _fontAtlas->blitRect(&_glyphDst, &_glyphSrc, _transparency);
  209. }
  210.  
  211.  
  212.  
  213.  
  214. void BitmapFont::print(s32 x, s32 y, const char* str, size_t maxLen){
  215.   if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
  216.   if(str == nullptr) throw "str = nullptr";
  217.  
  218.   shape::point start(x,y); //used for newline chars
  219.   maxLen = strnlen_s(str, (maxLen) ? maxLen+1 : KIT_U32_MAX);
  220.  
  221.  
  222.   if(_verticalNewline){
  223.     for(size_t c=0; c<maxLen; ++c){
  224.       char chr = str[c];
  225.       if(!chr) break;
  226.  
  227.       switch(chr){
  228.       case '\n':
  229.         x  = start.x;
  230.         y += (s32)(_newlineLen * _glyphScale.y);
  231.         break;
  232.       default:
  233.         putChar(x,y, chr);
  234.         x += (s32)(_stepLengths[chr] * _glyphScale.x);
  235.       }
  236.     }
  237.  
  238.  
  239.   } else { //horizontal newline
  240.     for(size_t c=0; c<maxLen; ++c){
  241.       char chr = str[c];
  242.       if(!chr) break;
  243.  
  244.       switch(chr){
  245.       case '\n':
  246.         x += (s32)(_newlineLen * _glyphScale.x);
  247.         y  = start.y;
  248.         break;
  249.       default:
  250.         putChar(x,y, chr);
  251.         y += (s32)(_stepLengths[chr] * _glyphScale.y);
  252.       }
  253.     }
  254.  
  255.  
  256.   }
  257. }
  258.  
  259.  
  260.  
  261.  
  262. }; /* namespace kit */
  263. /******************************************************************************/
  264. /******************************************************************************/
  265. //"kit_w32\src\kit_win32\kit_Bitmap_QOI.cpp":
  266. #include "kit_Bitmap_shared.hpp"
  267.  
  268. #define QOI_OUTPUT_ARGB
  269.  
  270. #define QOI_MALLOC(sz) memory::alloc(sz)
  271. #define QOI_FREE(p)    memory::free(&(p))
  272. #define QOI_ZEROARR(a) memory::set((a),0,sizeof(a))
  273.  
  274. #define QOI_IMPLEMENTATION
  275.  
  276. //i'm replacing the data types with QOI_<type> so i can easily change them
  277. #define QOI_U8  kit::u8  //unsigned char
  278. #define QOI_U32 kit::u32 //unsigned int
  279. #define QOI_S8  kit::s8  //  signed char
  280. #define QOI_S32 kit::s32 //  signed int
  281.  
  282. #define QOI_MAGICINT KIT_MAGIC_QOI // = "qoif"
  283.  
  284.  
  285. namespace kit {
  286.  
  287.  
  288.  
  289.  
  290. struct qoi_desc {
  291.   QOI_U32 width;
  292.   QOI_U32 height;
  293.   QOI_U8 channels;
  294.   QOI_U8 colorspace;
  295. };
  296.  
  297. union qoi_rgba_t {
  298.   struct { QOI_U8 r, g, b, a; } rgba;
  299.   QOI_U32 v;
  300. };
  301.  
  302. void* qoi_decode(const void* data, QOI_S32 size, qoi_desc* desc, QOI_S32 channels);
  303.  
  304.  
  305.  
  306.  
  307. color::ARGB* Bitmap::_parseQOI(BinaryData& fileData, shape::point& size){
  308.   s32    fileSize = (s32)fileData.getSize();
  309.   void* _fileData = (void*)fileData.getData();
  310.  
  311.   if(fileData.getSize() > KIT_S32_MAX) throw "file is too large for a QOI (>=2GiB)";
  312.  
  313.   qoi_desc desc;
  314. #ifdef QOI_OUTPUT_ARGB
  315.   color::ARGB* pixelsIn = (color::ARGB*)qoi_decode(_fileData, fileSize, &desc, 4);
  316. #else
  317.   color::ABGR* pixelsIn = (color::ABGR*)qoi_decode(_fileData, fileSize, &desc, 4);
  318. #endif /* QOI_OUTPUT_ARGB */
  319.   if(pixelsIn == nullptr) throw "failed to decode qoi";
  320.  
  321.  
  322.   size_t numPixels = desc.width*desc.height;
  323.   color::ARGB* pixelsOut = (color::ARGB*)memory::alloc(sizeof(color::ARGB)*numPixels);
  324.   if(pixelsOut == nullptr){
  325.     memory::free(&pixelsIn);
  326.     throw "failed to allocate memory for output decoded pixels";
  327.   }
  328.  
  329.  
  330.   //vertically flip output, since qoi is top-down, while bitmaps are bottom-up
  331.   for(u32 _yi=0; _yi<desc.height; ++_yi){
  332.     //premultiply the y indexes
  333.     u32 yi_in  = desc.width * _yi;
  334.     u32 yi_out = desc.width * (desc.height-1 - _yi);
  335.  
  336.     for(u32 xi=0; xi<desc.width; ++xi){
  337. #ifdef QOI_OUTPUT_ARGB
  338.       pixelsOut[xi + yi_out].v = pixelsIn[xi + yi_in].v;
  339. #else
  340.       pixelsOut[xi + yi_out].b = pixelsIn[xi + yi_in].b;
  341.       pixelsOut[xi + yi_out].g = pixelsIn[xi + yi_in].g;
  342.       pixelsOut[xi + yi_out].a = pixelsIn[xi + yi_in].a;
  343.       pixelsOut[xi + yi_out].r = pixelsIn[xi + yi_in].r;
  344. #endif /* QOI_OUTPUT_ARGB */
  345.     }
  346.   }
  347.  
  348.   memory::free(&pixelsIn); //free the unflipped decoded pixel data
  349.  
  350.  
  351.   size.x = desc.width;
  352.   size.y = desc.height;
  353.  
  354.   return pixelsOut;
  355. }
  356.  
  357.  
  358.  
  359.  
  360.  
  361. /*MAGIC QOI EN/DECODER STUFF*/
  362.  
  363. /* -----------------------------------------------------------------------------
  364. Header - Public functions */
  365.  
  366. #ifndef QOI_H
  367. #define QOI_H
  368.  
  369. #ifdef __cplusplus
  370. extern "C" {
  371. #endif
  372.  
  373. /* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
  374. It describes either the input format (for qoi_write and qoi_encode), or is
  375. filled with the description read from the file header (for qoi_read and
  376. qoi_decode).
  377.  
  378. The colorspace in this qoi_desc is an enum where
  379.   0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
  380.   1 = all channels are linear
  381. You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
  382. informative. It will be saved to the file header, but does not affect
  383. how chunks are en-/decoded. */
  384.  
  385. #define QOI_SRGB   0
  386. #define QOI_LINEAR 1
  387.  
  388.  
  389. /* Decode a QOI image from memory.
  390.  
  391. The function either returns NULL on failure (invalid parameters or malloc
  392. failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
  393. is filled with the description from the file header.
  394.  
  395. The returned pixel data should be free()d after use. */
  396.  
  397. //void *qoi_decode(const void *data, QOI_S32 size, qoi_desc *desc, QOI_S32 channels);
  398.  
  399.  
  400. #ifdef __cplusplus
  401. }
  402. #endif
  403. #endif /* QOI_H */
  404.  
  405.  
  406. /* -----------------------------------------------------------------------------
  407. Implementation */
  408.  
  409. #ifdef QOI_IMPLEMENTATION
  410.  
  411. #ifndef QOI_MALLOC
  412.   #include <stdlib.h>
  413.   #define QOI_MALLOC(sz) malloc(sz)
  414.   #define QOI_FREE(p)    free(p)
  415. #endif
  416. #ifndef QOI_ZEROARR
  417.   #include <string.h>
  418.   #define QOI_ZEROARR(a) memset((a),0,sizeof(a))
  419. #endif
  420.  
  421. #define QOI_OP_INDEX  0x00 /* 00xxxxxx */
  422. #define QOI_OP_DIFF   0x40 /* 01xxxxxx */
  423. #define QOI_OP_LUMA   0x80 /* 10xxxxxx */
  424. #define QOI_OP_RUN    0xc0 /* 11xxxxxx */
  425. #define QOI_OP_RGB    0xfe /* 11111110 */
  426. #define QOI_OP_RGBA   0xff /* 11111111 */
  427.  
  428. #define QOI_MASK_2    0xc0 /* 11000000 */
  429.  
  430. #define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11)
  431. #define QOI_MAGIC \
  432.   (((QOI_U32)'q') << 24 | ((QOI_U32)'o') << 16 | \
  433.    ((QOI_U32)'i') <<  8 | ((QOI_U32)'f'))
  434. #define QOI_HEADER_SIZE 14
  435.  
  436. /* 2GB is the max file size that this implementation can safely handle. We guard
  437. against anything larger than that, assuming the worst case with 5 bytes per
  438. pixel, rounded down to a nice clean value. 400 million pixels ought to be
  439. enough for anybody. */
  440. #define QOI_PIXELS_MAX ((QOI_U32)400000000)
  441.  
  442. static const QOI_U8 qoi_padding[8] = {0,0,0,0,0,0,0,1};
  443.  
  444. static void qoi_write_32(QOI_U8* bytes, QOI_S32* p, QOI_U32 v) {
  445.   bytes[(*p)++] = (0xff000000 & v) >> 24;
  446.   bytes[(*p)++] = (0x00ff0000 & v) >> 16;
  447.   bytes[(*p)++] = (0x0000ff00 & v) >> 8;
  448.   bytes[(*p)++] = (0x000000ff & v);
  449. }
  450.  
  451. static QOI_U32 qoi_read_32(const QOI_U8* bytes, QOI_S32* p) {
  452.   QOI_U32 a = bytes[(*p)++];
  453.   QOI_U32 b = bytes[(*p)++];
  454.   QOI_U32 c = bytes[(*p)++];
  455.   QOI_U32 d = bytes[(*p)++];
  456.   return a << 24 | b << 16 | c << 8 | d;
  457. }
  458.  
  459. void* qoi_decode(const void* data, QOI_S32 size, qoi_desc* desc, QOI_S32 channels) {
  460.   const QOI_U8 *bytes;
  461.   QOI_U32 header_magic;
  462.   QOI_U8 *pixels;
  463.   qoi_rgba_t index[64];
  464.   qoi_rgba_t px;
  465.   QOI_S32 px_len, chunks_len, px_pos;
  466.   QOI_S32 p = 0, run = 0;
  467.  
  468.   if (
  469.     data == nullptr || desc == nullptr ||
  470.     (channels != 0 && channels != 3 && channels != 4) ||
  471.     size < QOI_HEADER_SIZE + (QOI_S32)sizeof(qoi_padding)
  472.   ) {
  473.     return nullptr;
  474.   }
  475.  
  476.   bytes = (const QOI_U8 *)data;
  477.  
  478.   header_magic = qoi_read_32(bytes, &p);
  479.   desc->width = qoi_read_32(bytes, &p);
  480.   desc->height = qoi_read_32(bytes, &p);
  481.   desc->channels = bytes[p++];
  482.   desc->colorspace = bytes[p++];
  483.  
  484.   if (
  485.     desc->width == 0 || desc->height == 0 ||
  486.     desc->channels < 3 || desc->channels > 4 ||
  487.     desc->colorspace > 1 ||
  488.     header_magic != QOI_MAGIC ||
  489.     desc->height >= QOI_PIXELS_MAX / desc->width
  490.   ) {
  491.     return nullptr;
  492.   }
  493.  
  494.   if (channels == 0) {
  495.     channels = desc->channels;
  496.   }
  497.  
  498.   px_len = desc->width * desc->height * channels;
  499.   pixels = (QOI_U8 *) QOI_MALLOC(px_len);
  500.   if (!pixels) {
  501.     return nullptr;
  502.   }
  503.  
  504.   QOI_ZEROARR(index);
  505.   px.rgba.r = 0;
  506.   px.rgba.g = 0;
  507.   px.rgba.b = 0;
  508.   px.rgba.a = 255;
  509.  
  510.   chunks_len = size - (QOI_S32)sizeof(qoi_padding);
  511.   for (px_pos = 0; px_pos < px_len; px_pos += channels) {
  512.     if (run > 0) {
  513.       run--;
  514.     }
  515.     else if (p < chunks_len) {
  516.       QOI_S32 b1 = bytes[p++];
  517.  
  518.       if (b1 == QOI_OP_RGB) {
  519.         px.rgba.r = bytes[p++];
  520.         px.rgba.g = bytes[p++];
  521.         px.rgba.b = bytes[p++];
  522.       }
  523.       else if (b1 == QOI_OP_RGBA) {
  524.         px.rgba.r = bytes[p++];
  525.         px.rgba.g = bytes[p++];
  526.         px.rgba.b = bytes[p++];
  527.         px.rgba.a = bytes[p++];
  528.       }
  529.       else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
  530.         px = index[b1];
  531.       }
  532.       else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
  533.         px.rgba.r += ((b1 >> 4) & 0x03) - 2;
  534.         px.rgba.g += ((b1 >> 2) & 0x03) - 2;
  535.         px.rgba.b += ( b1       & 0x03) - 2;
  536.       }
  537.       else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
  538.         QOI_S32 b2 = bytes[p++];
  539.         QOI_S32 vg = (b1 & 0x3f) - 32;
  540.         px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
  541.         px.rgba.g += vg;
  542.         px.rgba.b += vg - 8 +  (b2       & 0x0f);
  543.       }
  544.       else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
  545.         run = (b1 & 0x3f);
  546.       }
  547.  
  548.       index[QOI_COLOR_HASH(px) % 64] = px;
  549.     }
  550.  
  551. #ifdef QOI_OUTPUT_ARGB
  552.     pixels[px_pos + 0] = px.rgba.b;
  553.     pixels[px_pos + 1] = px.rgba.g;
  554.     pixels[px_pos + 2] = px.rgba.r;
  555. #else
  556.     pixels[px_pos + 0] = px.rgba.r;
  557.     pixels[px_pos + 1] = px.rgba.g;
  558.     pixels[px_pos + 2] = px.rgba.b;
  559. #endif /* QOI_OUTPUT_ARGB */
  560.     if (channels == 4) pixels[px_pos + 3] = px.rgba.a;
  561.   }
  562.  
  563.   return pixels;
  564. }
  565.  
  566.  
  567. #endif /* QOI_IMPLEMENTATION */
  568.  
  569. /*MAGIC QOI EN/DECODER STUFF*/
  570.  
  571.  
  572.  
  573.  
  574. }; /* namespace kit */
  575. /******************************************************************************/
  576. /******************************************************************************/
  577. //"kit_w32\src\kit_win32\kit_fileio.cpp":
  578. #include "kit_fileio_shared.hpp"
  579.  
  580. #define KIT_INVALID_FILE_OBJECT _kit_invalid_file_object
  581.  
  582.  
  583. namespace kit {
  584.  
  585. static const char _kit_invalid_file_object[] = "invalid file object";
  586.  
  587.  
  588.  
  589.  
  590. /*++++++++++++*/
  591. /*+BinaryData+*/
  592. /*++++++++++++*/
  593.  
  594. BinaryData::BinaryData(const char* filePath){
  595.   _type = KIT_CLASSTYPE_FILEIO_BINARYDATA;
  596.  
  597.   size_t fileSize = fileio::getSize(filePath); //should throw if file is invalid
  598.   if(fileSize == 0) throw "file is empty";
  599.   if(fileSize >= KIT_U32_MAX) throw "loading files >=4GiB is currently not supported";
  600.  
  601.   //open the file
  602.   HANDLE fileHandle = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ,
  603.                                   nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  604.   if(fileHandle == INVALID_HANDLE_VALUE) throw "failed to open file";
  605.  
  606.  
  607.   //allocate memory for file data
  608.   _data = (char*)memory::alloc(fileSize+1);
  609.   if(_data == nullptr){
  610.     CloseHandle(fileHandle);
  611.     throw "failed to allocate memory for data";
  612.   }
  613.  
  614.   _data_len = fileSize;
  615.   //set last byte to 0 in case file is a null terminated string
  616.    //(fileSize+1 is allocated for this purpose)
  617.   _data[fileSize] = 0; //originally memory::set 0, but that seemed redundant in this case
  618.   *((void**)&_magic) = _data; //_magic isn't an actual type, so this is a workaround
  619.  
  620.  
  621.   DWORD bytesRead;
  622.   BOOL success = ReadFile(fileHandle, _data, (DWORD)fileSize, &bytesRead, nullptr);
  623.   CloseHandle(fileHandle);
  624.   if(!success){
  625.     memory::free(&_data);
  626.     throw "failed to read from file";
  627.   }
  628.   if(bytesRead < fileSize){
  629.     memory::free(&_data);
  630.     throw "bytes read was less than file size";
  631.   }
  632.  
  633.  
  634.   _valid = true;
  635.   _constructing = false;
  636. }
  637.  
  638.  
  639.  
  640. BinaryData::BinaryData(const void* data, size_t dataSize){
  641.   _type = KIT_CLASSTYPE_FILEIO_BINARYDATA;
  642.  
  643.   if(dataSize == KIT_U64_MAX) throw "dataSize = -1"; //lol
  644.  
  645.   _data = (char*)memory::alloc(dataSize+1);
  646.   if(_data == nullptr)
  647.     throw "failed to allocate memory for data";
  648.  
  649.   _data_len = dataSize;
  650.   _data[dataSize] = 0;
  651.   *((void**)&_magic) = _data;
  652.  
  653.   if(data != nullptr) memory::copy(_data, data, dataSize);
  654.  
  655.   _valid = true;
  656.   _constructing = false;
  657. }
  658.  
  659.  
  660.  
  661. BinaryData::~BinaryData(){
  662.   if(!_valid) return;
  663.   _valid = false;
  664.  
  665.   if(_data != nullptr) memory::free(&_data);
  666. }
  667.  
  668. /*------------*/
  669. /*-BinaryData-*/
  670. /*------------*/
  671.  
  672.  
  673.  
  674.  
  675. #define IS_READONLY(_attributes) \
  676.   ( (_attributes)&FILE_ATTRIBUTE_READONLY )
  677.  
  678. #define IS_DIRECTORY(_attributes) \
  679.   ( (_attributes)&FILE_ATTRIBUTE_DIRECTORY )
  680.  
  681.  
  682.  
  683. #define IS_READONLY_FILE(_attributes) \
  684.   ( IS_READONLY(_attributes) && !IS_DIRECTORY(_attributes) )
  685.  
  686. bool isFileReadOnly(const char* filePath){
  687.   if(filePath == nullptr) throw "filePath = nullptr";
  688.  
  689.   DWORD fileAttributes = GetFileAttributesA(filePath);
  690.  
  691.   if(fileAttributes == INVALID_FILE_ATTRIBUTES){
  692.     if(GetLastError() != ERROR_FILE_NOT_FOUND) throw "failed to get file attributes";
  693.     else                                       throw "file doesn't exist";
  694.  
  695.   } else if(IS_READONLY_FILE(fileAttributes)){
  696.     return true;
  697.  
  698.   } else {
  699.     return false;
  700.  
  701.   }
  702.  
  703. }
  704.  
  705.  
  706.  
  707. #define IS_NORMAL_FILE(_attributes) \
  708.   ( !( IS_READONLY(_attributes) || IS_DIRECTORY(_attributes) ) )
  709.  
  710. bool fileio::fileExists(const char* filePath){
  711.   if(filePath == nullptr) throw "filePath = nullptr";
  712.  
  713.   DWORD fileAttributes = GetFileAttributesA(filePath);
  714.  
  715.   if(fileAttributes == INVALID_FILE_ATTRIBUTES){
  716.     if(GetLastError() != ERROR_FILE_NOT_FOUND) throw "failed to get file attributes";
  717.     else                                       return false;
  718.  
  719.   } else if(IS_NORMAL_FILE(fileAttributes)){
  720.     return true;
  721.  
  722.   } else {
  723.     throw "path exists, but is not associated with a normal file";
  724.  
  725.   }
  726.  
  727. }
  728.  
  729.  
  730.  
  731. size_t fileio::getSize(const char* filePath){
  732.   if(filePath == nullptr) throw "filePath = nullptr";
  733.   HANDLE fileHandle = CreateFileA(filePath, 0, FILE_SHARE_READ,
  734.                                   nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  735.   if(fileHandle == INVALID_HANDLE_VALUE){
  736.     if(GetLastError() == ERROR_FILE_NOT_FOUND) throw "file not found";
  737.     else                                       throw "failed to open file";
  738.   }
  739.  
  740.   LARGE_INTEGER fileSize;
  741.   BOOL success = GetFileSizeEx(fileHandle, &fileSize);
  742.   CloseHandle(fileHandle); //close the file whether or not the query succeeds
  743.   if(!success) throw "failed to get file size";
  744.   return (size_t)fileSize.QuadPart;
  745. }
  746.  
  747.  
  748.  
  749. void fileio::deleteFile(const char* filePath){
  750.   if(!fileio::fileExists(filePath)) throw "file does not exist";
  751.   if(!DeleteFileA(filePath)) throw "failed to delete file";
  752. }
  753.  
  754.  
  755.  
  756. void fileio::writeToFile(const char* filePath, const void* data,
  757.                          size_t dataSize, bool append)
  758. {
  759.   if(filePath == nullptr) throw "filePath = nullptr";
  760.   if(data == nullptr) throw "data = nullptr";
  761.   //if you really wanted to, i guess you could write files larger than 4 gigs
  762.    //with an overwrite and a series of appends, so that's always an option?
  763.   if(dataSize >= KIT_U32_MAX) throw "writing files >=4GiB is currently not supported";
  764.  
  765.   DWORD accessMode, creationDisposition;
  766.   if(append){ //create or append to existing
  767.     accessMode          = FILE_APPEND_DATA;
  768.     creationDisposition = OPEN_ALWAYS;
  769.  
  770.   } else { //create or overwrite existing
  771.     accessMode          = GENERIC_WRITE;
  772.     creationDisposition = CREATE_ALWAYS;
  773.  
  774.   }
  775.  
  776.  
  777.   HANDLE fileHandle = CreateFileA(filePath, accessMode, 0, nullptr,
  778.                                   creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
  779.   if(fileHandle == INVALID_HANDLE_VALUE) throw "failed to open file";
  780.  
  781.  
  782.   //(if dataSize *is* 0, then just create/open the file without writing to it)
  783.   if(dataSize > 0){
  784.     DWORD bytesWritten;
  785.     BOOL success = WriteFile(fileHandle, data, (DWORD)dataSize, &bytesWritten, nullptr);
  786.     CloseHandle(fileHandle);
  787.     if(!success) throw "failed to write to file";
  788.     if(bytesWritten < dataSize) throw "bytes read was less than dataSize";
  789.  
  790.   } else {
  791.     CloseHandle(fileHandle);
  792.  
  793.   }
  794.  
  795. }
  796.  
  797.  
  798.  
  799.  
  800. }; /* namespace kit */
  801. /******************************************************************************/
  802. /******************************************************************************/
  803. //"kit_w32\src\kit_win32\kit_FStr.cpp":
  804. #include "_kit_common_shared.hpp"
  805.  
  806. #define KIT_INVALID_FSTR _kit_invalid_fstr
  807.  
  808. #define KIT_IS_INVALID_FSTR (!_valid && !_constructing)
  809.  
  810.  
  811. namespace kit {
  812.  
  813. static const char _kit_invalid_fstr[] = "invalid fstr object";
  814.  
  815.  
  816.  
  817.  
  818. FStr::FStr(u16 maxSize){
  819.   _type = KIT_CLASSTYPE_FSTR;
  820.  
  821.   if(maxSize == 0) throw "maxSize = 0";
  822.  
  823.   //using alloc2 intentionally here
  824.   _str = (char*)memory::alloc2(sizeof(char)*maxSize);
  825.   _str[0] = 0; //just in case
  826.   _str_size = maxSize;
  827.  
  828.   _valid = true;
  829.   _constructing = false;
  830. }
  831.  
  832.  
  833.  
  834. FStr::~FStr(){
  835.   if(!_valid) return;
  836.   _valid = false;
  837.  
  838.   if(_str != nullptr) memory::free(&_str);
  839. }
  840.  
  841.  
  842.  
  843.  
  844. char* FStr::fmt(const char* fmt_str, ...){
  845.   if(KIT_IS_INVALID_FSTR) throw KIT_INVALID_FSTR;
  846.  
  847.   va_list args;
  848.   va_start(args, fmt_str);
  849.  
  850.   vsprintf_s(_str, _str_size-1, fmt_str, args);
  851.  
  852.   va_end(args);
  853.   _str[_str_size-1] = 0; //just in case
  854.  
  855.   return _str;
  856. }
  857.  
  858.  
  859.  
  860.  
  861. }; /* namespace kit */
  862. /******************************************************************************/
  863. /******************************************************************************/
  864. //"kit_w32\src\kit_win32\kit_func.cpp":
  865. #include "_kit_common_shared.hpp"
  866.  
  867.  
  868. namespace kit {
  869.  
  870.  
  871.  
  872.  
  873. u32 showMessageBox(const char* text, const char* title,
  874.                    u32 type, Window* win, u32 defaultButton)
  875. {
  876.   char* _text  = (text  != nullptr) ? text  : "";
  877.   char* _title = (title != nullptr) ? title : "";
  878.  
  879.   HWND winHandle = nullptr;
  880.   if(win != nullptr){
  881.     _WindowOpaque* win_opq = (_WindowOpaque*)KIT_GET_CLASS_OPAQUE(win);
  882.     winHandle = win_opq->winHandle;
  883.   }
  884.  
  885.   defaultButton = (defaultButton&3)<<8; //0x000 -> 0x300
  886.  
  887.   return MessageBoxA(winHandle, _text, _title, type|defaultButton);
  888. }
  889.  
  890.  
  891.  
  892.  
  893. u32 getLastSystemError(){
  894.   return GetLastError(); //yep, that's it
  895. }
  896.  
  897.  
  898.  
  899.  
  900. u32 getNumLogicalCPUCores(){
  901.   SYSTEM_INFO sysInfo;
  902.   GetSystemInfo(&sysInfo);
  903.   return sysInfo.dwNumberOfProcessors;
  904. }
  905.  
  906.  
  907.  
  908.  
  909. bool pollWindowEvent(WindowEvent* event_p){
  910.   //take one event off the current event queue and set it to *event_p
  911.   EnterCriticalSection(&eventVars::lock);
  912.   WindowEvent event = RemoveFromEventQueue();
  913.   LeaveCriticalSection(&eventVars::lock);
  914.  
  915.  
  916.   //if previous event queue is now empty, process any pending window messages,
  917.    //while adding any events generated by WindowProc to the event queue
  918.   if(eventVars::next == eventVars::end){
  919.     MSG message;
  920.     while(PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE)){
  921.       TranslateMessage(&message);
  922.       DispatchMessageA(&message);
  923.     }
  924.   }
  925.  
  926.  
  927.   if(event_p != nullptr) *event_p = event;
  928.   return event.type != WINEVENT_NULL;
  929. }
  930.  
  931.  
  932.  
  933.  
  934. }; /* namespace kit */
  935. /******************************************************************************/
  936. /******************************************************************************/
  937. //"kit_w32\src\kit_win32\kit_main.cpp":
  938. #include "_kit_common_shared.hpp"
  939.  
  940. using namespace kit;
  941.  
  942.  
  943. /*+w32 stuff+*/
  944.  
  945. HINSTANCE w32::hThisInst = nullptr;
  946. HINSTANCE w32::hPrevInst = nullptr;
  947. LPSTR     w32::lpszArg   = nullptr;
  948. int       w32::nCmdShow  = SW_HIDE;
  949.  
  950. LARGE_INTEGER w32::ticksPerSecond;
  951.  
  952. /*-w32 stuff-*/
  953.  
  954.  
  955. /*+event stuff+*/
  956.  
  957. CRITICAL_SECTION eventVars::lock;
  958.  
  959. WindowEvent*     eventVars::queue;
  960. u16              eventVars::next;
  961. u16              eventVars::end;
  962.  
  963. /*-event stuff-*/
  964.  
  965.  
  966.  
  967.  
  968. //get first and last char of string, excluding leading or trailing whitespace
  969.  //(whitespace as in ' '; i'm not going to bother with '\t', '\n', etc.)
  970. static inline char* _getFirstCharPtr(char* start){
  971.   if(*start == 0) return start;
  972.   while(*start == ' ') ++start;
  973.   return start;
  974. }
  975.  
  976. static inline char* _getLastCharPtr(char* start){
  977.   if(*start == 0) return start;
  978.   char* end = start;
  979.   while(*(end+1) != 0 ) ++end; //go to null terminator
  980.   while(*end == ' ') --end; //go back until a non-whitespace char is found
  981.   return end;
  982. }
  983.  
  984.  
  985.  
  986.  
  987. //provided by the user
  988. extern int main(int argc, char** argv);
  989.  
  990.  
  991. //converts lpszArg to how argv normally behaves,
  992.  //before calling a user-defined main() function
  993. int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
  994.                    LPSTR     lpszArg,   int       nCmdShow)
  995. {
  996.   /*+++++*/
  997.   /*+w32+*/
  998.   /*+++++*/
  999.  
  1000.   //assign some global values
  1001.   w32::hThisInst = hThisInst;
  1002.   w32::hPrevInst = hPrevInst;
  1003.   w32::lpszArg   = lpszArg;
  1004.   w32::nCmdShow  = nCmdShow;
  1005.  
  1006.   QueryPerformanceFrequency(&w32::ticksPerSecond);
  1007.  
  1008.   /*-----*/
  1009.   /*-w32-*/
  1010.   /*-----*/
  1011.  
  1012.  
  1013.   /*+++++++*/
  1014.   /*+_argv+*/
  1015.   /*+++++++*/
  1016.  
  1017.   char*      p = (char*)lpszArg;
  1018.   int    _argc = 1; //should always contain path to executable
  1019.   char** _argv = nullptr;
  1020.  
  1021.    //parse for the number of arguments (assuming space as delimiter)
  1022.   char* first = _getFirstCharPtr(p);
  1023.   char* last  = _getLastCharPtr(p);
  1024.   int Arg_len = (int)(last-first) + ((*first!=0) ? 1 : 0);
  1025.  
  1026.   if(Arg_len > 0) ++_argc;
  1027.   for(p=first; p<=last; ++p){
  1028.     if(*p == ' ') ++_argc;
  1029.   }
  1030.  
  1031.    //create and fill in _argv
  1032.   _argv = (char**)memory::alloc( sizeof(char*) * _argc );
  1033.   if(_argv == nullptr) return ERROR_NOT_ENOUGH_MEMORY;
  1034.   //memory::set(_argv, 0, sizeof(char*)*_argc ); //(i'm like 90% sure this is redundant)
  1035.  
  1036.   char filepath[MAX_PATH]; //path to current process
  1037.   if(GetModuleFileNameA(NULL, filepath, MAX_PATH) == 0)
  1038.     return ERROR_INSUFFICIENT_BUFFER;
  1039.   _argv[0] = filepath;
  1040.  
  1041.   if(Arg_len > 0){
  1042.     int i = 1;
  1043.     _argv[i++] = first;
  1044.     for(p=first; p<=last; ++p){
  1045.       if(*p == ' '){
  1046.         *p = 0; //set delimiter to null
  1047.         _argv[i++] = p+1; //+1 as in +sizeof(char*)
  1048.       }
  1049.     }
  1050.     *p = 0; //make sure last arg has null terminator
  1051.   }
  1052.  
  1053.   /*-------*/
  1054.   /*-_argv-*/
  1055.   /*-------*/
  1056.  
  1057.  
  1058.   /*+++++++++++*/
  1059.   /*+eventVars+*/
  1060.   /*+++++++++++*/
  1061.  
  1062.   //(no memory::set is necessary for the event queue, thankfully)
  1063.   eventVars::queue = (WindowEvent*)memory::alloc(sizeof(WindowEvent)*65536);
  1064.   if(_argv == nullptr) return ERROR_NOT_ENOUGH_MEMORY;
  1065.   eventVars::next = 0; //both indexes are 16-bit, so they'll roll over on overflow
  1066.   eventVars::end  = 0;  //(which is nice, since the queue's length is exactly 2^16)
  1067.  
  1068.   InitializeCriticalSectionAndSpinCount(&eventVars::lock, KIT_LOCK_SPINCOUNT);
  1069.  
  1070.   /*-----------*/
  1071.   /*-eventVars-*/
  1072.   /*-----------*/
  1073.  
  1074.  
  1075.   /*+++++++++++*/
  1076.   /*+portaudio+*/
  1077.   /*+++++++++++*/
  1078.  
  1079.   PaError pa_err = Pa_Initialize();
  1080.   if(pa_err != paNoError){
  1081.     _portaudioError:
  1082.     _printf("PortAudio failed: \"%s\"\n",Pa_GetErrorText(pa_err));
  1083.     return pa_err;
  1084.   }
  1085.  
  1086.   /*-----------*/
  1087.   /*-portaudio-*/
  1088.   /*-----------*/
  1089.  
  1090.  
  1091.   int returnCode = main(_argc,_argv);
  1092.  
  1093.  
  1094.   DeleteCriticalSection(&eventVars::lock);
  1095.   memory::free(&eventVars::queue);
  1096.  
  1097.  
  1098.   memory::free(&_argv);
  1099. #ifdef _DEBUG
  1100.   //should be 0 if all goes well
  1101.   _printf("# OF ALLOCATIONS: %llu\n",memory::getNumAllocations());
  1102. #endif
  1103.  
  1104.  
  1105.   //remove all messages from all windows in main thread, just in case
  1106.   MSG message;
  1107.   while(PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)){ /* do nothing */ }
  1108.   //^^(idk if this really does anything useful though)
  1109.  
  1110.  
  1111.   pa_err = Pa_Terminate();
  1112.   if(pa_err != paNoError) goto _portaudioError;
  1113.  
  1114.  
  1115.   return returnCode;
  1116. }
  1117.  
  1118.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement