├── .github └── workflows │ └── main.yml ├── README.md ├── app.h ├── array.h ├── assetsys.h ├── audiosys.h ├── buffer.h ├── crtemu.h ├── cstr.h ├── dialog.h ├── dir.h ├── docs ├── app.md ├── assetsys.md ├── hashtable.md ├── http.md ├── ini.md ├── rnd.md ├── strpool.md └── thread.md ├── frametimer.h ├── ftplib.h ├── hashtable.h ├── hoedown.h ├── http.h ├── id3tag.h ├── img.h ├── ini.h ├── libxdiff.h ├── mus.h ├── opl.h ├── paldither.h ├── palettize.h ├── palrle.h ├── pixelfont.h ├── rnd.h ├── samplerate.h ├── speech.h ├── strpool.h ├── sysfont.h ├── testfw.h └── thread.h /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | jobs: 6 | build-windows-msvc: 7 | runs-on: windows-2019 8 | steps: 9 | - uses: actions/checkout@v1 10 | # this runs vcvarsall for us, so we get the MSVC toolchain in PATH. 11 | - uses: seanmiddleditch/gha-setup-vsdevenv@master 12 | - name: build cstr.h 13 | run: | 14 | cl /Tc cstr.h /DCSTR_IMPLEMENTATION /DCSTR_RUN_TESTS /MTd 15 | - name: run cstr tests 16 | run: .\cstr.exe 17 | - name: build assetsys.h 18 | run: | 19 | cl /Tc assetsys.h /DASSETSYS_IMPLEMENTATION /DASSETSYS_RUN_TESTS /DSTRPOOL_IMPLEMENTATION /MTd 20 | - name: run assetsys tests 21 | run: .\assetsys.exe 22 | build-windows-msvc-cpp: 23 | runs-on: windows-2019 24 | steps: 25 | - uses: actions/checkout@v1 26 | # this runs vcvarsall for us, so we get the MSVC toolchain in PATH. 27 | - uses: seanmiddleditch/gha-setup-vsdevenv@master 28 | - name: build cstr.h 29 | run: | 30 | cl /Tp cstr.h /DCSTR_IMPLEMENTATION /DCSTR_RUN_TESTS /MTd 31 | - name: run cstr tests 32 | run: .\cstr.exe 33 | - name: build assetsys.h 34 | run: | 35 | cl /Tp assetsys.h /DASSETSYS_IMPLEMENTATION /DASSETSYS_RUN_TESTS /DSTRPOOL_IMPLEMENTATION /MTd 36 | - name: run assetsys tests 37 | run: .\assetsys.exe 38 | build-windows-tcc: 39 | runs-on: windows-2019 40 | steps: 41 | - uses: actions/checkout@v1 42 | - uses: robinraju/release-downloader@v1.2 43 | with: 44 | repository: "mattiasgustavsson/tcc-build" 45 | tag: "tcc64" 46 | fileName: "tcc-0.9.27-win64-bin.zip" 47 | - name: install dependencies 48 | run: 7z x tcc-0.9.27-win64-bin.zip 49 | - name: build cstr.h 50 | run: | 51 | tcc\tcc -xc cstr.h -DCSTR_IMPLEMENTATION -DCSTR_RUN_TESTS 52 | - name: run cstr tests 53 | run: .\cstr.exe 54 | - name: build assetsys.h 55 | run: | 56 | tcc\tcc -xc assetsys.h -DASSETSYS_IMPLEMENTATION -DASSETSYS_RUN_TESTS -DSTRPOOL_IMPLEMENTATION 57 | - name: run assetsys tests 58 | run: .\assetsys.exe 59 | build-macos: 60 | runs-on: macOS-latest 61 | steps: 62 | - uses: actions/checkout@v1 63 | - name: build cstr.h 64 | run: | 65 | clang -xc cstr.h -DCSTR_IMPLEMENTATION -DCSTR_RUN_TESTS 66 | - name: run cstr tests 67 | run: ./a.out 68 | - name: build assetsys.h 69 | run: | 70 | clang -xc assetsys.h -DASSETSYS_IMPLEMENTATION -DASSETSYS_RUN_TESTS -DSTRPOOL_IMPLEMENTATION 71 | - name: run assetsys tests 72 | run: ./a.out 73 | build-macos-cpp: 74 | runs-on: macOS-latest 75 | steps: 76 | - uses: actions/checkout@v1 77 | - name: build cstr.h 78 | run: | 79 | clang -xc++ cstr.h -DCSTR_IMPLEMENTATION -DCSTR_RUN_TESTS 80 | - name: run cstr tests 81 | run: ./a.out 82 | - name: build assetsys.h 83 | run: | 84 | clang -xc++ assetsys.h -DASSETSYS_IMPLEMENTATION -DASSETSYS_RUN_TESTS -DSTRPOOL_IMPLEMENTATION 85 | - name: run assetsys tests 86 | run: ./a.out 87 | build-linux-gcc: 88 | runs-on: ubuntu-latest 89 | steps: 90 | - uses: actions/checkout@v1 91 | - name: build cstr.h 92 | run: | 93 | gcc -xc cstr.h -DCSTR_IMPLEMENTATION -DCSTR_RUN_TESTS 94 | - name: run cstr tests 95 | run: ./a.out 96 | - name: build assetsys.h 97 | run: | 98 | gcc -xc assetsys.h -DASSETSYS_IMPLEMENTATION -DASSETSYS_RUN_TESTS -DSTRPOOL_IMPLEMENTATION 99 | - name: run assetsys tests 100 | run: ./a.out 101 | build-linux-gcc-cpp: 102 | runs-on: ubuntu-latest 103 | steps: 104 | - uses: actions/checkout@v1 105 | - name: build cstr.h 106 | run: | 107 | gcc -xc++ cstr.h -DCSTR_IMPLEMENTATION -DCSTR_RUN_TESTS 108 | - name: run cstr tests 109 | run: ./a.out 110 | - name: build assetsys.h 111 | run: | 112 | gcc -xc++ assetsys.h -DASSETSYS_IMPLEMENTATION -DASSETSYS_RUN_TESTS -DSTRPOOL_IMPLEMENTATION 113 | - name: run assetsys tests 114 | run: ./a.out 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![build](https://github.com/mattiasgustavsson/libs/actions/workflows/main.yml/badge.svg) 2 | 3 | # libs 4 | Single-file public domain libraries for C/C++ (dual licensed under MIT). 5 | 6 | * [app.h](docs/app.md) - Small cross-platform base framework for graphical apps, for C/C++. 7 | * [assetsys.h](docs/assetsys.md) - File system abstraction to read from zip-files, for C/C++. 8 | * [hashtable.h](docs/hashtable.md) - Cache efficient hash table implementation for C/C++. 9 | * [http.h](docs/http.md) - Basic HTTP protocol implementation over sockets (no https). 10 | * [ini.h](docs/ini.md) - Simple ini-file reader for C/C++. 11 | * [rnd.h](docs/rnd.md) - Pseudo-random number generators for C/C++. 12 | * [strpool.h](docs/strpool.md) - Highly efficient string pool for C/C++. 13 | * [thread.h](docs/thread.md) - Cross platform threading functions for C/C++. 14 | 15 | 16 | # wip libs 17 | More libs, work-in-progress, some are unfinished, some are complete but lacking documentation. 18 | 19 | * array.h - Dynamic array library for C/C++. 20 | * audiosys.h - Sound mixer library for C/C++. 21 | * buffer.h - Memory buffer with read/write operations, for C/C++. 22 | * crtemu.h - Cathode ray tube emulation shader for C/C++. 23 | * cstr.h - String interning and manipulation library for C/C++. 24 | * dialog.h - Loading and management of dialogs for a custom game dialog system. 25 | * dir.h - Directory listing functions for C/C++. 26 | * frametimer.h - Framerate timer functionality, for C/C++. 27 | * id3tag.h - Read/write ID3 tags from/to mp3 files in C/C++. 28 | * img.h - Image processing functions for C/C++. 29 | * mus.h - Parsing library for MUS music files (as used in DOS games). 30 | * paldither.h - Convert true-color image to custom palette, with dither. 31 | * palettize.h - Median-cut palette generation and remapping for C/C++. 32 | * palrle.h - Run-length encoding of palettized bitmaps, for C/C++. 33 | * pixelfont.h - Custom pixel font format builder and renderer. 34 | * sysfont.h - Simple debug text renderer for C/C++. 35 | * testfw.h - Basic test framework for C/C++. 36 | 37 | 38 | # repackaged libs 39 | Single-file header-only versions of libs written by other people, released under the same license as the original lib. 40 | I recommend using the latest version of these libs - I only repackage them like this to fit my single-file-libs centered 41 | dev paradigm, and if you don't absolutely need that, you are better off using the original multi-file versions. 42 | 43 | * ftplib.h - FTP client lib for C/C++. *By Thomas Pfau.* 44 | * hoedown.h - Markdown to HTML renderer for C/C++. *By Porte/Marti/Mendez/Torres.* 45 | * libxdiff.h - File Differential Library. *By Davide Libenzi.* 46 | * opl.h - OPL3/SB16 emulation with MIDI interface. *Based on code by Aaron Giles and Mateusz Viste* 47 | * samplerate.h - Sample-rate converter (libsamplerate) for C/C++. *By Erik de Castro Lopo* 48 | * speech.h - Basic text-to-speech synthesizer for C/C++. *By Jari Komppa / Nick Ing-Simmons (et al)* 49 | -------------------------------------------------------------------------------- /array.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | array.h - v0.1 - Dynamic array library for C/C++. 7 | 8 | Do this: 9 | #define ARRAY_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef array_h 14 | #define array_h 15 | 16 | #ifndef ARRAY_BOOL_T 17 | #define _CRT_NONSTDC_NO_DEPRECATE 18 | #define _CRT_SECURE_NO_WARNINGS 19 | #include 20 | #define ARRAY_BOOL_T bool 21 | #endif 22 | 23 | #define array_t( type ) struct { int count; type* items; } 24 | #define array_param_t( type ) void 25 | #define array_create( type ) ARRAY_CAST( (void*)internal_array_create( sizeof( type ), NULL ) ) 26 | #define array_create_memctx( type, memctx ) ARRAY_CAST( (void*)internal_array_create( sizeof( type ), (memctx) ) ) 27 | #define array_destroy( array ) internal_array_destroy( (struct internal_array_t*) (array) ) 28 | #define array_add( array, item ) ARRAY_CAST( internal_array_add( (struct internal_array_t*) (array), (void*) (item), (int)sizeof( *item ) ) ) 29 | #define array_remove( array, index ) internal_array_remove( (struct internal_array_t*) (array), (index) ) 30 | #define array_remove_ordered( array, index ) internal_array_remove_ordered( (struct internal_array_t*) (array), (index) ) 31 | #define array_get( array, index, item ) internal_array_get( (struct internal_array_t*) (array), (index), (void*) (item) ) 32 | #define array_set( array, index, item ) internal_array_set( (struct internal_array_t*) (array), (index), (void*) (item) ) 33 | #define array_count( array ) internal_array_count( (struct internal_array_t*) (array) ) 34 | #define array_sort( array, compare ) internal_array_sort( (struct internal_array_t*) (array), (compare) ) 35 | #define array_bsearch( array, key, compare ) internal_array_bsearch( (struct internal_array_t*) (array), (void*) (key), (compare) ) 36 | #define array_find( array, item ) internal_array_find( (struct internal_array_t*) (array), (void*) (item) ) 37 | #define array_item( array, index ) ARRAY_CAST( internal_array_item( (struct internal_array_t*) (array), (index) ) ) 38 | 39 | 40 | // In C, a void* can be implicitly cast to any other kind of pointer, while in C++ you need an explicit cast. In most 41 | // cases, the explicit cast works for both C and C++, but if we consider the case where we have nested structs, then 42 | // the way you refer to them differs between C and C++ (in C++, `parent_type::nested_type`, in C just `nested_type`). 43 | // In addition, with the automatic cast in C, it is possible to use unnamed nested structs and still dynamically 44 | // allocate arrays of that type - this would be desirable when the code is compiled from C++ as well. 45 | // This VOID_CAST macro allows for automatic cast from void* in C++. In C, it does nothing, but for C++ it uses a 46 | // simple template function to define a cast-to-anything operator. 47 | // Use like this: 48 | // struct { 49 | // struct { 50 | // int x; 51 | // } *nested; 52 | // } parent; 53 | // parent.nested = VOID_CAST( malloc( sizeof( *parent.nested ) * count ) ); 54 | // 55 | #ifndef ARRAY_CAST 56 | #ifdef __cplusplus 57 | struct array_cast { 58 | inline array_cast( void* x_ ) : x( x_ ) { } 59 | inline array_cast( void const* x_ ) : x( (void*) x_ ) { } 60 | template< typename T > inline operator T() { return (T)x; } // cast to whatever requested 61 | void* x; 62 | }; 63 | #define ARRAY_CAST( x ) array_cast( x ) 64 | #else 65 | #define ARRAY_CAST( x ) x 66 | #endif 67 | #endif 68 | 69 | 70 | struct internal_array_t; 71 | 72 | struct internal_array_t* internal_array_create( int item_size, void* memctx ); 73 | void internal_array_destroy( struct internal_array_t* array ); 74 | void* internal_array_add( struct internal_array_t* array, void* item, int item_size ); 75 | void internal_array_remove( struct internal_array_t* array, int index ); 76 | void internal_array_remove_ordered( struct internal_array_t* array, int index ); 77 | ARRAY_BOOL_T internal_array_get( struct internal_array_t* array, int index, void* item ); 78 | ARRAY_BOOL_T internal_array_set( struct internal_array_t* array, int index, void const* item ); 79 | int internal_array_count( struct internal_array_t* array ); 80 | void internal_array_sort( struct internal_array_t* array, int (*compare)( void const*, void const* ) ); 81 | int internal_array_bsearch( struct internal_array_t* array, void* key, int (*compare)( void const*, void const* ) ); 82 | int internal_array_find( struct internal_array_t* array, void* item ); 83 | void* internal_array_item( struct internal_array_t* array, int index ); 84 | 85 | #endif /* array_h */ 86 | 87 | 88 | /* 89 | ---------------------- 90 | IMPLEMENTATION 91 | ---------------------- 92 | */ 93 | 94 | #ifdef ARRAY_IMPLEMENTATION 95 | #undef ARRAY_IMPLEMENTATION 96 | 97 | #ifndef ARRAY_ASSERT 98 | #define _CRT_NONSTDC_NO_DEPRECATE 99 | #define _CRT_SECURE_NO_WARNINGS 100 | #include 101 | #define ARRAY_ASSERT( condition, message ) assert( condition && message ); 102 | #endif 103 | 104 | #ifndef ARRAY_MALLOC 105 | #define _CRT_NONSTDC_NO_DEPRECATE 106 | #define _CRT_SECURE_NO_WARNINGS 107 | #include 108 | #define ARRAY_MALLOC( ctx, size ) ( malloc( size ) ) 109 | #define ARRAY_FREE( ctx, ptr ) ( free( ptr ) ) 110 | #endif 111 | 112 | #ifndef ARRAY_MEMCPY 113 | #define _CRT_NONSTDC_NO_DEPRECATE 114 | #define _CRT_SECURE_NO_WARNINGS 115 | #include 116 | #define ARRAY_MEMCPY( dst, src, cnt ) ( memcpy( (dst), (src), (cnt) ) ) 117 | #endif 118 | 119 | #ifndef ARRAY_MEMMOVE 120 | #define _CRT_NONSTDC_NO_DEPRECATE 121 | #define _CRT_SECURE_NO_WARNINGS 122 | #include 123 | #define ARRAY_MEMMOVE( dst, src, cnt ) ( memcpy( (dst), (src), (cnt) ) ) 124 | #endif 125 | 126 | #ifndef ARRAY_MEMCMP 127 | #define _CRT_NONSTDC_NO_DEPRECATE 128 | #define _CRT_SECURE_NO_WARNINGS 129 | #include 130 | #define ARRAY_MEMCMP( a, b, cnt ) ( memcmp( (a), (b), (cnt) ) ) 131 | #endif 132 | 133 | #ifndef ARRAY_QSORT 134 | #define _CRT_NONSTDC_NO_DEPRECATE 135 | #define _CRT_SECURE_NO_WARNINGS 136 | #include 137 | #define ARRAY_QSORT( base, num, size, cmp ) ( qsort( (base), (num), (size), (cmp) ) ) 138 | #endif 139 | 140 | #ifndef ARRAY_BSEARCH 141 | #define _CRT_NONSTDC_NO_DEPRECATE 142 | #define _CRT_SECURE_NO_WARNINGS 143 | #include 144 | #define ARRAY_BSEARCH( key, base, num, size, cmp ) ( bsearch( (key), (base), (num), (size), (cmp) ) ) 145 | #endif 146 | 147 | 148 | struct internal_array_t { 149 | int count; 150 | void* items; 151 | void* memctx; 152 | int item_size; 153 | int capacity; 154 | }; 155 | 156 | 157 | struct internal_array_t* internal_array_create( int item_size, void* memctx ) { 158 | struct internal_array_t* array = (struct internal_array_t*) ARRAY_MALLOC( memctx, sizeof( struct internal_array_t ) ); 159 | array->memctx = memctx; 160 | array->item_size = item_size; 161 | array->capacity = 256; 162 | array->count = 0; 163 | array->items = ARRAY_MALLOC( memctx, (size_t) array->capacity * item_size ); 164 | return array; 165 | } 166 | 167 | 168 | void internal_array_destroy( struct internal_array_t* array ) { 169 | ARRAY_FREE( array->memctx, array->items ); 170 | ARRAY_FREE( array->memctx, array ); 171 | } 172 | 173 | 174 | void* internal_array_add( struct internal_array_t* array, void* item, int item_size ) { 175 | ARRAY_ASSERT( item_size == array->item_size, "Invalid item" ); 176 | if( array->count >= array->capacity ) { 177 | array->capacity *= 2; 178 | void* items = array->items; 179 | array->items = ARRAY_MALLOC( array->memctx, (size_t) array->capacity * array->item_size ); 180 | ARRAY_MEMCPY( array->items, items, (size_t)array->count * array->item_size ); 181 | ARRAY_FREE( array->memctx, items ); 182 | } 183 | ARRAY_MEMCPY( (void*)( ( (uintptr_t) array->items ) + array->count * array->item_size ), item, 184 | (size_t)array->item_size ); 185 | ++array->count; 186 | return (void*)( ( (uintptr_t) array->items ) + ( array->count - 1 ) * array->item_size ); 187 | } 188 | 189 | 190 | void internal_array_remove( struct internal_array_t* array, int index ) { 191 | if( index >= 0 && index < array->count ) { 192 | --array->count; 193 | ARRAY_MEMMOVE( (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), 194 | (void*)( ( (uintptr_t) array->items ) + array->count * array->item_size ), (size_t) array->item_size ); 195 | } 196 | } 197 | 198 | void internal_array_remove_ordered( struct internal_array_t* array, int index ) { 199 | if( index >= 0 && index < array->count ) { 200 | --array->count; 201 | ARRAY_MEMMOVE( (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), 202 | (void*)( ( (uintptr_t) array->items ) + ( index + 1 ) * array->item_size ), 203 | (size_t)array->item_size * ( array->count - index ) ); 204 | } 205 | } 206 | 207 | ARRAY_BOOL_T internal_array_get( struct internal_array_t* array, int index, void* item ) { 208 | ARRAY_BOOL_T result = index >= 0 && index < array->count; 209 | if( result ) { 210 | ARRAY_MEMCPY( item, (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), 211 | (size_t) array->item_size ); 212 | } 213 | return result; 214 | } 215 | 216 | ARRAY_BOOL_T internal_array_set( struct internal_array_t* array, int index, void const* item ) { 217 | ARRAY_BOOL_T result = index >= 0 && index < array->count; 218 | if( result ) { 219 | ARRAY_MEMCPY( (void*)( ( (uintptr_t) array->items ) + index * array->item_size ), item, 220 | (size_t) array->item_size ); 221 | } 222 | return result; 223 | } 224 | 225 | int internal_array_count( struct internal_array_t* array ) { 226 | int count = array->count; 227 | return count; 228 | } 229 | 230 | 231 | void internal_array_sort( struct internal_array_t* array, int (*compare)( void const*, void const* ) ) { 232 | ARRAY_QSORT( array->items, (size_t) array->count, (size_t) array->item_size, compare ); 233 | } 234 | 235 | 236 | int internal_array_bsearch( struct internal_array_t* array, void* key, int (*compare)( void const*, void const* ) ) { 237 | void* item = ARRAY_BSEARCH( key, array->items, (size_t) array->count, (size_t) array->item_size, compare ); 238 | int result = -1; 239 | if( item ) { 240 | result = (int)( ( ((uintptr_t)item) - ((uintptr_t)array->items) ) / array->item_size ); 241 | } 242 | return result; 243 | } 244 | 245 | 246 | int internal_array_find( struct internal_array_t* array, void* item ) { 247 | for( int i = 0; i < array->count; ++i ) { 248 | if( ARRAY_MEMCMP( (void*)( ( (uintptr_t) array->items ) + i * array->item_size ), item, 249 | (size_t) array->item_size) == 0 ) { 250 | 251 | return i; 252 | } 253 | } 254 | return -1; 255 | } 256 | 257 | 258 | void* internal_array_item( struct internal_array_t* array, int index ) { 259 | if( index >= 0 && index < array->count ) { 260 | return (void*)( ( (uintptr_t) array->items ) + index * array->item_size ); 261 | } else { 262 | return NULL; 263 | } 264 | } 265 | 266 | #endif /* ARRAY_IMPLEMENTATION */ 267 | 268 | /* 269 | ------------------------------------------------------------------------------ 270 | 271 | This software is available under 2 licenses - you may choose the one you like. 272 | 273 | ------------------------------------------------------------------------------ 274 | 275 | ALTERNATIVE A - MIT License 276 | 277 | Copyright (c) 2022 Mattias Gustavsson 278 | 279 | Permission is hereby granted, free of charge, to any person obtaining a copy of 280 | this software and associated documentation files (the "Software"), to deal in 281 | the Software without restriction, including without limitation the rights to 282 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 283 | of the Software, and to permit persons to whom the Software is furnished to do 284 | so, subject to the following conditions: 285 | 286 | The above copyright notice and this permission notice shall be included in all 287 | copies or substantial portions of the Software. 288 | 289 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 290 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 291 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 292 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 293 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 294 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 295 | SOFTWARE. 296 | 297 | ------------------------------------------------------------------------------ 298 | 299 | ALTERNATIVE B - Public Domain (www.unlicense.org) 300 | 301 | This is free and unencumbered software released into the public domain. 302 | 303 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 304 | software, either in source code form or as a compiled binary, for any purpose, 305 | commercial or non-commercial, and by any means. 306 | 307 | In jurisdictions that recognize copyright laws, the author or authors of this 308 | software dedicate any and all copyright interest in the software to the public 309 | domain. We make this dedication for the benefit of the public at large and to 310 | the detriment of our heirs and successors. We intend this dedication to be an 311 | overt act of relinquishment in perpetuity of all present and future rights to 312 | this software under copyright law. 313 | 314 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 315 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 316 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 317 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 318 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 319 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 320 | 321 | ------------------------------------------------------------------------------ 322 | */ 323 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | buffer.h - v0.1 - Memory buffer with read/write operations, for C/C++. 7 | 8 | Do this: 9 | #define BUFFER_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef buffer_h 14 | #define buffer_h 15 | 16 | // If you want buffer to swap endianness on read/write, do this before include: #define BUFFER_BIG_ENDIAN 17 | 18 | #ifndef BUFFER_I8_T 19 | #define BUFFER_I8_T char 20 | #endif 21 | 22 | #ifndef BUFFER_I16_T 23 | #define BUFFER_I16_T short 24 | #endif 25 | 26 | #ifndef BUFFER_I32_T 27 | #define BUFFER_I32_T int 28 | #endif 29 | 30 | #ifndef BUFFER_I64_T 31 | #define BUFFER_I64_T long long 32 | #endif 33 | 34 | #ifndef BUFFER_U8_T 35 | #define BUFFER_U8_T unsigned char 36 | #endif 37 | 38 | #ifndef BUFFER_U16_T 39 | #define BUFFER_U16_T unsigned short 40 | #endif 41 | 42 | #ifndef BUFFER_U32_T 43 | #define BUFFER_U32_T unsigned int 44 | #endif 45 | 46 | #ifndef BUFFER_U64_T 47 | #define BUFFER_U64_T unsigned long long 48 | #endif 49 | 50 | 51 | typedef struct buffer_t buffer_t; 52 | 53 | buffer_t* buffer_create( void ); 54 | buffer_t* buffer_load( const char* filename ); 55 | buffer_t* buffer_map( void* data, size_t size ); 56 | void buffer_destroy( buffer_t* buffer ); 57 | bool buffer_save( buffer_t* buffer, char const* filename ); 58 | void buffer_resize( buffer_t* buffer, size_t size ); 59 | size_t buffer_position( buffer_t* buffer ); 60 | size_t buffer_position_set( buffer_t* buffer, size_t position ); 61 | size_t buffer_size( buffer_t* buffer ); 62 | void* buffer_data( buffer_t* buffer ); 63 | 64 | int buffer_read_char( buffer_t* buffer, char* value, int count ); 65 | int buffer_read_i8( buffer_t* buffer, BUFFER_I8_T* value, int count ); 66 | int buffer_read_i16( buffer_t* buffer, BUFFER_I16_T* value, int count ); 67 | int buffer_read_i32( buffer_t* buffer, BUFFER_I32_T* value, int count ); 68 | int buffer_read_i64( buffer_t* buffer, BUFFER_I64_T* value, int count ); 69 | int buffer_read_u8( buffer_t* buffer, BUFFER_U8_T* value, int count ); 70 | int buffer_read_u16( buffer_t* buffer, BUFFER_U16_T* value, int count ); 71 | int buffer_read_u32( buffer_t* buffer, BUFFER_U32_T* value, int count ); 72 | int buffer_read_u64( buffer_t* buffer, BUFFER_U64_T* value, int count ); 73 | int buffer_read_float( buffer_t* buffer, float* value, int count ); 74 | int buffer_read_double( buffer_t* buffer, double* value, int count ); 75 | int buffer_read_bool( buffer_t* buffer, bool* value, int count ); 76 | 77 | int buffer_write_char( buffer_t* buffer, char const* value, int count ); 78 | int buffer_write_i8( buffer_t* buffer, BUFFER_I8_T const* value, int count ); 79 | int buffer_write_i16( buffer_t* buffer, BUFFER_I16_T const* value, int count ); 80 | int buffer_write_i32( buffer_t* buffer, BUFFER_I32_T const* value, int count ); 81 | int buffer_write_i64( buffer_t* buffer, BUFFER_I64_T const* value, int count ); 82 | int buffer_write_u8( buffer_t* buffer, BUFFER_U8_T const* value, int count ); 83 | int buffer_write_u16( buffer_t* buffer, BUFFER_U16_T const* value, int count ); 84 | int buffer_write_u32( buffer_t* buffer, BUFFER_U32_T const* value, int count ); 85 | int buffer_write_u64( buffer_t* buffer, BUFFER_U64_T const* value, int count ); 86 | int buffer_write_float( buffer_t* buffer, float const* value, int count ); 87 | int buffer_write_double( buffer_t* buffer, double const* value, int count ); 88 | int buffer_write_bool( buffer_t* buffer, bool const* value, int count ); 89 | 90 | #endif /* buffer_h */ 91 | 92 | 93 | #ifdef BUFFER_IMPLEMENTATION 94 | #undef BUFFER_IMPLEMENTATION 95 | 96 | #include 97 | #include 98 | #include 99 | 100 | static BUFFER_U32_T buffer_pow2ceil( BUFFER_U32_T v ) { 101 | --v; 102 | v |= v >> 1; 103 | v |= v >> 2; 104 | v |= v >> 4; 105 | v |= v >> 8; 106 | v |= v >> 16; 107 | ++v; 108 | v += ( v == 0 ); 109 | return v; 110 | } 111 | 112 | 113 | struct buffer_t { 114 | size_t capacity; 115 | size_t size; 116 | size_t position; 117 | void* data; 118 | int is_mapped; 119 | }; 120 | 121 | 122 | buffer_t* buffer_create( void ) { 123 | buffer_t* buffer = (buffer_t*) malloc( sizeof( buffer_t) ); 124 | buffer->capacity = 4096; 125 | buffer->size = 0; 126 | buffer->position = 0; 127 | buffer->data = malloc( buffer->capacity ); 128 | buffer->is_mapped = 0; 129 | return buffer; 130 | } 131 | 132 | 133 | buffer_t* buffer_load( const char* filename ) { 134 | FILE* fp = fopen( filename, "rb" ); 135 | if( !fp ) { 136 | return NULL; 137 | } 138 | fseek( fp, 0, SEEK_END ); 139 | int size = (int) ftell( fp ); 140 | fseek( fp, 0, SEEK_SET ); 141 | if( size == 0 ) { 142 | fclose( fp ); 143 | return NULL; 144 | } 145 | 146 | int pow2size = (int)buffer_pow2ceil( (BUFFER_U32_T) size ); 147 | void* data = malloc( pow2size ); 148 | int read = (int) fread( data, 1, size, fp ); 149 | fclose( fp ); 150 | if( read != size ) { 151 | free( data ); 152 | return NULL; 153 | } 154 | 155 | buffer_t* buffer = (buffer_t*) malloc( sizeof( buffer_t) ); 156 | buffer->capacity = pow2size; 157 | buffer->size = size; 158 | buffer->position = 0; 159 | buffer->data = data; 160 | buffer->is_mapped = 0; 161 | return buffer; 162 | } 163 | 164 | 165 | buffer_t* buffer_map( void* data, size_t size ) { 166 | if( !data ) { 167 | return NULL; 168 | } 169 | buffer_t* buffer = (buffer_t*) malloc( sizeof( buffer_t) ); 170 | buffer->capacity = size; 171 | buffer->size = size; 172 | buffer->position = 0; 173 | buffer->data = data; 174 | buffer->is_mapped = 1; 175 | return buffer; 176 | } 177 | 178 | 179 | void buffer_destroy( buffer_t* buffer ) { 180 | if( !buffer->is_mapped ) { 181 | free( buffer->data ); 182 | } 183 | free( buffer ); 184 | } 185 | 186 | 187 | bool buffer_save( buffer_t* buffer, char const* filename ) { 188 | FILE* fp = fopen( filename, "wb" ); 189 | if( !fp ) { 190 | return false; 191 | } 192 | size_t written = fwrite( buffer->data, 1, buffer->size, fp ); 193 | fclose( fp ); 194 | return written == buffer->size; 195 | } 196 | 197 | 198 | void buffer_resize( buffer_t* buffer, size_t size ) { 199 | if( buffer->is_mapped ) { 200 | return; 201 | } 202 | if( size > buffer->capacity ) { 203 | while( size > buffer->capacity ) { 204 | buffer->capacity *= 2; 205 | } 206 | buffer->data = realloc( buffer->data, buffer->capacity ); 207 | } 208 | buffer->size = size; 209 | if( buffer->position > size ) { 210 | buffer->position = size; 211 | } 212 | } 213 | 214 | 215 | size_t buffer_position( buffer_t* buffer ) { 216 | size_t result = buffer->position; 217 | return result; 218 | } 219 | 220 | 221 | size_t buffer_position_set( buffer_t* buffer, size_t position ) { 222 | buffer->position = position > buffer->size ? buffer->size : position; 223 | size_t result = buffer->position; 224 | return result; 225 | } 226 | 227 | 228 | size_t buffer_size( buffer_t* buffer ) { 229 | size_t result = buffer->size; 230 | return result; 231 | } 232 | 233 | 234 | void* buffer_data( buffer_t* buffer ) { 235 | return buffer->data; 236 | } 237 | 238 | #ifndef BUFFER_BIG_ENDIAN 239 | #define BUFFER_READ_IMPL \ 240 | { \ 241 | int result = 0; \ 242 | for( int i = 0; i < count; ++i ) { \ 243 | if( buffer->position + sizeof( *value ) > buffer->size ) { \ 244 | return result; \ 245 | } \ 246 | memcpy( &value[ i ], (void*)( ( (uintptr_t) buffer->data ) + buffer->position ), sizeof( *value ) ); \ 247 | buffer->position += sizeof( *value ); \ 248 | ++result; \ 249 | } \ 250 | return result; \ 251 | } 252 | #else 253 | #define BUFFER_READ_IMPL \ 254 | { \ 255 | int result = 0; \ 256 | for( int i = 0; i < count; ++i ) { \ 257 | if( buffer->position + sizeof( *value ) > buffer->size ) { \ 258 | return result; \ 259 | } \ 260 | void* x = &value[ i ]; \ 261 | memcpy( x, (void*)( ( (uintptr_t) buffer->data ) + buffer->position ), sizeof( *value ) ); \ 262 | if( sizeof(*value) == 2 ) \ 263 | *(BUFFER_U16_T*)(x) = \ 264 | ((((*(BUFFER_U16_T*)(x)) & 0xFF00) >> 8) | \ 265 | (((*(BUFFER_U16_T*)(x)) & 0x00FF) << 8)); \ 266 | else if( sizeof(*value) == 4 ) \ 267 | *(BUFFER_U32_T*)(x) = \ 268 | ((((*(BUFFER_U32_T*)(x)) & 0xFF000000) >> 24) | \ 269 | (((*(BUFFER_U32_T*)(x)) & 0x00FF0000) >> 8) | \ 270 | (((*(BUFFER_U32_T*)(x)) & 0x0000FF00) << 8) | \ 271 | (((*(BUFFER_U32_T*)(x)) & 0x000000FF) << 24) ); \ 272 | else if( sizeof(*value) == 8 ) \ 273 | *(BUFFER_U64_T*)(x) = \ 274 | ((((*(BUFFER_U64_T*)(x)) & 0xFF00000000000000) >> 56 ) | \ 275 | (((*(BUFFER_U64_T*)(x)) & 0x00FF000000000000) >> 40 ) | \ 276 | (((*(BUFFER_U64_T*)(x)) & 0x0000FF0000000000) >> 24 ) | \ 277 | (((*(BUFFER_U64_T*)(x)) & 0x000000FF00000000) >> 8 ) | \ 278 | (((*(BUFFER_U64_T*)(x)) & 0x00000000FF000000) << 8) | \ 279 | (((*(BUFFER_U64_T*)(x)) & 0x0000000000FF0000) << 24) | \ 280 | (((*(BUFFER_U64_T*)(x)) & 0x000000000000FF00) << 40) | \ 281 | (((*(BUFFER_U64_T*)(x)) & 0x00000000000000FF) << 56)); \ 282 | buffer->position += sizeof( *value ); \ 283 | ++result; \ 284 | } \ 285 | return result; \ 286 | } 287 | #endif 288 | 289 | int buffer_read_char( buffer_t* buffer, char* value, int count ) BUFFER_READ_IMPL 290 | int buffer_read_i8( buffer_t* buffer, BUFFER_I8_T* value, int count ) BUFFER_READ_IMPL 291 | int buffer_read_i16( buffer_t* buffer, BUFFER_I16_T* value, int count ) BUFFER_READ_IMPL 292 | int buffer_read_i32( buffer_t* buffer, BUFFER_I32_T* value, int count ) BUFFER_READ_IMPL 293 | int buffer_read_i64( buffer_t* buffer, BUFFER_I64_T* value, int count ) BUFFER_READ_IMPL 294 | int buffer_read_u8( buffer_t* buffer, BUFFER_U8_T* value, int count ) BUFFER_READ_IMPL 295 | int buffer_read_u16( buffer_t* buffer, BUFFER_U16_T* value, int count ) BUFFER_READ_IMPL 296 | int buffer_read_u32( buffer_t* buffer, BUFFER_U32_T* value, int count ) BUFFER_READ_IMPL 297 | int buffer_read_u64( buffer_t* buffer, BUFFER_U64_T* value, int count ) BUFFER_READ_IMPL 298 | int buffer_read_float( buffer_t* buffer, float* value, int count ) BUFFER_READ_IMPL 299 | int buffer_read_double( buffer_t* buffer, double* value, int count ) BUFFER_READ_IMPL 300 | int buffer_read_bool( buffer_t* buffer, bool* value, int count ) BUFFER_READ_IMPL 301 | 302 | #undef BUFFER_READ_IMPL 303 | 304 | 305 | #ifndef BUFFER_BIG_ENDIAN 306 | #define BUFFER_WRITE_IMPL \ 307 | { \ 308 | int result = 0; \ 309 | for( int i = 0; i < count; ++i ) { \ 310 | if( buffer->position + sizeof( *value ) > buffer->size ) { \ 311 | if( buffer->is_mapped ) break; \ 312 | buffer->size = buffer->position + sizeof( *value ); \ 313 | while( buffer->size > buffer->capacity ) { \ 314 | buffer->capacity *= 2; \ 315 | } \ 316 | buffer->data = realloc( buffer->data, buffer->capacity ); \ 317 | } \ 318 | memcpy( (void*)( ( (uintptr_t) buffer->data ) + buffer->position ), &value[ i ], sizeof( *value ) ); \ 319 | buffer->position += sizeof( *value ); \ 320 | ++result; \ 321 | } \ 322 | return result; \ 323 | } 324 | #else 325 | #define BUFFER_WRITE_IMPL \ 326 | { \ 327 | int result = 0; \ 328 | for( int i = 0; i < count; ++i ) { \ 329 | if( buffer->position + sizeof( *value ) > buffer->size ) { \ 330 | if( buffer->is_mapped ) break; \ 331 | buffer->size = buffer->position + sizeof( *value ); \ 332 | while( buffer->size > buffer->capacity ) { \ 333 | buffer->capacity *= 2; \ 334 | } \ 335 | buffer->data = realloc( buffer->data, buffer->capacity ); \ 336 | } \ 337 | void* x = (void*)( ( (uintptr_t) buffer->data ) + buffer->position ); \ 338 | memcpy( x, &value[ i ], sizeof( *value ) ); \ 339 | if( sizeof(*value) == 2 ) \ 340 | *(BUFFER_U16_T*)(x) = \ 341 | ((((*(BUFFER_U16_T*)(x)) & 0xFF00) >> 8) | \ 342 | (((*(BUFFER_U16_T*)(x)) & 0x00FF) << 8)); \ 343 | else if( sizeof(*value) == 4 ) \ 344 | *(BUFFER_U32_T*)(x) = \ 345 | ((((*(BUFFER_U32_T*)(x)) & 0xFF000000) >> 24) | \ 346 | (((*(BUFFER_U32_T*)(x)) & 0x00FF0000) >> 8) | \ 347 | (((*(BUFFER_U32_T*)(x)) & 0x0000FF00) << 8) | \ 348 | (((*(BUFFER_U32_T*)(x)) & 0x000000FF) << 24) ); \ 349 | else if( sizeof(*value) == 8 ) \ 350 | *(BUFFER_U64_T*)(x) = \ 351 | ((((*(BUFFER_U64_T*)(x)) & 0xFF00000000000000) >> 56 ) | \ 352 | (((*(BUFFER_U64_T*)(x)) & 0x00FF000000000000) >> 40 ) | \ 353 | (((*(BUFFER_U64_T*)(x)) & 0x0000FF0000000000) >> 24 ) | \ 354 | (((*(BUFFER_U64_T*)(x)) & 0x000000FF00000000) >> 8 ) | \ 355 | (((*(BUFFER_U64_T*)(x)) & 0x00000000FF000000) << 8) | \ 356 | (((*(BUFFER_U64_T*)(x)) & 0x0000000000FF0000) << 24) | \ 357 | (((*(BUFFER_U64_T*)(x)) & 0x000000000000FF00) << 40) | \ 358 | (((*(BUFFER_U64_T*)(x)) & 0x00000000000000FF) << 56)); \ 359 | buffer->position += sizeof( *value ); \ 360 | ++result; \ 361 | } \ 362 | return result; \ 363 | } 364 | #endif 365 | 366 | int buffer_write_char( buffer_t* buffer, char const* value, int count ) BUFFER_WRITE_IMPL 367 | int buffer_write_i8( buffer_t* buffer, BUFFER_I8_T const* value, int count ) BUFFER_WRITE_IMPL 368 | int buffer_write_i16( buffer_t* buffer, BUFFER_I16_T const* value, int count ) BUFFER_WRITE_IMPL 369 | int buffer_write_i32( buffer_t* buffer, BUFFER_I32_T const* value, int count ) BUFFER_WRITE_IMPL 370 | int buffer_write_i64( buffer_t* buffer, BUFFER_I64_T const* value, int count ) BUFFER_WRITE_IMPL 371 | int buffer_write_u8( buffer_t* buffer, BUFFER_U8_T const* value, int count ) BUFFER_WRITE_IMPL 372 | int buffer_write_u16( buffer_t* buffer, BUFFER_U16_T const* value, int count ) BUFFER_WRITE_IMPL 373 | int buffer_write_u32( buffer_t* buffer, BUFFER_U32_T const* value, int count ) BUFFER_WRITE_IMPL 374 | int buffer_write_u64( buffer_t* buffer, BUFFER_U64_T const* value, int count ) BUFFER_WRITE_IMPL 375 | int buffer_write_float( buffer_t* buffer, float const* value, int count ) BUFFER_WRITE_IMPL 376 | int buffer_write_double( buffer_t* buffer, double const* value, int count ) BUFFER_WRITE_IMPL 377 | int buffer_write_bool( buffer_t* buffer, bool const* value, int count ) BUFFER_WRITE_IMPL 378 | 379 | #undef BUFFER_WRITE_IMPL 380 | 381 | #endif /* BUFFER_IMPLEMENTATION */ 382 | 383 | /* 384 | ------------------------------------------------------------------------------ 385 | 386 | This software is available under 2 licenses - you may choose the one you like. 387 | 388 | ------------------------------------------------------------------------------ 389 | 390 | ALTERNATIVE A - MIT License 391 | 392 | Copyright (c) 2022 Mattias Gustavsson 393 | 394 | Permission is hereby granted, free of charge, to any person obtaining a copy of 395 | this software and associated documentation files (the "Software"), to deal in 396 | the Software without restriction, including without limitation the rights to 397 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 398 | of the Software, and to permit persons to whom the Software is furnished to do 399 | so, subject to the following conditions: 400 | 401 | The above copyright notice and this permission notice shall be included in all 402 | copies or substantial portions of the Software. 403 | 404 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 405 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 406 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 407 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 408 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 409 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 410 | SOFTWARE. 411 | 412 | ------------------------------------------------------------------------------ 413 | 414 | ALTERNATIVE B - Public Domain (www.unlicense.org) 415 | 416 | This is free and unencumbered software released into the public domain. 417 | 418 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 419 | software, either in source code form or as a compiled binary, for any purpose, 420 | commercial or non-commercial, and by any means. 421 | 422 | In jurisdictions that recognize copyright laws, the author or authors of this 423 | software dedicate any and all copyright interest in the software to the public 424 | domain. We make this dedication for the benefit of the public at large and to 425 | the detriment of our heirs and successors. We intend this dedication to be an 426 | overt act of relinquishment in perpetuity of all present and future rights to 427 | this software under copyright law. 428 | 429 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 430 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 431 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 432 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 433 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 434 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 435 | 436 | ------------------------------------------------------------------------------ 437 | */ 438 | -------------------------------------------------------------------------------- /dir.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ------------------------------------------------------------------------------ 4 | Licensing information can be found at the end of the dir. 5 | ------------------------------------------------------------------------------ 6 | 7 | dir.h - v0.1 - Directory listing functions for C/C++ 8 | 9 | Do this: 10 | #define DIR_IMPLEMENTATION 11 | before you include this file in *one* C/C++ dir to create the implementation. 12 | */ 13 | 14 | #ifndef dir_h 15 | #define dir_h 16 | 17 | typedef struct dir_t dir_t; 18 | typedef struct dir_entry_t dir_entry_t; 19 | 20 | dir_t* dir_open( char const* path ); 21 | void dir_close( dir_t* dir ); 22 | char const* dir_path( dir_t* dir ); 23 | dir_entry_t* dir_read( dir_t* dir ); 24 | 25 | char const* dir_name( dir_entry_t* entry ); 26 | int dir_is_file( dir_entry_t* entry ); 27 | int dir_is_folder( dir_entry_t* entry ); 28 | 29 | #endif /* dir_h */ 30 | 31 | /* 32 | ---------------------- 33 | IMPLEMENTATION 34 | ---------------------- 35 | */ 36 | 37 | #ifdef DIR_IMPLEMENTATION 38 | #undef DIR_IMPLEMENTATION 39 | 40 | #ifndef DIR_MALLOC 41 | #define _CRT_NONSTDC_NO_DEPRECATE 42 | #define _CRT_SECURE_NO_WARNINGS 43 | #include 44 | #if defined(__cplusplus) 45 | #define DIR_MALLOC( size ) ( ::malloc( size ) ) 46 | #define DIR_FREE( ptr ) ( ::free( ptr ) ) 47 | #else 48 | #define DIR_MALLOC( size ) ( malloc( size ) ) 49 | #define DIR_FREE( ptr ) ( free( ptr ) ) 50 | #endif 51 | #endif 52 | 53 | 54 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 55 | // WINDOWS 56 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 57 | 58 | #if defined( DIR_WINDOWS ) 59 | 60 | #define _CRT_NONSTDC_NO_DEPRECATE 61 | #define _CRT_SECURE_NO_WARNINGS 62 | #if !defined( _WIN32_WINNT ) || _WIN32_WINNT < 0x0501 63 | #undef _WIN32_WINNT 64 | #define _WIN32_WINNT 0x0501 // requires Windows XP minimum 65 | #endif 66 | // 0x0400=Windows NT 4.0, 0x0500=Windows 2000, 0x0501=Windows XP, 0x0502=Windows Server 2003, 0x0600=Windows Vista, 67 | // 0x0601=Windows 7, 0x0602=Windows 8, 0x0603=Windows 8.1, 0x0A00=Windows 10, 68 | #define _WINSOCKAPI_ 69 | #pragma warning( push ) 70 | #pragma warning( disable: 4365 ) 71 | #pragma warning( disable: 4619 ) 72 | #pragma warning( disable: 4668 ) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 73 | #pragma warning( disable: 4768 ) // __declspec attributes before linkage specification are ignored 74 | #pragma warning( disable: 4255 ) // 'function' : no function prototype given: converting '()' to '(void)' 75 | #define _NTDDSCM_H_ 76 | #include 77 | #pragma warning( pop ) 78 | 79 | struct dir_entry_t 80 | { 81 | char name[ MAX_PATH ]; 82 | BOOL is_folder; 83 | }; 84 | 85 | 86 | struct dir_t 87 | { 88 | char path[ MAX_PATH ]; 89 | HANDLE handle; 90 | WIN32_FIND_DATAA data; 91 | dir_entry_t entry; 92 | }; 93 | 94 | 95 | dir_t* dir_open( char const* path ) 96 | { 97 | if( !path ) return 0; 98 | 99 | size_t path_len = strlen( path ); 100 | BOOL trailing_path_separator = path[ path_len - 1 ] == '\\' || path[ path_len - 1 ] == '/'; 101 | const char* string_to_append = "*.*"; 102 | if( path_len + strlen( string_to_append ) + ( trailing_path_separator ? 0 : 1 ) >= MAX_PATH ) return NULL; 103 | char search_pattern[ MAX_PATH ]; 104 | strcpy( search_pattern, path ); 105 | if( !trailing_path_separator ) strcat( search_pattern, "\\" ); 106 | strcat( search_pattern, string_to_append ); 107 | 108 | WIN32_FIND_DATAA data; 109 | HANDLE handle = FindFirstFileA( search_pattern, &data ); 110 | if( handle == INVALID_HANDLE_VALUE ) return NULL; 111 | 112 | dir_t* dir = (dir_t*) DIR_MALLOC( sizeof( dir_t ) ); 113 | strcpy( dir->path, path ); 114 | dir->handle = handle; 115 | dir->data = data; 116 | 117 | return dir; 118 | } 119 | 120 | 121 | void dir_close( dir_t* dir ) 122 | { 123 | if( !dir ) return; 124 | 125 | if( dir->handle != INVALID_HANDLE_VALUE ) FindClose( dir->handle ); 126 | DIR_FREE( dir ); 127 | } 128 | 129 | 130 | char const* dir_path( dir_t* dir ) 131 | { 132 | if( !dir ) return NULL; 133 | return dir->path; 134 | } 135 | 136 | 137 | dir_entry_t* dir_read( dir_t* dir ) 138 | { 139 | if( !dir ) return NULL; 140 | if( dir->handle == INVALID_HANDLE_VALUE ) return NULL; 141 | 142 | strcpy( dir->entry.name, dir->data.cFileName ); 143 | dir->entry.is_folder = ( dir->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0; 144 | 145 | BOOL result = FindNextFileA( dir->handle, &dir->data ); 146 | if( !result ) 147 | { 148 | FindClose( dir->handle ); 149 | dir->handle = INVALID_HANDLE_VALUE; 150 | } 151 | 152 | return &dir->entry; 153 | } 154 | 155 | 156 | char const* dir_name( dir_entry_t* entry ) 157 | { 158 | if( !entry ) return NULL; 159 | return entry->name; 160 | } 161 | 162 | 163 | int dir_is_file( dir_entry_t* entry ) 164 | { 165 | if( !entry ) return 0; 166 | return entry->is_folder == FALSE; 167 | } 168 | 169 | 170 | int dir_is_folder( dir_entry_t* entry ) 171 | { 172 | if( !entry ) return 0; 173 | return entry->is_folder == TRUE; 174 | } 175 | 176 | 177 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 178 | // POSIX 179 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 180 | #elif defined( DIR_POSIX ) 181 | 182 | #include 183 | 184 | 185 | dir_t* dir_open( char const* path ) 186 | { 187 | DIR* dir = opendir( path ); 188 | return (dir_t*) dir; 189 | } 190 | 191 | 192 | void dir_close( dir_t* dir ) 193 | { 194 | if( !dir ) return; 195 | closedir( (DIR*) dir ); 196 | } 197 | 198 | 199 | dir_entry_t* dir_read( dir_t* dir ) 200 | { 201 | if( !dir ) return NULL; 202 | return (dir_entry_t*)readdir( (DIR*) dir ); 203 | } 204 | 205 | 206 | char const* dir_name( dir_entry_t* entry ) 207 | { 208 | if( !entry ) return NULL; 209 | return ( (struct dirent*)entry )->d_name; 210 | } 211 | 212 | 213 | int dir_is_file( dir_entry_t* entry ) 214 | { 215 | if( !entry ) return 0; 216 | return ( (struct dirent*)entry )->d_type == DT_REG; 217 | } 218 | 219 | 220 | int dir_is_folder( dir_entry_t* entry ) 221 | { 222 | if( !entry ) return 0; 223 | return ( (struct dirent*)entry )->d_type == DT_DIR; 224 | } 225 | 226 | 227 | 228 | 229 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 230 | // PLATFORM ERROR 231 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 232 | #else 233 | 234 | #error Undefined platform. Define DIR_WINDOWS or DIR_POSIX. 235 | 236 | #endif 237 | 238 | 239 | #endif /* DIR_IMPLEMENTATION */ 240 | 241 | /* 242 | ------------------------------------------------------------------------------ 243 | 244 | This software is available under 2 licenses - you may choose the one you like. 245 | 246 | ------------------------------------------------------------------------------ 247 | 248 | ALTERNATIVE A - MIT License 249 | 250 | Copyright (c) 2017 Mattias Gustavsson 251 | 252 | Permission is hereby granted, free of charge, to any person obtaining a copy of 253 | this software and associated documentation files (the "Software"), to deal in 254 | the Software without restriction, including without limitation the rights to 255 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 256 | of the Software, and to permit persons to whom the Software is furnished to do 257 | so, subject to the following conditions: 258 | 259 | The above copyright notice and this permission notice shall be included in all 260 | copies or substantial portions of the Software. 261 | 262 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 263 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 264 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 265 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 266 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 267 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 268 | SOFTWARE. 269 | 270 | ------------------------------------------------------------------------------ 271 | 272 | ALTERNATIVE B - Public Domain (www.unlicense.org) 273 | 274 | This is free and unencumbered software released into the public domain. 275 | 276 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 277 | software, either in source code form or as a compiled binary, for any purpose, 278 | commercial or non-commercial, and by any means. 279 | 280 | In jurisdictions that recognize copyright laws, the author or authors of this 281 | software dedicate any and all copyright interest in the software to the public 282 | domain. We make this dedication for the benefit of the public at large and to 283 | the detriment of our heirs and successors. We intend this dedication to be an 284 | overt act of relinquishment in perpetuity of all present and future rights to 285 | this software under copyright law. 286 | 287 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 288 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 289 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 290 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 291 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 292 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 293 | 294 | ------------------------------------------------------------------------------ 295 | */ 296 | -------------------------------------------------------------------------------- /docs/assetsys.md: -------------------------------------------------------------------------------- 1 | assetsys.h 2 | ========== 3 | 4 | Library: [assetsys.h](../assetsys.h) 5 | 6 | 7 | Example 8 | ======= 9 | 10 | ```cpp 11 | #define ASSETSYS_IMPLEMENTATION 12 | #include "libs/assetsys.h" 13 | 14 | #include // for printf 15 | 16 | void list_assets( assetsys_t* assetsys, char const* path, int indent ) 17 | { 18 | // Print folder names and recursively list assets 19 | for( int i = 0; i < assetsys_subdir_count( assetsys, path ); ++i ) 20 | { 21 | char const* subdir_name = assetsys_subdir_name( assetsys, path, i ); 22 | for( int j = 0; j < indent; ++j ) printf( " " ); 23 | printf( "%s/\n", subdir_name ); 24 | 25 | char const* subdir_path = assetsys_subdir_path( assetsys, path, i ); 26 | list_assets( assetsys, subdir_path, indent + 1 ); 27 | } 28 | 29 | // Print file names 30 | for( int i = 0; i < assetsys_file_count( assetsys, path ); ++i ) 31 | { 32 | char const* file_name = assetsys_file_name( assetsys, path, i ); 33 | for( int j = 0; j < indent; ++j ) printf( " " ); 34 | printf( "%s\n", file_name ); 35 | } 36 | } 37 | 38 | int main( int, char** ) 39 | { 40 | assetsys_t* assetsys = assetsys_create( 0 ); 41 | 42 | // Mount current working folder as a virtual "/data" path 43 | assetsys_mount( assetsys, ".", "/data" ); 44 | 45 | // Print all files and subfolders 46 | list_assets( assetsys, "/", 0 ); // Start at root 47 | 48 | // Load a file 49 | assetsys_file_t file; 50 | assetsys_file( assetsys, "/data/readme.txt", &file ); 51 | int size = assetsys_file_size( assetsys, file ); 52 | char* content = (char*) malloc( size + 1 ); // extra space for '\0' 53 | assetsys_file_load( assetsys, file, content ); 54 | content[ size ] = '\0'; // zero terminate the text file 55 | printf( "%s\n", content ); 56 | free( content ); 57 | 58 | assetsys_destroy( assetsys ); 59 | } 60 | ``` 61 | 62 | 63 | API Documentation 64 | ================= 65 | 66 | assetsys.h is a system for loading binary assets into your game. It allows you to mount directories and archive files 67 | (bundles of files; assetsys.h supports using standard zip files for this) assign them a virtual path. You then load 68 | assets through assetsys using the virtual path (which can stay the same even if the mounts change). assetsys.h is 69 | case-insensitive regardless of platform, and only accepts forward slash "/" as path separator, to ensure consistent 70 | behavior. It allows you to mount several paths or archive files to the same virtual path, even if they contain files of 71 | the same name, and a later mount will take precedence over a previous one. This allows you to, for example, have a 72 | `data` archive file and an `update` archive file, where `update` contains new versions of only some of the files. 73 | 74 | assetsys.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use 75 | it, you just include assetsys.h to get the API declarations. To get the definitions, you must include assetsys.h from 76 | *one* single C or C++ file, and #define the symbol `ASSETSYS_IMPLEMENTATION` before you do. 77 | 78 | assetsys.h has a dependency om another single-header library, strpool.h, which is used for efficient storage and 79 | comparison of the filename and path strings. assetsys.h automatically includes strpool.h, so it must reside in the same 80 | path. It does not specify the STRPOOL_IMPLEMENTATION define, on the assumption that you might be including strpool.h in 81 | some other part of your program. If you are not, you can make assetsys.h include the strpool implemention by doing: 82 | 83 | #define ASSETSYS_IMPLEMENTATION 84 | #define STRPOOL_IMPLEMENTATION 85 | #include "assetsys.h" 86 | 87 | 88 | Customization 89 | ------------- 90 | There are a few different things in assetsys.h which are configurable by #defines. Most of the API use the `int` data 91 | type, for integer values where the exact size is not important. However, for some functions, it specifically makes use 92 | of an unsigned 64 bit data types. It default to using `unsigned long long`, but can be redefined by #defining 93 | ASSETSYS_U64, before including assetsys.h. This is useful if you, for example, use the types from `` in the 94 | rest of your program, and you want assetsys.h to use compatible types. In this case, you would include assetsys.h using 95 | the following code: 96 | 97 | #define ASSETSYS_U64 uint64_t 98 | #include "assetsys.h" 99 | 100 | Note that when customizing the data type, you need to use the same definition in every place where you include 101 | assetsys.h, as they affect the declarations as well as the definitions. 102 | 103 | The rest of the customizations only affect the implementation, so will only need to be defined in the file where you 104 | have the #define ASSETSYS_IMPLEMENTATION. 105 | 106 | 107 | ### Custom memory allocators 108 | 109 | To store the internal data structures, ini.h needs to do dynamic allocation by calling `malloc`. Programs might want to 110 | keep track of allocations done, or use custom defined pools to allocate memory from. assetsys.h allows for specifying 111 | custom memory allocation functions for `malloc` and `free`. This is done with the following code: 112 | 113 | #define ASSETSYS_IMPLEMENTATION 114 | #define ASSETSYS_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) ) 115 | #define ASSETSYS_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) ) 116 | #include "assetsys.h" 117 | 118 | where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter 119 | is an optional parameter of type `void*`. When `assetsys_init` is called, you can set the `memctx` field of the `config` 120 | parameter, to a pointer to anything you like, and which will be passed through as the `ctx` parameter to every 121 | `ASSETSYS_MALLOC`/`ASSETSYS_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your 122 | tracking data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the 123 | right type, and access the tracking data. 124 | 125 | If no custom allocator is defined, assetsys.h will default to `malloc` and `free` from the C runtime library. 126 | 127 | 128 | ### Custom assert 129 | 130 | assetsys.h makes use of asserts to report usage errors and code errors. By default, it makes use of the C runtime 131 | library `assert` macro, which only executes in debug builds. However, it allows for substituting with your own assert 132 | function or macro using the following code: 133 | 134 | #define ASSETSYS_IMPLEMENTATION 135 | #define ASSETSYS_ASSERT( condition ) ( my_custom_assert( condition ) ) 136 | #include "assetsys.h" 137 | 138 | Note that if you only want the asserts to trigger in debug builds, you must add a check for this in your custom assert. 139 | 140 | 141 | ### miniz implementation 142 | 143 | assetsys.h makes use of the miniz library for parsing and decompressing zip files. It includes the entire miniz source 144 | code inside assetsys.h, so normally you don't have to worry about it. However, in the case where you might already be 145 | using miniz in some other part of the program, you can tell assetsys.h to not include the implementation for miniz. It 146 | will still include the miniz definitions, and if you don't include the miniz implementation elsewhere, you will get a 147 | linker error. To exclude the miniz implementation, simply define `ASSETSYS_NO_MINIZ` before including assetsys.h, like 148 | this: 149 | 150 | #define ASSETSYS_IMPLEMENTATION 151 | #define ASSETSYS_NO_MINIZ 152 | #include "assetsys.h" 153 | 154 | 155 | assetsys_create 156 | --------------- 157 | 158 | assetsys_t* assetsys_create( void* memctx ) 159 | 160 | Creates a new assetsys instance. assetsys.h does not use any global variables, all data it needs is accessed through 161 | the instance created by calling assetsys_create. Different instances can be used safely from different threads, but if 162 | using the same instance from multiple threads, it is up to the user to make sure functions are not called concurrently, 163 | for example by adding a mutex lock around each call. 164 | 165 | 166 | assetsys_destroy 167 | ---------------- 168 | 169 | void assetsys_destroy( assetsys_t* sys ) 170 | 171 | Destroys an assetsys instance, releasing all the resources used by it. 172 | 173 | 174 | assetsys_mount 175 | -------------- 176 | 177 | assetsys_error_t assetsys_mount( assetsys_t* sys, char const* path, char const* mount_as ) 178 | 179 | Mounts the data source `path`, making all its files accessible through this assetsys instance. The data source can be 180 | either a folder or an archive file (a standard .zip file, with or without compression). `path` must be a relative path, 181 | and must use forward slash `/` as path separator, never backslash, regardless of platform. It must not end with a path 182 | separator. The string `mount_as` will be prepended to all mounted files, and can be passed as an empty string "" if 183 | desired. `mount_as` may not contain the characters backslash `\` or colon `:`. It must not end with a path separator. 184 | `assetsys_mount` will return `ASSETSYS_ERROR_INVALID_PARAMETER` if either `path` or `mount_as` is NULL. It will return 185 | `ASSETSYS_ERROR_INVALID_PATH` if the conditions detailed above are not met, or if the file or folder specified by `path` 186 | could not be found. If `path` indicates a file, and it is not a valid archive file, `assetsys_mount` returns 187 | `ASSETSYS_ERROR_FAILED_TO_READ_ZIP`. 188 | 189 | If multiple mounts contains the same file and it is accessible through the same full path (whether because of the 190 | `mount_as` prefix or not), the last mounted data source will be used when loading that file. 191 | 192 | 193 | assetsys_mount_from_memory 194 | ------------------- 195 | 196 | assetsys_error_t assetsys_mount_from_memory( assetsys_t* sys, void const* data, size_t size, char const* mount_as ) 197 | 198 | Same as `assetsys_mount()`, but takes a data buffer of an archived *.zip* file, along with the size of the file. 199 | 200 | assetsys_dismount 201 | ----------------- 202 | 203 | assetsys_error_t assetsys_dismount( assetsys_t* sys, char const* path, char const* mounted_as ) 204 | 205 | Removes a data source which was mounted by calling `assetsys_mount`. `path` and `mounted_as` must be the same as was 206 | used when mounting. If `path` is NULL, `assetsys_dismount` returns `ASSETSYS_ERROR_INVALID_PARAMETER`. If `mounted_as` 207 | is NULL, or no matching mount could be found, it returns `ASSETSYS_ERROR_INVALID_MOUNT`. 208 | 209 | 210 | assetsys_file 211 | ------------- 212 | 213 | assetsys_error_t assetsys_file( assetsys_t* sys, char const* path, assetsys_file_t* file ) 214 | 215 | Retrieves a handle for the file specified by `path`. `path` needs to be an absolute path, including the `mount_as` 216 | prefix specified when the data source was mounted, and matching is case insensitive. The mounts are searched in reverse 217 | order they were added, and if a file with the specified path could not be found, `assetsys_file` returns 218 | `ASSETSYS_ERROR_FILE_NOT_FOUND`. The handle is written to `file`, which must be a pointer to a `assetsys_file_t` 219 | variable declared by the caller. The handle is used in calls to `assetsys_file_load` and `assetsys_file_size`. The 220 | handle is only valid until any mounts are modified by calling `assetsys_mount` or `assetsys_dismount`. 221 | 222 | 223 | assetsys_file_load 224 | ------------------ 225 | 226 | assetsys_error_t assetsys_file_load( assetsys_t* sys, assetsys_file_t file, void* buffer ) 227 | 228 | Load the data from the file specified by the handle `file` (initialized by calling `assetsys_file`) and writes it into 229 | the memory indicated by `buffer`. This memory buffer must be large enough to fit the entire file. To find out how large 230 | the buffer needs to be, call `assetsys_file_size`. If the file could not be loaded, `assetsys_file_load` returns 231 | `ASSETSYS_ERROR_FAILED_TO_READ_FILE`. 232 | 233 | 234 | assetsys_file_size 235 | ------------------ 236 | 237 | int assetsys_file_size( assetsys_t* sys, assetsys_file_t file ) 238 | 239 | Returns the size, in bytes, of the file specified by the handle `file` (initialized by calling `assetsys_file`). If the 240 | file handle is not valid, `assetsys_file_size` returns 0. 241 | 242 | 243 | assetsys_file_count 244 | ------------------- 245 | 246 | int assetsys_file_count( assetsys_t* sys, char const* path ) 247 | 248 | Returns the number of files in the directory with the specified path, or 0 if the path is invalid. `path` needs to be an 249 | absolute path, including the `mount_as` prefix specified when the data source was mounted, and matching is case 250 | insensitive. `assetsys_file_count` returns the total number of files from all mounts, which fall under the path. 251 | 252 | 253 | assetsys_file_name 254 | ------------------ 255 | 256 | char const* assetsys_file_name( assetsys_t* sys, char const* path, int index ) 257 | 258 | Returns the filename and extension (but not the full path) of one of the files in the specified path. `path` needs to be 259 | an absolute path, including the `mount_as` prefix specified when the data source was mounted, and matching is case 260 | insensitive. `index` needs to be between 0 and one less than the count returned by calling `assetsys_file_count` with 261 | the same path. If the path is invalid or index is out of range, `assetsys_file_name` returns NULL. 262 | 263 | 264 | assetsys_file_path 265 | ------------------ 266 | 267 | char const* assetsys_file_path( assetsys_t* sys, char const* path, int index ) 268 | 269 | Returns the full path, including filename and extension, of one of the files in the specified path. `path` needs to be 270 | an absolute path, including the `mount_as` prefix specified when the data source was mounted, and matching is case 271 | insensitive. `index` needs to be between 0 and one less than the count returned by calling `assetsys_file_count` with 272 | the same path. If the path is invalid or index is out of range, `assetsys_file_path` returns NULL. 273 | 274 | 275 | assetsys_subdir_count 276 | --------------------- 277 | 278 | int assetsys_subdir_count( assetsys_t* sys, char const* path ) 279 | 280 | Returns the number of subdirectories in the directory with the specified path, or 0 if the path is invalid. `path` needs 281 | to be an absolute path, including the `mount_as` prefix specified when the data source was mounted, and matching is case 282 | insensitive. `assetsys_subdir_count` returns the total number of directories from all mounts, which fall under the path. 283 | 284 | 285 | assetsys_subdir_name 286 | -------------------- 287 | 288 | char const* assetsys_subdir_name( assetsys_t* sys, char const* path, int index ) 289 | 290 | Returns the name (but not the full path) of one of the subdirectories in the specified path. `path` needs to be an 291 | absolute path, including the `mount_as` prefix specified when the data source was mounted, and matching is case 292 | insensitive. `index` needs to be between 0 and one less than the count returned by calling `assetsys_subdir_count` with 293 | the same path. If the path is invalid or index is out of range, `assetsys_subdir_name` returns NULL. 294 | 295 | 296 | assetsys_subdir_path 297 | -------------------- 298 | 299 | char const* assetsys_subdir_path( assetsys_t* sys, char const* path, int index ) 300 | 301 | Returns the name, including the full path, of one of the files in the specified path. `path` needs to be an absolute 302 | path, including the `mount_as` prefix specified when the data source was mounted, and matching is case insensitive. 303 | `index` needs to be between 0 and one less than the count returned by calling `assetsys_subdir_count` with the same 304 | path. If the path is invalid or index is out of range, `assetsys_subdir_path` returns NULL. 305 | -------------------------------------------------------------------------------- /docs/hashtable.md: -------------------------------------------------------------------------------- 1 | hashtable.h 2 | =========== 3 | 4 | Library: [hashtable.h](../hashtable.h) 5 | 6 | 7 | Example 8 | ======= 9 | 10 | ```cpp 11 | #define HASHTABLE_IMPLEMENTATION 12 | #include "hashtable.h" 13 | 14 | #include // for printf 15 | 16 | int main( int argc, char** argv ) 17 | { 18 | (void) argc, argv; 19 | 20 | // define some example key and value types 21 | typedef struct key_t { int a, b, c; } key_t; 22 | typedef struct value_t 23 | { 24 | char id[ 64 ]; 25 | float x, y, z; 26 | int n[ 250 ]; 27 | } value_t; 28 | 29 | // create a couple of sample keys 30 | // (don't bother to fill in the fields for this sample) 31 | key_t* key_a = (key_t*)malloc( sizeof( key_t ) ); 32 | key_t* key_b = (key_t*)malloc( sizeof( key_t ) ); 33 | 34 | hashtable_t table; 35 | hashtable_init( &table, sizeof( value_t ), 256, 0 ); 36 | 37 | { 38 | // values are copied into the table, not stored by pointer 39 | // (don't bother to fill in all the fields for this sample) 40 | value_t value_a = { "Item A" }; 41 | value_t value_b = { "Item B" }; 42 | hashtable_insert( &table, (HASHTABLE_U64)(uintptr_t)key_a, &value_a ); 43 | hashtable_insert( &table, (HASHTABLE_U64)(uintptr_t)key_b, &value_b ); 44 | } 45 | 46 | // find the values by key 47 | value_t* value_a = (value_t*)hashtable_find( &table, (HASHTABLE_U64)(uintptr_t)key_a ); 48 | printf( "First item: %s\n", value_a->id ); 49 | value_t* value_b = (value_t*)hashtable_find( &table, (HASHTABLE_U64)(uintptr_t)key_b ); 50 | printf( "Second item: %s\n", value_b->id ); 51 | 52 | // remove one of the items 53 | hashtable_remove( &table, (HASHTABLE_U64)(uintptr_t)key_a ); 54 | 55 | // it is possible to enumerate keys and values 56 | int count = hashtable_count( &table ); 57 | HASHTABLE_U64 const* keys = hashtable_keys( &table ); 58 | value_t* items = (value_t*)hashtable_items( &table ); 59 | printf( "\nEnumeration:\n" ); 60 | for( int i = 0; i < count; ++i ) 61 | printf( " 0x%X : %s\n", (int) keys[ i ], items[ i ].id ); 62 | 63 | // cleanup 64 | hashtable_term( &table ); 65 | free( key_b ); 66 | free( key_a ); 67 | return 0; 68 | } 69 | ``` 70 | 71 | 72 | API Documentation 73 | ================= 74 | 75 | hashtable.h is a small library for storing values in a table and access them efficiently by a 64-bit key. It is a 76 | single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it, you just 77 | include hashtable.h to get the API declarations. To get the definitions, you must include hashtable.h from *one* single 78 | C or C++ file, and #define the symbol `HASHTABLE_IMPLEMENTATION` before you do. 79 | 80 | The key value must be unique per entry, and is hashed for efficient lookup using an internal hashing algorithm. This 81 | library does not support custom key types, so typically pointers or handles are used as key values. 82 | 83 | The library is written with efficiency in mind. Data and keys are stored in separate structures, for better cache 84 | coherency, and hash collisions are resolved with open addressing/linear probing using the next available slot, which is 85 | also good for the cache. 86 | 87 | 88 | Customization 89 | ------------- 90 | There are a few different things in hashtable.h which are configurable by #defines. Most of the API use the `int` data 91 | type, for integer values where the exact size is not important. However, for some functions, it specifically makes use 92 | of 32 and 64 bit data types. These default to using `unsigned int` and `unsigned long long` by default, but can be 93 | redefined by #defining HASHTABLE_U32 and HASHTABLE_U64 respectively, before including hashtable.h. This is useful if 94 | you, for example, use the types from `` in the rest of your program, and you want hashtable.h to use 95 | compatible types. In this case, you would include hashtable.h using the following code: 96 | 97 | #define HASHTABLE_U32 uint32_t 98 | #define HASHTABLE_U64 uint64_t 99 | #include "hashtable.h" 100 | 101 | Note that when customizing the data types, you need to use the same definition in every place where you include 102 | hashtable.h, as they affect the declarations as well as the definitions. 103 | 104 | The rest of the customizations only affect the implementation, so will only need to be defined in the file where you 105 | have the #define HASHTABLE_IMPLEMENTATION. 106 | 107 | Note that if all customizations are utilized, hashtable.h will include no external files whatsoever, which might be 108 | useful if you need full control over what code is being built. 109 | 110 | 111 | ### size_t 112 | 113 | Internally, the hashtable.h implementation makes use of the standard `size_t` data type. This requires including the 114 | c runtime library header ``. To allow full configurability, and avoid hashtable.h including stddef.h, you can 115 | specify which type hashtable.h should use for its size_t, by #defining HASHTABLE_SIZE_T, like this: 116 | 117 | #define HASHTABLE_IMPLEMENTATION 118 | #define HASHTABLE_SIZE_T uint64_t 119 | #include "hashtable.h" 120 | 121 | If not specified, hashtable.h will by default include stddef.h and use the standard `size_t` type. 122 | 123 | 124 | ### Custom memory allocators 125 | 126 | To store the internal data structures, hashtable.h needs to do dynamic allocation by calling `malloc`. Programs might 127 | want to keep track of allocations done, or use custom defined pools to allocate memory from. hashtable.h allows for 128 | specifying custom memory allocation functions for `malloc` and `free`. This is done with the following code: 129 | 130 | #define HASHTABLE_IMPLEMENTATION 131 | #define HASHTABLE_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) ) 132 | #define HASHTABLE_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) ) 133 | #include "hashtable.h" 134 | 135 | where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter 136 | is an optional parameter of type `void*`. When `hashtable_init` is called, you can pass in a `memctx` parameter, which 137 | can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every 138 | `HASHTABLE_MALLOC`/`HASHTABLE_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your 139 | tracking data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the 140 | right type, and access the tracking data. 141 | 142 | If no custom allocator is defined, hashtable.h will default to `malloc` and `free` from the C runtime library. 143 | 144 | 145 | ### Custom assert 146 | 147 | hashtable.h makes use of asserts to report usage errors and failed allocation errors. By default, it makes use of the C 148 | runtime library `assert` macro, which only executes in debug builds. However, it allows for substituting with your own 149 | assert function or macro using the following code: 150 | 151 | #define HASHTABLE_IMPLEMENTATION 152 | #define HASHTABLE_ASSERT( condition ) ( my_custom_assert( condition ) ) 153 | #include "hashtable.h" 154 | 155 | Note that if you only want the asserts to trigger in debug builds, you must add a check for this in your custom assert. 156 | 157 | 158 | ### Custom C runtime functions 159 | 160 | The library makes use of two additional functions from the C runtime library, and for full flexibility, it allows you 161 | to substitute them for your own. Here's an example: 162 | 163 | #define HASHTABLE_IMPLEMENTATION 164 | #define HASHTABLE_MEMCPY( dst, src, cnt ) ( my_memcpy_func( dst, src, cnt ) ) 165 | #define HASHTABLE_MEMSET( ptr, val, cnt ) ( my_memset_func( ptr, val, cnt ) ) 166 | #include "hashtable.h" 167 | 168 | If no custom function is defined, hashtable.h will default to the C runtime library equivalent. 169 | 170 | 171 | hashtable_init 172 | -------------- 173 | 174 | void hashtable_init( hashtable_t* table, int item_size, int initial_capacity, void* memctx ) 175 | 176 | Initialize a hashtable instance. `item_size` specifies the size, in bytes, of the data type holding a single item stored 177 | in the table. `initial_capacity` is the number of items to allocate storage for initially - capacity will automatically 178 | grow as needed, by reallocating memory. 179 | 180 | 181 | hashtable_term 182 | -------------- 183 | 184 | void hashtable_term( hashtable_t* table ) 185 | 186 | Terminates a hashtable instance, releasing all memory used by it. No further calls to the hashtable API are valid until 187 | the instance is reinitialized by another call to `hashtable_init`. 188 | 189 | 190 | hashtable_insert 191 | ---------------- 192 | 193 | void hashtable_insert( hashtable_t* table, HASHTABLE_U64 key, void const* item ) 194 | 195 | Inserts a data item into the hashtable, associating it with the specified key. The item is copied into the hashtable, 196 | rather than just storing the `item` pointer, so the `item` pointer can be safely released after the call to 197 | `hashtable_insert`. The value of `key` must be unique - it is not valid to store two items with the same key value. An 198 | assert is triggered if trying to add a key which already exists, which means that if the default assert is used, it will 199 | only be checked in debug builds - in release builds, it is up to the calling code to ensure this doesn't happen, or the 200 | hashtable will be left in an undefined state. 201 | 202 | 203 | hashtable_remove 204 | ---------------- 205 | 206 | void hashtable_remove( hashtable_t* table, HASHTABLE_U64 key ) 207 | 208 | Removes the item associated with the specified key, and the instance of the key itself, from the hashtable. If the 209 | specified key could not be found, an assert is triggered. 210 | 211 | 212 | hashtable_clear 213 | --------------- 214 | 215 | void hashtable_clear( hashtable_t* table ) 216 | 217 | Removes all the items stored in the hashtable, without deallocating any of the memory it has allocated. 218 | 219 | 220 | hashtable_find 221 | -------------- 222 | 223 | void* hashtable_find( hashtable_t const* table, HASHTABLE_U64 key ) 224 | 225 | Returns a pointer to the item associated with the specified key, or NULL it the key was not found. The lookup is 226 | designed for efficiency, and for minimizing cache missed. 227 | 228 | 229 | hashtable_count 230 | --------------- 231 | 232 | int hashtable_count( hashtable_t const* table ) 233 | 234 | Returns the number of items currently held in the table. 235 | 236 | 237 | hashtable_items 238 | --------------- 239 | 240 | void* hashtable_items( hashtable_t const* table ) 241 | 242 | Returns a pointer to the items currently held in the table. All items are stored in a contiguous memory block, and you 243 | can get to the next item be moving the pointer `item_size` bytes forward, where `item_size` is the same value as passed 244 | to hash_table_init. The easiest way to acces items is to cast the return value to the correct type and just index it as 245 | a normal array. It contains as many items as returned by `hashtable_count`. 246 | 247 | 248 | hashtable_keys 249 | -------------- 250 | 251 | HASHTABLE_U64 const* hashtable_keys( hashtable_t const* table ) 252 | 253 | Returns a pointer to the keys currently held in the table, in the same order as the items returned from 254 | `hashtable_items`. Can be indexed as an array with as many elements as returned by `hashtable_count`. 255 | 256 | 257 | hashtable_swap 258 | -------------- 259 | 260 | void hashtable_swap( hashtable_t* table, int index_a, int index_b ) 261 | 262 | Swaps the specified item/key pairs, and updates the hash lookup for both. Can be used to re-order the contents, as 263 | retrieved by calling `hashtable_items` and `hashtable_keys`, while keeping the hashing intact. 264 | 265 | -------------------------------------------------------------------------------- /docs/http.md: -------------------------------------------------------------------------------- 1 | http.h 2 | ====== 3 | 4 | Library: [http.h](../http.h) 5 | 6 | 7 | Example 8 | ======= 9 | 10 | ```cpp 11 | #define HTTP_IMPLEMENTATION 12 | #include "http.h" 13 | 14 | int main( int argc, char** argv ) 15 | { 16 | (void) argc, argv; 17 | 18 | http_t* request = http_get( "http://www.mattiasgustavsson.com/http_test.txt", NULL ); 19 | if( !request ) 20 | { 21 | printf( "Invalid request.\n" ); 22 | return 1; 23 | } 24 | 25 | http_status_t status = HTTP_STATUS_PENDING; 26 | int prev_size = -1; 27 | while( status == HTTP_STATUS_PENDING ) 28 | { 29 | status = http_process( request ); 30 | if( prev_size != (int) request->response_size ) 31 | { 32 | printf( "%d byte(s) received.\n", (int) request->response_size ); 33 | prev_size = (int) request->response_size; 34 | } 35 | } 36 | 37 | if( status == HTTP_STATUS_FAILED ) 38 | { 39 | printf( "HTTP request failed (%d): %s.\n", request->status_code, request->reason_phrase ); 40 | http_release( request ); 41 | return 1; 42 | } 43 | 44 | printf( "\nContent type: %s\n\n%s\n", request->content_type, (char const*)request->response_data ); 45 | http_release( request ); 46 | return 0; 47 | } 48 | ``` 49 | 50 | 51 | API Documentation 52 | ================= 53 | 54 | http.h is a small library for making http requests from a web server. It only supports GET and POST http commands, and 55 | is designed for when you just need a very basic way of communicating over http. http.h does not support https 56 | connections, just plain http. 57 | 58 | http.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use 59 | it, you just include http.h to get the API declarations. To get the definitions, you must include http.h from 60 | *one* single C or C++ file, and #define the symbol `HTTP_IMPLEMENTATION` before you do. 61 | 62 | 63 | Customization 64 | ------------- 65 | 66 | ### Custom memory allocators 67 | 68 | For working memory and to store the retrieved data, http.h needs to do dynamic allocation by calling `malloc`. Programs 69 | might want to keep track of allocations done, or use custom defined pools to allocate memory from. http.h allows 70 | for specifying custom memory allocation functions for `malloc` and `free`. This is done with the following code: 71 | 72 | #define HTTP_IMPLEMENTATION 73 | #define HTTP_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) ) 74 | #define HTTP_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) ) 75 | #include "http.h" 76 | 77 | where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter 78 | is an optional parameter of type `void*`. When `http_get` or `http_post` is called, , you can pass in a `memctx` 79 | parameter, which can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every 80 | `HTTP_MALLOC`/`HTTP_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your 81 | tracking data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the 82 | right type, and access the tracking data. 83 | 84 | If no custom allocator is defined, http.h will default to `malloc` and `free` from the C runtime library. 85 | 86 | 87 | http_get 88 | -------- 89 | 90 | http_t* http_get( char const* url, void* memctx ) 91 | 92 | Initiates a http GET request with the specified url. `url` is a zero terminated string containing the request location, 93 | just like you would type it in a browser, for example `http://www.mattiasgustavsson.com:80/http_test.txt`. `memctx` is a 94 | pointer to user defined data which will be passed through to the custom HTTP_MALLOC/HTTP_FREE calls. It can be NULL if 95 | no user defined data is needed. Returns a `http_t` instance, which needs to be passed to `http_process` to process the 96 | request. When the request is finished (or have failed), the returned `http_t` instance needs to be released by calling 97 | `http_release`. If the request was invalid, `http_get` returns NULL. 98 | 99 | 100 | http_post 101 | --------- 102 | 103 | http_t* http_post( char const* url, void const* data, size_t size, void* memctx ) 104 | 105 | Initiates a http POST request with the specified url. `url` is a zero terminated string containing the request location, 106 | just like you would type it in a browser, for example `http://www.mattiasgustavsson.com:80/http_test.txt`. `data` is a 107 | pointer to the data to be sent along as part of the request, and `size` is the number of bytes to send. `memctx` is a 108 | pointer to user defined data which will be passed through to the custom HTTP_MALLOC/HTTP_FREE calls. It can be NULL if 109 | no user defined data is needed. Returns a `http_t` instance, which needs to be passed to `http_process` to process the 110 | request. When the request is finished (or have failed), the returned `http_t` instance needs to be released by calling 111 | `http_release`. If the request was invalid, `http_post` returns NULL. 112 | 113 | 114 | http_process 115 | ------------ 116 | 117 | http_status_t http_process( http_t* http ) 118 | 119 | http.h uses non-blocking sockets, so after a request have been made by calling either `http_get` or `http_post`, you 120 | have to keep calling `http_process` for as long as it returns `HTTP_STATUS_PENDING`. You can call it from a loop which 121 | does other work too, for example from inside a game loop or from a loop which calls `http_process` on multiple requests. 122 | If the request fails, `http_process` returns `HTTP_STATUS_FAILED`, and the fields `status_code` and `reason_phrase` may 123 | contain more details (for example, status code can be 404 if the requested resource was not found on the server). If the 124 | request completes successfully, it returns `HTTP_STATUS_COMPLETED`. In this case, the `http_t` instance will contain 125 | details about the result. `status_code` and `reason_phrase` contains the details about the result, as specified in the 126 | HTTP protocol. `content_type` contains the MIME type for the returns resource, for example `text/html` for a normal web 127 | page. `response_data` is the pointer to the received data, and `resonse_size` is the number of bytes it contains. In the 128 | case when the response data is in text format, http.h ensures there is a zero terminator placed immediately after the 129 | response data block, so it is safe to interpret the resonse data as a `char*`. Note that the data size in this case will 130 | be the length of the data without the additional zero terminator. 131 | 132 | 133 | http_release 134 | ------------ 135 | 136 | void http_release( http_t* http ) 137 | 138 | Releases the resources acquired by `http_get` or `http_post`. Should be call when you are finished with the request. 139 | -------------------------------------------------------------------------------- /docs/ini.md: -------------------------------------------------------------------------------- 1 | ini.h 2 | ===== 3 | 4 | Library: [ini.h](../ini.h) 5 | 6 | 7 | Examples 8 | ======== 9 | 10 | Loading an ini file and retrieving values 11 | ----------------------------------------- 12 | 13 | ```cpp 14 | #define INI_IMPLEMENTATION 15 | #include "ini.h" 16 | 17 | #include 18 | #include 19 | 20 | int main() 21 | { 22 | FILE* fp = fopen( "test.ini", "r" ); 23 | fseek( fp, 0, SEEK_END ); 24 | int size = ftell( fp ); 25 | fseek( fp, 0, SEEK_SET ); 26 | char* data = (char*) malloc( size + 1 ); 27 | fread( data, 1, size, fp ); 28 | data[ size ] = '\0'; 29 | fclose( fp ); 30 | 31 | ini_t* ini = ini_load( data ); 32 | free( data ); 33 | int second_index = ini_find_property( ini, INI_GLOBAL_SECTION, "SecondSetting" ); 34 | char const* second = ini_property_value( ini, INI_GLOBAL_SECTION, second_index ); 35 | printf( "%s=%s\n", "SecondSetting", second ); 36 | int section = ini_find_section( ini, "MySection" ); 37 | int third_index = ini_find_property( ini, section, "ThirdSetting" ); 38 | char const* third = ini_property_value( ini, section, third_index ); 39 | printf( "%s=%s\n", "ThirdSetting", third ); 40 | ini_destroy( ini ); 41 | 42 | return 0; 43 | } 44 | ``` 45 | 46 | Creating a new ini file 47 | ----------------------- 48 | 49 | ```cpp 50 | #define INI_IMPLEMENTATION 51 | #include "ini.h" 52 | 53 | #include 54 | #include 55 | 56 | int main() 57 | { 58 | ini_t* ini = ini_create(); 59 | ini_property_add( ini, INI_GLOBAL_SECTION, "FirstSetting", "Test" ); 60 | ini_property_add( ini, INI_GLOBAL_SECTION, "SecondSetting", "2" ); 61 | int section = ini_section_add( ini, "MySection" ); 62 | ini_property_add( ini, section, "ThirdSetting", "Three" ); 63 | 64 | int size = ini_save( ini, NULL, 0 ); // Find the size needed 65 | char* data = (char*) malloc( size ); 66 | size = ini_save( ini, data, size ); // Actually save the file 67 | ini_destroy( ini ); 68 | 69 | FILE* fp = fopen( "test.ini", "w" ); 70 | fwrite( data, 1, size, fp ); 71 | fclose( fp ); 72 | free( data ); 73 | 74 | return 0; 75 | } 76 | ``` 77 | 78 | 79 | API Documentation 80 | ================= 81 | 82 | ini.h is a small library for reading classic .ini files. It is a single-header library, and does not need any .lib files 83 | or other binaries, or any build scripts. To use it, you just include ini.h to get the API declarations. To get the 84 | definitions, you must include ini.h from *one* single C or C++ file, and #define the symbol `INI_IMPLEMENTATION` before 85 | you do. 86 | 87 | 88 | Customization 89 | ------------- 90 | There are a few different things in ini.h which are configurable by #defines. The customizations only affect the 91 | implementation, so will only need to be defined in the file where you have the #define INI_IMPLEMENTATION. 92 | 93 | Note that if all customizations are utilized, ini.h will include no external files whatsoever, which might be useful 94 | if you need full control over what code is being built. 95 | 96 | 97 | ### Custom memory allocators 98 | 99 | To store the internal data structures, ini.h needs to do dynamic allocation by calling `malloc`. Programs might want to 100 | keep track of allocations done, or use custom defined pools to allocate memory from. ini.h allows for specifying custom 101 | memory allocation functions for `malloc` and `free`. 102 | This is done with the following code: 103 | 104 | #define INI_IMPLEMENTATION 105 | #define INI_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) ) 106 | #define INI_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) ) 107 | #include "ini.h" 108 | 109 | where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter 110 | is an optional parameter of type `void*`. When `ini_create` or `ini_load` is called, you can pass in a `memctx` 111 | parameter, which can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every 112 | `INI_MALLOC`/`INI_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your tracking 113 | data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the 114 | right type, and access the tracking data. 115 | 116 | If no custom allocator is defined, ini.h will default to `malloc` and `free` from the C runtime library. 117 | 118 | 119 | ### Custom C runtime function 120 | 121 | The library makes use of three additional functions from the C runtime library, and for full flexibility, it allows you 122 | to substitute them for your own. Here's an example: 123 | 124 | #define INI_IMPLEMENTATION 125 | #define INI_MEMCPY( dst, src, cnt ) ( my_memcpy_func( dst, src, cnt ) ) 126 | #define INI_STRLEN( s ) ( my_strlen_func( s ) ) 127 | #define INI_STRICMP( s1, s2 ) ( my_stricmp_func( s1, s2 ) ) 128 | #include "ini.h" 129 | 130 | If no custom function is defined, ini.h will default to the C runtime library equivalent. 131 | 132 | 133 | ini_create 134 | ---------- 135 | 136 | ini_t* ini_create( void* memctx ) 137 | 138 | Instantiates a new, empty ini structure, which can be manipulated with other API calls, to fill it with data. To save it 139 | out to an ini-file string, use `ini_save`. When no longer needed, it can be destroyed by calling `ini_destroy`. 140 | `memctx` is a pointer to user defined data which will be passed through to the custom INI_MALLOC/INI_FREE calls. It can 141 | be NULL if no user defined data is needed. 142 | 143 | 144 | ini_load 145 | -------- 146 | 147 | ini_t* ini_load( char const* data, void* memctx ) 148 | 149 | Parse the zero-terminated string `data` containing an ini-file, and create a new ini_t instance containing the data. 150 | The instance can be manipulated with other API calls to enumerate sections/properties and retrieve values. When no 151 | longer needed, it can be destroyed by calling `ini_destroy`. `memctx` is a pointer to user defined data which will be 152 | passed through to the custom INI_MALLOC/INI_FREE calls. It can be NULL if no user defined data is needed. 153 | 154 | 155 | ini_save 156 | -------- 157 | 158 | int ini_save( ini_t const* ini, char* data, int size ) 159 | 160 | Saves an ini structure as a zero-terminated ini-file string, into the specified buffer. Returns the number of bytes 161 | written, including the zero terminator. If `data` is NULL, nothing is written, but `ini_save` still returns the number 162 | of bytes it would have written. If the size of `data`, as specified in the `size` parameter, is smaller than that 163 | required, only part of the ini-file string will be written. `ini_save` still returns the number of bytes it would have 164 | written had the buffer been large enough. 165 | 166 | 167 | ini_destroy 168 | ----------- 169 | 170 | void ini_destroy( ini_t* ini ) 171 | 172 | Destroy an `ini_t` instance created by calling `ini_load` or `ini_create`, releasing the memory allocated by it. No 173 | further API calls are valid on an `ini_t` instance after calling `ini_destroy` on it. 174 | 175 | 176 | ini_section_count 177 | ----------------- 178 | 179 | int ini_section_count( ini_t const* ini ) 180 | 181 | Returns the number of sections in an ini file. There's at least one section in an ini file (the global section), but 182 | there can be many more, each specified in the file by the section name wrapped in square brackets [ ]. 183 | 184 | 185 | ini_section_name 186 | ---------------- 187 | 188 | char const* ini_section_name( ini_t const* ini, int section ) 189 | 190 | Returns the name of the section with the specified index. `section` must be non-negative and less than the value 191 | returned by `ini_section_count`, or `ini_section_name` will return NULL. The defined constant `INI_GLOBAL_SECTION` can 192 | be used to indicate the global section. 193 | 194 | 195 | ini_property_count 196 | ------------------ 197 | 198 | int ini_property_count( ini_t const* ini, int section ) 199 | 200 | Returns the number of properties belonging to the section with the specified index. `section` must be non-negative and 201 | less than the value returned by `ini_section_count`, or `ini_section_name` will return 0. The defined constant 202 | `INI_GLOBAL_SECTION` can be used to indicate the global section. Properties are declared in the ini-file on he format 203 | `name=value`. 204 | 205 | 206 | ini_property_name 207 | ----------------- 208 | 209 | char const* ini_property_name( ini_t const* ini, int section, int property ) 210 | 211 | Returns the name of the property with the specified index `property` in the section with the specified index `section`. 212 | `section` must be non-negative and less than the value returned by `ini_section_count`, and `property` must be 213 | non-negative and less than the value returned by `ini_property_count`, or `ini_property_name` will return NULL. The 214 | defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. 215 | 216 | 217 | ini_property_value 218 | ------------------ 219 | 220 | char const* ini_property_value( ini_t const* ini, int section, int property ) 221 | 222 | Returns the value of the property with the specified index `property` in the section with the specified index `section`. 223 | `section` must be non-negative and less than the value returned by `ini_section_count`, and `property` must be 224 | non-negative and less than the value returned by `ini_property_count`, or `ini_property_value` will return NULL. The 225 | defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. 226 | 227 | 228 | ini_find_section 229 | ---------------- 230 | 231 | int ini_find_section( ini_t const* ini, char const* name, int name_length ) 232 | 233 | Finds the section with the specified name, and returns its index. `name_length` specifies the number of characters in 234 | `name`, which does not have to be zero-terminated. If `name_length` is zero, the length is determined automatically, but 235 | in this case `name` has to be zero-terminated. If no section with the specified name could be found, the value 236 | `INI_NOT_FOUND` is returned. 237 | 238 | 239 | ini_find_property 240 | ----------------- 241 | 242 | int ini_find_property( ini_t const* ini, int section, char const* name, int name_length ) 243 | 244 | Finds the property with the specified name, within the section with the specified index, and returns the index of the 245 | property. `name_length` specifies the number of characters in `name`, which does not have to be zero-terminated. If 246 | `name_length` is zero, the length is determined automatically, but in this case `name` has to be zero-terminated. If no 247 | property with the specified name could be found within the specified section, the value `INI_NOT_FOUND` is returned. 248 | `section` must be non-negative and less than the value returned by `ini_section_count`, or `ini_find_property` will 249 | return `INI_NOT_FOUND`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. 250 | 251 | 252 | ini_section_add 253 | --------------- 254 | 255 | int ini_section_add( ini_t* ini, char const* name, int length ) 256 | 257 | Adds a section with the specified name, and returns the index it was added at. There is no check done to see if a 258 | section with the specified name already exists - multiple sections of the same name are allowed. `length` specifies the 259 | number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, the length is determined 260 | automatically, but in this case `name` has to be zero-terminated. 261 | 262 | 263 | ini_property_add 264 | ---------------- 265 | 266 | void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length ) 267 | 268 | Adds a property with the specified name and value to the specified section, and returns the index it was added at. There 269 | is no check done to see if a property with the specified name already exists - multiple properties of the same name are 270 | allowed. `name_length` and `value_length` specifies the number of characters in `name` and `value`, which does not have 271 | to be zero-terminated. If `name_length` or `value_length` is zero, the length is determined automatically, but in this 272 | case `name`/`value` has to be zero-terminated. `section` must be non-negative and less than the value returned by 273 | `ini_section_count`, or the property will not be added. The defined constant `INI_GLOBAL_SECTION` can be used to 274 | indicate the global section. 275 | 276 | 277 | ini_section_remove 278 | ------------------ 279 | 280 | void ini_section_remove( ini_t* ini, int section ) 281 | 282 | Removes the section with the specified index, and all properties within it. `section` must be non-negative and less than 283 | the value returned by `ini_section_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global 284 | section. Note that removing a section will shuffle section indices, so that section indices you may have stored will no 285 | longer indicate the same section as it did before the remove. Use the find functions to update your indices. 286 | 287 | 288 | ini_property_remove 289 | ------------------- 290 | 291 | void ini_property_remove( ini_t* ini, int section, int property ) 292 | 293 | Removes the property with the specified index from the specified section. `section` must be non-negative and less than 294 | the value returned by `ini_section_count`, and `property` must be non-negative and less than the value returned by 295 | `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. Note that 296 | removing a property will shuffle property indices within the specified section, so that property indices you may have 297 | stored will no longer indicate the same property as it did before the remove. Use the find functions to update your 298 | indices. 299 | 300 | 301 | ini_section_name_set 302 | -------------------- 303 | 304 | void ini_section_name_set( ini_t* ini, int section, char const* name, int length ) 305 | 306 | Change the name of the section with the specified index. `section` must be non-negative and less than the value returned 307 | by `ini_section_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. `length` 308 | specifies the number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, the length 309 | is determined automatically, but in this case `name` has to be zero-terminated. 310 | 311 | 312 | ini_property_name_set 313 | --------------------- 314 | 315 | void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length ) 316 | 317 | Change the name of the property with the specified index in the specified section. `section` must be non-negative and 318 | less than the value returned by `ini_section_count`, and `property` must be non-negative and less than the value 319 | returned by `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. 320 | `length` specifies the number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, 321 | the length is determined automatically, but in this case `name` has to be zero-terminated. 322 | 323 | 324 | ini_property_value_set 325 | ---------------------- 326 | 327 | void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length ) 328 | 329 | Change the value of the property with the specified index in the specified section. `section` must be non-negative and 330 | less than the value returned by `ini_section_count`, and `property` must be non-negative and less than the value 331 | returned by `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. 332 | `length` specifies the number of characters in `value`, which does not have to be zero-terminated. If `length` is zero, 333 | the length is determined automatically, but in this case `value` has to be zero-terminated. 334 | -------------------------------------------------------------------------------- /docs/rnd.md: -------------------------------------------------------------------------------- 1 | rnd.h 2 | ===== 3 | 4 | Library: [rnd.h](../rnd.h) 5 | 6 | 7 | Example 8 | ======= 9 | 10 | A basic example showing how to use the PCG set of random functions. 11 | 12 | ```cpp 13 | #define RND_IMPLEMENTATION 14 | #include "rnd.h" 15 | 16 | #include // for printf 17 | #include // for time 18 | 19 | int main( int argc, char** argv ) 20 | { 21 | (void) argc, argv; 22 | 23 | rnd_pcg_t pcg; 24 | rnd_pcg_seed( &pcg, 0u ); // initialize generator 25 | 26 | // print a handful of random integers 27 | // these will be the same on every run, as we 28 | // seeded the rng with a fixed value 29 | for( int i = 0; i < 5; ++i ) 30 | { 31 | RND_U32 n = rnd_pcg_next( &pcg ); 32 | printf( "%08x, ", n ); 33 | } 34 | printf( "\n" ); 35 | 36 | // reseed with a value which is different on each run 37 | time_t seconds; 38 | time( &seconds ); 39 | rnd_pcg_seed( &pcg, (RND_U32) seconds ); 40 | 41 | // print another handful of random integers 42 | // these will be different on every run 43 | for( int i = 0; i < 5; ++i ) 44 | { 45 | RND_U32 n = rnd_pcg_next( &pcg ); 46 | printf( "%08x, ", n ); 47 | } 48 | printf( "\n" ); 49 | 50 | 51 | // print a handful of random floats 52 | for( int i = 0; i < 5; ++i ) 53 | { 54 | float f = rnd_pcg_nextf( &pcg ); 55 | printf( "%f, ", f ); 56 | } 57 | printf( "\n" ); 58 | 59 | // print random integers in the range 1 to 6 60 | for( int i = 0; i < 15; ++i ) 61 | { 62 | int r = rnd_pcg_range( &pcg, 1, 6 ); 63 | printf( "%d, ", r ); 64 | } 65 | printf( "\n" ); 66 | 67 | return 0; 68 | } 69 | ``` 70 | 71 | 72 | API Documentation 73 | ================= 74 | 75 | rnd.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it, 76 | you just include rnd.h to get the API declarations. To get the definitions, you must include rnd.h from *one* single C 77 | or C++ file, and #define the symbol `RND_IMPLEMENTATION` before you do. 78 | 79 | The library is meant for general-purpose use, such as games and similar apps. It is not meant to be used for 80 | cryptography and similar use cases. 81 | 82 | 83 | Customization 84 | ------------- 85 | rnd.h allows for specifying the exact type of 32 and 64 bit unsigned integers to be used in its API. By default, these 86 | default to `unsigned int` and `unsigned long long`, but can be redefined by #defining RND_U32 and RND_U64 respectively 87 | before including rnd.h. This is useful if you, for example, use the types from `` in the rest of your program, 88 | and you want rnd.h to use compatible types. In this case, you would include rnd.h using the following code: 89 | 90 | #define RND_U32 uint32_t 91 | #define RND_U64 uint64_t 92 | #include "rnd.h" 93 | 94 | Note that when customizing the data type, you need to use the same definition in every place where you include rnd.h, 95 | as it affect the declarations as well as the definitions. 96 | 97 | 98 | The generators 99 | -------------- 100 | 101 | The library includes four different generators: PCG, WELL, GameRand and XorShift. They all have different 102 | characteristics, and you might want to use them for different things. GameRand is very fast, but does not give a great 103 | distribution or period length. XorShift is the only one returning a 64-bit value. WELL is an improvement of the often 104 | used Mersenne Twister, and has quite a large internal state. PCG is small, fast and has a small state. If you don't 105 | have any specific reason, you may default to using PCG. 106 | 107 | All generators expose their internal state, so it is possible to save this state and later restore it, to resume the 108 | random sequence from the same point. 109 | 110 | 111 | ### PCG - Permuted Congruential Generator 112 | 113 | PCG is a family of simple fast space-efficient statistically good algorithms for random number generation. Unlike many 114 | general-purpose RNGs, they are also hard to predict. 115 | 116 | More information can be found here: http://www.pcg-random.org/ 117 | 118 | 119 | ### WELL - Well Equidistributed Long-period Linear 120 | 121 | Random number generation, using the WELL algorithm by F. Panneton, P. L'Ecuyer and M. Matsumoto. 122 | More information in the original paper: http://www.iro.umontreal.ca/~panneton/WELLRNG.html 123 | 124 | This code is originally based on WELL512 C/C++ code written by Chris Lomont (published in Game Programming Gems 7) 125 | and placed in the public domain. http://lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf 126 | 127 | 128 | ### GameRand 129 | 130 | Based on the random number generator by Ian C. Bullard: 131 | http://www.redditmirror.cc/cache/websites/mjolnirstudios.com_7yjlc/mjolnirstudios.com/IanBullard/files/79ffbca75a75720f066d491e9ea935a0-10.html 132 | 133 | GameRand is a random number generator based off an "Image of the Day" posted by Stephan Schaem. More information here: 134 | http://www.flipcode.com/archives/07-15-2002.shtml 135 | 136 | 137 | ### XorShift 138 | 139 | A random number generator of the type LFSR (linear feedback shift registers). This specific implementation uses the 140 | XorShift+ variation, and returns 64-bit random numbers. 141 | 142 | More information can be found here: https://en.wikipedia.org/wiki/Xorshift 143 | 144 | 145 | 146 | rnd_pcg_seed 147 | ------------ 148 | 149 | void rnd_pcg_seed( rnd_pcg_t* pcg, RND_U32 seed ) 150 | 151 | Initialize a PCG generator with the specified seed. The generator is not valid until it's been seeded. 152 | 153 | 154 | rnd_pcg_next 155 | ------------ 156 | 157 | RND_U32 rnd_pcg_next( rnd_pcg_t* pcg ) 158 | 159 | Returns a random number N in the range: 0 <= N <= 0xffffffff, from the specified PCG generator. 160 | 161 | 162 | rnd_pcg_nextf 163 | ------------- 164 | 165 | float rnd_pcg_nextf( rnd_pcg_t* pcg ) 166 | 167 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified PCG generator. 168 | 169 | 170 | rnd_pcg_range 171 | ------------- 172 | 173 | int rnd_pcg_range( rnd_pcg_t* pcg, int min, int max ) 174 | 175 | Returns a random integer N in the range: min <= N <= max, from the specified PCG generator. 176 | 177 | 178 | rnd_well_seed 179 | ------------- 180 | 181 | void rnd_well_seed( rnd_well_t* well, RND_U32 seed ) 182 | 183 | Initialize a WELL generator with the specified seed. The generator is not valid until it's been seeded. 184 | 185 | 186 | rnd_well_next 187 | ------------- 188 | 189 | RND_U32 rnd_well_next( rnd_well_t* well ) 190 | 191 | Returns a random number N in the range: 0 <= N <= 0xffffffff, from the specified WELL generator. 192 | 193 | 194 | rnd_well_nextf 195 | -------------- 196 | float rnd_well_nextf( rnd_well_t* well ) 197 | 198 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified WELL generator. 199 | 200 | 201 | rnd_well_range 202 | -------------- 203 | 204 | int rnd_well_range( rnd_well_t* well, int min, int max ) 205 | 206 | Returns a random integer N in the range: min <= N <= max, from the specified WELL generator. 207 | 208 | 209 | rnd_gamerand_seed 210 | ----------------- 211 | 212 | void rnd_gamerand_seed( rnd_gamerand_t* gamerand, RND_U32 seed ) 213 | 214 | Initialize a GameRand generator with the specified seed. The generator is not valid until it's been seeded. 215 | 216 | 217 | rnd_gamerand_next 218 | ----------------- 219 | 220 | RND_U32 rnd_gamerand_next( rnd_gamerand_t* gamerand ) 221 | 222 | Returns a random number N in the range: 0 <= N <= 0xffffffff, from the specified GameRand generator. 223 | 224 | 225 | rnd_gamerand_nextf 226 | ------------------ 227 | 228 | float rnd_gamerand_nextf( rnd_gamerand_t* gamerand ) 229 | 230 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified GameRand generator. 231 | 232 | 233 | rnd_gamerand_range 234 | ------------------ 235 | 236 | int rnd_gamerand_range( rnd_gamerand_t* gamerand, int min, int max ) 237 | 238 | Returns a random integer N in the range: min <= N <= max, from the specified GameRand generator. 239 | 240 | 241 | rnd_xorshift_seed 242 | ----------------- 243 | 244 | void rnd_xorshift_seed( rnd_xorshift_t* xorshift, RND_U64 seed ) 245 | 246 | Initialize a XorShift generator with the specified seed. The generator is not valid until it's been seeded. 247 | 248 | 249 | rnd_xorshift_next 250 | ----------------- 251 | 252 | RND_U64 rnd_xorshift_next( rnd_xorshift_t* xorshift ) 253 | 254 | Returns a random number N in the range: 0 <= N <= 0xffffffffffffffff, from the specified XorShift generator. 255 | 256 | 257 | rnd_xorshift_nextf 258 | ------------------ 259 | 260 | float rnd_xorshift_nextf( rnd_xorshift_t* xorshift ) 261 | 262 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified XorShift generator. 263 | 264 | 265 | rnd_xorshift_range 266 | ------------------ 267 | 268 | int rnd_xorshift_range( rnd_xorshift_t* xorshift, int min, int max ) 269 | 270 | Returns a random integer N in the range: min <= N <= max, from the specified XorShift generator. 271 | 272 | -------------------------------------------------------------------------------- /docs/strpool.md: -------------------------------------------------------------------------------- 1 | strpool.h 2 | ========= 3 | 4 | Library: [strpool.h](../strpool.h) 5 | 6 | 7 | Example 8 | ======= 9 | 10 | ```cpp 11 | #define STRPOOL_IMPLEMENTATION 12 | #include "strpool.h" 13 | 14 | #include // for printf 15 | #include // for strlen 16 | 17 | int main( int argc, char** argv ) 18 | { 19 | (void) argc, argv; 20 | 21 | strpool_config_t conf = strpool_default_config; 22 | //conf.ignore_case = true; 23 | 24 | strpool_t pool; 25 | strpool_init( &pool, &conf ); 26 | 27 | STRPOOL_U64 str_a = strpool_inject( &pool, "This is a test string", (int) strlen( "This is a test string" ) ); 28 | STRPOOL_U64 str_b = strpool_inject( &pool, "THIS IS A TEST STRING", (int) strlen( "THIS IS A TEST STRING" ) ); 29 | 30 | printf( "%s\n", strpool_cstr( &pool, str_a ) ); 31 | printf( "%s\n", strpool_cstr( &pool, str_b ) ); 32 | printf( "%s\n", str_a == str_b ? "Strings are the same" : "Strings are different" ); 33 | 34 | strpool_term( &pool ); 35 | return 0; 36 | } 37 | ``` 38 | 39 | 40 | API Documentation 41 | ================= 42 | 43 | strpool.h is a system for string interning, where each string is stored only once. It makes comparing strings very fast, 44 | as it will just be uint64 comparison rather than looping over strings and comparing character by character. strpool.h is 45 | also optimized for fast creation of strings, and with an efficient memory allocation scheme. 46 | 47 | strpool.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use 48 | it, you just include strpool.h to get the API declarations. To get the definitions, you must include strpool.h from 49 | *one* single C or C++ file, and #define the symbol `STRPOOL_IMPLEMENTATION` before you do. 50 | 51 | 52 | Customization 53 | ------------- 54 | There are a few different things in strpool.h which are configurable by #defines. Most of the API use the `int` data 55 | type, for integer values where the exact size is not important. However, for some functions, it specifically makes use 56 | of 32 and 64 bit data types. These default to using `unsigned int` and `unsigned long long` by default, but can be 57 | redefined by #defining STRPOOL_U32 and STRPOOL_U64 respectively, before including strpool.h. This is useful if you, for 58 | example, use the types from `` in the rest of your program, and you want strpool.h to use compatible types. In 59 | this case, you would include strpool.h using the following code: 60 | 61 | #define STRPOOL_U32 uint32_t 62 | #define STRPOOL_U64 uint64_t 63 | #include "strpool.h" 64 | 65 | Note that when customizing the data types, you need to use the same definition in every place where you include 66 | strpool.h, as they affect the declarations as well as the definitions. 67 | 68 | The rest of the customizations only affect the implementation, so will only need to be defined in the file where you 69 | have the #define STRPOOL_IMPLEMENTATION. 70 | 71 | Note that if all customizations are utilized, strpool.h will include no external files whatsoever, which might be useful 72 | if you need full control over what code is being built. 73 | 74 | 75 | ### Custom memory allocators 76 | 77 | To store strings and the internal structures (entry list, hashtable etc) strpool.h needs to dodynamic allocation by 78 | calling `malloc`. Programs might want to keep track of allocations done, or use custom defined pools to allocate memory 79 | from. strpool.h allows for specifying custom memory allocation functions for `malloc` and `free`. 80 | This is done with the following code: 81 | 82 | #define STRPOOL_IMPLEMENTATION 83 | #define STRPOOL_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) ) 84 | #define STRPOOL_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) ) 85 | #include "strpool.h" 86 | 87 | where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter 88 | is an optional parameter of type `void*`. When `strpool_init` is called, you can set the `memctx` field of the `config` 89 | parameter, to a pointer to anything you like, and which will be passed through as the `ctx` parameter to every 90 | `STRPOOL_MALLOC`/`STRPOOL_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your 91 | tracking data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the 92 | right type, and access the tracking data. 93 | 94 | If no custom allocator is defined, strpool.h will default to `malloc` and `free` from the C runtime library. 95 | 96 | 97 | ### Custom assert 98 | 99 | strpool.h makes use of asserts to report usage errors and failed allocation errors. By default, it makes use of the C 100 | runtime library `assert` macro, which only executes in debug builds. However, it allows for substituting with your own 101 | assert function or macro using the following code: 102 | 103 | #define STRPOOL_IMPLEMENTATION 104 | #define STRPOOL_ASSERT( condition ) ( my_custom_assert( condition ) ) 105 | #include "strpool.h" 106 | 107 | Note that if you only want the asserts to trigger in debug builds, you must add a check for this in your custom assert. 108 | 109 | 110 | ### Custom C runtime function 111 | 112 | The library makes use of four additional functions from the C runtime library, and for full flexibility, it allows you 113 | to substitute them for your own. Here's an example: 114 | 115 | #define STRPOOL_IMPLEMENTATION 116 | #define STRPOOL_MEMSET( ptr, val, cnt ) ( my_memset_func( ptr, val, cnt ) ) 117 | #define STRPOOL_MEMCPY( dst, src, cnt ) ( my_memcpy_func( dst, src, cnt ) ) 118 | #define STRPOOL_MEMCMP( pr1, pr2, cnt ) ( my_memcmp_func( pr1, pr2, cnt ) ) 119 | #define STRPOOL_STRNICMP( s1, s2, len ) ( my_strnicmp_func( s1, s2, len ) ) 120 | #include "strpool.h" 121 | 122 | If no custom function is defined, strpool.h will default to the C runtime library equivalent. 123 | 124 | 125 | strpool_init 126 | ------------ 127 | 128 | void strpool_init( strpool_t* pool, strpool_config_t const* config ) 129 | 130 | Initializes an instance of the string pool. The `config` parameter allows for controlling the behavior of the pool 131 | instance. It contains the following fields: 132 | 133 | * memctx - pointer to user defined data which will be passed through to custom STRPOOL_MALLOC/STRPOOL_FREE calls. May 134 | be NULL. 135 | * ignore_case - set to 0 to make strings case sensitive, set to 1 to make strings case insensitive. Default is 0. 136 | * counter_bits - how many bits of the string handle to use for keeping track of handle reuse and invalidation. Default 137 | is 32. See below for details about the handle bits. 138 | * index_bits - how many bits of the string handle to use for referencing string instances. Default is 32. See below for 139 | details about the handle bits. 140 | * entry_capacity - number of string instance entries to pre-allocate space for when pool is initialized. Default 141 | is space for 4096 string entries. 142 | * block_capacity - number of string storage block entries to pre-allocate space for when pool is initialized. Default 143 | is space for 32 entries of block information - though only a single block will be pre-allocated. 144 | * block_size - size to allocate for each string storage block. A higher value might mean you often have more memory 145 | allocated than is actually being used. A lower value means you will be making allocations more often. Default 146 | is 256 kilobyte. 147 | * min_length - minimum space to allocate for each string. A higher value wastes more space, but makes it more likely 148 | that recycled storage can be re-used by subsequent requests. Default is a string length of 23 characters. 149 | 150 | The function `strpool_inject` returns a 64-bit handle. Using the settings `counter_bits`/`index_bits`, you can control 151 | how many bits of the handle is in use, and how many are used for index vs counter. For example, setting `counter_bits` 152 | to 8 and `index_bits` to 24, you will get a handle which only uses 32 bits in total, can store some 16 million different 153 | strings (2^24 -1), with a reuse counter going up to 255 before wrapping around. In this scenario, the 64-bit handle 154 | returned from strpool_inject can be safely truncated and stored in a 32-bit variable. Any combination of counter vs 155 | index bits is possible, but the number of strings which can be stored will be limited by `index_bits`. 156 | 157 | The counter bits need a more detailed description. When a string is added via `strpool_inject`, you get a handle back, 158 | which is used to reference the string. You might store this handle in various data structures. When removing a string by 159 | calling `strpool_discard`, the index part of that handle will be recycled, and re-used for future `strpool_inject`. 160 | However, when a string is discarded, the counter part of the handle will be increased, so the system knows that any 161 | handles that are still being kept around in any data structure, does no longer point to a valid string (and thus will 162 | return a NULL string pointer when queried through `strpool_cstr`). If your use case involves creating a bunch of strings 163 | and just keeping them around until the application terminates, it is fine to specify 0 for `counter_bits`, thereby 164 | effectively disabling the handle validation all together. If you have a case where strings are being repeatedly created 165 | and removed, but strings are queried very frequently, then you can specify a low number for `counter_bits` (since you 166 | can invalidate any stored handles as soon as you find out it's been invalidated). If you have a case where handles might 167 | sit inside data structures for a long period of time before you check their validity, you best specify a high value for 168 | `counter_bits`. The default value is 32 bits for index and 32 bits for counter. 169 | 170 | 171 | strpool_term 172 | ------------ 173 | 174 | void strpool_term( strpool_t* pool ) 175 | 176 | Terminates a string pool instance, releasing all memory used by it. No further calls to the strpool API are valid until 177 | the instance is reinitialized by another call to `strpool_init`. 178 | 179 | 180 | strpool_defrag 181 | -------------- 182 | 183 | void strpool_defrag( strpool_t* pool ) 184 | 185 | As strings are added to and removed from the pool, the memory blocks holding the strings may get fragmented, making them 186 | take up more allocated memory than is actually needed to store the set of strings, should they be packed tightly, 187 | `strpool_defrag` consolidates all strings into a single memory block (which might well be larger than the block size 188 | specified when the pool was initialized), and recreates the internal hash table. Any additionally allocated memory 189 | blocks will be deallocated, making the memory used by the pool as little as it can be to fit the current set of strings. 190 | All string handles remain valid after a call to `strpool_defrag`. 191 | 192 | 193 | strpool_inject 194 | -------------- 195 | 196 | STRPOOL_U64 strpool_inject( strpool_t* pool, char const* string, int length ) 197 | 198 | Adds a string to the pool, and returns a handle for the added string. If the string doesn't exist, it will be stored in 199 | an unused part of an already allocated storage block (or a new block will be allocated if there is no free space large 200 | enough to hold the string), and inserted into the internal hash table. If the string already exists, a handle to the 201 | existing string will be returned. If the `string` parameter is already pointing to a string stored in the pool, there 202 | are specific optimizations for avoiding to loop over it to calculate the hash for it, with the idea being that you 203 | should be able to use char* types when you're passing strings around, and use the string pool for storage, without too 204 | much of a performance penalty. `string` does not have to be null terminated, but when it is retrieved from the string 205 | pool, it will be. If `string` is NULL or length is 0, a handle with a value of 0 will be returned, to signify empty 206 | string. 207 | 208 | 209 | strpool_discard 210 | --------------- 211 | 212 | void strpool_discard( strpool_t* pool, STRPOOL_U64 handle ) 213 | 214 | Removes a string from the pool. Any handles held for the string will be invalid after this. Memory used for storing the 215 | string will be recycled and used for further `strpool_inject` calls. If `handle` is invalid, `strpool_discard` will do 216 | nothing. 217 | 218 | 219 | strpool_incref 220 | -------------- 221 | 222 | int strpool_incref( strpool_t* pool, STRPOOL_U64 handle ) 223 | 224 | `strpool.h` supports reference counting of strings. It is optional and not automatic, and does not automatically discard 225 | strings when the reference count reaches 0. To use reference counting, make sure to call `strpool_incref` whenever you 226 | add a string (after having called `strpool_inject`), and to call `strpool_decref` whenever you want to remove a string 227 | (but only call `strpool_discard` if reference count have reached 0). It would be advisable to write wrapper functions 228 | to ensure consistency in this, or if C++ is used, a wrapper class with constructors/destructor. `strpool_incref` returns 229 | the reference count after increasing it. If `handle` is invalid, `strpool_incref` will do nothing, and return 0. 230 | 231 | 232 | strpool_decref 233 | -------------- 234 | 235 | int strpool_decref( strpool_t* pool, STRPOOL_U64 handle ) 236 | 237 | Decreases the reference count of the specified string by 1, returning the reference count after decrementing. If the 238 | reference count is less than 1, an assert will be triggered. If `handle` is invalid, `strpool_decref` will do nothing, 239 | and return 0. 240 | 241 | 242 | strpool_getref 243 | -------------- 244 | 245 | int strpool_getref( strpool_t* pool, STRPOOL_U64 handle ) 246 | 247 | Returns the current reference count for the specified string. If `handle` is invalid, `strpool_getref` will do nothing, 248 | and return 0. 249 | 250 | 251 | strpool_isvalid 252 | --------------- 253 | 254 | int strpool_isvalid( strpool_t const* pool, STRPOOL_U64 handle ) 255 | 256 | Returns 1 if the specified string handle is valid, and 0 if it is not. 257 | 258 | 259 | strpool_cstr 260 | ------------ 261 | 262 | char const* strpool_cstr( strpool_t const* pool, STRPOOL_U64 handle ) 263 | 264 | Returns the zero-terminated C string for the specified string handle. The resulting string pointer is only valid as long 265 | as no call is made to `strpool_init`, `strpool_term`, `strpool_defrag` or `strpool_discard`. It is therefor recommended 266 | to never store the C string pointer, and always grab it fresh by another call to `strpool_cstr` when it is needed. 267 | `strpool_cstr` is a very fast function to call - it does little more than an array lookup. If `handle` is invalid, 268 | `strpool_cstr` returns NULL. 269 | 270 | 271 | strpool_length 272 | -------------- 273 | 274 | int strpool_length( strpool_t const* pool, STRPOOL_U64 handle ) 275 | 276 | Returns the length, in characters, of the specified string. The resulting value is only valid as long as no call is made 277 | to `strpool_init`, `strpool_term`, `strpool_defrag` or `strpool_discard`. It is therefor recommended to never store the 278 | value, and always grab it fresh by another call to `strpool_length` when it is needed. `strpool_length` is a very fast 279 | function to call - it does little more than an array lookup. If `handle` is invalid, `strpool_length` returns 0. 280 | 281 | 282 | strpool_collate 283 | --------------- 284 | 285 | char* strpool_collate( strpool_t const* pool, int* count ) 286 | 287 | Returns a list of all the strings currently stored in the string pool, and stores the number of strings in the int 288 | variable pointed to by `count`. If there are no strings in the string pool, `strpool_collate` returns NULL. The pointer 289 | returned points to the first character of the first string. Strings are zero-terminated, and immediately after the 290 | termination character, comes the first character of the next string. 291 | 292 | 293 | strpool_free_collated 294 | --------------------- 295 | 296 | void strpool_free_collated( strpool_t const* pool, char* collated_ptr ) 297 | 298 | Releases the memory returned by `strpool_collate`. 299 | 300 | -------------------------------------------------------------------------------- /docs/thread.md: -------------------------------------------------------------------------------- 1 | thread.h 2 | ======== 3 | 4 | Library: [thread.h](../thread.h) 5 | 6 | 7 | Example 8 | ======= 9 | 10 | Here's a basic sample program which starts a second thread which just waits and prints a message. 11 | 12 | ```cpp 13 | #define THREAD_IMPLEMENTATION 14 | #include "thread.h" 15 | 16 | #include // for printf 17 | 18 | int thread_proc( void* user_data) 19 | { 20 | thread_timer_t timer; 21 | thread_timer_init( &timer ); 22 | 23 | int count = 0; 24 | thread_atomic_int_t* exit_flag = (thread_atomic_int_t*) user_data; 25 | while( thread_atomic_int_load( exit_flag ) == 0 ) 26 | { 27 | printf( "Thread... " ); 28 | thread_timer_wait( &timer, 1000000000 ); // sleep for a second 29 | ++count; 30 | } 31 | 32 | thread_timer_term( &timer ); 33 | printf( "Done\n" ); 34 | return count; 35 | } 36 | 37 | int main( int argc, char** argv ) 38 | { 39 | (void) argc, argv; 40 | 41 | thread_atomic_int_t exit_flag; 42 | thread_atomic_int_store( &exit_flag, 0 ); 43 | 44 | thread_ptr_t thread = thread_create( thread_proc, &exit_flag, "Example thread", THREAD_STACK_SIZE_DEFAULT ); 45 | 46 | thread_timer_t timer; 47 | thread_timer_init( &timer ); 48 | for( int i = 0; i < 5; ++i ) 49 | { 50 | printf( "Main... " ); 51 | thread_timer_wait( &timer, 2000000000 ); // sleep for two seconds 52 | } 53 | thread_timer_term( &timer ); 54 | 55 | thread_atomic_int_store( &exit_flag, 1 ); // signal thread to exit 56 | int retval = thread_join( thread ); 57 | 58 | printf( "Count: %d\n", retval ); 59 | 60 | thread_destroy( thread ); 61 | return retval; 62 | } 63 | ``` 64 | 65 | 66 | API Documentation 67 | ================= 68 | 69 | thread.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it, 70 | you just include thread.h to get the API declarations. To get the definitions, you must include thread.h from *one* 71 | single C or C++ file, and #define the symbol `THREAD_IMPLEMENTATION` before you do. 72 | 73 | 74 | Customization 75 | ------------- 76 | thread.h allows for specifying the exact type of 64-bit unsigned integer to be used in its API. By default, it is 77 | defined as `unsigned long long`, but as this is not a standard type on all compilers, you can redefine it by #defining 78 | THREAD_U64 before including thread.h. This is useful if you, for example, use the types from `` in the rest of 79 | your program, and you want thread.h to use compatible types. In this case, you would include thread.h using the 80 | following code: 81 | 82 | #define THREAD_U64 uint64_t 83 | #include "thread.h" 84 | 85 | Note that when customizing this data type, you need to use the same definition in every place where you include 86 | thread.h, as it affect the declarations as well as the definitions. 87 | 88 | 89 | thread_current_thread_id 90 | ------------------------ 91 | 92 | thread_id_t thread_current_thread_id( void ) 93 | 94 | Returns a unique identifier for the calling thread. After the thread terminates, the id might be reused for new threads. 95 | 96 | 97 | thread_yield 98 | ------------ 99 | 100 | void thread_yield( void ) 101 | 102 | Makes the calling thread yield execution to another thread. The operating system controls which thread is switched to. 103 | 104 | 105 | thread_set_high_priority 106 | ------------------------ 107 | 108 | void thread_set_high_priority( void ) 109 | 110 | When created, threads are set to run at normal priority. In some rare cases, such as a sound buffer update loop, it can 111 | be necessary to have one thread of your application run on a higher priority than the rest. Calling 112 | `thread_set_high_priority` will raise the priority of the calling thread, giving it a chance to be run more often. 113 | Do not increase the priority of a thread unless you absolutely have to, as it can negatively affect performance if used 114 | without care. 115 | 116 | 117 | thread_exit 118 | ----------- 119 | 120 | void thread_exit( int return_code ) 121 | 122 | Exits the calling thread, as if you had done `return return_code;` from the main body of the thread function. 123 | 124 | 125 | thread_create 126 | ------------- 127 | 128 | thread_ptr_t thread_create( int (*thread_proc)( void* ), void* user_data, char const* name, int stack_size ) 129 | 130 | Creates a new thread running the `thread_proc` function, passing the `user_data` through to it. The thread will be 131 | given the debug name given in the `name` parameter, if supported on the platform, and it will have the stack size 132 | specified in the `stack_size` parameter. To get the operating system default stack size, use the defined constant 133 | `THREAD_STACK_SIZE_DEFAULT`. When returning from the thread_proc function, the value you return can be received in 134 | another thread by calling thread_join. `thread_create` returns a pointer to the thread instance, which can be used 135 | as a parameter to the functions `thread_destroy` and `thread_join`. 136 | 137 | 138 | thread_destroy 139 | -------------- 140 | 141 | void thread_destroy( thread_ptr_t thread ) 142 | 143 | Destroys a thread that was created by calling `thread_create`. Make sure the thread has exited before you attempt to 144 | destroy it. This can be accomplished by calling `thread_join`. It is not possible for force termination of a thread by 145 | calling `thread_destroy`. 146 | 147 | 148 | thread_join 149 | ----------- 150 | 151 | int thread_join( thread_ptr_t thread ) 152 | 153 | Waits for the specified thread to exit. Returns the value which the thread returned when exiting. 154 | 155 | 156 | thread_mutex_init 157 | ----------------- 158 | 159 | void thread_mutex_init( thread_mutex_t* mutex ) 160 | 161 | Initializes the specified mutex instance, preparing it for use. A mutex can be used to lock sections of code, such that 162 | it can only be run by one thread at a time. 163 | 164 | 165 | thread_mutex_term 166 | ----------------- 167 | 168 | void thread_mutex_term( thread_mutex_t* mutex ) 169 | 170 | Terminates the specified mutex instance, releasing any system resources held by it. 171 | 172 | 173 | thread_mutex_lock 174 | ----------------- 175 | 176 | void thread_mutex_lock( thread_mutex_t* mutex ) 177 | 178 | Takes an exclusive lock on a mutex. If the lock is already taken by another thread, `thread_mutex_lock` will yield the 179 | calling thread and wait for the lock to become available before returning. The mutex must be initialized by calling 180 | `thread_mutex_init` before it can be locked. 181 | 182 | 183 | thread_mutex_unlock 184 | ------------------- 185 | 186 | void thread_mutex_unlock( thread_mutex_t* mutex ) 187 | 188 | Releases a lock taken by calling `thread_mutex_lock`. 189 | 190 | 191 | thread_signal_init 192 | ------------------ 193 | 194 | void thread_signal_init( thread_signal_t* signal ) 195 | 196 | Initializes the specified signal instance, preparing it for use. A signal works like a flag, which can be waited on by 197 | one thread, until it is raised from another thread. 198 | 199 | 200 | thread_signal_term 201 | ------------------ 202 | 203 | void thread_signal_term( thread_signal_t* signal ) 204 | 205 | Terminates the specified signal instance, releasing any system resources held by it. 206 | 207 | 208 | thread_signal_raise 209 | ------------------- 210 | 211 | void thread_signal_raise( thread_signal_t* signal ) 212 | 213 | Raise the specified signal. Other threads waiting for the signal will proceed. 214 | 215 | 216 | thread_signal_wait 217 | ------------------ 218 | 219 | int thread_signal_wait( thread_signal_t* signal, int timeout_ms ) 220 | 221 | Waits for a signal to be raised, or until `timeout_ms` milliseconds have passed. If the wait timed out, a value of 0 is 222 | returned, otherwise a non-zero value is returned. If the `timeout_ms` parameter is THREAD_SIGNAL_WAIT_INFINITE, 223 | `thread_signal_wait` waits indefinitely. 224 | 225 | 226 | thread_atomic_int_load 227 | ---------------------- 228 | 229 | int thread_atomic_int_load( thread_atomic_int_t* atomic ) 230 | 231 | Returns the value of `atomic` as an atomic operation. 232 | 233 | 234 | thread_atomic_int_store 235 | ----------------------- 236 | 237 | void thread_atomic_int_store( thread_atomic_int_t* atomic, int desired ) 238 | 239 | Sets the value of `atomic` as an atomic operation. 240 | 241 | 242 | thread_atomic_int_inc 243 | --------------------- 244 | 245 | int thread_atomic_int_inc( thread_atomic_int_t* atomic ) 246 | 247 | Increments the value of `atomic` by one, as an atomic operation. Returns the value `atomic` had before the operation. 248 | 249 | 250 | thread_atomic_int_dec 251 | --------------------- 252 | 253 | int thread_atomic_int_dec( thread_atomic_int_t* atomic ) 254 | 255 | Decrements the value of `atomic` by one, as an atomic operation. Returns the value `atomic` had before the operation. 256 | 257 | 258 | thread_atomic_int_add 259 | --------------------- 260 | 261 | int thread_atomic_int_add( thread_atomic_int_t* atomic, int value ) 262 | 263 | Adds the specified value to `atomic`, as an atomic operation. Returns the value `atomic` had before the operation. 264 | 265 | 266 | thread_atomic_int_sub 267 | --------------------- 268 | 269 | int thread_atomic_int_sub( thread_atomic_int_t* atomic, int value ) 270 | 271 | Subtracts the specified value to `atomic`, as an atomic operation. Returns the value `atomic` had before the operation. 272 | 273 | 274 | thread_atomic_int_swap 275 | ---------------------- 276 | 277 | int thread_atomic_int_swap( thread_atomic_int_t* atomic, int desired ) 278 | 279 | Sets the value of `atomic` as an atomic operation. Returns the value `atomic` had before the operation. 280 | 281 | 282 | thread_atomic_int_compare_and_swap 283 | ---------------------------------- 284 | 285 | int thread_atomic_int_compare_and_swap( thread_atomic_int_t* atomic, int expected, int desired ) 286 | 287 | Compares the value of `atomic` to the value of `expected`, and if they match, sets the vale of `atomic` to `desired`, 288 | all as an atomic operation. Returns the value `atomic` had before the operation. 289 | 290 | 291 | thread_atomic_ptr_load 292 | ---------------------- 293 | 294 | void* thread_atomic_ptr_load( thread_atomic_ptr_t* atomic ) 295 | 296 | Returns the value of `atomic` as an atomic operation. 297 | 298 | 299 | thread_atomic_ptr_store 300 | ----------------------- 301 | 302 | void thread_atomic_ptr_store( thread_atomic_ptr_t* atomic, void* desired ) 303 | 304 | Sets the value of `atomic` as an atomic operation. 305 | 306 | 307 | thread_atomic_ptr_swap 308 | ---------------------- 309 | 310 | void* thread_atomic_ptr_swap( thread_atomic_ptr_t* atomic, void* desired ) 311 | 312 | Sets the value of `atomic` as an atomic operation. Returns the value `atomic` had before the operation. 313 | 314 | 315 | thread_atomic_ptr_compare_and_swap 316 | ---------------------------------- 317 | 318 | void* thread_atomic_ptr_compare_and_swap( thread_atomic_ptr_t* atomic, void* expected, void* desired ) 319 | 320 | Compares the value of `atomic` to the value of `expected`, and if they match, sets the vale of `atomic` to `desired`, 321 | all as an atomic operation. Returns the value `atomic` had before the operation. 322 | 323 | 324 | thread_timer_init 325 | ----------------- 326 | 327 | void thread_timer_init( thread_timer_t* timer ) 328 | 329 | Initializes the specified timer instance, preparing it for use. A timer can be used to sleep a thread for a high 330 | precision duration. 331 | 332 | 333 | thread_timer_term 334 | ----------------- 335 | 336 | void thread_timer_term( thread_timer_t* timer ) 337 | 338 | Terminates the specified timer instance, releasing any system resources held by it. 339 | 340 | 341 | thread_timer_wait 342 | ----------------- 343 | 344 | void thread_timer_wait( thread_timer_t* timer, THREAD_U64 nanoseconds ) 345 | 346 | Waits until `nanoseconds` amount of time have passed, before returning. 347 | 348 | 349 | thread_tls_create 350 | ----------------- 351 | 352 | thread_tls_t thread_tls_create( void ) 353 | 354 | Creates a thread local storage (TLS) index. Once created, each thread has its own value for that TLS index, which can 355 | be set or retrieved individually. 356 | 357 | 358 | thread_tls_destroy 359 | ------------------ 360 | 361 | void thread_tls_destroy( thread_tls_t tls ) 362 | 363 | Destroys the specified TLS index. No further calls to `thread_tls_set` or `thread_tls_get` are valid after this. 364 | 365 | 366 | thread_tls_set 367 | -------------- 368 | 369 | void thread_tls_set( thread_tls_t tls, void* value ) 370 | 371 | Stores a value in the calling thread's slot for the specified TLS index. Each thread has its own value for each TLS 372 | index. 373 | 374 | 375 | thread_tls_get 376 | -------------- 377 | 378 | void* thread_tls_get( thread_tls_t tls ) 379 | 380 | Retrieves the value from the calling thread's slot for the specified TLS index. Each thread has its own value for each 381 | TLS index. 382 | 383 | 384 | thread_queue_init 385 | ----------------- 386 | 387 | void thread_queue_init( thread_queue_t* queue, int size, void** values, int count ) 388 | 389 | Initializes the specified queue instance, preparing it for use. The queue is a lock-free (but not wait-free) 390 | single-producer/single-consumer queue - it will not acquire any locks as long as there is space for adding or items to 391 | be consume, but will lock and wait when there is not. The `size` parameter specifies the number of elements in the 392 | queue. The `values` parameter is an array of queue slots (`size` elements in length), each being of type `void*`. If 393 | the queue is initially empty, the `count` parameter should be 0, otherwise it indicates the number of entires, from the 394 | start of the `values` array, that the queue is initialized with. The `values` array is not copied, and must remain valid 395 | until `thread_queue_term` is called. 396 | 397 | 398 | thread_queue_term 399 | ----------------- 400 | 401 | void thread_queue_term( thread_queue_t* queue ) 402 | 403 | Terminates the specified queue instance, releasing any system resources held by it. 404 | 405 | 406 | thread_queue_produce 407 | -------------------- 408 | 409 | int thread_queue_produce( thread_queue_t* queue, void* value, int timeout_ms ) 410 | 411 | Adds an element to a single-producer/single-consumer queue. If there is space in the queue to add another element, no 412 | lock will be taken. If the queue is full, calling thread will sleep until an element is consumed from another thread, 413 | before adding the element, or until `timeout_ms` milliseconds have passed. If the wait timed out, a value of 0 is 414 | returned, otherwise a non-zero value is returned. If the `timeout_ms` parameter is THREAD_QUEUE_WAIT_INFINITE, 415 | `thread_queue_produce` waits indefinitely. 416 | 417 | 418 | thread_queue_consume 419 | -------------------- 420 | 421 | void* thread_queue_consume( thread_queue_t* queue, int timeout_ms ) 422 | 423 | Removes an element from a single-producer/single-consumer queue. If the queue contains at least one element, no lock 424 | will be taken. If the queue is empty, the calling thread will sleep until an element is added from another thread, or 425 | until `timeout_ms` milliseconds have passed. If the wait timed out, a value of NULL is returned, otherwise 426 | `thread_queue_consume` returns the value that was removed from the queue. If the `timeout_ms` parameter is 427 | THREAD_QUEUE_WAIT_INFINITE, `thread_queue_consume` waits indefinitely. 428 | 429 | 430 | thread_queue_count 431 | ------------------ 432 | 433 | int thread_queue_count( thread_queue_t* queue ) 434 | 435 | Returns the number of elements currently held in a single-producer/single-consumer queue. Be aware that by the time you 436 | get the count, it might have changed by another thread calling consume or produce, so use with care. 437 | 438 | -------------------------------------------------------------------------------- /frametimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | frametimer.h - v0.1 - Framerate timer functionality. 7 | 8 | Do this: 9 | #define FRAMETIMER_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef frametimer_h 14 | #define frametimer_h 15 | 16 | typedef struct frametimer_t frametimer_t; 17 | 18 | frametimer_t* frametimer_create( void* memxtx ); 19 | 20 | void frametimer_destroy( frametimer_t* frametimer ); 21 | 22 | void frametimer_lock_rate( frametimer_t* frametimer, int fps ); 23 | 24 | float frametimer_update( frametimer_t* frametimer ); 25 | 26 | float frametimer_delta_time( frametimer_t* frametimer ); 27 | 28 | int frametimer_frame_counter( frametimer_t* frametimer ); 29 | 30 | #endif /* frametimer_h */ 31 | 32 | /* 33 | ---------------------- 34 | IMPLEMENTATION 35 | ---------------------- 36 | */ 37 | 38 | #ifdef FRAMETIMER_IMPLEMENTATION 39 | #undef FRAMETIMER_IMPLEMENTATION 40 | 41 | #define _CRT_NONSTDC_NO_DEPRECATE 42 | #ifndef _CRT_SECURE_NO_WARNINGS 43 | #define _CRT_SECURE_NO_WARNINGS 44 | #endif 45 | #ifdef _WIN32 46 | #if !defined( _WIN32_WINNT ) || _WIN32_WINNT < 0x0501 47 | #undef _WIN32_WINNT 48 | #define _WIN32_WINNT 0x0501 // requires Windows XP minimum 49 | #endif 50 | // 0x0400=Windows NT 4.0, 0x0500=Windows 2000, 0x0501=Windows XP, 0x0502=Windows Server 2003, 0x0600=Windows Vista, 51 | // 0x0601=Windows 7, 0x0602=Windows 8, 0x0603=Windows 8.1, 0x0A00=Windows 10, 52 | #define _WINSOCKAPI_ 53 | #pragma warning( push ) 54 | #pragma warning( disable: 4619 ) 55 | #pragma warning( disable: 4668 ) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 56 | #pragma warning( disable: 4768 ) // __declspec attributes before linkage specification are ignored 57 | #pragma warning( disable: 4255 ) // 'function' : no function prototype given: converting '()' to '(void)' 58 | #include 59 | #pragma warning( pop ) 60 | #ifndef __TINYC__ 61 | #pragma comment(lib, "winmm.lib") 62 | #else 63 | typedef struct timecaps_tag { UINT wPeriodMin; UINT wPeriodMax; } TIMECAPS, *PTIMECAPS, NEAR *NPTIMECAPS, FAR *LPTIMECAPS; 64 | typedef UINT MMRESULT; 65 | #define TIMERR_NOERROR (0) 66 | static MMRESULT (*timeGetDevCaps)( LPTIMECAPS ptc, UINT cbtc ); 67 | static MMRESULT (*timeBeginPeriod)( UINT uPeriod ); 68 | static MMRESULT (*timeEndPeriod)( UINT uPeriod ); 69 | #endif 70 | #elif defined( __APPLE__ ) 71 | #include 72 | #elif defined( __wasm__ ) 73 | #define WA_CORO_IMPLEMENT_NANOSLEEP 74 | #include 75 | #else 76 | #include 77 | #endif 78 | 79 | #ifndef FRAMETIMER_MALLOC 80 | #include 81 | #if defined(__cplusplus) 82 | #define FRAMETIMER_MALLOC( ctx, size ) ( ::malloc( size ) ) 83 | #define FRAMETIMER_FREE( ctx, ptr ) ( ::free( ptr ) ) 84 | #else 85 | #define FRAMETIMER_MALLOC( ctx, size ) ( malloc( size ) ) 86 | #define FRAMETIMER_FREE( ctx, ptr ) ( free( ptr ) ) 87 | #endif 88 | #endif 89 | 90 | #ifndef FRAMETIMER_U64 91 | #define FRAMETIMER_U64 unsigned long long 92 | #endif 93 | 94 | struct frametimer_t 95 | { 96 | FRAMETIMER_U64 clock_freq; 97 | FRAMETIMER_U64 prev_clock; 98 | void* memctx; 99 | float delta_time; 100 | int initialized; 101 | int frame_counter; 102 | int frame_rate_lock; 103 | #ifdef _WIN32 104 | HANDLE waitable_timer; 105 | #endif 106 | }; 107 | 108 | 109 | frametimer_t* frametimer_create( void* memctx ) 110 | { 111 | frametimer_t* frametimer = (frametimer_t*) FRAMETIMER_MALLOC( memctx, sizeof( frametimer_t ) ); 112 | #ifdef _WIN32 113 | #ifdef __TINYC__ 114 | HMODULE winmm = LoadLibrary( "winmm" ); 115 | timeGetDevCaps = GetProcAddress( winmm, "timeGetDevCaps"); 116 | timeBeginPeriod = GetProcAddress( winmm, "timeBeginPeriod"); 117 | timeEndPeriod = GetProcAddress( winmm, "timeEndPeriod"); 118 | #endif 119 | TIMECAPS tc; 120 | if( timeGetDevCaps( &tc, sizeof( TIMECAPS ) ) == TIMERR_NOERROR ) 121 | timeBeginPeriod( tc.wPeriodMin ); 122 | frametimer->waitable_timer = CreateWaitableTimer(NULL, TRUE, NULL); 123 | #endif 124 | 125 | frametimer->memctx = memctx; 126 | frametimer->initialized = 0; 127 | 128 | #ifdef _WIN32 129 | LARGE_INTEGER f; 130 | QueryPerformanceFrequency( &f ); 131 | frametimer->clock_freq = (FRAMETIMER_U64) f.QuadPart; 132 | #else 133 | frametimer->clock_freq = 1000000000ull; 134 | #endif 135 | 136 | frametimer->prev_clock = 0; 137 | frametimer->delta_time = 0.0f; 138 | frametimer->frame_counter = 0; 139 | frametimer->frame_rate_lock = 0; 140 | return frametimer; 141 | } 142 | 143 | 144 | void frametimer_destroy( frametimer_t* frametimer ) 145 | { 146 | #ifdef _WIN32 147 | CloseHandle( frametimer->waitable_timer ); 148 | TIMECAPS tc; 149 | if( timeGetDevCaps( &tc, sizeof( TIMECAPS ) ) == TIMERR_NOERROR ) 150 | timeEndPeriod( tc.wPeriodMin ); 151 | #endif 152 | FRAMETIMER_FREE( frametimer->memctx, frametimer ); 153 | } 154 | 155 | 156 | void frametimer_lock_rate( frametimer_t* frametimer, int fps ) 157 | { 158 | frametimer->frame_rate_lock = ( fps > 0 && fps < 5 ) ? 5 : fps < 0 ? 0 : fps; 159 | } 160 | 161 | 162 | float frametimer_update( frametimer_t* frametimer ) 163 | { 164 | if( !frametimer->initialized ) 165 | { 166 | #ifdef _WIN32 167 | LARGE_INTEGER c; 168 | QueryPerformanceCounter( &c ); 169 | frametimer->prev_clock = (FRAMETIMER_U64) c.QuadPart; 170 | #elif defined( __APPLE__ ) 171 | frametimer->prev_clock = clock_gettime_nsec_np( CLOCK_UPTIME_RAW ); 172 | #else 173 | struct timespec t; 174 | clock_gettime( CLOCK_MONOTONIC_RAW, &t ); 175 | frametimer->prev_clock = (FRAMETIMER_U64)t.tv_sec; 176 | frametimer->prev_clock *= 1000000000ull; 177 | frametimer->prev_clock += (FRAMETIMER_U64)t.tv_nsec; 178 | #endif 179 | frametimer->initialized = 1; 180 | } 181 | 182 | ++frametimer->frame_counter; 183 | 184 | 185 | FRAMETIMER_U64 curr_clock = 0ULL; 186 | #ifdef _WIN32 187 | LARGE_INTEGER c; 188 | QueryPerformanceCounter( &c ); 189 | curr_clock = (FRAMETIMER_U64) c.QuadPart; 190 | #elif defined( __APPLE__ ) 191 | curr_clock = (FRAMETIMER_U64) clock_gettime_nsec_np( CLOCK_UPTIME_RAW ); 192 | #else 193 | struct timespec t; 194 | clock_gettime( CLOCK_MONOTONIC_RAW, &t ); 195 | curr_clock = (FRAMETIMER_U64)t.tv_sec; 196 | curr_clock *= 1000000000ull; 197 | curr_clock += (FRAMETIMER_U64)t.tv_nsec; 198 | #endif 199 | 200 | if( frametimer->frame_rate_lock > 0 ) 201 | { 202 | FRAMETIMER_U64 delta = 0ULL; 203 | if( curr_clock > frametimer->prev_clock ) 204 | delta = curr_clock - frametimer->prev_clock - 1ULL; 205 | if( delta < frametimer->clock_freq / frametimer->frame_rate_lock ) 206 | { 207 | FRAMETIMER_U64 wait = ( frametimer->clock_freq / frametimer->frame_rate_lock ) - delta; 208 | #ifdef _WIN32 209 | if( wait > 0 ) 210 | { 211 | LARGE_INTEGER due_time; 212 | due_time.QuadPart = - (LONGLONG) ( ( 10000000ULL * wait ) / frametimer->clock_freq ) ; 213 | 214 | SetWaitableTimer( frametimer->waitable_timer, &due_time, 0, 0, 0, FALSE ); 215 | WaitForSingleObject( frametimer->waitable_timer, 200 ); // wait long enough for timer to trigger ( 200ms == 5fps ) 216 | CancelWaitableTimer( frametimer->waitable_timer ); // in case we timed out 217 | } 218 | #else 219 | struct timespec t = { 0, 0 }; 220 | t.tv_nsec = wait; 221 | while( t.tv_nsec > 0 ) 222 | { 223 | struct timespec r = { 0, 0 }; 224 | if( nanosleep( &t, &r ) >= 0 ) break; 225 | t = r; 226 | } 227 | #endif 228 | curr_clock += wait; 229 | } 230 | } 231 | 232 | FRAMETIMER_U64 delta_clock = 0ULL; 233 | if( curr_clock > frametimer->prev_clock ) delta_clock = curr_clock - frametimer->prev_clock; 234 | 235 | // Cap delta time if it is too high (running at less than 5 fps ) or things will jump 236 | // like crazy on occasional long stalls. 237 | if( delta_clock > frametimer->clock_freq / 5ULL ) delta_clock = frametimer->clock_freq / 5ULL; // Cap to 5 fps 238 | 239 | float delta_time = (float) ( ( (double) delta_clock ) / ( (double) frametimer->clock_freq ) ); 240 | 241 | frametimer->delta_time = delta_time; 242 | frametimer->prev_clock = curr_clock; 243 | 244 | return delta_time; 245 | } 246 | 247 | 248 | float frametimer_delta_time( frametimer_t* frametimer ) 249 | { 250 | return frametimer->delta_time; 251 | } 252 | 253 | 254 | int frametimer_frame_counter( frametimer_t* frametimer ) 255 | { 256 | return frametimer->frame_counter; 257 | } 258 | 259 | 260 | #endif /* FRAMETIMER_IMPLEMENTATION */ 261 | 262 | 263 | /* 264 | ------------------------------------------------------------------------------ 265 | 266 | This software is available under 2 licenses - you may choose the one you like. 267 | 268 | ------------------------------------------------------------------------------ 269 | 270 | ALTERNATIVE A - MIT License 271 | 272 | Copyright (c) 2015 Mattias Gustavsson 273 | 274 | Permission is hereby granted, free of charge, to any person obtaining a copy of 275 | this software and associated documentation files (the "Software"), to deal in 276 | the Software without restriction, including without limitation the rights to 277 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 278 | of the Software, and to permit persons to whom the Software is furnished to do 279 | so, subject to the following conditions: 280 | 281 | The above copyright notice and this permission notice shall be included in all 282 | copies or substantial portions of the Software. 283 | 284 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 285 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 286 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 287 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 288 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 289 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 290 | SOFTWARE. 291 | 292 | ------------------------------------------------------------------------------ 293 | 294 | ALTERNATIVE B - Public Domain (www.unlicense.org) 295 | 296 | This is free and unencumbered software released into the public domain. 297 | 298 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 299 | software, either in source code form or as a compiled binary, for any purpose, 300 | commercial or non-commercial, and by any means. 301 | 302 | In jurisdictions that recognize copyright laws, the author or authors of this 303 | software dedicate any and all copyright interest in the software to the public 304 | domain. We make this dedication for the benefit of the public at large and to 305 | the detriment of our heirs and successors. We intend this dedication to be an 306 | overt act of relinquishment in perpetuity of all present and future rights to 307 | this software under copyright law. 308 | 309 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 310 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 311 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 312 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 313 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 314 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 315 | 316 | ------------------------------------------------------------------------------ 317 | */ 318 | -------------------------------------------------------------------------------- /hoedown.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattiasgustavsson/libs/d59f972d3287550d2f215d8b4dc8e9ce8b049512/hoedown.h -------------------------------------------------------------------------------- /img.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | img.h - v0.1 - Image processing functions for C/C++. 7 | 8 | Do this: 9 | #define IMG_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef img_h 14 | #define img_h 15 | 16 | #ifndef IMG_U32 17 | #define IMG_U32 unsigned int 18 | #endif 19 | 20 | 21 | typedef struct img_rgba_t { 22 | float r; 23 | float g; 24 | float b; 25 | float a; 26 | } img_rgba_t; 27 | 28 | typedef struct img_t { 29 | int width; 30 | int height; 31 | img_rgba_t* pixels; 32 | } img_t; 33 | 34 | typedef struct img_hsva_t { 35 | float h; 36 | float s; 37 | float v; 38 | float a; 39 | } img_hsva_t; 40 | 41 | img_t img_create( int width, int height ); 42 | img_t img_from_abgr32( IMG_U32* abgr, int width, int height ); 43 | void img_free( img_t* img ); 44 | 45 | void img_to_argb32( img_t* img, IMG_U32* abgr ); 46 | img_rgba_t img_sample_clamp( img_t* img, float u, float v ); 47 | 48 | img_rgba_t img_rgba_lerp( img_rgba_t a, img_rgba_t b, float s ); 49 | img_hsva_t img_rgba_to_hsva( img_rgba_t rgb ); 50 | img_rgba_t img_hsva_to_rgba( img_hsva_t hsv ); 51 | 52 | void img_adjust_brightness( img_t* img, float value ); 53 | void img_adjust_contrast( img_t* img, float value ); 54 | void img_adjust_saturation( img_t* img, float value ); 55 | void img_sharpen( img_t* img, float radius, float blend ); 56 | 57 | 58 | #endif /* img_h */ 59 | 60 | /* 61 | ---------------------- 62 | IMPLEMENTATION 63 | ---------------------- 64 | */ 65 | 66 | #ifdef IMG_IMPLEMENTATION 67 | #undef IMG_IMPLEMENTATION 68 | 69 | #define _CRT_NONSTDC_NO_DEPRECATE 70 | #define _CRT_SECURE_NO_WARNINGS 71 | #include 72 | 73 | 74 | #if !defined( IMG_POW ) || !defined( IMG_FLOOR ) 75 | #define _CRT_NONSTDC_NO_DEPRECATE 76 | #define _CRT_SECURE_NO_WARNINGS 77 | #pragma warning( push ) 78 | #pragma warning( disable: 4668 ) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 79 | #include 80 | #pragma warning( pop ) 81 | #endif 82 | 83 | 84 | #ifndef IMG_POW 85 | #ifdef __TINYC__ 86 | #define IMG_POW( x, y ) ( (float) pow( (double) x, (double) y ) ) 87 | #else 88 | #define IMG_POW( x, y ) powf( x, y ) 89 | #endif 90 | #endif 91 | 92 | #ifndef IMG_FLOOR 93 | #ifdef __TINYC__ 94 | #define IMG_FLOOR( x ) ( (float) floor( (double) x ) ) 95 | #else 96 | #define IMG_FLOOR( x ) floorf( x ) 97 | #endif 98 | #endif 99 | 100 | 101 | img_t img_create( int width, int height ) { 102 | img_t img; 103 | img.width = width; 104 | img.height = height; 105 | img.pixels = (img_rgba_t*) malloc( sizeof( img_rgba_t ) * width * height ); 106 | memset( img.pixels, 0, sizeof( img_rgba_t ) * width * height ); 107 | return img; 108 | } 109 | 110 | 111 | img_t img_from_abgr32( IMG_U32* abgr, int width, int height ) { 112 | img_t img; 113 | img.width = width; 114 | img.height = height; 115 | img.pixels = (img_rgba_t*) malloc( sizeof( img_rgba_t ) * width * height ); 116 | for( int i = 0; i < width * height; ++i ) { 117 | IMG_U32 p = abgr[ i ]; 118 | IMG_U32 b = ( p ) & 0xff; 119 | IMG_U32 g = ( p >> 8 ) & 0xff; 120 | IMG_U32 r = ( p >> 16 ) & 0xff; 121 | IMG_U32 a = ( p >> 24 ) & 0xff; 122 | img_rgba_t* f = &img.pixels[ i ]; 123 | f->r = ( (float) r ) / 255.0f; 124 | f->g = ( (float) g ) / 255.0f; 125 | f->b = ( (float) b ) / 255.0f; 126 | f->a = ( (float) a ) / 255.0f; 127 | } 128 | return img; 129 | } 130 | 131 | 132 | void img_free( img_t* img ) { 133 | free( img->pixels ); 134 | img->pixels = NULL; 135 | } 136 | 137 | 138 | float img_clamp( float x, float low, float high ) { 139 | return x < low ? low : x > high ? high : x; 140 | } 141 | 142 | 143 | void img_to_argb32( img_t* img, IMG_U32* abgr ) { 144 | for( int i = 0; i < img->width * img->height; ++i ) { 145 | img_rgba_t p = img->pixels[ i ]; 146 | p.r = img_clamp( p.r, 0.0f, 1.0f ); 147 | p.g = img_clamp( p.g, 0.0f, 1.0f ); 148 | p.b = img_clamp( p.b, 0.0f, 1.0f ); 149 | p.a = img_clamp( p.a, 0.0f, 1.0f ); 150 | IMG_U32 r = (IMG_U32)( p.r * 256.0f ); 151 | IMG_U32 g = (IMG_U32)( p.g * 256.0f ); 152 | IMG_U32 b = (IMG_U32)( p.b * 256.0f ); 153 | IMG_U32 a = (IMG_U32)( p.a * 256.0f ); 154 | r = r > 255 ? 255 : r; 155 | g = g > 255 ? 255 : g; 156 | b = b > 255 ? 255 : b; 157 | a = a > 255 ? 255 : a; 158 | abgr[ i ] = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | ( b ); 159 | } 160 | } 161 | 162 | 163 | 164 | img_rgba_t img_rgba_lerp( img_rgba_t a, img_rgba_t b, float s ) { 165 | img_rgba_t c; 166 | c.r = a.r + ( b.r - a.r ) * s; 167 | c.g = a.g + ( b.g - a.g ) * s; 168 | c.b = a.b + ( b.b - a.b ) * s; 169 | c.a = a.a + ( b.a - a.a ) * s; 170 | return c; 171 | } 172 | 173 | 174 | img_rgba_t img_sample_clamp( img_t* img, float u, float v ) { 175 | int maxw = ( img->width - 1 ); 176 | int maxh = ( img->height - 1 ); 177 | 178 | float fu = IMG_FLOOR( u ); 179 | float du = u - fu; 180 | float fv = IMG_FLOOR( v ); 181 | float dv = v - fv; 182 | 183 | int x1 = (int) ( fu ); 184 | int y1 = (int) ( fv ); 185 | int x2 = (int) ( fu + 1.0f ); 186 | int y2 = (int) ( fv + 1.0f ); 187 | 188 | x1 = x1 < 0 ? 0 : x1 > maxw ? maxw : x1; 189 | x2 = x2 < 0 ? 0 : x2 > maxw ? maxw : x2; 190 | y1 = y1 < 0 ? 0 : y1 > maxh ? maxh : y1; 191 | y2 = y2 < 0 ? 0 : y2 > maxh ? maxh : y2; 192 | 193 | img_rgba_t c1 = img->pixels[ x1 + y1 * img->width ]; 194 | img_rgba_t c2 = img->pixels[ x2 + y1 * img->width ]; 195 | img_rgba_t c3 = img->pixels[ x1 + y2 * img->width ]; 196 | img_rgba_t c4 = img->pixels[ x2 + y2 * img->width ]; 197 | 198 | return img_rgba_lerp( img_rgba_lerp( c1, c2, du ), img_rgba_lerp( c3, c4, du ), dv ); 199 | } 200 | 201 | 202 | void img_adjust_brightness( img_t* img, float value ) { 203 | if( value == 0.0f ) return; 204 | for( int i = 0; i < img->width * img->height; ++i ) { 205 | img_rgba_t* p = &img->pixels[ i ]; 206 | p->r = p->r + value; 207 | p->g = p->g + value; 208 | p->b = p->b + value; 209 | } 210 | } 211 | 212 | void img_adjust_contrast( img_t* img, float value ) { 213 | if( value == 0.0f ) return; 214 | for( int i = 0; i < img->width * img->height; ++i ) { 215 | img_rgba_t* p = &img->pixels[ i ]; 216 | p->r = ( p->r - 0.5f ) * value + 0.5f; 217 | p->g = ( p->g - 0.5f ) * value + 0.5f; 218 | p->b = ( p->b - 0.5f ) * value + 0.5f; 219 | } 220 | } 221 | 222 | #define img_min( x, y ) ( (x) < (y) ? (x) : (y) ) 223 | #define img_max( x, y ) ( (x) > (y) ? (x) : (y) ) 224 | 225 | img_hsva_t img_rgba_to_hsva( img_rgba_t rgb ) { 226 | img_hsva_t hsv; 227 | hsv.a = rgb.a; 228 | 229 | float cmin = img_min( rgb.r, img_min( rgb.g, rgb.b ) ); //Min. value of RGB 230 | float cmax = img_max( rgb.r, img_max( rgb.g, rgb.b ) ); //Max. value of RGB 231 | float cdel = cmax - cmin; //Delta RGB value 232 | 233 | hsv.v = cmax; 234 | 235 | if( cdel == 0 ) { //This is a gray, no chroma... 236 | hsv.h = 0; //HSV results from 0 to 1 237 | hsv.s = 0; 238 | } else { //Chromatic data... 239 | hsv.s = cdel / cmax; 240 | 241 | float rdel = ( ( ( cmax - rgb.r ) / 6.0f ) + ( cdel / 2.0f ) ) / cdel; 242 | float gdel = ( ( ( cmax - rgb.g ) / 6.0f ) + ( cdel / 2.0f ) ) / cdel; 243 | float bdel = ( ( ( cmax - rgb.b ) / 6.0f ) + ( cdel / 2.0f ) ) / cdel; 244 | 245 | if( rgb.r == cmax ) { 246 | hsv.h = bdel - gdel; 247 | } else if( rgb.g == cmax ) { 248 | hsv.h = ( 1.0f / 3.0f ) + rdel - bdel; 249 | } else { 250 | hsv.h = ( 2.0f / 3.0f ) + gdel - rdel; 251 | } 252 | 253 | if ( hsv.h < 0.0f ) { 254 | hsv.h += 1.0f; 255 | } 256 | if ( hsv.h > 1.0f ) { 257 | hsv.h -= 1.0f; 258 | } 259 | } 260 | 261 | hsv.h = hsv.h; 262 | hsv.s = hsv.s; 263 | hsv.v = hsv.v; 264 | return hsv; 265 | } 266 | 267 | 268 | img_rgba_t img_hsva_to_rgba( img_hsva_t hsv ) { 269 | img_rgba_t rgb; 270 | rgb.a = hsv.a; 271 | 272 | if( hsv.s == 0.0f ) { // HSV from 0 to 1 273 | rgb.r = hsv.v; 274 | rgb.g = hsv.v; 275 | rgb.b = hsv.v; 276 | } else { 277 | float h = hsv.h * 6.0f; 278 | if( h == 6.0f ) { 279 | h = 0.0f; //H must be < 1 280 | } 281 | float i = IMG_FLOOR( h ); 282 | float v1 = hsv.v * ( 1.0f - hsv.s ); 283 | float v2 = hsv.v * ( 1.0f - hsv.s * ( h - i ) ); 284 | float v3 = hsv.v * ( 1.0f - hsv.s * ( 1.0f - ( h - i ) ) ); 285 | 286 | switch( (int) i ) { 287 | case 0: { rgb.r = hsv.v; rgb.g = v3 ; rgb.b = v1 ; } break; 288 | case 1: { rgb.r = v2 ; rgb.g = hsv.v; rgb.b = v1 ; } break; 289 | case 2: { rgb.r = v1 ; rgb.g = hsv.v; rgb.b = v3 ; } break; 290 | case 3: { rgb.r = v1 ; rgb.g = v2 ; rgb.b = hsv.v; } break; 291 | case 4: { rgb.r = v3 ; rgb.g = v1 ; rgb.b = hsv.v; } break; 292 | default:{ rgb.r = hsv.v; rgb.g = v1 ; rgb.b = v2 ; } break; 293 | } 294 | } 295 | 296 | rgb.r = rgb.r; 297 | rgb.g = rgb.g; 298 | rgb.b = rgb.b; 299 | return rgb; 300 | } 301 | 302 | 303 | void img_adjust_saturation( img_t* img, float value ) { 304 | if( value == 0.0f ) return; 305 | for( int i = 0; i < img->width * img->height; ++i ) { 306 | img_rgba_t* p = &img->pixels[ i ]; 307 | img_hsva_t hsv = img_rgba_to_hsva( *p ); 308 | hsv.s = img_clamp( hsv.s + value, 0.0f, 1.0f ); 309 | *p = img_hsva_to_rgba( hsv ); 310 | } 311 | } 312 | 313 | 314 | void img_sharpen( img_t* img, float radius, float blend ) { 315 | float filter[ 9 ] = { 316 | -1.0f, -1.0f, -1.0f, 317 | -1.0f, 9.0f, -1.0f, 318 | -1.0f, -1.0f, -1.0f, 319 | }; 320 | 321 | img_rgba_t* result = (img_rgba_t*) malloc( img->width * img->height * sizeof( img_rgba_t ) ); 322 | 323 | img_rgba_t* src = img->pixels; 324 | img_rgba_t* dst = result; 325 | for( int y = 0; y < img->height; ++y ) { 326 | for( int x = 0; x < img->width; ++x ) { 327 | if( src->a > 0.0f ) { 328 | img_rgba_t acc = { 0.0f, 0.0f, 0.0f, 0.0f }; 329 | for( int fx = -1; fx <= 1; ++fx ) { 330 | for( int fy = -1; fy <= 1; ++fy ) { 331 | float u = ( (float) x ) + ( (float) fx ) * radius; 332 | float v = ( (float) y ) + ( (float) fy ) * radius; 333 | img_rgba_t s = img_sample_clamp( img, u, v ); 334 | if( s.a < 0.0001f ) { 335 | s = *src; 336 | } 337 | acc.r += s.r * ( filter[ ( 1 + fx ) + ( 1 + fy ) * 3 ] ); 338 | acc.g += s.g * ( filter[ ( 1 + fx ) + ( 1 + fy ) * 3 ] ); 339 | acc.b += s.b * ( filter[ ( 1 + fx ) + ( 1 + fy ) * 3 ] ); 340 | } 341 | } 342 | *dst = img_rgba_lerp( *src, acc, blend ); 343 | dst->a = src->a; 344 | } else { 345 | *dst = *src; 346 | } 347 | ++src; 348 | ++dst; 349 | } 350 | } 351 | 352 | free( img->pixels ); 353 | img->pixels = result; 354 | } 355 | 356 | #endif /* IMG_IMPLEMENTATION */ 357 | 358 | /* 359 | ------------------------------------------------------------------------------ 360 | 361 | This software is available under 2 licenses - you may choose the one you like. 362 | 363 | ------------------------------------------------------------------------------ 364 | 365 | ALTERNATIVE A - MIT License 366 | 367 | Copyright (c) 2019 Mattias Gustavsson 368 | 369 | Permission is hereby granted, free of charge, to any person obtaining a copy of 370 | this software and associated documentation files (the "Software"), to deal in 371 | the Software without restriction, including without limitation the rights to 372 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 373 | of the Software, and to permit persons to whom the Software is furnished to do 374 | so, subject to the following conditions: 375 | 376 | The above copyright notice and this permission notice shall be included in all 377 | copies or substantial portions of the Software. 378 | 379 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 380 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 381 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 382 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 383 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 384 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 385 | SOFTWARE. 386 | 387 | ------------------------------------------------------------------------------ 388 | 389 | ALTERNATIVE B - Public Domain (www.unlicense.org) 390 | 391 | This is free and unencumbered software released into the public domain. 392 | 393 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 394 | software, either in source code form or as a compiled binary, for any purpose, 395 | commercial or non-commercial, and by any means. 396 | 397 | In jurisdictions that recognize copyright laws, the author or authors of this 398 | software dedicate any and all copyright interest in the software to the public 399 | domain. We make this dedication for the benefit of the public at large and to 400 | the detriment of our heirs and successors. We intend this dedication to be an 401 | overt act of relinquishment in perpetuity of all present and future rights to 402 | this software under copyright law. 403 | 404 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 405 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 406 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 407 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 408 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 409 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 410 | 411 | ------------------------------------------------------------------------------ 412 | */ 413 | -------------------------------------------------------------------------------- /mus.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | mus.h - v0.1 - Parsing library for MUS music files (as used in DOS games). 7 | 8 | Do this: 9 | #define MUS_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef mus_h 14 | #define mus_h 15 | 16 | #include 17 | 18 | typedef struct mus_t mus_t; 19 | 20 | mus_t* mus_create( void const* data, size_t size, void* memctx ); 21 | void mus_destroy( mus_t* mus ); 22 | 23 | typedef enum mus_cmd_t { 24 | MUS_CMD_RELEASE_NOTE, 25 | MUS_CMD_PLAY_NOTE, 26 | MUS_CMD_PITCH_BEND, 27 | MUS_CMD_SYSTEM_EVENT, 28 | MUS_CMD_CONTROLLER, 29 | MUS_CMD_END_OF_MEASURE, 30 | MUS_CMD_FINISH, 31 | MUS_CMD_RENDER_SAMPLES, 32 | } mus_cmd_t; 33 | 34 | struct mus_cmd_release_note_t { 35 | int note; 36 | }; 37 | 38 | struct mus_cmd_play_note_t { 39 | int note; 40 | int volume; 41 | }; 42 | 43 | struct mus_cmd_pitch_bend_t { 44 | int bend_amount; 45 | }; 46 | 47 | enum mus_system_event_t { 48 | MUS_SYSTEM_EVENT_ALL_SOUNDS_OFF, 49 | MUS_SYSTEM_EVENT_ALL_NOTES_OFF, 50 | MUS_SYSTEM_EVENT_MONO, 51 | MUS_SYSTEM_EVENT_POLY, 52 | MUS_SYSTEM_EVENT_RESET_ALL_CONTROLLERS, 53 | }; 54 | 55 | struct mus_cmd_system_event_t { 56 | enum mus_system_event_t event; 57 | }; 58 | 59 | enum mus_controller_t { 60 | MUS_CONTROLLER_CHANGE_INSTRUMENT, 61 | MUS_CONTROLLER_BANK_SELECT, 62 | MUS_CONTROLLER_MODULATION, 63 | MUS_CONTROLLER_VOLUME, 64 | MUS_CONTROLLER_PAN, 65 | MUS_CONTROLLER_EXPRESSION, 66 | MUS_CONTROLLER_REVERB_DEPTH, 67 | MUS_CONTROLLER_CHORUS_DEPTH, 68 | MUS_CONTROLLER_SUSTAIN_PEDAL, 69 | MUS_CONTROLLER_SOFT_PEDAL, 70 | }; 71 | 72 | struct mus_cmd_controller_t { 73 | enum mus_controller_t controller; 74 | int value; 75 | }; 76 | 77 | struct mus_cmd_render_samples_t { 78 | int samples_count; 79 | }; 80 | 81 | union mus_cmd_data_t { 82 | struct mus_cmd_release_note_t release_note; 83 | struct mus_cmd_play_note_t play_note; 84 | struct mus_cmd_pitch_bend_t pitch_bend; 85 | struct mus_cmd_system_event_t system_event; 86 | struct mus_cmd_controller_t controller; 87 | struct mus_cmd_render_samples_t render_samples; 88 | }; 89 | 90 | typedef struct mus_event_t { 91 | int channel; 92 | enum mus_cmd_t cmd; 93 | union mus_cmd_data_t data; 94 | } mus_event_t; 95 | 96 | 97 | void mus_next_event( mus_t* mus, mus_event_t* event ); 98 | 99 | void mus_restart( mus_t* mus ); 100 | 101 | #endif /* mus_h */ 102 | 103 | 104 | /* 105 | ---------------------- 106 | IMPLEMENTATION 107 | ---------------------- 108 | */ 109 | 110 | #ifdef MUS_IMPLEMENTATION 111 | #undef MUS_IMPLEMENTATION 112 | 113 | #if !defined( MUS_MALLOC ) || !defined( MUS_FREE ) 114 | #include 115 | #define MUS_MALLOC malloc 116 | #define MUS_FREE free 117 | #endif 118 | 119 | struct mus_t { 120 | int note_volume[ 16 ]; 121 | int accumulated_delay; 122 | int pos; 123 | int length; 124 | uint8_t data[ 1 ]; // "open" array 125 | }; 126 | 127 | mus_t* mus_create( void const* data, size_t size, void* memctx ) { 128 | (void) memctx, (void) size; 129 | uintptr_t ptr = (uintptr_t) data; 130 | uint32_t sig = *(uint32_t*) ptr; 131 | ptr += 4; 132 | if( sig != 0x1a53554d ) { // Identifier "MUS" followed by 0x1A 133 | return NULL; 134 | } 135 | int length = *(uint16_t*) ptr; 136 | ptr += 2; 137 | 138 | int offset = *(uint16_t*) ptr; 139 | ptr += 2; 140 | 141 | if( (size_t)( length + offset ) > size ) { 142 | return NULL; 143 | } 144 | 145 | mus_t* mus = (mus_t*) MUS_MALLOC( sizeof( mus_t ) + length - 1 ); 146 | mus->length = length; 147 | memcpy( mus->data, (void*)( ((uintptr_t)data) + offset ), length ); 148 | mus_restart( mus ); 149 | return mus; 150 | } 151 | 152 | 153 | void mus_destroy( mus_t* mus ) { 154 | MUS_FREE( mus ); 155 | } 156 | 157 | 158 | void mus_next_event( mus_t* mus, mus_event_t* event ) { 159 | if( mus->accumulated_delay ) { 160 | int samples_count = ( mus->accumulated_delay * 44100 ) / 140; 161 | event->channel = 0; 162 | event->cmd = MUS_CMD_RENDER_SAMPLES; 163 | event->data.render_samples.samples_count = samples_count; 164 | mus->accumulated_delay = 0; 165 | return; 166 | } 167 | while( mus->pos < mus->length ) { 168 | uint8_t data = mus->data[ mus->pos++ ]; 169 | int channel = data & 15; 170 | int type = ( data >> 4 ) & 7; 171 | int last = ( data >> 7 ) & 1; 172 | int event_valid = 0; 173 | switch( type ) { 174 | case 0: { // Release Note 175 | data = mus->data[ mus->pos++ ]; 176 | int note = data & 127; 177 | event->channel = channel; 178 | event->cmd = MUS_CMD_RELEASE_NOTE; 179 | event->data.release_note.note = note; 180 | event_valid = 1; 181 | } break; 182 | 183 | case 1: { // Play Note 184 | data = mus->data[ mus->pos++ ]; 185 | int note = data & 127; 186 | int has_vol = ( data >> 7 ); 187 | if( has_vol ) { 188 | data = mus->data[ mus->pos++ ]; 189 | mus->note_volume[ channel ] = data; 190 | } 191 | event->channel = channel; 192 | event->cmd = MUS_CMD_PLAY_NOTE; 193 | event->data.play_note.note = note; 194 | event->data.play_note.volume = mus->note_volume[ channel ]; 195 | event_valid = 1; 196 | } break; 197 | 198 | case 2: { // Pitch Bend 199 | data = mus->data[ mus->pos++ ]; 200 | int bend_amount = data; 201 | event->channel = channel; 202 | event->cmd = MUS_CMD_PITCH_BEND; 203 | event->data.pitch_bend.bend_amount = bend_amount; 204 | event_valid = 1; 205 | } break; 206 | 207 | case 3: { // System Event 208 | data = mus->data[ mus->pos++ ]; 209 | int sysevent = data & 127; 210 | event->channel = channel; 211 | event->cmd = MUS_CMD_SYSTEM_EVENT; 212 | event->data.system_event.event = (enum mus_system_event_t)sysevent; 213 | event_valid = 1; 214 | } break; 215 | 216 | case 4: { // Controller 217 | data = mus->data[ mus->pos++ ]; 218 | int controller = data & 127; 219 | data = mus->data[ mus->pos++ ]; 220 | int value = data & 127; 221 | event->channel = channel; 222 | event->cmd = MUS_CMD_CONTROLLER; 223 | event->data.controller.controller = (enum mus_controller_t)controller; 224 | event->data.controller.value = value; 225 | event_valid = 1; 226 | } break; 227 | 228 | case 5: { // End of Measure 229 | event->channel = channel; 230 | event->cmd = MUS_CMD_END_OF_MEASURE; 231 | event_valid = 1; 232 | } break; 233 | 234 | case 6: { // Finish 235 | event->channel = channel; 236 | event->cmd = MUS_CMD_END_OF_MEASURE; 237 | event_valid = 1; 238 | } break; 239 | 240 | case 7: { // Unused 241 | data = mus->data[ mus->pos++ ]; 242 | } break; 243 | } 244 | 245 | if( last ) { 246 | int delay = 0; 247 | for( ; ; ) { 248 | data = mus->data[ mus->pos++ ]; 249 | delay = delay * 128 + ( data & 127 ); 250 | if( ( data >> 7 ) == 0 ) { 251 | if( event_valid ) { 252 | mus->accumulated_delay = delay; 253 | } else { 254 | int samples_count = ( delay * 44100 ) / 140; 255 | event->channel = 0; 256 | event->cmd = MUS_CMD_RENDER_SAMPLES; 257 | event->data.render_samples.samples_count = samples_count; 258 | event_valid = 1; 259 | } 260 | break; 261 | } 262 | } 263 | } 264 | if( event_valid ) { 265 | return; 266 | } 267 | } 268 | 269 | event->channel = 0; 270 | event->cmd = MUS_CMD_FINISH; 271 | } 272 | 273 | 274 | void mus_restart( mus_t* mus ) { 275 | mus->accumulated_delay = 0; 276 | for( int i = 0; i < sizeof( mus->note_volume ) / sizeof( *mus->note_volume ); ++i ){ 277 | mus->note_volume[ i ] = 127; 278 | } 279 | mus->pos = 0; 280 | } 281 | 282 | 283 | #endif /* MUS_IMPLEMENTATION */ 284 | 285 | /* 286 | ------------------------------------------------------------------------------ 287 | 288 | This software is available under 2 licenses - you may choose the one you like. 289 | 290 | ------------------------------------------------------------------------------ 291 | 292 | ALTERNATIVE A - MIT License 293 | 294 | Copyright (c) 2021 Mattias Gustavsson 295 | 296 | Permission is hereby granted, free of charge, to any person obtaining a copy of 297 | this software and associated documentation files (the "Software"), to deal in 298 | the Software without restriction, including without limitation the rights to 299 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 300 | of the Software, and to permit persons to whom the Software is furnished to do 301 | so, subject to the following conditions: 302 | 303 | The above copyright notice and this permission notice shall be included in all 304 | copies or substantial portions of the Software. 305 | 306 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 307 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 308 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 309 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 310 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 311 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 312 | SOFTWARE. 313 | 314 | ------------------------------------------------------------------------------ 315 | 316 | ALTERNATIVE B - Public Domain (www.unlicense.org) 317 | 318 | This is free and unencumbered software released into the public domain. 319 | 320 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 321 | software, either in source code form or as a compiled binary, for any purpose, 322 | commercial or non-commercial, and by any means. 323 | 324 | In jurisdictions that recognize copyright laws, the author or authors of this 325 | software dedicate any and all copyright interest in the software to the public 326 | domain. We make this dedication for the benefit of the public at large and to 327 | the detriment of our heirs and successors. We intend this dedication to be an 328 | overt act of relinquishment in perpetuity of all present and future rights to 329 | this software under copyright law. 330 | 331 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 332 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 333 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 334 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 335 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 336 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 337 | 338 | ------------------------------------------------------------------------------ 339 | */ 340 | -------------------------------------------------------------------------------- /palrle.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | palrle.h - v0.1 - Run-length encoding of palettized bitmaps, for C/C++. 7 | 8 | Do this: 9 | #define PALRLE_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef palrle_h 14 | #define palrle_h 15 | 16 | #ifndef PALRLE_U8 17 | #define PALRLE_U8 unsigned char 18 | #endif 19 | #ifndef PALRLE_U16 20 | #define PALRLE_U16 unsigned short 21 | #endif 22 | #ifndef PALRLE_U32 23 | #define PALRLE_U32 unsigned int 24 | #endif 25 | 26 | typedef struct palrle_data_t { 27 | PALRLE_U32 size; 28 | PALRLE_U16 width; 29 | PALRLE_U16 height; 30 | PALRLE_U16 xoffset; 31 | PALRLE_U16 yoffset; 32 | PALRLE_U16 hpitch; 33 | PALRLE_U16 vpitch; 34 | PALRLE_U16 palette_count; 35 | PALRLE_U8 data[ 1 ]; // "open" array 36 | } palrle_data_t; 37 | 38 | palrle_data_t* palrle_encode( PALRLE_U8* pixels, int width, int height, PALRLE_U32* palette, int palette_count, void* memctx ); 39 | palrle_data_t* palrle_encode_mask( PALRLE_U8* pixels, PALRLE_U8* mask, int width, int height, PALRLE_U32* palette, int palette_count, void* memctx ); 40 | //palrle_data_t* palrle_encode_transparency_index( PALRLE_U8* pixels, PALRLE_U8 transparency_index, int width, int height, PALRLE_U32* palette, int palette_count, void* memctx ); 41 | 42 | void palrle_decode( palrle_data_t* rle_data, PALRLE_U8* pixels, PALRLE_U8* mask ); 43 | 44 | void palrle_blit( palrle_data_t* rle_data, int x, int y, PALRLE_U8* pixels, int width, int height ); 45 | 46 | void palrle_free( palrle_data_t* rle_data, void* memctx ); 47 | 48 | 49 | #endif /* palrle_h */ 50 | 51 | /* 52 | ---------------------- 53 | IMPLEMENTATION 54 | ---------------------- 55 | */ 56 | 57 | #ifdef PALRLE_IMPLEMENTATION 58 | #undef PALRLE_IMPLEMENTATION 59 | 60 | #ifndef PALRLE_MALLOC 61 | #define _CRT_NONSTDC_NO_DEPRECATE 62 | #define _CRT_SECURE_NO_WARNINGS 63 | #include 64 | #define PALRLE_MALLOC( ctx, size ) ( malloc( size ) ) 65 | #define PALRLE_FREE( ctx, ptr ) ( free( ptr ) ) 66 | #endif 67 | 68 | 69 | palrle_data_t* palrle_encode( PALRLE_U8* pixels, int width, int height, PALRLE_U32* palette, int palette_count, void* memctx ) { 70 | (void) memctx; 71 | 72 | int xmin = 0; 73 | int xmax = width - 1; 74 | int ymin = 0; 75 | int ymax = height - 1; 76 | int hpitch = xmax - xmin + 1; 77 | int vpitch = ymax - ymin + 1; 78 | 79 | // Bitmap is completely empty, so just store the palette and dimensions 80 | if( hpitch <= 0 || vpitch <= 0 ) { 81 | size_t size = sizeof( palrle_data_t ) - sizeof( PALRLE_U8 ) + sizeof( PALRLE_U32 ) * palette_count; 82 | palrle_data_t* data = (palrle_data_t*) PALRLE_MALLOC( memctx, size ); 83 | data->size = (PALRLE_U32) size; 84 | data->width = (PALRLE_U16) width; 85 | data->height = (PALRLE_U16) height; 86 | data->xoffset = 0; 87 | data->yoffset = 0; 88 | data->hpitch = 0; 89 | data->vpitch = 0; 90 | data->palette_count = (PALRLE_U16) palette_count; 91 | if( palette ) memcpy( data->data, palette, sizeof( PALRLE_U32 ) * palette_count ); 92 | return data; 93 | } 94 | 95 | palrle_data_t* data = (palrle_data_t*) PALRLE_MALLOC( memctx, 96 | sizeof( palrle_data_t ) + // size for the struct itself 97 | sizeof( PALRLE_U32 ) * palette_count + // size for storing palette entries 98 | sizeof( PALRLE_U32 ) * vpitch + // size for storing the offset for each row 99 | hpitch * vpitch * 2 ); // assume worst case - we should never need more than twice the number of pixels 100 | memset( data, 0, sizeof( palrle_data_t ) + sizeof( PALRLE_U32 ) * palette_count + sizeof( PALRLE_U32 ) * vpitch + 101 | hpitch * vpitch * 2 ); 102 | 103 | 104 | data->size = (PALRLE_U32) ( sizeof( palrle_data_t ) - sizeof( PALRLE_U8 ) ); 105 | data->width = (PALRLE_U16) width; 106 | data->height = (PALRLE_U16) height; 107 | data->xoffset = (PALRLE_U16) xmin; 108 | data->yoffset = (PALRLE_U16) ymin; 109 | data->hpitch = (PALRLE_U16) hpitch; 110 | data->vpitch = (PALRLE_U16) vpitch; 111 | data->palette_count = (PALRLE_U16) palette_count; 112 | if( palette ) memcpy( data->data, palette, sizeof( PALRLE_U32 ) * palette_count ); 113 | 114 | int row_offset = (int)( sizeof( PALRLE_U32 ) * palette_count ); 115 | int rle_offset = (int)( row_offset + sizeof( PALRLE_U32 ) * vpitch ); 116 | for( int y = 0; y < vpitch; ++y ) { 117 | *( (PALRLE_U32*)&data->data[ row_offset ] ) = (PALRLE_U32) rle_offset; 118 | row_offset += sizeof( PALRLE_U32 ); 119 | int x = 0; 120 | while( x < hpitch ) { 121 | // add empty pixel count 122 | data->data[ rle_offset++ ] = (PALRLE_U8) 0; 123 | 124 | // add non-empty pixels 125 | int color = pixels[ x + xmin + ( y + ymin ) * width ]; 126 | int count = 0; 127 | int tx = x; 128 | while( tx < hpitch ) { 129 | if( pixels[ tx + xmin + ( y + ymin ) * width ] != color ) break; 130 | if( count >= 127 ) break; 131 | ++count; 132 | ++tx; 133 | } 134 | 135 | if( count == 0 ) { 136 | data->data[ rle_offset++ ] = 0; 137 | continue; 138 | } 139 | 140 | if( count > 2 ) { // store as a run 141 | data->data[ rle_offset++ ] = (PALRLE_U8) count; // number of pixels 142 | data->data[ rle_offset++ ] = (PALRLE_U8) color; // of palette index `color` 143 | x = tx; 144 | } else { // store as unique values 145 | PALRLE_U8* uniques_out = &data->data[ rle_offset++ ]; 146 | int uniques = 1; 147 | data->data[ rle_offset++ ] = (PALRLE_U8) color; 148 | ++x; 149 | 150 | // add pixexls until we encounter a run 151 | while( x < hpitch ) { 152 | // check the length of the next run 153 | color = pixels[ x + xmin + ( y + ymin ) * width ]; 154 | count = 0; 155 | tx = x; 156 | while( tx < hpitch ) { 157 | if( pixels[ tx + xmin + ( y + ymin ) * width ] != color ) break; 158 | if( count > 2 ) break; // No need to keep counting, we know this is a run 159 | ++count; 160 | ++tx; 161 | } 162 | if( count > 2 || count == 0 ) { 163 | break; 164 | } else { 165 | if( uniques >= 128 ) break; 166 | ++uniques; 167 | data->data[ rle_offset++ ] = (PALRLE_U8) color; 168 | ++x; 169 | } 170 | } 171 | *uniques_out = (PALRLE_U8)( (char) -uniques ); 172 | } 173 | } 174 | } 175 | data->size += rle_offset; 176 | 177 | return data; 178 | } 179 | 180 | 181 | palrle_data_t* palrle_encode_mask( PALRLE_U8* pixels, PALRLE_U8* mask, int width, int height, PALRLE_U32* palette, int palette_count, void* memctx ) { 182 | (void) memctx; 183 | // Crop to smallest non-empty region 184 | int xmin = width; 185 | int xmax = 0; 186 | int ymin = height; 187 | int ymax = 0; 188 | for( int y = 0; y < height; ++y ) { 189 | for( int x = 0; x < width; ++x ) { 190 | if( mask[ x + y * width ] ) { 191 | if( x < xmin ) xmin = x; 192 | if( y < ymin ) ymin = y; 193 | if( x > xmax ) xmax = x; 194 | if( y > ymax ) ymax = y; 195 | } 196 | } 197 | } 198 | int hpitch = xmax - xmin + 1; 199 | int vpitch = ymax - ymin + 1; 200 | 201 | // Bitmap is completely empty, so just store the palette and dimensions 202 | if( hpitch <= 0 || vpitch <= 0 ) { 203 | size_t size = sizeof( palrle_data_t ) - sizeof( PALRLE_U8 ) + sizeof( PALRLE_U32 ) * palette_count; 204 | palrle_data_t* data = (palrle_data_t*) PALRLE_MALLOC( memctx, size ); 205 | data->size = (PALRLE_U32) size; 206 | data->width = (PALRLE_U16) width; 207 | data->height = (PALRLE_U16) height; 208 | data->xoffset = 0; 209 | data->yoffset = 0; 210 | data->hpitch = 0; 211 | data->vpitch = 0; 212 | data->palette_count = (PALRLE_U16) palette_count; 213 | if( palette ) memcpy( data->data, palette, sizeof( PALRLE_U32 ) * palette_count ); 214 | return data; 215 | } 216 | 217 | palrle_data_t* data = (palrle_data_t*) PALRLE_MALLOC( memctx, 218 | sizeof( palrle_data_t ) + // size for the struct itself 219 | sizeof( PALRLE_U32 ) * palette_count + // size for storing palette entries 220 | sizeof( PALRLE_U32 ) * vpitch + // size for storing the offset for each row 221 | hpitch * vpitch * 2 ); // assume worst case - we should never need more than twice the number of pixels 222 | memset( data, 0, sizeof( palrle_data_t ) + sizeof( PALRLE_U32 ) * palette_count + sizeof( PALRLE_U32 ) * vpitch + 223 | hpitch * vpitch * 2 ); 224 | 225 | 226 | data->size = (PALRLE_U32) ( sizeof( palrle_data_t ) - sizeof( PALRLE_U8 ) ); 227 | data->width = (PALRLE_U16) width; 228 | data->height = (PALRLE_U16) height; 229 | data->xoffset = (PALRLE_U16) xmin; 230 | data->yoffset = (PALRLE_U16) ymin; 231 | data->hpitch = (PALRLE_U16) hpitch; 232 | data->vpitch = (PALRLE_U16) vpitch; 233 | data->palette_count = (PALRLE_U16) palette_count; 234 | if( palette ) memcpy( data->data, palette, sizeof( PALRLE_U32 ) * palette_count ); 235 | 236 | int row_offset = (int)( sizeof( PALRLE_U32 ) * palette_count ); 237 | int rle_offset = (int)( row_offset + sizeof( PALRLE_U32 ) * vpitch ); 238 | for( int y = 0; y < vpitch; ++y ) { 239 | *( (PALRLE_U32*)&data->data[ row_offset ] ) = (PALRLE_U32) rle_offset; 240 | row_offset += sizeof( PALRLE_U32 ); 241 | int x = 0; 242 | while( x < hpitch ) { 243 | // add empty pixel count 244 | int empty = 0; 245 | while( x < hpitch ) { 246 | if( mask[ x + xmin + ( y + ymin ) * width ] != 0 ) break; 247 | if( empty >= 255 ) { 248 | data->data[ rle_offset++ ] = 255; // 255 empty pixels 249 | data->data[ rle_offset++ ] = 0; // 0 non-empty pixels 250 | empty = 0; 251 | } 252 | ++empty; 253 | ++x; 254 | } 255 | data->data[ rle_offset++ ] = (PALRLE_U8) empty; 256 | 257 | // add non-empty pixels 258 | int color = pixels[ x + xmin + ( y + ymin ) * width ]; 259 | int count = 0; 260 | int tx = x; 261 | while( tx < hpitch ) { 262 | if( mask[ tx + xmin + ( y + ymin ) * width ] == 0 ) break; 263 | if( pixels[ tx + xmin + ( y + ymin ) * width ] != color ) break; 264 | if( count >= 127 ) break; 265 | ++count; 266 | ++tx; 267 | } 268 | 269 | if( count == 0 ) { 270 | data->data[ rle_offset++ ] = 0; 271 | continue; 272 | } 273 | 274 | if( count > 2 ) { // store as a run 275 | data->data[ rle_offset++ ] = (PALRLE_U8) count; // number of pixels 276 | data->data[ rle_offset++ ] = (PALRLE_U8) color; // of palette index `color` 277 | x = tx; 278 | } else { // store as unique values 279 | PALRLE_U8* uniques_out = &data->data[ rle_offset++ ]; 280 | int uniques = 1; 281 | data->data[ rle_offset++ ] = (PALRLE_U8) color; 282 | ++x; 283 | 284 | // add pixexls until we encounter a run 285 | while( x < hpitch ) { 286 | // check the length of the next run 287 | color = pixels[ x + xmin + ( y + ymin ) * width ]; 288 | count = 0; 289 | tx = x; 290 | while( tx < hpitch ) { 291 | if( mask[ tx + xmin + ( y + ymin ) * width ] == 0 ) break; 292 | if( pixels[ tx + xmin + ( y + ymin ) * width ] != color ) break; 293 | if( count > 2 ) break; // No need to keep counting, we know this is a run 294 | ++count; 295 | ++tx; 296 | } 297 | if( count > 2 || count == 0 ) { 298 | break; 299 | } else { 300 | if( uniques >= 128 ) break; 301 | ++uniques; 302 | data->data[ rle_offset++ ] = (PALRLE_U8) color; 303 | ++x; 304 | } 305 | } 306 | *uniques_out = (PALRLE_U8)( (char) -uniques ); 307 | } 308 | } 309 | } 310 | data->size += rle_offset; 311 | 312 | return data; 313 | } 314 | 315 | 316 | /* 317 | palrle_data_t* palrle_encode_transparency_index( PALRLE_U8* pixels, PALRLE_U8 transparency_index, int width, int height, PALRLE_U32* palette, int palette_count, void* memctx ) { 318 | (void) pixels, transparency_index, width, height, memctx; 319 | return 0; 320 | } 321 | */ 322 | 323 | 324 | 325 | void palrle_decode( palrle_data_t* rle_data, PALRLE_U8* pixels, PALRLE_U8* mask ) { 326 | memset( pixels, 0, rle_data->width * rle_data->height * sizeof( PALRLE_U8 ) ); 327 | if( mask ) memset( mask, 0, rle_data->width * rle_data->height * sizeof( PALRLE_U8 ) ); 328 | PALRLE_U8* data = &rle_data->data[ sizeof( PALRLE_U32 ) * ( rle_data->palette_count + rle_data->vpitch ) ]; 329 | for( int y = 0; y < rle_data->vpitch; ++y ) { 330 | int x = 0; 331 | while( x < rle_data->hpitch ) { 332 | x += *data++; 333 | char count = (char)( *data++ ); 334 | if( count > 0 ) { 335 | PALRLE_U8 color = *data++; 336 | for( int i = 0; i < count; ++i ) { 337 | pixels[ rle_data->xoffset + x + ( rle_data->yoffset + y ) * rle_data->width ] = color; 338 | if( mask ) mask[ rle_data->xoffset + x + ( rle_data->yoffset + y ) * rle_data->width ] = 255; 339 | ++x; 340 | } 341 | } else { 342 | for( int i = 0; i < -count; ++i ) { 343 | pixels[ rle_data->xoffset + x + ( rle_data->yoffset + y ) * rle_data->width ] = *data++; 344 | if( mask ) mask[ rle_data->xoffset + x + ( rle_data->yoffset + y ) * rle_data->width ] = 255; 345 | ++x; 346 | } 347 | } 348 | } 349 | } 350 | } 351 | 352 | 353 | void palrle_blit( palrle_data_t* rle_data, int x, int y, PALRLE_U8* pixels, int width, int height ) { 354 | PALRLE_U8* data = &rle_data->data[ sizeof( PALRLE_U32 ) * ( rle_data->palette_count + rle_data->vpitch ) ]; 355 | for( int iy = 0; iy < rle_data->vpitch; ++iy ) { 356 | int ix = 0; 357 | while( ix < rle_data->hpitch ) { 358 | ix += *data++; 359 | char count = (char)( *data++ ); 360 | if( count > 0 ) { 361 | PALRLE_U8 color = *data++; 362 | for( int i = 0; i < count; ++i ) { 363 | int xp = rle_data->xoffset + ix + x; 364 | int yp = rle_data->yoffset + iy + y; 365 | if( xp > 0 && yp > 0 && xp < width && yp < height ) pixels[ xp + yp * width ] = color; 366 | ++ix; 367 | } 368 | } else { 369 | for( int i = 0; i < -count; ++i ) { 370 | PALRLE_U8 color = *data++; 371 | int xp = rle_data->xoffset + ix + x; 372 | int yp = rle_data->yoffset + iy + y; 373 | if( xp > 0 && yp > 0 && xp < width && yp < height ) pixels[ xp + yp * width ] = color; 374 | ++ix; 375 | } 376 | } 377 | } 378 | } 379 | } 380 | 381 | 382 | void palrle_free( palrle_data_t* rle_data, void* memctx ) { 383 | (void) rle_data, (void) memctx; 384 | PALRLE_FREE( memctx, rle_data ); 385 | } 386 | 387 | #endif /* PALRLE_IMPLEMENTATION */ 388 | 389 | 390 | /* 391 | ------------------------------------------------------------------------------ 392 | 393 | This software is available under 2 licenses - you may choose the one you like. 394 | 395 | ------------------------------------------------------------------------------ 396 | 397 | ALTERNATIVE A - MIT License 398 | 399 | Copyright (c) 2019 Mattias Gustavsson 400 | 401 | Permission is hereby granted, free of charge, to any person obtaining a copy of 402 | this software and associated documentation files (the "Software"), to deal in 403 | the Software without restriction, including without limitation the rights to 404 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 405 | of the Software, and to permit persons to whom the Software is furnished to do 406 | so, subject to the following conditions: 407 | 408 | The above copyright notice and this permission notice shall be included in all 409 | copies or substantial portions of the Software. 410 | 411 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 412 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 413 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 414 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 415 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 416 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 417 | SOFTWARE. 418 | 419 | ------------------------------------------------------------------------------ 420 | 421 | ALTERNATIVE B - Public Domain (www.unlicense.org) 422 | 423 | This is free and unencumbered software released into the public domain. 424 | 425 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 426 | software, either in source code form or as a compiled binary, for any purpose, 427 | commercial or non-commercial, and by any means. 428 | 429 | In jurisdictions that recognize copyright laws, the author or authors of this 430 | software dedicate any and all copyright interest in the software to the public 431 | domain. We make this dedication for the benefit of the public at large and to 432 | the detriment of our heirs and successors. We intend this dedication to be an 433 | overt act of relinquishment in perpetuity of all present and future rights to 434 | this software under copyright law. 435 | 436 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 437 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 438 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 439 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 440 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 441 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 442 | 443 | ------------------------------------------------------------------------------ 444 | */ 445 | -------------------------------------------------------------------------------- /rnd.h: -------------------------------------------------------------------------------- 1 | /* 2 | ------------------------------------------------------------------------------ 3 | Licensing information can be found at the end of the file. 4 | ------------------------------------------------------------------------------ 5 | 6 | rnd.h - v1.0 - Pseudo-random number generators for C/C++. 7 | 8 | Do this: 9 | #define RND_IMPLEMENTATION 10 | before you include this file in *one* C/C++ file to create the implementation. 11 | */ 12 | 13 | #ifndef rnd_h 14 | #define rnd_h 15 | 16 | #ifndef RND_U32 17 | #define RND_U32 unsigned int 18 | #endif 19 | #ifndef RND_U64 20 | #define RND_U64 unsigned long long 21 | #endif 22 | 23 | typedef struct rnd_pcg_t { RND_U64 state[ 2 ]; } rnd_pcg_t; 24 | void rnd_pcg_seed( rnd_pcg_t* pcg, RND_U32 seed ); 25 | RND_U32 rnd_pcg_next( rnd_pcg_t* pcg ); 26 | float rnd_pcg_nextf( rnd_pcg_t* pcg ); 27 | int rnd_pcg_range( rnd_pcg_t* pcg, int min, int max ); 28 | 29 | typedef struct rnd_well_t { RND_U32 state[ 17 ]; } rnd_well_t; 30 | void rnd_well_seed( rnd_well_t* well, RND_U32 seed ); 31 | RND_U32 rnd_well_next( rnd_well_t* well ); 32 | float rnd_well_nextf( rnd_well_t* well ); 33 | int rnd_well_range( rnd_well_t* well, int min, int max ); 34 | 35 | typedef struct rnd_gamerand_t { RND_U32 state[ 2 ]; } rnd_gamerand_t; 36 | void rnd_gamerand_seed( rnd_gamerand_t* gamerand, RND_U32 seed ); 37 | RND_U32 rnd_gamerand_next( rnd_gamerand_t* gamerand ); 38 | float rnd_gamerand_nextf( rnd_gamerand_t* gamerand ); 39 | int rnd_gamerand_range( rnd_gamerand_t* gamerand, int min, int max ); 40 | 41 | typedef struct rnd_xorshift_t { RND_U64 state[ 2 ]; } rnd_xorshift_t; 42 | void rnd_xorshift_seed( rnd_xorshift_t* xorshift, RND_U64 seed ); 43 | RND_U64 rnd_xorshift_next( rnd_xorshift_t* xorshift ); 44 | float rnd_xorshift_nextf( rnd_xorshift_t* xorshift ); 45 | int rnd_xorshift_range( rnd_xorshift_t* xorshift, int min, int max ); 46 | 47 | #endif /* rnd_h */ 48 | 49 | /** 50 | 51 | rnd.h 52 | ===== 53 | 54 | Pseudo-random number generators for C/C++. 55 | 56 | 57 | Example 58 | ------- 59 | 60 | A basic example showing how to use the PCG set of random functions. 61 | 62 | #define RND_IMPLEMENTATION 63 | #include "rnd.h" 64 | 65 | #include // for printf 66 | #include // for time 67 | 68 | int main( int argc, char** argv ) { 69 | 70 | rnd_pcg_t pcg; 71 | rnd_pcg_seed( &pcg, 0u ); // initialize generator 72 | 73 | // print a handful of random integers 74 | // these will be the same on every run, as we 75 | // seeded the rng with a fixed value 76 | for( int i = 0; i < 5; ++i ) { 77 | RND_U32 n = rnd_pcg_next( &pcg ); 78 | printf( "%08x, ", n ); 79 | } 80 | printf( "\n" ); 81 | 82 | // reseed with a value which is different on each run 83 | time_t seconds; 84 | time( &seconds ); 85 | rnd_pcg_seed( &pcg, (RND_U32) seconds ); 86 | 87 | // print another handful of random integers 88 | // these will be different on every run 89 | for( int i = 0; i < 5; ++i ) { 90 | RND_U32 n = rnd_pcg_next( &pcg ); 91 | printf( "%08x, ", n ); 92 | } 93 | printf( "\n" ); 94 | 95 | 96 | // print a handful of random floats 97 | for( int i = 0; i < 5; ++i ) { 98 | float f = rnd_pcg_nextf( &pcg ); 99 | printf( "%f, ", f ); 100 | } 101 | printf( "\n" ); 102 | 103 | // print random integers in the range 1 to 6 104 | for( int i = 0; i < 15; ++i ) { 105 | int r = rnd_pcg_range( &pcg, 1, 6 ); 106 | printf( "%d, ", r ); 107 | } 108 | printf( "\n" ); 109 | 110 | return 0; 111 | } 112 | 113 | 114 | API Documentation 115 | ----------------- 116 | 117 | rnd.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it, 118 | you just include rnd.h to get the API declarations. To get the definitions, you must include rnd.h from *one* single C 119 | or C++ file, and #define the symbol `RND_IMPLEMENTATION` before you do. 120 | 121 | The library is meant for general-purpose use, such as games and similar apps. It is not meant to be used for 122 | cryptography and similar use cases. 123 | 124 | 125 | ### Customization 126 | 127 | rnd.h allows for specifying the exact type of 32 and 64 bit unsigned integers to be used in its API. By default, these 128 | default to `unsigned int` and `unsigned long long`, but can be redefined by #defining RND_U32 and RND_U64 respectively 129 | before including rnd.h. This is useful if you, for example, use the types from `` in the rest of your program, 130 | and you want rnd.h to use compatible types. In this case, you would include rnd.h using the following code: 131 | 132 | #define RND_U32 uint32_t 133 | #define RND_U64 uint64_t 134 | #include "rnd.h" 135 | 136 | Note that when customizing the data type, you need to use the same definition in every place where you include rnd.h, 137 | as it affect the declarations as well as the definitions. 138 | 139 | 140 | ### The generators 141 | 142 | The library includes four different generators: PCG, WELL, GameRand and XorShift. They all have different 143 | characteristics, and you might want to use them for different things. GameRand is very fast, but does not give a great 144 | distribution or period length. XorShift is the only one returning a 64-bit value. WELL is an improvement of the often 145 | used Mersenne Twister, and has quite a large internal state. PCG is small, fast and has a small state. If you don't 146 | have any specific reason, you may default to using PCG. 147 | 148 | All generators expose their internal state, so it is possible to save this state and later restore it, to resume the 149 | random sequence from the same point. 150 | 151 | 152 | #### PCG - Permuted Congruential Generator 153 | 154 | PCG is a family of simple fast space-efficient statistically good algorithms for random number generation. Unlike many 155 | general-purpose RNGs, they are also hard to predict. 156 | 157 | More information can be found here: 158 | 159 | http://www.pcg-random.org/ 160 | 161 | 162 | #### WELL - Well Equidistributed Long-period Linear 163 | 164 | Random number generation, using the WELL algorithm by F. Panneton, P. L'Ecuyer and M. Matsumoto. 165 | More information in the original paper: 166 | 167 | http://www.iro.umontreal.ca/~panneton/WELLRNG.html 168 | 169 | This code is originally based on WELL512 C/C++ code written by Chris Lomont (published in Game Programming Gems 7) 170 | and placed in the public domain. 171 | 172 | http://lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf 173 | 174 | 175 | #### GameRand 176 | 177 | Based on the random number generator by Ian C. Bullard: 178 | 179 | http://www.redditmirror.cc/cache/websites/mjolnirstudios.com_7yjlc/mjolnirstudios.com/IanBullard/files/79ffbca75a75720f066d491e9ea935a0-10.html 180 | 181 | GameRand is a random number generator based off an "Image of the Day" posted by Stephan Schaem. More information here: 182 | 183 | http://www.flipcode.com/archives/07-15-2002.shtml 184 | 185 | 186 | #### XorShift 187 | 188 | A random number generator of the type LFSR (linear feedback shift registers). This specific implementation uses the 189 | XorShift+ variation, and returns 64-bit random numbers. 190 | 191 | More information can be found here: 192 | 193 | https://en.wikipedia.org/wiki/Xorshift 194 | 195 | 196 | 197 | rnd_pcg_seed 198 | ------------ 199 | 200 | void rnd_pcg_seed( rnd_pcg_t* pcg, RND_U32 seed ) 201 | 202 | Initialize a PCG generator with the specified seed. The generator is not valid until it's been seeded. 203 | 204 | 205 | rnd_pcg_next 206 | ------------ 207 | 208 | RND_U32 rnd_pcg_next( rnd_pcg_t* pcg ) 209 | 210 | Returns a random number N in the range: 0 <= N <= 0xffffffff, from the specified PCG generator. 211 | 212 | 213 | rnd_pcg_nextf 214 | ------------- 215 | 216 | float rnd_pcg_nextf( rnd_pcg_t* pcg ) 217 | 218 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified PCG generator. 219 | 220 | 221 | rnd_pcg_range 222 | ------------- 223 | 224 | int rnd_pcg_range( rnd_pcg_t* pcg, int min, int max ) 225 | 226 | Returns a random integer N in the range: min <= N <= max, from the specified PCG generator. 227 | 228 | 229 | rnd_well_seed 230 | ------------- 231 | 232 | void rnd_well_seed( rnd_well_t* well, RND_U32 seed ) 233 | 234 | Initialize a WELL generator with the specified seed. The generator is not valid until it's been seeded. 235 | 236 | 237 | rnd_well_next 238 | ------------- 239 | 240 | RND_U32 rnd_well_next( rnd_well_t* well ) 241 | 242 | Returns a random number N in the range: 0 <= N <= 0xffffffff, from the specified WELL generator. 243 | 244 | 245 | rnd_well_nextf 246 | -------------- 247 | float rnd_well_nextf( rnd_well_t* well ) 248 | 249 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified WELL generator. 250 | 251 | 252 | rnd_well_range 253 | -------------- 254 | 255 | int rnd_well_range( rnd_well_t* well, int min, int max ) 256 | 257 | Returns a random integer N in the range: min <= N <= max, from the specified WELL generator. 258 | 259 | 260 | rnd_gamerand_seed 261 | ----------------- 262 | 263 | void rnd_gamerand_seed( rnd_gamerand_t* gamerand, RND_U32 seed ) 264 | 265 | Initialize a GameRand generator with the specified seed. The generator is not valid until it's been seeded. 266 | 267 | 268 | rnd_gamerand_next 269 | ----------------- 270 | 271 | RND_U32 rnd_gamerand_next( rnd_gamerand_t* gamerand ) 272 | 273 | Returns a random number N in the range: 0 <= N <= 0xffffffff, from the specified GameRand generator. 274 | 275 | 276 | rnd_gamerand_nextf 277 | ------------------ 278 | 279 | float rnd_gamerand_nextf( rnd_gamerand_t* gamerand ) 280 | 281 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified GameRand generator. 282 | 283 | 284 | rnd_gamerand_range 285 | ------------------ 286 | 287 | int rnd_gamerand_range( rnd_gamerand_t* gamerand, int min, int max ) 288 | 289 | Returns a random integer N in the range: min <= N <= max, from the specified GameRand generator. 290 | 291 | 292 | rnd_xorshift_seed 293 | ----------------- 294 | 295 | void rnd_xorshift_seed( rnd_xorshift_t* xorshift, RND_U64 seed ) 296 | 297 | Initialize a XorShift generator with the specified seed. The generator is not valid until it's been seeded. 298 | 299 | 300 | rnd_xorshift_next 301 | ----------------- 302 | 303 | RND_U64 rnd_xorshift_next( rnd_xorshift_t* xorshift ) 304 | 305 | Returns a random number N in the range: 0 <= N <= 0xffffffffffffffff, from the specified XorShift generator. 306 | 307 | 308 | rnd_xorshift_nextf 309 | ------------------ 310 | 311 | float rnd_xorshift_nextf( rnd_xorshift_t* xorshift ) 312 | 313 | Returns a random float X in the range: 0.0f <= X < 1.0f, from the specified XorShift generator. 314 | 315 | 316 | rnd_xorshift_range 317 | ------------------ 318 | 319 | int rnd_xorshift_range( rnd_xorshift_t* xorshift, int min, int max ) 320 | 321 | Returns a random integer N in the range: min <= N <= max, from the specified XorShift generator. 322 | 323 | 324 | */ 325 | 326 | 327 | /* 328 | ---------------------- 329 | IMPLEMENTATION 330 | ---------------------- 331 | */ 332 | 333 | #ifdef RND_IMPLEMENTATION 334 | #undef RND_IMPLEMENTATION 335 | 336 | // Convert a randomized RND_U32 value to a float value x in the range 0.0f <= x < 1.0f. Contributed by Jonatan Hedborg 337 | static float rnd_internal_float_normalized_from_u32( RND_U32 value ) 338 | { 339 | RND_U32 exponent = 127; 340 | RND_U32 mantissa = value >> 9; 341 | RND_U32 result = ( exponent << 23 ) | mantissa; 342 | float fresult = *(float*)( &result ); 343 | return fresult - 1.0f; 344 | } 345 | 346 | 347 | static RND_U32 rnd_internal_murmur3_avalanche32( RND_U32 h ) 348 | { 349 | h ^= h >> 16; 350 | h *= 0x85ebca6b; 351 | h ^= h >> 13; 352 | h *= 0xc2b2ae35; 353 | h ^= h >> 16; 354 | return h; 355 | } 356 | 357 | 358 | static RND_U64 rnd_internal_murmur3_avalanche64( RND_U64 h ) 359 | { 360 | h ^= h >> 33; 361 | h *= 0xff51afd7ed558ccd; 362 | h ^= h >> 33; 363 | h *= 0xc4ceb9fe1a85ec53; 364 | h ^= h >> 33; 365 | return h; 366 | } 367 | 368 | 369 | void rnd_pcg_seed( rnd_pcg_t* pcg, RND_U32 seed ) 370 | { 371 | RND_U64 value = ( ( (RND_U64) seed ) << 1ULL ) | 1ULL; 372 | value = rnd_internal_murmur3_avalanche64( value ); 373 | pcg->state[ 0 ] = 0U; 374 | pcg->state[ 1 ] = ( value << 1ULL ) | 1ULL; 375 | rnd_pcg_next( pcg ); 376 | pcg->state[ 0 ] += rnd_internal_murmur3_avalanche64( value ); 377 | rnd_pcg_next( pcg ); 378 | } 379 | 380 | 381 | RND_U32 rnd_pcg_next( rnd_pcg_t* pcg ) 382 | { 383 | RND_U64 oldstate = pcg->state[ 0 ]; 384 | pcg->state[ 0 ] = oldstate * 0x5851f42d4c957f2dULL + pcg->state[ 1 ]; 385 | RND_U32 xorshifted = (RND_U32)( ( ( oldstate >> 18ULL) ^ oldstate ) >> 27ULL ); 386 | RND_U32 rot = (RND_U32)( oldstate >> 59ULL ); 387 | return ( xorshifted >> rot ) | ( xorshifted << ( ( -(int) rot ) & 31 ) ); 388 | } 389 | 390 | 391 | float rnd_pcg_nextf( rnd_pcg_t* pcg ) 392 | { 393 | return rnd_internal_float_normalized_from_u32( rnd_pcg_next( pcg ) ); 394 | } 395 | 396 | 397 | int rnd_pcg_range( rnd_pcg_t* pcg, int min, int max ) 398 | { 399 | int const range = ( max - min ) + 1; 400 | if( range <= 0 ) return min; 401 | int const value = (int) ( rnd_pcg_nextf( pcg ) * range ); 402 | return min + value; 403 | } 404 | 405 | 406 | void rnd_well_seed( rnd_well_t* well, RND_U32 seed ) 407 | { 408 | RND_U32 value = rnd_internal_murmur3_avalanche32( ( seed << 1U ) | 1U ); 409 | well->state[ 16 ] = 0; 410 | well->state[ 0 ] = value ^ 0xf68a9fc1U; 411 | for( int i = 1; i < 16; ++i ) 412 | well->state[ i ] = ( 0x6c078965U * ( well->state[ i - 1 ] ^ ( well->state[ i - 1 ] >> 30 ) ) + i ); 413 | } 414 | 415 | 416 | RND_U32 rnd_well_next( rnd_well_t* well ) 417 | { 418 | RND_U32 a = well->state[ well->state[ 16 ] ]; 419 | RND_U32 c = well->state[ ( well->state[ 16 ] + 13 ) & 15 ]; 420 | RND_U32 b = a ^ c ^ ( a << 16 ) ^ ( c << 15 ); 421 | c = well->state[ ( well->state[ 16 ] + 9 ) & 15 ]; 422 | c ^= ( c >> 11 ); 423 | a = well->state[ well->state[ 16 ] ] = b ^ c; 424 | RND_U32 d = a ^ ( ( a << 5 ) & 0xda442d24U ); 425 | well->state[ 16 ] = (well->state[ 16 ] + 15 ) & 15; 426 | a = well->state[ well->state[ 16 ] ]; 427 | well->state[ well->state[ 16 ] ] = a ^ b ^ d ^ ( a << 2 ) ^ ( b << 18 ) ^ ( c << 28 ); 428 | return well->state[ well->state[ 16 ] ]; 429 | } 430 | 431 | 432 | float rnd_well_nextf( rnd_well_t* well ) 433 | { 434 | return rnd_internal_float_normalized_from_u32( rnd_well_next( well ) ); 435 | } 436 | 437 | 438 | int rnd_well_range( rnd_well_t* well, int min, int max ) 439 | { 440 | int const range = ( max - min ) + 1; 441 | if( range <= 0 ) return min; 442 | int const value = (int) ( rnd_well_nextf( well ) * range ); 443 | return min + value; 444 | } 445 | 446 | 447 | void rnd_gamerand_seed( rnd_gamerand_t* gamerand, RND_U32 seed ) 448 | { 449 | RND_U32 value = rnd_internal_murmur3_avalanche32( ( seed << 1U ) | 1U ); 450 | gamerand->state[ 0 ] = value; 451 | gamerand->state[ 1 ] = value ^ 0x49616e42U; 452 | } 453 | 454 | 455 | RND_U32 rnd_gamerand_next( rnd_gamerand_t* gamerand ) 456 | { 457 | gamerand->state[ 0 ] = ( gamerand->state[ 0 ] << 16 ) + ( gamerand->state[ 0 ] >> 16 ); 458 | gamerand->state[ 0 ] += gamerand->state[ 1 ]; 459 | gamerand->state[ 1 ] += gamerand->state[ 0 ]; 460 | return gamerand->state[ 0 ]; 461 | } 462 | 463 | 464 | float rnd_gamerand_nextf( rnd_gamerand_t* gamerand ) 465 | { 466 | return rnd_internal_float_normalized_from_u32( rnd_gamerand_next( gamerand ) ); 467 | } 468 | 469 | 470 | int rnd_gamerand_range( rnd_gamerand_t* gamerand, int min, int max ) 471 | { 472 | int const range = ( max - min ) + 1; 473 | if( range <= 0 ) return min; 474 | int const value = (int) ( rnd_gamerand_nextf( gamerand ) * range ); 475 | return min + value; 476 | } 477 | 478 | 479 | void rnd_xorshift_seed( rnd_xorshift_t* xorshift, RND_U64 seed ) 480 | { 481 | RND_U64 value = rnd_internal_murmur3_avalanche64( ( seed << 1ULL ) | 1ULL ); 482 | xorshift->state[ 0 ] = value; 483 | value = rnd_internal_murmur3_avalanche64( value ); 484 | xorshift->state[ 1 ] = value; 485 | } 486 | 487 | 488 | RND_U64 rnd_xorshift_next( rnd_xorshift_t* xorshift ) 489 | { 490 | RND_U64 x = xorshift->state[ 0 ]; 491 | RND_U64 const y = xorshift->state[ 1 ]; 492 | xorshift->state[ 0 ] = y; 493 | x ^= x << 23; 494 | x ^= x >> 17; 495 | x ^= y ^ ( y >> 26 ); 496 | xorshift->state[ 1 ] = x; 497 | return x + y; 498 | } 499 | 500 | 501 | float rnd_xorshift_nextf( rnd_xorshift_t* xorshift ) 502 | { 503 | return rnd_internal_float_normalized_from_u32( (RND_U32)( rnd_xorshift_next( xorshift ) >> 32 ) ); 504 | } 505 | 506 | 507 | int rnd_xorshift_range( rnd_xorshift_t* xorshift, int min, int max ) 508 | { 509 | int const range = ( max - min ) + 1; 510 | if( range <= 0 ) return min; 511 | int const value = (int) ( rnd_xorshift_nextf( xorshift ) * range ); 512 | return min + value; 513 | } 514 | 515 | 516 | 517 | #endif /* RND_IMPLEMENTATION */ 518 | 519 | /* 520 | 521 | contributors: 522 | Jonatan Hedborg (unsigned int to normalized float conversion) 523 | 524 | revision history: 525 | 1.0 first publicly released version 526 | */ 527 | 528 | /* 529 | ------------------------------------------------------------------------------ 530 | 531 | This software is available under 2 licenses - you may choose the one you like. 532 | Based on public domain implementation - original licenses can be found next to 533 | the relevant implementation sections of this file. 534 | 535 | ------------------------------------------------------------------------------ 536 | 537 | ALTERNATIVE A - MIT License 538 | 539 | Copyright (c) 2016 Mattias Gustavsson 540 | 541 | Permission is hereby granted, free of charge, to any person obtaining a copy of 542 | this software and associated documentation files (the "Software"), to deal in 543 | the Software without restriction, including without limitation the rights to 544 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 545 | of the Software, and to permit persons to whom the Software is furnished to do 546 | so, subject to the following conditions: 547 | 548 | The above copyright notice and this permission notice shall be included in all 549 | copies or substantial portions of the Software. 550 | 551 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 552 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 553 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 554 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 555 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 556 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 557 | SOFTWARE. 558 | 559 | ------------------------------------------------------------------------------ 560 | 561 | ALTERNATIVE B - Public Domain (www.unlicense.org) 562 | 563 | This is free and unencumbered software released into the public domain. 564 | 565 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 566 | software, either in source code form or as a compiled binary, for any purpose, 567 | commercial or non-commercial, and by any means. 568 | 569 | In jurisdictions that recognize copyright laws, the author or authors of this 570 | software dedicate any and all copyright interest in the software to the public 571 | domain. We make this dedication for the benefit of the public at large and to 572 | the detriment of our heirs and successors. We intend this dedication to be an 573 | overt act of relinquishment in perpetuity of all present and future rights to 574 | this software under copyright law. 575 | 576 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 577 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 578 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 579 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 580 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 581 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 582 | 583 | ------------------------------------------------------------------------------ 584 | */ --------------------------------------------------------------------------------