├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── c-cpp.yml ├── .gitignore ├── LICENSE ├── Readme.md ├── apg ├── apg.h ├── build.sh ├── build_msvc.bat └── tests │ ├── algo_comp.c │ ├── anton_256.bmp │ ├── apg.c │ ├── blobs.bmp │ ├── cpptest.cpp │ ├── dir_list.c │ ├── example_output_maze_128.png │ ├── example_output_maze_32.png │ ├── example_output_maze_64.png │ ├── greedy_test.c │ ├── hash_test.c │ ├── is_file.c │ ├── make_big_file.c │ ├── maze_128.png │ ├── maze_32.png │ ├── maze_64.png │ ├── rand_r_test.c │ ├── rle_compress.c │ ├── rle_test.c │ ├── test.c │ ├── test_big_file.c │ ├── test_file.txt │ ├── two.c │ └── two.h ├── apg_bmp ├── apg_bmp.c ├── apg_bmp.h ├── build.bat ├── build.sh ├── test_code │ ├── main_read.c │ └── main_write.c ├── test_images │ ├── 13b.bmp │ ├── 14b.bmp │ ├── 1kb.bmp │ ├── 2x2_mono.bmp │ ├── 4x4_mono.bmp │ ├── 53b.bmp │ ├── 5x5_mono.bmp │ ├── 64b.bmp │ ├── alpha.bmp │ ├── anton_16colour.bmp │ ├── anton_24bpp.bmp │ ├── anton_256.bmp │ ├── anton_32bpp_alpha.bmp │ ├── anton_mono.bmp │ ├── blobs.bmp │ ├── blobs_alpha.bmp │ └── storm.bmp └── tests_fuzzing │ ├── fuzz_24bpp.sh │ ├── fuzz_32bpp.sh │ ├── fuzz_main.c │ └── fuzzing_inputs │ ├── 24bpp │ ├── a.bmp │ ├── b.bmp │ ├── c.bmp │ ├── d.bmp │ ├── e.bmp │ ├── f.bmp │ ├── g.bmp │ ├── h.bmp │ ├── i.bmp │ ├── j.bmp │ ├── k.bmp │ ├── l.bmp │ ├── long.bmp │ ├── m.bmp │ ├── n.bmp │ ├── o.bmp │ └── tall.bmp │ └── 32bpp │ ├── a.bmp │ ├── b.bmp │ ├── c.bmp │ ├── d.bmp │ ├── e.bmp │ ├── f.bmp │ ├── g.bmp │ ├── h.bmp │ ├── i.bmp │ ├── j.bmp │ ├── k.bmp │ ├── l.bmp │ ├── long.bmp │ ├── m.bmp │ ├── n.bmp │ ├── o.bmp │ └── tall.bmp ├── apg_console ├── apg_console.c ├── apg_console.h ├── build.bat ├── build.sh └── tests │ └── main.c ├── apg_gldb ├── README.md ├── apg_gldb.c ├── apg_gldb.h ├── chunks.jpeg ├── screenshot.png ├── screenshot2.png ├── screenshot3.png └── screenshot4.png ├── apg_interp ├── README.md ├── accel_exp.png ├── accel_sine.png ├── apg_interp.h ├── build.sh ├── decel_bounce.png ├── decel_elastic.png ├── decel_sine.png ├── interp.js ├── linear.png └── tests │ └── test.c ├── apg_jobs ├── apg_jobs.c ├── apg_jobs.h ├── build.sh ├── build_msvc_dll.bat ├── build_msvc_test_program.bat └── tests │ └── main.c ├── apg_maths ├── README.md ├── apg_maths.c ├── apg_maths.h ├── apg_maths.js ├── build.sh └── tests │ ├── build_msvc.bat │ └── test.c ├── apg_mod ├── apg_mod.c ├── apg_mod.h ├── build.sh └── tests │ ├── dump_wavs.c │ └── print_tracks.c ├── apg_pixfont ├── apg_pixfont.c ├── apg_pixfont.h ├── build.bat ├── build.sh ├── build │ └── PLACEHOLDER.txt ├── pixfont.png ├── tests │ └── test_pixfont.cpp └── utils │ ├── bake_font_array.c │ └── create_atlas.c ├── apg_plot ├── apg_plot.c └── apg_plot.h ├── apg_tga ├── 02_rainbow.tga ├── 02_write_ppm.tga ├── apg_tga.h ├── build.bat ├── build.sh ├── palette.tga └── test_code │ ├── main_read.c │ └── main_write.c ├── apg_unicode ├── apg_unicode.c ├── apg_unicode.h ├── build.sh └── tests │ ├── main.c │ └── test.txt ├── apg_wav ├── apg_wav.c ├── apg_wav.h ├── build.sh ├── examples │ ├── main_play_file.c │ └── main_visualise.c └── tests │ ├── main_read.c │ └── main_write.c ├── build_linux.sh └── third_party ├── portaudio ├── LICENSE.txt ├── bin │ └── libportaudio-x86_64-w64-mingw32.static.dll └── include │ ├── pa_asio.h │ ├── pa_jack.h │ ├── pa_linux_alsa.h │ ├── pa_mac_core.h │ ├── pa_win_ds.h │ ├── pa_win_wasapi.h │ ├── pa_win_waveformat.h │ ├── pa_win_wdmks.h │ ├── pa_win_wmme.h │ └── portaudio.h └── stb ├── stb_image.h └── stb_image_write.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: '0' 3 | AlignAfterOpenBracket: DontAlign 4 | AlignConsecutiveAssignments: 'true' 5 | AlignOperands: 'true' 6 | AlignTrailingComments: 'true' 7 | AllowShortBlocksOnASingleLine: 'true' 8 | AllowShortCaseLabelsOnASingleLine: 'true' 9 | AllowShortFunctionsOnASingleLine: All 10 | AllowShortIfStatementsOnASingleLine: 'true' 11 | AllowShortLoopsOnASingleLine: 'true' 12 | AlwaysBreakBeforeMultilineStrings: 'true' 13 | BinPackArguments: 'true' 14 | BinPackParameters: 'true' 15 | BreakBeforeBraces: Attach 16 | ColumnLimit: '160' 17 | ContinuationIndentWidth: '2' 18 | IndentCaseLabels: 'false' 19 | IndentWidth: '2' 20 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 21 | Language: Cpp 22 | MaxEmptyLinesToKeep: '1' 23 | NamespaceIndentation: None 24 | PenaltyBreakBeforeFirstCallParameter: '1' 25 | PenaltyBreakComment: '5' 26 | PenaltyBreakString: '10' 27 | PenaltyExcessCharacter: '1' 28 | PenaltyReturnTypeOnItsOwnLine: '1' 29 | PointerAlignment: Left 30 | SortIncludes: 'false' 31 | SpacesBeforeTrailingComments: '1' 32 | SpacesInCStyleCastParentheses: 'false' 33 | SpacesInParentheses: 'true' 34 | TabWidth: '2' 35 | 36 | ... 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: build 17 | run: bash ./build_linux.sh 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #projects 2 | .vscode/ 3 | #compilers and linkers 4 | *.o 5 | *.s 6 | *.exp 7 | #runtime generated 8 | apg.log 9 | *.wav 10 | out.* 11 | apg_console/apg_pixfont.c 12 | apg_console/apg_pixfont.h 13 | apg_console/testoutput.png 14 | apg_console/testuserenteredtext.png 15 | apg_bmp/tests_fuzzing/fuzz_24bpp_outputs/ 16 | apg_bmp/tests_fuzzing/fuzz_32bpp_outputs/ 17 | #binaries 18 | a.out 19 | *.dll 20 | *.dylib 21 | *.7z 22 | *.zip 23 | *.exe 24 | *.bin 25 | *.sav 26 | *.lib 27 | *.obj 28 | *.mod 29 | *.s3m 30 | *.xm 31 | *.dat 32 | *.rle 33 | apg_bmp/test_read_bmp 34 | apg_bmp/test_write_bmp 35 | apg_bmp/tests_fuzzing/fuzz_24bpp 36 | apg_bmp/tests_fuzzing/fuzz_32bpp 37 | apg_tga/test_read_tga 38 | apg_tga/test_write_tga 39 | #working test data 40 | apg_pixfont/0.png 41 | apg_pixfont/1.png 42 | apg_pixfont/2.png 43 | apg_pixfont/3.png 44 | apg_pixfont/4.png 45 | apg_pixfont/6.png 46 | apg_pixfont/5.png 47 | apg_pixfont/7.png 48 | apg_pixfont/utils/code.c 49 | apg_pixfont/tests/0.png 50 | apg_pixfont/tests/1.png 51 | apg_pixfont/tests/2.png 52 | apg_pixfont/tests/3.png 53 | apg_pixfont/tests/4.png 54 | apg_pixfont/tests/5.png 55 | apg_pixfont/tests/6.png 56 | apg_pixfont/tests/7.png 57 | apg/tests/anton_24bpp.bmp 58 | apg/tests/anton2022.sav 59 | apg_bmp/test_images/ 60 | apg_maths/tests/tmp/ 61 | apg_mod/*.raw 62 | apg_mod/*.mp3 63 | *Tutorial.txt 64 | apg/tests/out_path.png 65 | output_black.png 66 | output_white.png 67 | apg/tests/x.png 68 | apg_wav/out_vis.png 69 | apg_wav/out_vis2.png 70 | apg/apg.h 71 | apg/tests/rle_compress.c 72 | apg/tests/test_rand_r 73 | apg_pixfont/utils/atlas.bmp 74 | apg_pixfont/utils/atlas.png 75 | apg_pixfont/utils/atlas_italic.png 76 | apg_pixfont/utils/atlas_bold.png 77 | apg_pixfont/utils/atlas_underline.png 78 | apg_pixfont/utils/atlas_strikethrough.png 79 | apg_pixfont/atlas_bold.png 80 | apg_pixfont/atlas_italic.png 81 | apg_pixfont/atlas_strikethrough.png 82 | apg_pixfont/atlas_underline.png 83 | apg_pixfont/atlas.png 84 | apg_pixfont/8.png 85 | apg_pixfont/9.png 86 | apg_pixfont/10.png 87 | apg_pixfont/11.png 88 | apg_pixfont/12.png 89 | apg_pixfont/13.png 90 | apg_pixfont/14.png 91 | apg_pixfont/15.png 92 | apg_pixfont/16.png 93 | apg_pixfont/17.png 94 | apg_pixfont/18.png 95 | apg_pixfont/19.png 96 | apg_pixfont/20.png 97 | apg_pixfont/21.png 98 | apg_pixfont/22.png 99 | apg_pixfont/23.png 100 | apg_pixfont/24.png 101 | apg_pixfont/25.png 102 | apg_pixfont/26.png 103 | apg_pixfont/27.png 104 | apg_pixfont/28.png 105 | apg_pixfont/29.png 106 | apg_pixfont/30.png 107 | apg_pixfont/31.png 108 | apg_pixfont/32.png 109 | apg_pixfont/33.png 110 | apg_pixfont/34.png 111 | apg_pixfont/35.png 112 | apg_pixfont/36.png 113 | apg_pixfont/37.png 114 | apg_pixfont/38.png 115 | apg_pixfont/39.png 116 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------- 2 | This software is available under two licences - you may use it under either licence. 3 | ------------------------------------------------------------------------------------- 4 | FIRST LICENCE OPTION 5 | 6 | Apache License 7 | Version 2.0, January 2004 8 | http://www.apache.org/licenses/ 9 | Copyright 2019 Anton Gerdelan. 10 | Licensed under the Apache License, Version 2.0 (the "License"); 11 | you may not use this file except in compliance with the License. 12 | You may obtain a copy of the License at 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | Unless required by applicable law or agreed to in writing, software 15 | distributed under the License is distributed on an "AS IS" BASIS, 16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | See the License for the specific language governing permissions and 18 | limitations under the License. 19 | ------------------------------------------------------------------------------------- 20 | SECOND LICENCE OPTION 21 | 22 | Public Domain (www.unlicense.org) 23 | This is free and unencumbered software released into the public domain. 24 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 25 | software, either in source code form or as a compiled binary, for any purpose, 26 | commercial or non-commercial, and by any means. 27 | In jurisdictions that recognize copyright laws, the author or authors of this 28 | software dedicate any and all copyright interest in the software to the public 29 | domain. We make this dedication for the benefit of the public at large and to 30 | the detriment of our heirs and successors. We intend this dedication to be an 31 | overt act of relinquishment in perpetuity of all present and future rights to 32 | this software under copyright law. 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 37 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 38 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 39 | ------------------------------------------------------------------------------------- 40 | -------------------------------------------------------------------------------- /apg/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang -o test_rle_compress_file.bin tests/rle_compress.c -I ./ -Wall -Wextra -pedantic -fsanitize=address -g 3 | clang -o test_rle_string.bin tests/rle_test.c -I ./ -Wall -Wextra -pedantic -fsanitize=address -g 4 | clang -o test_hash.bin tests/hash_test.c -I ./ -Wall -Wextra -pedantic -fsanitize=address -g 5 | clang -o test_is_file.bin tests/is_file.c -I ./ -Wall -Wextra -pedantic -fsanitize=address -g 6 | clang -o test_dir_list.bin tests/dir_list.c -I ./ -Wall -Wextra -pedantic -fsanitize=address -g 7 | clang -o test_rand.bin tests/rand_r_test.c -I ./ -Wall -Wextra -pedantic -fsanitize=address -g 8 | -------------------------------------------------------------------------------- /apg/build_msvc.bat: -------------------------------------------------------------------------------- 1 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" 2 | 3 | REM "we recommend you compile by using either the /W3 or /W4 warning level" 4 | REM C4221 is nonstandard extension used in struct literals. 5 | REM C4996 is strdup -> _strdup deprecation warning 6 | set COMPILER_FLAGS=/W4 /D_CRT_SECURE_NO_WARNINGS /wd4221 /wd4996 /MTd 7 | REM set LIBS=imagehlp.lib 8 | 9 | set BUILD_DIR=".\build" 10 | if not exist %BUILD_DIR% mkdir %BUILD_DIR% 11 | pushd %BUILD_DIR% 12 | 13 | set I=/I ..\ ^ 14 | /I ..\tests\ 15 | 16 | REM ============================================================== 17 | REM HASH TEST 18 | REM ============================================================== 19 | set LINKER_FLAGS=/out:hash_test.exe 20 | set SRC=..\tests\hash_test.c 21 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 22 | 23 | REM ============================================================== 24 | REM GREEDY TEST 25 | REM ============================================================== 26 | set LINKER_FLAGS=/out:greedy_test.exe 27 | set SRC=..\tests\greedy_test.c 28 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 29 | 30 | REM ============================================================== 31 | REM MAKE BIG FILE 32 | REM ============================================================== 33 | set LINKER_FLAGS=/out:make_big_file.exe 34 | set SRC=..\tests\make_big_file.c 35 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 36 | 37 | REM ============================================================== 38 | REM BIG FILE TEST 39 | REM ============================================================== 40 | set LINKER_FLAGS=/out:bigfile_test.exe 41 | set SRC=..\tests\test_big_file.c 42 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 43 | 44 | REM ============================================================== 45 | REM IS FILE TEST 46 | REM ============================================================== 47 | set LINKER_FLAGS=/out:is_file_test.exe 48 | set SRC=..\tests\is_file.c 49 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 50 | 51 | REM ============================================================== 52 | REM IS FILE TEST 53 | REM ============================================================== 54 | set LINKER_FLAGS=/out:dir_list_test.exe 55 | set SRC=..\tests\dir_list.c 56 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 57 | 58 | REM ============================================================== 59 | REM RAND TEST 60 | REM ============================================================== 61 | set LINKER_FLAGS=/out:rand_test.exe 62 | set SRC=..\tests\rand_r_test.c 63 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 64 | 65 | pause 66 | -------------------------------------------------------------------------------- /apg/tests/anton_256.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/anton_256.bmp -------------------------------------------------------------------------------- /apg/tests/blobs.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/blobs.bmp -------------------------------------------------------------------------------- /apg/tests/cpptest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This test just makes sure a C++ compiler can compile with the apg.h code. 3 | 4 | Note that I cut out the implementation section from apg.h into apg.c to make this easier to compile, 5 | since the implementation is _not_ a valid C subset of C++, and cannot be compiled with a C++ compiler. 6 | 7 | COMPILE: 8 | ------------------- 9 | gcc -o apg.o -c .\apg.c -I .. -D APG_NO_BACKTRACES 10 | g++ -o cpptest cpptest.cpp apg.o -I .. 11 | */ 12 | 13 | #include "apg.h" // Don't do #define APG_IMPLEMENTATION since it isn't a C++ subset. 14 | 15 | #include 16 | 17 | int main() { 18 | apg_file_t record; 19 | bool cpp_found = apg_file_size( "cpptest.cpp" ); 20 | 21 | if ( cpp_found ) { 22 | std::cout << "Found `cpptest.cpp` in CWD!" << std::endl; 23 | } else { 24 | std::cout << "Did NOT find file `cpptest.cpp` in CWD!" << std::endl; 25 | } 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /apg/tests/dir_list.c: -------------------------------------------------------------------------------- 1 | #define APG_IMPLEMENTATION 2 | #define APG_NO_BACKTRACES 3 | #include "../apg.h" 4 | #include 5 | 6 | int main( int argc, char** argv ) { 7 | if ( argc < 2 ) { 8 | printf( "Usage: ./is_file PATH\n" ); 9 | return 0; 10 | } 11 | apg_dirent_t* list_ptr = NULL; 12 | int n_list = 0; 13 | bool res = apg_dir_contents( argv[1], &list_ptr, &n_list ); 14 | if ( !res ) { 15 | fprintf( stderr, "ERROR: reading directory %s\n", argv[1] ); 16 | return 1; 17 | } 18 | printf( "Contents of %s:\n", argv[1] ); 19 | for ( int i = 0; i < n_list; i++ ) { printf( "[%i] type=%i path=%s\n", i, list_ptr[i].type, list_ptr[i].path ); } 20 | 21 | res = apg_free_dir_contents_list( &list_ptr, n_list ); 22 | if ( !res ) { 23 | fprintf( stderr, "ERROR: freeing directory contents list.\n" ); 24 | return 1; 25 | } 26 | 27 | printf( "\nNormal exit\n" ); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /apg/tests/example_output_maze_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/example_output_maze_128.png -------------------------------------------------------------------------------- /apg/tests/example_output_maze_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/example_output_maze_32.png -------------------------------------------------------------------------------- /apg/tests/example_output_maze_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/example_output_maze_64.png -------------------------------------------------------------------------------- /apg/tests/greedy_test.c: -------------------------------------------------------------------------------- 1 | #define APG_NO_BACKTRACES 2 | #define APG_IMPLEMENTATION 3 | #include "apg.h" 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct node_t { 9 | int64_t key; 10 | int64_t h; 11 | int64_t neighbours[4]; 12 | int64_t n_neighbours; 13 | } node_t; 14 | 15 | // TODO(anton) generate a muuuuch larger set to test timing from top-left to bottom-right...somehow. maybe from an image where black pixels = no neighbour? 16 | 17 | node_t nodes[6] = { 18 | { .key = 0, .h = 100, .neighbours = { 1, 2, 3, 4 }, .n_neighbours = 4 }, // 19 | { .key = 1, .h = 75, .neighbours = { 0 }, .n_neighbours = 1 }, // 20 | { .key = 2, .h = 50, .neighbours = { 0 }, .n_neighbours = 1 }, // 21 | { .key = 3, .h = 66, .neighbours = { 0 }, .n_neighbours = 1 }, // 22 | { .key = 4, .h = 69, .neighbours = { 5 }, .n_neighbours = 1 }, // 23 | { .key = 5, .h = 0, .neighbours = { 4 }, .n_neighbours = 1 } // 24 | }; 25 | 26 | static int64_t _h_cb( int64_t key, int64_t target_key ) { 27 | (void)target_key; 28 | for ( int i = 0; i < 6; i++ ) { 29 | if ( key == nodes[i].key ) { return nodes[i].h; } 30 | } 31 | assert( false && "couldn't get h for key" ); 32 | return -1; 33 | } 34 | 35 | static int64_t _get_neighbours_cb( int64_t key, int64_t target_key, int64_t* neighs ) { 36 | (void)target_key; 37 | for ( int i = 0; i < 6; i++ ) { 38 | if ( key == nodes[i].key ) { 39 | memcpy( neighs, nodes[i].neighbours, sizeof( int64_t ) * nodes[i].n_neighbours ); 40 | return nodes[i].n_neighbours; 41 | } 42 | } 43 | assert( false && "couldn't get neighbour count" ); 44 | return -1; 45 | } 46 | 47 | #define N 1024 48 | 49 | apg_gbfs_node_t eval_ptr[512]; 50 | int64_t visited_ptr[512]; 51 | apg_gbfs_node_t queue_ptr[128]; 52 | 53 | int main() { 54 | int64_t reversed_path[2048], path_n = 0; 55 | apg_time_init(); 56 | double cumulative_time = 0.0; 57 | for ( int runi = 0; runi < N; runi++ ) { 58 | double start = apg_time_s(); 59 | bool ret = apg_gbfs( 0, 5, _h_cb, _get_neighbours_cb, reversed_path, &path_n, 2048LL, eval_ptr, 512LL, visited_ptr, 512LL, queue_ptr, 128LL ); 60 | double elapsed = apg_time_s() - start; 61 | cumulative_time += elapsed; 62 | if ( ret ) { 63 | printf( "FOUND PATH from keys 0 to 5 with %lli steps.\n", path_n ); 64 | for ( int64_t i = path_n - 1, j = 0; i >= 0; i--, j++ ) { printf( "%lli) key: %lli\n", j, reversed_path[i] ); } 65 | } else { 66 | printf( "NO PATH FOUND!\n" ); 67 | } 68 | printf( "Time elapsed in search: %lfms\n", elapsed * 1000.0 ); 69 | } 70 | printf( "Cumulative search time for %u searches %lfms\nAverage search time %lfms\n", N, cumulative_time * 1000.0, ( cumulative_time * 1000.0 ) / (double)N ); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /apg/tests/hash_test.c: -------------------------------------------------------------------------------- 1 | /* hash_test.h Test of hash functions from apg.h 2 | Author: Anton Gerdelan antongerdelan.net 3 | Language: C99 4 | */ 5 | 6 | #define APG_IMPLEMENTATION 7 | #define APG_NO_BACKTRACES 8 | #include "../apg.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #define N_STORE 666 14 | 15 | int main( void ) { 16 | printf( "===========================================\n" ); 17 | { 18 | apg_hash_table_t table = apg_hash_table_create( 128 ); 19 | if ( !table.list_ptr ) { return 1; } // OOM 20 | 21 | uint32_t collisions = 0; 22 | 23 | { // Storing random keys, collision test. 24 | 25 | #define SN 64 // hash table 4x the size of the items stored seems reasonable collision wise 26 | #define ASTRLENMAX 16 27 | 28 | // Commented the following line out so I can test for consistency between MSVC/gcc etc. 29 | // apg_srand( (uint32_t)time( NULL ) ); 30 | char values[SN][ASTRLENMAX]; 31 | for ( uint32_t i = 0; i < SN; i++ ) { 32 | // I use my own rand so i get consistent results on windows vs linux etc. 33 | for ( uint32_t j = 0; j < ASTRLENMAX - 1; j++ ) { values[i][j] = apg_rand() % 64 + 'A'; } 34 | values[i][ASTRLENMAX - 1] = 0; 35 | if ( !apg_hash_store( values[i], &values[i], &table, &collisions ) ) { 36 | printf( "ERROR: failed to store key %s in table with %u/%u entries.\n", values[i], table.count_stored, table.n ); 37 | if ( table.count_stored >= table.n ) { printf( " -> Hash table was full\n" ); } // set SN to bigger than 2048 to test this 38 | return 1; 39 | } 40 | } 41 | 42 | int anton_value = 666; 43 | { // Storing a few easily retrievable keys & search test 44 | if ( !apg_hash_store( "Anton Gerdelan", &anton_value, &table, &collisions ) ) { 45 | printf( "ERROR: failed to store key Anton Gerdelan in table with %u/%u entries.\n", table.count_stored, table.n ); 46 | if ( table.count_stored >= table.n ) { printf( " -> Hash table was full\n" ); } // set SN to bigger than 2048 to test this 47 | return 1; 48 | } 49 | if ( !apg_hash_store( "Anton2", &anton_value, &table, &collisions ) ) { 50 | printf( "ERROR: failed to store key Anton2 in table with %u/%u entries.\n", table.count_stored, table.n ); 51 | if ( table.count_stored >= table.n ) { printf( " -> Hash table was full\n" ); } // set SN to bigger than 2048 to test this 52 | return 1; 53 | } 54 | } 55 | 56 | // Test key already in table 57 | if ( !apg_hash_store( "Anton2", &anton_value, &table, &collisions ) ) { 58 | printf( "ERROR: failed to store key Anton2 in table with %u/%u entries.\n", table.count_stored, table.n ); 59 | if ( table.count_stored >= table.n ) { printf( " -> Hash table was full\n" ); } // set SN to bigger than 2048 to test this 60 | uint32_t search_idx = 0; 61 | if ( apg_hash_search( "Anton2", &table, &search_idx, &collisions ) ) { 62 | printf( " -> because key was already in the table at postion %u\n", search_idx ); 63 | } else { 64 | return 1; 65 | } 66 | } 67 | 68 | // print all table entries 69 | for ( uint32_t i = 0; i < table.n; i++ ) { 70 | if ( table.list_ptr[i].value_ptr ) { printf( "%u) key: %s. value_addr: %p\n", i, table.list_ptr[i].keystr, table.list_ptr[i].value_ptr ); } 71 | } 72 | printf( "String hash collisions=%u at capacity %u/%u (%.2f%%)\n", collisions, table.count_stored, table.n, (float)table.count_stored / (float)table.n ); 73 | } 74 | 75 | { // searching 76 | uint32_t search_idx = 0; 77 | if ( apg_hash_search( "Anton", &table, &search_idx, &collisions ) ) { 78 | printf( "ERROR search found non-existent key `Anton` at index %u\n", search_idx ); 79 | return 1; 80 | } 81 | if ( apg_hash_search( "Anton Gerdelan", &table, &search_idx, &collisions ) ) { printf( "search found `Anton Gerdelan` at index %u\n", search_idx ); } 82 | if ( apg_hash_search( "Anton2", &table, &search_idx, &collisions ) ) { printf( "search found `Anton2` at index %u\n", search_idx ); } 83 | } 84 | 85 | printf( "table cap %u/%u\n", table.count_stored, table.n ); 86 | // try auto-expand (should be right on the realloc point at 50%) 87 | if ( !apg_hash_auto_expand( &table, APG_GIGABYTES( 4 ) ) ) { 88 | printf( "ERROR: realloc failed1\n" ); 89 | return 1; 90 | } 91 | printf( "new table cap %u/%u\n", table.count_stored, table.n ); 92 | // try again - should do nothing 93 | if ( !apg_hash_auto_expand( &table, APG_GIGABYTES( 4 ) ) ) { 94 | printf( "ERROR: realloc failed2\n" ); 95 | return 1; 96 | } 97 | printf( "new table cap %u/%u\n", table.count_stored, table.n ); 98 | 99 | apg_hash_table_free( &table ); 100 | } 101 | 102 | printf( "Normal exit.\n" ); 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /apg/tests/is_file.c: -------------------------------------------------------------------------------- 1 | #define APG_IMPLEMENTATION 2 | #define APG_NO_BACKTRACES 3 | #include "../apg.h" 4 | #include 5 | 6 | int main( int argc, char** argv ) { 7 | if ( argc < 2 ) { 8 | printf( "Usage: ./is_file PATH\n" ); 9 | return 0; 10 | } 11 | bool is_file = apg_is_file( argv[1] ); 12 | bool is_dir = apg_is_dir( argv[1] ); 13 | 14 | printf( "Path `%s`\n is_file=%i\n is_dir =%i\n", argv[1], is_file, is_dir ); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /apg/tests/make_big_file.c: -------------------------------------------------------------------------------- 1 | // Simple program to generate a multi-GB file to use for testing. 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | FILE* f_ptr = fopen( "bigfile.dat", "wb" ); 8 | if ( !f_ptr ) { 9 | fprintf( stderr, "ERROR opening file for writing\n" ); 10 | return 1; 11 | } 12 | int n_gbs = 6; 13 | // Allocate 1GB 14 | size_t sz = 1024ULL * 1024ULL * 1024ULL; 15 | void* ptr = malloc( sz ); 16 | if ( !ptr ) { 17 | fprintf( stderr, "ERROR OOM\n" ); 18 | return 1; 19 | } 20 | // Write in smaller stages so Windows doesn't choke on an internal 2GB limit. 21 | for ( int i = 0; i < n_gbs; i++ ) { 22 | fprintf( stdout, "Writing %zu bytes... %i/%i\n", sz, i + 1, n_gbs ); 23 | size_t out = fwrite( ptr, sz, 1, f_ptr ); 24 | if ( 1 != out ) { 25 | fprintf( stderr, "ERROR writing file\n" ); 26 | return 1; 27 | } 28 | } 29 | fclose( f_ptr ); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /apg/tests/maze_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/maze_128.png -------------------------------------------------------------------------------- /apg/tests/maze_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/maze_32.png -------------------------------------------------------------------------------- /apg/tests/maze_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg/tests/maze_64.png -------------------------------------------------------------------------------- /apg/tests/rand_r_test.c: -------------------------------------------------------------------------------- 1 | #define APG_IMPLEMENTATION 2 | #define APG_NO_BACKTRACES 3 | #include "apg.h" 4 | #include 5 | #include 6 | 7 | int main() { 8 | apg_rand_t initial_seed = time( NULL ); // Equivalent to `srand( time( NULL ) );`. 9 | apg_rand_t working_seed = initial_seed; // In case we want to remember the original sequence start. 10 | printf( "Initial seed = %lu\n", initial_seed ); 11 | for ( int i = 0; i < 10; i++ ) { printf( "apg_rand_r returned %i\n", apg_rand_r( &working_seed ) ); } 12 | for ( int i = 0; i < 10; i++ ) { printf( "apg_randf_r returned %f\n", apg_randf_r( &working_seed ) ); } 13 | printf( "Working seed at exit = %lu\n", working_seed ); 14 | 15 | // These results should match the ones given by the above. 16 | apg_srand( initial_seed ); 17 | for ( int i = 0; i < 10; i++ ) { printf( "apg_rand returned %i\n", apg_rand() ); } 18 | for ( int i = 0; i < 10; i++ ) { printf( "apg_randf returned %f\n", apg_randf() ); } 19 | } 20 | -------------------------------------------------------------------------------- /apg/tests/rle_compress.c: -------------------------------------------------------------------------------- 1 | #define APG_IMPLEMENTATION 2 | #include "apg.h" 3 | #include 4 | #include 5 | 6 | typedef struct _entire_file_t { 7 | void* data; 8 | size_t sz; 9 | } _entire_file_t; 10 | 11 | static bool _read_entire_file( const char* filename, _entire_file_t* record ) { 12 | FILE* fp = fopen( filename, "rb" ); 13 | if ( !fp ) { return false; } 14 | fseek( fp, 0L, SEEK_END ); 15 | record->sz = (size_t)ftell( fp ); 16 | record->data = malloc( record->sz ); 17 | if ( !record->data ) { 18 | fclose( fp ); 19 | return false; 20 | } 21 | rewind( fp ); 22 | size_t nr = fread( record->data, record->sz, 1, fp ); 23 | fclose( fp ); 24 | if ( 1 != nr ) { return false; } 25 | return true; 26 | } 27 | 28 | int main( int argc, char** argv ) { 29 | if ( argc < 3 ) { 30 | printf( "usage: compress.exe myfile.bmp output.rle\n" ); 31 | return 0; 32 | } 33 | _entire_file_t record; 34 | if ( !_read_entire_file( argv[1], &record ) ) { 35 | printf( "error reading file %s\n", argv[1] ); 36 | return 1; 37 | } 38 | size_t out_sz; 39 | apg_rle_compress( record.data, record.sz, NULL, &out_sz ); 40 | printf( "record sz %i. compressed sz %i\n%.2f%% size when compressed\n", (int)record.sz, (int)out_sz, ( (float)out_sz / (float)record.sz ) * 100 ); 41 | uint8_t* out_ptr = malloc( out_sz ); 42 | apg_rle_compress( record.data, record.sz, out_ptr, &out_sz ); 43 | 44 | FILE* fptr = fopen( argv[2], "wb" ); 45 | if ( !fptr ) { 46 | printf( "error writing file %s\n", argv[2] ); 47 | return 1; 48 | } 49 | fwrite( out_ptr, out_sz, 1, fptr ); 50 | fclose( fptr ); 51 | 52 | free( out_ptr ); 53 | free( record.data ); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /apg/tests/rle_test.c: -------------------------------------------------------------------------------- 1 | #define APG_IMPLEMENTATION 2 | #include "apg.h" 3 | #include 4 | #include 5 | #include 6 | 7 | int main( void ) { 8 | const char* input_buffer = "ABBCCCDDDDEEEEEFFFFFFGGGGGGGHHHHHHHHIIIIIIIII"; 9 | char* decompressed_buffer = NULL; 10 | 11 | printf( "-------------compression-----------\n" ); 12 | size_t input_sz = strlen( input_buffer ) + 1; 13 | size_t compressed_sz = 0; 14 | apg_rle_compress( (uint8_t*)input_buffer, input_sz, NULL, &compressed_sz ); // +1 to include the \0 15 | char* compressed_buffer = malloc( compressed_sz ); 16 | apg_rle_compress( (uint8_t*)input_buffer, input_sz, (uint8_t*)compressed_buffer, &compressed_sz ); // +1 to include the \0 17 | printf( "input str: %s\noutput str: %s\n", input_buffer, compressed_buffer ); 18 | float pc = ( (float)compressed_sz / (float)input_sz ) * 100.0f; 19 | printf( "input len=%u\noutput len=%u\n%.2f%% of original size\n", (uint32_t)input_sz, (uint32_t)compressed_sz, pc ); 20 | 21 | printf( "-------------and decompression-----------\n" ); 22 | { 23 | size_t decompressed_sz = 0; 24 | apg_rle_decompress( (uint8_t*)compressed_buffer, compressed_sz, NULL, &decompressed_sz ); 25 | printf( "decompressed_sz=%u\n", (uint32_t)decompressed_sz ); 26 | decompressed_buffer = malloc( decompressed_sz ); 27 | apg_rle_decompress( (uint8_t*)compressed_buffer, compressed_sz, (uint8_t*)decompressed_buffer, &decompressed_sz ); 28 | printf( "decompressed buffer: %s\n", decompressed_buffer ); 29 | 30 | assert( strcmp( decompressed_buffer, input_buffer ) == 0 ); 31 | assert( decompressed_sz == input_sz ); 32 | 33 | free( decompressed_buffer ); 34 | } 35 | 36 | free( compressed_buffer ); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /apg/tests/test.c: -------------------------------------------------------------------------------- 1 | #include "two.h" 2 | #define APG_IMPLEMENTATION 3 | #include "apg.h" 4 | #include 5 | #include 6 | 7 | int main( int argc, char** argv ) { 8 | g_apg_argc = argc; 9 | g_apg_argv = argv; 10 | 11 | apg_time_init(); 12 | 13 | double T = 0.0; 14 | double prev = apg_time_s(); 15 | while ( T < 1.0 ) { 16 | double curr = apg_time_s(); 17 | double elapsed = curr - prev; 18 | prev = curr; 19 | T += elapsed; 20 | printf( "T= %lf\n", T ); 21 | } 22 | 23 | apg_start_log(); 24 | 25 | int pn = apg_check_param( "hello" ); 26 | printf( "the user param 'hello' was found at arg num %i (-1 indicates not found)\n", pn ); 27 | //if ( pn > 0 ) { return 0; } 28 | 29 | uint32_t uval = APG_MAX( 110, 120 ); 30 | printf( "uval = %u\n", uval ); 31 | apg_log( "the value was %u\n", uval ); 32 | 33 | uval = APG_CLAMP( uval, 11, 12 ); 34 | printf( "uval = %u\n", uval ); 35 | 36 | apg_log_err( "ERROR: this is a fake error log\n" ); 37 | 38 | two(); 39 | 40 | printf( "test exited normally\n" ); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /apg/tests/test_big_file.c: -------------------------------------------------------------------------------- 1 | // Test program to check if multi-GB files are read and addressed correctly on a particular platform. 2 | 3 | #define APG_NO_BACKTRACES 4 | #define APG_IMPLEMENTATION 5 | #include "../apg.h" 6 | 7 | int main() { 8 | apg_time_init(); 9 | 10 | // Test file size independently first. 11 | int64_t sz = apg_file_size( "bigfile.dat" ); 12 | printf( " apg_file_size() reports %lli bytes.\n", sz ); 13 | 14 | double start = apg_time_s(); 15 | 16 | apg_file_t record = ( apg_file_t ){ .sz = 0 }; 17 | if ( !apg_read_entire_file( "bigfile.dat", &record ) ) { 18 | fprintf( stderr, "ERROR: reading file \n" ); 19 | return 1; 20 | } 21 | 22 | double end = apg_time_s() - start; 23 | 24 | printf( "File size as long int is % li\n size as size_t is\t %zu\nSize of long is\t\t %zu\nSize of off_t is\t %zu\n", (long int)record.sz, record.sz, 25 | sizeof( long ), sizeof( off_t ) ); 26 | printf( "File read of size %zu was successful.\n", record.sz ); 27 | printf( "size of long long %zu\n", sizeof(long long int ) ); 28 | 29 | printf("File read took %lf seconds.\n", end ); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /apg/tests/test_file.txt: -------------------------------------------------------------------------------- 1 | first line in file 2 | second line in file 3 | -------------------------------------------------------------------------------- /apg/tests/two.c: -------------------------------------------------------------------------------- 1 | #include "two.h" 2 | #include "apg.h" // making sure it works when included in two files 3 | #include 4 | 5 | void two() { 6 | // open a file 7 | char buff[1024]; 8 | if ( !apg_file_to_str( "test_file.txt", 1024, buff ) ) { 9 | fprintf( stderr, "Couldn't find file test_file.txt\n" ); 10 | return; 11 | } 12 | printf( "file contents:\n[%s]\n", buff ); 13 | } 14 | -------------------------------------------------------------------------------- /apg/tests/two.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void two(); 4 | -------------------------------------------------------------------------------- /apg_bmp/apg_bmp.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | apg_bmp - A BMP File Reader/Writer Library 3 | ------------------------------------------------------------------------------- 4 | Original author: Anton Gerdelan 5 | Project URL: https://github.com/capnramses/apg 6 | Licence: See bottom of file. 7 | Language: C89 ( Implementation is C99 ) 8 | ------------------------------------------------------------------------------- 9 | 10 | Contributors 11 | ------------------------------------------------------------------------------- 12 | Anton Gerdelan - Initial code. 13 | Saija Sorsa - Fuzz testing. 14 | 15 | Instructions 16 | ------------------------------------------------------------------------------- 17 | - Just drop this header, and the matching .c file into your project. 18 | - If in a C++ project set these files to build as C, not C++. 19 | - To get debug printouts during parsing define APG_BMP_DEBUG_OUTPUT. 20 | 21 | Features 22 | ------------------------------------------------------------------------------- 23 | - Fast, simple, and supports more sub-formats than most BMP libraries. 24 | - The reader function is fuzzed with AFL https://lcamtuf.coredump.cx/afl/. 25 | - The reader is robust to large files and malformed files, and will, in some 26 | cases, return any valid partial data in an image. 27 | - Reader supports 32bpp (with alpha channel), 24bpp, 8bpp, 4bpp, and 1bpp 28 | monochrome BMP images. 29 | - Reader handles indexed BMP images using a colour palette. 30 | - Reader supports 8-bit and 4-bit RLE compression. 31 | - Writer supports 32bpp RGBA and 24bpp uncompressed RGB images. 32 | 33 | Current Limitations 34 | ------------------------------------------------------------------------------- 35 | - Because I don't have any samples to test on, the following are not supported: 36 | - 16-bit images. 37 | - Interleaved channel bit layouts; e.g. RGB101010 RGB555 RGB565. 38 | - Delta position escape codes in RLE. 39 | - Alpha channels are written in BITMAPINFOHEADER, which covers most cases, 40 | and supports older software. For wider alpha support in other apps the v5 41 | header could be used. 42 | - Gamma curves from v4 and v5 bitmap headers are ignored. 43 | - Maximum image dimensions are set to 65536*65536 as a safe maximum for 44 | interoperability with other software. See _BMP_MAX_DIMS to change this. 45 | - Images over 2GB are not supported, but could be by replacing ftell/fseek 46 | with platform-specific #ifdefs for 64-bit equivalents (ftello, stat, etc.). 47 | 48 | FAQ 49 | ------------------------------------------------------------------------------- 50 | Q. What makes this image loader special? Why would I use it? 51 | 52 | This library started as a curiosity project, to see if I could read really 53 | old BMP files, and understand the format. It was then used as an example for 54 | a security class learning fuzzing. Because it was fuzzed it was used in some 55 | very large projects as an image loader. There are many other BMP loaders, 56 | but this one is pretty small and fast, and can handle some very old formats 57 | that are not broadly supported. There is a blog post about it here: 58 | https://antongerdelan.net/blog/formatted/2020_03_24_apg_bmp.html 59 | 60 | Q. Why won't this compile in my C++ project? 61 | 62 | This is a C library, just make sure the apg_bmp.c file is set to compile as 63 | C, not C++. Then the compiled object file will compile in with your C++ 64 | program. 65 | 66 | Q. Are you open to pull requests? 67 | 68 | Yes, but it's not being actively worked on, so turn-around time may be slow. 69 | If the PR is accepted, I'll add you to the Contributors list. 70 | 71 | Welcome: Bug fixes, BMP feature-handling improvement. 72 | Not desired: Build systems, language & code style changes, large PRs. 73 | 74 | Version History 75 | ------------------------------------------------------------------------------- 76 | 3.4.0 - 2023 May. 31. 8-bit and 4-bit RLE compression support added. 77 | 3.3.1 - 2023 Feb. 1. Fixed type casting warnings from MSVC. 78 | 3.3 - 2023 Jan. 11. Fixed bug: images with alpha channel were y-flipped. 79 | 3.2 - 2022 Mar. 22. Minor signed/unsigned tweaks to constants. 80 | 3.1 - 2020 Mar. 18. 81 | \*****************************************************************************/ 82 | 83 | #ifndef APG_BMP_H_ 84 | #define APG_BMP_H_ 85 | 86 | #ifdef _WIN32 87 | /** Explicit symbol export for building .DLLs with MSVC so it generates a corresponding .LIB. */ 88 | #define APG_BMP_EXPORT __declspec( dllexport ) 89 | #else 90 | #define APG_BMP_EXPORT 91 | #endif 92 | 93 | #ifdef __cplusplus 94 | extern "C" { 95 | #endif /* CPP */ 96 | 97 | /** Reads a bitmap from a file, allocates memory for the raw image data, and returns it. 98 | * @param w,h Retrieves the width and height of the BMP in pixels. 99 | * @param n_chans Retrieves the number of channels in the BMP. 100 | * @returns Tightly-packed pixel memory in RGBA order. The caller must call free() on the memory. 101 | * NULL on any error. Any allocated memory is freed before returning NULL. 102 | */ 103 | APG_BMP_EXPORT unsigned char* apg_bmp_read( const char* filename, int* w, int* h, unsigned int* n_chans ); 104 | 105 | /** Calls free() on memory created by apg_bmp_read. */ 106 | APG_BMP_EXPORT void apg_bmp_free( unsigned char* pixels_ptr ); 107 | 108 | /** Writes a bitmap to a file. 109 | * @param filename e.g."my_bitmap.bmp". Must not be NULL. 110 | * @param pixels_ptr Pointer to tightly-packed pixel memory in RGBA order. Must not be NULL. 111 | * There must be abs(w)*abs(h)*n_chans bytes in the memory pointed to. 112 | * @param w,h Width and height of the image in pixels. 113 | * @param n_chans The number of channels in the BMP. 3 or 4 supported for writing, 114 | * which means RGB or RGBA memory, respectively. 115 | * @returns Zero on any error, non zero on success. 116 | */ 117 | APG_BMP_EXPORT unsigned int apg_bmp_write( const char* filename, unsigned char* pixels_ptr, int w, int h, unsigned int n_chans ); 118 | 119 | #ifdef __cplusplus 120 | } 121 | #endif /* CPP */ 122 | 123 | #endif /*_APG_BMP_H_ */ 124 | 125 | /* 126 | ------------------------------------------------------------------------------------- 127 | This software is available under two licences - you may use it under either licence. 128 | ------------------------------------------------------------------------------------- 129 | FIRST LICENCE OPTION 130 | 131 | > Apache License 132 | > Version 2.0, January 2004 133 | > http://www.apache.org/licenses/ 134 | > Copyright 2019-2023 Anton Gerdelan. 135 | > Licensed under the Apache License, Version 2.0 (the "License"); 136 | > you may not use this file except in compliance with the License. 137 | > You may obtain a copy of the License at 138 | > http://www.apache.org/licenses/LICENSE-2.0 139 | > Unless required by applicable law or agreed to in writing, software 140 | > distributed under the License is distributed on an "AS IS" BASIS, 141 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142 | > See the License for the specific language governing permissions and 143 | > limitations under the License. 144 | ------------------------------------------------------------------------------------- 145 | SECOND LICENCE OPTION 146 | 147 | > This is free and unencumbered software released into the public domain. 148 | > 149 | > Anyone is free to copy, modify, publish, use, compile, sell, or 150 | > distribute this software, either in source code form or as a compiled 151 | > binary, for any purpose, commercial or non-commercial, and by any 152 | > means. 153 | > 154 | > In jurisdictions that recognize copyright laws, the author or authors 155 | > of this software dedicate any and all copyright interest in the 156 | > software to the public domain. We make this dedication for the benefit 157 | > of the public at large and to the detriment of our heirs and 158 | > successors. We intend this dedication to be an overt act of 159 | > relinquishment in perpetuity of all present and future rights to this 160 | > software under copyright law. 161 | > 162 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 163 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 164 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 165 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 166 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 167 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 168 | > OTHER DEALINGS IN THE SOFTWARE. 169 | > 170 | > For more information, please refer to 171 | ------------------------------------------------------------------------------------- 172 | */ 173 | -------------------------------------------------------------------------------- /apg_bmp/build.bat: -------------------------------------------------------------------------------- 1 | REM building apg_bmp tests with clang.exe... 2 | gcc -g -Wall -Wextra -pedantic -o test_read_bmp.exe test_code/main_read.c -I . -I test_code/ -I ../third_party/stb/ apg_bmp.c -DAPG_BMP_DEBUG_OUTPUT 3 | gcc -g -Wall -Wextra -pedantic -o test_write_bmp.exe test_code/main_write.c -I . -I test_code/ -I ../third_party/stb/ apg_bmp.c -DAPG_BMP_DEBUG_OUTPUT 4 | pause 5 | -------------------------------------------------------------------------------- /apg_bmp/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang -fsanitize=address -fsanitize=undefined -g -Wall -Wextra -pedantic -o test_read_bmp.bin test_code/main_read.c apg_bmp.c -I./ -I test_code/ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 3 | clang -fsanitize=address -fsanitize=undefined -g -Wall -Wextra -pedantic -o test_write_bmp.bin test_code/main_write.c apg_bmp.c -I./ -I test_code/ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 4 | -------------------------------------------------------------------------------- /apg_bmp/test_code/main_read.c: -------------------------------------------------------------------------------- 1 | /* Test Read Program for apg_bmp 2 | Uses stb_image_write to write out a PNG to 'out.png' as proof. 3 | Anton Gerdelan 4 | */ 5 | 6 | #define STB_IMAGE_WRITE_IMPLEMENTATION 7 | #include "stb_image_write.h" // used for writing out file to check it worked 8 | #include "apg_bmp.h" 9 | #include 10 | #include 11 | 12 | int main( int argc, const char** argv ) { 13 | if ( argc < 2 ) { 14 | printf( "usage: ./test_readwrite_bmp INPUT.BMP\n" ); 15 | return 0; 16 | } 17 | printf( "Reading `%s`. Writing out.png\n", argv[1] ); 18 | int w = 0, h = 0; 19 | unsigned int n_chans = 0; 20 | unsigned char* img_mem = apg_bmp_read( argv[1], &w, &h, &n_chans ); 21 | if ( !img_mem ) { 22 | fprintf( stderr, "ERROR: failed to read image `%s`\n", argv[1] ); 23 | return 1; 24 | } 25 | 26 | if ( !stbi_write_png( "out.png", w, h, n_chans, img_mem, w * n_chans ) ) { 27 | fprintf( stderr, "ERROR: writing out PNG\n" ); 28 | return 1; 29 | } 30 | printf( "wrote image of w %u h %u n_chans %u\n", w, h, n_chans ); 31 | 32 | free( img_mem ); 33 | printf( "done\n" ); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /apg_bmp/test_code/main_write.c: -------------------------------------------------------------------------------- 1 | #include "apg_bmp.h" 2 | #include 3 | #include 4 | 5 | int main( int argc, char** argv ) { 6 | if ( argc < 3 ) { 7 | printf( "usage: ./readwrite input.bmp output.bmp\n" ); 8 | return 0; 9 | } 10 | 11 | printf( "reading `%s`\n", argv[1] ); 12 | 13 | int w = 0, h = 0; 14 | unsigned int n_chans = 0; 15 | unsigned char* img_ptr = apg_bmp_read( argv[1], &w, &h, &n_chans ); 16 | if ( !img_ptr ) { 17 | fprintf( stderr, "ERROR reading BMP\n" ); 18 | return 1; 19 | } 20 | 21 | printf( "read image\n|-w = %i\n|-h = %i\n|-n_chans = %u\n", w, h, n_chans ); 22 | 23 | printf( "writing `%s`\n", argv[2] ); 24 | if ( !apg_bmp_write( argv[2], img_ptr, w, h, n_chans ) ) { 25 | fprintf( stderr, "ERROR writing BMP\n" ); 26 | return 1; 27 | } 28 | 29 | apg_bmp_free( img_ptr ); 30 | 31 | printf( "wrote image file. program done\n" ); 32 | 33 | return 1; 34 | } 35 | -------------------------------------------------------------------------------- /apg_bmp/test_images/13b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/13b.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/14b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/14b.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/1kb.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/1kb.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/2x2_mono.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/2x2_mono.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/4x4_mono.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/4x4_mono.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/53b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/53b.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/5x5_mono.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/5x5_mono.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/64b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/64b.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/alpha.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/alpha.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/anton_16colour.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/anton_16colour.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/anton_24bpp.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/anton_24bpp.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/anton_256.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/anton_256.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/anton_32bpp_alpha.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/anton_32bpp_alpha.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/anton_mono.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/anton_mono.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/blobs.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/blobs.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/blobs_alpha.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/blobs_alpha.bmp -------------------------------------------------------------------------------- /apg_bmp/test_images/storm.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/test_images/storm.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzz_24bpp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BIN=fuzz_24bpp 3 | INDIR=fuzzing_inputs/24bpp 4 | OUTDIR=fuzz_24bpp_outputs 5 | 6 | #set up folders 7 | rm -f $BIN 8 | rm -rf $OUTDIR 9 | mkdir $OUTDIR 10 | 11 | #build for fuzzing 12 | afl-gcc -g -o $BIN fuzz_main.c ../apg_bmp.c -I ../ 13 | 14 | #run with fuzz 15 | AFL_EXIT_WHEN_DONE=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 16 | AFL_SKIP_CPUFREQ=1 afl-fuzz -i $INDIR/ -o $OUTDIR/ -- ./$BIN @@ 17 | -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzz_32bpp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BIN=fuzz_32bpp 3 | INDIR=fuzzing_inputs/32bpp 4 | OUTDIR=fuzz_32bpp_outputs 5 | 6 | #set up folders 7 | rm -f $BIN 8 | rm -rf $OUTDIR 9 | mkdir $OUTDIR 10 | 11 | #build for fuzzing 12 | afl-gcc -g -o $BIN fuzz_main.c ../apg_bmp.c -I ../ 13 | 14 | #run with fuzz 15 | AFL_EXIT_WHEN_DONE=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFL_SKIP_CPUFREQ=1 \ 16 | afl-fuzz -i $INDIR/ -o $OUTDIR/ -- ./$BIN @@ 17 | -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzz_main.c: -------------------------------------------------------------------------------- 1 | /* Test Read Program for apg_bmp -- for fuzzing tests 2 | Anton Gerdelan 3 | */ 4 | 5 | #include "apg_bmp.h" 6 | #include 7 | #include 8 | #include 9 | 10 | int main( int argc, const char** argv ) { 11 | if ( argc < 2 ) { 12 | printf( "usage: ./test_readwrite_bmp INPUT.BMP\n" ); 13 | return 0; 14 | } 15 | assert( argc > 1 ); 16 | int w = 0, h = 0, n_chans = 0; 17 | unsigned char* img_mem = apg_bmp_read( argv[1], &w, &h, &n_chans ); 18 | if ( !img_mem ) { 19 | fprintf( stderr, "ERROR: failed to read image `%s`\n", argv[1] ); 20 | return 1; 21 | } 22 | free( img_mem ); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/a.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/b.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/c.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/c.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/d.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/d.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/e.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/e.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/f.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/f.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/g.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/g.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/h.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/h.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/i.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/i.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/j.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/j.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/k.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/k.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/l.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/l.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/long.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/long.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/m.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/m.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/n.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/n.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/o.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/o.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/tall.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/24bpp/tall.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/a.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/a.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/b.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/b.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/c.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/c.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/d.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/d.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/e.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/e.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/f.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/f.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/g.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/g.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/h.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/h.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/i.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/i.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/j.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/j.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/k.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/k.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/l.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/l.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/long.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/long.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/m.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/m.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/n.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/n.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/o.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/o.bmp -------------------------------------------------------------------------------- /apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/tall.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_bmp/tests_fuzzing/fuzzing_inputs/32bpp/tall.bmp -------------------------------------------------------------------------------- /apg_console/build.bat: -------------------------------------------------------------------------------- 1 | set CC=gcc 2 | set CPP=g++ 3 | set LD=ld 4 | set FLAGS=-g -Wall -Wextra -pedantic -Werror 5 | REM SAN=-fsanitize=address -fsanitize=undefined 6 | 7 | cp ../apg_pixfont/apg_pixfont.c ./ 8 | cp ../apg_pixfont/apg_pixfont.h ./ 9 | 10 | %CC% %FLAGS% %SAN% tests/main.c apg_console.c apg_pixfont.c -I . 11 | -------------------------------------------------------------------------------- /apg_console/build.sh: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CPP=clang++ 3 | LD=ld 4 | FLAGS="-g -Wall -Wextra -pedantic -Werror" 5 | SAN="-fsanitize=address -fsanitize=undefined" 6 | 7 | cp ../apg_pixfont/apg_pixfont.c ./ 8 | cp ../apg_pixfont/apg_pixfont.h ./ 9 | cp ../apg_unicode/apg_unicode.c ./ 10 | cp ../apg_unicode/apg_unicode.h ./ 11 | 12 | $CC $FLAGS $SAN tests/main.c apg_console.c apg_pixfont.c apg_unicode.c -I ./ 13 | -------------------------------------------------------------------------------- /apg_console/tests/main.c: -------------------------------------------------------------------------------- 1 | // test program for apg_console 2 | // Anton Gerdelan 24 Mar 2020 3 | 4 | #include "apg_console.h" 5 | #include 6 | #include 7 | 8 | bool anton_func( const char* arg_str ) { 9 | printf( "the value given to anton_func was `%s`\n", arg_str ); 10 | return true; 11 | } 12 | 13 | int main( void ) { 14 | 15 | // resolving a prior bug where text wouldn't print until a \n was entered 16 | apg_c_append_user_entered_text( "does this print without a slash n?" ); 17 | apg_c_dump_to_stdout(); 18 | apg_c_append_user_entered_text("\n"); 19 | 20 | int anton_var = 666; 21 | apg_c_register_var( "anton_var", &anton_var, APG_C_INT32 ); 22 | apg_c_var_t* v_ptr = apg_c_get_var( "anton_var" ); 23 | printf( "var: `%s`. val: %i\n", v_ptr->str, *( (int*)v_ptr->var_ptr ) ); 24 | apg_c_register_func( "anton_func", anton_func ); 25 | 26 | apg_c_append_user_entered_text( "help\n" ); 27 | apg_c_dump_to_stdout(); 28 | apg_c_append_user_entered_text( "clear\n" ); 29 | apg_c_dump_to_stdout(); 30 | apg_c_append_user_entered_text( "list_vars\n" ); 31 | apg_c_output_clear(); 32 | apg_c_append_user_entered_text( "list_funcs\n" ); 33 | apg_c_printf( "a line I added" ); 34 | apg_c_printf( "another line I added" ); 35 | apg_c_dump_to_stdout(); 36 | apg_c_append_user_entered_text( "anton_func\n" ); 37 | apg_c_append_user_entered_text( "anton_func 123.456\n" ); 38 | if ( apg_c_image_redraw_required() ) { 39 | printf( "apg_c_image_redraw_required()=TRUE\n" ); 40 | } else { 41 | printf( "apg_c_image_redraw_required()=FALSE\n" ); 42 | } 43 | int w = 512; 44 | int h = 512; 45 | int n_channels = 3; 46 | uint8_t* img_ptr = malloc( w * h * n_channels ); 47 | uint8_t background_colour[] = {0xFF, 0xFF, 0x00, 0xFF}; 48 | apg_c_draw_to_image_mem( img_ptr, w, h, n_channels, background_colour ); // NOTE(Anton) img output would be nice but pulls another dependency into test app 49 | if ( apg_c_image_redraw_required() ) { 50 | printf( "apg_c_image_redraw_required()=TRUE\n" ); 51 | } else { 52 | printf( "apg_c_image_redraw_required()=FALSE\n" ); 53 | } 54 | apg_c_append_user_entered_text( "anton_f" ); 55 | apg_c_backspace(); 56 | apg_c_append_user_entered_text( "\n" ); // should output "ERROR" for "anton_" here in text (just testing backspace works) 57 | apg_c_dump_to_stdout(); 58 | apg_c_append_user_entered_text( "anton_f" ); 59 | apg_c_autocomplete(); 60 | apg_c_append_user_entered_text( "\n" ); 61 | apg_c_dump_to_stdout(); 62 | apg_c_reuse_hist( 1 ); 63 | free( img_ptr ); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /apg_gldb/README.md: -------------------------------------------------------------------------------- 1 | # apg_gldb: OpenGL Debug Drawing Functions 2 | 3 | ![screenshot of current features](screenshot2.png) 4 | 5 | My own spin on the drop-in code everyone does to draw lines and stuff to help 6 | debug vectors and things as they happen. 7 | 8 | Runs on most hardware supporting OpenGL 2.1 and newer. 9 | 10 | The code to draw normals and show the AABB in the screenshot above is: 11 | ``` 12 | // Debug mesh normals. 13 | float* pp = vp; 14 | float* nn = vn; 15 | float ss = 0.1f; 16 | float yellow[] = { 1.0f, 1.0f, 0.0f, 1.0f }; 17 | for ( int i = 0; i < point_count; i++ ) { 18 | apg_gldb_add_normal( nn, pp, ss, yellow ); 19 | pp += 3; 20 | nn += 3; 21 | } 22 | // Debug AABB. 23 | float white[] = { 1.0f, 1.0f, 1.0f, 1.0f }; 24 | float min_xyz[] = { -1.352f, -0.969f, -0.852f }; 25 | float max_xyz[] = { 1.352f, 0.93f, 0.836f }; 26 | apg_gldb_add_aabb( min_xyz, max_xyz, white ); 27 | ``` 28 | Where `ss` is the scale I want the lines for the normals to have, `vp` is the array of vertex points, and `vn` is the array of vertex normals. 29 | 30 | ## Stuff supported so far: 31 | 32 | ![screenshot of current features](screenshot4.png) 33 | 34 | * Accept camera matrices so line points are defaulted to world space. 35 | * 3D lines with colours. 36 | * Normals shown as 3D line starting at given 3D point, in normal direction for 37 | given scale, and coloured from black to colour in direction of normal. 38 | * 3D positions as a 3D t-shape sort of thing (lines). 39 | * Axis-aligned bounding box (lines). 40 | * Sphere represented as 3D cross and 3 circles of lines. 41 | * Draw a frustum box based on corner points. 42 | * Functions to modify previously created lines, AABB, and frustum. 43 | 44 | ## Design Thinking 45 | 46 | My thinking was to maintain one gigantic buffer with all of the lines 47 | points and colours. Then I can draw the entire lot in one pass. 48 | 49 | I don't have a ```remove_line()``` - you just wipe the whole lot arbitrarily. 50 | You can update previously added lines. 51 | 52 | ## Example Use-Case 53 | 54 | ![screenshot of current features](chunks.jpeg) 55 | 56 | I used this in a couple of projects to test frustum culling, where you can 'freeze' the camera, and draw the 57 | previous frustum as well as the bounds of objects used for culling. -------------------------------------------------------------------------------- /apg_gldb/apg_gldb.h: -------------------------------------------------------------------------------- 1 | /* 2 | OpenGL Debug Drawing Functions 3 | https://github.com/capnramses/opengl_debug_draw 4 | C89 interface, C99 implementation. 5 | Requires OpenGL 3.0 Core or newer, or an older version supporting ARB_vertex_array_object. 6 | Requires GLSL 1.2.0 or newer. 7 | Anton Gerdelan 8 | LICENCE - See bottom of this file. 9 | 10 | BUILD INSTRUCTIONS 11 | 1. Drop the .c and .h file into your project's source code. 12 | 2. Modify apg_gldb.c to include your OpenGL header. e.g. 13 | 14 | // #include "apg_glcontext.h" // REPLACE THIS INCLUDE WITH YOUR PROJECT'S OPENGL HEADER 15 | #include // Your header here. 16 | 17 | USAGE INSTRUCTIONS 18 | 1. #include "apg_db.h" 19 | 2. Call apg_gldb_init() before adding geometry, but after starting your window and OpenGL context. 20 | 3. Add line-based geometry with the apg_gldb_add_...() functions. 21 | 4. When drawing, update the camera matrix with apg_gldb_update_cam() and then call apg_gldb_draw(). 22 | 5. To modify lines call the corresponding apg_gldb_mod_...() functions. 23 | 6. Call apg_gldb_free() when done i.e. at the end of your program. 24 | 25 | HISTORY 26 | 0.4.1 - 2023/04/19 - Compiler warning tweaks. 27 | 0.4 - 18 May 2020 - const. 28 | 0.3 - 13 May 2020 - Tidied API and docs. Added _mod_ function for AABB and frustum. 29 | 0.2 - 16 Jun 2015 - Feature complete v. original spec. 30 | 0.1 - 11 Jun 2015 - First version. 31 | 32 | TODO 33 | - Recreate test/example program. 34 | - Add test build to CI/CD tests. 35 | */ 36 | 37 | #pragma once 38 | #include 39 | #include 40 | 41 | /* Memory is reserved to support this many lines at one time. */ 42 | #define APG_GLDB_MAX_LINES 10000 43 | 44 | /* Reserves memory for drawing and creates GPU resources. */ 45 | bool apg_gldb_init( void ); 46 | 47 | /* Frees all allocated memory and GPU resources. */ 48 | void apg_gldb_free( void ); 49 | 50 | /* Creates a new debug line in world coordinate space. 51 | PARAMS 52 | start_xyz, end_xyz - Arrays of 3 floats for positions of line ends in world space. 53 | colour_rgba - Colour to draw the line. 54 | RETURNS the line id. 55 | */ 56 | int apg_gldb_add_line( const float* start_xyz, const float* end_xyz, const float* colour_rgba ); 57 | 58 | /* Creates a line with a colour that goes from black to coloured in direction of a normal. 59 | PARAMS 60 | n_xyz - Array of 3 floats for direction of the normal in world space. 61 | pos_xyz - Position for to draw the base of the normal. 62 | scale - Length to draw the line representing the normal. 63 | colour_rgba - Colour to draw the line. 64 | RETURNS the line id. 65 | */ 66 | int apg_gldb_add_normal( const float* n_xyz, const float* pos_xyz, const float scale, const float* colour_rgba ); 67 | 68 | /* Creates 3 lines in a cross with a colour to show a position. 69 | RETURNS the first of 3 contiguous line ids. 70 | */ 71 | int apg_gldb_add_pos( const float* pos_xyz, const float scale, const float* colour_rgba ); 72 | 73 | /* Draws a box for this axis-aligned bounding box. 74 | PARAMS 75 | min_xyz - The minimum bounds (corner) for the box. 76 | max_xyz - The maximum bounds (corner) for the box. 77 | colour_rgba - Colour to render the lines. 78 | RETURNS the first of 12 contiguous line ids 79 | */ 80 | int apg_gldb_add_aabb( const float* min_xyz, const float* max_xyz, const float* colour_rgba ); 81 | 82 | /* Draws a circle+radius to represent a sphere. 83 | RETURNS the first of 39 line ids 84 | */ 85 | int apg_gldb_add_rad_circle( const float* centre_xyz, float radius, const float* colour_rgba ); 86 | 87 | /* Takes 8 xyz corner points for given camera frustum and draws a box whenever apg_gldb_draw() is called. 88 | Most camera code already extracts points from matrices so that is not repeated here. 89 | RETURNS first line's id. 90 | */ 91 | int apg_gldb_add_frustum( const float* ftl, const float* ftr, const float* fbl, const float* fbr, const float* ntl, const float* ntr, const float* nbl, 92 | const float* nbr, const float* colour_rgba ); 93 | 94 | /* Modify or move a line previously added. 95 | RETURNS false if line_id wasn't valid. 96 | */ 97 | bool apg_gldb_mod_line( uint32_t line_id, const float* start_xyz, const float* end_xyz, const float* colour_rgba ); 98 | 99 | /* Modify or move an axis-aligned bounding box previously added via apg_gldb_add_aabb(). 100 | PARAMS 101 | line_id - The value returned by apg_gldb_add_aabb(). 102 | min_xyz - New minimum bounds for the box. 103 | max_xyz - New maximum bounds for the box. 104 | colour_rgba - New colour to render the lines. 105 | RETURNS false if line_id wasn't valid. 106 | TODO(Anton) - the impl of this should modifier the buffer in one op, not individual calls to apg_gldb_mod_line(). 107 | */ 108 | bool apg_gldb_mod_aabb( uint32_t line_id, const float* min_xyz, const float* max_xyz, const float* colour_rgba ); 109 | 110 | bool apg_gldb_mod_frustum( uint32_t line_id, const float* ftl, const float* ftr, const float* fbl, const float* fbr, const float* ntl, const float* ntr, 111 | const float* nbl, const float* nbr, const float* colour_rgba ); 112 | 113 | /* Wipes all the lines for redrawing. Doesn't actually delete the buffer - call apg_gldb_free() do release allocated graphics resources. */ 114 | void apg_gldb_reset_lines( void ); 115 | 116 | /* Updates the camera matrix so that line points given are defined as being in world coordinate space. 117 | PARAMS 118 | matrix - A 16 float column-major matrix as 1D array in column order. 119 | */ 120 | void apg_gldb_update_cam( const float* PV_mat4 ); 121 | 122 | /* Draws the lines. 123 | PARAMS 124 | x_ray - If true then depth testing is disabled. 125 | */ 126 | void apg_gldb_draw( bool x_ray ); 127 | 128 | /* 129 | ------------------------------------------------------------------------------------- 130 | This software is available under two licences - you may use it under either licence. 131 | ------------------------------------------------------------------------------------- 132 | FIRST LICENCE OPTION 133 | 134 | > Apache License 135 | > Version 2.0, January 2004 136 | > http://www.apache.org/licenses/ 137 | > Copyright 2019 Anton Gerdelan. 138 | > Licensed under the Apache License, Version 2.0 (the "License"); 139 | > you may not use this file except in compliance with the License. 140 | > You may obtain a copy of the License at 141 | > http://www.apache.org/licenses/LICENSE-2.0 142 | > Unless required by applicable law or agreed to in writing, software 143 | > distributed under the License is distributed on an "AS IS" BASIS, 144 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 145 | > See the License for the specific language governing permissions and 146 | > limitations under the License. 147 | ------------------------------------------------------------------------------------- 148 | SECOND LICENCE OPTION 149 | 150 | > This is free and unencumbered software released into the public domain. 151 | > 152 | > Anyone is free to copy, modify, publish, use, compile, sell, or 153 | > distribute this software, either in source code form or as a compiled 154 | > binary, for any purpose, commercial or non-commercial, and by any 155 | > means. 156 | > 157 | > In jurisdictions that recognize copyright laws, the author or authors 158 | > of this software dedicate any and all copyright interest in the 159 | > software to the public domain. We make this dedication for the benefit 160 | > of the public at large and to the detriment of our heirs and 161 | > successors. We intend this dedication to be an overt act of 162 | > relinquishment in perpetuity of all present and future rights to this 163 | > software under copyright law. 164 | > 165 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 166 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 167 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 168 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 169 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 170 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 171 | > OTHER DEALINGS IN THE SOFTWARE. 172 | > 173 | > For more information, please refer to 174 | ------------------------------------------------------------------------------------- 175 | */ 176 | -------------------------------------------------------------------------------- /apg_gldb/chunks.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_gldb/chunks.jpeg -------------------------------------------------------------------------------- /apg_gldb/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_gldb/screenshot.png -------------------------------------------------------------------------------- /apg_gldb/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_gldb/screenshot2.png -------------------------------------------------------------------------------- /apg_gldb/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_gldb/screenshot3.png -------------------------------------------------------------------------------- /apg_gldb/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_gldb/screenshot4.png -------------------------------------------------------------------------------- /apg_interp/README.md: -------------------------------------------------------------------------------- 1 | # apg_interp # 2 | 3 | A small library of interpolation functions for animations, and transitions 4 | between different numbers. 5 | 6 | Libraries exist for "tweening" and "easing" functions, but I didn't like the 7 | interfaces, nor the mathematics used, so I made my own, simplified, library that 8 | has names and parameters that are more intuitive to me, and more pure functions. 9 | 10 | C99 and JavaScript ports are here. 11 | 12 | I wrote a blog post about this http://antongerdelan.net/blog/formatted/2015_03_18_interpolation.html 13 | 14 | ## functions ## 15 | 16 | * `clamp` - useful to constrain function range 17 | * `lerp` - linear interpolation 18 | * `accel_sine` - the same as "easeInSine" 19 | * `accel_exp` - the same as "easeInExpo" 20 | * `bow_string` - similar to "easeInBack" 21 | * `decel_sine` - the same as "easeOutSine" 22 | * `decel_elastic` - similar to "easeOutElastic" but with no lead-up 23 | * `decel_bounce` - similar to "easeOutBounce" but with no lead-up 24 | 25 | ![lerp](linear.png) 26 | ![accel sine](accel_sine.png) 27 | ![accel exp](accel_exp.png) 28 | ![decel sine](decel_sine.png) 29 | ![decel elastic](decel_elastic.png) 30 | ![decel bounce](decel_bounce.png) 31 | 32 | ## To Do ## 33 | 34 | * add an `n` parameter to bounce and elastic functions to set the number ofwaves in the domain. 35 | * make a chart for `bow_string` 36 | -------------------------------------------------------------------------------- /apg_interp/accel_exp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_interp/accel_exp.png -------------------------------------------------------------------------------- /apg_interp/accel_sine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_interp/accel_sine.png -------------------------------------------------------------------------------- /apg_interp/apg_interp.h: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================= 3 | Interpolation Functions in C99 4 | ======================================================================= 5 | Author: Anton Gerdelan @capnramses 6 | Licence: see bottom of file. 7 | ======================================================================= 8 | Version History 9 | 10 | * 2015 Mar 15 - First v 11 | * 2019 Aug 10 - added apg_interp prefix to functions 12 | 13 | Notes 14 | 15 | * nice easing demos found at: http://easings.net/ 16 | 17 | typical variables used by 'tweening' notes on the web are: 18 | t = current time 19 | b = beginning value 20 | c = change in value 21 | d = duration 22 | functions are named "in" and "out" 23 | this is non-standard weirdness, so I shan't be using that 24 | 25 | better notation: 26 | x_i = starting 'time' value 27 | x_f = ending 'time' value 28 | x = current 'time' value 29 | y_i = min y (eg at x=0.0 for lerp) 30 | y_f = max y (eg at x=1.0 for lerp) 31 | returns y 32 | functions are named "accel" and "decel" instead of "in" and "out" 33 | 34 | internally: 35 | 36 | x - x_i == t 37 | y_i == b 38 | y_r == c 39 | x_r == d 40 | x_n == t / d 41 | ======================================================================= 42 | */ 43 | 44 | #ifndef _APG_INTERP_H_ 45 | #define _APG_INTERP_H_ 46 | 47 | #define _USE_MATH_DEFINES 48 | #include 49 | #ifndef M_PI /* not defined in strict c99 */ 50 | #define M_PI 3.14159265358979323846264338327 51 | #define M_PI_2 M_PI / 2.0 52 | #endif 53 | #define HALF_PI M_PI_2 54 | 55 | float apg_interp_lerp( float x, float x_i, float x_f, float y_i, float y_f ); 56 | float apg_interp_accel_sine( float x, float x_i, float x_f, float y_i, float y_f ); 57 | float apg_interp_accel_exp( float x, float x_i, float x_f, float y_i, float y_f ); 58 | float apg_interp_bow_string( float x, float x_i, float x_f, float y_i, float y_f ); 59 | float apg_interp_decel_sine( float x, float x_i, float x_f, float y_i, float y_f ); 60 | float apg_interp_decel_elastic( float x, float x_i, float x_f, float y_i, float y_f ); 61 | float apg_interp_decel_bounce( float x, float x_i, float x_f, float y_i, float y_f ); 62 | 63 | /* linear interpolation 64 | y = x 65 | */ 66 | inline float apg_interp_lerp( float x, float x_i, float x_f, float y_i, float y_f ) { 67 | /* work out x as factor between 0 and 1 */ 68 | float x_r = x_f - x_i; 69 | float x_n = ( x - x_i ) / x_r; 70 | /* same for y */ 71 | float y_r = y_f - y_i; 72 | /* core function */ 73 | float y = x_n; 74 | return y_r * y + y_i; 75 | } 76 | 77 | /* aka "easeInSine" 78 | accelerating with cosine wave 79 | gentle accel that smooths out 80 | y = 1.0 - cos (x * 0.5 * pi) 81 | */ 82 | inline float apg_interp_accel_sine( float x, float x_i, float x_f, float y_i, float y_f ) { 83 | float x_r = x_f - x_i; 84 | float x_n = ( x - x_i ) / x_r; 85 | float y_r = y_f - y_i; 86 | /* returns wave from -1 to 0, hence the "=1.0 - f(x)" */ 87 | float y = 1.0f - cosf( x_n * HALF_PI ); 88 | return y_r * y + y_i; 89 | } 90 | 91 | /* aka "easeInExpo" 92 | like easeInSine but continuing sharper accel 93 | y = 2^(10 * (x-1)) 94 | e.g. gravity */ 95 | inline float apg_interp_accel_exp( float x, float x_i, float x_f, float y_i, float y_f ) { 96 | float x_r = x_f - x_i; 97 | float x_n = ( x - x_i ) / x_r; 98 | float y_r = y_f - y_i; 99 | /* powf is from C99 */ 100 | float y = powf( 2.0f, 10.0f * ( x_n - 1.0f ) ); 101 | return y_r * y + y_i; 102 | } 103 | 104 | /* similar to "easeInBack" 105 | first half of domain is a sine wave from 0.0 to trough -0.5amp to 0.0. 106 | second half of domain is a basic quadratic from 0.0 to 1.0amp 107 | x_n < 0.5 -> f(x) = sin(2x*pi)*-0.5 // considers 0.0:0.5 range 108 | x_n >= 0.5 -> f(x) = x^2 so = 4 * (x-0.5)^2 // considers 0.5:1.0 range 109 | e.g. bow string 110 | */ 111 | inline float apg_interp_bow_string( float x, float x_i, float x_f, float y_i, float y_f ) { 112 | float x_r = x_f - x_i; 113 | float x_n = ( x - x_i ) / x_r; 114 | float y_r = y_f - y_i; 115 | float y = 0.0f; 116 | // pull back part 117 | if ( x_n < 0.5f ) { 118 | y = sinf( 2.0f * x_n * M_PI ) * -0.5f; 119 | // accel part 120 | } else { 121 | y = 4.0f * ( x_n - 0.5f ) * ( x_n - 0.5f ); 122 | } 123 | return y_r * y + y_i; 124 | } 125 | 126 | /* aka "easeOutSine" 127 | decelerating with cosine wave 128 | f(x) = sin(x * 0.5 * pi) 129 | */ 130 | inline float apg_interp_decel_sine( float x, float x_i, float x_f, float y_i, float y_f ) { 131 | float x_r = x_f - x_i; 132 | float x_n = ( x - x_i ) / x_r; 133 | float y_r = y_f - y_i; 134 | float y = sinf( x_n * HALF_PI ); 135 | return y_r * y + y_i; 136 | } 137 | 138 | /* similar to "easeOutElastic" but with no lead-up 139 | starts at y=0, wobbles about 0 (between +y_f and -y_f) diminishing to y=0 140 | f(x) = (1.0 - x)*sin(x*pi*8); 141 | e.g. guitar string 142 | */ 143 | inline float apg_interp_decel_elastic( float x, float x_i, float x_f, float y_i, float y_f ) { 144 | float x_r = x_f - x_i; 145 | float x_n = ( x - x_i ) / x_r; 146 | float y_r = y_f - y_i; 147 | /* num of peaks and troughs */ 148 | float n = 8.0f; 149 | float y = ( 1.0f - x_n ) * sinf( x_n * M_PI * n ); 150 | return y_r * y + y_i; 151 | } 152 | 153 | /* similar to "easeOutBounce" but with no lead-up 154 | like decel_elastic but waves always positive 155 | f(x) = (1.0 - x)*abs(sin(x*pi*8)); 156 | e.g. ball hitting a surface at 1.0 157 | */ 158 | inline float apg_interp_decel_bounce( float x, float x_i, float x_f, float y_i, float y_f ) { 159 | float x_r = x_f - x_i; 160 | float x_n = ( x - x_i ) / x_r; 161 | float y_r = y_f - y_i; 162 | /* num of peaks and troughs */ 163 | float n = 8.0f; 164 | float y = ( 1.0f - x_n ) * fabs( sinf( x_n * M_PI * n ) ); 165 | return y_r * y + y_i; 166 | } 167 | 168 | /* aka "easeInOutElastic" 169 | delayed spring from 0.0 to 1.0 with wobbles 170 | */ 171 | 172 | #endif 173 | 174 | /* 175 | ------------------------------------------------------------------------------------- 176 | This software is available under two licences - you may use it under either licence. 177 | ------------------------------------------------------------------------------------- 178 | FIRST LICENCE OPTION 179 | 180 | > Apache License 181 | > Version 2.0, January 2004 182 | > http://www.apache.org/licenses/ 183 | > Copyright 2019 Anton Gerdelan. 184 | > Licensed under the Apache License, Version 2.0 (the "License"); 185 | > you may not use this file except in compliance with the License. 186 | > You may obtain a copy of the License at 187 | > http://www.apache.org/licenses/LICENSE-2.0 188 | > Unless required by applicable law or agreed to in writing, software 189 | > distributed under the License is distributed on an "AS IS" BASIS, 190 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 191 | > See the License for the specific language governing permissions and 192 | > limitations under the License. 193 | ------------------------------------------------------------------------------------- 194 | SECOND LICENCE OPTION 195 | 196 | > This is free and unencumbered software released into the public domain. 197 | > 198 | > Anyone is free to copy, modify, publish, use, compile, sell, or 199 | > distribute this software, either in source code form or as a compiled 200 | > binary, for any purpose, commercial or non-commercial, and by any 201 | > means. 202 | > 203 | > In jurisdictions that recognize copyright laws, the author or authors 204 | > of this software dedicate any and all copyright interest in the 205 | > software to the public domain. We make this dedication for the benefit 206 | > of the public at large and to the detriment of our heirs and 207 | > successors. We intend this dedication to be an overt act of 208 | > relinquishment in perpetuity of all present and future rights to this 209 | > software under copyright law. 210 | > 211 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 212 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 213 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 214 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 215 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 216 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 217 | > OTHER DEALINGS IN THE SOFTWARE. 218 | > 219 | > For more information, please refer to 220 | ------------------------------------------------------------------------------------- 221 | */ 222 | -------------------------------------------------------------------------------- /apg_interp/build.sh: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CPP=clang++ 3 | LD=ld 4 | FLAGS="-g -Wall -Wextra -pedantic -Werror" 5 | SAN="-fsanitize=address -fsanitize=undefined" 6 | 7 | $CC $FLAGS $SAN -std=c99 -I ./ tests/test.c -lm 8 | -------------------------------------------------------------------------------- /apg_interp/decel_bounce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_interp/decel_bounce.png -------------------------------------------------------------------------------- /apg_interp/decel_elastic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_interp/decel_elastic.png -------------------------------------------------------------------------------- /apg_interp/decel_sine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_interp/decel_sine.png -------------------------------------------------------------------------------- /apg_interp/interp.js: -------------------------------------------------------------------------------- 1 | /* 2 | ======================================================================= 3 | Interpolation Functions in JavaScript aka "Tweening" or "Easing" 4 | ======================================================================= 5 | Author: Anton Gerdelan @capnramses 6 | Licence: see bottom of file. 7 | ======================================================================= 8 | Version History 9 | 10 | * 2015 Mar 23 - First v 11 | * 2020 Jan 04 - Standardised licence options. 12 | */ 13 | 14 | 15 | // 16 | // not an interpolation function, but useful when using them 17 | // returns value x clamped between min and max 18 | // 19 | function clamp (x, minx, maxx) { 20 | if (x < minx) { 21 | return minx; 22 | } 23 | if (x > maxx) { 24 | return maxx; 25 | } 26 | return x; 27 | } 28 | 29 | // 30 | // linear interpolation 31 | // y = x 32 | // 33 | function lerp (x, x_i, x_f, y_i, y_f) { 34 | // work out x as factor between 0 and 1 35 | var x_r = x_f - x_i; 36 | var x_n = (x - x_i) / x_r; 37 | // same for y 38 | var y_r = y_f - y_i; 39 | // core function 40 | var y = x_n; 41 | return y_r * y + y_i; 42 | } 43 | 44 | // 45 | // aka "easeInSine" 46 | // accelerating with cosine wave 47 | // gentle accel that smooths out 48 | // y = 1.0 - cos (x * 0.5 * pi) 49 | // 50 | function accel_sine (x, x_i, x_f, y_i, y_f) { 51 | var x_r = x_f - x_i; 52 | var x_n = (x - x_i) / x_r; 53 | var y_r = y_f - y_i; 54 | // returns wave from -1 to 0, hence the "=1.0 - f(x)" 55 | var y = 1.0 - Math.cos (x_n * Math.PI * 0.5); 56 | return y_r * y + y_i; 57 | } 58 | 59 | // 60 | // aka "easeInExpo" 61 | // like easeInSine but continuing sharper accel 62 | // y = 2^(10 * (x-1)) 63 | // e.g. gravity 64 | // 65 | function accel_exp (x, x_i, x_f, y_i, y_f) { 66 | var x_r = x_f - x_i; 67 | var x_n = (x - x_i) / x_r; 68 | var y_r = y_f - y_i; 69 | // powf is from C99 70 | var y = Math.pow (2.0, 10.0 * (x_n - 1.0)); 71 | return y_r * y + y_i; 72 | } 73 | 74 | // 75 | // similar to "easeInBack" 76 | // first half of domain is a sine wave from 0.0 to trough -0.5amp to 0.0. 77 | // second half of domain is a basic quadratic from 0.0 to 1.0amp 78 | // x_n < 0.5 -> f(x) = sin(2x*pi)*-0.5 // considers 0.0:0.5 range 79 | // x_n >= 0.5 -> f(x) = x^2 so = 4 * (x-0.5)^2 // considers 0.5:1.0 range 80 | // e.g. bow string 81 | // 82 | function bow_string (x, x_i, x_f, y_i, y_f) { 83 | var x_r = x_f - x_i; 84 | var x_n = (x - x_i) / x_r; 85 | var y_r = y_f - y_i; 86 | var y = 0.0; 87 | // pull back part 88 | if (x_n < 0.5) { 89 | y = Math.sin (2.0 * x_n * Math.PI) * -0.5; 90 | // accel part 91 | } else { 92 | y = 4.0 * (x_n - 0.5) * (x_n - 0.5); 93 | } 94 | return y_r * y + y_i; 95 | } 96 | 97 | // 98 | // aka "easeOutSine" 99 | // decelerating with cosine wave 100 | // f(x) = sin(x * 0.5 * pi) 101 | // 102 | function decel_sine (x, x_i, x_f, y_i, y_f) { 103 | var x_r = x_f - x_i; 104 | var x_n = (x - x_i) / x_r; 105 | var y_r = y_f - y_i; 106 | var y = Math.sin (x_n * Math.PI * 0.5); 107 | return y_r * y + y_i; 108 | } 109 | 110 | // 111 | // similar to "easeOutElastic" but with no lead-up 112 | // starts at y=0, wobbles about 0 (between +y_f and -y_f) diminishing to y=0 113 | // f(x) = (1.0 - x)*sin(x*pi*8); 114 | // e.g. guitar string 115 | // 116 | function decel_elastic (x, x_i, x_f, y_i, y_f) { 117 | var x_r = x_f - x_i; 118 | var x_n = (x - x_i) / x_r; 119 | var y_r = y_f - y_i; 120 | // num of peaks and troughs 121 | var n = 4.0; 122 | var y = (1.0 - x_n) * Math.sin (x_n * Math.PI * n); 123 | return y_r * y + y_i; 124 | } 125 | 126 | // 127 | // similar to "easeOutBounce" but with no lead-up 128 | // like decel_elastic but waves always positive 129 | // f(x) = (1.0 - x)*abs(sin(x*pi*8)); 130 | // e.g. ball hitting a surface at 1.0 131 | // 132 | function decel_bounce (x, x_i, x_f, y_i, y_f) { 133 | var x_r = x_f - x_i; 134 | var x_n = (x - x_i) / x_r; 135 | var y_r = y_f - y_i; 136 | // num of peaks and troughs 137 | var n = 4.0; 138 | var y = (1.0 - x_n) * Math.abs (Math.sin (x_n * Math.PI * n)); 139 | return y_r * y + y_i; 140 | } 141 | 142 | /* 143 | ------------------------------------------------------------------------------------- 144 | This software is available under two licences - you may use it under either licence. 145 | ------------------------------------------------------------------------------------- 146 | FIRST LICENCE OPTION 147 | 148 | > Apache License 149 | > Version 2.0, January 2004 150 | > http://www.apache.org/licenses/ 151 | > Copyright 2019 Anton Gerdelan. 152 | > Licensed under the Apache License, Version 2.0 (the "License"); 153 | > you may not use this file except in compliance with the License. 154 | > You may obtain a copy of the License at 155 | > http://www.apache.org/licenses/LICENSE-2.0 156 | > Unless required by applicable law or agreed to in writing, software 157 | > distributed under the License is distributed on an "AS IS" BASIS, 158 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 159 | > See the License for the specific language governing permissions and 160 | > limitations under the License. 161 | ------------------------------------------------------------------------------------- 162 | SECOND LICENCE OPTION 163 | 164 | > This is free and unencumbered software released into the public domain. 165 | > 166 | > Anyone is free to copy, modify, publish, use, compile, sell, or 167 | > distribute this software, either in source code form or as a compiled 168 | > binary, for any purpose, commercial or non-commercial, and by any 169 | > means. 170 | > 171 | > In jurisdictions that recognize copyright laws, the author or authors 172 | > of this software dedicate any and all copyright interest in the 173 | > software to the public domain. We make this dedication for the benefit 174 | > of the public at large and to the detriment of our heirs and 175 | > successors. We intend this dedication to be an overt act of 176 | > relinquishment in perpetuity of all present and future rights to this 177 | > software under copyright law. 178 | > 179 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 180 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 181 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 182 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 183 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 184 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 185 | > OTHER DEALINGS IN THE SOFTWARE. 186 | > 187 | > For more information, please refer to 188 | ------------------------------------------------------------------------------------- 189 | */ 190 | -------------------------------------------------------------------------------- /apg_interp/linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_interp/linear.png -------------------------------------------------------------------------------- /apg_interp/tests/test.c: -------------------------------------------------------------------------------- 1 | #include "apg_interp.h" 2 | #include 3 | #include 4 | #include // unix sleep 5 | #include 6 | 7 | int main( void ) { 8 | printf( "hello world\n" ); 9 | time_t prev_time, curr_time; 10 | time( &prev_time ); 11 | double x = 0.0; 12 | while ( true ) { 13 | time( &curr_time ); 14 | double delta_s = difftime( curr_time, prev_time ); 15 | prev_time = curr_time; 16 | x += delta_s; 17 | if ( x > 20.0 ) { x = 0.0; } 18 | printf( "x = %f\n", x ); 19 | 20 | float y; 21 | y = apg_interp_lerp( x, 0.0f, 20.0f, 0.0f, 1.0f ); 22 | printf( "lerp = %f\n", y ); 23 | y = apg_interp_accel_sine( x, 0.0f, 20.0f, 0.0f, 1.0f ); 24 | printf( "accel_sine = %f\n", y ); 25 | y = apg_interp_accel_exp( x, 0.0f, 20.0f, 0.0f, 1.0f ); 26 | printf( "accel_exp = %f\n", y ); 27 | y = apg_interp_bow_string( x, 0.0f, 20.0f, 0.0f, 1.0f ); 28 | printf( "bow_string = %f\n", y ); 29 | y = apg_interp_decel_sine( x, 0.0f, 20.0f, 0.0f, 1.0f ); 30 | printf( "decel_sine = %f\n", y ); 31 | y = apg_interp_decel_elastic( x, 0.0f, 20.0f, 0.0f, 1.0f ); 32 | printf( "decel_elastic = %f\n", y ); 33 | y = apg_interp_decel_bounce( x, 0.0f, 20.0f, 0.0f, 1.0f ); 34 | printf( "decel_bounce = %f\n", y ); 35 | 36 | sleep( 1 ); // 1 second 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /apg_jobs/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -fsanitize=address (not allowed with thread) 3 | SANS="-fsanitize=thread -fsanitize=undefined" 4 | FLAGS="-Wall -Wextra -pedantic" 5 | clang $SANS $FLAGS tests/main.c apg_jobs.c -I ./ -pthread 6 | -------------------------------------------------------------------------------- /apg_jobs/build_msvc_dll.bat: -------------------------------------------------------------------------------- 1 | REM WARNING: this "call ..." is for use as a batch file from explorer. Don't call this in a terminal or it double-sets things and goes bonkers. 2 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" 3 | 4 | cl /LD apg_jobs.c 5 | 6 | pause 7 | -------------------------------------------------------------------------------- /apg_jobs/build_msvc_test_program.bat: -------------------------------------------------------------------------------- 1 | REM WARNING: this "call ..." is for use as a batch file from explorer. Don't call this in a terminal or it double-sets things and goes bonkers. 2 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" 3 | 4 | REM "we recommend you compile by using either the /W3 or /W4 warning level" 5 | REM C4221 is nonstandard extension used in struct literals. 6 | set COMPILER_FLAGS=/W4 /D_CRT_SECURE_NO_WARNINGS /wd4221 7 | set LINKER_FLAGS=/out:test_apg_jobs.exe 8 | set LIBS= 9 | 10 | set BUILD_DIR=".\build" 11 | if not exist %BUILD_DIR% mkdir %BUILD_DIR% 12 | pushd %BUILD_DIR% 13 | 14 | set I=/I ..\src\ /I ..\src\apg\ /I..\src\stb\ /I..\src\glad\include\ 15 | 16 | set SRC=..\main.c ^ 17 | ..\apg_jobs.c 18 | 19 | cl %COMPILER_FLAGS% %SRC% %I% /link %LINKER_FLAGS% %LIBS% 20 | 21 | copy test_apg_jobs.exe ..\ 22 | 23 | pause 24 | -------------------------------------------------------------------------------- /apg_jobs/tests/main.c: -------------------------------------------------------------------------------- 1 | /** @file main.c 2 | * Test program for apg_jobs. 3 | * Only runs on *nix machines since it uses pthread and usleep(). 4 | */ 5 | 6 | #include "apg_jobs.h" 7 | #ifdef _WIN32 8 | #include 9 | #else 10 | #include // usleep 11 | #endif 12 | #include 13 | #include 14 | 15 | void apg_sleep_ms( int ms ) { 16 | #ifdef WIN32 17 | Sleep( ms ); /* NOTE(Anton) may not need this since using gcc on Windows and usleep() works */ 18 | /* NOTE(Anton) 13 Jan 2022 -- this nanosleep function didn't work on my linux despite _POSIX_C_SOURCE entering the elif 19 | #elif _POSIX_C_SOURCE >= 199309L 20 | struct timespec ts; 21 | ts.tv_sec = ms / 1000; 22 | ts.tv_nsec = ( ms % 1000 ) * 1000000; 23 | nanosleep( &ts, NULL ); 24 | */ 25 | #else 26 | usleep( ms * 1000 ); 27 | #endif 28 | } 29 | 30 | void work_cb( void* arg_ptr ) { 31 | int* val = arg_ptr; 32 | int old = *val; 33 | *val += 1000; 34 | 35 | fprintf( stderr, "starting job, old=%d, val=%d\n", old, *val ); 36 | apg_sleep_ms( rand() % 1000 ); 37 | fprintf( stderr, "ending job, old=%d, val=%d\n", old, *val ); 38 | } 39 | 40 | int main( void ) { 41 | // similar to `lscpu` command, where my machine has 1 socket with 4 cores per socket 42 | // and 2 threads per core (8 logical, 4 physical). 43 | int n_procs = apg_jobs_n_logical_procs(); 44 | printf( "n_procs = %i\n", n_procs ); 45 | 46 | apg_jobs_pool_t thread_pool; 47 | int queue_max = 256; // make this really short ( like 2 ) to test queue block/wait behaviour 48 | bool ret = apg_jobs_init( &thread_pool, n_procs * 8, queue_max ); 49 | if ( !ret ) { 50 | fprintf( stderr, "ERROR: failed to init pool\n" ); 51 | return 1; 52 | } 53 | printf( "apg_jobs initialised. pushing jobs:\n" ); 54 | 55 | int num_items = 100; 56 | int* vals = malloc( sizeof( int ) * num_items ); 57 | for ( int i = 0; i < num_items; i++ ) { 58 | vals[i] = i; 59 | printf( "apg_jobs pushing %i\n", i ); 60 | apg_jobs_push_job( &thread_pool, work_cb, &vals[i] ); 61 | } 62 | 63 | printf( "apg_jobs waiting for all jobs\n" ); 64 | 65 | apg_jobs_wait( &thread_pool ); 66 | 67 | for ( int i = 0; i < num_items; i++ ) { printf( "%d\n", vals[i] ); } 68 | 69 | printf( "apg_jobs free\n" ); 70 | ret = apg_jobs_free( &thread_pool ); 71 | if ( !ret ) { 72 | fprintf( stderr, "ERROR: failed to free pool\n" ); 73 | return 1; 74 | } 75 | 76 | free( vals ); 77 | printf( "normal halt\n" ); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /apg_maths/README.md: -------------------------------------------------------------------------------- 1 | # apg_maths # 2 | 3 | Minimal maths functions for 3D graphics. 4 | Functions designed to resemble GLSL and GLU. 5 | Column-major matrix operations and memory layout. 6 | 7 | * `apg_maths.h,.c` - C99 8 | * `apg_maths.js` - A fairly complete port to JavaScript for use with WebGL 9 | * `tests/` - Test programs for the C99 functions. 10 | 11 | ## Data Types ## 12 | 13 | Data types are encoded as 1D arrays in column-major memory order. 14 | 15 | * `vec2` 2D vector. 16 | * `vec3` 3D vector. 17 | * `vec4` 4D vector. 18 | * `mat3` 3x3 matrix. 19 | * `mat4` 4x4 matrix. 20 | * `versor` quaternion. 21 | 22 | See inside source files for instructions on usage. 23 | 24 | ## Functions 25 | 26 | * `print()` for each data type (contents). 27 | * Vector length, squared length, normalisation, dot and cross products. 28 | * Some converstions between direction vectors and angles. 29 | * Matrix identity, inverse, determinant, transpose, rotations, and scaling. 30 | * Affine matrix construction. 31 | * Virtual camera matrix construction in GLU format ("look at" etc.). 32 | * Quaternion construction from axis-angle. 33 | * Unit quaternion (versor) normalisation etc. 34 | * Versor to matrix converstion. 35 | * Slerp (spherical interpolation). 36 | -------------------------------------------------------------------------------- /apg_maths/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -fsanitize=address (not allowed with thread) 3 | SANS="-fsanitize=thread -fsanitize=undefined" 4 | FLAGS="-Wall -Wextra -pedantic" 5 | clang $SANS $FLAGS tests/test.c apg_maths.c -I ./ 6 | -------------------------------------------------------------------------------- /apg_maths/tests/build_msvc.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM NOTE: Uncomment whichever one that you have installed! 4 | REM call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 5 | REM call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" x64 6 | REM call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64 7 | REM call "C:\Program Files (x86)\Microsoft Visual Studio 13.0\VC\vcvarsall.bat" x64 8 | REM call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 9 | REM call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 10 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" 11 | 12 | REM The /Z7 option produces object files that also contain full symbolic debugging information for use with the debugger 13 | REM /Fc Causes the compiler to display the full path of source code files passed to the compiler in diagnostics. 14 | REM /Fm outputs a map file 15 | REM /Fd outputs a PDB file /MTd link with LIBCMTD.LIB debug lib /F set stack size /W set warning level (default n=1) /Wall enable all warnings /wd disable warning n 16 | REM language standard options are: /std:c++14 /std:c++17 /std:c++latest /std:c11 /std:c17 17 | set COMPILER_FLAGS=/MTd /std:c11 /nologo /Wall /FC /Fm /Z7 /wd4061 /wd4100 /wd4201 /wd4204 /wd4255 /wd4365 /wd4464 /wd4505 /wd4514 /wd4530 /wd4577 /wd4668 /wd4710 /wd4820 /wd4996 /wd5045 /wd5100 18 | set LINKER_FLAGS=/INCREMENTAL:NO /opt:ref 19 | REM set LINKER_PATHS=/LIBPATH:"../" 20 | REM set SYSTEM_LIBS= 21 | REM set LOCAL_LIBS= 22 | 23 | set BUILD_DIR=".\tmp" 24 | if not exist %BUILD_DIR% mkdir %BUILD_DIR% 25 | pushd %BUILD_DIR% 26 | 27 | cl %COMPILER_FLAGS% ^ 28 | ../test.c ../../apg_maths.c ^ 29 | /I ../ /I ../../ ^ 30 | /link %LINKER_PATHS% %LINKER_FLAGS% %LOCAL_LIBS% %SYSTEM_LIBS% 31 | 32 | popd 33 | copy %BUILD_DIR%\test.exe .\test_msvc.exe 34 | echo Done 35 | -------------------------------------------------------------------------------- /apg_maths/tests/test.c: -------------------------------------------------------------------------------- 1 | #include "apg_maths.h" 2 | #include 3 | #include // memset 4 | 5 | int main( void ) { 6 | printf( "testing C99 version of maths library\n" ); 7 | 8 | // vec2 v2, v2b; 9 | vec3 v3, v3b; 10 | // vec4 v4, v4b; 11 | mat4 m4; // m4b; 12 | // versor q, qb; 13 | 14 | // constructors and assignment 15 | printf( "* zero_mat4\n" ); 16 | memset( &m4, 0, sizeof( mat4 ) ); 17 | print_mat4( m4 ); 18 | printf( "* identity_mat4\n" ); 19 | m4 = identity_mat4(); 20 | print_mat4( m4 ); 21 | 22 | v3 = ( vec3 ){.x = 0, .y = 0, .z = 1}; 23 | v3b = ( vec3 ){.x = 0, .y = 0, .z = 2}; 24 | 25 | printf( "* add_vec3_vec3\n" ); 26 | v3 = add_vec3_vec3( v3, v3b ); 27 | print_vec3( v3 ); 28 | printf( "* sub_vec3_vec3\n" ); 29 | v3 = sub_vec3_vec3( v3, v3b ); 30 | print_vec3( v3 ); 31 | 32 | mat4 la = look_at( ( vec3 ){.x = 0.0, .y = 7.0f, .z = 0.0}, ( vec3 ){.x = 0.0f, .y = 0.0f, .z = 0.0f}, ( vec3 ){.x = 0, .y = 0, .z = -1} ); 33 | print_mat4( la ); 34 | 35 | // add_vec3_f 36 | // sub_vec3_f 37 | // mult_vec3_f 38 | // div_vec3_f 39 | // mult_vec3_vec3 40 | // div_vec3_vec3 41 | 42 | // length_vec3 43 | // length2_vec3 44 | 45 | { // tests for distance_plane_point(). distances should be negative if point is behind the plane. 46 | const int n = 8; 47 | vec4 planes_xyzd[] = { 48 | ( vec4 ){1, 0, 0, 0}, // 0 49 | ( vec4 ){1, 0, 0, -1}, // 1 50 | ( vec4 ){1, 0, 0, 0}, // 2 51 | ( vec4 ){1, 0, 0, -1}, // 3 52 | ( vec4 ){0, 1, 0, 0}, // 4 53 | ( vec4 ){1, 0, 0, 1}, // 5 54 | vec4_from_vec3f( normalise_vec3( ( vec3 ){1, 0, 1} ), 1 ), // 6 55 | ( vec4 ){0, 1, 0, -1} // 7 56 | }; 57 | vec3 points[] = {( vec3 ){2, 0, 0}, ( vec3 ){2, 0, 0}, ( vec3 ){-2, 0, 0}, ( vec3 ){-2, 0, 0}, ( vec3 ){-2, 0, 0}, ( vec3 ){-1, 0, 0}, ( vec3 ){1, 0, 0}, 58 | ( vec3 ){1, 0, 0}}; 59 | for ( int i = 0; i < n; i++ ) { 60 | float dist = distance_plane_point( planes_xyzd[i], points[i] ); 61 | printf( "test %i) distance from plane (%.2f,%.2f,%.2f,%.2f) to point (%.2f,%.2f,%.2f) = %f\n", i, planes_xyzd[i].x, planes_xyzd[i].y, planes_xyzd[i].z, 62 | planes_xyzd[i].w, points[i].x, points[i].y, points[i].z, dist ); 63 | } 64 | } 65 | { // tests for frustum_planes_from_PV() 66 | printf("\ntests for frustum_planes_from_PV()\n"); 67 | mat4 P = perspective( 45, 1, 10, 100 ); 68 | mat4 V = look_at( ( vec3 ){.x = 0, .y = 0, .z = 0}, ( vec3 ){.z = -100}, ( vec3 ){.y = 1} ); 69 | mat4 PV = mul_mat4_mat4( P, V ); 70 | vec4 planes_xyzd[6]; 71 | bool normalise = true; 72 | frustum_planes_from_PV( PV, planes_xyzd, normalise ); 73 | for ( int i = 0; i < 6; i++ ) { 74 | printf( "plane %i:\n", i ); 75 | print_vec4( planes_xyzd[i] ); 76 | } 77 | } 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /apg_mod/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -fsanitize=address (not allowed with thread) 3 | SANS="-fsanitize=thread -fsanitize=undefined" 4 | FLAGS="-Wall -Wextra -pedantic" 5 | clang -o print_tracks.bin $SANS $FLAGS tests/print_tracks.c apg_mod.c -I ./ 6 | 7 | APG_WAV_INC="../apg_wav/" 8 | 9 | clang -o dump_wavs.bin $SANS $FLAGS tests/dump_wavs.c apg_mod.c -I ./ \ 10 | -I $APG_WAV_INC $APG_WAV_INC/apg_wav.c 11 | -------------------------------------------------------------------------------- /apg_mod/tests/dump_wavs.c: -------------------------------------------------------------------------------- 1 | // apg_mod - test/example - extract audio samples as .wav files. 2 | // Depends on apg_wav to do the conversion. 3 | // By Anton Gerdelan 4 | 5 | #include "apg_mod.h" 6 | #include "apg_wav.h" 7 | #include 8 | #include 9 | #include 10 | 11 | int main( int argc, char** argv ) { 12 | if ( argc < 2 ) { 13 | printf( "Usage: %s MYFILE.mod\n", argv[0] ); 14 | return 0; 15 | } 16 | const char* filename_ptr = argv[1]; 17 | 18 | apg_mod_t mod = ( apg_mod_t ){ .sample_data_ptrs[0] = NULL }; 19 | if ( !apg_mod_read_file( filename_ptr, &mod ) ) { 20 | fprintf( stderr, "ERROR: could not open file %s\n", filename_ptr ); 21 | return 1; 22 | } 23 | 24 | printf( "Loaded song: %s\n", mod.song_name ); 25 | 26 | uint32_t sample_rate_hz = 11025; 27 | // data_sz == n_samples * n_chans * bytes_per_sample 28 | 29 | // Write samples to .wav files. 30 | for ( int i = 0; i < APG_MOD_N_SAMPLES; i++ ) { 31 | if ( 0 == mod.sample_sz_bytes[i] ) { continue; } 32 | char tmp[64]; 33 | sprintf( tmp, "sample%02i.wav", i ); 34 | uint32_t n_samples = mod.sample_sz_bytes[i] / sizeof( int16_t ); // not sure why this exists as a param if it can be derived from other params. 35 | bool ret = apg_wav_write( tmp, mod.sample_data_ptrs[i], mod.sample_sz_bytes[i], 1, sample_rate_hz, n_samples, 16 ); 36 | if ( !ret ) { 37 | printf( "couldnt write a sample for %i\n", i ); 38 | continue; 39 | } 40 | printf( "Wrote %s\n", tmp ); 41 | } 42 | 43 | if ( !apg_mod_free( &mod ) ) { 44 | fprintf( stderr, "ERROR: could not free mod\n" ); 45 | return 1; 46 | } 47 | 48 | printf( "Normal exit\n" ); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /apg_mod/tests/print_tracks.c: -------------------------------------------------------------------------------- 1 | // apg_mod - test/example - print .mod song score rows to stdout. 2 | // By Anton Gerdelan 3 | 4 | #include "apg_mod.h" 5 | #include 6 | #include 7 | #include 8 | 9 | int main( int argc, char** argv ) { 10 | if ( argc < 2 ) { 11 | printf( "Usage: %s MYFILE.mod\n", argv[0] ); 12 | return 0; 13 | } 14 | const char* filename_ptr = argv[1]; 15 | 16 | apg_mod_t mod = ( apg_mod_t ){ .sample_data_ptrs[0] = NULL }; 17 | if ( !apg_mod_read_file( filename_ptr, &mod ) ) { 18 | fprintf( stderr, "ERROR: could not open file %s\n", filename_ptr ); 19 | return 1; 20 | } 21 | 22 | printf( "Loaded song: %s\n", mod.song_name ); 23 | 24 | for ( int o_idx = 0; o_idx < mod.n_orders; o_idx++ ) { 25 | uint8_t p_idx = mod.orders_ptr[o_idx]; 26 | printf( "o%i/%i --p%i--\n", o_idx, mod.n_orders, p_idx ); 27 | for ( int r_idx = 0; r_idx < APG_MOD_N_PATTERN_ROWS; r_idx++ ) { 28 | printf( "r%2i] ", r_idx ); 29 | for ( int c_idx = 0; c_idx < mod.n_chans; c_idx++ ) { 30 | apg_mod_note_t note = ( apg_mod_note_t ){ .sample_idx = 0 }; 31 | if ( apg_mod_fetch_note( &mod, p_idx, r_idx, c_idx, ¬e ) ) { 32 | int idx = apg_mod_find_period_table_idx( note.period_value_12b ); 33 | char tmp[4]; 34 | strcpy( tmp, "..." ); 35 | if ( idx > -1 ) { strcpy( tmp, _note_names[idx] ); } 36 | printf( "%s %2i %2i %2i, ", tmp, note.sample_idx, note.effect_type_4b, note.effect_params ); 37 | } 38 | } 39 | printf( "\n" ); 40 | } 41 | } 42 | 43 | // Write samples to .raw files. 44 | // for ( int i = 0; i < APG_MOD_N_SAMPLES; i++ ) { 45 | // bool ret = apg_mod_dump_raw_sample_file( &mod, i ); 46 | // if ( !ret ) { fprintf( stderr, "ERROR: could not write sample %i\n", i ); } 47 | //} 48 | 49 | if ( !apg_mod_free( &mod ) ) { 50 | fprintf( stderr, "ERROR: could not free mod\n" ); 51 | return 1; 52 | } 53 | 54 | printf( "Normal exit\n" ); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /apg_pixfont/build.bat: -------------------------------------------------------------------------------- 1 | set CC=gcc 2 | set CPP=g++ 3 | set LD=ld 4 | set FLAGS=-g -Wall -Wextra -pedantic -Wno-missing-field-initializers 5 | set SAN= 6 | REM # -fsanitize=address -fsanitize=undefined" 7 | %CPP% %FLAGS% %SAN% -c tests/test_pixfont.cpp -o build/test_pixfont.o -I . -I ../third_party/stb/ 8 | %CC% %FLAGS% %SAN% -c apg_pixfont.c -o build/apg_pixfont.o -I . 9 | %CPP% %FLAGS% -o test_pixfont.exe build/apg_pixfont.o build/test_pixfont.o -lm 10 | 11 | %CC% -o bakefont.exe utils/bake_font_array.c -I ../third_party/stb/ -lm 12 | %CC% -g -o create_atlas.exe utils/create_atlas.c apg_pixfont.c -I ../third_party/stb/ -I . -lm 13 | -------------------------------------------------------------------------------- /apg_pixfont/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # any error code causes script to exit with error code 4 | set -e 5 | # echo everything 6 | #set -x 7 | 8 | colour_pass="\033[32;1m" 9 | colour_default="\033[0m" 10 | horiz_div="========================" 11 | 12 | CC=clang 13 | CPP=clang++ 14 | LD=ld 15 | FLAGS="-g -Wall -Wextra -pedantic -Wno-missing-field-initializers" 16 | SAN="" # -fsanitize=address -fsanitize=undefined" 17 | $CPP $FLAGS $SAN -c tests/test_pixfont.cpp -o build/test_pixfont.o -I ./ -I ../third_party/stb/ 18 | $CC $FLAGS $SAN -c apg_pixfont.c -o build/apg_pixfont.o -I ./ 19 | $CPP -o test_pixfont.bin build/apg_pixfont.o build/test_pixfont.o -lm 20 | 21 | $CC -o bakefont.bin utils/bake_font_array.c -I ../third_party/stb/ -lm 22 | $CC -o create_atlas.bin utils/create_atlas.c apg_pixfont.c -I ../third_party/stb/ -I ./ -lm 23 | 24 | printf '%b%s\n%s\n%s\n%b\n' $colour_pass $horiz_div "Build SUCCESS" $horiz_div $colour_default 25 | -------------------------------------------------------------------------------- /apg_pixfont/build/PLACEHOLDER.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_pixfont/build/PLACEHOLDER.txt -------------------------------------------------------------------------------- /apg_pixfont/pixfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_pixfont/pixfont.png -------------------------------------------------------------------------------- /apg_pixfont/tests/test_pixfont.cpp: -------------------------------------------------------------------------------- 1 | /* test_pixfont.cpp - Test program for apg_pixfont. 2 | C++ Implementation ( to make sure I got C header compatibility right ). 3 | See apg_pixfont.h for library licence and instructions. 4 | Anton Gerdelan 2019 5 | ============================================================== */ 6 | 7 | #include "apg_pixfont.h" 8 | #define STB_IMAGE_WRITE_IMPLEMENTATION 9 | #include "stb_image_write.h" 10 | #include 11 | 12 | #define N_TEST_STRINGS 8 13 | 14 | int main() { 15 | const char* test_strings[N_TEST_STRINGS] = { 16 | "Hello, World!", // 17 | "This is a line\nbreak - did it work?\n\n\n", // 18 | "über spaß!", // 19 | "An bhfuil cead agam dul\ngo dtí an leithreas?", // 20 | "This is My Lovely, Big Heading", // 21 | "Absolute Unit of a Text", // 22 | "Nobody Needs\nText This\nHUGE!", // 23 | "Small is ok but but VERYVERYVERYVERYVERYVERYVERYVERY long STRINGSINHERETHEYWONTSTOPSOLONGOMG to be here." // 24 | }; 25 | const int n_chans[N_TEST_STRINGS] = { 1, 2, 3, 4, 4, 4, 4, 4 }; 26 | int thickness[N_TEST_STRINGS] = { 1, 1, 1, 1, 2, 3, 10, 1 }; 27 | bool outlines[N_TEST_STRINGS] = { false, true, false, true, true, true, true, true }; 28 | 29 | for ( int s = 0; s < 5; s++ ) { 30 | apg_pixfont_style_t style = static_cast(s); 31 | for ( int i = 0; i < N_TEST_STRINGS; i++ ) { 32 | int w = 0, h = 0; 33 | 34 | char* str = strdup( test_strings[i] ); 35 | apg_pixfont_word_wrap_str( str, 10 ); 36 | 37 | // FIND SIZE REQUIRED FOR TEXT IMAGE 38 | bool result = apg_pixfont_image_size_for_str( str, &w, &h, thickness[i], outlines[i], style, 10 ); 39 | if ( !result ) { 40 | fprintf( stderr, "ERROR: sizing string image %i\n", i ); 41 | return 1; 42 | } 43 | 44 | // CREATE TEXT IMAGE 45 | unsigned char* text_img = (unsigned char*)calloc( 1, w * h * n_chans[i] ); 46 | result = apg_pixfont_str_into_image( str, text_img, w, h, n_chans[i], 0xFF, 0x7F, 0x00, 0xFF, thickness[i], outlines[i], style, 10 ); 47 | if ( !result ) { 48 | fprintf( stderr, "ERROR: creating string image %i\n", i ); 49 | return 1; 50 | } 51 | 52 | // WRITE OUTPUT TO FILE 53 | char tmp[256]; 54 | sprintf( tmp, "%i.png", s * N_TEST_STRINGS + i ); 55 | result = stbi_write_png( tmp, w, h, n_chans[i], text_img, w * n_chans[i] ); 56 | if ( !result ) { 57 | fprintf( stderr, "ERROR: writing string image %i\n", i ); 58 | return 1; 59 | } 60 | 61 | // FREE IMAGE MEMORY 62 | free( text_img ); 63 | free( str ); 64 | } 65 | } 66 | 67 | // convert a font image file to C array for pasting into apg_pixfont.c 68 | #ifdef GENERATE_C_ARRAY_FONT 69 | { 70 | int w = 0, h = 0, n = 0; 71 | unsigned char* img = stbi_load( "pixfont.png", &w, &h, &n, 0 ); 72 | if ( !font.img ) { 73 | fprintf( stderr, "ERROR: loading font image\n" ); 74 | return 1; 75 | } 76 | 77 | FILE* fptr = fopen( "font.c", "w" ); 78 | fprintf( fptr, "static const int _font_img_w = %i;\n", font.w ); 79 | fprintf( fptr, "static const int _font_img_h = %i;\n", font.h ); 80 | fprintf( fptr, "static const int _font_img_n_chans = %i;\n", font.n_colour_channels ); 81 | fprintf( fptr, "static const unsigned char _font_img[] = { " ); 82 | for ( int y = 0; y < font.h; y++ ) { 83 | for ( int x = 0; x < font.w; x++ ) { 84 | if ( y != font.h - 1 || x != font.w - 1 ) { 85 | fprintf( fptr, "0X%02X,", font.img[y * font.w + x] ); 86 | } else { 87 | fprintf( fptr, "0X%02X", font.img[y * font.w + x] ); 88 | } 89 | } 90 | } 91 | fprintf( fptr, " };\n" ); 92 | fclose( fptr ); 93 | } 94 | #endif 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /apg_pixfont/utils/bake_font_array.c: -------------------------------------------------------------------------------- 1 | // Utility for updating apg_pixfont.c with a new hard-coded font image 2 | // Example use case: "Ah! I forgot to add ê to the typeface image...let's paint that into the reference 3 | // image and then update the hard-coded version in the library." 4 | // Input: some font image .png 5 | // Output: A C array in text is written to stdout that can be copy-pasted into the code. 6 | // Author: Anton Gerdelan, 17 April 2020 7 | // Build: 8 | // gcc -o bake_font bake_font_array.c -lm 9 | // Usage: 10 | // ./bake_font MY_IMAGE.png > some_code.c 11 | 12 | #define STB_IMAGE_IMPLEMENTATION 13 | #include "stb_image.h" 14 | #include 15 | 16 | int main( int argc, char** argv ) { 17 | if ( argc < 2 ) { 18 | printf( "Usage: ./bake_font MY_IMAGE.png > some_code.c\n" ); 19 | return 0; 20 | } 21 | int w = 0, h = 0, n = 0; 22 | unsigned char* img_ptr = stbi_load( argv[1], &w, &h, &n, 1 ); 23 | if ( !img_ptr ) { 24 | fprintf( stderr, "ERROR loading font from image file `%s`\n", argv[1] ); 25 | return 1; 26 | } 27 | printf( "// clang-format off\n" ); 28 | printf( "static const int _font_img_w = %i;\n", w ); 29 | printf( "static const int _font_img_h = %i;\n", h ); 30 | printf( "static const unsigned char _font_img[] = { " ); 31 | int max = w * h; 32 | for ( int idx = 0; idx < max - 1; idx++ ) { printf( "%i,", img_ptr[idx] ); } // 1 byte per pixel so ++ 33 | printf( "%i", img_ptr[max - 1] ); // no comma on last element 34 | printf( " };\n" ); 35 | printf( "// clang-format on\n" ); 36 | 37 | free( img_ptr ); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /apg_pixfont/utils/create_atlas.c: -------------------------------------------------------------------------------- 1 | // Example utility to create a typical 16x16 cell atlas image using apg_pixelfont 2 | // by Anton Gerdelan 2023 Feb 26. 3 | // 4 | // Atlas contains ASCII codepoints 0x20-0x7F (skips control codes before space), 5 | // and then includes the Latin-1 supplement, excluding its control codes section also. 6 | // This leaves ~64 blanks at the end that could be repurposed. 7 | // 8 | // * Advantage to this? Images of pre-baked outlines or styles without requiring run-time generation. 9 | // * Does it need to be in a square image? No. Power of two dimensions are fine, but it might help with 10 | // mipmaps on some setups, or work with existing software better than a strip. 11 | // * Could the main library just use these atlases? Yes, but I find it easier to hand-edit an atlas. 12 | // There are some use-cases where baking that into code is handy for quick blit-to-screen one-off debugging. 13 | // * Could you just load 256 invidual glyphs of each style to memory? Yes, that would fit into texture arrays 14 | // and avoid bleeding issues with mipmaps. There's plenty of padding for the glyphs here though. For thickness 2 15 | // use 32x32px cells. This also looks a bit nicer for italics. 16 | 17 | // gcc .\create_atlas.c ..\apg_pixfont.c -I ..\ -I ..\..\third_party\stb\ 18 | 19 | #include "apg_pixfont.h" 20 | #define STB_IMAGE_WRITE_IMPLEMENTATION 21 | #include "stb_image_write.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | int cell_dims[2] = { 16, 16 }; // ~1MB per 256-char sheet. Prefer power-of-two sizes, but not essential. 29 | 30 | #define MASK_FIRST_ONE 128 // 128 or 10000000 31 | #define MASK_FIRST_TWO 192 // 192 or 11000000 32 | #define MASK_FIRST_THREE 224 // 224 or 11100000 33 | #define MASK_FIRST_FOUR 240 // 240 or 11110000 34 | #define MASK_FIRST_FIVE 248 // 248 or 11111000 35 | int apg_cp_to_utf8( uint32_t codepoint, char* mbs ) { 36 | assert( mbs ); 37 | if ( !mbs ) { 38 | mbs[0] = (char)0xEF; 39 | mbs[1] = (char)0xBF; 40 | mbs[2] = (char)0xBD; 41 | mbs[3] = '\0'; 42 | return 4; 43 | } 44 | 45 | if ( codepoint <= 0x7F ) { // ASCII 46 | mbs[0] = (char)codepoint; 47 | mbs[1] = '\0'; 48 | return 1; 49 | } 50 | // 2 bytes: max 0b11111111111 -> 110xxxxx 10xxxxxx 51 | if ( codepoint <= 0x07FF ) { // (U+0080 to U+07FF - Latin, Greek, Hebrew, Arabic, ... ) 52 | // ( shift off lower byte(s), cut off anything in front from earlier byte(s), append 110xxxxx to front ) 53 | mbs[0] = (char)( ( ( codepoint >> 6 ) & 0x1F ) | MASK_FIRST_TWO ); 54 | mbs[1] = (char)( ( codepoint & 0x3F ) | MASK_FIRST_ONE ); 55 | mbs[2] = '\0'; 56 | return 2; 57 | } 58 | // 3-bytes 59 | if ( codepoint <= 0xFFFF ) { 60 | mbs[0] = (char)( ( ( codepoint >> 12 ) & 0x0F ) | MASK_FIRST_THREE ); 61 | mbs[1] = (char)( ( ( codepoint >> 6 ) & 0x3F ) | MASK_FIRST_ONE ); 62 | mbs[2] = (char)( ( codepoint & 0x3F ) | MASK_FIRST_ONE ); 63 | mbs[3] = '\0'; 64 | return 3; 65 | } 66 | // 4-bytes 67 | if ( codepoint <= 0x10FFFF ) { 68 | mbs[0] = (char)( ( ( codepoint >> 18 ) & 0x07 ) | MASK_FIRST_FOUR ); 69 | mbs[1] = (char)( ( ( codepoint >> 12 ) & 0x3F ) | MASK_FIRST_ONE ); 70 | mbs[2] = (char)( ( ( codepoint >> 6 ) & 0x3F ) | MASK_FIRST_ONE ); 71 | mbs[3] = (char)( ( codepoint & 0x3F ) | MASK_FIRST_ONE ); 72 | mbs[4] = '\0'; 73 | return 4; 74 | } 75 | // unknown unicode - use diamond question mark 76 | mbs[0] = (char)0xEF; 77 | mbs[1] = (char)0xBF; 78 | mbs[2] = (char)0xBD; 79 | mbs[3] = '\0'; 80 | return 4; 81 | } 82 | 83 | uint32_t get_codepoint( int index ) { 84 | uint32_t codepoint = index + ' '; // Space is the glyph in the top-left (skip ASCII control codes). 85 | 86 | if ( codepoint > 127 ) { codepoint += ( 0xA0 - 0x80 ); } // A0 includes Latin-1 Punctuation ans Symbols section. 87 | 88 | // up to position 175 ( 11 rows of 16 ) 89 | // Extras 90 | if ( 192 == index ) { codepoint = 0x0153; printf("got cp!\n");} 91 | if ( 193 == index ) { codepoint = 0x0154; } 92 | if ( 194 == index ) { codepoint = 0x01EA; } 93 | if ( 195 == index ) { codepoint = 0x01EB; } 94 | return codepoint; 95 | } 96 | 97 | bool draw_atlas( const char* filename, int thickness, int add_outline, apg_pixfont_style_t style ) { 98 | int max_w = 0, max_h = 0; 99 | for ( int i = 0; i < 256; i++ ) { 100 | uint32_t codepoint = get_codepoint( i ); 101 | char tmp[5] = { i - ' ', '\0' }; 102 | if ( !apg_cp_to_utf8( codepoint, tmp ) ) { return false; } 103 | int w = 0, h = 0; 104 | if ( !apg_pixfont_image_size_for_str( tmp, &w, &h, thickness, add_outline, style, 0 ) ) { continue; } 105 | max_w = w < max_w ? max_w : w; 106 | max_h = h < max_h ? max_h : h; 107 | } 108 | printf( "atlas style %i: glyph max_w,h = %ix%i cell pixel dims = %ix%i\n", (int)style, max_w, max_h, cell_dims[0], cell_dims[1] ); 109 | // -2 below, is to account for +1 for outline and +1 for uneven number adjustment. 110 | // Default y size is 16 pixels, if outline is drawn then 17. That will get rounded up to 18. 111 | // In the worst case a fully-spanning top-to-bottom glyph (unlikely) would lose the outline pixel on the bottom. 112 | // Biggest width for 1 glyph in a cell, at thickness 1, should be 6 (widest glyph) + 7 (max italics shift) + 1 (outline) = 14. 113 | if ( max_w > cell_dims[0] || max_h - 2 > cell_dims[1] ) { 114 | fprintf( stderr, "ERROR: cells are not big enough for glyphs. Resize.\n" ); 115 | // return 1; 116 | } 117 | int n_chans = 4; // Could be 2, or even 1, if there are no outlines. 118 | uint8_t* atlas_ptr = calloc( cell_dims[0] * cell_dims[1] * n_chans, 256 ); 119 | if ( !atlas_ptr ) { 120 | fprintf( stderr, "ERROR: malloc OOM\n" ); 121 | return false; 122 | } 123 | size_t subimg_sz = cell_dims[0] * cell_dims[1] * n_chans; 124 | uint8_t* subimg_ptr = calloc( subimg_sz, 1 ); 125 | if ( !subimg_ptr ) { 126 | fprintf( stderr, "ERROR: malloc OOM\n" ); 127 | return false; 128 | } 129 | for ( int i = 0; i < 256; i++ ) { 130 | memset( subimg_ptr, 0, subimg_sz ); 131 | uint32_t codepoint = get_codepoint( i ); 132 | char tmp[5] = { i - ' ', '\0' }; 133 | if ( !apg_cp_to_utf8( codepoint, tmp ) ) { return false; } 134 | uint32_t cell_col = i % 16; 135 | uint32_t cell_row = i / 16; 136 | if ( !apg_pixfont_str_into_image( tmp, subimg_ptr, cell_dims[0], cell_dims[1], n_chans, 0xFF, 0xFF, 0xFF, 0xFF, thickness, add_outline, style, 0 ) ) { 137 | fprintf( stderr, "Bad result writing image for char %i '%c'\n", i, tmp[0] ); 138 | continue; 139 | } 140 | /* uncomment this bit to get a separate image for each glyph: 141 | char subimg_str[64]; 142 | sprintf( subimg_str, "images/%i.png", i ); 143 | stbi_write_png( subimg_str, cell_dims[0], cell_dims[1], n_chans, subimg_ptr, cell_dims[0] * n_chans ); 144 | */ 145 | size_t cell_row_offset = cell_row * 16 * cell_dims[0] * cell_dims[1] * n_chans; 146 | size_t cell_col_offset = cell_col * cell_dims[0] * n_chans; 147 | for ( int y = 0; y < cell_dims[1]; y++ ) { // Copy one sub-image line at a time. 148 | uint8_t* dst_ptr = atlas_ptr + cell_row_offset + cell_col_offset + y * 16 * cell_dims[0] * n_chans; 149 | uint8_t* src_ptr = subimg_ptr + cell_dims[0] * n_chans * y; 150 | memcpy( dst_ptr, src_ptr, cell_dims[0] * n_chans ); 151 | } 152 | } 153 | int ret = stbi_write_png( filename, cell_dims[0] * 16, cell_dims[1] * 16, n_chans, atlas_ptr, cell_dims[0] * 16 * n_chans ); 154 | free( subimg_ptr ); 155 | free( atlas_ptr ); 156 | if ( !ret ) { return false; } 157 | return true; 158 | } 159 | 160 | int main() { 161 | const char* atlas_str = "atlas.png"; 162 | const char* atlas_bold_str = "atlas_bold.png"; 163 | const char* atlas_italic_str = "atlas_italic.png"; 164 | const char* atlas_underline_str = "atlas_underline.png"; 165 | const char* atlas_strikethrough_str = "atlas_strikethrough.png"; 166 | // Find max dimensions per character and check that font will fit in atlas. 167 | int thickness = 1; 168 | int add_outline = 1; 169 | 170 | if ( !draw_atlas( atlas_str, thickness, add_outline, APG_PIXFONT_STYLE_REGULAR ) ) { fprintf( stderr, "ERROR drawing regular atlas.\n" ); } 171 | if ( !draw_atlas( atlas_bold_str, thickness, add_outline, APG_PIXFONT_STYLE_BOLD ) ) { fprintf( stderr, "ERROR drawing bold atlas.\n" ); } 172 | if ( !draw_atlas( atlas_italic_str, thickness, add_outline, APG_PIXFONT_STYLE_ITALIC ) ) { fprintf( stderr, "ERROR drawing italic atlas.\n" ); } 173 | if ( !draw_atlas( atlas_underline_str, thickness, add_outline, APG_PIXFONT_STYLE_UNDERLINE ) ) { fprintf( stderr, "ERROR drawing underline atlas.\n" ); } 174 | if ( !draw_atlas( atlas_strikethrough_str, thickness, add_outline, APG_PIXFONT_STYLE_STRIKETHROUGH ) ) { 175 | fprintf( stderr, "ERROR drawing strikthrough atlas.\n" ); 176 | } 177 | printf( "done\n" ); 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /apg_plot/apg_plot.h: -------------------------------------------------------------------------------- 1 | /* =============================================================================================== 2 | apg_plot 3 | Mini-library for creating quick bitmaps with line plots of a 2D data series. 4 | Author: Anton Gerdelan @capnramses 5 | URL: https://github.com/capnramses/apg 6 | Licence: See bottom of file. 7 | Language: C99. 8 | ================================================================================================== 9 | Compilation Instructions: 10 | * Drop apg_plot.h and .c into your C or C++ project source files. 11 | * Make sure that your build system or compiler compiles the .c file as C, not as C++. 12 | 13 | API Instructions: 14 | * Call apg_plot_init() somewhere in your code to create a new chart of given dimensions. 15 | * To plot a data series as points call apg_plot_plot_points(), providing your array of xy 16 | data. 17 | * This library assumes your data memory layout is a 1D or 2D array in the memory order: 18 | x-value,y-value,x-value,y-value... for n data points. 19 | 20 | Test/Example Instructions: 21 | * To compile the example, assuming you have the whole apg repository, or otherwise have 22 | stb_image_write.h: 23 | gcc apg_plot.c -D_APG_PLOT_UNIT_TEST -I ../third_party/stb/ -lm 24 | ================================================================================================== 25 | TODO: 26 | * An 'advance chart' option for ring buffer scrolling charts to memcpy() rather than redraw the 27 | whole thing each time it updates. 28 | * Possibly try Wu's line draw as an alternative. 29 | * Possibly allow symbols and/or error bars for plot points. This would require a different sort 30 | of data range: ~ x-value,y-value,x-error,y-error,... 31 | * Functions to allow lines/plots/axes to be bigger than 1 pixel, for higher-resolution bitmaps. 32 | * Maybe add tics to axes. Possibly also an optional apg_pixel_font text or so. 33 | ================================================================================================== 34 | History: 35 | 0.2.1 - 2023/04/19 - Minor compiler warning tweaks. 36 | 0.2 - 2022/07/20 - Export symbols and renamed to apg_plot because its shorter and cooler. 37 | 0.1 - 2022/07/20 - First version in apg libraries. Pulled from hobby project and tidied up. 38 | ================================================================================================== 39 | */ 40 | 41 | #pragma once 42 | 43 | #ifdef _WIN32 44 | /** Explicit symbol export for building .dll files with MSVC so it generates a corresponding .lib file. */ 45 | #define APG_PLOT_EXPORT __declspec( dllexport ) 46 | #else 47 | #define APG_PLOT_EXPORT 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | #include 55 | #include 56 | 57 | typedef struct apg_plot_params_t { 58 | int w, h; // Pixels dimensions. 59 | float min_x, max_x, min_y, max_y; // Chart data value bounds on each axis. 60 | } apg_plot_params_t; 61 | 62 | typedef struct apg_plot_t { 63 | uint8_t* rgb_ptr; // Pixels. 64 | apg_plot_params_t params; 65 | } apg_plot_t; 66 | 67 | APG_PLOT_EXPORT apg_plot_t apg_plot_init( apg_plot_params_t chart_params ); 68 | 69 | APG_PLOT_EXPORT bool apg_plot_free( apg_plot_t* chart_ptr ); 70 | 71 | APG_PLOT_EXPORT bool apg_plot_clear( apg_plot_t* chart_ptr ); 72 | 73 | APG_PLOT_EXPORT bool apg_plot_plot_lines( apg_plot_t* chart_ptr, float* xy_ptr, int n ); 74 | 75 | APG_PLOT_EXPORT bool apg_plot_plot_points( apg_plot_t* chart_ptr, float* xy_ptr, int n ); 76 | 77 | APG_PLOT_EXPORT bool apg_plot_x_axis_draw( apg_plot_t* chart_ptr, float y_value ); 78 | 79 | APG_PLOT_EXPORT bool apg_plot_y_axis_draw( apg_plot_t* chart_ptr, float x_value ); 80 | 81 | // These values are global, rather than remembered by a particular chart, and apply to all chart drawing operations. 82 | APG_PLOT_EXPORT void apg_plot_background_colour( uint8_t greyscale_value ); 83 | APG_PLOT_EXPORT void apg_plot_line_colour( uint8_t r, uint8_t g, uint8_t b ); 84 | APG_PLOT_EXPORT void apg_plot_plot_colour( uint8_t r, uint8_t g, uint8_t b ); 85 | APG_PLOT_EXPORT void apg_plot_x_axis_colour( uint8_t r, uint8_t g, uint8_t b ); 86 | APG_PLOT_EXPORT void apg_plot_y_axis_colour( uint8_t r, uint8_t g, uint8_t b ); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | /* 93 | ------------------------------------------------------------------------------------- 94 | This software is available under two licences - you may use it under either licence. 95 | ------------------------------------------------------------------------------------- 96 | FIRST LICENCE OPTION 97 | 98 | > Apache License 99 | > Version 2.0, January 2004 100 | > http://www.apache.org/licenses/ 101 | > Copyright 2019 Anton Gerdelan. 102 | > Licensed under the Apache License, Version 2.0 (the "License"); 103 | > you may not use this file except in compliance with the License. 104 | > You may obtain a copy of the License at 105 | > http://www.apache.org/licenses/LICENSE-2.0 106 | > Unless required by applicable law or agreed to in writing, software 107 | > distributed under the License is distributed on an "AS IS" BASIS, 108 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 109 | > See the License for the specific language governing permissions and 110 | > limitations under the License. 111 | ------------------------------------------------------------------------------------- 112 | SECOND LICENCE OPTION 113 | 114 | > This is free and unencumbered software released into the public domain. 115 | > 116 | > Anyone is free to copy, modify, publish, use, compile, sell, or 117 | > distribute this software, either in source code form or as a compiled 118 | > binary, for any purpose, commercial or non-commercial, and by any 119 | > means. 120 | > 121 | > In jurisdictions that recognize copyright laws, the author or authors 122 | > of this software dedicate any and all copyright interest in the 123 | > software to the public domain. We make this dedication for the benefit 124 | > of the public at large and to the detriment of our heirs and 125 | > successors. We intend this dedication to be an overt act of 126 | > relinquishment in perpetuity of all present and future rights to this 127 | > software under copyright law. 128 | > 129 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 130 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 131 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 132 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 133 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 134 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 135 | > OTHER DEALINGS IN THE SOFTWARE. 136 | > 137 | > For more information, please refer to 138 | ------------------------------------------------------------------------------------- 139 | */ 140 | -------------------------------------------------------------------------------- /apg_tga/02_rainbow.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_tga/02_rainbow.tga -------------------------------------------------------------------------------- /apg_tga/02_write_ppm.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_tga/02_write_ppm.tga -------------------------------------------------------------------------------- /apg_tga/build.bat: -------------------------------------------------------------------------------- 1 | REM building apg_tga tests... 2 | gcc -g -Wall -Wextra -pedantic -Wfatal-errors -o test_read_tga.exe test_code/main_read.c -I . -Itest_code/ -DAPG_TGA_DEBUG_OUTPUT 3 | gcc -g -Wall -Wextra -pedantic -Wfatal-errors -o test_write_tga.exe test_code/main_write.c -I . -Itest_code/ -DAPG_TGA_DEBUG_OUTPUT 4 | pause 5 | -------------------------------------------------------------------------------- /apg_tga/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang -fsanitize=address -fsanitize=undefined -g -Wall -Wextra -pedantic -o test_read_tga.bin test_code/main_read.c -I ./ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 3 | clang -fsanitize=address -fsanitize=undefined -g -Wall -Wextra -pedantic -o test_write_tga.bin test_code/main_write.c -I ./ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 4 | -------------------------------------------------------------------------------- /apg_tga/palette.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/apg_tga/palette.tga -------------------------------------------------------------------------------- /apg_tga/test_code/main_read.c: -------------------------------------------------------------------------------- 1 | 2 | #define APG_TGA_IMPLEMENTATION 3 | #include "apg_tga.h" 4 | #define STB_IMAGE_WRITE_IMPLEMENTATION 5 | #include "stb_image_write.h" 6 | #include 7 | 8 | int main( int argc, char** argv ) { 9 | if ( argc < 2 ) { 10 | printf( "usage: test_read MY_IMAGE.tga\n" ); 11 | return 0; 12 | } 13 | printf( "opening `%s`\n", argv[1] ); 14 | 15 | unsigned int w = 0, h = 0; 16 | unsigned int n_chans = 0; 17 | int vert_flip = 0; 18 | unsigned char* img_mem = apg_tga_read_file( argv[1], &w, &h, &n_chans, vert_flip ); 19 | if ( !img_mem ) { 20 | fprintf( stderr, "ERROR: failed to read image `%s`\n", argv[1] ); 21 | return 1; 22 | } 23 | 24 | // convert BGR to RGB or BGRA to RGBA 25 | if (!apg_tga_bgr_to_rgb(img_mem, w,h,n_chans)) { return 1; } 26 | 27 | if ( !stbi_write_png( "out.png", w, h, n_chans, img_mem, w * n_chans ) ) { 28 | fprintf( stderr, "ERROR: writing out PNG\n" ); 29 | return 1; 30 | } 31 | printf( "wrote image of w %u h %u n_chans %u\n", w, h, n_chans ); 32 | 33 | free( img_mem ); 34 | printf( "done\n" ); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /apg_tga/test_code/main_write.c: -------------------------------------------------------------------------------- 1 | /* 2 | Test Program for apg_tga.h 3 | Author: Anton Gerdelan -- @capnramses 4 | */ 5 | 6 | #define STB_IMAGE_IMPLEMENTATION 7 | #include "stb_image.h" 8 | #define APG_TGA_IMPLEMENTATION 9 | #include "apg_tga.h" 10 | #include 11 | #include 12 | 13 | int main( int argc, char** argv ) { 14 | if ( argc < 2 ) { 15 | printf( "usage: %s my_file.tga\n", argv[0] ); 16 | return 0; 17 | } 18 | printf( "loading %s\n", argv[1] ); 19 | int w, h, n; 20 | uint8_t* img = stbi_load( argv[1], &w, &h, &n, 0 ); 21 | if ( !img ) { return 1; } 22 | 23 | printf( "loaded %s - %ix%i n=%i!\n", argv[1], w, h, n ); 24 | if(!apg_tga_bgr_to_rgb( img, (unsigned int)w,(unsigned int)h,(unsigned int)n)){return 1;} 25 | 26 | if ( !apg_tga_write_file( "out.tga", img, (unsigned int)w, (unsigned int)h, (unsigned int)n ) ) { 27 | fprintf( stderr, "ERROR writing file\n" ); 28 | return 1; 29 | } 30 | free( img ); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /apg_unicode/apg_unicode.h: -------------------------------------------------------------------------------- 1 | /* apg_unicode 2 | Unicode <-> UTF-8 Multibyte String Functions for C & C++ 3 | Anton Gerdelan 4 | Version: 0.2.2 5 | Licence: see bottom of file. 6 | C89 ( Implementation is C99 ) 7 | 8 | TODO: 9 | * Find out why some vars in bitwise ops are unused - feels like a copy-paste mistake between versions. 10 | * Compile with all warnings and address unused vars etc. 11 | * More tests. Arabic, reversed, etc 12 | * CI tests. 13 | 14 | Not Supported (Yet): 15 | * Arabic (and other) ligatures 16 | 17 | Further Reading: 18 | * On special unicode "non-spacing" modifier codepoints: http://mts.io/2015/04/21/unicode-symbol-render-text-emoji/ 19 | * Skin tone modifier sequences https://unicode.org/emoji/charts/full-emoji-modifiers.html 20 | * A good description of Arabic text formatting and styling https://w3c.github.io/alreq/ 21 | * I based Arabic cursive look-up table on the medial and final forms available in https://www.unicode.org/charts/PDF/UFE70.pdf 22 | 23 | History: 24 | * 0.2.0 3 May 2020 Dug up unicode files from Project Storm and brushed off the dust. 25 | */ 26 | 27 | #pragma once 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #include 34 | 35 | #define APG_UNICODE_MAX_STR 2048 // max length of string. for avoiding infinite loops. 36 | 37 | /* Converts a unicode codepoint to an UTF-8 encoded multi-byte sequence. 38 | PARAMS 39 | mbs - Pointer to a buffer location that can hold the UTF-8 multi-byte sequence + null terminator (max 5 bytes). 40 | RETURNS: Number of bytes in the sequence (1 - 4). On error the function returns 4 and mbs holds the question mark character . 41 | NOTE: UTF-8 mbs can be used with ASCII string functions that process byte-by-byte. 42 | */ 43 | int apg_cp_to_utf8( uint32_t codepoint, char* mbs ); 44 | 45 | /* Converts part of an utf-8 encoded multi-byte sequence (i.e. a string) to a unicode codepoint. 46 | PARAMS 47 | mbs - Pointer to first byte of UTF-8 sequence in a multi-byte array. 48 | sz - Sets number of bytes detected in sequence (1 - 4). 49 | RETURNS: Unicode codepoint, or 0 on error or end of string. 50 | */ 51 | uint32_t apg_utf8_to_cp( const char* mbs, int* sz ); 52 | 53 | /* Get number of codepoints in an UTF8-encoded sequence. Note that strlen() on a MBS returns the number of bytes, not codepoints. 54 | PARAMS 55 | buf - must be nul-terminated 56 | RETURNS < 0 on error, or the number of valid code points in the multi-byte sequence */ 57 | int apg_utf8_count_cp( const char* buf ); 58 | 59 | /* Reverse an UTF-8 encoded multi-byte string. 60 | PARAMS 61 | out - Output multi-byte string. 62 | in - Input multi-byte string. Must be nul-terminated. 63 | */ 64 | void apg_utf8_reverse( char* out, const char* in ); 65 | 66 | /* Conversion of Arabic codepoint to correct cursive form, based on cursive properties of neighbouring codepoints. Simply put: joins the lines together between 67 | characters. 68 | PARAMS: cp_left and cp_right are in order of writing/reading - right-to-left. So cp_right is the /earlier/ codepoint. 69 | RETURNS: Unicode codepoint for correct cursive to use for an Arabic codepoint within a string. 70 | NOTE: Memory order for right-to-left text is usually element [0] => rightmost, [len-1] => leftmost. 71 | */ 72 | uint32_t apg_cursive_arabic_cp( uint32_t cp_left, uint32_t cp, uint32_t cp_right ); 73 | 74 | /* Converts any general Unicode Arabic characters (U+0627 to U+0649) to cursive-aware equivalents. 75 | PARAMS 76 | in - Input must be in standard right-to-left memory arrangement. Must be nul-terminated. 77 | out - Output will be a string of the same size in range (U+FE70 to U+FEFF ). 78 | WARNING: You must allow extra space in the output buffer in case bytes required per codepoint increases to 3. 79 | */ 80 | void apg_utf8_convert_to_arabic_cursive( char* out, const char* in, int* out_sz ); 81 | 82 | /* Trims the end n chars from a utf8-encoded string. 83 | PARAMS 84 | buf - Must be nul-terminated. 85 | NOTE: Searches string from front-to-back so not efficient for long strings. 86 | Could instead be implemented to progressively look at last 4 bytes for unicode indicators. 87 | */ 88 | void apg_utf8_trim_end( char* buf, int n ); 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | /* 95 | ------------------------------------------------------------------------------------- 96 | This software is available under two licences - you may use it under either licence. 97 | ------------------------------------------------------------------------------------- 98 | FIRST LICENCE OPTION 99 | 100 | > Apache License 101 | > Version 2.0, January 2004 102 | > http://www.apache.org/licenses/ 103 | > Copyright 2019 Anton Gerdelan. 104 | > Licensed under the Apache License, Version 2.0 (the "License"); 105 | > you may not use this file except in compliance with the License. 106 | > You may obtain a copy of the License at 107 | > http://www.apache.org/licenses/LICENSE-2.0 108 | > Unless required by applicable law or agreed to in writing, software 109 | > distributed under the License is distributed on an "AS IS" BASIS, 110 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 111 | > See the License for the specific language governing permissions and 112 | > limitations under the License. 113 | ------------------------------------------------------------------------------------- 114 | SECOND LICENCE OPTION 115 | 116 | > This is free and unencumbered software released into the public domain. 117 | > 118 | > Anyone is free to copy, modify, publish, use, compile, sell, or 119 | > distribute this software, either in source code form or as a compiled 120 | > binary, for any purpose, commercial or non-commercial, and by any 121 | > means. 122 | > 123 | > In jurisdictions that recognize copyright laws, the author or authors 124 | > of this software dedicate any and all copyright interest in the 125 | > software to the public domain. We make this dedication for the benefit 126 | > of the public at large and to the detriment of our heirs and 127 | > successors. We intend this dedication to be an overt act of 128 | > relinquishment in perpetuity of all present and future rights to this 129 | > software under copyright law. 130 | > 131 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 132 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 133 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 134 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 135 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 136 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 137 | > OTHER DEALINGS IN THE SOFTWARE. 138 | > 139 | > For more information, please refer to 140 | ------------------------------------------------------------------------------------- 141 | */ 142 | -------------------------------------------------------------------------------- /apg_unicode/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gcc -o test_unicode.bin tests/main.c apg_unicode.c -I ./ 3 | -------------------------------------------------------------------------------- /apg_unicode/tests/main.c: -------------------------------------------------------------------------------- 1 | // test program 2 | // COMPILE: 3 | // gcc main.c ../apg_unicode.c -I ../ 4 | // RUN: 5 | // a.out ./test.txt (or any UTF-8 file) 6 | // only the first 2048 or fewer bytes are read from the file. 7 | // output: out.txt (UTF-8) 8 | 9 | #include "apg_unicode.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define APG_MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) ) 17 | #define APG_MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) 18 | #define APG_CLAMP( x, lo, hi ) ( APG_MIN( hi, APG_MAX( lo, x ) ) ) 19 | 20 | /* convenience struct and file->memory function */ 21 | typedef struct _entire_file_t { 22 | void* data; 23 | size_t sz; 24 | } _entire_file_t; 25 | 26 | /* 27 | RETURNS 28 | - true on success. record->data is allocated memory and must be freed by the caller. 29 | - false on any error. Any allocated memory is freed if false is returned */ 30 | static bool _read_entire_file( const char* filename, _entire_file_t* record ) { 31 | FILE* fp = fopen( filename, "rb" ); 32 | if ( !fp ) { return false; } 33 | fseek( fp, 0L, SEEK_END ); 34 | record->sz = (size_t)ftell( fp ); 35 | record->data = malloc( record->sz + 1 ); // + 1 to allow for a \0 to be appended 36 | if ( !record->data ) { 37 | fclose( fp ); 38 | return false; 39 | } 40 | rewind( fp ); 41 | size_t nr = fread( record->data, record->sz, 1, fp ); 42 | fclose( fp ); 43 | if ( 1 != nr ) { return false; } 44 | return true; 45 | } 46 | 47 | int apg_strnlen( const char* str, int maxlen ) { 48 | int i = 0; 49 | while ( i < maxlen && str[i] ) { i++; } 50 | return i; 51 | } 52 | 53 | int main( int argc, char** argv ) { 54 | if ( argc < 2 ) { 55 | printf( "usage: a.out UTF8INPUTFILE.txt\n" ); 56 | return 0; 57 | } 58 | 59 | // read whole file into a buffer 60 | _entire_file_t record = { .sz = 0 }; 61 | if ( !_read_entire_file( argv[1], &record ) ) { 62 | fprintf( stderr, "ERROR opening file `%s`\n", argv[1] ); 63 | return 1; 64 | } 65 | char *ptr = (char*)record.data; 66 | ptr[record.sz] = '\0'; 67 | 68 | // just read the first N chars from the file as a string. ignore the rest. 69 | int sz = strnlen( ptr, APG_MIN( record.sz, APG_UNICODE_MAX_STR ) ); 70 | 71 | FILE* fp = fopen( "out.txt", "w" ); 72 | while ( sz > 0 ) { 73 | // convert a sequence of up to 4 UTF-8 bytes into a 32-bit codepoint 74 | uint32_t cp = apg_utf8_to_cp( ptr, &sz ); 75 | // store the sequence of UTF-8 bytes in a temporary string. 76 | char tmp[5]; 77 | tmp[0] = 0; 78 | strncat( tmp, ptr, sz ); 79 | char tmpb[5]; 80 | // convert the codepoint back to a UTF-8 byte sequence 81 | int szb = apg_cp_to_utf8( cp, tmpb ); 82 | // compare the new output with the original bytes and report an error if they did not match 83 | if ( 0 != strcmp( tmp, tmpb ) ) { 84 | fprintf( fp, "ERROR [%s] vs [%s] cp = %u (U+%04X), sz = %i,%i\n", tmp, tmpb, cp, cp, sz, szb ); 85 | } 86 | // write to out.txt: 87 | // 1. the UTF-8 byte sequence as a string, 88 | // 2. then the codepoint decimal value, 89 | // 3. then the UTF-8 unicode hex value, 90 | // 4. then the size in bytes. 91 | fprintf( fp, "[%s] cp = %u (U+%04X), sz = %i\n", tmp, cp, cp, sz ); 92 | ptr += sz; 93 | } 94 | fclose( fp ); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /apg_unicode/tests/test.txt: -------------------------------------------------------------------------------- 1 | Fáilte.Ő ΏΘ ЩӜ ݞ ణ ആ ญ ᚉ ant😈n ᛋ € ✋ is Amazing ✌️ ぢぽ\n习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯𠀀 2 | -------------------------------------------------------------------------------- /apg_wav/apg_wav.c: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | Wave file read/write 3 | Anton Gerdelan 4 | C99 5 | Version 0.2.1 6 | Licence: see header. 7 | \*****************************************************************************/ 8 | 9 | #include "apg_wav.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Convenience struct and file->memory function. 16 | typedef struct entire_file_t { 17 | void* data_ptr; 18 | size_t sz; 19 | } entire_file_t; 20 | 21 | static bool _read_entire_file( const char* filename, entire_file_t* record_ptr ) { 22 | FILE* fp = fopen( filename, "rb" ); 23 | if ( !fp ) { return false; } 24 | fseek( fp, 0L, SEEK_END ); 25 | record_ptr->sz = (size_t)ftell( fp ); 26 | record_ptr->data_ptr = malloc( record_ptr->sz ); 27 | if ( !record_ptr->data_ptr ) { 28 | fclose( fp ); 29 | return false; 30 | } 31 | rewind( fp ); 32 | size_t nr = fread( record_ptr->data_ptr, record_ptr->sz, 1, fp ); 33 | fclose( fp ); 34 | if ( 1 != nr ) { return false; } 35 | return true; 36 | } 37 | 38 | bool apg_wav_write( const char* filename, const void* data_ptr, uint32_t data_sz, uint16_t n_chans, uint32_t sample_rate_hz, uint32_t n_samples, uint16_t bits_per_sample ) { 39 | if ( !filename || !data_ptr || 0 == data_sz || 0 == n_chans || 0 == sample_rate_hz || 0 == bits_per_sample ) { return false; } 40 | if ( 0 != bits_per_sample % 8 ) { return false; } 41 | 42 | uint32_t bytes_per_sample = bits_per_sample / 8; 43 | apg_wav_header_t wav_header = ( apg_wav_header_t ){ 44 | .file_sz = data_sz + 44, // 45 | .fmt_sz = 16, // 46 | .fmt_type = 1, // 47 | .n_chans = n_chans, // 48 | .sample_rate_hz = sample_rate_hz, // 49 | .byte_rate = sample_rate_hz * n_chans * bytes_per_sample, // 50 | .block_align = ( bits_per_sample * n_chans ) / 8, // 51 | .bits_per_sample = bits_per_sample, // 52 | .data_sz = data_sz // Can't trust converters (ffmpeg!) to do this correctly! 53 | }; 54 | memcpy( wav_header.riff_magic_num, "RIFF", 4 ); 55 | memcpy( wav_header.wave_magic_num, "WAVE", 4 ); 56 | memcpy( wav_header.fmt_magic_num, "fmt ", 4 ); // trailing space is required (erroneously described as a 'null' in other docs). 57 | memcpy( wav_header.data_magic_num, "data", 4 ); 58 | 59 | assert( 44 == sizeof( apg_wav_header_t ) ); 60 | assert( data_sz == n_samples * n_chans * bytes_per_sample ); 61 | 62 | { // File I/O 63 | FILE* fp = fopen( filename, "wb" ); 64 | if ( !fp ) { return false; } 65 | size_t n = fwrite( &wav_header, sizeof( apg_wav_header_t ), 1, fp ); 66 | if ( n != 1 ) { 67 | fclose( fp ); 68 | return false; 69 | } 70 | n = fwrite( data_ptr, data_sz, 1, fp ); 71 | if ( n != 1 ) { 72 | fclose( fp ); 73 | return false; 74 | } 75 | fclose( fp ); 76 | } 77 | return true; 78 | } 79 | 80 | bool apg_wav_read( const char* filename, apg_wav_t* wav_ptr ) { 81 | if ( !filename || !wav_ptr ) { 82 | fprintf( stderr, "ERROR: NULL params\n" ); 83 | return false; 84 | } 85 | 86 | memset( wav_ptr, 0, sizeof( apg_wav_t ) ); 87 | 88 | entire_file_t record; 89 | bool ret = _read_entire_file( filename, &record ); 90 | if ( !ret || 0 == record.sz ) { 91 | fprintf( stderr, "ERROR: Reading file `%s` from disk.\n", filename ); 92 | return false; 93 | } 94 | // too small for any data 95 | if ( record.sz <= 44 ) { 96 | free( record.data_ptr ); 97 | fprintf( stderr, "ERROR: file sz = %i, smaller than WAVE header of 44 bytes\n", (int)record.sz ); 98 | return false; 99 | } 100 | uint8_t* byte_ptr = record.data_ptr; 101 | 102 | wav_ptr->header_ptr = (apg_wav_header_t*)record.data_ptr; 103 | // too small for reported data (not reliable! - might need to remove this validation check). 104 | if ( record.sz < wav_ptr->header_ptr->file_sz || record.sz < wav_ptr->header_ptr->data_sz + 44 ) { 105 | fprintf( stderr, "WARNING: Size of file mismatches data in header. Probably corrupted file.\n" ); 106 | // return false; 107 | } 108 | // unsupported type 109 | if ( wav_ptr->header_ptr->fmt_type != 1 || wav_ptr->header_ptr->fmt_sz != 16 ) { 110 | fprintf( stderr, "WARNING: unsupported format: fmt_type = %i (expected 1), fmt_sz = %i (expected 16)\n", (int)wav_ptr->header_ptr->fmt_type, 111 | wav_ptr->header_ptr->fmt_sz ); 112 | return false; 113 | } 114 | 115 | wav_ptr->file_data_ptr = byte_ptr; 116 | wav_ptr->pcm_data_ptr = &byte_ptr[44]; 117 | 118 | return true; 119 | } 120 | 121 | double apg_wav_duration( const apg_wav_t* wav_ptr ) { 122 | if ( !wav_ptr ) { return -0.0; } 123 | double d = (double)wav_ptr->header_ptr->data_sz / (double)wav_ptr->header_ptr->byte_rate; 124 | return d; 125 | } 126 | 127 | bool apg_wav_free( apg_wav_t* wav_ptr ) { 128 | if ( !wav_ptr || !wav_ptr->file_data_ptr ) { 129 | fprintf( stderr, "ERROR freeing wav - wav_ptr is %p and file_data_ptr is %p\n", (void*)wav_ptr, (void*)wav_ptr->file_data_ptr ); 130 | return false; 131 | } 132 | 133 | free( wav_ptr->file_data_ptr ); 134 | memset( wav_ptr, 0, sizeof( apg_wav_t ) ); 135 | 136 | return true; 137 | } 138 | -------------------------------------------------------------------------------- /apg_wav/apg_wav.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | apg_wav - Waveform Audio File Format read & write 3 | Anton Gerdelan 2022 4 | C99 5 | Licence: See bottom of this file or LICENSE file. 6 | 7 | History 8 | ------- 9 | 0.2.1 - 17 Jan 2022 - Duration function. Degrated some file parsing errors to 10 | warnings. 11 | 0.2 - 04 Jan 2022 - Tidied up and testing reading with a PortAudio example. 12 | 0.1 - ??? - First version on GitHub. 13 | \*****************************************************************************/ 14 | 15 | #ifndef _APG_WAV_H_ 16 | #define _APG_WAV_H_ 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #include 23 | #include 24 | 25 | #pragma pack( push, 1 ) 26 | /// Header from a .wav file. 44-bytes. 27 | typedef struct apg_wav_header_t { 28 | char riff_magic_num[4]; // "RIFF" 29 | uint32_t file_sz; // Overall file size in bytes. 30 | char wave_magic_num[4]; // "WAVE" 31 | char fmt_magic_num[4]; // "fmt\0" includes trailing null. Marks start of format subchunk. 32 | uint32_t fmt_sz; // Size of this format subchunk in bytes. 33 | uint16_t fmt_type; // 1=PCM. Other numbers indicate compression (not supported). 34 | uint16_t n_chans; // Number of audio channels. 2 for stereo. 35 | uint32_t sample_rate_hz; // 44100 (CD) 48000 (DAT) ... 36 | uint32_t byte_rate; // ( sample_rate_hz * bytes per sample * n_chans ) 37 | uint16_t block_align; // (BitsPerSample * Channels) / 8. ->> 1 = 8-bit mono. 2 = 8-bit stereo. 3 = 8-bit stereo or 16-bit mono. 4 = 16-bit stereo. 38 | uint16_t bits_per_sample; // Usually 16 but can be 8. 39 | char data_magic_num[4]; // "data" 40 | uint32_t data_sz; // Size of PCM data section in bytes. 41 | } apg_wav_header_t; 42 | #pragma pack( pop ) 43 | 44 | typedef struct apg_wav_t { 45 | apg_wav_header_t* header_ptr; // Use for playback settings. 46 | uint8_t* file_data_ptr; // Pointer to entire file 47 | uint8_t* pcm_data_ptr; // Pointer to the data section (44 bytes on from top of file data). 48 | } apg_wav_t; 49 | 50 | /// Information returned when reading a file that can be used for playing it back correctly. 51 | 52 | bool apg_wav_write( const char* filename, const void* data_ptr, uint32_t data_sz, uint16_t n_chans, uint32_t sample_rate_hz, uint32_t n_samples, uint16_t bits_per_sample ); 53 | 54 | /** 55 | * @param wav_data_ptr Pointer to a previously unused struct to fill out, including allocating memory to store file contents. 56 | * @return Returns false on error. 57 | * @warning This function allocates memory. Call apg_wav_free() on your apg_wav_data_t when done with playback, to release memory. 58 | */ 59 | bool apg_wav_read( const char* filename, apg_wav_t* wav_data_ptr ); 60 | 61 | double apg_wav_duration( const apg_wav_t* wav_ptr ); 62 | 63 | bool apg_wav_free( apg_wav_t* wav_data_ptr ); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif 70 | 71 | /* 72 | ------------------------------------------------------------------------------------- 73 | This software is available under two licences - you may use it under either licence. 74 | ------------------------------------------------------------------------------------- 75 | FIRST LICENCE OPTION 76 | 77 | > Apache License 78 | > Version 2.0, January 2004 79 | > http://www.apache.org/licenses/ 80 | > Copyright 2019 Anton Gerdelan. 81 | > Licensed under the Apache License, Version 2.0 (the "License"); 82 | > you may not use this file except in compliance with the License. 83 | > You may obtain a copy of the License at 84 | > http://www.apache.org/licenses/LICENSE-2.0 85 | > Unless required by applicable law or agreed to in writing, software 86 | > distributed under the License is distributed on an "AS IS" BASIS, 87 | > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 88 | > See the License for the specific language governing permissions and 89 | > limitations under the License. 90 | ------------------------------------------------------------------------------------- 91 | SECOND LICENCE OPTION 92 | 93 | > This is free and unencumbered software released into the public domain. 94 | > 95 | > Anyone is free to copy, modify, publish, use, compile, sell, or 96 | > distribute this software, either in source code form or as a compiled 97 | > binary, for any purpose, commercial or non-commercial, and by any 98 | > means. 99 | > 100 | > In jurisdictions that recognize copyright laws, the author or authors 101 | > of this software dedicate any and all copyright interest in the 102 | > software to the public domain. We make this dedication for the benefit 103 | > of the public at large and to the detriment of our heirs and 104 | > successors. We intend this dedication to be an overt act of 105 | > relinquishment in perpetuity of all present and future rights to this 106 | > software under copyright law. 107 | > 108 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 109 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 110 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 111 | > IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 112 | > OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 113 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 114 | > OTHER DEALINGS IN THE SOFTWARE. 115 | > 116 | > For more information, please refer to 117 | ------------------------------------------------------------------------------------- 118 | */ 119 | -------------------------------------------------------------------------------- /apg_wav/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gcc -o play_file.bin \ 3 | examples/main_play_file.c \ 4 | apg_wav.c \ 5 | -I ./ \ 6 | -lportaudio 7 | -------------------------------------------------------------------------------- /apg_wav/examples/main_play_file.c: -------------------------------------------------------------------------------- 1 | // Example that plays a .wav file 2 | // For this example install the PortAudio library first: 3 | // http://portaudio.com/ 4 | // Ubuntu: `sudo apt install portaudio19-dev` 5 | // Compile e.g.: 6 | // gcc examples/main_play_file.c apg_wav.c -o test_play_file.bin -I ./ -lm -lportaudio 7 | 8 | #include "portaudio.h" 9 | #include "apg_wav.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // User data struct 17 | typedef struct audio_source_t { 18 | apg_wav_t wav; // Audio data loaded by apg_wav 19 | double duration_s; 20 | uint32_t wav_data_idx; // Counter of where my wav is up to in playback of bytes. 21 | } audio_source_t; 22 | 23 | // Callback that feeds wave data into port audio's stream during playback 24 | static int antons_pa_cb( const void* input_buffer_ptr, void* output_buffer_ptr, unsigned long frames_per_buffer, const PaStreamCallbackTimeInfo* time_info_ptr, 25 | PaStreamCallbackFlags status_flags, void* user_data_ptr ) { 26 | (void)input_buffer_ptr; // suppress unused var warning 27 | 28 | audio_source_t* src_ptr = (audio_source_t*)user_data_ptr; 29 | assert( src_ptr ); 30 | 31 | // because some encoders like ffmpeg break this WAV variable we need to calculate it from the file size. 32 | uint32_t actual_data_sz = src_ptr->wav.header_ptr->file_sz - 44; // 44 is size of WAV PCM header. 33 | 34 | uint32_t sample_sz = src_ptr->wav.header_ptr->bits_per_sample / 8; 35 | 36 | if ( src_ptr->wav_data_idx + frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz < actual_data_sz ) { 37 | memcpy( output_buffer_ptr, &src_ptr->wav.pcm_data_ptr[src_ptr->wav_data_idx], frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz ); 38 | } else { 39 | memset( output_buffer_ptr, 0, frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz ); 40 | } 41 | src_ptr->wav_data_idx += frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz; 42 | 43 | return 0; 44 | } 45 | 46 | int main( int argc, char** argv ) { 47 | if ( argc < 2 ) { 48 | printf( "usage: %s FILE.wav\n", argv[0] ); 49 | return 0; 50 | } 51 | const char* filename = argv[1]; 52 | 53 | // Load a WAV file from disk 54 | printf( "loading `%s`\n", filename ); 55 | audio_source_t audio_source = ( audio_source_t ){ .wav_data_idx = 0 }; 56 | bool res = apg_wav_read( filename, &audio_source.wav ); 57 | if ( !res ) { 58 | fprintf( stderr, "ERROR loading file %s %i\n", filename ); 59 | return 1; 60 | } 61 | audio_source.duration_s = apg_wav_duration( &audio_source.wav ); 62 | 63 | // Start PortAudio 64 | printf( "%s\n", Pa_GetVersionText() ); 65 | PaError err = Pa_Initialize(); 66 | if ( err != paNoError ) { 67 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 68 | return 1; 69 | } 70 | printf( "BPS = %i\n", (int)audio_source.wav.header_ptr->bits_per_sample ); 71 | 72 | PaSampleFormat fmt = paFloat32; 73 | switch ( audio_source.wav.header_ptr->bits_per_sample ) { 74 | case 16: fmt = paInt16; break; 75 | case 8: fmt = paUInt8; break; // 8-bit is unsigned in wav, but 16 is signed. 76 | default: 77 | fprintf( stderr, "WARNING: unhandled bits-per-sample of %i detected.\n", audio_source.wav.header_ptr->bits_per_sample ); 78 | fmt = paInt16; 79 | break; // guess 80 | } 81 | 82 | PaStream* stream = NULL; // usually just 1 stream per device 83 | err = Pa_OpenDefaultStream( &stream, 84 | 0, // no input channels (mic/record etc) 85 | audio_source.wav.header_ptr->n_chans, // mono/stereo 86 | fmt, // 8-bit, 16-bit int or 32-bit float supported in this demo 87 | audio_source.wav.header_ptr->sample_rate_hz, 88 | 256, // frames per buffer to request from callback (can use paFramesPerBufferUnspecified) 89 | antons_pa_cb, &audio_source ); 90 | if ( err != paNoError ) { 91 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 92 | return 1; 93 | } 94 | 95 | printf( "sample Hz: %i\n", audio_source.wav.header_ptr->sample_rate_hz ); 96 | printf( "wav duration %lf\n", audio_source.duration_s ); 97 | 98 | Pa_StartStream( stream ); 99 | if ( err != paNoError ) { 100 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 101 | return 1; 102 | } 103 | 104 | Pa_Sleep( audio_source.duration_s * 1000 ); 105 | 106 | err = Pa_StopStream( stream ); 107 | if ( err != paNoError ) { 108 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 109 | return 1; 110 | } 111 | err = Pa_CloseStream( stream ); 112 | if ( err != paNoError ) { 113 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 114 | return 1; 115 | } 116 | err = Pa_Terminate(); 117 | if ( err != paNoError ) { 118 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 119 | return 1; 120 | } 121 | 122 | res = apg_wav_free( &audio_source.wav ); 123 | if ( !res ) { 124 | fprintf( stderr, "ERROR freeing wav resources\n" ); 125 | return false; 126 | } 127 | 128 | printf( "normal exit\n" ); 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /apg_wav/examples/main_visualise.c: -------------------------------------------------------------------------------- 1 | /** Example program that plays a sound and also draws the waveform into an image file `out_vis.png`. 2 | * If the wave file has 2 channels then the second channel is also written, to `out_vis2.png`. 3 | * 4 | * For this example install the PortAudio library first: 5 | * http://portaudio.com/ 6 | * Ubuntu: `sudo apt install portaudio19-dev` 7 | 8 | Compile e.g.: 9 | 10 | Windows MinGW 11 | 12 | gcc -o test_visualise_file.exe examples\main_visualise.c apg_wav.c ..\apg_plot\apg_plot.c 13 | -I . -I ..\apg_plot\ -I ..\third_party\ -I ..\third_party\portaudio\include\ -lm -lportaudio -L . 14 | 15 | Ubuntu 16 | 17 | gcc -o test_visualise_file.bin examples/main_visualise.c apg_wav.c ../apg_plot/apg_plot.c -I ./ -I ../apg_plot/ -I ../third_party/ -lportaudio -lm 18 | 19 | */ 20 | 21 | #include "portaudio.h" 22 | #include "apg_wav.h" 23 | #include "apg_plot.h" 24 | #define STB_IMAGE_WRITE_IMPLEMENTATION 25 | #include "stb/stb_image_write.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | // User data struct 33 | typedef struct audio_source_t { 34 | apg_wav_t wav; // Audio data loaded by apg_wav 35 | double duration_s; 36 | uint32_t wav_data_idx; // Counter of where my wav is up to in playback of bytes. 37 | } audio_source_t; 38 | 39 | // Callback that feeds wave data into port audio's stream during playback 40 | static int antons_pa_cb( const void* input_buffer_ptr, void* output_buffer_ptr, unsigned long frames_per_buffer, const PaStreamCallbackTimeInfo* time_info_ptr, 41 | PaStreamCallbackFlags status_flags, void* user_data_ptr ) { 42 | (void)input_buffer_ptr; // suppress unused var warning 43 | 44 | audio_source_t* src_ptr = (audio_source_t*)user_data_ptr; 45 | assert( src_ptr ); 46 | 47 | // because some encoders like ffmpeg break this WAV variable we need to calculate it from the file size. 48 | uint32_t actual_data_sz = src_ptr->wav.header_ptr->file_sz - 44; // 44 is size of WAV PCM header. 49 | 50 | uint32_t sample_sz = src_ptr->wav.header_ptr->bits_per_sample / 8; 51 | 52 | if ( src_ptr->wav_data_idx + frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz < actual_data_sz ) { 53 | memcpy( output_buffer_ptr, &src_ptr->wav.pcm_data_ptr[src_ptr->wav_data_idx], frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz ); 54 | } else { 55 | memset( output_buffer_ptr, 0, frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz ); 56 | } 57 | src_ptr->wav_data_idx += frames_per_buffer * src_ptr->wav.header_ptr->n_chans * sample_sz; 58 | 59 | return 0; 60 | } 61 | 62 | static void _wav_bitmap( apg_wav_t* wav_ptr ) { 63 | uint32_t actual_data_sz = wav_ptr->header_ptr->file_sz - 44; // 44 is size of WAV PCM header. 64 | uint32_t sample_sz = wav_ptr->header_ptr->bits_per_sample / 8; 65 | int n_channels = wav_ptr->header_ptr->n_chans; 66 | uint32_t n_samples = actual_data_sz / sample_sz; 67 | printf( "sample size %u, n samples %u\n", sample_sz, n_samples ); 68 | float duration_s = apg_wav_duration( wav_ptr ); 69 | int img_width = (int)( duration_s * 512.0f ); 70 | int img_height = 256; 71 | 72 | apg_plot_t chart = 73 | apg_plot_init( ( apg_plot_params_t ){ .h = img_height, .w = img_width, .max_y = 1.0f, .min_y = -1.0f, .max_x = n_samples / n_channels, .min_x = 0 } ); 74 | apg_plot_t chart2 = 75 | apg_plot_init( ( apg_plot_params_t ){ .h = img_height, .w = img_width, .max_y = 1.0f, .min_y = -1.0f, .max_x = n_samples / n_channels, .min_x = 0 } ); 76 | apg_plot_background_colour( 0xCC ); 77 | apg_plot_line_colour( 0x00, 0x00, 0xFF ); 78 | apg_plot_x_axis_colour( 0, 0, 0 ); 79 | apg_plot_clear( &chart ); 80 | apg_plot_clear( &chart2 ); 81 | 82 | float* xy_ptr = malloc( n_samples / n_channels * wav_ptr->header_ptr->bits_per_sample * 2.0f ); 83 | if ( !xy_ptr ) { return; } 84 | float* xy_ptr2 = malloc( n_samples / n_channels * wav_ptr->header_ptr->bits_per_sample * 2.0f ); 85 | if ( !xy_ptr2 ) { return; } 86 | 87 | for ( uint32_t i = 0; i < n_samples / n_channels; i++ ) { 88 | xy_ptr[i * 2 + 0] = (float)i; 89 | if ( 1 == sample_sz ) { // uint8_t 90 | xy_ptr[i * 2 + 1] = (float)wav_ptr->pcm_data_ptr[i * sample_sz * n_channels] / 127.5f - 1.0f; 91 | } else if ( 2 == sample_sz ) { // int16_t signed 92 | int16_t sample = 0; 93 | memcpy( &sample, &wav_ptr->pcm_data_ptr[i * sample_sz * n_channels], sample_sz ); 94 | xy_ptr[i * 2 + 1] = (float)sample / 32768.0f; 95 | } 96 | } 97 | if ( n_channels > 1 ) { 98 | for ( uint32_t i = 0; i < n_samples / n_channels; i++ ) { 99 | xy_ptr2[i * 2 + 0] = (float)i; 100 | if ( 1 == sample_sz ) { // uint8_t 101 | xy_ptr2[i * 2 + 1] = (float)wav_ptr->pcm_data_ptr[( i * n_channels + 1 ) * sample_sz] / 127.5f - 1.0f; 102 | } else if ( 2 == sample_sz ) { // int16_t signed 103 | int16_t sample = 0; 104 | memcpy( &sample, &wav_ptr->pcm_data_ptr[( i * n_channels + 1 ) * sample_sz], sample_sz ); 105 | xy_ptr2[i * 2 + 1] = (float)sample / 32768.0f; 106 | } 107 | } 108 | } 109 | 110 | apg_plot_plot_lines( &chart, xy_ptr, n_samples / n_channels ); 111 | apg_plot_x_axis_draw( &chart, 0.0f ); 112 | stbi_write_png( "out_vis.png", img_width, img_height, 3, chart.rgb_ptr, 3 * img_width ); 113 | if ( n_channels > 1 ) { 114 | apg_plot_plot_lines( &chart2, xy_ptr2, n_samples / n_channels ); 115 | apg_plot_x_axis_draw( &chart2, 0.0f ); 116 | stbi_write_png( "out_vis2.png", img_width, img_height, 3, chart2.rgb_ptr, 3 * img_width ); 117 | } 118 | 119 | free( xy_ptr ); 120 | free( xy_ptr2 ); 121 | apg_plot_free( &chart ); 122 | apg_plot_free( &chart2 ); 123 | } 124 | 125 | int main( int argc, char** argv ) { 126 | if ( argc < 2 ) { 127 | printf( "usage: %s FILE.wav\n", argv[0] ); 128 | return 0; 129 | } 130 | const char* filename = argv[1]; 131 | 132 | // Load a WAV file from disk 133 | printf( "loading `%s`\n", filename ); 134 | audio_source_t audio_source = ( audio_source_t ){ .wav_data_idx = 0 }; 135 | bool res = apg_wav_read( filename, &audio_source.wav ); 136 | if ( !res ) { 137 | fprintf( stderr, "ERROR loading file %s\n", filename ); 138 | return 1; 139 | } 140 | audio_source.duration_s = apg_wav_duration( &audio_source.wav ); 141 | 142 | _wav_bitmap( &audio_source.wav ); 143 | 144 | // Start PortAudio 145 | printf( "%s\n", Pa_GetVersionText() ); 146 | PaError err = Pa_Initialize(); 147 | if ( err != paNoError ) { 148 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 149 | return 1; 150 | } 151 | printf( "BPS = %i\n", (int)audio_source.wav.header_ptr->bits_per_sample ); 152 | printf( "#chans = %i\n", (int)audio_source.wav.header_ptr->n_chans ); 153 | 154 | PaSampleFormat fmt = paFloat32; 155 | switch ( audio_source.wav.header_ptr->bits_per_sample ) { 156 | case 16: fmt = paInt16; break; 157 | case 8: fmt = paUInt8; break; // 8-bit is unsigned in wav, but 16 is signed. 158 | default: 159 | fprintf( stderr, "WARNING: unhandled bits-per-sample of %i detected.\n", audio_source.wav.header_ptr->bits_per_sample ); 160 | fmt = paInt16; 161 | break; // guess 162 | } 163 | 164 | PaStream* stream = NULL; // usually just 1 stream per device 165 | err = Pa_OpenDefaultStream( &stream, 166 | 0, // no input channels (mic/record etc) 167 | audio_source.wav.header_ptr->n_chans, // mono/stereo 168 | fmt, // 8-bit, 16-bit int or 32-bit float supported in this demo 169 | audio_source.wav.header_ptr->sample_rate_hz, 170 | 256, // frames per buffer to request from callback (can use paFramesPerBufferUnspecified) 171 | antons_pa_cb, &audio_source ); 172 | if ( err != paNoError ) { 173 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 174 | return 1; 175 | } 176 | 177 | printf( "sample Hz: %i\n", audio_source.wav.header_ptr->sample_rate_hz ); 178 | printf( "wav duration %lf\n", audio_source.duration_s ); 179 | 180 | Pa_StartStream( stream ); 181 | if ( err != paNoError ) { 182 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 183 | return 1; 184 | } 185 | 186 | Pa_Sleep( audio_source.duration_s * 1000 ); 187 | 188 | err = Pa_StopStream( stream ); 189 | if ( err != paNoError ) { 190 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 191 | return 1; 192 | } 193 | err = Pa_CloseStream( stream ); 194 | if ( err != paNoError ) { 195 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 196 | return 1; 197 | } 198 | err = Pa_Terminate(); 199 | if ( err != paNoError ) { 200 | printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); 201 | return 1; 202 | } 203 | 204 | res = apg_wav_free( &audio_source.wav ); 205 | if ( !res ) { 206 | fprintf( stderr, "ERROR freeing wav resources\n" ); 207 | return false; 208 | } 209 | 210 | printf( "normal exit\n" ); 211 | 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /apg_wav/tests/main_read.c: -------------------------------------------------------------------------------- 1 | #include "apg_wav.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int main( int argc, char** argv ) { 7 | if ( argc < 2 ) { 8 | printf( "usage: ./read FILE.wav\n" ); 9 | return 1; 10 | } 11 | apg_wav_t wav_data = ( apg_wav_t ){ .file_data_ptr = NULL }; 12 | bool res = apg_wav_read( argv[1], &wav_data ); 13 | if ( !res ) { return 1; } 14 | 15 | printf( 16 | "wav_data:\n file_sz = \t\t%i\n fmt_sz = \t\t%i\n fmt_type = \t\t%i\n n_chans = \t\t%i\n sample_rate_hz = \t%i\n byte_rate = \t\t%i\n block_align = " 17 | "\t%i\n bits_per_sample = \t%i\n data_sz =\t\t%i\n", 18 | wav_data.header_ptr->file_sz, wav_data.header_ptr->fmt_sz, wav_data.header_ptr->fmt_type, wav_data.header_ptr->n_chans, wav_data.header_ptr->sample_rate_hz, 19 | wav_data.header_ptr->byte_rate, wav_data.header_ptr->block_align, wav_data.header_ptr->bits_per_sample, wav_data.header_ptr->data_sz ); 20 | 21 | res = apg_wav_free( &wav_data ); 22 | if ( !res ) { return 1; } 23 | 24 | printf( "normal exit\n" ); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /apg_wav/tests/main_write.c: -------------------------------------------------------------------------------- 1 | #include "apg_wav.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int main( void ) { 7 | int n_chans = 1; 8 | int sample_rate = 11025; 9 | int n_samples = 1024; 10 | int bits_per_sample = 16; 11 | // range of values: -32768 to 32767 12 | int16_t wav_data[1024]; 13 | 14 | // store a sinewave pattern in the file 100 times 15 | for ( int i = 0; i < 1024; i++ ) { 16 | float t_fac = i / 1024.0f; 17 | float vf = 32767.0f * sinf( t_fac * t_fac * 6.28f * 100.0f ); 18 | wav_data[i] = (int16_t)vf; 19 | } 20 | 21 | bool result = apg_wav_write( "testout.wav", wav_data, 1024 * sizeof( int16_t ), n_chans, sample_rate, n_samples, bits_per_sample ); 22 | if ( !result ) { return 1; } 23 | printf( "normal exit\n" ); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /build_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # any error code causes script to exit with error code 4 | set -e 5 | # echo everything 6 | #set -x 7 | 8 | colour_pass="\033[32;1m" 9 | colour_default="\033[0m" 10 | horiz_div="========================" 11 | 12 | CC=clang 13 | CPP=clang++ 14 | FLAGS="-fsanitize=address -fsanitize=undefined -Wall -Wextra -Werror -pedantic -g" 15 | 16 | # 17 | # [apg] 18 | # 19 | echo "building apg tests..." 20 | cd apg 21 | $CC $FLAGS -o test_rle_compress_file.bin tests/rle_compress.c -I ./ 22 | $CC $FLAGS -o test_rle_string.bin tests/rle_test.c -I ./ 23 | $CC $FLAGS -o test_hash.bin tests/hash_test.c -I ./ 24 | $CC $FLAGS -o test_is_file.bin tests/is_file.c -I ./ 25 | $CC $FLAGS -o test_dir_list.bin tests/dir_list.c -I ./ 26 | cd .. 27 | 28 | # 29 | # [apg_bmp] 30 | # 31 | echo "building apg_bmp tests..." 32 | cd apg_bmp 33 | $CC $FLAGS -o test_read_bmp.bin test_code/main_read.c apg_bmp.c -I./ -I test_code/ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 34 | $CC $FLAGS -o test_write_bmp.bin test_code/main_write.c apg_bmp.c -I./ -I test_code/ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 35 | cd .. 36 | 37 | # 38 | # [apg_console] 39 | # 40 | echo "building apg_console tests..." 41 | cd apg_console 42 | cp ../apg_pixfont/apg_pixfont.c ./ 43 | cp ../apg_pixfont/apg_pixfont.h ./ 44 | cp ../apg_unicode/apg_unicode.c ./ 45 | cp ../apg_unicode/apg_unicode.h ./ 46 | $CC $FLAGS tests/main.c apg_console.c apg_pixfont.c apg_unicode.c -I ./ 47 | cd .. 48 | 49 | # NOTE -- no tests for apg_gldb at the moment (opengl is a pain to set up on build servers) 50 | # [apg_gldb] 51 | # 52 | 53 | # 54 | # [apg_interp] 55 | # 56 | echo "building apg_interp tests..." 57 | cd apg_interp 58 | $CC $FLAGS -std=c99 -I ./ tests/test.c -lm 59 | cd .. 60 | 61 | # 62 | # [apg_jobs] 63 | # 64 | echo "building apg_jobs tests..." 65 | cd apg_jobs 66 | clang $SANS $FLAGS tests/main.c -I ./ apg_jobs.c -pthread 67 | cd .. 68 | 69 | # 70 | # [apg_linechart] 71 | # 72 | echo "building apg_plot tests..." 73 | cd apg_plot 74 | $CC $FLAGS -std=c99 -D_APG_PLOT_UNIT_TEST -I./ -I../third_party/stb/ apg_plot.c -lm 75 | cd .. 76 | 77 | # 78 | # [apg_maths] 79 | # 80 | echo "building apg_maths tests..." 81 | cd apg_maths 82 | $CC $FLAGS -std=c99 -I./ tests/test.c apg_maths.c -lm 83 | cd .. 84 | 85 | # 86 | # [apg_mod] 87 | # 88 | echo "building apg_mod tests..." 89 | cd apg_mod 90 | bash ./build.sh 91 | cd .. 92 | 93 | # 94 | # [apg_pixfont] 95 | # 96 | echo "building apg_pixfont tests..." 97 | cd apg_pixfont 98 | $CPP -c tests/test_pixfont.cpp -o tests/test_pixfont.o -I ./ -I ../third_party/stb/ 99 | $CC $FLAGS -c apg_pixfont.c -o apg_pixfont.o -I ./ 100 | $CC $FLAGS $SAN -o test_pixfont.bin apg_pixfont.o tests/test_pixfont.o -lm 101 | $CC $SAN -o bakefont.bin utils/bake_font_array.c -I ../third_party/stb/ -lm 102 | cd .. 103 | 104 | # 105 | # [apg_tga] 106 | # 107 | echo "building apg_tga tests..." 108 | cd apg_tga 109 | $CC $FLAGS -o test_read_tga test_code/main_read.c -I ./ -I test_code/ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 110 | $CC $FLAGS -o test_write_tga test_code/main_write.c -I ./ -I test_code/ -I ../third_party/stb/ -DAPG_TGA_DEBUG_OUTPUT 111 | cd .. 112 | 113 | # 114 | # [apg_unicode] 115 | # 116 | echo "building apg_unicode tests..." 117 | cd apg_unicode 118 | $CC $FLAGS -o test_unicode.bin tests/main.c apg_unicode.c -I ./ 119 | cd .. 120 | 121 | # 122 | # [apg_wav] 123 | # 124 | echo "building apg_wav tests..." 125 | cd apg_wav 126 | $CC $FLAGS -I./ -Itests/ tests/main_write.c apg_wav.c -lm 127 | $CC $FLAGS -I./ -Itests/ tests/main_read.c apg_wav.c -lm 128 | cd .. 129 | 130 | printf '%b%s\n%s\n%s\n%b\n' $colour_pass $horiz_div "Compile Check PASSED" $horiz_div $colour_default 131 | -------------------------------------------------------------------------------- /third_party/portaudio/LICENSE.txt: -------------------------------------------------------------------------------- 1 | PortAudio Portable Real-Time Audio Library 2 | Copyright (c) 1999-2011 Ross Bencina, Phil Burk 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | 11 | The text above constitutes the entire PortAudio license; however, the PortAudio community also makes the following non-binding requests: 12 | 13 | Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. It is also requested that these non-binding requests be included along with the license above. 14 | -------------------------------------------------------------------------------- /third_party/portaudio/bin/libportaudio-x86_64-w64-mingw32.static.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/capnramses/apg/b94ee8d691da5c8922ef3501af24c658fb1ece9d/third_party/portaudio/bin/libportaudio-x86_64-w64-mingw32.static.dll -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_asio.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_ASIO_H 2 | #define PA_ASIO_H 3 | /* 4 | * $Id$ 5 | * PortAudio Portable Real-Time Audio Library 6 | * ASIO specific extensions 7 | * 8 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | 42 | /** @file 43 | @ingroup public_header 44 | @brief ASIO-specific PortAudio API extension header file. 45 | */ 46 | 47 | #include "portaudio.h" 48 | 49 | #ifdef __cplusplus 50 | extern "C" 51 | { 52 | #endif /* __cplusplus */ 53 | 54 | 55 | /** Retrieve legal native buffer sizes for the specified device, in sample frames. 56 | 57 | @param device The global index of the device about which the query is being made. 58 | @param minBufferSizeFrames A pointer to the location which will receive the minimum buffer size value. 59 | @param maxBufferSizeFrames A pointer to the location which will receive the maximum buffer size value. 60 | @param preferredBufferSizeFrames A pointer to the location which will receive the preferred buffer size value. 61 | @param granularity A pointer to the location which will receive the "granularity". This value determines 62 | the step size used to compute the legal values between minBufferSizeFrames and maxBufferSizeFrames. 63 | If granularity is -1 then available buffer size values are powers of two. 64 | 65 | @see ASIOGetBufferSize in the ASIO SDK. 66 | 67 | @note: this function used to be called PaAsio_GetAvailableLatencyValues. There is a 68 | #define that maps PaAsio_GetAvailableLatencyValues to this function for backwards compatibility. 69 | */ 70 | PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device, 71 | long *minBufferSizeFrames, long *maxBufferSizeFrames, long *preferredBufferSizeFrames, long *granularity ); 72 | 73 | 74 | /** Backwards compatibility alias for PaAsio_GetAvailableBufferSizes 75 | 76 | @see PaAsio_GetAvailableBufferSizes 77 | */ 78 | #define PaAsio_GetAvailableLatencyValues PaAsio_GetAvailableBufferSizes 79 | 80 | 81 | /** Display the ASIO control panel for the specified device. 82 | 83 | @param device The global index of the device whose control panel is to be displayed. 84 | @param systemSpecific On Windows, the calling application's main window handle, 85 | on Macintosh this value should be zero. 86 | */ 87 | PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ); 88 | 89 | 90 | 91 | 92 | /** Retrieve a pointer to a string containing the name of the specified 93 | input channel. The string is valid until Pa_Terminate is called. 94 | 95 | The string will be no longer than 32 characters including the null terminator. 96 | */ 97 | PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, 98 | const char** channelName ); 99 | 100 | 101 | /** Retrieve a pointer to a string containing the name of the specified 102 | input channel. The string is valid until Pa_Terminate is called. 103 | 104 | The string will be no longer than 32 characters including the null terminator. 105 | */ 106 | PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, 107 | const char** channelName ); 108 | 109 | 110 | /** Set the sample rate of an open paASIO stream. 111 | 112 | @param stream The stream to operate on. 113 | @param sampleRate The new sample rate. 114 | 115 | Note that this function may fail if the stream is already running and the 116 | ASIO driver does not support switching the sample rate of a running stream. 117 | 118 | Returns paIncompatibleStreamHostApi if stream is not a paASIO stream. 119 | */ 120 | PaError PaAsio_SetStreamSampleRate( PaStream* stream, double sampleRate ); 121 | 122 | 123 | #define paAsioUseChannelSelectors (0x01) 124 | 125 | typedef struct PaAsioStreamInfo{ 126 | unsigned long size; /**< sizeof(PaAsioStreamInfo) */ 127 | PaHostApiTypeId hostApiType; /**< paASIO */ 128 | unsigned long version; /**< 1 */ 129 | 130 | unsigned long flags; 131 | 132 | /* Support for opening only specific channels of an ASIO device. 133 | If the paAsioUseChannelSelectors flag is set, channelSelectors is a 134 | pointer to an array of integers specifying the device channels to use. 135 | When used, the length of the channelSelectors array must match the 136 | corresponding channelCount parameter to Pa_OpenStream() otherwise a 137 | crash may result. 138 | The values in the selectors array must specify channels within the 139 | range of supported channels for the device or paInvalidChannelCount will 140 | result. 141 | */ 142 | int *channelSelectors; 143 | }PaAsioStreamInfo; 144 | 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif /* __cplusplus */ 149 | 150 | #endif /* PA_ASIO_H */ 151 | -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_jack.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_JACK_H 2 | #define PA_JACK_H 3 | 4 | /* 5 | * $Id: 6 | * PortAudio Portable Real-Time Audio Library 7 | * JACK-specific extensions 8 | * 9 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | * @ingroup public_header 44 | * @brief JACK-specific PortAudio API extension header file. 45 | */ 46 | 47 | #include "portaudio.h" 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | /** Set the JACK client name. 54 | * 55 | * During Pa_Initialize, When PA JACK connects as a client of the JACK server, it requests a certain 56 | * name, which is for instance prepended to port names. By default this name is "PortAudio". The 57 | * JACK server may append a suffix to the client name, in order to avoid clashes among clients that 58 | * try to connect with the same name (e.g., different PA JACK clients). 59 | * 60 | * This function must be called before Pa_Initialize, otherwise it won't have any effect. Note that 61 | * the string is not copied, but instead referenced directly, so it must not be freed for as long as 62 | * PA might need it. 63 | * @sa PaJack_GetClientName 64 | */ 65 | PaError PaJack_SetClientName( const char* name ); 66 | 67 | /** Get the JACK client name used by PA JACK. 68 | * 69 | * The caller is responsible for freeing the returned pointer. 70 | */ 71 | PaError PaJack_GetClientName(const char** clientName); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_linux_alsa.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_LINUX_ALSA_H 2 | #define PA_LINUX_ALSA_H 3 | 4 | /* 5 | * $Id$ 6 | * PortAudio Portable Real-Time Audio Library 7 | * ALSA-specific extensions 8 | * 9 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining 12 | * a copy of this software and associated documentation files 13 | * (the "Software"), to deal in the Software without restriction, 14 | * including without limitation the rights to use, copy, modify, merge, 15 | * publish, distribute, sublicense, and/or sell copies of the Software, 16 | * and to permit persons to whom the Software is furnished to do so, 17 | * subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be 20 | * included in all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 26 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 27 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | 31 | /* 32 | * The text above constitutes the entire PortAudio license; however, 33 | * the PortAudio community also makes the following non-binding requests: 34 | * 35 | * Any person wishing to distribute modifications to the Software is 36 | * requested to send the modifications to the original developer so that 37 | * they can be incorporated into the canonical version. It is also 38 | * requested that these non-binding requests be included along with the 39 | * license above. 40 | */ 41 | 42 | /** @file 43 | * @ingroup public_header 44 | * @brief ALSA-specific PortAudio API extension header file. 45 | */ 46 | 47 | #include "portaudio.h" 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | typedef struct PaAlsaStreamInfo 54 | { 55 | unsigned long size; 56 | PaHostApiTypeId hostApiType; 57 | unsigned long version; 58 | 59 | const char *deviceString; 60 | } 61 | PaAlsaStreamInfo; 62 | 63 | /** Initialize host API specific structure, call this before setting relevant attributes. */ 64 | void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info ); 65 | 66 | /** Instruct whether to enable real-time priority when starting the audio thread. 67 | * 68 | * If this is turned on by the stream is started, the audio callback thread will be created 69 | * with the FIFO scheduling policy, which is suitable for realtime operation. 70 | **/ 71 | void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable ); 72 | 73 | #if 0 74 | void PaAlsa_EnableWatchdog( PaStream *s, int enable ); 75 | #endif 76 | 77 | /** Get the ALSA-lib card index of this stream's input device. */ 78 | PaError PaAlsa_GetStreamInputCard( PaStream *s, int *card ); 79 | 80 | /** Get the ALSA-lib card index of this stream's output device. */ 81 | PaError PaAlsa_GetStreamOutputCard( PaStream *s, int *card ); 82 | 83 | /** Set the number of periods (buffer fragments) to configure devices with. 84 | * 85 | * By default the number of periods is 4, this is the lowest number of periods that works well on 86 | * the author's soundcard. 87 | * @param numPeriods The number of periods. 88 | */ 89 | PaError PaAlsa_SetNumPeriods( int numPeriods ); 90 | 91 | /** Set the maximum number of times to retry opening busy device (sleeping for a 92 | * short interval inbetween). 93 | */ 94 | PaError PaAlsa_SetRetriesBusy( int retries ); 95 | 96 | /** Set the path and name of ALSA library file if PortAudio is configured to load it dynamically (see 97 | * PA_ALSA_DYNAMIC). This setting will overwrite the default name set by PA_ALSA_PATHNAME define. 98 | * @param pathName Full path with filename. Only filename can be used, but dlopen() will lookup default 99 | * searchable directories (/usr/lib;/usr/local/lib) then. 100 | */ 101 | void PaAlsa_SetLibraryPathName( const char *pathName ); 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_mac_core.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_MAC_CORE_H 2 | #define PA_MAC_CORE_H 3 | /* 4 | * PortAudio Portable Real-Time Audio Library 5 | * Macintosh Core Audio specific extensions 6 | * portaudio.h should be included before this file. 7 | * 8 | * Copyright (c) 2005-2006 Bjorn Roche 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | * @ingroup public_header 43 | * @brief CoreAudio-specific PortAudio API extension header file. 44 | */ 45 | 46 | #include "portaudio.h" 47 | 48 | #include 49 | #include 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | 56 | /** 57 | * A pointer to a paMacCoreStreamInfo may be passed as 58 | * the hostApiSpecificStreamInfo in the PaStreamParameters struct 59 | * when opening a stream or querying the format. Use NULL, for the 60 | * defaults. Note that for duplex streams, flags for input and output 61 | * should be the same or behaviour is undefined. 62 | */ 63 | typedef struct 64 | { 65 | unsigned long size; /**size of whole structure including this header */ 66 | PaHostApiTypeId hostApiType; /**host API for which this data is intended */ 67 | unsigned long version; /**structure version */ 68 | unsigned long flags; /** flags to modify behaviour */ 69 | SInt32 const * channelMap; /** Channel map for HAL channel mapping , if not needed, use NULL;*/ 70 | unsigned long channelMapSize; /** Channel map size for HAL channel mapping , if not needed, use 0;*/ 71 | } PaMacCoreStreamInfo; 72 | 73 | /** 74 | * Functions 75 | */ 76 | 77 | 78 | /** Use this function to initialize a paMacCoreStreamInfo struct 79 | * using the requested flags. Note that channel mapping is turned 80 | * off after a call to this function. 81 | * @param data The datastructure to initialize 82 | * @param flags The flags to initialize the datastructure with. 83 | */ 84 | void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, unsigned long flags ); 85 | 86 | /** call this after pa_SetupMacCoreStreamInfo to use channel mapping as described in notes.txt. 87 | * @param data The stream info structure to assign a channel mapping to 88 | * @param channelMap The channel map array, as described in notes.txt. This array pointer will be used directly (ie the underlying data will not be copied), so the caller should not free the array until after the stream has been opened. 89 | * @param channelMapSize The size of the channel map array. 90 | */ 91 | void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, unsigned long channelMapSize ); 92 | 93 | /** 94 | * Retrieve the AudioDeviceID of the input device assigned to an open stream 95 | * 96 | * @param s The stream to query. 97 | * 98 | * @return A valid AudioDeviceID, or NULL if an error occurred. 99 | */ 100 | AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ); 101 | 102 | /** 103 | * Retrieve the AudioDeviceID of the output device assigned to an open stream 104 | * 105 | * @param s The stream to query. 106 | * 107 | * @return A valid AudioDeviceID, or NULL if an error occurred. 108 | */ 109 | AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ); 110 | 111 | /** 112 | * Returns a statically allocated string with the device's name 113 | * for the given channel. NULL will be returned on failure. 114 | * 115 | * This function's implementation is not complete! 116 | * 117 | * @param device The PortAudio device index. 118 | * @param channel The channel number who's name is requested. 119 | * @return a statically allocated string with the name of the device. 120 | * Because this string is statically allocated, it must be 121 | * copied if it is to be saved and used by the user after 122 | * another call to this function. 123 | * 124 | */ 125 | const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); 126 | 127 | 128 | /** Retrieve the range of legal native buffer sizes for the specified device, in sample frames. 129 | 130 | @param device The global index of the PortAudio device about which the query is being made. 131 | @param minBufferSizeFrames A pointer to the location which will receive the minimum buffer size value. 132 | @param maxBufferSizeFrames A pointer to the location which will receive the maximum buffer size value. 133 | 134 | @see kAudioDevicePropertyBufferFrameSizeRange in the CoreAudio SDK. 135 | */ 136 | PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, 137 | long *minBufferSizeFrames, long *maxBufferSizeFrames ); 138 | 139 | 140 | /** 141 | * Flags 142 | */ 143 | 144 | /** 145 | * The following flags alter the behaviour of PA on the mac platform. 146 | * they can be ORed together. These should work both for opening and 147 | * checking a device. 148 | */ 149 | 150 | /** Allows PortAudio to change things like the device's frame size, 151 | * which allows for much lower latency, but might disrupt the device 152 | * if other programs are using it, even when you are just Querying 153 | * the device. */ 154 | #define paMacCoreChangeDeviceParameters (0x01) 155 | 156 | /** In combination with the above flag, 157 | * causes the stream opening to fail, unless the exact sample rates 158 | * are supported by the device. */ 159 | #define paMacCoreFailIfConversionRequired (0x02) 160 | 161 | /** These flags set the SR conversion quality, if required. The weird ordering 162 | * allows Maximum Quality to be the default.*/ 163 | #define paMacCoreConversionQualityMin (0x0100) 164 | #define paMacCoreConversionQualityMedium (0x0200) 165 | #define paMacCoreConversionQualityLow (0x0300) 166 | #define paMacCoreConversionQualityHigh (0x0400) 167 | #define paMacCoreConversionQualityMax (0x0000) 168 | 169 | /** 170 | * Here are some "preset" combinations of flags (above) to get to some 171 | * common configurations. THIS IS OVERKILL, but if more flags are added 172 | * it won't be. 173 | */ 174 | 175 | /**This is the default setting: do as much sample rate conversion as possible 176 | * and as little mucking with the device as possible. */ 177 | #define paMacCorePlayNice (0x00) 178 | /**This setting is tuned for pro audio apps. It allows SR conversion on input 179 | and output, but it tries to set the appropriate SR on the device.*/ 180 | #define paMacCorePro (0x01) 181 | /**This is a setting to minimize CPU usage and still play nice.*/ 182 | #define paMacCoreMinimizeCPUButPlayNice (0x0100) 183 | /**This is a setting to minimize CPU usage, even if that means interrupting the device. */ 184 | #define paMacCoreMinimizeCPU (0x0101) 185 | 186 | 187 | #ifdef __cplusplus 188 | } 189 | #endif /** __cplusplus */ 190 | 191 | #endif /** PA_MAC_CORE_H */ 192 | -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_win_ds.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_WIN_DS_H 2 | #define PA_WIN_DS_H 3 | /* 4 | * $Id: $ 5 | * PortAudio Portable Real-Time Audio Library 6 | * DirectSound specific extensions 7 | * 8 | * Copyright (c) 1999-2007 Ross Bencina and Phil Burk 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | @ingroup public_header 43 | @brief DirectSound-specific PortAudio API extension header file. 44 | */ 45 | 46 | #include "portaudio.h" 47 | #include "pa_win_waveformat.h" 48 | 49 | #ifdef __cplusplus 50 | extern "C" 51 | { 52 | #endif /* __cplusplus */ 53 | 54 | 55 | #define paWinDirectSoundUseLowLevelLatencyParameters (0x01) 56 | #define paWinDirectSoundUseChannelMask (0x04) 57 | 58 | 59 | typedef struct PaWinDirectSoundStreamInfo{ 60 | unsigned long size; /**< sizeof(PaWinDirectSoundStreamInfo) */ 61 | PaHostApiTypeId hostApiType; /**< paDirectSound */ 62 | unsigned long version; /**< 2 */ 63 | 64 | unsigned long flags; /**< enable other features of this struct */ 65 | 66 | /** 67 | low-level latency setting support 68 | Sets the size of the DirectSound host buffer. 69 | When flags contains the paWinDirectSoundUseLowLevelLatencyParameters 70 | this size will be used instead of interpreting the generic latency 71 | parameters to Pa_OpenStream(). If the flag is not set this value is ignored. 72 | 73 | If the stream is a full duplex stream the implementation requires that 74 | the values of framesPerBuffer for input and output match (if both are specified). 75 | */ 76 | unsigned long framesPerBuffer; 77 | 78 | /** 79 | support for WAVEFORMATEXTENSIBLE channel masks. If flags contains 80 | paWinDirectSoundUseChannelMask this allows you to specify which speakers 81 | to address in a multichannel stream. Constants for channelMask 82 | are specified in pa_win_waveformat.h 83 | 84 | */ 85 | PaWinWaveFormatChannelMask channelMask; 86 | 87 | }PaWinDirectSoundStreamInfo; 88 | 89 | 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif /* __cplusplus */ 94 | 95 | #endif /* PA_WIN_DS_H */ 96 | -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_win_wdmks.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_WIN_WDMKS_H 2 | #define PA_WIN_WDMKS_H 3 | /* 4 | * $Id$ 5 | * PortAudio Portable Real-Time Audio Library 6 | * WDM/KS specific extensions 7 | * 8 | * Copyright (c) 1999-2007 Ross Bencina and Phil Burk 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | @ingroup public_header 43 | @brief WDM Kernel Streaming-specific PortAudio API extension header file. 44 | */ 45 | 46 | 47 | #include "portaudio.h" 48 | 49 | #include 50 | 51 | #ifdef __cplusplus 52 | extern "C" 53 | { 54 | #endif /* __cplusplus */ 55 | 56 | /** Flags to indicate valid fields in PaWinWDMKSInfo. 57 | @see PaWinWDMKSInfo 58 | @version Available as of 19.5.0. 59 | */ 60 | typedef enum PaWinWDMKSFlags 61 | { 62 | /** Makes WDMKS use the supplied latency figures instead of relying on the frame size reported 63 | by the WaveCyclic device. Use at own risk! 64 | */ 65 | paWinWDMKSOverrideFramesize = (1 << 0), 66 | 67 | /** Makes WDMKS (output stream) use the given channelMask instead of the default. 68 | @version Available as of 19.5.0. 69 | */ 70 | paWinWDMKSUseGivenChannelMask = (1 << 1), 71 | 72 | } PaWinWDMKSFlags; 73 | 74 | typedef struct PaWinWDMKSInfo{ 75 | unsigned long size; /**< sizeof(PaWinWDMKSInfo) */ 76 | PaHostApiTypeId hostApiType; /**< paWDMKS */ 77 | unsigned long version; /**< 1 */ 78 | 79 | /** Flags indicate which fields are valid. 80 | @see PaWinWDMKSFlags 81 | @version Available as of 19.5.0. 82 | */ 83 | unsigned long flags; 84 | 85 | /** The number of packets to use for WaveCyclic devices, range is [2, 8]. Set to zero for default value of 2. */ 86 | unsigned noOfPackets; 87 | 88 | /** If paWinWDMKSUseGivenChannelMask bit is set in flags, use this as channelMask instead of default. 89 | @see PaWinWDMKSFlags 90 | @version Available as of 19.5.0. 91 | */ 92 | unsigned channelMask; 93 | } PaWinWDMKSInfo; 94 | 95 | typedef enum PaWDMKSType 96 | { 97 | Type_kNotUsed, 98 | Type_kWaveCyclic, 99 | Type_kWaveRT, 100 | Type_kCnt, 101 | } PaWDMKSType; 102 | 103 | typedef enum PaWDMKSSubType 104 | { 105 | SubType_kUnknown, 106 | SubType_kNotification, 107 | SubType_kPolled, 108 | SubType_kCnt, 109 | } PaWDMKSSubType; 110 | 111 | typedef struct PaWinWDMKSDeviceInfo { 112 | wchar_t filterPath[MAX_PATH]; /**< KS filter path in Unicode! */ 113 | wchar_t topologyPath[MAX_PATH]; /**< Topology filter path in Unicode! */ 114 | PaWDMKSType streamingType; 115 | GUID deviceProductGuid; /**< The product GUID of the device (if supported) */ 116 | } PaWinWDMKSDeviceInfo; 117 | 118 | typedef struct PaWDMKSDirectionSpecificStreamInfo 119 | { 120 | PaDeviceIndex device; 121 | unsigned channels; /**< No of channels the device is opened with */ 122 | unsigned framesPerHostBuffer; /**< No of frames of the device buffer */ 123 | int endpointPinId; /**< Endpoint pin ID (on topology filter if topologyName is not empty) */ 124 | int muxNodeId; /**< Only valid for input */ 125 | PaWDMKSSubType streamingSubType; /**< Not known until device is opened for streaming */ 126 | } PaWDMKSDirectionSpecificStreamInfo; 127 | 128 | typedef struct PaWDMKSSpecificStreamInfo { 129 | PaWDMKSDirectionSpecificStreamInfo input; 130 | PaWDMKSDirectionSpecificStreamInfo output; 131 | } PaWDMKSSpecificStreamInfo; 132 | 133 | #ifdef __cplusplus 134 | } 135 | #endif /* __cplusplus */ 136 | 137 | #endif /* PA_WIN_DS_H */ 138 | -------------------------------------------------------------------------------- /third_party/portaudio/include/pa_win_wmme.h: -------------------------------------------------------------------------------- 1 | #ifndef PA_WIN_WMME_H 2 | #define PA_WIN_WMME_H 3 | /* 4 | * $Id$ 5 | * PortAudio Portable Real-Time Audio Library 6 | * MME specific extensions 7 | * 8 | * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining 11 | * a copy of this software and associated documentation files 12 | * (the "Software"), to deal in the Software without restriction, 13 | * including without limitation the rights to use, copy, modify, merge, 14 | * publish, distribute, sublicense, and/or sell copies of the Software, 15 | * and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | /* 31 | * The text above constitutes the entire PortAudio license; however, 32 | * the PortAudio community also makes the following non-binding requests: 33 | * 34 | * Any person wishing to distribute modifications to the Software is 35 | * requested to send the modifications to the original developer so that 36 | * they can be incorporated into the canonical version. It is also 37 | * requested that these non-binding requests be included along with the 38 | * license above. 39 | */ 40 | 41 | /** @file 42 | @ingroup public_header 43 | @brief WMME-specific PortAudio API extension header file. 44 | */ 45 | 46 | #include "portaudio.h" 47 | #include "pa_win_waveformat.h" 48 | 49 | #ifdef __cplusplus 50 | extern "C" 51 | { 52 | #endif /* __cplusplus */ 53 | 54 | 55 | /* The following are flags which can be set in 56 | PaWinMmeStreamInfo's flags field. 57 | */ 58 | 59 | #define paWinMmeUseLowLevelLatencyParameters (0x01) 60 | #define paWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */ 61 | #define paWinMmeUseChannelMask (0x04) 62 | 63 | /* By default, the mme implementation drops the processing thread's priority 64 | to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100% 65 | This flag disables any priority throttling. The processing thread will always 66 | run at THREAD_PRIORITY_TIME_CRITICAL. 67 | */ 68 | #define paWinMmeDontThrottleOverloadedProcessingThread (0x08) 69 | 70 | /* Flags for non-PCM spdif passthrough. 71 | */ 72 | #define paWinMmeWaveFormatDolbyAc3Spdif (0x10) 73 | #define paWinMmeWaveFormatWmaSpdif (0x20) 74 | 75 | 76 | typedef struct PaWinMmeDeviceAndChannelCount{ 77 | PaDeviceIndex device; 78 | int channelCount; 79 | }PaWinMmeDeviceAndChannelCount; 80 | 81 | 82 | typedef struct PaWinMmeStreamInfo{ 83 | unsigned long size; /**< sizeof(PaWinMmeStreamInfo) */ 84 | PaHostApiTypeId hostApiType; /**< paMME */ 85 | unsigned long version; /**< 1 */ 86 | 87 | unsigned long flags; 88 | 89 | /* low-level latency setting support 90 | These settings control the number and size of host buffers in order 91 | to set latency. They will be used instead of the generic parameters 92 | to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters 93 | flag. 94 | 95 | If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters 96 | are supplied for both input and output in a full duplex stream, then the 97 | input and output framesPerBuffer must be the same, or the larger of the 98 | two must be a multiple of the smaller, otherwise a 99 | paIncompatibleHostApiSpecificStreamInfo error will be returned from 100 | Pa_OpenStream(). 101 | */ 102 | unsigned long framesPerBuffer; 103 | unsigned long bufferCount; /* formerly numBuffers */ 104 | 105 | /* multiple devices per direction support 106 | If flags contains the PaWinMmeUseMultipleDevices flag, 107 | this functionality will be used, otherwise the device parameter to 108 | Pa_OpenStream() will be used instead. 109 | If devices are specified here, the corresponding device parameter 110 | to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification, 111 | otherwise an paInvalidDevice error will result. 112 | The total number of channels across all specified devices 113 | must agree with the corresponding channelCount parameter to 114 | Pa_OpenStream() otherwise a paInvalidChannelCount error will result. 115 | */ 116 | PaWinMmeDeviceAndChannelCount *devices; 117 | unsigned long deviceCount; 118 | 119 | /* 120 | support for WAVEFORMATEXTENSIBLE channel masks. If flags contains 121 | paWinMmeUseChannelMask this allows you to specify which speakers 122 | to address in a multichannel stream. Constants for channelMask 123 | are specified in pa_win_waveformat.h 124 | 125 | */ 126 | PaWinWaveFormatChannelMask channelMask; 127 | 128 | }PaWinMmeStreamInfo; 129 | 130 | 131 | /** Retrieve the number of wave in handles used by a PortAudio WinMME stream. 132 | Returns zero if the stream is output only. 133 | 134 | @return A non-negative value indicating the number of wave in handles 135 | or, a PaErrorCode (which are always negative) if PortAudio is not initialized 136 | or an error is encountered. 137 | 138 | @see PaWinMME_GetStreamInputHandle 139 | */ 140 | int PaWinMME_GetStreamInputHandleCount( PaStream* stream ); 141 | 142 | 143 | /** Retrieve a wave in handle used by a PortAudio WinMME stream. 144 | 145 | @param stream The stream to query. 146 | @param handleIndex The zero based index of the wave in handle to retrieve. This 147 | should be in the range [0, PaWinMME_GetStreamInputHandleCount(stream)-1]. 148 | 149 | @return A valid wave in handle, or NULL if an error occurred. 150 | 151 | @see PaWinMME_GetStreamInputHandle 152 | */ 153 | HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex ); 154 | 155 | 156 | /** Retrieve the number of wave out handles used by a PortAudio WinMME stream. 157 | Returns zero if the stream is input only. 158 | 159 | @return A non-negative value indicating the number of wave out handles 160 | or, a PaErrorCode (which are always negative) if PortAudio is not initialized 161 | or an error is encountered. 162 | 163 | @see PaWinMME_GetStreamOutputHandle 164 | */ 165 | int PaWinMME_GetStreamOutputHandleCount( PaStream* stream ); 166 | 167 | 168 | /** Retrieve a wave out handle used by a PortAudio WinMME stream. 169 | 170 | @param stream The stream to query. 171 | @param handleIndex The zero based index of the wave out handle to retrieve. 172 | This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1]. 173 | 174 | @return A valid wave out handle, or NULL if an error occurred. 175 | 176 | @see PaWinMME_GetStreamOutputHandleCount 177 | */ 178 | HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex ); 179 | 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif /* __cplusplus */ 184 | 185 | #endif /* PA_WIN_WMME_H */ 186 | --------------------------------------------------------------------------------