Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_BitmapFont.cpp":
- #include "_kit_common_shared.hpp"
- #define KIT_INVALID_BITMAPFONT _kit_invalid_bitmapfont
- #define KIT_IS_INVALID_BITMAPFONT (!_valid && !_constructing)
- namespace kit {
- static const char _kit_invalid_bitmapfont[] = "invalid bitmap font";
- void BitmapFont::_constructFromMemory(Bitmap* fontAtlas,
- const s16* stepLengths, s16 newlineLen,
- const shape::spoint* offsets, bool verticalNewline)
- {
- _type = KIT_CLASSTYPE_BITMAPFONT;
- //check if fontAtlas is valid
- if(fontAtlas == nullptr)
- throw "fontAtlas = nullptr";
- if(!KIT_IS_CLASS_TYPE(fontAtlas, KIT_CLASSTYPE_BITMAP))
- throw "*fontAtlas is not a Bitmap";
- if(!KIT_IS_CLASS_VALID(fontAtlas))
- throw "*fontAtlas is invalid";
- _fontAtlas = fontAtlas;
- shape::point atlasSize = _fontAtlas->getSize();
- if((atlasSize.x%16) || (atlasSize.y%16)) throw "(atlas size % 16) != 0";
- _glyphSrc.w = atlasSize.x/16 - 1; //-1 to account for alignment pixel
- _glyphSrc.h = atlasSize.y/16 - 1;
- if(_glyphSrc.w > 32767) throw "glyph width > 32767";
- if(_glyphSrc.h > 32767) throw "glyph height > 32767";
- //(_glyphDst is set every time putChar() is called)
- _glyphScale.x = 1.0f;
- _glyphScale.y = 1.0f;
- _verticalNewline = verticalNewline;
- //_glyphSrc.?+1 for a bit of default spacing
- //(has nothing to do with alignment pixels)
- s16 defStep = (verticalNewline) ? _glyphSrc.w+1 : _glyphSrc.h+1;
- s16 defNewline = (verticalNewline) ? _glyphSrc.h+1 : _glyphSrc.w+1;
- if(offsets != nullptr) memory::copy(_offsets, offsets, sizeof(shape::spoint)*256);
- else memory::set( _offsets, 0, sizeof(shape::spoint)*256);
- _newlineLen = (newlineLen != -32768) ? newlineLen : defNewline;
- if(stepLengths != nullptr){
- memory::copy(_stepLengths, stepLengths, 256);
- } else {
- //if stepLengths is not given, fill in _stepLengths with default values
- for(s32 i=0; i<256; ++i) _stepLengths[i] = defStep;
- _stepLengths[0x7F] = 0; //control code prefix should be length 0
- _stepLengths['\b'] = -defStep; //backspace should actually go back a space
- _stepLengths['\t'] = defStep*2; //change to *4 if needed
- }
- _valid = true;
- _constructing = false;
- }
- //loads a bitmap from an image file
- BitmapFont::BitmapFont(const char* filePath, Window* blit_dst, bool directAccess,
- const s16* stepLengths, s16 newlineLen,
- const shape::spoint* offsets, bool verticalNewline)
- {
- Bitmap* fontAtlas = new Bitmap(filePath, blit_dst, directAccess);
- try {
- _constructFromMemory(fontAtlas, stepLengths, newlineLen,
- offsets, verticalNewline);
- } catch(const char* errorText){
- delete fontAtlas;
- throw errorText;
- }
- }
- BitmapFont::~BitmapFont(){
- if(!_valid) return;
- _valid = false;
- //iirc deleting on a nullptr should be fine
- if(!_fromMemory) delete _fontAtlas;
- }
- //might break if you have a lot of negative step length chars
- shape::point BitmapFont::getStringSize(const char* str, size_t maxLen){
- if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
- shape::point strSize(0,0);
- shape::point strSizeTmp(0,0);
- maxLen = strnlen_s(str, (maxLen) ? maxLen+1 : KIT_U32_MAX);
- if(_verticalNewline){
- for(size_t c=0; c<maxLen; ++c){
- char chr = str[c];
- if(!chr) break;
- switch(chr){
- case '\n':
- if(strSize.x < strSizeTmp.x) strSize.x = strSizeTmp.x;
- strSizeTmp.x = 0;
- strSizeTmp.y += (s32)(_newlineLen * _glyphScale.y);
- break;
- default:
- strSizeTmp.x += (s32)(_stepLengths[chr] * _glyphScale.x);
- }
- }
- } else { //horizontal newline
- for(size_t c=0; c<maxLen; ++c){
- char chr = str[c];
- if(!chr) break;
- switch(chr){
- case '\n':
- if(strSize.y < strSizeTmp.y) strSize.y = strSizeTmp.y;
- strSizeTmp.x += (s32)(_newlineLen * _glyphScale.x);
- strSizeTmp.y = 0;
- break;
- default:
- strSizeTmp.y += (s32)(_stepLengths[chr] * _glyphScale.y);
- }
- }
- }
- if(strSize.x < strSizeTmp.x) strSize.x = strSizeTmp.x;
- if(strSize.y < strSizeTmp.y) strSize.y = strSizeTmp.y;
- strSize.x = MAX(0, strSize.x);
- strSize.y = MAX(0, strSize.y);
- return strSize;
- }
- shape::point BitmapFont::setScale(float x, float y){
- if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
- _glyphScale.x = MAX(0.0f, x);
- _glyphScale.y = MAX(0.0f, y);
- shape::point newGlyphSize;
- newGlyphSize.x = (s32)(_glyphSrc.w * _glyphScale.x);
- newGlyphSize.y = (s32)(_glyphSrc.h * _glyphScale.y);
- return newGlyphSize;
- }
- void BitmapFont::putChar(s32 x, s32 y, char chr){
- if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
- //127 is the control code prefix; don't draw anything
- if((chr&=0x7F) == 0x7F) return;
- u8 uchr = chr; //now we can play with another 128 chars :D
- //(_glyphSrc+1 to account for alignment pixel)
- _glyphSrc.x = ( uchr&15 ) * (_glyphSrc.w+1); //lo nybble of char selects column
- _glyphSrc.y = ( uchr>>4 ) * (_glyphSrc.h+1); //hi nybble of char selects row
- ++_glyphSrc.x; //account for alignment pixel (again)
- ++_glyphSrc.y;
- _glyphDst.x = x + _offsets[uchr].x;
- _glyphDst.y = y + _offsets[uchr].y;
- _glyphDst.w = (s32)(_glyphSrc.w * _glyphScale.x);
- _glyphDst.h = (s32)(_glyphSrc.h * _glyphScale.y);
- _fontAtlas->blitRect(&_glyphDst, &_glyphSrc, _transparency);
- }
- void BitmapFont::print(s32 x, s32 y, const char* str, size_t maxLen){
- if(KIT_IS_INVALID_BITMAPFONT) throw KIT_INVALID_BITMAPFONT;
- if(str == nullptr) throw "str = nullptr";
- shape::point start(x,y); //used for newline chars
- maxLen = strnlen_s(str, (maxLen) ? maxLen+1 : KIT_U32_MAX);
- if(_verticalNewline){
- for(size_t c=0; c<maxLen; ++c){
- char chr = str[c];
- if(!chr) break;
- switch(chr){
- case '\n':
- x = start.x;
- y += (s32)(_newlineLen * _glyphScale.y);
- break;
- default:
- putChar(x,y, chr);
- x += (s32)(_stepLengths[chr] * _glyphScale.x);
- }
- }
- } else { //horizontal newline
- for(size_t c=0; c<maxLen; ++c){
- char chr = str[c];
- if(!chr) break;
- switch(chr){
- case '\n':
- x += (s32)(_newlineLen * _glyphScale.x);
- y = start.y;
- break;
- default:
- putChar(x,y, chr);
- y += (s32)(_stepLengths[chr] * _glyphScale.y);
- }
- }
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_Bitmap_QOI.cpp":
- #include "kit_Bitmap_shared.hpp"
- #define QOI_OUTPUT_ARGB
- #define QOI_MALLOC(sz) memory::alloc(sz)
- #define QOI_FREE(p) memory::free(&(p))
- #define QOI_ZEROARR(a) memory::set((a),0,sizeof(a))
- #define QOI_IMPLEMENTATION
- //i'm replacing the data types with QOI_<type> so i can easily change them
- #define QOI_U8 kit::u8 //unsigned char
- #define QOI_U32 kit::u32 //unsigned int
- #define QOI_S8 kit::s8 // signed char
- #define QOI_S32 kit::s32 // signed int
- #define QOI_MAGICINT KIT_MAGIC_QOI // = "qoif"
- namespace kit {
- struct qoi_desc {
- QOI_U32 width;
- QOI_U32 height;
- QOI_U8 channels;
- QOI_U8 colorspace;
- };
- union qoi_rgba_t {
- struct { QOI_U8 r, g, b, a; } rgba;
- QOI_U32 v;
- };
- void* qoi_decode(const void* data, QOI_S32 size, qoi_desc* desc, QOI_S32 channels);
- color::ARGB* Bitmap::_parseQOI(BinaryData& fileData, shape::point& size){
- s32 fileSize = (s32)fileData.getSize();
- void* _fileData = (void*)fileData.getData();
- if(fileData.getSize() > KIT_S32_MAX) throw "file is too large for a QOI (>=2GiB)";
- qoi_desc desc;
- #ifdef QOI_OUTPUT_ARGB
- color::ARGB* pixelsIn = (color::ARGB*)qoi_decode(_fileData, fileSize, &desc, 4);
- #else
- color::ABGR* pixelsIn = (color::ABGR*)qoi_decode(_fileData, fileSize, &desc, 4);
- #endif /* QOI_OUTPUT_ARGB */
- if(pixelsIn == nullptr) throw "failed to decode qoi";
- size_t numPixels = desc.width*desc.height;
- color::ARGB* pixelsOut = (color::ARGB*)memory::alloc(sizeof(color::ARGB)*numPixels);
- if(pixelsOut == nullptr){
- memory::free(&pixelsIn);
- throw "failed to allocate memory for output decoded pixels";
- }
- //vertically flip output, since qoi is top-down, while bitmaps are bottom-up
- for(u32 _yi=0; _yi<desc.height; ++_yi){
- //premultiply the y indexes
- u32 yi_in = desc.width * _yi;
- u32 yi_out = desc.width * (desc.height-1 - _yi);
- for(u32 xi=0; xi<desc.width; ++xi){
- #ifdef QOI_OUTPUT_ARGB
- pixelsOut[xi + yi_out].v = pixelsIn[xi + yi_in].v;
- #else
- pixelsOut[xi + yi_out].b = pixelsIn[xi + yi_in].b;
- pixelsOut[xi + yi_out].g = pixelsIn[xi + yi_in].g;
- pixelsOut[xi + yi_out].a = pixelsIn[xi + yi_in].a;
- pixelsOut[xi + yi_out].r = pixelsIn[xi + yi_in].r;
- #endif /* QOI_OUTPUT_ARGB */
- }
- }
- memory::free(&pixelsIn); //free the unflipped decoded pixel data
- size.x = desc.width;
- size.y = desc.height;
- return pixelsOut;
- }
- /*MAGIC QOI EN/DECODER STUFF*/
- /* -----------------------------------------------------------------------------
- Header - Public functions */
- #ifndef QOI_H
- #define QOI_H
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
- It describes either the input format (for qoi_write and qoi_encode), or is
- filled with the description read from the file header (for qoi_read and
- qoi_decode).
- The colorspace in this qoi_desc is an enum where
- 0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
- 1 = all channels are linear
- You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
- informative. It will be saved to the file header, but does not affect
- how chunks are en-/decoded. */
- #define QOI_SRGB 0
- #define QOI_LINEAR 1
- /* Decode a QOI image from memory.
- The function either returns NULL on failure (invalid parameters or malloc
- failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
- is filled with the description from the file header.
- The returned pixel data should be free()d after use. */
- //void *qoi_decode(const void *data, QOI_S32 size, qoi_desc *desc, QOI_S32 channels);
- #ifdef __cplusplus
- }
- #endif
- #endif /* QOI_H */
- /* -----------------------------------------------------------------------------
- Implementation */
- #ifdef QOI_IMPLEMENTATION
- #ifndef QOI_MALLOC
- #include <stdlib.h>
- #define QOI_MALLOC(sz) malloc(sz)
- #define QOI_FREE(p) free(p)
- #endif
- #ifndef QOI_ZEROARR
- #include <string.h>
- #define QOI_ZEROARR(a) memset((a),0,sizeof(a))
- #endif
- #define QOI_OP_INDEX 0x00 /* 00xxxxxx */
- #define QOI_OP_DIFF 0x40 /* 01xxxxxx */
- #define QOI_OP_LUMA 0x80 /* 10xxxxxx */
- #define QOI_OP_RUN 0xc0 /* 11xxxxxx */
- #define QOI_OP_RGB 0xfe /* 11111110 */
- #define QOI_OP_RGBA 0xff /* 11111111 */
- #define QOI_MASK_2 0xc0 /* 11000000 */
- #define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11)
- #define QOI_MAGIC \
- (((QOI_U32)'q') << 24 | ((QOI_U32)'o') << 16 | \
- ((QOI_U32)'i') << 8 | ((QOI_U32)'f'))
- #define QOI_HEADER_SIZE 14
- /* 2GB is the max file size that this implementation can safely handle. We guard
- against anything larger than that, assuming the worst case with 5 bytes per
- pixel, rounded down to a nice clean value. 400 million pixels ought to be
- enough for anybody. */
- #define QOI_PIXELS_MAX ((QOI_U32)400000000)
- static const QOI_U8 qoi_padding[8] = {0,0,0,0,0,0,0,1};
- static void qoi_write_32(QOI_U8* bytes, QOI_S32* p, QOI_U32 v) {
- bytes[(*p)++] = (0xff000000 & v) >> 24;
- bytes[(*p)++] = (0x00ff0000 & v) >> 16;
- bytes[(*p)++] = (0x0000ff00 & v) >> 8;
- bytes[(*p)++] = (0x000000ff & v);
- }
- static QOI_U32 qoi_read_32(const QOI_U8* bytes, QOI_S32* p) {
- QOI_U32 a = bytes[(*p)++];
- QOI_U32 b = bytes[(*p)++];
- QOI_U32 c = bytes[(*p)++];
- QOI_U32 d = bytes[(*p)++];
- return a << 24 | b << 16 | c << 8 | d;
- }
- void* qoi_decode(const void* data, QOI_S32 size, qoi_desc* desc, QOI_S32 channels) {
- const QOI_U8 *bytes;
- QOI_U32 header_magic;
- QOI_U8 *pixels;
- qoi_rgba_t index[64];
- qoi_rgba_t px;
- QOI_S32 px_len, chunks_len, px_pos;
- QOI_S32 p = 0, run = 0;
- if (
- data == nullptr || desc == nullptr ||
- (channels != 0 && channels != 3 && channels != 4) ||
- size < QOI_HEADER_SIZE + (QOI_S32)sizeof(qoi_padding)
- ) {
- return nullptr;
- }
- bytes = (const QOI_U8 *)data;
- header_magic = qoi_read_32(bytes, &p);
- desc->width = qoi_read_32(bytes, &p);
- desc->height = qoi_read_32(bytes, &p);
- desc->channels = bytes[p++];
- desc->colorspace = bytes[p++];
- if (
- desc->width == 0 || desc->height == 0 ||
- desc->channels < 3 || desc->channels > 4 ||
- desc->colorspace > 1 ||
- header_magic != QOI_MAGIC ||
- desc->height >= QOI_PIXELS_MAX / desc->width
- ) {
- return nullptr;
- }
- if (channels == 0) {
- channels = desc->channels;
- }
- px_len = desc->width * desc->height * channels;
- pixels = (QOI_U8 *) QOI_MALLOC(px_len);
- if (!pixels) {
- return nullptr;
- }
- QOI_ZEROARR(index);
- px.rgba.r = 0;
- px.rgba.g = 0;
- px.rgba.b = 0;
- px.rgba.a = 255;
- chunks_len = size - (QOI_S32)sizeof(qoi_padding);
- for (px_pos = 0; px_pos < px_len; px_pos += channels) {
- if (run > 0) {
- run--;
- }
- else if (p < chunks_len) {
- QOI_S32 b1 = bytes[p++];
- if (b1 == QOI_OP_RGB) {
- px.rgba.r = bytes[p++];
- px.rgba.g = bytes[p++];
- px.rgba.b = bytes[p++];
- }
- else if (b1 == QOI_OP_RGBA) {
- px.rgba.r = bytes[p++];
- px.rgba.g = bytes[p++];
- px.rgba.b = bytes[p++];
- px.rgba.a = bytes[p++];
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
- px = index[b1];
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
- px.rgba.r += ((b1 >> 4) & 0x03) - 2;
- px.rgba.g += ((b1 >> 2) & 0x03) - 2;
- px.rgba.b += ( b1 & 0x03) - 2;
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
- QOI_S32 b2 = bytes[p++];
- QOI_S32 vg = (b1 & 0x3f) - 32;
- px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
- px.rgba.g += vg;
- px.rgba.b += vg - 8 + (b2 & 0x0f);
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
- run = (b1 & 0x3f);
- }
- index[QOI_COLOR_HASH(px) % 64] = px;
- }
- #ifdef QOI_OUTPUT_ARGB
- pixels[px_pos + 0] = px.rgba.b;
- pixels[px_pos + 1] = px.rgba.g;
- pixels[px_pos + 2] = px.rgba.r;
- #else
- pixels[px_pos + 0] = px.rgba.r;
- pixels[px_pos + 1] = px.rgba.g;
- pixels[px_pos + 2] = px.rgba.b;
- #endif /* QOI_OUTPUT_ARGB */
- if (channels == 4) pixels[px_pos + 3] = px.rgba.a;
- }
- return pixels;
- }
- #endif /* QOI_IMPLEMENTATION */
- /*MAGIC QOI EN/DECODER STUFF*/
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_fileio.cpp":
- #include "kit_fileio_shared.hpp"
- #define KIT_INVALID_FILE_OBJECT _kit_invalid_file_object
- namespace kit {
- static const char _kit_invalid_file_object[] = "invalid file object";
- /*++++++++++++*/
- /*+BinaryData+*/
- /*++++++++++++*/
- BinaryData::BinaryData(const char* filePath){
- _type = KIT_CLASSTYPE_FILEIO_BINARYDATA;
- size_t fileSize = fileio::getSize(filePath); //should throw if file is invalid
- if(fileSize == 0) throw "file is empty";
- if(fileSize >= KIT_U32_MAX) throw "loading files >=4GiB is currently not supported";
- //open the file
- HANDLE fileHandle = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
- if(fileHandle == INVALID_HANDLE_VALUE) throw "failed to open file";
- //allocate memory for file data
- _data = (char*)memory::alloc(fileSize+1);
- if(_data == nullptr){
- CloseHandle(fileHandle);
- throw "failed to allocate memory for data";
- }
- _data_len = fileSize;
- //set last byte to 0 in case file is a null terminated string
- //(fileSize+1 is allocated for this purpose)
- _data[fileSize] = 0; //originally memory::set 0, but that seemed redundant in this case
- *((void**)&_magic) = _data; //_magic isn't an actual type, so this is a workaround
- DWORD bytesRead;
- BOOL success = ReadFile(fileHandle, _data, (DWORD)fileSize, &bytesRead, nullptr);
- CloseHandle(fileHandle);
- if(!success){
- memory::free(&_data);
- throw "failed to read from file";
- }
- if(bytesRead < fileSize){
- memory::free(&_data);
- throw "bytes read was less than file size";
- }
- _valid = true;
- _constructing = false;
- }
- BinaryData::BinaryData(const void* data, size_t dataSize){
- _type = KIT_CLASSTYPE_FILEIO_BINARYDATA;
- if(dataSize == KIT_U64_MAX) throw "dataSize = -1"; //lol
- _data = (char*)memory::alloc(dataSize+1);
- if(_data == nullptr)
- throw "failed to allocate memory for data";
- _data_len = dataSize;
- _data[dataSize] = 0;
- *((void**)&_magic) = _data;
- if(data != nullptr) memory::copy(_data, data, dataSize);
- _valid = true;
- _constructing = false;
- }
- BinaryData::~BinaryData(){
- if(!_valid) return;
- _valid = false;
- if(_data != nullptr) memory::free(&_data);
- }
- /*------------*/
- /*-BinaryData-*/
- /*------------*/
- #define IS_READONLY(_attributes) \
- ( (_attributes)&FILE_ATTRIBUTE_READONLY )
- #define IS_DIRECTORY(_attributes) \
- ( (_attributes)&FILE_ATTRIBUTE_DIRECTORY )
- #define IS_READONLY_FILE(_attributes) \
- ( IS_READONLY(_attributes) && !IS_DIRECTORY(_attributes) )
- bool isFileReadOnly(const char* filePath){
- if(filePath == nullptr) throw "filePath = nullptr";
- DWORD fileAttributes = GetFileAttributesA(filePath);
- if(fileAttributes == INVALID_FILE_ATTRIBUTES){
- if(GetLastError() != ERROR_FILE_NOT_FOUND) throw "failed to get file attributes";
- else throw "file doesn't exist";
- } else if(IS_READONLY_FILE(fileAttributes)){
- return true;
- } else {
- return false;
- }
- }
- #define IS_NORMAL_FILE(_attributes) \
- ( !( IS_READONLY(_attributes) || IS_DIRECTORY(_attributes) ) )
- bool fileio::fileExists(const char* filePath){
- if(filePath == nullptr) throw "filePath = nullptr";
- DWORD fileAttributes = GetFileAttributesA(filePath);
- if(fileAttributes == INVALID_FILE_ATTRIBUTES){
- if(GetLastError() != ERROR_FILE_NOT_FOUND) throw "failed to get file attributes";
- else return false;
- } else if(IS_NORMAL_FILE(fileAttributes)){
- return true;
- } else {
- throw "path exists, but is not associated with a normal file";
- }
- }
- size_t fileio::getSize(const char* filePath){
- if(filePath == nullptr) throw "filePath = nullptr";
- HANDLE fileHandle = CreateFileA(filePath, 0, FILE_SHARE_READ,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
- if(fileHandle == INVALID_HANDLE_VALUE){
- if(GetLastError() == ERROR_FILE_NOT_FOUND) throw "file not found";
- else throw "failed to open file";
- }
- LARGE_INTEGER fileSize;
- BOOL success = GetFileSizeEx(fileHandle, &fileSize);
- CloseHandle(fileHandle); //close the file whether or not the query succeeds
- if(!success) throw "failed to get file size";
- return (size_t)fileSize.QuadPart;
- }
- void fileio::deleteFile(const char* filePath){
- if(!fileio::fileExists(filePath)) throw "file does not exist";
- if(!DeleteFileA(filePath)) throw "failed to delete file";
- }
- void fileio::writeToFile(const char* filePath, const void* data,
- size_t dataSize, bool append)
- {
- if(filePath == nullptr) throw "filePath = nullptr";
- if(data == nullptr) throw "data = nullptr";
- //if you really wanted to, i guess you could write files larger than 4 gigs
- //with an overwrite and a series of appends, so that's always an option?
- if(dataSize >= KIT_U32_MAX) throw "writing files >=4GiB is currently not supported";
- DWORD accessMode, creationDisposition;
- if(append){ //create or append to existing
- accessMode = FILE_APPEND_DATA;
- creationDisposition = OPEN_ALWAYS;
- } else { //create or overwrite existing
- accessMode = GENERIC_WRITE;
- creationDisposition = CREATE_ALWAYS;
- }
- HANDLE fileHandle = CreateFileA(filePath, accessMode, 0, nullptr,
- creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
- if(fileHandle == INVALID_HANDLE_VALUE) throw "failed to open file";
- //(if dataSize *is* 0, then just create/open the file without writing to it)
- if(dataSize > 0){
- DWORD bytesWritten;
- BOOL success = WriteFile(fileHandle, data, (DWORD)dataSize, &bytesWritten, nullptr);
- CloseHandle(fileHandle);
- if(!success) throw "failed to write to file";
- if(bytesWritten < dataSize) throw "bytes read was less than dataSize";
- } else {
- CloseHandle(fileHandle);
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_FStr.cpp":
- #include "_kit_common_shared.hpp"
- #define KIT_INVALID_FSTR _kit_invalid_fstr
- #define KIT_IS_INVALID_FSTR (!_valid && !_constructing)
- namespace kit {
- static const char _kit_invalid_fstr[] = "invalid fstr object";
- FStr::FStr(u16 maxSize){
- _type = KIT_CLASSTYPE_FSTR;
- if(maxSize == 0) throw "maxSize = 0";
- //using alloc2 intentionally here
- _str = (char*)memory::alloc2(sizeof(char)*maxSize);
- _str[0] = 0; //just in case
- _str_size = maxSize;
- _valid = true;
- _constructing = false;
- }
- FStr::~FStr(){
- if(!_valid) return;
- _valid = false;
- if(_str != nullptr) memory::free(&_str);
- }
- char* FStr::fmt(const char* fmt_str, ...){
- if(KIT_IS_INVALID_FSTR) throw KIT_INVALID_FSTR;
- va_list args;
- va_start(args, fmt_str);
- vsprintf_s(_str, _str_size-1, fmt_str, args);
- va_end(args);
- _str[_str_size-1] = 0; //just in case
- return _str;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_func.cpp":
- #include "_kit_common_shared.hpp"
- namespace kit {
- u32 showMessageBox(const char* text, const char* title,
- u32 type, Window* win, u32 defaultButton)
- {
- char* _text = (text != nullptr) ? text : "";
- char* _title = (title != nullptr) ? title : "";
- HWND winHandle = nullptr;
- if(win != nullptr){
- _WindowOpaque* win_opq = (_WindowOpaque*)KIT_GET_CLASS_OPAQUE(win);
- winHandle = win_opq->winHandle;
- }
- defaultButton = (defaultButton&3)<<8; //0x000 -> 0x300
- return MessageBoxA(winHandle, _text, _title, type|defaultButton);
- }
- u32 getLastSystemError(){
- return GetLastError(); //yep, that's it
- }
- u32 getNumLogicalCPUCores(){
- SYSTEM_INFO sysInfo;
- GetSystemInfo(&sysInfo);
- return sysInfo.dwNumberOfProcessors;
- }
- bool pollWindowEvent(WindowEvent* event_p){
- //take one event off the current event queue and set it to *event_p
- EnterCriticalSection(&eventVars::lock);
- WindowEvent event = RemoveFromEventQueue();
- LeaveCriticalSection(&eventVars::lock);
- //if previous event queue is now empty, process any pending window messages,
- //while adding any events generated by WindowProc to the event queue
- if(eventVars::next == eventVars::end){
- MSG message;
- while(PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE)){
- TranslateMessage(&message);
- DispatchMessageA(&message);
- }
- }
- if(event_p != nullptr) *event_p = event;
- return event.type != WINEVENT_NULL;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\kit_main.cpp":
- #include "_kit_common_shared.hpp"
- using namespace kit;
- /*+w32 stuff+*/
- HINSTANCE w32::hThisInst = nullptr;
- HINSTANCE w32::hPrevInst = nullptr;
- LPSTR w32::lpszArg = nullptr;
- int w32::nCmdShow = SW_HIDE;
- LARGE_INTEGER w32::ticksPerSecond;
- /*-w32 stuff-*/
- /*+event stuff+*/
- CRITICAL_SECTION eventVars::lock;
- WindowEvent* eventVars::queue;
- u16 eventVars::next;
- u16 eventVars::end;
- /*-event stuff-*/
- //get first and last char of string, excluding leading or trailing whitespace
- //(whitespace as in ' '; i'm not going to bother with '\t', '\n', etc.)
- static inline char* _getFirstCharPtr(char* start){
- if(*start == 0) return start;
- while(*start == ' ') ++start;
- return start;
- }
- static inline char* _getLastCharPtr(char* start){
- if(*start == 0) return start;
- char* end = start;
- while(*(end+1) != 0 ) ++end; //go to null terminator
- while(*end == ' ') --end; //go back until a non-whitespace char is found
- return end;
- }
- //provided by the user
- extern int main(int argc, char** argv);
- //converts lpszArg to how argv normally behaves,
- //before calling a user-defined main() function
- int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
- LPSTR lpszArg, int nCmdShow)
- {
- /*+++++*/
- /*+w32+*/
- /*+++++*/
- //assign some global values
- w32::hThisInst = hThisInst;
- w32::hPrevInst = hPrevInst;
- w32::lpszArg = lpszArg;
- w32::nCmdShow = nCmdShow;
- QueryPerformanceFrequency(&w32::ticksPerSecond);
- /*-----*/
- /*-w32-*/
- /*-----*/
- /*+++++++*/
- /*+_argv+*/
- /*+++++++*/
- char* p = (char*)lpszArg;
- int _argc = 1; //should always contain path to executable
- char** _argv = nullptr;
- //parse for the number of arguments (assuming space as delimiter)
- char* first = _getFirstCharPtr(p);
- char* last = _getLastCharPtr(p);
- int Arg_len = (int)(last-first) + ((*first!=0) ? 1 : 0);
- if(Arg_len > 0) ++_argc;
- for(p=first; p<=last; ++p){
- if(*p == ' ') ++_argc;
- }
- //create and fill in _argv
- _argv = (char**)memory::alloc( sizeof(char*) * _argc );
- if(_argv == nullptr) return ERROR_NOT_ENOUGH_MEMORY;
- //memory::set(_argv, 0, sizeof(char*)*_argc ); //(i'm like 90% sure this is redundant)
- char filepath[MAX_PATH]; //path to current process
- if(GetModuleFileNameA(NULL, filepath, MAX_PATH) == 0)
- return ERROR_INSUFFICIENT_BUFFER;
- _argv[0] = filepath;
- if(Arg_len > 0){
- int i = 1;
- _argv[i++] = first;
- for(p=first; p<=last; ++p){
- if(*p == ' '){
- *p = 0; //set delimiter to null
- _argv[i++] = p+1; //+1 as in +sizeof(char*)
- }
- }
- *p = 0; //make sure last arg has null terminator
- }
- /*-------*/
- /*-_argv-*/
- /*-------*/
- /*+++++++++++*/
- /*+eventVars+*/
- /*+++++++++++*/
- //(no memory::set is necessary for the event queue, thankfully)
- eventVars::queue = (WindowEvent*)memory::alloc(sizeof(WindowEvent)*65536);
- if(_argv == nullptr) return ERROR_NOT_ENOUGH_MEMORY;
- eventVars::next = 0; //both indexes are 16-bit, so they'll roll over on overflow
- eventVars::end = 0; //(which is nice, since the queue's length is exactly 2^16)
- InitializeCriticalSectionAndSpinCount(&eventVars::lock, KIT_LOCK_SPINCOUNT);
- /*-----------*/
- /*-eventVars-*/
- /*-----------*/
- /*+++++++++++*/
- /*+portaudio+*/
- /*+++++++++++*/
- PaError pa_err = Pa_Initialize();
- if(pa_err != paNoError){
- _portaudioError:
- _printf("PortAudio failed: \"%s\"\n",Pa_GetErrorText(pa_err));
- return pa_err;
- }
- /*-----------*/
- /*-portaudio-*/
- /*-----------*/
- int returnCode = main(_argc,_argv);
- DeleteCriticalSection(&eventVars::lock);
- memory::free(&eventVars::queue);
- memory::free(&_argv);
- #ifdef _DEBUG
- //should be 0 if all goes well
- _printf("# OF ALLOCATIONS: %llu\n",memory::getNumAllocations());
- #endif
- //remove all messages from all windows in main thread, just in case
- MSG message;
- while(PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)){ /* do nothing */ }
- //^^(idk if this really does anything useful though)
- pa_err = Pa_Terminate();
- if(pa_err != paNoError) goto _portaudioError;
- return returnCode;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement