├── .gitattributes ├── .github └── workflows │ ├── assembly_build.yml │ ├── assembly_test.yml │ ├── codeql-analysis.yml │ └── coverity-scan.yml ├── LICENSE ├── README.md ├── assembly ├── README ├── merge_files.py ├── nmd_assembly.h ├── nmd_common.c ├── nmd_common.h ├── nmd_x86_assembler.c ├── nmd_x86_decoder.c ├── nmd_x86_formatter.c └── nmd_x86_ldisasm.c ├── examples ├── assembly_example.c ├── graphics_d3d11.cpp ├── graphics_d3d9.cpp └── graphics_opengl.c ├── graphics ├── README ├── merge_files.py ├── nmd_common.c ├── nmd_common.h ├── nmd_default_font.c ├── nmd_drawlist.c ├── nmd_graphics.c ├── nmd_graphics.h ├── nmd_gui.c ├── nmd_renderer_d3d11.cpp ├── nmd_renderer_d3d9.cpp ├── nmd_renderer_opengl.c ├── nmd_stb_truetype.c └── stb_truetype.h ├── nmd_assembly.h ├── nmd_graphics.h ├── platform_specific ├── nmd_libc.h ├── nmd_memory.h └── nmd_memory_deprecated.hpp └── tests └── assembly_test.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=C 2 | -------------------------------------------------------------------------------- /.github/workflows/assembly_build.yml: -------------------------------------------------------------------------------- 1 | name: Build nmd_assembly.h C89 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'assembly/*' 7 | - 'tests/assembly_test.cpp' 8 | - 'examples/assembly_example.c' 9 | pull_request: 10 | paths: 11 | - 'assembly/*' 12 | - 'tests/assembly_test.cpp' 13 | - 'examples/assembly_example.c' 14 | 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v2 21 | 22 | - name: Merge files 23 | working-directory: assembly 24 | run: python merge_files.py 25 | 26 | - name: Build nmd_assembly.h 27 | run: gcc -std=c89 examples/assembly_example.c 28 | -------------------------------------------------------------------------------- /.github/workflows/assembly_test.yml: -------------------------------------------------------------------------------- 1 | name: Test nmd_assembly.h 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'tests/assembly_test.cpp' 7 | - 'assembly/*' 8 | pull_request: 9 | paths: 10 | - 'tests/assembly_test.cpp' 11 | - 'assembly/*' 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Install gtest 20 | run: sudo apt install libgtest-dev cmake 21 | 22 | - name: Configure gtest 23 | working-directory: /usr/src/gtest 24 | run: sudo cmake CMakeLists.txt 25 | 26 | - name: Build gtest 27 | working-directory: /usr/src/gtest 28 | run: sudo make 29 | 30 | - name: Copy gtest libraries 31 | working-directory: /usr/src/gtest 32 | run: sudo cp ./lib/*.a /usr/lib 33 | 34 | - name: Merge files 35 | working-directory: assembly 36 | run: python merge_files.py 37 | 38 | - name: Compile assembly_test.cpp 39 | run: g++ -Wall -g -pthread tests/assembly_test.cpp -lgtest_main -lgtest -lpthread -o assembly_test 40 | 41 | - name: Run assembly_test 42 | run: ./assembly_test 43 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | schedule: 16 | - cron: '00 00 * * 0' # Runs at 00:00 UTC on Sun 17 | 18 | jobs: 19 | analyze: 20 | name: Analyze 21 | runs-on: ubuntu-latest 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | language: [ 'cpp', 'python' ] 27 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 28 | # Learn more: 29 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | 35 | # Initializes the CodeQL tools for scanning. 36 | - name: Initialize CodeQL 37 | uses: github/codeql-action/init@v1 38 | with: 39 | languages: ${{ matrix.language }} 40 | # If you wish to specify custom queries, you can do so here or in a config file. 41 | # By default, queries listed here will override any specified in a config file. 42 | # Prefix the list here with "+" to use these queries and those in the config file. 43 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 44 | 45 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 46 | # If this step fails, then you should remove it and run the build manually (see below) 47 | #- name: Autobuild 48 | # uses: github/codeql-action/autobuild@v1 49 | 50 | # ℹ️ Command-line programs to run using the OS shell. 51 | # 📚 https://git.io/JvXDl 52 | 53 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 54 | # and modify them (or add more) to build your code if your project 55 | # uses a compiled language 56 | 57 | #- run: | 58 | # make bootstrap 59 | # make release 60 | 61 | - name: Merge files 62 | working-directory: assembly 63 | run: python merge_files.py 64 | 65 | - name: Build nmd_assembly.h 66 | run: gcc -std=c89 examples/assembly_example.c 67 | 68 | - name: Perform CodeQL Analysis 69 | uses: github/codeql-action/analyze@v1 70 | -------------------------------------------------------------------------------- /.github/workflows/coverity-scan.yml: -------------------------------------------------------------------------------- 1 | name: coverity-scan 2 | on: 3 | schedule: 4 | - cron: '00 00 * * 0,3' # Runs at 00:00 UTC on Sun and Wed 5 | 6 | jobs: 7 | latest: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v1 11 | - name: Download Coverity Build Tool 12 | run: | 13 | wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=Nomade040%2Fnmd" -O cov-analysis-linux64.tar.gz 14 | mkdir cov-analysis-linux64 15 | tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 16 | env: 17 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 18 | 19 | - name: Fixed world writable dirs 20 | run: | 21 | chmod go-w $HOME 22 | sudo chmod -R go-w /usr/share 23 | 24 | - name: Build with cov-build 25 | run: | 26 | export PATH=`pwd`/cov-analysis-linux64/bin:$PATH 27 | cov-build --dir cov-int gcc -std=c89 examples/assembly_example.c 28 | - name: Submit the result to Coverity Scan 29 | run: | 30 | tar czvf nmd.tgz cov-int 31 | curl --form token=$TOKEN \ 32 | --form email=nomade040@gmail.com \ 33 | --form file=@nmd.tgz \ 34 | --form version=trunk \ 35 | --form description="`git rev-parse --short "$GITHUB_SHA"`" \ 36 | https://scan.coverity.com/builds?project=Nomade040%2Fnmd 37 | env: 38 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Build nmd_assembly.h](https://github.com/Nomade040/nmd/workflows/Build%20nmd_assembly.h/badge.svg) ![Test nmd_assembly.h](https://github.com/Nomade040/nmd/workflows/Test%20nmd_assembly.h/badge.svg) [![Discord](https://img.shields.io/badge/chat-on%20Discord-green.svg)](https://discord.gg/VF4rVxA) 2 | Coverity Scan Build Status 3 | 4 | # nmd 5 | set of single-header libraries for C/C++ 6 | 7 | # Notable 8 | - C89 x86 assembler and disassembler: [nmd_assembly.h](nmd_assembly.h) 9 | - C89 2D graphics library: [nmd_graphics.h](nmd_graphics.h) 10 | 11 | # General information 12 | - **Each library's documentation is at the start of the file.** 13 | - **The end user should use the single-header libraries in the root directory.** The code in the folders(e.g. `/assembly`, `/graphics`) is for development only. 14 | 15 | # Showcase(listed in no particular order) 16 | - [RTTI Finder Dumper](https://github.com/theluc4s/RTTI-Finder-Dumper) 17 | - [CVEAC-2020](https://github.com/thesecretclub/CVEAC-2020) 18 | 19 | # Code guidelines 20 | - Ensure C89 compatibility. 21 | - Every identifier uses snake case. 22 | - Enums and macros are uppercase, every other identifier is lowercase. 23 | - Non-internal identifiers start with the `NMD_` prefix. e.g. `nmd_x86_decode()`. 24 | - Internal identifiers start with the `_NMD_` prefix. e.g. `_nmd_append_string()`. 25 | 26 | Repository inspired by [nothings/stb](https://github.com/nothings/stb). 27 | -------------------------------------------------------------------------------- /assembly/README: -------------------------------------------------------------------------------- 1 | The development of the single-header library 'nmd_assembly.h' is done here. 2 | 3 | If you need to use a macro(e.g. 'NMD_ASSEMBLY_DISABLE_DECODER_OPERANDS') you must tell the compiler in some way, otherwise the macro would just have effect on the current unit file. 4 | 5 | Run the 'merge_files.py' python script in order to merge all the files in the current folder into a single-header file "nmd_assembly.h" in the parent folder. -------------------------------------------------------------------------------- /assembly/merge_files.py: -------------------------------------------------------------------------------- 1 | file_names = [ 2 | # Header file 3 | 'nmd_assembly.h', 4 | 5 | # Implementation files 6 | 'nmd_common.c', # common macros, functions, structs... 7 | 'nmd_x86_assembler.c', 8 | 'nmd_x86_decoder.c', 9 | 'nmd_x86_ldisasm.c', 10 | 'nmd_x86_formatter.c', 11 | ] 12 | 13 | file_contents = [] 14 | 15 | import sys 16 | if sys.version_info < (3, 0): 17 | # If we are running Python 2, ignore the 'newline' arg. 18 | def wrap(opn): 19 | def open_py2(*args, **kwargs): 20 | if 'newline' in kwargs: 21 | del kwargs['newline'] 22 | return opn(*args, **kwargs) 23 | return open_py2 24 | open = wrap(open) 25 | 26 | 27 | with open('../nmd_assembly.h', 'w', newline='') as out: 28 | for file_name in file_names: 29 | with open(file_name, 'r') as file: 30 | # Read file's content 31 | content = file.read() 32 | 33 | # Remove these include statements 34 | content = content.replace('#include "nmd_common.h"', '') 35 | 36 | # Remove all empty lines at the start of the file 37 | while content[0] == '\n': 38 | content = content[1:] 39 | 40 | # Append the file to 'file_contents' 41 | file_contents.append(content) 42 | 43 | # Write the header 44 | out.write(file_contents[0]) 45 | file_contents.pop(0) 46 | 47 | out.write('\n\n') 48 | 49 | # Write the implementation 50 | out.write('#ifdef NMD_ASSEMBLY_IMPLEMENTATION\n\n') 51 | 52 | for file_content in file_contents: 53 | out.write(file_content) 54 | out.write('\n\n') 55 | 56 | out.write('#endif /* NMD_ASSEMBLY_IMPLEMENTATION */\n') 57 | -------------------------------------------------------------------------------- /assembly/nmd_common.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | /* Four high-order bits of an opcode to index a row of the opcode table */ 4 | #define _NMD_R(b) ((b) >> 4) 5 | 6 | /* Four low-order bits to index a column of the table */ 7 | #define _NMD_C(b) ((b) & 0xF) 8 | 9 | #define _NMD_NUM_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) 10 | 11 | #ifndef _NMD_IS_UPPERCASE 12 | #define _NMD_IS_UPPERCASE(c) ((c) >= 'A' && (c) <= 'Z') 13 | #define _NMD_IS_LOWERCASE(c) ((c) >= 'a' && (c) <= 'z') 14 | #define _NMD_TOLOWER(c) (_NMD_IS_UPPERCASE(c) ? (c) + 0x20 : (c)) 15 | #define _NMD_IS_DECIMAL_NUMBER(c) ((c) >= '0' && (c) <= '9') 16 | #define _NMD_MIN(a, b) ((a)<(b)?(a):(b)) 17 | #define _NMD_MAX(a, b) ((a)>(b)?(a):(b)) 18 | #endif /* _NMD_IS_UPPERCASE */ 19 | 20 | #define _NMD_SET_REG_OPERAND(operand, _is_implicit, _action, _reg) {operand.type = NMD_X86_OPERAND_TYPE_REGISTER; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.reg = _reg;} 21 | #define _NMD_SET_IMM_OPERAND(operand, _is_implicit, _action, _imm) {operand.type = NMD_X86_OPERAND_TYPE_IMMEDIATE; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.imm = _imm;} 22 | #define _NMD_SET_MEM_OPERAND(operand, _is_implicit, _action, _segment, _base, _index, _scale, _disp) {operand.type = NMD_X86_OPERAND_TYPE_MEMORY; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.mem.segment = _segment; operand.fields.mem.base = _base; operand.fields.mem.index = _index; operand.fields.mem.scale = _scale; operand.fields.mem.disp = _disp;} 23 | #define _NMD_GET_GPR(reg) (reg + (instruction->mode>>2)*8) /* reg(16),reg(32),reg(64). e.g. ax,eax,rax */ 24 | #define _NMD_GET_IP() (NMD_X86_REG_IP + (instruction->mode>>2)) /* ip,eip,rip */ 25 | #define _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, _16, _32) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : (_32))) /* Get something based on mode and operand size prefix. Used for instructions where the the 64-bit mode variant does not exist or is the same as the one for 32-bit mode */ 26 | #define _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, rex_w_prefix, _16, _32, _64) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : ((rex_w_prefix) ? (_64) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed with the REX.W prefix */ 27 | #define _NMD_GET_BY_MODE_OPSZPRFX_D64(mode, opszprfx, _16, _32, _64) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : ((mode) == NMD_X86_MODE_64 ? (_64) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed by default when mode is NMD_X86_MODE_64 and there's no operand size override prefix. */ 28 | #define _NMD_GET_BY_MODE_OPSZPRFX_F64(mode, opszprfx, _16, _32, _64) ((mode) == NMD_X86_MODE_64 ? (_64) : ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed when mode is NMD_X86_MODE_64 independent of an operand size override prefix. */ 29 | 30 | /* Make sure we can read a byte, read a byte, increment the buffer and decrement the buffer's size */ 31 | #define _NMD_READ_BYTE(buffer_, buffer_size_, var_) { if ((buffer_size_) < sizeof(uint8_t)) { return false; } var_ = *((uint8_t*)(buffer_)); buffer_ = ((uint8_t*)(buffer_)) + sizeof(uint8_t); (buffer_size_) -= sizeof(uint8_t); } 32 | 33 | NMD_ASSEMBLY_API const char* const _nmd_reg8[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; 34 | NMD_ASSEMBLY_API const char* const _nmd_reg8_x64[] = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil" }; 35 | NMD_ASSEMBLY_API const char* const _nmd_reg16[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; 36 | NMD_ASSEMBLY_API const char* const _nmd_reg32[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; 37 | NMD_ASSEMBLY_API const char* const _nmd_reg64[] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi" }; 38 | NMD_ASSEMBLY_API const char* const _nmd_regrxb[] = { "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }; 39 | NMD_ASSEMBLY_API const char* const _nmd_regrxw[] = { "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; 40 | NMD_ASSEMBLY_API const char* const _nmd_regrxd[] = { "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; 41 | NMD_ASSEMBLY_API const char* const _nmd_regrx[] = { "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; 42 | NMD_ASSEMBLY_API const char* const _nmd_segment_reg[] = { "es", "cs", "ss", "ds", "fs", "gs" }; 43 | 44 | NMD_ASSEMBLY_API const char* const _nmd_condition_suffixes[] = { "o", "no", "b", "nb", "z", "nz", "be", "a", "s", "ns", "p", "np", "l", "ge", "le", "g" }; 45 | 46 | NMD_ASSEMBLY_API const char* const _nmd_op1_opcode_map_mnemonics[] = { "add", "adc", "and", "xor", "or", "sbb", "sub", "cmp" }; 47 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp1[] = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }; 48 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp2[] = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" }; 49 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp3[] = { "test", "test", "not", "neg", "mul", "imul", "div", "idiv" }; 50 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp5[] = { "inc", "dec", "call", "call far", "jmp", "jmp far", "push" }; 51 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp6[] = { "sldt", "str", "lldt", "ltr", "verr", "verw" }; 52 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7[] = { "sgdt", "sidt", "lgdt", "lidt", "smsw", 0, "lmsw", "invlpg" }; 53 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg0[] = { "enclv", "vmcall", "vmlaunch", "vmresume", "vmxoff", "pconfig" }; 54 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg1[] = { "monitor", "mwait", "clac", "stac", 0, 0, 0, "encls" }; 55 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg2[] = { "xgetbv", "xsetbv", 0, 0, "vmfunc", "xend", "xtest", "enclu" }; 56 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg3[] = { "vmrun ", "vmmcall", "vmload ", "vmsave", "stgi", "clgi", "skinit eax", "invlpga " }; 57 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg7[] = { "swapgs", "rdtscp", "monitorx", "mwaitx", "clzero ", "rdpru" }; 58 | 59 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesD8[] = { "add", "mul", "com", "comp", "sub", "subr", "div", "divr" }; 60 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesD9[] = { "ld", 0, "st", "stp", "ldenv", "ldcw", "nstenv", "nstcw" }; 61 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDA_DE[] = { "iadd", "imul", "icom", "icomp", "isub", "isubr", "idiv", "idivr" }; 62 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDB[] = { "ild", "isttp", "ist", "istp", 0, "ld", 0, "stp" }; 63 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDC[] = { "add", "mul", "com", "comp", "sub", "subr", "div", "divr" }; 64 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDD[] = { "ld", "isttp", "st", "stp", "rstor", 0, "nsave", "nstsw" }; 65 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDF[] = { "ild", "isttp", "ist", "istp", "bld", "ild", "bstp", "istp" }; 66 | NMD_ASSEMBLY_API const char* const* _nmd_escape_opcodes[] = { _nmd_escape_opcodesD8, _nmd_escape_opcodesD9, _nmd_escape_opcodesDA_DE, _nmd_escape_opcodesDB, _nmd_escape_opcodesDC, _nmd_escape_opcodesDD, _nmd_escape_opcodesDA_DE, _nmd_escape_opcodesDF }; 67 | 68 | NMD_ASSEMBLY_API const uint8_t _nmd_op1_modrm[] = { 0xFF, 0x63, 0x69, 0x6B, 0xC0, 0xC1, 0xC6, 0xC7, 0xD0, 0xD1, 0xD2, 0xD3, 0xF6, 0xF7, 0xFE }; 69 | NMD_ASSEMBLY_API const uint8_t _nmd_op1_imm8[] = { 0x6A, 0x6B, 0x80, 0x82, 0x83, 0xA8, 0xC0, 0xC1, 0xC6, 0xCD, 0xD4, 0xD5, 0xEB }; 70 | NMD_ASSEMBLY_API const uint8_t _nmd_op1_imm32[] = { 0xE8, 0xE9, 0x68, 0x81, 0x69, 0xA9, 0xC7 }; 71 | NMD_ASSEMBLY_API const uint8_t _nmd_invalid_op2[] = { 0x04, 0x0a, 0x0c, 0x7a, 0x7b, 0x36, 0x39 }; 72 | NMD_ASSEMBLY_API const uint8_t _nmd_two_opcodes[] = { 0xb0, 0xb1, 0xb3, 0xbb, 0xc0, 0xc1 }; 73 | NMD_ASSEMBLY_API const uint8_t _nmd_valid_3DNow_opcodes[] = { 0x0c, 0x0d, 0x1c, 0x1d, 0x8a, 0x8e, 0x90, 0x94, 0x96, 0x97, 0x9a, 0x9e, 0xa0, 0xa4, 0xa6, 0xa7, 0xaa, 0xae, 0xb0, 0xb4, 0xb6, 0xb7, 0xbb, 0xbf }; 74 | 75 | NMD_ASSEMBLY_API bool _nmd_find_byte(const uint8_t* arr, const size_t N, const uint8_t x) 76 | { 77 | size_t i = 0; 78 | for (; i < N; i++) 79 | { 80 | if (arr[i] == x) 81 | return true; 82 | }; 83 | 84 | return false; 85 | } 86 | 87 | /* Returns a pointer to the first occurrence of 'c' in 's', or a null pointer if 'c' is not present. */ 88 | NMD_ASSEMBLY_API const char* _nmd_strchr(const char* s, char c) 89 | { 90 | for (; *s; s++) 91 | { 92 | if (*s == c) 93 | return s; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | /* Returns a pointer to the last occurrence of 'c' in 's', or a null pointer if 'c' is not present. */ 100 | NMD_ASSEMBLY_API const char* _nmd_reverse_strchr(const char* s, char c) 101 | { 102 | const char* end = s; 103 | while (*end) 104 | end++; 105 | 106 | for (; end > s; end--) 107 | { 108 | if (*end == c) 109 | return end; 110 | } 111 | 112 | return 0; 113 | } 114 | 115 | /* Returns a pointer to the first occurrence of 's2' in 's', or a null pointer if 's2' is not present. */ 116 | NMD_ASSEMBLY_API const char* _nmd_strstr(const char* s, const char* s2) 117 | { 118 | size_t i = 0; 119 | for (; *s; s++) 120 | { 121 | if (s2[i] == '\0') 122 | return s - i; 123 | 124 | if (*s != s2[i]) 125 | i = 0; 126 | 127 | if (*s == s2[i]) 128 | i++; 129 | } 130 | 131 | return 0; 132 | } 133 | 134 | /* Returns a pointer to the first occurrence of 's2' in 's', or a null pointer if 's2' is not present. If 's3_opt' is not null it receives the address of the next byte in 's'. */ 135 | NMD_ASSEMBLY_API const char* _nmd_strstr_ex(const char* s, const char* s2, const char** s3_opt) 136 | { 137 | size_t i = 0; 138 | for (; *s; s++) 139 | { 140 | if (s2[i] == '\0') 141 | { 142 | if (s3_opt) 143 | *s3_opt = s; 144 | return s - i; 145 | } 146 | 147 | if (*s != s2[i]) 148 | i = 0; 149 | 150 | if (*s == s2[i]) 151 | i++; 152 | } 153 | 154 | if (s2[i] == '\0') 155 | { 156 | if (s3_opt) 157 | *s3_opt = s; 158 | return s - i; 159 | } 160 | 161 | return 0; 162 | } 163 | 164 | 165 | /* Inserts 'c' at 's'. */ 166 | NMD_ASSEMBLY_API void _nmd_insert_char(const char* s, char c) 167 | { 168 | char* end = (char*)s; 169 | while (*end) 170 | end++; 171 | 172 | *(end + 1) = '\0'; 173 | 174 | for (; end > s; end--) 175 | *end = *(end - 1); 176 | 177 | *end = c; 178 | } 179 | 180 | /* Returns true if there is only a number between 's1' and 's2', false otherwise. */ 181 | NMD_ASSEMBLY_API bool _nmd_is_number(const char* s1, const char* s2) 182 | { 183 | const char* s = s1; 184 | for (; s < s2; s++) 185 | { 186 | if (!(*s >= '0' && *s <= '9') && !(*s >= 'a' && *s <= 'f') && !(*s >= 'A' && *s <= 'F')) 187 | { 188 | if ((s == s1 + 1 && *s1 == '0' && (*s == 'x' || *s == 'X')) || (s == s2 - 1 && (*s == 'h' || *s == 'H'))) 189 | continue; 190 | 191 | return false; 192 | } 193 | } 194 | 195 | return true; 196 | } 197 | 198 | /* Returns a pointer to the first occurrence of a number between 's1' and 's2', zero otherwise. */ 199 | NMD_ASSEMBLY_API const char* _nmd_find_number(const char* s1, const char* s2) 200 | { 201 | const char* s = s1; 202 | for (; s < s2; s++) 203 | { 204 | if ((*s >= '0' && *s <= '9') || (*s >= 'a' && *s <= 'f') || (*s >= 'A' && *s <= 'F')) 205 | return s; 206 | } 207 | 208 | return 0; 209 | } 210 | 211 | /* Returns true if s1 matches s2 exactly. */ 212 | NMD_ASSEMBLY_API bool _nmd_strcmp(const char* s1, const char* s2) 213 | { 214 | for (; *s1 && *s2; s1++, s2++) 215 | { 216 | if (*s1 != *s2) 217 | return false; 218 | } 219 | 220 | return !*s1 && !*s2; 221 | } 222 | 223 | NMD_ASSEMBLY_API size_t _nmd_get_bit_index(uint32_t mask) 224 | { 225 | size_t i = 0; 226 | while (!(mask & (1 << i))) 227 | i++; 228 | 229 | return i; 230 | } 231 | 232 | NMD_ASSEMBLY_API size_t _nmd_assembly_get_num_digits_hex(uint64_t n) 233 | { 234 | if (n == 0) 235 | return 1; 236 | 237 | size_t num_digits = 0; 238 | for (; n > 0; n /= 16) 239 | num_digits++; 240 | 241 | return num_digits; 242 | } 243 | 244 | NMD_ASSEMBLY_API size_t _nmd_assembly_get_num_digits(uint64_t n) 245 | { 246 | if (n == 0) 247 | return 1; 248 | 249 | size_t num_digits = 0; 250 | for (; n > 0; n /= 10) 251 | num_digits++; 252 | 253 | return num_digits; 254 | } 255 | -------------------------------------------------------------------------------- /assembly/nmd_common.h: -------------------------------------------------------------------------------- 1 | #ifndef NMD_COMMON_H 2 | #define NMD_COMMON_H 3 | 4 | #include "nmd_assembly.h" 5 | 6 | /* Four high-order bits of an opcode to index a row of the opcode table */ 7 | #define _NMD_R(b) ((b) >> 4) 8 | 9 | /* Four low-order bits to index a column of the table */ 10 | #define _NMD_C(b) ((b) & 0xF) 11 | 12 | #define _NMD_NUM_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) 13 | 14 | #define _NMD_IS_UPPERCASE(c) (c >= 'A' && c <= 'Z') 15 | #define _NMD_IS_LOWERCASE(c) (c >= 'a' && c <= 'z') 16 | #define _NMD_TOLOWER(c) (_NMD_IS_UPPERCASE(c) ? c + 0x20 : c) 17 | #define _NMD_IS_DECIMAL_NUMBER(c) (c >= '0' && c <= '9') 18 | #define _NMD_MIN(a, b) ((a)<(b)?(a):(b)) 19 | #define _NMD_MAX(a, b) ((a)>(b)?(a):(b)) 20 | 21 | #define _NMD_SET_REG_OPERAND(operand, _is_implicit, _action, _reg) {operand.type = NMD_X86_OPERAND_TYPE_REGISTER; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.reg = _reg;} 22 | #define _NMD_SET_IMM_OPERAND(operand, _is_implicit, _action, _imm) {operand.type = NMD_X86_OPERAND_TYPE_IMMEDIATE; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.imm = _imm;} 23 | #define _NMD_SET_MEM_OPERAND(operand, _is_implicit, _action, _segment, _base, _index, _scale, _disp) {operand.type = NMD_X86_OPERAND_TYPE_MEMORY; operand.is_implicit = _is_implicit; operand.action = _action; operand.fields.mem.segment = _segment; operand.fields.mem.base = _base; operand.fields.mem.index = _index; operand.fields.mem.scale = _scale; operand.fields.mem.disp = _disp;} 24 | #define _NMD_GET_GPR(reg) (reg + (instruction->mode>>2)*8) /* reg(16),reg(32),reg(64). e.g. ax,eax,rax */ 25 | #define _NMD_GET_IP() (NMD_X86_REG_IP + (instruction->mode>>2)) /* ip,eip,rip */ 26 | #define _NMD_GET_BY_MODE_OPSZPRFX(mode, opszprfx, _16, _32) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : (_32))) /* Get something based on mode and operand size prefix. Used for instructions where the the 64-bit mode variant does not exist or is the same as the one for 32-bit mode */ 27 | #define _NMD_GET_BY_MODE_OPSZPRFX_W64(mode, opszprfx, rex_w_prefix, _16, _32, _64) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : ((rex_w_prefix) ? (_64) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed with the REX.W prefix */ 28 | #define _NMD_GET_BY_MODE_OPSZPRFX_D64(mode, opszprfx, _16, _32, _64) ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : ((mode) == NMD_X86_MODE_64 ? (_64) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed by default when mode is NMD_X86_MODE_64 and there's no operand size override prefix. */ 29 | #define _NMD_GET_BY_MODE_OPSZPRFX_F64(mode, opszprfx, _16, _32, _64) ((mode) == NMD_X86_MODE_64 ? (_64) : ((mode) == NMD_X86_MODE_16 ? ((opszprfx) ? (_32) : (_16)) : ((opszprfx) ? (_16) : (_32)))) /* Get something based on mode and operand size prefix. The 64-bit version is accessed when mode is NMD_X86_MODE_64 independent of an operand size override prefix. */ 30 | 31 | /* Make sure we can read a byte, read a byte, increment the buffer and decrement the buffer's size */ 32 | #define _NMD_READ_BYTE(buffer_, buffer_size_, var_) { if ((buffer_size_) < sizeof(uint8_t)) { return false; } var_ = *((uint8_t*)(buffer_)); buffer_ = ((uint8_t*)(buffer_)) + sizeof(uint8_t); (buffer_size_) -= sizeof(uint8_t); } 33 | 34 | NMD_ASSEMBLY_API const char* const _nmd_reg8[8]; 35 | NMD_ASSEMBLY_API const char* const _nmd_reg8_x64[8]; 36 | NMD_ASSEMBLY_API const char* const _nmd_reg16[8]; 37 | NMD_ASSEMBLY_API const char* const _nmd_reg32[8]; 38 | NMD_ASSEMBLY_API const char* const _nmd_reg64[8]; 39 | NMD_ASSEMBLY_API const char* const _nmd_regrxb[8]; 40 | NMD_ASSEMBLY_API const char* const _nmd_regrxw[8]; 41 | NMD_ASSEMBLY_API const char* const _nmd_regrxd[8]; 42 | NMD_ASSEMBLY_API const char* const _nmd_regrx[8]; 43 | NMD_ASSEMBLY_API const char* const _nmd_segment_reg[6]; 44 | 45 | NMD_ASSEMBLY_API const char* const _nmd_condition_suffixes[16]; 46 | 47 | NMD_ASSEMBLY_API const char* const _nmd_op1_opcode_map_mnemonics[8]; 48 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp1[8]; 49 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp2[8]; 50 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp3[8]; 51 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp5[7]; 52 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp6[6]; 53 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7[8]; 54 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg0[6]; 55 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg1[8]; 56 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg2[8]; 57 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg3[8]; 58 | NMD_ASSEMBLY_API const char* const _nmd_opcode_extensions_grp7_reg7[6]; 59 | 60 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesD8[8]; 61 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesD9[8]; 62 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDA_DE[8]; 63 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDB[8]; 64 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDC[8]; 65 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDD[8]; 66 | NMD_ASSEMBLY_API const char* const _nmd_escape_opcodesDF[8]; 67 | NMD_ASSEMBLY_API const char* const* _nmd_escape_opcodes[8]; 68 | 69 | NMD_ASSEMBLY_API const uint8_t _nmd_op1_modrm[16]; 70 | NMD_ASSEMBLY_API const uint8_t _nmd_op1_imm8[13]; 71 | NMD_ASSEMBLY_API const uint8_t _nmd_op1_imm32[7]; 72 | NMD_ASSEMBLY_API const uint8_t _nmd_invalid_op2[7]; 73 | NMD_ASSEMBLY_API const uint8_t _nmd_two_opcodes[6]; 74 | NMD_ASSEMBLY_API const uint8_t _nmd_valid_3DNow_opcodes[24]; 75 | 76 | NMD_ASSEMBLY_API bool _nmd_find_byte(const uint8_t* arr, const size_t N, const uint8_t x); 77 | 78 | /* Returns a pointer to the first occurrence of 'c' in 's', or a null pointer if 'c' is not present. */ 79 | NMD_ASSEMBLY_API const char* _nmd_strchr(const char* s, char c); 80 | 81 | /* Returns a pointer to the last occurrence of 'c' in 's', or a null pointer if 'c' is not present. */ 82 | NMD_ASSEMBLY_API const char* _nmd_reverse_strchr(const char* s, char c); 83 | 84 | /* Returns a pointer to the first occurrence of 's2' in 's', or a null pointer if 's2' is not present. */ 85 | NMD_ASSEMBLY_API const char* _nmd_strstr(const char* s, const char* s2); 86 | 87 | /* Returns a pointer to the first occurrence of 's2' in 's', or a null pointer if 's2' is not present. If 's3_opt' is not null it receives the address of the next byte in 's'. */ 88 | NMD_ASSEMBLY_API const char* _nmd_strstr_ex(const char* s, const char* s2, const char** s3_opt); 89 | 90 | /* Inserts 'c' at 's'. */ 91 | NMD_ASSEMBLY_API void _nmd_insert_char(const char* s, char c); 92 | 93 | /* Returns true if there is only a number between 's1' and 's2', false otherwise. */ 94 | NMD_ASSEMBLY_API bool _nmd_is_number(const char* s1, const char* s2); 95 | 96 | /* Returns a pointer to the first occurence of a number between 's1' and 's2', zero otherwise. */ 97 | NMD_ASSEMBLY_API const char* _nmd_find_number(const char* s1, const char* s2); 98 | 99 | /* Returns true if s1 matches s2 exactly. */ 100 | NMD_ASSEMBLY_API bool _nmd_strcmp(const char* s1, const char* s2); 101 | 102 | NMD_ASSEMBLY_API size_t _nmd_get_bit_index(uint32_t mask); 103 | 104 | NMD_ASSEMBLY_API size_t _nmd_assembly_get_num_digits_hex(uint64_t n); 105 | 106 | NMD_ASSEMBLY_API size_t _nmd_assembly_get_num_digits(uint64_t n); 107 | 108 | #endif /* NMD_COMMON_H */ -------------------------------------------------------------------------------- /assembly/nmd_x86_ldisasm.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | NMD_ASSEMBLY_API bool _nmd_ldisasm_decode_modrm(const uint8_t** p_buffer, size_t* p_buffer_size, bool address_prefix, NMD_X86_MODE mode, nmd_x86_modrm* p_modrm) 4 | { 5 | _NMD_READ_BYTE(*p_buffer, *p_buffer_size, (*p_modrm).modrm); 6 | 7 | bool has_sib = false; 8 | size_t disp_size = 0; 9 | 10 | if (mode == NMD_X86_MODE_16) 11 | { 12 | if (p_modrm->fields.mod != 0b11) 13 | { 14 | if (p_modrm->fields.mod == 0b00) 15 | { 16 | if (p_modrm->fields.rm == 0b110) 17 | disp_size = 2; 18 | } 19 | else 20 | disp_size = p_modrm->fields.mod == 0b01 ? 1 : 2; 21 | } 22 | } 23 | else 24 | { 25 | if (address_prefix && mode == NMD_X86_MODE_32) 26 | { 27 | if ((p_modrm->fields.mod == 0b00 && p_modrm->fields.rm == 0b110) || p_modrm->fields.mod == 0b10) 28 | disp_size = 2; 29 | else if (p_modrm->fields.mod == 0b01) 30 | disp_size = 1; 31 | } 32 | else 33 | { 34 | /* Check for SIB byte */ 35 | uint8_t sib = 0; 36 | if (p_modrm->modrm < 0xC0 && p_modrm->fields.rm == 0b100 && (!address_prefix || (address_prefix && mode == NMD_X86_MODE_64))) 37 | { 38 | has_sib = true; 39 | _NMD_READ_BYTE(*p_buffer, *p_buffer_size, sib); 40 | } 41 | 42 | if (p_modrm->fields.mod == 0b01) /* disp8 (ModR/M) */ 43 | disp_size = 1; 44 | else if ((p_modrm->fields.mod == 0b00 && p_modrm->fields.rm == 0b101) || p_modrm->fields.mod == 0b10) /* disp16,32 (ModR/M) */ 45 | disp_size = (address_prefix && !(mode == NMD_X86_MODE_64 && address_prefix) ? 2 : 4); 46 | else if (has_sib && (sib & 0b111) == 0b101) /* disp8,32 (SIB) */ 47 | disp_size = (p_modrm->fields.mod == 0b01 ? 1 : 4); 48 | } 49 | } 50 | 51 | /* Make sure we can read 'instruction->disp_mask' bytes from the buffer */ 52 | if (*p_buffer_size < disp_size) 53 | return false; 54 | 55 | /* Increment the buffer and decrement the buffer's size */ 56 | *p_buffer += disp_size; 57 | *p_buffer_size -= disp_size; 58 | 59 | return true; 60 | } 61 | 62 | /* 63 | Returns the length of the instruction if it is valid, zero otherwise. 64 | Parameters: 65 | - buffer [in] A pointer to a buffer containing an encoded instruction. 66 | - buffer_size [in] The size of the buffer in bytes. 67 | - mode [in] The architecture mode. 'NMD_X86_MODE_32', 'NMD_X86_MODE_64' or 'NMD_X86_MODE_16'. 68 | */ 69 | NMD_ASSEMBLY_API size_t nmd_x86_ldisasm(const void* const buffer, size_t buffer_size, const NMD_X86_MODE mode) 70 | { 71 | bool operand_prefix = false; 72 | bool address_prefix = false; 73 | bool repeat_prefix = false; 74 | bool repeat_not_zero_prefix = false; 75 | bool rexW = false; 76 | bool lock_prefix = false; 77 | uint16_t simd_prefix = NMD_X86_PREFIXES_NONE; 78 | uint8_t opcode_size = 0; 79 | bool has_modrm = false; 80 | nmd_x86_modrm modrm; 81 | modrm.modrm = 0; 82 | 83 | /* Security considerations for memory safety: 84 | The contents of 'buffer' should be considered untrusted and decoded carefully. 85 | 86 | 'buffer' should always point to the start of the buffer. We use the 'b' 87 | buffer iterator to read data from the buffer, however before accessing it 88 | make sure to check 'buffer_size' to see if we can safely access it. Then, 89 | after reading data from the buffer we increment 'b' and decrement 'buffer_size'. 90 | Helper macros: _NMD_READ_BYTE() 91 | */ 92 | 93 | /* Set buffer iterator */ 94 | const uint8_t* b = (const uint8_t*)buffer; 95 | 96 | /* Clamp 'buffer_size' to 15. We will only read up to 15 bytes(NMD_X86_MAXIMUM_INSTRUCTION_LENGTH) */ 97 | if (buffer_size > 15) 98 | buffer_size = 15; 99 | 100 | /* Decode legacy and REX prefixes */ 101 | for (; buffer_size > 0; b++, buffer_size--) 102 | { 103 | switch (*b) 104 | { 105 | case 0xF0: lock_prefix = true; continue; 106 | case 0xF2: repeat_not_zero_prefix = true, simd_prefix = NMD_X86_PREFIXES_REPEAT_NOT_ZERO; continue; 107 | case 0xF3: repeat_prefix = true, simd_prefix = NMD_X86_PREFIXES_REPEAT; continue; 108 | case 0x2E: continue; 109 | case 0x36: continue; 110 | case 0x3E: continue; 111 | case 0x26: continue; 112 | case 0x64: continue; 113 | case 0x65: continue; 114 | case 0x66: operand_prefix = true, simd_prefix = NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE; continue; 115 | case 0x67: address_prefix = true; continue; 116 | default: 117 | if (mode == NMD_X86_MODE_64 && _NMD_R(*b) == 4) /* REX prefixes [0x40,0x4f] */ 118 | { 119 | if(_NMD_C(*b) & 0b1000) 120 | rexW = true; 121 | continue; 122 | } 123 | } 124 | 125 | break; 126 | } 127 | 128 | /* Calculate the number of prefixes based on how much the iterator moved */ 129 | const size_t num_prefixes = (uint8_t)((ptrdiff_t)(b)-(ptrdiff_t)(buffer)); 130 | 131 | /* Opcode byte. This variable is used because 'op' is simpler than 'instruction->opcode' */ 132 | uint8_t op; 133 | _NMD_READ_BYTE(b, buffer_size, op); 134 | 135 | if (op == 0x0F) /* 2 or 3 byte opcode */ 136 | { 137 | _NMD_READ_BYTE(b, buffer_size, op); 138 | 139 | if (op == 0x38 || op == 0x3A) /* 3 byte opcode */ 140 | { 141 | const bool is_opcode_map38 = op == 0x38; 142 | opcode_size = 3; 143 | 144 | _NMD_READ_BYTE(b, buffer_size, op); 145 | 146 | if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) 147 | return 0; 148 | has_modrm = true; 149 | 150 | if (is_opcode_map38) 151 | { 152 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK 153 | if (op == 0x36) 154 | { 155 | return 0; 156 | } 157 | else if (op <= 0xb || (op >= 0x1c && op <= 0x1e)) 158 | { 159 | if (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) 160 | return 0; 161 | } 162 | else if (op >= 0xc8 && op <= 0xcd) 163 | { 164 | if (simd_prefix) 165 | return 0; 166 | } 167 | else if (op == 0x10 || op == 0x14 || op == 0x15 || op == 0x17 || (op >= 0x20 && op <= 0x25) || op == 0x28 || op == 0x29 || op == 0x2b || _NMD_R(op) == 3 || op == 0x40 || op == 0x41 || op == 0xcf || (op >= 0xdb && op <= 0xdf)) 168 | { 169 | if (simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) 170 | return 0; 171 | } 172 | else if (op == 0x2a || (op >= 0x80 && op <= 0x82)) 173 | { 174 | if (modrm.fields.mod == 0b11 || simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) 175 | return 0; 176 | } 177 | else if (op == 0xf0 || op == 0xf1) 178 | { 179 | if (modrm.fields.mod == 0b11 && (simd_prefix == NMD_X86_PREFIXES_NONE || simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) 180 | return 0; 181 | else if (simd_prefix == NMD_X86_PREFIXES_REPEAT) 182 | return 0; 183 | } 184 | else if (op == 0xf5 || op == 0xf8) 185 | { 186 | if (simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || modrm.fields.mod == 0b11) 187 | return 0; 188 | } 189 | else if (op == 0xf6) 190 | { 191 | if (simd_prefix == NMD_X86_PREFIXES_NONE && modrm.fields.mod == 0b11) 192 | return 0; 193 | else if (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) 194 | return 0; 195 | } 196 | else if (op == 0xf9) 197 | { 198 | if (simd_prefix != NMD_X86_PREFIXES_NONE || modrm.fields.mod == 0b11) 199 | return 0; 200 | } 201 | else 202 | return 0; 203 | #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ 204 | } 205 | else /* 0x3a */ 206 | { 207 | /* "Read" the immediate byte */ 208 | uint8_t imm; 209 | _NMD_READ_BYTE(b, buffer_size, imm); 210 | 211 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK 212 | if ((op >= 0x8 && op <= 0xe) || (op >= 0x14 && op <= 0x17) || (op >= 0x20 && op <= 0x22) || (op >= 0x40 && op <= 0x42) || op == 0x44 || (op >= 0x60 && op <= 0x63) || op == 0xdf || op == 0xce || op == 0xcf) 213 | { 214 | if (simd_prefix != NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE) 215 | return 0; 216 | } 217 | else if (op == 0x0f || op == 0xcc) 218 | { 219 | if (simd_prefix) 220 | return 0; 221 | } 222 | else 223 | return 0; 224 | #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ 225 | } 226 | } 227 | else if (op == 0x0f) /* 3DNow! opcode map*/ 228 | { 229 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW 230 | if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) 231 | return false; 232 | 233 | uint8_t imm; 234 | _NMD_READ_BYTE(b, buffer_size, imm); 235 | 236 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK 237 | if (!_nmd_find_byte(_nmd_valid_3DNow_opcodes, sizeof(_nmd_valid_3DNow_opcodes), imm)) 238 | return false; 239 | #endif /*NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ 240 | #else /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW */ 241 | return false; 242 | #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_3DNOW */ 243 | } 244 | else /* 2 byte opcode. */ 245 | { 246 | opcode_size = 2; 247 | 248 | /* Check for ModR/M, SIB and displacement */ 249 | if (op >= 0x20 && op <= 0x23) 250 | { 251 | has_modrm = true; 252 | _NMD_READ_BYTE(b, buffer_size, modrm.modrm); 253 | } 254 | else if (op < 4 || (_NMD_R(op) != 3 && _NMD_R(op) > 0 && _NMD_R(op) < 7) || (op >= 0xD0 && op != 0xFF) || (_NMD_R(op) == 7 && _NMD_C(op) != 7) || _NMD_R(op) == 9 || _NMD_R(op) == 0xB || (_NMD_R(op) == 0xC && _NMD_C(op) < 8) || (_NMD_R(op) == 0xA && (op % 8) >= 3) || op == 0x0ff || op == 0x00 || op == 0x0d) 255 | { 256 | if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) 257 | return 0; 258 | has_modrm = true; 259 | } 260 | 261 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK 262 | if (_nmd_find_byte(_nmd_invalid_op2, sizeof(_nmd_invalid_op2), op)) 263 | return 0; 264 | else if (op == 0xc7) 265 | { 266 | if ((!simd_prefix && (modrm.fields.mod == 0b11 ? modrm.fields.reg <= 0b101 : modrm.fields.reg == 0b000 || modrm.fields.reg == 0b010)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO && (modrm.fields.mod == 0b11 || modrm.fields.reg != 0b001)) || ((simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT) && (modrm.fields.mod == 0b11 ? modrm.fields.reg <= (simd_prefix == NMD_X86_PREFIXES_REPEAT ? 0b110 : 0b101) : (modrm.fields.reg != 0b001 && modrm.fields.reg != 0b110)))) 267 | return 0; 268 | } 269 | else if (op == 0x00) 270 | { 271 | if (modrm.fields.reg >= 0b110) 272 | return 0; 273 | } 274 | else if (op == 0x01) 275 | { 276 | if ((modrm.fields.mod == 0b11 ? (( (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || simd_prefix == NMD_X86_PREFIXES_REPEAT) && ((modrm.modrm >= 0xc0 && modrm.modrm <= 0xc5) || (modrm.modrm >= 0xc8 && modrm.modrm <= 0xcb) || (modrm.modrm >= 0xcf && modrm.modrm <= 0xd1) || (modrm.modrm >= 0xd4 && modrm.modrm <= 0xd7) || modrm.modrm == 0xee || modrm.modrm == 0xef || modrm.modrm == 0xfa || modrm.modrm == 0xfb)) || (modrm.fields.reg == 0b000 && modrm.fields.rm >= 0b110) || (modrm.fields.reg == 0b001 && modrm.fields.rm >= 0b100 && modrm.fields.rm <= 0b110) || (modrm.fields.reg == 0b010 && (modrm.fields.rm == 0b010 || modrm.fields.rm == 0b011)) || (modrm.fields.reg == 0b101 && modrm.fields.rm < 0b110 && (!repeat_prefix || (simd_prefix == NMD_X86_PREFIXES_REPEAT && (modrm.fields.rm != 0b000 && modrm.fields.rm != 0b010)))) || (modrm.fields.reg == 0b111 && (modrm.fields.rm > 0b101 || (mode != NMD_X86_MODE_64 && modrm.fields.rm == 0b000)))) : (!repeat_prefix && modrm.fields.reg == 0b101))) 277 | return 0; 278 | } 279 | else if (op == 0x1A || op == 0x1B) 280 | { 281 | if (modrm.fields.mod == 0b11) 282 | return 0; 283 | } 284 | else if (op == 0x20 || op == 0x22) 285 | { 286 | if (modrm.fields.reg == 0b001 || modrm.fields.reg >= 0b101) 287 | return 0; 288 | } 289 | else if (op >= 0x24 && op <= 0x27) 290 | return 0; 291 | else if (op >= 0x3b && op <= 0x3f) 292 | return 0; 293 | else if (_NMD_R(op) == 5) 294 | { 295 | if ((op == 0x50 && modrm.fields.mod != 0b11) || (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (op == 0x52 || op == 0x53)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT && (op == 0x50 || (op >= 0x54 && op <= 0x57))) || (repeat_not_zero_prefix && (op == 0x50 || (op >= 0x52 && op <= 0x57) || op == 0x5b))) 296 | return 0; 297 | } 298 | else if (_NMD_R(op) == 6) 299 | { 300 | if ((!(simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && (op == 0x6c || op == 0x6d)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT && op != 0x6f) || repeat_not_zero_prefix) 301 | return 0; 302 | } 303 | else if (op == 0x78 || op == 0x79) 304 | { 305 | if ((((simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && op == 0x78) && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b000)) || ((simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && modrm.fields.mod != 0b11)) || (simd_prefix == NMD_X86_PREFIXES_REPEAT)) 306 | return 0; 307 | } 308 | else if (op == 0x7c || op == 0x7d) 309 | { 310 | if (simd_prefix == NMD_X86_PREFIXES_REPEAT || !(simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE || simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO)) 311 | return 0; 312 | } 313 | else if (op == 0x7e || op == 0x7f) 314 | { 315 | if (repeat_not_zero_prefix) 316 | return 0; 317 | } 318 | else if (op >= 0x71 && op <= 0x73) 319 | { 320 | if ((simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) || modrm.modrm <= 0xcf || (modrm.modrm >= 0xe8 && modrm.modrm <= 0xef)) 321 | return 0; 322 | } 323 | else if (op == 0x73) 324 | { 325 | if (modrm.modrm >= 0xe0 && modrm.modrm <= 0xe8) 326 | return 0; 327 | } 328 | else if (op == 0xa6) 329 | { 330 | if (modrm.modrm != 0xc0 && modrm.modrm != 0xc8 && modrm.modrm != 0xd0) 331 | return 0; 332 | } 333 | else if (op == 0xa7) 334 | { 335 | if (!(modrm.fields.mod == 0b11 && modrm.fields.reg <= 0b101 && modrm.fields.rm == 0b000)) 336 | return 0; 337 | } 338 | else if (op == 0xae) 339 | { 340 | if (((!simd_prefix && modrm.fields.mod == 0b11 && modrm.fields.reg <= 0b100) || (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b110)) || (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (modrm.fields.reg < 0b110 || (modrm.fields.mod == 0b11 && modrm.fields.reg == 0b111))) || (simd_prefix == NMD_X86_PREFIXES_REPEAT && (modrm.fields.reg != 0b100 && modrm.fields.reg != 0b110) && !(modrm.fields.mod == 0b11 && modrm.fields.reg == 0b101)))) 341 | return 0; 342 | } 343 | else if (op == 0xb8) 344 | { 345 | if (!repeat_prefix) 346 | return 0; 347 | } 348 | else if (op == 0xba) 349 | { 350 | if (modrm.fields.reg <= 0b011) 351 | return 0; 352 | } 353 | else if (op == 0xd0) 354 | { 355 | if (!simd_prefix || simd_prefix == NMD_X86_PREFIXES_REPEAT) 356 | return 0; 357 | } 358 | else if (op == 0xe0) 359 | { 360 | if (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) 361 | return 0; 362 | } 363 | else if (op == 0xf0) 364 | { 365 | if (simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO ? modrm.fields.mod == 0b11 : true) 366 | return 0; 367 | } 368 | else if (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) 369 | { 370 | if ((op >= 0x13 && op <= 0x17 && !(op == 0x16 && simd_prefix == NMD_X86_PREFIXES_REPEAT)) || op == 0x28 || op == 0x29 || op == 0x2e || op == 0x2f || (op <= 0x76 && op >= 0x74)) 371 | return 0; 372 | } 373 | else if (op == 0x71 || op == 0x72 || (op == 0x73 && !(simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE))) 374 | { 375 | if ((modrm.modrm >= 0xd8 && modrm.modrm <= 0xdf) || modrm.modrm >= 0xf8) 376 | return 0; 377 | } 378 | else if (op >= 0xc3 && op <= 0xc6) 379 | { 380 | if ((op == 0xc5 && modrm.fields.mod != 0b11) || (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) || (op == 0xc3 && simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE)) 381 | return 0; 382 | } 383 | else if (_NMD_R(op) >= 0xd && _NMD_C(op) != 0 && op != 0xff && ((_NMD_C(op) == 6 && _NMD_R(op) != 0xf) ? (!simd_prefix || (_NMD_R(op) == 0xD && (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) ? modrm.fields.mod != 0b11 : false)) : (simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO || ((_NMD_C(op) == 7 && _NMD_R(op) != 0xe) ? modrm.fields.mod != 0b11 : false)))) 384 | return 0; 385 | else if (has_modrm && modrm.fields.mod == 0b11) 386 | { 387 | if (op == 0xb2 || op == 0xb4 || op == 0xb5 || op == 0xc3 || op == 0xe7 || op == 0x2b || (simd_prefix == NMD_X86_PREFIXES_OPERAND_SIZE_OVERRIDE && (op == 0x12 || op == 0x16)) || (!(simd_prefix == NMD_X86_PREFIXES_REPEAT || simd_prefix == NMD_X86_PREFIXES_REPEAT_NOT_ZERO) && (op == 0x13 || op == 0x17))) 388 | return 0; 389 | } 390 | #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ 391 | 392 | uint8_t imm_mask = 0; 393 | if (_NMD_R(op) == 8) /* imm32 */ 394 | imm_mask = _NMD_GET_BY_MODE_OPSZPRFX_F64(mode, operand_prefix, 2, 4, 4); 395 | else if ((_NMD_R(op) == 7 && _NMD_C(op) < 4) || op == 0xA4 || op == 0xC2 || (op > 0xC3 && op <= 0xC6) || op == 0xBA || op == 0xAC) /* imm8 */ 396 | imm_mask = 1; 397 | else if (op == 0x78 && (repeat_not_zero_prefix || operand_prefix)) /* imm8 + imm8 = "imm16" */ 398 | imm_mask = 2; 399 | 400 | /* Make sure we can "read" 'imm_mask' bytes from the buffer */ 401 | if (buffer_size < imm_mask) 402 | return false; 403 | 404 | /* Increment the buffer and decrement the buffer's size */ 405 | b += imm_mask; 406 | buffer_size -= imm_mask; 407 | } 408 | } 409 | else /* 1 byte opcode */ 410 | { 411 | opcode_size = 1; 412 | 413 | /* Check for ModR/M, SIB and displacement */ 414 | if (_NMD_R(op) == 8 || _nmd_find_byte(_nmd_op1_modrm, sizeof(_nmd_op1_modrm), op) || (_NMD_R(op) < 4 && (_NMD_C(op) < 4 || (_NMD_C(op) >= 8 && _NMD_C(op) < 0xC))) || (_NMD_R(op) == 0xD && _NMD_C(op) >= 8)/* || ((op == 0xc4 || op == 0xc5) && remaining_size > 1 && ((nmd_x86_modrm*)(b + 1))->fields.mod != 0b11)*/) 415 | { 416 | if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) 417 | return 0; 418 | has_modrm = true; 419 | } 420 | 421 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK 422 | if (op == 0xC6 || op == 0xC7) 423 | { 424 | if ((modrm.fields.reg != 0b000 && modrm.fields.reg != 0b111) || (modrm.fields.reg == 0b111 && (modrm.fields.mod != 0b11 || modrm.fields.rm != 0b000))) 425 | return 0; 426 | } 427 | else if (op == 0x8f) 428 | { 429 | if (modrm.fields.reg != 0b000) 430 | return 0; 431 | } 432 | else if (op == 0xfe) 433 | { 434 | if (modrm.fields.reg >= 0b010) 435 | return 0; 436 | } 437 | else if (op == 0xff) 438 | { 439 | if (modrm.fields.reg == 0b111 || (modrm.fields.mod == 0b11 && (modrm.fields.reg == 0b011 || modrm.fields.reg == 0b101))) 440 | return 0; 441 | } 442 | else if (op == 0x8c) 443 | { 444 | if (modrm.fields.reg >= 0b110) 445 | return 0; 446 | } 447 | else if (op == 0x8e) 448 | { 449 | if (modrm.fields.reg == 0b001 || modrm.fields.reg >= 0b110) 450 | return 0; 451 | } 452 | else if (op == 0x62) 453 | { 454 | if (mode == NMD_X86_MODE_64) 455 | return 0; 456 | } 457 | else if (op == 0x8d) 458 | { 459 | if (modrm.fields.mod == 0b11) 460 | return 0; 461 | } 462 | else if (op == 0xc4 || op == 0xc5) 463 | { 464 | if (mode == NMD_X86_MODE_64 && has_modrm && modrm.fields.mod != 0b11) 465 | return 0; 466 | } 467 | else if (op >= 0xd8 && op <= 0xdf) 468 | { 469 | switch (op) 470 | { 471 | case 0xd9: 472 | if ((modrm.fields.reg == 0b001 && modrm.fields.mod != 0b11) || (modrm.modrm > 0xd0 && modrm.modrm < 0xd8) || modrm.modrm == 0xe2 || modrm.modrm == 0xe3 || modrm.modrm == 0xe6 || modrm.modrm == 0xe7 || modrm.modrm == 0xef) 473 | return 0; 474 | break; 475 | case 0xda: 476 | if (modrm.modrm >= 0xe0 && modrm.modrm != 0xe9) 477 | return 0; 478 | break; 479 | case 0xdb: 480 | if (((modrm.fields.reg == 0b100 || modrm.fields.reg == 0b110) && modrm.fields.mod != 0b11) || (modrm.modrm >= 0xe5 && modrm.modrm <= 0xe7) || modrm.modrm >= 0xf8) 481 | return 0; 482 | break; 483 | case 0xdd: 484 | if ((modrm.fields.reg == 0b101 && modrm.fields.mod != 0b11) || _NMD_R(modrm.modrm) == 0xf) 485 | return 0; 486 | break; 487 | case 0xde: 488 | if (modrm.modrm == 0xd8 || (modrm.modrm >= 0xda && modrm.modrm <= 0xdf)) 489 | return 0; 490 | break; 491 | case 0xdf: 492 | if ((modrm.modrm >= 0xe1 && modrm.modrm <= 0xe7) || modrm.modrm >= 0xf8) 493 | return 0; 494 | break; 495 | } 496 | } 497 | else if (mode == NMD_X86_MODE_64) 498 | { 499 | if (op == 0x6 || op == 0x7 || op == 0xe || op == 0x16 || op == 0x17 || op == 0x1e || op == 0x1f || op == 0x27 || op == 0x2f || op == 0x37 || op == 0x3f || (op >= 0x60 && op <= 0x62) || op == 0x82 || op == 0xce || (op >= 0xd4 && op <= 0xd6)) 500 | return 0; 501 | } 502 | #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VALIDITY_CHECK */ 503 | 504 | #ifndef NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VEX 505 | /* Check if instruction is VEX */ 506 | if ((op == 0xc4 || op == 0xc5) && !has_modrm) 507 | { 508 | const uint8_t byte0 = op; 509 | 510 | uint8_t byte1; 511 | _NMD_READ_BYTE(b, buffer_size, byte1); 512 | 513 | if (byte0 == 0xc4) 514 | { 515 | uint8_t byte2; 516 | _NMD_READ_BYTE(b, buffer_size, byte2); 517 | 518 | _NMD_READ_BYTE(b, buffer_size, op); 519 | 520 | if (op == 0x0c || op == 0x0d || op == 0x40 || op == 0x41 || op == 0x17 || op == 0x21 || op == 0x42) 521 | { 522 | uint8_t imm; 523 | _NMD_READ_BYTE(b, buffer_size, imm); 524 | } 525 | } 526 | else /* 0xc5 */ 527 | { 528 | _NMD_READ_BYTE(b, buffer_size, op); 529 | } 530 | 531 | if (!_nmd_ldisasm_decode_modrm(&b, &buffer_size, address_prefix, mode, &modrm)) 532 | return false; 533 | has_modrm = true; 534 | } 535 | else 536 | #endif /* NMD_ASSEMBLY_DISABLE_LENGTH_DISASSEMBLER_VEX */ 537 | 538 | { 539 | /* Check for immediate */ 540 | uint8_t imm_mask = 0; 541 | if (_nmd_find_byte(_nmd_op1_imm32, sizeof(_nmd_op1_imm32), op) || (_NMD_R(op) < 4 && (_NMD_C(op) == 5 || _NMD_C(op) == 0xD)) || (_NMD_R(op) == 0xB && _NMD_C(op) >= 8) || (op == 0xF7 && modrm.fields.reg == 0b000)) /* imm32,16 */ 542 | { 543 | if (_NMD_R(op) == 0xB && _NMD_C(op) >= 8) 544 | imm_mask = rexW ? 8 : (operand_prefix || (mode == NMD_X86_MODE_16 && !operand_prefix) ? 2 : 4); 545 | else 546 | { 547 | if ((mode == NMD_X86_MODE_16 && operand_prefix) || (mode != NMD_X86_MODE_16 && !operand_prefix)) 548 | imm_mask = NMD_X86_IMM32; 549 | else 550 | imm_mask = NMD_X86_IMM16; 551 | } 552 | } 553 | else if (_NMD_R(op) == 7 || (_NMD_R(op) == 0xE && _NMD_C(op) < 8) || (_NMD_R(op) == 0xB && _NMD_C(op) < 8) || (_NMD_R(op) < 4 && (_NMD_C(op) == 4 || _NMD_C(op) == 0xC)) || (op == 0xF6 && modrm.fields.reg <= 0b001) || _nmd_find_byte(_nmd_op1_imm8, sizeof(_nmd_op1_imm8), op)) /* imm8 */ 554 | imm_mask = 1; 555 | else if (_NMD_R(op) == 0xA && _NMD_C(op) < 4) 556 | imm_mask = (mode == NMD_X86_MODE_64) ? (address_prefix ? 4 : 8) : (address_prefix ? 2 : 4); 557 | else if (op == 0xEA || op == 0x9A) /* imm32,48 */ 558 | { 559 | if (mode == NMD_X86_MODE_64) 560 | return 0; 561 | imm_mask = (operand_prefix ? 4 : 6); 562 | } 563 | else if (op == 0xC2 || op == 0xCA) /* imm16 */ 564 | imm_mask = 2; 565 | else if (op == 0xC8) /* imm16 + imm8 */ 566 | imm_mask = 3; 567 | 568 | /* Make sure we can "read" 'imm_mask' bytes from the buffer */ 569 | if (buffer_size < imm_mask) 570 | return false; 571 | 572 | /* Increment the buffer and decrement the buffer's size */ 573 | b += imm_mask; 574 | buffer_size -= imm_mask; 575 | } 576 | } 577 | 578 | if (lock_prefix) 579 | { 580 | if (!(has_modrm && modrm.fields.mod != 0b11 && 581 | ((opcode_size == 1 && (op == 0x86 || op == 0x87 || (_NMD_R(op) < 4 && (op % 8) < 2 && op < 0x38) || ((op >= 0x80 && op <= 0x83) && modrm.fields.reg != 0b111) || (op >= 0xfe && modrm.fields.reg < 2) || ((op == 0xf6 || op == 0xf7) && (modrm.fields.reg == 0b010 || modrm.fields.reg == 0b011)))) || 582 | (opcode_size == 2 && (_nmd_find_byte(_nmd_two_opcodes, sizeof(_nmd_two_opcodes), op) || op == 0xab || (op == 0xba && modrm.fields.reg != 0b100) || (op == 0xc7 && modrm.fields.reg == 0b001)))))) 583 | return 0; 584 | } 585 | 586 | return (size_t)((ptrdiff_t)(b) - (ptrdiff_t)(buffer)); 587 | } -------------------------------------------------------------------------------- /examples/assembly_example.c: -------------------------------------------------------------------------------- 1 | #define NMD_ASSEMBLY_IMPLEMENTATION 2 | #include "../nmd_assembly.h" 3 | #include 4 | int main() 5 | { 6 | const uint8_t buffer[] = { 0x33, 0xC0, 0x40, 0xC3, 0x8B, 0x65, 0xE8 }; 7 | const uint8_t* const buffer_end = buffer + sizeof(buffer); 8 | 9 | nmd_x86_instruction instruction; 10 | char formatted_instruction[128]; 11 | 12 | size_t i = 0; 13 | for (; i < sizeof(buffer); i += instruction.length) 14 | { 15 | if (!nmd_x86_decode(buffer + i, buffer_end - (buffer + i), &instruction, NMD_X86_MODE_32, NMD_X86_DECODER_FLAGS_MINIMAL)) 16 | break; 17 | 18 | nmd_x86_format(&instruction, formatted_instruction, NMD_X86_INVALID_RUNTIME_ADDRESS, NMD_X86_FORMAT_FLAGS_DEFAULT); 19 | 20 | printf("%s\n", formatted_instruction); 21 | } 22 | } -------------------------------------------------------------------------------- /examples/graphics_d3d11.cpp: -------------------------------------------------------------------------------- 1 | #define NMD_GRAPHICS_IMPLEMENTATION 2 | #define NMD_GRAPHICS_D3D11 3 | #include "../nmd_graphics.h" 4 | 5 | IDXGISwapChain* g_swap_chain; 6 | ID3D11RenderTargetView* g_render_target_view; 7 | ID3D11Device* g_device; 8 | ID3D11DeviceContext* g_device_context; 9 | 10 | void create_render_target() 11 | { 12 | ID3D11Texture2D* back_buffer; 13 | g_swap_chain->GetBuffer(0, IID_PPV_ARGS(&back_buffer)); 14 | g_device->CreateRenderTargetView(back_buffer, NULL, &g_render_target_view); 15 | g_device_context->OMSetRenderTargets(1, &g_render_target_view, NULL); 16 | back_buffer->Release(); 17 | } 18 | 19 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 20 | { 21 | nmd_win32_wnd_proc(hWnd, uMsg, wParam, lParam); 22 | 23 | switch (uMsg) 24 | { 25 | case WM_SIZE: 26 | if (g_swap_chain && wParam != SIZE_MINIMIZED) 27 | { 28 | if (g_render_target_view) 29 | g_render_target_view->Release(); 30 | g_swap_chain->ResizeBuffers(0, LOWORD(lParam), HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); 31 | create_render_target(); 32 | 33 | nmd_d3d11_resize(LOWORD(lParam), HIWORD(lParam)); 34 | } 35 | return 0; 36 | case WM_CLOSE: 37 | DestroyWindow(hWnd); 38 | return 0; 39 | case WM_DESTROY: 40 | PostQuitMessage(0); 41 | return 0; 42 | } 43 | 44 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 45 | } 46 | 47 | int main() 48 | { 49 | WNDCLASSEXW wcx; 50 | memset(&wcx, 0, sizeof(WNDCLASSEXW)); 51 | wcx.cbSize = sizeof(WNDCLASSEXW); 52 | wcx.lpfnWndProc = WindowProc; 53 | wcx.lpszClassName = TEXT("D3D11"); 54 | 55 | if (!RegisterClassExW(&wcx)) 56 | return 1; 57 | 58 | HWND hWnd; 59 | if (!(hWnd = CreateWindowExW(0, TEXT("D3D11"), TEXT("D3D11"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, NULL, NULL))) 60 | return 1; 61 | 62 | DXGI_SWAP_CHAIN_DESC swap_chain_desc; 63 | memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); 64 | swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1; 65 | swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 66 | swap_chain_desc.SampleDesc.Count = 1; 67 | swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 68 | swap_chain_desc.BufferCount = 1; 69 | swap_chain_desc.OutputWindow = hWnd; 70 | swap_chain_desc.Windowed = true; 71 | swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 72 | 73 | if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc, &g_swap_chain, &g_device, NULL, &g_device_context))) 74 | return 1; 75 | 76 | create_render_target(); 77 | 78 | nmd_d3d11_set_device_context(g_device_context); 79 | nmd_d3d11_resize(640, 480); 80 | 81 | bool checked = false; 82 | float f = 0; 83 | while (true) 84 | { 85 | MSG msg; 86 | while (PeekMessageW(&msg, NULL, NULL, NULL, PM_REMOVE)) 87 | { 88 | TranslateMessage(&msg); 89 | DispatchMessage(&msg); 90 | 91 | if (msg.message == WM_QUIT) 92 | return msg.wParam; 93 | } 94 | 95 | nmd_new_frame(); 96 | 97 | nmd_begin("Menu"); 98 | if (nmd_button("Create message box")) 99 | MessageBoxA(0, "You clicked the button", "Button", 0); 100 | nmd_text("hello"); 101 | nmd_checkbox("check box", &checked); 102 | nmd_slider_float("slider", &f, -10, 10); 103 | 104 | nmd_end(); 105 | 106 | //nmd_add_rect_filled(50, 50, 200, 200, NMD_COLOR_AZURE, 0, 0); 107 | //nmd_add_line(60, 60, 250, 60, NMD_COLOR_BLACK, 1.0f); 108 | //nmd_add_line(60, 70, 250, 150, NMD_COLOR_BLACK, 1.0f); 109 | 110 | nmd_end_frame(); 111 | 112 | FLOAT clear_color[4] = { 1.0f, 0.67f, 0.14f, 1.0f }; 113 | g_device_context->ClearRenderTargetView(g_render_target_view, (float*)&clear_color); 114 | nmd_d3d11_render(); 115 | g_swap_chain->Present(1, 0); 116 | } 117 | } -------------------------------------------------------------------------------- /examples/graphics_d3d9.cpp: -------------------------------------------------------------------------------- 1 | #define NMD_GRAPHICS_IMPLEMENTATION 2 | #define NMD_GRAPHICS_D3D9 3 | #include "../nmd_graphics.h" 4 | 5 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 6 | { 7 | switch (uMsg) 8 | { 9 | case WM_CLOSE: 10 | DestroyWindow(hWnd); 11 | return 0; 12 | case WM_DESTROY: 13 | PostQuitMessage(0); 14 | return 0; 15 | } 16 | 17 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 18 | } 19 | 20 | int main() 21 | { 22 | WNDCLASSEXW wcx; 23 | memset(&wcx, 0, sizeof(WNDCLASSEXW)); 24 | wcx.cbSize = sizeof(WNDCLASSEXW); 25 | wcx.lpfnWndProc = WindowProc; 26 | wcx.lpszClassName = TEXT("D3D9"); 27 | 28 | if (!RegisterClassExW(&wcx)) 29 | return -1; 30 | 31 | HWND hWnd; 32 | if (!(hWnd = CreateWindowExW(0, TEXT("D3D9"), TEXT("D3D9"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, NULL, NULL))) 33 | return -1; 34 | 35 | ShowWindow(hWnd, SW_SHOW); 36 | 37 | LPDIRECT3D9 d3d9; 38 | LPDIRECT3DDEVICE9 d3dDevice; 39 | if ((d3d9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) 40 | return -1; 41 | 42 | D3DPRESENT_PARAMETERS d3dpp; 43 | memset(&d3dpp, 0, sizeof(D3DPRESENT_PARAMETERS)); 44 | d3dpp.Windowed = TRUE; 45 | d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 46 | d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; 47 | d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; 48 | if (d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &d3dDevice) < 0) 49 | return false; 50 | d3dDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); 51 | nmd_get_context()->drawList.fillAntiAliasing = false; 52 | 53 | nmd_d3d9_set_device(d3dDevice); 54 | nmd_d3d9_resize(640, 480); 55 | 56 | nmd_atlas a; 57 | nmd_bake_font("C:/Windows/Fonts/arial.ttf", &a, 32.0f); 58 | 59 | a.font = nmd_d3d9_create_texture(a.pixels32, a.width, a.height); 60 | 61 | MSG msg; 62 | while (true) 63 | { 64 | while (PeekMessageW(&msg, NULL, NULL, NULL, PM_REMOVE)) 65 | { 66 | TranslateMessage(&msg); 67 | DispatchMessage(&msg); 68 | 69 | if (msg.message == WM_QUIT) 70 | return 0; 71 | } 72 | 73 | nmd_new_frame(); 74 | 75 | nmd_add_rect_filled(50, 50, 200, 200, NMD_COLOR_AZURE, 0, 0); 76 | nmd_add_line(60, 60, 250, 60, NMD_COLOR_BLACK, 1.0f); 77 | nmd_add_line(60, 70, 250, 150, NMD_COLOR_BLACK, 1.0f); 78 | 79 | nmd_add_text(&a, 20, 20, "Nomade", 0, NMD_COLOR_RED); 80 | 81 | nmd_end_frame(); 82 | 83 | d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(255, 170, 40, 255), 0, 0); 84 | d3dDevice->BeginScene(); 85 | nmd_d3d9_render(); 86 | d3dDevice->EndScene(); 87 | HRESULT result = d3dDevice->Present(NULL, NULL, NULL, NULL); 88 | } 89 | } -------------------------------------------------------------------------------- /examples/graphics_opengl.c: -------------------------------------------------------------------------------- 1 | #define NMD_GRAPHICS_IMPLEMENTATION 2 | #define NMD_GRAPHICS_OPENGL 3 | #include 4 | #include 5 | #include "../nmd_graphics.h" 6 | 7 | #ifdef _WIN32 8 | #pragma comment(lib, "opengl32.lib") 9 | #endif 10 | 11 | LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 12 | { 13 | switch (uMsg) 14 | { 15 | case WM_CLOSE: 16 | DestroyWindow(hWnd); 17 | return 0; 18 | case WM_DESTROY: 19 | PostQuitMessage(0); 20 | return 0; 21 | } 22 | 23 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 24 | } 25 | 26 | int main() 27 | { 28 | GLFWwindow* window; 29 | if (!glfwInit()) 30 | return -1; 31 | 32 | window = glfwCreateWindow(640, 480, "OpenGL", NULL, NULL); 33 | if (!window) 34 | { 35 | glfwTerminate(); 36 | return -1; 37 | } 38 | 39 | glfwMakeContextCurrent(window); 40 | 41 | glewInit(); 42 | 43 | nmd_opengl_resize(640, 480); 44 | 45 | while (!glfwWindowShouldClose(window)) 46 | { 47 | glfwPollEvents(); 48 | 49 | nmd_new_frame(); 50 | 51 | nmd_add_rect_filled(50, 50, 200, 200, NMD_COLOR_AZURE, 0, 0); 52 | nmd_add_line(60, 60, 250, 60, NMD_COLOR_BLACK, 1.0f); 53 | nmd_add_line(60, 70, 250, 150, NMD_COLOR_BLACK, 1.0f); 54 | 55 | nmd_end_frame(); 56 | 57 | glClearColor(1.0f, 0.67f, 0.14f, 1.0f); 58 | glClear(GL_COLOR_BUFFER_BIT); 59 | 60 | nmd_opengl_render(); 61 | 62 | glfwSwapBuffers(window); 63 | } 64 | } -------------------------------------------------------------------------------- /graphics/README: -------------------------------------------------------------------------------- 1 | The development of the single-header library 'nmd_graphics.cpp' is done here. 2 | 3 | If you need to use a macro(e.g. 'NMD_GRAPHICS_DISABLE_DEFAULT_FONT') you must tell the compiler in some way, otherwise the macro would just have effect on the current unit file. 4 | 5 | Run the 'merge_files.py' python script in order to merge all the files in the current folder into a single-header file "nmd_graphics.hpp" in the parent folder. -------------------------------------------------------------------------------- /graphics/merge_files.py: -------------------------------------------------------------------------------- 1 | file_names = [ 2 | # Header file 3 | 'nmd_graphics.h', 4 | 5 | # Implementation files 6 | 'nmd_common.c', 7 | 'nmd_stb_truetype.c', 8 | 'nmd_default_font.c', 9 | 'stb_truetype.h', 10 | 'nmd_graphics.c', 11 | 'nmd_drawlist.c', 12 | 'nmd_gui.c', 13 | 'nmd_renderer_d3d9.cpp', 14 | 'nmd_renderer_d3d11.cpp', 15 | 'nmd_renderer_opengl.c' 16 | ] 17 | 18 | file_contents = [] 19 | 20 | with open('../nmd_graphics.h', 'w') as out: 21 | for file_name in file_names: 22 | with open(file_name, 'r') as file: 23 | # Read file's content 24 | content = file.read() 25 | 26 | # Remove these include statements 27 | content = content.replace('#include "nmd_common.h"', '') 28 | 29 | # Remove all empty lines at the start of the file 30 | while content[0] == '\n': 31 | content = content[1:] 32 | 33 | # Append the file to 'file_contents' 34 | file_contents.append(content) 35 | 36 | # Write the header 37 | out.write(file_contents[0]) 38 | file_contents.pop(0) 39 | 40 | out.write('\n\n') 41 | 42 | # Write the implementation 43 | out.write('#ifdef NMD_GRAPHICS_IMPLEMENTATION\n\n') 44 | 45 | for file_content in file_contents: 46 | out.write(file_content) 47 | out.write('\n\n') 48 | 49 | out.write('#endif // NMD_GRAPHICS_IMPLEMENTATION\n') 50 | -------------------------------------------------------------------------------- /graphics/nmd_common.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | #define NMD_PI 3.141592653f 4 | #define NMD_2PI 6.283185306f 5 | 6 | #define NMD_CLAMP(x, low, high) ((x < low) ? low : (x > high) ? high : x) 7 | #define NMD_MIN(a, b) (a < b ? a : b) 8 | #define NMD_MAX(a, b) (a > b ? a : b) 9 | 10 | #define NMD_CIRCLE_AUTO_SEGMENT_MIN 12 11 | #define NMD_CIRCLE_AUTO_SEGMENT_MAX 512 12 | #define NMD_CIRCLE_AUTO_SEGMENT_CALC(radius, max_error) NMD_CLAMP(NMD_2PI / NMD_ACOS(((radius) - max_error) / (radius)), NMD_CIRCLE_AUTO_SEGMENT_MIN, NMD_CIRCLE_AUTO_SEGMENT_MAX) 13 | 14 | #define _NMD_OFFSETOF(TYPE, NAME) (&((TYPE*)0)->NAME) 15 | -------------------------------------------------------------------------------- /graphics/nmd_common.h: -------------------------------------------------------------------------------- 1 | #ifndef NMD_COMMON_H 2 | #define NMD_COMMON_H 3 | 4 | #include "nmd_graphics.h" 5 | #include "stb_truetype.h" 6 | 7 | #define NMD_PI 3.141592653f 8 | #define NMD_2PI 6.283185306f 9 | 10 | #define NMD_CLAMP(x, low, high) ((x < low) ? low : (x > high) ? high : x) 11 | #define NMD_MIN(a, b) (a < b ? a : b) 12 | #define NMD_MAX(a, b) (a > b ? a : b) 13 | 14 | #define NMD_CIRCLE_AUTO_SEGMENT_MIN 12 15 | #define NMD_CIRCLE_AUTO_SEGMENT_MAX 512 16 | #define NMD_CIRCLE_AUTO_SEGMENT_CALC(radius, max_error) NMD_CLAMP(NMD_2PI / NMD_ACOS(((radius) - max_error) / (radius)), NMD_CIRCLE_AUTO_SEGMENT_MIN, NMD_CIRCLE_AUTO_SEGMENT_MAX) 17 | 18 | #define _NMD_OFFSETOF(TYPE, NAME) (&((TYPE*)0)->NAME) 19 | 20 | extern nmd_context _nmd_context; 21 | extern const uint8_t nmd_karla_ttf_regular[14824]; 22 | 23 | #endif /* NMD_COMMON_H */ -------------------------------------------------------------------------------- /graphics/nmd_default_font.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | /* 4 | Uncompressed true type font 'Karla' by Jonny Pinhorn. Licensed under the Open Font License. 5 | Author's public contact information: 6 | - Jonnypinhorn.co.uk 7 | - https://github.com/jonpinhorn 8 | - https://twitter.com/jonpinhorn_type 9 | - jonpinhorn.typedesign@gmail.com 10 | */ 11 | 12 | #ifndef NMD_GRAPHICS_DISABLE_DEFAULT_FONT 13 | const uint8_t nmd_karla_ttf_regular[14824] = { 0,1,0,0,0,15,0,128,0,3,0,112,71,68,69,70,0,17,0,157,0,0,53,116,0,0,0,22,71,80,79,83,3,128,47,117,0,0,53,140,0,0,4,0,71,83,85,66,220,66,234,59,0,0,57,140,0,0,0,92,79,83,47,50,132,55,30,240,0,0,47,176,0,0,0,96,99,109,97,112,78,215,82,232,0,0,48,16,0,0,0,212,103,97,115,112,0,0,0,16,0,0,53,108,0,0,0,8,103,108,121,102,180,71,175,247,0,0,0,252,0,0,42,136,104,101,97,100,249,147,22,70,0,0,44,224,0,0,0,54,104,104,101,97,6,192,3,38,0,0,47,140,0,0,0,36,104,109,116,120,54,142,32,192,0,0,45,24,0,0,2,116,108,111,99,97,16,143,27,140,0,0,43,164,0,0,1,60,109,97,120,112,0,228,0,66,0,0,43,132,0,0,0,32,110,97,109,101,68,55,103,50,0,0,48,236,0,0,3,12,112,111,115,116,67,234,186,24,0,0,51,248,0,0,1,115,112,114,101,112,104,6,140,133,0,0,48,228,0,0,0,7,0,2,0,82,255,247,0,201,2,115,0,3,0,11,0,0,19,51,3,35,22,38,52,54,50,22,20,6,99,83,9,64,6,33,33,51,35,35,2,115,254,61,185,33,47,33,33,47,33,0,0,2,0,28,1,205,1,22,2,169,0,3,0,7,0,0,19,7,35,39,51,7,35,39,110,11,60,11,250,11,60,11,2,169,220,220,220,220,0,2,0,53,0,31,2,74,2,81,0,27,0,31,0,0,37,35,7,35,55,35,55,51,55,35,55,51,55,51,7,51,55,51,7,51,7,35,7,51,7,35,7,35,39,51,55,35,1,124,154,14,74,14,99,5,100,19,101,6,100,15,74,15,154,15,73,15,103,6,102,19,103,6,103,14,74,133,153,19,153,170,139,139,54,178,53,138,138,138,138,53,178,54,139,193,178,0,0,3,0,69,255,165,2,51,2,201,0,31,0,38,0,45,0,0,1,22,22,20,6,7,21,35,53,38,38,53,51,20,23,53,39,38,38,52,54,55,53,51,21,22,22,23,35,38,39,21,23,52,39,39,21,54,54,2,6,20,22,23,23,53,1,161,69,77,114,102,62,95,121,77,139,32,83,85,101,99,62,87,94,11,78,17,97,128,92,36,63,65,247,58,40,45,30,1,74,23,77,133,101,6,81,82,8,103,87,113,13,235,12,26,72,134,89,7,75,76,7,86,68,80,12,215,186,74,29,12,220,5,62,1,178,54,73,41,14,11,199,0,0,5,0,61,255,245,2,155,2,128,0,9,0,19,0,23,0,33,0,45,0,0,18,22,21,20,6,34,38,53,52,54,22,38,34,6,21,20,22,50,54,53,37,51,1,35,1,50,22,20,6,35,34,38,52,54,23,34,6,21,20,22,51,50,54,53,52,38,241,76,75,108,73,74,118,36,58,36,36,58,36,1,25,82,254,89,81,1,170,54,75,75,54,54,73,73,54,29,36,36,29,29,36,36,2,128,76,68,68,75,76,67,67,77,97,44,44,47,47,42,42,47,133,253,139,1,20,75,137,75,76,135,76,53,44,47,47,42,42,47,47,44,0,3,0,89,255,245,3,101,2,127,0,36,0,43,0,55,0,0,1,6,7,23,22,22,50,54,55,51,6,6,35,34,38,39,39,6,35,34,38,52,54,55,39,38,53,52,54,50,22,20,6,7,23,54,55,4,6,20,22,50,55,39,55,52,38,34,6,20,22,23,23,54,55,54,2,213,45,70,43,20,31,49,39,3,74,4,67,64,39,66,39,26,100,128,105,142,95,92,14,77,105,173,103,78,88,158,68,44,254,90,73,83,172,81,186,155,55,99,55,26,30,27,104,16,6,1,94,137,85,37,17,16,37,45,72,79,32,35,22,89,105,148,75,15,13,67,80,63,84,84,119,86,38,139,82,125,102,54,96,69,66,163,200,36,48,55,64,50,26,25,48,52,17,0,0,1,0,27,1,201,0,109,2,165,0,3,0,0,19,7,35,39,109,11,60,11,2,165,220,220,0,1,0,73,255,143,1,72,2,216,0,9,0,0,18,16,23,7,38,38,52,54,55,23,155,173,57,98,100,100,98,57,2,0,254,102,175,40,89,216,231,215,90,41,0,1,0,28,255,143,1,27,2,216,0,9,0,0,54,16,39,55,22,22,20,6,7,39,201,173,57,98,100,100,98,57,102,1,154,175,41,90,215,231,216,89,40,0,0,1,0,56,1,132,1,102,2,172,0,14,0,0,19,39,55,23,39,51,7,55,23,7,23,7,39,7,39,173,117,24,106,10,62,10,106,24,116,90,44,80,80,45,2,4,40,54,54,128,128,54,54,40,89,39,104,104,39,0,0,1,0,18,0,0,1,253,1,235,0,11,0,0,1,21,51,21,35,21,35,53,35,53,51,53,1,47,206,206,79,206,206,1,235,212,67,212,212,67,212,0,0,1,0,30,255,147,0,178,0,97,0,11,0,0,22,38,52,54,50,22,20,6,7,39,54,55,82,30,31,57,38,44,45,59,62,13,3,26,44,30,45,68,71,22,29,30,45,0,0,1,0,38,1,1,1,54,1,69,0,3,0,0,19,33,21,33,38,1,16,254,240,1,69,68,0,1,0,30,255,247,0,148,0,104,0,7,0,0,22,38,52,54,50,22,20,6,63,33,33,51,34,34,9,33,47,33,33,47,33,0,0,1,0,57,255,183,1,132,2,219,0,3,0,0,1,51,3,35,1,52,80,252,79,2,219,252,220,0,0,2,0,51,255,245,2,32,2,128,0,7,0,15,0,0,0,22,16,6,34,38,16,54,4,38,34,6,20,22,50,54,1,156,132,132,228,133,133,1,22,84,161,84,84,161,84,2,128,168,254,197,168,166,1,63,166,203,131,131,245,131,131,0,0,1,0,49,0,0,0,230,2,119,0,8,0,0,19,54,55,51,17,35,17,6,7,49,67,50,64,78,50,53,2,68,9,42,253,137,2,25,32,3,0,1,0,64,0,0,2,1,2,128,0,28,0,0,55,33,21,33,53,52,55,54,55,55,54,53,52,38,34,6,7,35,54,54,50,22,20,6,7,7,6,6,21,143,1,109,254,68,84,27,33,124,96,66,119,75,6,87,5,122,191,120,79,69,127,48,47,73,73,93,111,52,17,13,50,38,87,48,61,50,50,82,88,104,153,90,27,51,20,51,41,0,0,1,0,52,255,245,2,17,2,128,0,33,0,0,1,20,7,22,22,21,20,6,34,38,53,51,22,22,50,54,52,38,35,35,53,51,50,54,52,38,34,6,7,35,54,54,50,22,1,249,110,60,74,126,206,145,82,2,91,140,77,74,83,72,49,72,84,68,112,75,13,82,11,116,183,125,1,212,100,39,17,78,61,83,101,107,97,64,68,67,99,63,63,57,96,62,39,53,83,81,97,0,0,2,0,26,0,0,2,25,2,126,0,10,0,13,0,0,1,17,51,21,35,21,35,53,33,53,1,3,51,17,1,172,109,109,77,254,187,1,73,235,233,2,126,254,94,68,152,152,61,1,169,254,87,1,44,0,0,1,0,65,255,245,1,253,2,117,0,24,0,0,37,52,35,35,19,33,21,33,7,54,51,50,22,20,6,34,38,53,51,20,23,22,51,50,54,1,171,155,169,27,1,93,254,239,17,52,47,103,118,124,196,124,79,84,26,31,64,78,204,119,1,50,72,181,9,91,184,121,99,87,82,25,7,81,0,2,0,51,255,244,2,3,2,128,0,21,0,30,0,0,1,38,34,6,21,20,23,54,54,50,22,20,6,35,34,38,16,54,51,50,22,23,4,6,20,22,50,54,53,52,38,1,169,17,180,97,5,6,101,158,114,118,96,112,138,140,121,84,106,8,254,247,75,74,114,75,75,1,214,98,148,128,53,35,92,83,111,173,107,180,1,37,179,94,76,161,71,110,67,66,58,58,66,0,0,1,0,24,0,0,1,196,2,117,0,6,0,0,1,21,1,35,1,33,53,1,196,254,224,106,1,46,254,176,2,117,73,253,212,2,41,76,0,3,0,55,255,245,2,49,2,128,0,21,0,31,0,42,0,0,19,38,53,52,54,50,22,21,20,6,7,23,22,22,21,20,6,34,38,53,52,54,23,6,6,20,22,50,54,52,38,39,39,20,22,23,23,54,54,52,38,34,6,201,125,124,205,132,69,67,17,69,74,135,229,142,81,140,63,76,96,155,91,48,42,230,44,41,73,60,78,82,130,84,1,62,57,98,75,92,98,77,52,82,10,6,26,71,61,76,92,102,77,62,78,19,7,65,96,60,52,74,45,15,216,27,39,16,28,2,59,95,59,57,0,2,0,66,255,245,2,18,2,128,0,28,0,37,0,0,1,50,22,23,22,21,20,7,6,35,34,38,53,51,22,22,50,55,54,53,52,39,6,6,34,38,53,52,54,22,34,6,21,20,22,50,54,52,1,26,51,92,33,72,136,47,55,103,120,83,2,68,104,32,91,5,10,97,157,114,118,152,114,74,75,113,75,2,128,44,41,88,141,245,69,23,112,85,57,68,19,57,200,41,33,81,80,111,86,87,106,73,66,58,58,66,71,110,0,2,0,56,0,23,0,174,1,186,0,7,0,15,0,0,54,38,52,54,50,22,20,6,2,38,52,54,50,22,20,6,89,33,33,51,34,34,51,33,33,51,34,34,23,33,47,33,33,47,33,1,50,33,47,33,33,47,33,0,0,2,0,57,255,147,0,205,1,186,0,11,0,19,0,0,22,38,52,54,50,22,20,6,7,39,54,55,2,38,52,54,50,22,20,6,109,30,31,57,38,44,45,59,62,13,17,33,33,51,34,34,3,26,44,30,45,68,71,22,29,30,45,1,78,33,47,33,33,47,33,0,0,1,0,40,0,40,1,152,2,60,0,6,0,0,1,5,5,7,37,53,37,1,152,254,224,1,32,52,254,196,1,60,2,0,207,204,61,231,69,232,0,2,0,79,0,117,1,153,1,121,0,3,0,7,0,0,37,21,33,53,37,21,33,53,1,153,254,182,1,74,254,182,185,68,68,192,69,69,0,1,0,47,0,40,1,158,2,60,0,6,0,0,19,5,21,5,39,37,37,98,1,60,254,196,51,1,30,254,226,2,60,232,69,231,61,204,207,0,0,2,0,30,255,245,1,197,2,128,0,25,0,35,0,0,19,34,7,35,54,54,50,22,21,20,6,7,6,6,7,6,21,21,35,53,52,62,2,52,38,3,50,22,20,6,35,34,38,52,54,248,117,17,84,7,108,195,113,52,58,25,34,10,19,78,42,110,38,63,87,26,34,34,26,26,32,32,2,56,92,74,90,96,69,52,69,32,14,22,14,25,47,39,45,63,67,60,45,76,51,254,46,34,47,32,32,47,34,0,0,2,0,67,255,75,3,126,2,128,0,10,0,61,0,0,1,52,35,34,6,21,20,22,50,54,55,23,20,51,50,54,55,54,53,52,38,35,34,6,7,6,16,22,51,21,34,39,38,38,52,62,2,50,30,2,21,20,6,35,34,38,39,39,6,6,35,34,38,53,52,54,51,50,22,21,2,63,59,59,94,55,82,52,23,66,39,20,47,19,46,162,139,82,134,47,100,212,185,213,134,63,68,66,118,163,182,142,100,56,129,86,43,52,5,3,18,60,40,74,95,132,91,60,69,1,33,84,97,74,53,58,47,45,45,51,27,26,61,95,119,154,56,47,100,254,214,185,64,115,54,149,178,152,111,62,54,93,126,67,122,150,36,34,16,38,48,98,75,99,135,72,73,0,0,2,0,26,0,0,2,37,2,117,0,7,0,10,0,0,19,51,19,35,39,35,7,35,55,51,3,242,96,211,82,54,250,54,83,158,209,104,2,117,253,139,160,160,222,1,54,0,0,3,0,101,0,0,2,41,2,117,0,15,0,24,0,32,0,0,19,51,50,22,21,20,6,7,22,22,21,20,7,6,35,35,55,50,54,53,52,38,35,35,21,17,51,50,54,52,38,35,35,101,235,99,107,59,60,59,71,113,42,61,236,234,72,62,68,66,155,154,58,69,67,60,154,2,117,94,71,54,80,14,10,82,52,116,41,15,69,58,48,48,57,211,1,23,57,100,56,0,0,1,0,51,255,245,2,54,2,128,0,22,0,0,1,50,22,23,7,38,38,35,34,6,20,22,51,50,54,53,51,20,6,34,38,16,54,1,63,101,123,23,85,20,85,57,79,104,93,90,75,87,85,135,235,145,150,2,128,101,81,17,59,69,132,235,142,79,65,99,116,180,1,46,169,0,0,2,0,100,0,0,2,86,2,117,0,7,0,16,0,0,1,50,22,16,6,35,35,17,19,51,50,54,53,52,38,35,35,1,29,142,171,171,142,185,79,106,105,124,125,104,106,2,117,171,254,225,171,2,117,253,208,139,107,107,137,0,0,1,0,100,0,0,1,231,2,117,0,11,0,0,19,33,21,33,21,33,21,33,21,33,21,33,100,1,131,254,204,1,34,254,222,1,52,254,125,2,117,68,211,67,214,69,0,1,0,101,0,0,1,227,2,117,0,9,0,0,19,33,21,33,21,33,21,33,17,35,101,1,126,254,209,1,26,254,230,79,2,117,68,209,68,254,228,0,0,1,0,51,255,245,2,59,2,127,0,25,0,0,37,6,34,38,16,54,51,50,22,23,7,38,34,6,20,22,51,50,54,53,53,39,53,51,17,35,1,234,42,242,155,169,126,74,111,40,76,65,174,121,104,88,72,88,158,235,64,108,119,176,1,42,176,60,66,26,81,142,227,138,96,94,2,6,52,254,201,0,0,1,0,101,0,0,2,56,2,117,0,11,0,0,19,17,33,17,51,17,35,17,33,17,35,17,180,1,53,79,79,254,203,79,2,117,254,235,1,21,253,139,1,28,254,228,2,117,0,1,0,101,0,0,0,180,2,117,0,3,0,0,19,51,17,35,101,79,79,2,117,253,139,0,0,1,0,8,255,245,1,68,2,117,0,11,0,0,36,6,34,39,53,22,50,54,53,17,51,17,1,68,93,144,79,70,123,44,79,79,90,42,82,48,60,57,1,191,254,65,0,1,0,101,0,0,2,76,2,117,0,11,0,0,19,17,1,51,1,1,35,3,7,21,35,17,181,1,25,109,254,237,1,36,102,243,62,80,2,117,254,221,1,35,254,229,254,166,1,35,64,227,2,117,0,1,0,101,0,0,1,204,2,117,0,5,0,0,55,33,21,33,17,51,180,1,24,254,153,79,69,69,2,117,0,1,0,101,0,0,2,235,2,117,0,12,0,0,27,2,51,17,35,17,3,35,3,17,35,17,214,212,210,111,79,216,53,219,79,2,117,254,86,1,170,253,139,2,5,254,74,1,189,253,244,2,117,0,0,1,0,99,0,0,2,72,2,117,0,9,0,0,19,1,17,51,17,35,1,17,35,17,193,1,56,79,88,254,195,80,2,117,254,7,1,249,253,139,2,0,254,0,2,117,0,2,0,51,255,245,2,84,2,128,0,10,0,20,0,0,1,50,22,16,6,35,34,38,53,52,54,23,34,6,20,22,51,50,54,52,38,1,67,122,151,150,123,123,149,149,123,88,102,102,88,88,103,103,2,128,167,254,193,165,167,158,159,167,71,132,248,128,128,248,132,0,0,2,0,99,0,0,2,3,2,117,0,9,0,17,0,0,0,22,20,6,35,35,21,35,17,51,17,50,54,52,38,35,35,21,1,150,109,109,104,124,79,203,65,67,67,65,124,2,117,105,178,103,243,2,117,254,194,66,115,69,250,0,0,2,0,51,255,89,2,84,2,128,0,21,0,31,0,0,5,6,35,34,39,39,38,38,16,54,51,50,22,21,20,6,7,23,22,23,50,55,1,34,6,20,22,51,50,54,52,38,2,84,40,44,85,61,47,121,147,149,123,122,151,106,91,31,29,40,43,54,254,239,88,102,102,88,88,103,103,148,19,89,67,2,166,1,60,167,167,159,132,161,23,44,39,2,25,2,119,132,248,128,128,248,132,0,0,2,0,101,0,0,2,43,2,117,0,12,0,20,0,0,0,6,7,19,35,3,35,17,35,17,51,50,22,7,50,54,52,38,35,35,21,2,27,83,81,180,102,163,110,79,219,106,113,225,71,73,71,67,140,1,115,96,14,254,251,1,1,254,255,2,117,102,215,69,113,67,249,0,0,1,0,69,255,245,2,24,2,128,0,31,0,0,1,38,35,34,6,20,22,23,23,22,22,20,6,34,38,39,51,20,22,50,54,52,38,39,39,38,38,52,54,50,22,23,1,180,17,118,63,68,42,47,131,67,79,124,208,133,2,77,87,137,80,49,48,111,78,80,112,202,107,8,1,220,92,55,77,40,15,45,23,80,145,99,105,95,62,66,61,83,48,16,41,26,72,139,93,89,75,0,0,1,0,6,0,0,1,239,2,117,0,7,0,0,19,33,21,35,17,35,17,35,6,1,233,205,79,205,2,117,68,253,207,2,49,0,0,1,0,87,255,245,2,53,2,117,0,16,0,0,19,17,20,22,51,50,54,53,17,51,17,20,6,34,38,53,17,166,88,72,72,88,79,130,219,129,2,117,254,110,88,78,78,88,1,146,254,110,118,120,120,118,1,146,0,1,0,18,0,0,2,33,2,117,0,6,0,0,27,2,51,3,35,3,101,180,181,83,223,82,222,2,117,253,239,2,17,253,139,2,117,0,0,1,0,14,0,0,3,112,2,117,0,12,0,0,27,2,51,19,19,51,3,35,3,3,35,3,102,153,155,53,154,176,87,222,83,137,142,83,199,2,117,253,245,1,202,254,54,2,11,253,139,1,147,254,109,2,117,0,0,1,0,47,0,0,2,81,2,117,0,11,0,0,33,35,39,7,35,19,3,51,19,19,51,3,2,81,98,182,169,96,222,223,95,180,166,95,217,251,251,1,56,1,61,254,255,1,1,254,196,0,0,1,0,10,0,0,2,27,2,117,0,8,0,0,27,2,51,3,17,35,17,3,104,169,173,93,226,80,223,2,117,254,223,1,33,254,141,254,254,1,2,1,115,0,0,1,0,73,0,0,2,23,2,117,0,9,0,0,55,1,37,53,33,21,1,5,21,33,73,1,107,254,149,1,206,254,149,1,107,254,50,71,1,227,3,72,71,254,29,3,72,0,0,1,0,101,255,154,1,43,2,219,0,7,0,0,19,51,21,35,17,51,21,35,101,198,119,119,198,2,219,70,253,75,70,0,0,1,0,45,255,183,1,120,2,219,0,3,0,0,19,51,19,35,45,79,252,80,2,219,252,220,0,1,255,242,255,154,0,184,2,219,0,7,0,0,23,35,53,51,17,35,53,51,184,198,119,119,198,102,70,2,181,70,0,1,0,21,0,245,1,178,2,74,0,6,0,0,55,19,51,19,35,39,7,21,176,61,176,88,119,117,245,1,85,254,171,246,246,0,0,1,0,55,255,132,2,159,255,200,0,3,0,0,23,33,21,33,55,2,104,253,152,56,68,0,0,1,0,24,2,165,1,36,3,92,0,3,0,0,19,23,7,39,57,235,23,245,3,92,133,50,113,0,0,2,0,70,255,245,1,219,1,234,0,24,0,33,0,0,1,52,38,34,6,21,35,52,55,54,51,50,22,21,17,35,39,6,35,34,38,52,54,50,23,21,38,34,6,21,20,51,50,54,1,141,54,103,63,87,118,36,42,89,100,68,8,44,115,77,93,103,154,70,71,106,66,102,58,83,1,54,65,56,41,44,110,26,8,90,92,254,204,80,91,86,128,72,26,50,20,38,41,90,83,0,0,2,0,101,255,245,2,22,2,169,0,13,0,23,0,0,19,54,50,22,20,6,35,34,38,39,7,35,17,51,18,6,7,21,20,22,50,54,52,38,180,48,184,122,124,89,48,77,22,18,55,79,78,76,2,79,112,82,81,1,151,83,137,225,139,48,47,84,2,169,254,251,73,65,78,66,79,99,164,98,0,1,0,50,255,245,1,205,1,234,0,21,0,0,0,22,23,7,38,38,35,34,6,20,22,50,54,53,51,20,6,35,34,38,52,54,1,89,100,15,80,13,58,35,64,79,77,115,57,81,107,86,91,127,126,1,234,87,65,7,42,47,96,165,100,53,49,77,95,138,229,134,0,2,0,60,255,245,1,236,2,169,0,13,0,23,0,0,1,17,51,17,35,39,6,6,35,34,38,52,54,50,6,6,20,22,50,54,55,53,52,38,1,158,78,64,10,23,76,45,91,123,121,185,146,79,80,112,79,2,78,1,151,1,18,253,87,80,45,46,140,225,136,70,98,164,99,75,63,78,67,78,0,2,0,50,255,245,1,215,1,234,0,16,0,24,0,0,37,50,55,51,6,6,35,34,38,52,54,50,22,7,33,20,22,19,38,35,34,6,7,51,52,1,10,99,14,81,11,105,78,96,120,121,201,99,15,254,185,72,123,23,33,61,71,6,255,53,87,72,79,137,228,136,156,112,74,95,1,106,12,83,62,100,0,1,0,49,0,0,1,91,2,177,0,20,0,0,1,38,35,34,6,21,21,51,21,35,17,35,17,35,53,51,53,52,54,50,23,1,77,33,19,35,40,99,99,78,79,79,78,102,39,2,102,13,34,43,72,54,254,88,1,168,54,73,71,67,13,0,0,3,0,28,255,10,2,37,2,59,0,40,0,52,0,62,0,0,55,38,53,52,54,55,38,53,52,54,50,23,54,54,51,7,34,7,22,21,20,6,35,34,39,6,6,21,20,51,51,50,22,21,20,6,34,38,53,52,54,23,20,22,50,54,53,52,38,35,35,6,6,0,38,34,6,21,20,22,51,50,54,121,60,47,35,54,111,152,53,7,71,58,7,88,4,35,111,83,57,44,20,32,88,186,67,78,153,234,134,51,27,83,169,113,33,34,193,51,54,1,38,62,109,62,63,54,54,62,15,29,60,31,47,8,48,78,78,96,36,53,64,78,74,43,60,77,99,23,4,29,25,53,57,51,76,114,87,66,43,54,94,38,55,73,49,23,33,2,45,1,164,65,65,52,52,67,68,0,0,1,0,101,0,0,2,7,2,169,0,17,0,0,19,54,51,50,22,21,17,35,17,52,38,34,6,21,21,35,17,51,180,48,111,85,95,78,65,122,74,79,79,1,134,100,112,97,254,231,1,25,69,70,103,91,226,2,169,0,0,2,0,94,0,0,0,198,2,178,0,3,0,11,0,0,19,51,17,35,18,38,52,54,50,22,20,6,106,79,79,15,27,27,48,29,29,1,223,254,33,2,79,27,45,27,27,45,27,0,0,2,255,170,255,10,0,213,2,178,0,9,0,23,0,0,18,38,52,54,51,50,22,20,6,35,3,50,53,17,51,17,20,7,6,35,34,39,55,22,136,27,27,24,24,29,29,24,127,88,79,90,28,34,62,72,4,63,2,79,27,45,27,27,45,27,253,0,110,2,35,253,221,137,32,10,37,69,37,0,0,1,0,101,0,0,2,20,2,169,0,11,0,0,55,7,21,35,17,51,17,55,51,7,19,35,244,64,79,79,231,110,220,231,97,253,52,201,2,169,254,116,193,179,254,213,0,1,0,101,0,0,0,180,2,169,0,3,0,0,19,51,17,35,101,79,79,2,169,253,87,0,0,1,0,100,0,0,3,82,1,234,0,30,0,0,19,54,51,50,22,23,54,51,50,22,21,17,35,17,52,38,34,6,21,21,35,17,52,38,34,6,7,21,35,17,51,177,47,114,62,84,19,45,122,86,94,78,65,122,67,78,65,120,74,2,79,68,1,130,104,61,54,115,112,97,254,231,1,25,69,70,100,88,232,1,25,69,70,98,87,235,1,222,0,1,0,100,0,0,2,6,1,234,0,17,0,0,19,54,51,50,22,21,17,35,17,52,38,34,6,7,21,35,17,51,177,47,114,85,95,78,65,120,74,2,79,68,1,130,104,112,97,254,231,1,25,69,70,98,87,235,1,222,0,2,0,50,255,245,1,240,1,234,0,11,0,19,0,0,1,50,22,21,20,6,35,34,38,53,52,54,22,38,34,6,20,22,50,54,1,17,100,123,123,100,100,123,123,243,72,139,74,70,139,76,1,234,130,121,120,130,130,120,121,130,165,97,97,171,97,97,0,2,0,101,255,21,2,22,1,234,0,11,0,21,0,0,19,54,50,22,20,6,34,39,17,35,17,51,18,54,52,38,34,6,7,21,20,22,175,47,187,125,126,184,44,79,65,202,85,81,116,74,2,76,1,149,85,138,226,137,69,254,219,2,201,254,93,96,167,98,73,62,91,63,72,0,0,2,0,51,255,10,2,44,1,234,0,19,0,31,0,0,1,50,23,55,51,17,20,22,22,23,7,38,38,53,53,6,34,38,52,54,22,6,20,22,51,50,55,54,55,53,52,38,1,8,102,46,17,54,23,29,21,26,68,57,41,187,126,125,37,81,86,57,82,35,12,1,76,1,234,90,78,253,209,49,33,15,7,61,18,78,74,152,87,137,226,138,70,98,167,96,73,23,32,91,66,76,0,1,0,100,0,0,1,105,1,231,0,13,0,0,1,34,7,21,35,17,51,21,54,51,50,23,7,38,1,40,113,4,79,79,36,91,29,26,4,30,1,155,178,233,1,223,92,100,9,77,10,0,0,1,0,60,255,245,1,209,1,234,0,31,0,0,18,54,50,22,23,35,38,35,34,6,20,22,23,23,22,22,20,6,34,38,39,51,22,22,50,54,52,38,39,39,38,53,76,101,172,97,2,77,9,101,49,53,40,44,96,61,65,106,190,106,3,76,2,69,104,68,40,45,93,125,1,164,70,72,55,65,44,51,35,13,32,19,59,103,83,85,67,45,45,44,61,32,12,31,37,93,0,1,0,34,255,230,1,95,2,99,0,21,0,0,37,6,39,38,39,38,53,17,35,53,51,53,51,21,51,21,35,17,20,51,50,55,1,95,86,71,51,21,11,77,77,78,150,150,68,37,46,14,40,23,16,51,25,35,1,38,60,133,133,60,254,219,73,18,0,1,0,87,255,247,1,249,1,223,0,17,0,0,37,6,35,34,38,53,17,51,17,20,51,50,54,55,53,51,17,35,1,170,49,110,81,99,79,112,65,81,2,79,79,95,104,90,94,1,48,254,214,121,100,78,241,254,33,0,0,1,0,18,0,0,1,229,1,222,0,6,0,0,27,2,51,3,35,3,107,144,145,89,190,87,190,1,222,254,117,1,139,254,34,1,222,0,0,1,0,18,0,0,2,192,1,222,0,12,0,0,27,2,51,19,19,51,3,35,3,3,35,3,100,116,114,66,113,117,78,156,77,110,108,76,159,1,222,254,131,1,102,254,150,1,129,254,34,1,79,254,177,1,222,0,0,1,0,26,0,0,1,230,1,223,0,11,0,0,33,35,39,7,35,55,39,51,23,55,51,7,1,229,96,137,130,96,181,181,96,137,131,96,183,181,181,239,240,180,180,240,0,1,0,5,255,10,1,203,1,222,0,17,0,0,23,22,51,50,55,54,55,55,3,51,19,19,51,3,6,6,34,39,5,49,54,40,29,21,17,14,196,88,145,113,80,179,23,75,115,62,139,38,40,29,59,49,1,222,254,131,1,125,253,195,73,78,35,0,0,1,0,53,0,0,1,167,1,222,0,9,0,0,55,1,33,53,33,21,1,33,21,33,53,1,25,254,231,1,114,254,235,1,21,254,142,64,1,94,64,64,254,162,64,0,0,1,0,75,255,118,1,85,2,236,0,31,0,0,19,22,21,21,20,22,51,21,34,53,53,52,38,35,35,53,51,50,54,53,53,52,55,54,51,21,34,6,21,21,20,7,154,52,61,74,213,17,19,17,17,19,17,114,40,59,74,61,52,1,47,25,88,93,81,85,69,234,92,43,36,76,35,44,91,168,49,18,69,85,82,92,86,27,0,1,0,101,255,134,0,180,2,238,0,3,0,0,19,51,17,35,101,79,79,2,238,252,152,0,0,1,0,8,255,118,1,18,2,236,0,31,0,0,19,38,53,53,52,38,35,53,50,21,21,20,22,51,51,21,35,34,6,21,21,20,7,6,35,53,50,54,53,53,52,55,195,52,61,74,213,17,19,17,17,19,17,114,41,58,74,61,52,1,51,27,86,92,82,85,69,235,91,44,35,76,36,43,92,168,48,18,69,85,81,93,88,25,0,1,0,53,0,223,1,206,1,103,0,17,0,0,19,34,7,39,54,51,50,22,51,50,55,23,6,35,34,38,39,38,158,37,24,44,33,74,34,134,26,40,25,43,35,78,23,96,14,39,1,26,59,23,111,55,57,27,106,36,6,14,0,1,0,20,0,0,2,17,2,128,0,37,0,0,1,38,35,34,6,21,21,51,21,35,21,20,7,51,50,54,55,51,6,6,35,33,53,51,50,54,53,53,35,53,51,53,52,54,51,50,22,23,1,144,16,86,42,57,182,182,37,183,49,45,6,84,6,84,94,254,187,28,38,35,91,91,93,91,71,90,11,1,234,78,64,72,109,56,104,68,26,41,44,77,77,69,44,46,108,56,109,99,109,76,74,0,0,2,0,24,3,11,1,42,3,111,0,9,0,17,0,0,18,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,53,29,29,23,23,31,31,23,146,30,30,45,31,31,3,11,29,42,29,29,42,29,29,42,29,29,42,29,0,1,0,23,2,165,1,34,3,92,0,3,0,0,1,7,39,55,1,34,244,23,235,3,22,113,50,133,0,3,0,26,0,0,2,37,3,92,0,7,0,10,0,14,0,0,19,51,19,35,39,35,7,35,55,51,3,3,23,7,39,242,96,211,82,54,250,54,83,158,209,104,99,235,23,245,2,117,253,139,160,160,222,1,54,1,72,133,50,113,0,3,0,26,0,0,2,37,3,92,0,7,0,10,0,14,0,0,19,51,19,35,39,35,7,35,55,51,3,19,7,39,55,242,96,211,82,54,250,54,83,158,209,104,134,244,23,235,2,117,253,139,160,160,222,1,54,1,2,113,50,133,0,3,0,26,0,0,2,37,3,104,0,7,0,10,0,16,0,0,19,51,19,35,39,35,7,35,55,51,3,55,7,39,7,39,55,242,96,211,82,54,250,54,83,158,209,104,180,50,129,130,50,180,2,117,253,139,160,160,222,1,54,184,39,108,108,39,156,0,0,3,0,26,0,0,2,37,3,74,0,7,0,10,0,30,0,0,19,51,19,35,39,35,7,35,55,51,3,39,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,242,96,211,82,54,250,54,83,158,209,104,68,32,25,32,12,46,52,34,46,27,26,28,10,35,11,49,41,34,60,21,2,117,253,139,160,160,222,1,54,238,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,4,0,26,0,0,2,37,3,67,0,7,0,10,0,20,0,28,0,0,19,51,19,35,39,35,7,35,55,51,3,38,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,242,96,211,82,54,250,54,83,158,209,104,86,29,29,23,23,31,31,23,146,30,30,45,31,31,2,117,253,139,160,160,222,1,54,203,29,42,29,29,42,29,29,42,29,29,42,29,0,2,0,100,0,0,1,231,3,92,0,11,0,15,0,0,19,33,21,33,21,33,21,33,21,33,21,33,19,23,7,39,100,1,131,254,204,1,34,254,222,1,52,254,125,94,235,23,245,2,117,68,211,67,214,69,3,92,133,50,113,0,0,2,0,100,0,0,1,231,3,92,0,11,0,15,0,0,51,33,53,33,53,33,53,33,53,33,53,33,37,7,39,55,100,1,131,254,204,1,34,254,222,1,52,254,125,1,71,244,23,235,69,214,67,211,68,161,113,50,133,0,0,2,0,105,0,0,1,236,3,104,0,11,0,17,0,0,19,33,21,33,21,33,21,33,21,33,21,33,1,7,39,7,39,55,105,1,131,254,204,1,34,254,222,1,52,254,125,1,118,50,129,130,50,180,2,117,68,211,67,214,69,2,204,39,108,108,39,156,0,3,0,100,0,0,1,231,3,67,0,11,0,21,0,29,0,0,19,33,21,33,21,33,21,33,21,33,21,33,18,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,100,1,131,254,204,1,34,254,222,1,52,254,125,87,29,29,23,23,31,31,23,146,30,30,45,31,31,2,117,68,211,67,214,69,2,223,29,42,29,29,42,29,29,42,29,29,42,29,0,2,0,7,0,0,1,19,3,92,0,3,0,7,0,0,19,51,17,35,3,23,7,39,101,79,79,61,235,23,245,2,117,253,139,3,92,133,50,113,0,2,0,6,0,0,1,17,3,92,0,3,0,7,0,0,51,51,17,35,55,7,39,55,101,79,79,172,244,23,235,2,117,161,113,50,133,0,0,2,255,217,0,0,1,64,3,104,0,3,0,9,0,0,19,51,17,35,19,7,39,7,39,55,101,79,79,219,50,129,130,50,180,2,117,253,139,2,204,39,108,108,39,156,0,3,0,4,0,0,1,22,3,67,0,3,0,13,0,21,0,0,19,51,17,35,2,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,101,79,79,68,29,29,23,23,31,31,23,146,30,30,45,31,31,2,117,253,139,2,223,29,42,29,29,42,29,29,42,29,29,42,29,0,0,2,0,99,0,0,2,72,3,74,0,9,0,29,0,0,19,17,51,17,1,51,17,35,17,1,55,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,99,80,1,61,88,79,254,200,81,32,25,32,12,46,52,33,47,27,26,28,10,35,11,49,41,34,60,21,2,117,253,139,2,0,254,0,2,117,254,7,1,249,141,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,0,3,0,51,255,245,2,84,3,92,0,10,0,20,0,24,0,0,1,50,22,16,6,35,34,38,53,52,54,23,34,6,20,22,51,50,54,52,38,3,23,7,39,1,67,122,151,150,123,123,149,149,123,88,102,102,88,88,103,103,188,235,23,245,2,128,167,254,193,165,167,158,159,167,71,132,248,128,128,248,132,1,35,133,50,113,0,3,0,51,255,245,2,84,3,92,0,10,0,20,0,24,0,0,1,34,6,21,20,22,51,50,54,16,38,7,50,22,20,6,35,34,38,52,54,55,7,39,55,1,67,123,149,149,123,123,150,151,122,88,103,103,88,88,102,102,221,244,23,235,2,128,167,159,158,167,165,1,63,167,71,132,248,128,128,248,132,221,113,50,133,0,0,3,0,51,255,245,2,84,3,104,0,10,0,20,0,26,0,0,1,50,22,16,6,35,34,38,53,52,54,23,34,6,20,22,51,50,54,52,38,55,7,39,7,39,55,1,67,122,151,150,123,123,149,149,123,88,102,102,88,88,103,103,91,50,129,130,50,180,2,128,167,254,193,165,167,158,159,167,71,132,248,128,128,248,132,147,39,108,108,39,156,0,0,3,0,51,255,245,2,84,3,74,0,10,0,20,0,40,0,0,1,34,6,21,20,22,51,50,54,16,38,7,50,22,20,6,35,34,38,52,54,55,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,1,67,123,149,149,123,123,150,151,122,88,103,103,88,88,102,102,19,32,25,32,12,46,52,33,47,27,26,28,10,35,11,49,41,34,60,21,2,128,167,159,158,167,165,1,63,167,71,132,248,128,128,248,132,201,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,4,0,51,255,245,2,84,3,67,0,10,0,20,0,30,0,38,0,0,1,50,22,16,6,35,34,38,53,52,54,23,34,6,20,22,51,50,54,52,46,2,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,1,67,122,151,150,123,123,149,149,123,88,102,102,88,88,103,103,196,29,29,23,23,31,31,23,146,30,30,45,31,31,2,128,167,254,193,165,167,158,159,167,71,132,248,128,128,248,132,166,29,42,29,29,42,29,29,42,29,29,42,29,0,0,2,0,87,255,245,2,53,3,92,0,16,0,20,0,0,19,17,20,22,51,50,54,53,17,51,17,20,6,34,38,53,17,55,23,7,39,166,88,72,72,88,79,130,219,129,139,235,23,245,2,117,254,110,88,78,78,88,1,146,254,110,118,120,120,118,1,146,231,133,50,113,0,2,0,87,255,245,2,53,3,92,0,16,0,20,0,0,19,17,20,22,50,54,53,17,35,17,20,6,35,34,38,53,17,37,7,39,55,87,129,219,130,79,88,72,72,88,1,37,244,23,235,2,117,254,110,118,120,120,118,1,146,254,110,88,78,78,88,1,146,161,113,50,133,0,0,2,0,87,255,245,2,53,3,104,0,16,0,22,0,0,19,17,20,22,51,50,54,53,17,51,17,20,6,34,38,53,17,37,7,39,7,39,55,166,88,72,72,88,79,130,219,129,1,162,50,129,130,50,180,2,117,254,110,88,78,78,88,1,146,254,110,118,120,120,118,1,146,87,39,108,108,39,156,0,0,3,0,87,255,245,2,53,3,67,0,16,0,26,0,34,0,0,19,17,20,22,51,50,54,53,17,51,17,20,6,34,38,53,17,54,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,166,88,72,72,88,79,130,219,129,131,29,29,23,23,31,31,23,146,30,30,45,31,31,2,117,254,110,88,78,78,88,1,146,254,110,118,120,120,118,1,146,106,29,42,29,29,42,29,29,42,29,29,42,29,0,0,3,0,60,255,245,1,209,2,219,0,24,0,33,0,37,0,0,1,52,38,34,6,21,35,52,55,54,51,50,22,21,17,35,39,6,35,34,38,52,54,50,23,21,38,34,6,21,20,51,50,54,3,23,7,39,1,131,54,103,63,87,118,36,42,89,100,68,8,44,115,77,93,103,154,70,71,106,66,102,58,83,205,235,23,245,1,54,65,56,41,44,110,26,8,90,92,254,204,80,91,86,128,72,26,50,20,38,41,90,83,2,86,133,50,113,0,3,0,60,255,245,1,209,2,219,0,24,0,34,0,38,0,0,1,52,38,34,6,21,35,52,55,54,51,50,22,21,17,35,39,6,35,34,38,52,54,50,23,21,38,34,6,21,20,51,50,54,55,19,7,39,55,1,131,54,103,63,87,118,36,42,89,100,68,8,44,115,77,93,103,154,70,71,106,66,102,57,82,2,28,244,23,235,1,54,65,56,41,44,110,26,8,90,92,254,204,80,91,86,128,72,26,50,20,38,41,90,80,63,1,212,113,50,133,0,0,3,0,60,255,245,1,209,2,231,0,24,0,33,0,39,0,0,1,52,38,34,6,21,35,52,55,54,51,50,22,21,17,35,39,6,35,34,38,52,54,50,23,21,38,34,6,21,20,51,50,54,19,7,39,7,39,55,1,131,54,103,63,87,118,36,42,89,100,68,8,44,115,77,93,103,154,70,71,106,66,102,58,83,74,50,129,130,50,180,1,54,65,56,41,44,110,26,8,90,92,254,204,80,91,86,128,72,26,50,20,38,41,90,83,1,198,39,108,108,39,156,0,3,0,60,255,245,1,209,2,201,0,24,0,34,0,54,0,0,1,52,38,34,6,21,35,52,55,54,51,50,22,21,17,35,39,6,35,34,38,52,54,50,23,21,38,34,6,21,20,51,50,54,55,3,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,1,131,54,103,63,87,118,36,42,89,100,68,8,44,115,77,93,103,154,70,71,106,66,102,57,82,2,174,32,25,32,12,46,52,34,46,27,26,28,10,35,11,49,41,34,60,21,1,54,65,56,41,44,110,26,8,90,92,254,204,80,91,86,128,72,26,50,20,38,41,90,80,63,1,192,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,4,0,60,255,245,1,209,2,193,0,24,0,33,0,43,0,51,0,0,1,52,38,34,6,21,35,52,55,54,51,50,22,21,17,35,39,6,35,34,38,52,54,50,23,21,38,34,6,21,20,51,50,54,2,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,1,131,54,103,63,87,118,36,42,89,100,68,8,44,115,77,93,103,154,70,71,106,66,102,58,83,213,29,29,23,23,31,31,23,146,30,30,45,31,31,1,54,65,56,41,44,110,26,8,90,92,254,204,80,91,86,128,72,26,50,20,38,41,90,83,1,216,29,42,29,29,42,29,29,42,29,29,42,29,0,0,3,0,51,255,245,1,216,2,224,0,16,0,24,0,28,0,0,37,50,55,51,6,6,35,34,38,52,54,50,22,7,33,20,22,19,38,35,34,6,7,51,52,3,23,7,39,1,11,99,14,81,11,105,78,96,120,121,201,99,15,254,185,72,122,22,32,62,71,6,255,227,235,23,245,53,87,72,79,137,228,136,156,112,74,95,1,106,12,83,62,100,1,98,133,50,113,0,0,3,0,51,255,245,1,216,2,224,0,16,0,22,0,26,0,0,37,6,35,34,38,53,33,54,38,34,6,20,22,51,50,54,55,2,22,21,35,54,54,55,7,39,55,1,124,14,99,65,72,1,71,15,99,201,121,120,96,78,105,11,130,55,255,6,71,184,244,23,235,140,87,95,74,112,156,136,228,137,79,72,1,31,83,62,62,83,239,113,50,133,0,3,0,54,255,245,1,219,2,236,0,16,0,24,0,30,0,0,37,50,55,51,6,6,35,34,38,52,54,50,22,7,33,20,22,19,38,35,34,6,7,51,52,55,7,39,7,39,55,1,14,99,14,81,11,105,78,96,120,121,201,99,15,254,185,72,123,23,33,61,71,6,255,53,50,129,130,50,180,53,87,72,79,137,228,136,156,112,74,95,1,106,12,83,62,100,210,39,108,108,39,156,0,4,0,51,255,245,1,216,2,193,0,16,0,24,0,34,0,42,0,0,37,50,55,51,6,6,35,34,38,52,54,50,22,7,33,20,22,19,38,35,34,6,7,51,52,38,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,1,11,99,14,81,11,105,78,96,120,121,201,99,15,254,185,72,122,22,32,62,71,6,255,234,29,29,23,23,31,31,23,146,30,30,45,31,31,53,87,72,79,137,228,136,156,112,74,95,1,106,12,83,62,100,223,29,42,29,29,42,29,29,42,29,29,42,29,0,0,2,0,12,0,0,1,24,2,219,0,3,0,7,0,0,19,51,17,35,3,23,7,39,106,79,79,61,235,23,245,1,223,254,33,2,219,133,50,113,0,2,0,11,0,0,1,22,2,219,0,3,0,7,0,0,51,51,17,35,55,7,39,55,106,79,79,172,244,23,235,1,223,182,113,50,133,0,0,2,255,222,0,0,1,69,2,231,0,3,0,9,0,0,19,51,17,35,19,7,39,7,39,55,106,79,79,219,50,129,130,50,180,1,223,254,33,2,75,39,108,108,39,156,0,3,0,9,0,0,1,27,2,193,0,3,0,13,0,21,0,0,19,51,17,35,2,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,106,79,79,68,29,29,23,23,31,31,23,146,30,30,45,31,31,1,223,254,33,2,93,29,42,29,29,42,29,29,42,29,29,42,29,0,0,2,0,101,0,0,2,7,2,201,0,17,0,37,0,0,1,34,7,39,35,17,51,53,54,54,50,22,21,17,51,17,52,38,39,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,1,83,114,47,9,68,79,2,74,120,65,78,95,187,32,25,32,12,46,52,34,46,27,26,28,10,35,11,49,41,34,60,21,1,234,104,92,254,34,235,87,98,70,69,254,231,1,25,97,112,151,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,0,3,0,51,255,245,1,241,2,219,0,11,0,19,0,23,0,0,1,50,22,21,20,6,35,34,38,53,52,54,22,38,34,6,20,22,50,54,3,23,7,39,1,18,100,123,123,100,100,123,123,243,72,139,74,70,139,76,243,235,23,245,1,234,130,121,120,130,130,120,121,130,165,97,97,171,97,97,2,65,133,50,113,0,0,3,0,51,255,245,1,241,2,219,0,11,0,19,0,23,0,0,1,34,6,21,20,22,51,50,54,53,52,38,6,54,50,22,20,6,34,38,1,7,39,55,1,18,100,123,123,100,100,123,123,242,74,139,72,76,139,70,1,19,244,23,235,1,234,130,121,120,130,130,120,121,130,165,97,97,171,97,97,1,251,113,50,133,0,3,0,51,255,245,1,241,2,231,0,11,0,19,0,25,0,0,1,50,22,21,20,6,35,34,38,53,52,54,22,38,34,6,20,22,50,54,19,7,39,7,39,55,1,18,100,123,123,100,100,123,123,243,72,139,74,70,139,76,36,50,129,130,50,180,1,234,130,121,120,130,130,120,121,130,165,97,97,171,97,97,1,177,39,108,108,39,156,0,0,3,0,51,255,245,1,241,2,201,0,11,0,19,0,39,0,0,1,34,6,21,20,22,51,50,54,53,52,38,6,54,50,22,20,6,34,38,19,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,1,18,100,123,123,100,100,123,123,242,74,139,72,76,139,70,74,32,25,32,12,46,52,33,47,27,26,28,10,35,11,49,41,34,60,21,1,234,130,121,120,130,130,120,121,130,165,97,97,171,97,97,1,231,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,4,0,51,255,245,1,241,2,193,0,11,0,19,0,29,0,37,0,0,1,50,22,21,20,6,35,34,38,53,52,54,22,38,34,6,20,22,50,54,2,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,1,18,100,123,123,100,100,123,123,243,72,139,74,70,139,76,250,29,29,23,23,31,31,23,146,30,30,45,31,31,1,234,130,121,120,130,130,120,121,130,165,97,97,171,97,97,1,195,29,42,29,29,42,29,29,42,29,29,42,29,0,2,0,87,255,247,1,249,3,1,0,17,0,21,0,0,37,6,35,34,38,53,17,51,17,20,51,50,54,55,53,51,17,35,3,23,7,39,1,170,49,110,81,99,79,112,65,81,2,79,79,226,235,23,245,95,104,90,94,1,48,254,214,121,100,78,241,254,33,3,1,133,50,113,0,2,0,87,255,247,1,249,3,1,0,17,0,21,0,0,5,50,55,21,51,17,35,21,20,6,35,34,53,17,35,17,20,22,19,7,39,55,1,11,110,49,79,79,82,66,112,79,99,247,244,23,235,9,104,95,1,223,233,83,103,121,1,42,254,208,94,90,2,196,113,50,133,0,0,2,0,87,255,247,1,249,3,13,0,17,0,23,0,0,37,6,35,34,38,53,17,51,17,20,51,50,54,55,53,51,17,35,19,7,39,7,39,55,1,170,49,110,81,99,79,112,65,81,2,79,79,54,50,129,130,50,180,95,104,90,94,1,48,254,214,121,100,78,241,254,33,2,113,39,108,108,39,156,0,3,0,87,255,247,1,249,2,193,0,17,0,27,0,35,0,0,37,6,35,34,38,53,17,51,17,20,51,50,54,55,53,51,17,35,2,38,52,54,51,50,22,20,6,35,50,38,52,54,50,22,20,6,1,170,49,110,81,99,79,112,65,81,2,79,79,233,29,29,23,23,31,31,23,146,30,30,45,31,31,95,104,90,94,1,48,254,214,121,100,78,241,254,33,2,93,29,42,29,29,42,29,29,42,29,29,42,29,0,0,1,0,101,0,0,0,180,1,223,0,3,0,0,19,51,17,35,101,79,79,1,223,254,33,0,0,1,0,36,1,163,0,184,2,113,0,11,0,0,18,38,52,54,50,22,20,6,7,39,54,55,88,30,31,57,38,44,45,59,62,13,2,13,26,44,30,45,68,71,22,29,30,45,0,1,0,24,2,165,1,127,3,104,0,5,0,0,1,7,39,7,39,55,1,127,50,129,130,50,180,2,204,39,108,108,39,156,0,1,0,23,2,207,1,83,3,74,0,19,0,0,19,34,7,39,54,54,50,23,22,22,50,54,55,23,6,6,34,46,2,112,32,25,32,12,46,52,33,47,27,26,28,10,35,11,49,41,34,60,21,3,2,51,19,51,53,17,23,12,25,27,23,48,52,12,31,8,0,1,0,55,1,1,1,163,1,69,0,3,0,0,19,33,21,33,55,1,108,254,148,1,69,68,0,1,0,55,1,1,2,159,1,69,0,3,0,0,19,33,21,33,55,2,104,253,152,1,69,68,0,1,0,36,1,162,0,184,2,114,0,12,0,0,18,6,34,38,52,54,55,23,6,7,22,22,21,162,31,56,39,47,45,56,62,13,23,30,1,193,31,46,69,71,22,29,32,44,2,26,22,0,0,1,0,15,1,162,0,162,2,114,0,13,0,0,18,54,50,22,21,20,6,7,39,54,55,38,38,53,36,32,57,37,47,44,56,62,13,23,31,2,84,30,44,35,35,71,23,30,32,44,2,26,22,0,0,1,0,92,0,0,1,252,2,117,0,27,0,0,19,33,21,35,22,23,51,21,35,6,7,6,7,5,35,37,53,51,50,54,55,35,53,51,38,38,35,35,92,1,160,183,69,15,99,94,7,112,40,55,1,18,112,254,242,61,87,84,3,235,231,11,83,76,61,2,117,49,36,67,48,115,44,15,5,250,248,48,76,57,48,46,57,0,0,1,0,79,1,2,1,153,1,69,0,3,0,0,1,21,33,53,1,153,254,182,1,69,67,67,0,1,0,0,0,157,0,63,0,5,0,0,0,0,0,2,0,0,0,1,0,1,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,0,44,0,93,0,164,0,235,1,66,1,79,1,101,1,123,1,153,1,174,1,198,1,211,1,229,1,243,2,19,2,39,2,85,2,136,2,164,2,203,2,253,3,16,3,82,3,139,3,169,3,205,3,225,3,244,4,8,4,63,4,150,4,174,4,224,5,6,5,37,5,60,5,81,5,122,5,146,5,159,5,182,5,209,5,224,5,251,6,18,6,54,6,85,6,137,6,174,6,225,6,243,7,16,7,35,7,64,7,90,7,112,7,136,7,153,7,166,7,182,7,200,7,213,7,227,8,22,8,62,8,98,8,138,8,179,8,212,9,45,9,75,9,100,9,140,9,163,9,176,9,222,9,252,10,30,10,68,10,119,10,145,10,195,10,229,11,3,11,22,11,51,11,74,11,108,11,131,11,175,11,188,11,232,12,7,12,60,12,91,12,105,12,136,12,167,12,201,12,253,13,45,13,76,13,106,13,140,13,188,13,208,13,227,13,250,14,32,14,84,14,127,14,170,14,216,15,24,15,84,15,120,15,157,15,197,15,251,16,53,16,113,16,174,16,255,17,75,17,124,17,170,17,221,18,31,18,51,18,70,18,93,18,131,18,191,18,233,19,19,19,64,19,127,19,186,19,223,20,4,20,44,20,99,20,112,20,136,20,153,20,188,20,201,20,214,20,240,21,11,21,55,21,68,0,1,0,0,0,1,0,0,184,134,128,40,95,15,60,245,0,11,3,232,0,0,0,0,202,188,123,31,0,0,0,0,204,143,87,201,255,170,255,10,3,126,3,111,0,0,0,8,0,2,0,0,0,0,0,0,2,41,0,0,0,0,0,0,2,41,0,0,0,238,0,0,1,22,0,82,1,50,0,28,2,115,0,53,2,120,0,69,2,214,0,61,3,148,0,89,0,136,0,27,1,100,0,73,1,100,0,28,1,156,0,56,2,15,0,18,0,210,0,30,1,93,0,38,0,179,0,30,1,176,0,57,2,82,0,51,1,75,0,49,2,68,0,64,2,79,0,52,2,47,0,26,2,53,0,65,2,61,0,51,1,214,0,24,2,103,0,55,2,69,0,66,0,231,0,56,1,6,0,57,1,198,0,40,1,232,0,79,1,198,0,47,1,243,0,30,3,172,0,67,2,63,0,26,2,110,0,101,2,101,0,51,2,149,0,100,2,50,0,100,2,12,0,101,2,133,0,51,2,157,0,101,1,24,0,101,1,148,0,8,2,97,0,101,1,212,0,101,3,80,0,101,2,173,0,99,2,134,0,51,2,42,0,99,2,140,0,51,2,101,0,101,2,93,0,69,1,245,0,6,2,142,0,87,2,51,0,18,3,127,0,14,2,130,0,47,2,37,0,10,2,80,0,73,1,61,0,101,1,176,0,45,1,29,255,242,1,192,0,21,2,214,0,55,1,59,0,24,2,48,0,70,2,72,0,101,2,3,0,50,2,82,0,60,2,3,0,50,1,87,0,49,2,53,0,28,2,92,0,101,1,43,0,94,1,58,255,170,2,52,0,101,1,24,0,101,3,167,0,100,2,91,0,100,2,34,0,50,2,82,0,101,2,73,0,51,1,125,0,100,2,14,0,60,1,120,0,34,2,94,0,87,1,247,0,18,2,213,0,18,2,0,0,26,1,228,0,5,1,219,0,53,1,93,0,75,1,24,0,101,1,93,0,8,2,3,0,53,2,53,0,20,1,67,0,24,1,59,0,23,2,63,0,26,2,63,0,26,2,63,0,26,2,63,0,26,2,63,0,26,2,52,0,100,2,52,0,100,2,52,0,105,2,52,0,100,1,24,0,7,1,24,0,6,1,24,255,217,1,24,0,4,2,174,0,99,2,134,0,51,2,134,0,51,2,134,0,51,2,134,0,51,2,134,0,51,2,142,0,87,2,142,0,87,2,142,0,87,2,142,0,87,2,39,0,60,2,39,0,60,2,39,0,60,2,39,0,60,2,39,0,60,2,2,0,51,2,2,0,51,2,2,0,54,2,2,0,51,1,43,0,12,1,43,0,11,1,43,255,222,1,43,0,9,2,92,0,101,2,35,0,51,2,35,0,51,2,35,0,51,2,35,0,51,2,35,0,51,2,94,0,87,2,94,0,87,2,94,0,87,2,94,0,87,1,24,0,101,0,184,0,36,1,151,0,24,1,110,0,23,1,218,0,55,2,214,0,55,0,214,0,36,0,214,0,15,2,69,0,92,1,232,0,79,0,1,0,0,3,149,255,4,0,0,3,172,255,170,255,216,3,126,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,157,0,3,1,253,1,144,0,5,0,8,2,188,2,138,0,0,0,140,2,188,2,138,0,0,1,221,0,50,0,250,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,39,0,0,0,66,0,0,0,0,0,0,0,0,112,121,114,115,0,64,0,32,34,18,3,149,255,4,0,0,3,149,0,252,0,0,0,1,0,0,0,0,1,222,2,117,0,0,0,32,0,2,0,0,0,2,0,0,0,3,0,0,0,20,0,3,0,1,0,0,0,20,0,4,0,192,0,0,0,44,0,32,0,4,0,12,0,126,0,160,0,163,0,168,0,180,0,196,0,207,0,214,0,220,0,228,0,239,0,246,0,252,1,49,2,188,2,198,2,220,32,20,32,25,32,185,34,18,255,255,0,0,0,32,0,160,0,163,0,168,0,180,0,192,0,200,0,209,0,217,0,224,0,232,0,241,0,249,1,49,2,188,2,198,2,220,32,19,32,24,32,185,34,18,255,255,255,227,255,99,255,191,255,187,255,176,255,165,255,162,255,161,255,159,255,156,255,153,255,152,255,150,255,98,253,216,253,207,253,186,224,132,224,129,223,226,222,138,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,184,1,255,133,176,4,141,0,0,0,0,11,0,138,0,3,0,1,4,9,0,0,0,218,0,0,0,3,0,1,4,9,0,1,0,10,0,218,0,3,0,1,4,9,0,2,0,14,0,228,0,3,0,1,4,9,0,3,0,84,0,242,0,3,0,1,4,9,0,4,0,10,0,218,0,3,0,1,4,9,0,5,0,26,1,70,0,3,0,1,4,9,0,6,0,26,1,96,0,3,0,1,4,9,0,9,0,32,1,122,0,3,0,1,4,9,0,12,0,28,1,154,0,3,0,1,4,9,0,13,0,152,1,182,0,3,0,1,4,9,0,14,0,52,2,78,0,67,0,111,0,112,0,121,0,114,0,105,0,103,0,104,0,116,0,32,0,40,0,99,0,41,0,32,0,50,0,48,0,49,0,49,0,45,0,50,0,48,0,49,0,50,0,44,0,32,0,74,0,111,0,110,0,97,0,116,0,104,0,97,0,110,0,32,0,80,0,105,0,110,0,104,0,111,0,114,0,110,0,32,0,40,0,106,0,111,0,110,0,112,0,105,0,110,0,104,0,111,0,114,0,110,0,46,0,116,0,121,0,112,0,101,0,100,0,101,0,115,0,105,0,103,0,110,0,64,0,103,0,109,0,97,0,105,0,108,0,46,0,99,0,111,0,109,0,41,0,44,0,32,0,119,0,105,0,116,0,104,0,32,0,82,0,101,0,115,0,101,0,114,0,118,0,101,0,100,0,32,0,70,0,111,0,110,0,116,0,32,0,78,0,97,0,109,0,101,0,115,0,32,0,39,0,75,0,97,0,114,0,108,0,97,0,39,0,75,0,97,0,114,0,108,0,97,0,82,0,101,0,103,0,117,0,108,0,97,0,114,0,70,0,111,0,110,0,116,0,70,0,111,0,114,0,103,0,101,0,32,0,50,0,46,0,48,0,32,0,58,0,32,0,75,0,97,0,114,0,108,0,97,0,32,0,82,0,101,0,103,0,117,0,108,0,97,0,114,0,32,0,58,0,32,0,49,0,51,0,45,0,49,0,48,0,45,0,50,0,48,0,49,0,49,0,86,0,101,0,114,0,115,0,105,0,111,0,110,0,32,0,49,0,46,0,48,0,48,0,48,0,75,0,97,0,114,0,108,0,97,0,45,0,82,0,101,0,103,0,117,0,108,0,97,0,114,0,74,0,111,0,110,0,97,0,116,0,104,0,97,0,110,0,32,0,80,0,105,0,110,0,104,0,111,0,114,0,110,0,106,0,111,0,110,0,112,0,105,0,110,0,104,0,111,0,114,0,110,0,46,0,99,0,111,0,109,0,84,0,104,0,105,0,115,0,32,0,70,0,111,0,110,0,116,0,32,0,83,0,111,0,102,0,116,0,119,0,97,0,114,0,101,0,32,0,105,0,115,0,32,0,108,0,105,0,99,0,101,0,110,0,115,0,101,0,100,0,32,0,117,0,110,0,100,0,101,0,114,0,32,0,116,0,104,0,101,0,32,0,83,0,73,0,76,0,32,0,79,0,112,0,101,0,110,0,32,0,70,0,111,0,110,0,116,0,32,0,76,0,105,0,99,0,101,0,110,0,115,0,101,0,44,0,32,0,86,0,101,0,114,0,115,0,105,0,111,0,110,0,32,0,49,0,46,0,49,0,46,0,104,0,116,0,116,0,112,0,58,0,47,0,47,0,115,0,99,0,114,0,105,0,112,0,116,0,115,0,46,0,115,0,105,0,108,0,46,0,111,0,114,0,103,0,47,0,79,0,70,0,76,0,2,0,0,0,0,0,0,255,181,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,157,0,0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,0,32,0,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,57,0,58,0,59,0,60,0,61,0,62,0,63,0,64,0,65,0,66,0,67,0,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,92,0,93,0,94,0,95,0,96,0,97,0,133,0,142,0,141,0,173,0,201,0,199,0,174,0,98,0,203,0,101,0,200,0,202,0,207,0,204,0,205,0,206,0,102,0,211,0,208,0,209,0,175,0,103,0,214,0,212,0,213,0,104,0,106,0,105,0,107,0,109,0,108,0,113,0,112,0,114,0,115,0,117,0,116,0,118,0,119,0,120,0,122,0,121,0,123,0,125,0,124,0,127,0,126,0,128,0,129,0,215,1,2,0,216,0,217,0,178,0,179,0,182,0,183,1,3,0,239,10,97,112,111,115,116,114,111,112,104,101,11,114,117,112,101,101,115,121,109,98,111,108,0,0,1,0,1,255,255,0,15,0,1,0,0,0,12,0,0,0,0,0,0,0,2,0,1,0,1,0,156,0,1,0,0,0,1,0,0,0,10,0,30,0,44,0,1,108,97,116,110,0,8,0,4,0,0,0,0,255,255,0,1,0,0,0,1,107,101,114,110,0,8,0,0,0,1,0,0,0,1,0,4,0,2,0,0,0,1,0,8,0,1,0,82,0,4,0,0,0,36,0,152,0,186,0,192,1,6,1,40,1,54,1,60,1,66,1,72,1,158,1,216,2,14,2,20,2,130,2,148,2,162,2,176,2,190,2,216,2,226,2,236,2,242,3,0,3,10,3,20,3,38,3,48,3,62,3,76,3,102,3,108,3,118,3,140,3,158,3,168,3,190,0,2,0,11,0,36,0,36,0,0,0,39,0,39,0,1,0,41,0,41,0,2,0,47,0,47,0,3,0,50,0,52,0,4,0,54,0,55,0,7,0,57,0,60,0,9,0,68,0,70,0,13,0,72,0,75,0,16,0,77,0,78,0,20,0,80,0,93,0,22,0,8,0,55,255,216,0,57,255,228,0,58,255,228,0,60,255,230,0,73,255,244,0,89,255,234,0,90,255,232,0,92,255,228,0,1,0,60,255,231,0,17,0,36,255,199,0,58,255,248,0,59,255,240,0,60,255,248,0,68,255,232,0,70,255,228,0,71,255,232,0,72,255,228,0,74,255,211,0,82,255,228,0,84,255,228,0,88,255,232,0,89,255,224,0,90,255,220,0,91,255,228,0,92,255,228,0,93,255,232,0,8,0,45,0,16,0,55,255,207,0,57,255,211,0,58,255,215,0,60,255,187,0,89,255,232,0,90,255,232,0,92,255,236,0,3,0,57,255,248,0,59,255,244,0,60,255,240,0,1,0,36,255,218,0,1,0,60,255,240,0,1,0,60,255,230,0,21,0,36,255,216,0,45,255,187,0,68,255,169,0,70,255,181,0,71,255,171,0,72,255,181,0,73,255,203,0,74,255,169,0,80,255,187,0,81,255,187,0,82,255,177,0,83,255,187,0,84,255,181,0,85,255,183,0,86,255,159,0,88,255,187,0,89,255,183,0,90,255,216,0,91,255,199,0,92,255,206,0,93,255,203,0,14,0,36,255,223,0,38,255,248,0,45,255,187,0,50,255,248,0,68,255,223,0,70,255,223,0,71,255,223,0,72,255,223,0,73,255,216,0,74,255,207,0,82,255,223,0,84,255,227,0,85,255,239,0,86,255,223,0,13,0,36,255,223,0,45,255,187,0,68,255,223,0,70,255,223,0,71,255,223,0,72,255,223,0,73,255,216,0,74,255,207,0,82,255,223,0,84,255,223,0,85,255,223,0,86,255,216,0,88,255,228,0,1,0,50,255,244,0,27,0,36,255,187,0,38,255,239,0,43,255,248,0,45,255,174,0,50,255,240,0,52,255,240,0,54,255,228,0,68,255,195,0,70,255,191,0,71,255,191,0,72,255,191,0,73,255,191,0,74,255,179,0,80,255,191,0,81,255,191,0,82,255,191,0,83,255,191,0,84,255,191,0,85,255,191,0,86,255,191,0,87,255,219,0,88,255,189,0,89,255,211,0,90,255,211,0,91,255,203,0,92,255,199,0,93,255,191,0,4,0,55,255,167,0,57,255,219,0,58,255,228,0,60,255,203,0,3,0,55,255,236,0,57,255,227,0,60,255,239,0,3,0,55,255,195,0,57,255,228,0,60,255,223,0,3,0,55,255,195,0,57,255,232,0,60,255,215,0,6,0,36,255,240,0,45,255,203,0,70,255,240,0,74,255,230,0,77,255,240,0,86,255,232,0,2,0,77,0,73,0,92,0,16,0,2,0,55,255,248,0,60,255,211,0,1,0,73,255,234,0,3,0,73,255,240,0,77,255,248,0,92,255,240,0,2,0,55,255,220,0,60,255,215,0,2,0,55,255,212,0,60,255,215,0,4,0,55,255,185,0,57,255,223,0,58,255,223,0,60,255,191,0,2,0,55,255,203,0,60,255,220,0,3,0,55,255,183,0,60,255,209,0,77,0,81,0,3,0,45,255,216,0,55,255,208,0,74,255,236,0,6,0,55,255,167,0,57,255,228,0,58,255,220,0,60,255,199,0,73,255,228,0,92,255,236,0,1,0,60,255,219,0,2,0,55,255,199,0,60,255,207,0,5,0,36,255,232,0,45,255,203,0,55,255,196,0,60,255,211,0,74,255,248,0,4,0,36,255,228,0,45,255,215,0,55,255,224,0,60,255,224,0,2,0,55,255,215,0,60,255,207,0,5,0,36,255,244,0,45,255,232,0,55,255,200,0,60,255,228,0,74,255,248,0,2,0,55,255,232,0,60,255,215,0,1,0,0,0,10,0,30,0,44,0,1,108,97,116,110,0,8,0,4,0,0,0,0,255,255,0,1,0,0,0,1,111,110,117,109,0,8,0,0,0,1,0,0,0,1,0,4,0,1,0,0,0,1,0,8,0,2,0,26,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,19,0,28,0,0 }; 14 | #endif /* NMD_GRAPHICS_DISABLE_DEFAULT_FONT */ 15 | -------------------------------------------------------------------------------- /graphics/nmd_graphics.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | nmd_context _nmd_context; 4 | bool _nmd_initialized = false; 5 | 6 | nmd_color nmd_rgb(uint8_t r, uint8_t g, uint8_t b) 7 | { 8 | return nmd_rgba(r, g, b, 0xff); 9 | } 10 | 11 | nmd_color nmd_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) 12 | { 13 | nmd_color color; 14 | color.r = NMD_CLAMP(r, 0, 255); 15 | color.g = NMD_CLAMP(g, 0, 255); 16 | color.b = NMD_CLAMP(b, 0, 255); 17 | color.a = NMD_CLAMP(a, 0, 255); 18 | 19 | return color; 20 | } 21 | 22 | nmd_context* nmd_get_context() 23 | { 24 | return &_nmd_context; 25 | } 26 | 27 | /* 28 | Creates one or more draw commands for the unaccounted vertices and indices. 29 | Parameters: 30 | clip_rect [opt/in] A pointer to a rect that specifies the clip area. This parameter can be null. 31 | */ 32 | void nmd_push_draw_command(const nmd_rect* clip_rect) 33 | { 34 | /* Calculate the number of vertices and indices present in draw commands */ 35 | size_t num_accounted_vertices = 0, num_accounted_indices = 0; 36 | size_t i = 0; 37 | for (; i < _nmd_context.draw_list.num_draw_commands; i++) 38 | { 39 | num_accounted_vertices += _nmd_context.draw_list.draw_commands[i].num_vertices; 40 | num_accounted_indices += _nmd_context.draw_list.draw_commands[i].num_indices; 41 | } 42 | 43 | /* Calculate the number of vertices and indices NOT present in draw commands */ 44 | size_t num_unaccounted_indices = _nmd_context.draw_list.num_indices - num_accounted_indices; 45 | 46 | /* Create draw commands until all vertices and indices are present in draw commands */ 47 | while (num_unaccounted_indices > 0) 48 | { 49 | /* If the number of unaccounted indices is less than the maximum number of indices that can be hold by 'nmd_index'(usually 2^16) */ 50 | if (num_unaccounted_indices < (1 << (8 * sizeof(nmd_index)))) 51 | { 52 | /* Add draw command */ 53 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].num_vertices = _nmd_context.draw_list.num_vertices - num_accounted_vertices; 54 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].num_indices = _nmd_context.draw_list.num_indices - num_accounted_indices; 55 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].user_texture_id = _nmd_context.draw_list.blank_tex_id; 56 | if (clip_rect) 57 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].rect = *clip_rect; 58 | else 59 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].rect.p1.x = -1.0f; 60 | 61 | _nmd_context.draw_list.num_draw_commands++; 62 | return; 63 | } 64 | else 65 | { 66 | size_t num_indices = (1 << (8 * sizeof(nmd_index))); 67 | nmd_index last_index = _nmd_context.draw_list.indices[num_indices - 1]; 68 | 69 | bool is_last_index_referenced = false; 70 | do 71 | { 72 | for (size_t i = num_indices; i < num_unaccounted_indices; i++) 73 | { 74 | if (_nmd_context.draw_list.indices[i] == last_index) 75 | { 76 | is_last_index_referenced = true; 77 | num_indices -= 3; 78 | last_index = _nmd_context.draw_list.indices[num_indices - 1]; 79 | break; 80 | } 81 | } 82 | } while (is_last_index_referenced); 83 | 84 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].num_vertices = last_index + 1; 85 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].num_indices = num_indices; 86 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].user_texture_id = _nmd_context.draw_list.blank_tex_id; 87 | 88 | _nmd_context.draw_list.num_draw_commands++; 89 | 90 | num_unaccounted_indices -= num_indices; 91 | } 92 | } 93 | } 94 | 95 | void nmd_push_texture_draw_command(nmd_tex_id user_texture_id, const nmd_rect* clip_rect) 96 | { 97 | size_t num_accounted_vertices = 0, num_accounted_indices = 0; 98 | size_t i = 0; 99 | for (; i < _nmd_context.draw_list.num_draw_commands; i++) 100 | { 101 | num_accounted_vertices += _nmd_context.draw_list.draw_commands[i].num_vertices; 102 | num_accounted_indices += _nmd_context.draw_list.draw_commands[i].num_indices; 103 | } 104 | 105 | const size_t num_unaccounted_indices = _nmd_context.draw_list.num_indices - num_accounted_indices; 106 | 107 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].num_vertices = _nmd_context.draw_list.num_vertices - num_accounted_vertices; 108 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].num_indices = num_unaccounted_indices; 109 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].user_texture_id = user_texture_id; 110 | if (clip_rect) 111 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].rect = *clip_rect; 112 | else 113 | _nmd_context.draw_list.draw_commands[_nmd_context.draw_list.num_draw_commands].rect.p1.x = -1.0f; 114 | _nmd_context.draw_list.num_draw_commands++; 115 | } 116 | 117 | void _nmd_calculate_circle_segments(float max_error) 118 | { 119 | for (size_t i = 0; i < 64; i++) 120 | { 121 | const uint8_t segment_count = NMD_CIRCLE_AUTO_SEGMENT_CALC(i + 1.0f, max_error); 122 | _nmd_context.draw_list.cached_circle_segment_counts64[i] = NMD_MIN(segment_count, 255); 123 | } 124 | } 125 | 126 | #ifdef _WIN32 127 | void nmd_win32_set_hwnd(HWND hWnd) 128 | { 129 | _nmd_context.hWnd = hWnd; 130 | } 131 | #endif /* _WIN32*/ 132 | 133 | /* Starts a new empty scene/frame. Internally this function clears all vertices, indices and command buffers. */ 134 | void nmd_new_frame() 135 | { 136 | if (!_nmd_initialized) 137 | { 138 | _nmd_initialized = true; 139 | 140 | _nmd_context.draw_list.line_anti_aliasing = true; 141 | _nmd_context.draw_list.fill_anti_aliasing = true; 142 | 143 | for (size_t i = 0; i < 12; i++) 144 | { 145 | const float angle = (i / 12.0f) * NMD_2PI; 146 | _nmd_context.draw_list.cached_circle_vertices12[i].x = NMD_COS(angle); 147 | _nmd_context.draw_list.cached_circle_vertices12[i].y = NMD_SIN(angle); 148 | } 149 | 150 | _nmd_calculate_circle_segments(1.6f); 151 | 152 | /* Allocate buffers */ 153 | _nmd_context.draw_list.path = (nmd_vec2*)NMD_MALLOC(NMD_PATH_BUFFER_INITIAL_SIZE * sizeof(nmd_vec2)); 154 | _nmd_context.draw_list.path_capacity = NMD_PATH_BUFFER_INITIAL_SIZE * sizeof(nmd_vec2); 155 | 156 | _nmd_context.draw_list.vertices = (nmd_vertex*)NMD_MALLOC(NMD_VERTEX_BUFFER_INITIAL_SIZE * sizeof(nmd_vertex)); 157 | _nmd_context.draw_list.vertices_capacity = NMD_VERTEX_BUFFER_INITIAL_SIZE * sizeof(nmd_vertex); 158 | 159 | _nmd_context.draw_list.indices = (nmd_index*)NMD_MALLOC(NMD_INDEX_BUFFER_INITIAL_SIZE * sizeof(nmd_index)); 160 | _nmd_context.draw_list.indices_capacity = NMD_INDEX_BUFFER_INITIAL_SIZE * sizeof(nmd_index); 161 | 162 | _nmd_context.draw_list.draw_commands = (nmd_draw_command*)NMD_MALLOC(NMD_DRAW_COMMANDS_BUFFER_INITIAL_SIZE * sizeof(nmd_draw_command)); 163 | _nmd_context.draw_list.draw_commands_capacity = NMD_DRAW_COMMANDS_BUFFER_INITIAL_SIZE * sizeof(nmd_draw_command); 164 | 165 | _nmd_context.gui.num_windows = 0; 166 | _nmd_context.gui.windows = (nmd_window*)NMD_MALLOC(NMD_WINDOWS_BUFFER_INITIAL_SIZE * sizeof(nmd_window)); 167 | _nmd_context.gui.windows_capacity = NMD_WINDOWS_BUFFER_INITIAL_SIZE; 168 | _nmd_context.gui.window = 0; 169 | _nmd_context.gui.window_pos.x = 60; 170 | _nmd_context.gui.window_pos.y = 60; 171 | } 172 | 173 | _nmd_context.draw_list.num_vertices = 0; 174 | _nmd_context.draw_list.num_indices = 0; 175 | _nmd_context.draw_list.num_draw_commands = 0; 176 | 177 | #ifdef _WIN32 178 | POINT point; 179 | if (_nmd_context.hWnd && GetCursorPos(&point) && ScreenToClient(_nmd_context.hWnd, &point)) 180 | { 181 | _nmd_context.io.mouse_pos.x = point.x; 182 | _nmd_context.io.mouse_pos.y = point.y; 183 | } 184 | #endif /* _WIN32 */ 185 | } 186 | 187 | /* "Ends" a frame. Wrapper around nmd_push_draw_command(). */ 188 | void nmd_end_frame() 189 | { 190 | /* Clears the mouse released state because it should only be used once */ 191 | for (size_t i = 0; i < 5; i++) 192 | _nmd_context.io.mouse_released[i] = false; 193 | 194 | nmd_push_draw_command(0); 195 | } 196 | 197 | bool nmd_bake_font_from_memory(const void* font_data, nmd_atlas* atlas, float size) 198 | { 199 | atlas->width = 512; 200 | atlas->height = 512; 201 | 202 | atlas->pixels8 = (uint8_t*)NMD_MALLOC(atlas->width * atlas->height); 203 | atlas->pixels32 = (nmd_color*)NMD_MALLOC(atlas->width * atlas->height * 4); 204 | atlas->baked_chars = NMD_MALLOC(sizeof(stbtt_bakedchar) * 96); 205 | 206 | stbtt_BakeFontBitmap((const unsigned char*)font_data, 0, size, atlas->pixels8, atlas->width, atlas->height, 0x20, 96, (stbtt_bakedchar*)atlas->baked_chars); 207 | 208 | size_t i = 0; 209 | for (; i < atlas->width * atlas->height; i++) 210 | atlas->pixels32[i] = nmd_rgba(255, 255, 255, atlas->pixels8[i]); 211 | 212 | return true; 213 | } 214 | 215 | bool nmd_bake_font(const char* font_path, nmd_atlas* atlas, float size) 216 | { 217 | bool ret = false; 218 | 219 | #ifndef NMD_GRAPHICS_DISABLE_FILE_IO 220 | FILE* f = fopen(font_path, "rb"); 221 | 222 | /* Get file size*/ 223 | fseek(f, 0L, SEEK_END); 224 | const size_t file_size = ftell(f); 225 | fseek(f, 0L, SEEK_SET); 226 | 227 | /* Allocate and read file */ 228 | void* font_data = NMD_MALLOC(file_size); 229 | fread(font_data, 1, file_size, f); 230 | 231 | ret = nmd_bake_font_from_memory(font_data, atlas, size); 232 | 233 | /* Close and free file */ 234 | fclose(f); 235 | NMD_FREE(font_data); 236 | #endif 237 | 238 | return ret; 239 | } 240 | 241 | //bool nmd_bake_font(nmd_atlas* atlas) 242 | //{ 243 | // 244 | // int i = 0; 245 | // void* tmp = 0; 246 | // size_t tmp_size, img_size; 247 | // struct nk_font* font_iter; 248 | // struct nk_font_baker* baker; 249 | // 250 | //#ifdef NK_INCLUDE_DEFAULT_FONT 251 | // /* no font added so just use default font */ 252 | // if (!atlas->font_num) 253 | // atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0); 254 | //#endif 255 | // NK_ASSERT(atlas->font_num); 256 | // if (!atlas->font_num) return 0; 257 | // 258 | // /* allocate temporary baker memory required for the baking process */ 259 | // nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num); 260 | // tmp = atlas->temporary.alloc(atlas->temporary.userdata, 0, tmp_size); 261 | // NK_ASSERT(tmp); 262 | // if (!tmp) goto failed; 263 | // memset(tmp, 0, tmp_size); 264 | // 265 | // /* allocate glyph memory for all fonts */ 266 | // baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary); 267 | // atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc( 268 | // atlas->permanent.userdata, 0, sizeof(struct nk_font_glyph) *(size_t)atlas->glyph_count); 269 | // NK_ASSERT(atlas->glyphs); 270 | // if (!atlas->glyphs) 271 | // goto failed; 272 | // 273 | // /* pack all glyphs into a tight fit space */ 274 | // atlas->custom.w = (NK_CURSOR_DATA_W * 2) + 1; 275 | // atlas->custom.h = NK_CURSOR_DATA_H + 1; 276 | // if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom, 277 | // atlas->config, atlas->font_num, &atlas->temporary)) 278 | // goto failed; 279 | // 280 | // /* allocate memory for the baked image font atlas */ 281 | // atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata, 0, img_size); 282 | // NK_ASSERT(atlas->pixel); 283 | // if (!atlas->pixel) 284 | // goto failed; 285 | // 286 | // /* bake glyphs and custom white pixel into image */ 287 | // nk_font_bake(baker, atlas->pixel, *width, *height, 288 | // atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num); 289 | // nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom, 290 | // nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X'); 291 | // 292 | // if (fmt == NK_FONT_ATLAS_RGBA32) { 293 | // /* convert alpha8 image into rgba32 image */ 294 | // void* img_rgba = atlas->temporary.alloc(atlas->temporary.userdata, 0, 295 | // (size_t)(*width * *height * 4)); 296 | // NK_ASSERT(img_rgba); 297 | // if (!img_rgba) goto failed; 298 | // nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel); 299 | // atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); 300 | // atlas->pixel = img_rgba; 301 | // } 302 | // atlas->tex_width = *width; 303 | // atlas->tex_height = *height; 304 | // 305 | // /* initialize each font */ 306 | // for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { 307 | // struct nk_font* font = font_iter; 308 | // struct nk_font_config* config = font->config; 309 | // nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs, 310 | // config->font, nk_handle_ptr(0)); 311 | // } 312 | // 313 | //failed: 314 | // /* error so cleanup all memory */ 315 | // if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp); 316 | // if (atlas->glyphs) { 317 | // atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); 318 | // atlas->glyphs = 0; 319 | // } 320 | // if (atlas->pixel) { 321 | // atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); 322 | // atlas->pixel = 0; 323 | // } 324 | // return 0; 325 | //} 326 | -------------------------------------------------------------------------------- /graphics/nmd_graphics.h: -------------------------------------------------------------------------------- 1 | /* This is a C89 platform independent 2D immediate mode graphics library. 2 | 3 | This library just generates triangles(represented by vertices and indices) from functions like nmd_add_rect_filled(). 4 | There's a GUI component. There're helper functions to handle input on the following platforms: 5 | - Windows: nmd_win32_wnd_proc 6 | 7 | Setup: 8 | Define the 'NMD_GRAPHICS_IMPLEMENTATION' macro in one source file before the include statement to instantiate the implementation. 9 | #define NMD_GRAPHICS_IMPLEMENTATION 10 | #include "nmd_graphics.h" 11 | 12 | The general workflow for using the library is the following: 13 | 1 - Call nmd_new_frame() to clear all vertex, index and command buffers. 14 | 2 - Call whatever primitive function you need(e.g. nmd_add_line(), nmd_add_rect_filled()). 15 | 3 - Call nmd_end_frame() to create the necessary draw command(s) that describe the data(vertices and indices) for redering. 16 | 4 - Now you can do anything with the data. You probably want to call nmd_opengl_render(), nmd_d3d9_render() or nmd_d3d11_render() here. 17 | 18 | OpenGL Usage: 19 | You MUST define the 'NMD_GRAPHICS_OPENGL' macro once project-wise(compiler dependent) or for every include statement that you'll use any of the following functions. 20 | You MUST call nmd_opengl_resize() once for initialization and every time the window resizes. 21 | You MUST call nmd_opengl_render() to issue draw calls that render the data in the drawlist. 22 | You may call nmd_opengl_create_texture() if a helper function for texture creation is desired. 23 | You may define the 'NMD_GRAPHICS_OPENGL_DONT_BACKUP_RENDER_STATE' macro if you don't mind the library overriding the render state. 24 | You may define the 'NMD_GRAPHICS_OPENGL_OPTIMIZE_RENDER_STATE' macro so the render state only changes when necessary. Note that this option may only be used if this library is the only component that uses OpenGL. 25 | 26 | D3D9 Usage: 27 | You MUST define the 'NMD_GRAPHICS_D3D9' macro once project-wise(compiler dependent) or for every include statement that you'll use any of the following functions. 28 | You MUST call nmd_d3d9_set_device() once for initialization and every time the device changes. 29 | You MUST call nmd_d3d9_resize() once for initialization and every time the window resizes. 30 | You MUST call nmd_d3d9_render() to issue draw calls that render the data in the drawlist. 31 | You may call nmd_d3d9_create_texture() if a helper function for texture creation is desired. 32 | You may define the 'NMD_GRAPHICS_D3D9_DONT_BACKUP_RENDER_STATE' macro if you don't mind the library overriding the render state. 33 | You may define the 'NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE' macro so the render state only changes when necessary. Note that this option may only be used if this library is the only component that uses Direct3D 9. 34 | 35 | D3D11 Usage: 36 | You MUST define the 'NMD_GRAPHICS_D3D11' macro once project-wise(compiler dependent) or for every include statement that you'll use any of the following functions. 37 | You MUST call nmd_d3d11_set_device_context() once for initialization and every time the device context changes. 38 | You MUST call nmd_d3d11_resize() once for initialization and every time the window resizes. 39 | You MUST call nmd_d3d11_render() to issue draw calls that render the data in the drawlist. 40 | You may call nmd_d3d11_create_texture() if a helper function for texture creation is desired. 41 | You may define the 'NMD_GRAPHICS_D3D11_DONT_BACKUP_RENDER_STATE' macro if you don't mind the library overriding the render state. 42 | You may define the 'NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE' macro so the render state only changes when necessary. Note that this option may only be used if this library is the only component that uses Direct3D 11. 43 | 44 | Internals: 45 | The 'nmd_context'(acessible by nmd_get_context()) global variable holds the state of the entire library, it 46 | contains a 'nmd_drawlist' variable which holds the vertex, index and command buffers. Each command buffer 47 | translate to a call to a rendering's API draw function. Shapes can be rendered in the drawlist by calling 48 | functions like nmd_add_line() and nmd_add_filled_rect(). 49 | 50 | Fixed width integer types: 51 | By default the library includes and to include int types. 52 | If these header-files are not available in your environment you may define the 'NMD_DEFINE_INT_TYPES' macro so the library will define them. 53 | By defining the 'NMD_IGNORE_INT_TYPES' macro, the library will neither include nor define int types. 54 | 55 | Define the 'NMD_GRAPHICS_DISABLE_DEFAULT_ALLOCATOR' macro to tell the library not to include default allocators. 56 | Define the 'NMD_GRAPHICS_DISABLE_FILE_IO' macro to tell the library not to support file operations for fonts. 57 | Define the 'NMD_GRAPHICS_AVOID_ALLOCA' macro to tell the library to use malloc/free instead of alloca 58 | Default fonts: 59 | The 'Karla' true type font in included by default. Define the 'NMD_GRAPHICS_DISABLE_DEFAULT_FONT' macro to remove the font at compile time. 60 | 61 | NOTE: A big part of this library's code has been derived from Imgui's and Nuklear's code. Huge credit to both projects. 62 | 63 | Credits: 64 | - imgui: https://github.com/ocornut/imgui 65 | - nuklear: https://github.com/Immediate-Mode-UI/Nuklear 66 | - stb_truetype: https://github.com/nothings/stb/blob/master/stb_truetype.h 67 | */ 68 | 69 | #ifndef NMD_GRAPHICS_H 70 | #define NMD_GRAPHICS_H 71 | 72 | #ifndef _NMD_DEFINE_INT_TYPES 73 | #ifdef NMD_DEFINE_INT_TYPES 74 | #define _NMD_DEFINE_INT_TYPES 75 | #ifndef __cplusplus 76 | #define bool _Bool 77 | #define false 0 78 | #define true 1 79 | #endif /* __cplusplus */ 80 | typedef signed char int8_t; 81 | typedef unsigned char uint8_t; 82 | typedef signed short int16_t; 83 | typedef unsigned short uint16_t; 84 | typedef signed int int32_t; 85 | typedef unsigned int uint32_t; 86 | typedef signed long long int64_t; 87 | typedef unsigned long long uint64_t; 88 | #if defined(_WIN64) && defined(_MSC_VER) 89 | typedef unsigned __int64 size_t; 90 | typedef __int64 ptrdiff_t; 91 | #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) 92 | typedef unsigned __int32 size_t 93 | typedef __int32 ptrdiff_t; 94 | #elif defined(__GNUC__) || defined(__clang__) 95 | #if defined(__x86_64__) || defined(__ppc64__) 96 | typedef unsigned long size_t 97 | typedef long ptrdiff_t 98 | #else 99 | typedef unsigned int size_t 100 | typedef int ptrdiff_t 101 | #endif 102 | #else 103 | typedef unsigned long size_t 104 | typedef long ptrdiff_t 105 | #endif 106 | 107 | #else /* NMD_DEFINE_INT_TYPES */ 108 | #ifndef NMD_IGNORE_INT_TYPES 109 | #include 110 | #include 111 | #include 112 | #endif /* NMD_IGNORE_INT_TYPES */ 113 | #endif /* NMD_DEFINE_INT_TYPES */ 114 | #endif /* _NMD_DEFINE_INT_TYPES */ 115 | 116 | #ifndef NMD_MALLOC 117 | #include 118 | #define NMD_MALLOC malloc 119 | #define NMD_FREE free 120 | #endif /* NMD_MALLOC */ 121 | 122 | #ifndef NMD_MEMSET 123 | #include 124 | #define NMD_MEMSET memset 125 | #endif /* NMD_MEMSET */ 126 | 127 | #ifndef NMD_MEMCPY 128 | #include 129 | #define NMD_MEMCPY memcpy 130 | #endif /* NMD_MEMCPY */ 131 | 132 | #ifndef NMD_STRLEN 133 | #include 134 | #define NMD_STRLEN strlen 135 | #endif /* NMD_STRLEN */ 136 | 137 | #ifndef NMD_GRAPHICS_AVOID_ALLOCA 138 | #ifndef NMD_ALLOCA 139 | #include 140 | #define NMD_ALLOCA alloca 141 | #endif /* NMD_ALLOCA */ 142 | #endif /* NMD_GRAPHICS_AVOID_ALLOCA */ 143 | 144 | #ifndef NMD_SPRINTF 145 | #include 146 | #define NMD_SPRINTF sprintf 147 | #endif /* NMD_SPRINTF */ 148 | 149 | #ifndef NMD_VSPRINTF 150 | #include 151 | #define NMD_VSPRINTF vsprintf 152 | #endif /* NMD_VSPRINTF */ 153 | 154 | #ifndef NMD_SQRT 155 | #include 156 | #define NMD_SQRT sqrt 157 | #endif /* NMD_SQRT */ 158 | 159 | #ifndef NMD_ACOS 160 | #include 161 | #define NMD_ACOS acos 162 | #endif /* NMD_ACOS */ 163 | 164 | #ifndef NMD_COS 165 | #include 166 | #define NMD_COS cos 167 | #endif /* NMD_COS */ 168 | 169 | #ifndef NMD_SIN 170 | #include 171 | #define NMD_SIN sin 172 | #endif /* NMD_SIN */ 173 | 174 | #define STBTT_malloc(x,u) ((void)(u),NMD_MALLOC(x)) 175 | #define STBTT_free(x,u) ((void)(u),NMD_FREE(x)) 176 | #define STBTT_strlen(x) NMD_STRLEN(x) 177 | #define STBTT_memcpy NMD_MEMCPY 178 | #define STBTT_memset NMD_MEMSET 179 | 180 | /* The number of points the buffer intially supports */ 181 | #ifndef NMD_PATH_BUFFER_INITIAL_SIZE 182 | #define NMD_PATH_BUFFER_INITIAL_SIZE 32 183 | #endif /* NMD_PATH_BUFFER_INITIAL_SIZE */ 184 | 185 | /* The number of vertices the buffer intially supports */ 186 | #ifndef NMD_VERTEX_BUFFER_INITIAL_SIZE 187 | #define NMD_VERTEX_BUFFER_INITIAL_SIZE 2500 188 | #endif /* NMD_VERTEX_BUFFER_INITIAL_SIZE */ 189 | 190 | /* The number of indices the buffer intially supports */ 191 | #ifndef NMD_INDEX_BUFFER_INITIAL_SIZE 192 | #define NMD_INDEX_BUFFER_INITIAL_SIZE 5000 193 | #endif /* NMD_INDEX_BUFFER_INITIAL_SIZE */ 194 | 195 | /* The number of draw commands the buffer intially supports */ 196 | #ifndef NMD_DRAW_COMMANDS_BUFFER_INITIAL_SIZE 197 | #define NMD_DRAW_COMMANDS_BUFFER_INITIAL_SIZE 32 198 | #endif /* NMD_DRAW_COMMANDS_BUFFER_INITIAL_SIZE */ 199 | 200 | /* The number of windows the buffer intially supports */ 201 | #ifndef NMD_WINDOWS_BUFFER_INITIAL_SIZE 202 | #define NMD_WINDOWS_BUFFER_INITIAL_SIZE 4 203 | #endif /* NMD_WINDOWS_BUFFER_INITIAL_SIZE */ 204 | 205 | #ifdef _WIN32 206 | #include 207 | LRESULT nmd_win32_wnd_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 208 | #endif /* _WIN32 */ 209 | 210 | typedef uint16_t nmd_index; 211 | typedef void* nmd_tex_id; 212 | 213 | #ifdef NMD_GRAPHICS_OPENGL 214 | bool nmd_opengl_resize(int width, int height); 215 | void nmd_opengl_render(); 216 | nmd_tex_id nmd_opengl_create_texture(void* pixels, int width, int height); 217 | #endif /* NMD_GRAPHICS_OPENGL */ 218 | 219 | #ifdef NMD_GRAPHICS_D3D9 220 | #include 221 | void nmd_d3d9_set_device(LPDIRECT3DDEVICE9 pDevice); 222 | void nmd_d3d9_resize(int width, int height); 223 | void nmd_d3d9_render(); 224 | nmd_tex_id nmd_d3d9_create_texture(void* pixels, int width, int height); 225 | #endif /* NMD_GRAPHICS_D3D9 */ 226 | 227 | #ifdef NMD_GRAPHICS_D3D11 228 | #include 229 | void nmd_d3d11_set_device_context(ID3D11DeviceContext* pDeviceContext); 230 | bool nmd_d3d11_resize(int width, int height); 231 | void nmd_d3d11_render(); 232 | void nmd_d3d11_delete_objects(); 233 | nmd_tex_id nmd_d3d11_create_texture(void* pixels, int width, int height); 234 | #endif /* NMD_GRAPHICS_D3D11 */ 235 | 236 | enum NMD_CORNER 237 | { 238 | NMD_CORNER_NONE = (1 << 0), 239 | NMD_CORNER_TOP_LEFT = (1 << 1), 240 | NMD_CORNER_TOP_RIGHT = (1 << 2), 241 | NMD_CORNER_BOTTOM_LEFT = (1 << 3), 242 | NMD_CORNER_BOTTOM_RIGHT = (1 << 4), 243 | 244 | /* While these are not actual corners they are nice to have. */ 245 | NMD_CORNER_TOP = NMD_CORNER_TOP_LEFT | NMD_CORNER_TOP_RIGHT, 246 | NMD_CORNER_BOTTOM = NMD_CORNER_BOTTOM_LEFT | NMD_CORNER_BOTTOM_RIGHT, 247 | NMD_CORNER_LEFT = NMD_CORNER_TOP_LEFT | NMD_CORNER_BOTTOM_LEFT, 248 | NMD_CORNER_RIGHT = NMD_CORNER_TOP_RIGHT | NMD_CORNER_BOTTOM_RIGHT, 249 | 250 | NMD_CORNER_ALL = (1 << 5) - 1 251 | }; 252 | 253 | typedef struct 254 | { 255 | float x, y; 256 | } nmd_vec2; 257 | 258 | typedef struct 259 | { 260 | float x, y, z; 261 | } nmd_vec3; 262 | 263 | typedef struct 264 | { 265 | nmd_vec2 p0; 266 | nmd_vec2 p1; 267 | } nmd_rect; 268 | 269 | typedef struct 270 | { 271 | /* 'num_vertices' has the type 'nmd_index' because the number of vertices is always less or equal the number of indices. */ 272 | nmd_index num_vertices; 273 | 274 | nmd_index num_indices; 275 | nmd_tex_id user_texture_id; 276 | 277 | nmd_rect rect; 278 | 279 | } nmd_draw_command; 280 | 281 | typedef struct 282 | { 283 | uint8_t r, g, b, a; 284 | } nmd_color; 285 | 286 | typedef struct 287 | { 288 | nmd_vec2 pos; 289 | nmd_vec2 uv; 290 | nmd_color color; 291 | } nmd_vertex; 292 | 293 | /* Describes a texture atlas */ 294 | typedef struct 295 | { 296 | int width; 297 | int height; 298 | uint8_t* pixels8; 299 | nmd_color* pixels32; 300 | void* baked_chars; /* internal */ 301 | nmd_tex_id font_id; 302 | } nmd_atlas; 303 | 304 | typedef struct 305 | { 306 | bool line_anti_aliasing; /* If true, all lines will have AA applied to them. */ 307 | bool fill_anti_aliasing; /* If true, all filled polygons will have AA applied to them. */ 308 | 309 | nmd_vec2 cached_circle_vertices12[12]; 310 | uint8_t cached_circle_segment_counts64[64]; 311 | float curve_tessellation_tolerance; 312 | 313 | nmd_vec2* path; 314 | size_t num_points; /* number of points('nmd_vec2') in the 'path' buffer. */ 315 | size_t path_capacity; /* size of the 'path' buffer in bytes. */ 316 | 317 | nmd_vertex* vertices; 318 | size_t num_vertices; /* number of vertices in the 'vertices' buffer. */ 319 | size_t vertices_capacity; /* size of the 'vertices' buffer in bytes. */ 320 | 321 | nmd_index* indices; 322 | size_t num_indices; /* number of indices in the 'indices' buffer. */ 323 | size_t indices_capacity; /* size of the 'indices' buffer in bytes. */ 324 | 325 | nmd_draw_command* draw_commands; 326 | size_t num_draw_commands; /* number of draw commands in the 'draw_commands' buffer. */ 327 | size_t draw_commands_capacity; /* size of the 'draw_commands' buffer in bytes. */ 328 | 329 | nmd_atlas default_atlas; 330 | nmd_tex_id blank_tex_id; 331 | 332 | /* 333 | void PathBezierCurveTo(const Vec2& p2, const Vec2& p3, const Vec2& p4, size_t num_segments);*/ 334 | } nmd_drawlist; 335 | 336 | typedef struct 337 | { 338 | uint32_t id; /* A 32-bit number that identifies the window */ 339 | nmd_rect rect; /* Specifies the area that the windows lies */ 340 | bool visible; /* True if the window is visible */ 341 | bool moving; /* True if the window is being moved by the mouse */ 342 | bool collapsed; /* True if the window is collapsed */ 343 | bool allow_close; /* The has a close button and can be closed(visble=0) */ 344 | bool allow_move_title_bar; /* The window can be moved when the mouse drags the title bar */ 345 | bool allow_move_body; /* The window can be moved when the mouse drags the window's body */ 346 | bool allow_collapse; /* The window has a collpse button and can be collapsed */ 347 | bool allow_resize; /* The window can be resized */ 348 | int y_offset; 349 | } nmd_window; 350 | 351 | typedef struct 352 | { 353 | /* The position of the mouse relative to the window */ 354 | nmd_vec2 mouse_pos; 355 | 356 | /* The state of keyboard keys */ 357 | bool keys_down[256]; 358 | 359 | /* The state of mouse's buttons 360 | mouse_down[0]: left button 361 | mouse_down[1]: right button 362 | mouse_down[2]: middle button 363 | mouse_down[3]/mouse_down[4]: special buttons 364 | */ 365 | bool mouse_down[5]; 366 | 367 | bool mouse_released[5]; /* Mouse was released. nmd_end_frame() clears this array, so it's only used one frame */ 368 | nmd_vec2 mouse_clicked_pos[5]; /* Position when mouse button was clicked */ 369 | 370 | nmd_vec2 window_move_delta; /* The delta pos between the top left corner of the window being moved and the mouse's position when it was pressed*/ 371 | } nmd_io; 372 | 373 | typedef struct 374 | { 375 | nmd_window* window; /* The current window being accessed */ 376 | nmd_window* windows; /* An array of windows */ 377 | size_t num_windows; /* The number of windows in the 'windows' array */ 378 | size_t windows_capacity; /* The capacity of the 'windows' array */ 379 | nmd_vec2 window_pos; /* The window's initial position */ 380 | char fmt_buffer[1024]; /* temporary buffer */ 381 | } nmd_gui; 382 | 383 | typedef struct 384 | { 385 | nmd_drawlist draw_list; /* Vertices, indices, draw commands */ 386 | nmd_io io; /* IO data */ 387 | nmd_gui gui; /* Windows, gui related data */ 388 | 389 | #ifdef _WIN32 390 | HWND hWnd; 391 | #endif /* _WIN32*/ 392 | } nmd_context; 393 | 394 | #ifdef _WIN32 395 | void nmd_win32_set_hwnd(HWND hWnd); 396 | #endif /* _WIN32*/ 397 | 398 | void nmd_path_to(float x0, float y0); 399 | void nmd_path_rect(float x0, float y0, float x1, float y1, float rounding, uint32_t rounding_corners); 400 | 401 | /* 402 | 'start_at_center' places the first vertex at the center, this can be used to create a pie chart when using nmd_path_fill_convex(). 403 | This functions uses twelve(12) chached vertices initialized during startup, it should be faster than PathArcTo. 404 | */ 405 | void nmd_path_arc_to_cached(float x0, float y0, float radius, size_t start_angle_of12, size_t end_angle_of12, bool start_at_center); 406 | void nmd_path_arc_to(float x0, float y0, float radius, float start_angle, float end_angle, size_t num_segments, bool start_at_center); 407 | 408 | void nmd_path_fill_convex(nmd_color color); 409 | void nmd_path_stroke(nmd_color color, bool closed, float thickness); 410 | 411 | void nmd_add_line(float x0, float y0, float x1, float y1, nmd_color color, float thickness); 412 | 413 | void nmd_add_rect(float x0, float y0, float x1, float y1, nmd_color color, float rounding, uint32_t corner_flags, float thickness); 414 | void nmd_add_rect_filled(float x0, float y0, float x1, float y1, nmd_color color, float rounding, uint32_t corner_flags); 415 | void nmd_add_rect_filled_multi_color(float x0, float y0, float x1, float y1, nmd_color color_upper_left, nmd_color color_upper_right, nmd_color color_bottom_right, nmd_color color_bottom_left); 416 | 417 | void nmd_add_quad(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, nmd_color color, float thickness); 418 | void nmd_add_quad_filled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, nmd_color color); 419 | 420 | void nmd_add_triangle(float x0, float y0, float x1, float y1, float x2, float y2, nmd_color color, float thickness); 421 | void nmd_add_triangle_filled(float x0, float y0, float x1, float y1, float x2, float y2, nmd_color color); 422 | 423 | void nmd_add_dummy_text(float x, float y, const char* text, float height, nmd_color color, float spacing); 424 | 425 | /* 426 | Set num_segments to zero if you want the function to automatically determine the number of segmnts. 427 | num_segments = 12 428 | */ 429 | void nmd_add_circle(float x0, float y0, float radius, nmd_color color, size_t num_segments, float thickness); 430 | void nmd_add_circle_filled(float x0, float y0, float radius, nmd_color color, size_t num_segments); 431 | 432 | void nmd_add_ngon(float x0, float y0, float radius, nmd_color color, size_t num_segments, float thickness); 433 | void nmd_add_ngon_filled(float x0, float y0, float radius, nmd_color color, size_t num_segments); 434 | 435 | void nmd_add_polyline(const nmd_vec2* points, size_t num_points, nmd_color color, bool closed, float thickness); 436 | void nmd_add_convex_polygon_filled(const nmd_vec2* points, size_t num_points, nmd_color color); 437 | /*void nmd_add_bezier_curve(nmd_vec2 p0, nmd_vec2 p1, nmd_vec2 p2, nmd_vec2 p3, nmd_color color, float thickness, size_t num_segments);*/ 438 | 439 | /*void nmd_add_text(float x, float y, const char* text, nmd_color color);*/ 440 | void nmd_get_text_size(const nmd_atlas* font, const char* text, const char* text_end, nmd_vec2* size_out); 441 | void nmd_add_text(const nmd_atlas* font, float x, float y, const char* text, const char* text_end, nmd_color color); 442 | 443 | void nmd_add_image(nmd_tex_id user_texture_id, float x0, float y0, float x1, float y1, nmd_color color); 444 | void nmd_add_image_uv(nmd_tex_id user_texture_id, float x0, float y0, float x1, float y1, float uv_x0, float uv_y0, float uv_x1, float uv_y1, nmd_color color); 445 | 446 | void nmd_add_image_quad(nmd_tex_id user_texture_id, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, nmd_color color); 447 | void nmd_add_image_quad_uv(nmd_tex_id user_texture_id, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float uv_x0, float uv_y0, float uv_x1, float uv_y1, float uv_x2, float uv_y2, float uv_x3, float uv_y3, nmd_color color); 448 | 449 | void nmd_add_image_rounded(nmd_tex_id user_texture_id, float x0, float y0, float x1, float y1, float rounding, uint32_t corner_flags, nmd_color color); 450 | void nmd_add_image_rounded_uv(nmd_tex_id user_texture_id, float x0, float y0, float x1, float y1, float rounding, uint32_t corner_flags, float uv_x0, float uv_y0, float uv_x1, float uv_y1, nmd_color color); 451 | 452 | void nmd_prim_rect_uv(float x0, float y0, float x1, float y1, float uv_x0, float uv_y0, float uv_x1, float uv_y1, nmd_color color); 453 | void nmd_prim_quad_uv(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float uv_x0, float uv_y0, float uv_x1, float uv_y1, float uv_x2, float uv_y2, float uv_x3, float uv_y3, nmd_color color); 454 | 455 | nmd_color nmd_rgb(uint8_t r, uint8_t g, uint8_t b); 456 | nmd_color nmd_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); 457 | 458 | nmd_context* nmd_get_context(); 459 | 460 | /* Specifies the begin of the window. Widgets can be added after calling this function. Returns true if the window is not minimized */ 461 | bool nmd_begin(const char* window_name); 462 | 463 | /* Specifies the end of the window. Widgets won't be added after calling this function */ 464 | void nmd_end(); 465 | 466 | /* Appends text to the window. Be careful, the formatted string must not exceed 1024 bytes + null terminator */ 467 | void nmd_text(const char* fmt, ...); 468 | 469 | /* Adds a button widget. Returns true if the button is clicked */ 470 | bool nmd_button(const char* label); 471 | 472 | /* Adds a checkbox widget. Returns true if the checkbox state changes. */ 473 | bool nmd_checkbox(const char* label, bool* checked); 474 | 475 | /* Adds a float slider widget. Returns true if the value changes. */ 476 | bool nmd_slider_float(const char* label, float* value, float min_value, float max_value); 477 | 478 | /* Starts a new empty scene/frame. Internally this function clears all vertices, indices and command buffers. */ 479 | void nmd_new_frame(); 480 | 481 | /* "Ends" a frame. Wrapper around nmd_push_draw_command(). */ 482 | void nmd_end_frame(); 483 | 484 | /* 485 | Creates one or more draw commands for the unaccounted vertices and indices. 486 | Parameters: 487 | clip_rect [opt/in] A pointer to a rect that specifies the clip area. This parameter can be null. 488 | */ 489 | void nmd_push_draw_command(const nmd_rect* clip_rect); 490 | 491 | void nmd_push_texture_draw_command(nmd_tex_id user_texture_id, const nmd_rect* clip_rect); 492 | 493 | bool nmd_bake_font_from_memory(const void* font_data, nmd_atlas* atlas, float size); 494 | 495 | bool nmd_bake_font(const char* font_path, nmd_atlas* atlas, float size); 496 | 497 | #define NMD_COLOR_BLACK nmd_rgb( 0, 0, 0) 498 | #define NMD_COLOR_WHITE nmd_rgb(255, 255, 255) 499 | #define NMD_COLOR_RED nmd_rgb(255, 0, 0) 500 | #define NMD_COLOR_GREEN nmd_rgb( 0, 255, 0) 501 | #define NMD_COLOR_BLUE nmd_rgb( 0, 0, 255) 502 | #define NMD_COLOR_ORANGE nmd_rgb(255, 165, 0) 503 | #define NMD_COLOR_AMBER nmd_rgb(255, 191, 0) 504 | #define NMD_COLOR_ANDROID_GREEN nmd_rgb(164, 198, 57) 505 | #define NMD_COLOR_AZURE nmd_rgb( 0, 127, 255) 506 | #define NMD_COLOR_BRONZE nmd_rgb(205, 127, 50) 507 | #define NMD_COLOR_CORN nmd_rgb(251, 236, 93) 508 | #define NMD_COLOR_EMERALD nmd_rgb( 80, 200, 120) 509 | #define NMD_COLOR_LAPIS_LAZULI nmd_rgb( 38, 97, 156) 510 | #define NMD_COLOR_LAVA nmd_rgb(207, 16, 32) 511 | 512 | #define NMD_COLOR_GUI_MAIN nmd_rgb( 58, 109, 41) 513 | #define NMD_COLOR_GUI_WIDGET_BACKGROUND nmd_rgb( 38, 66, 29) 514 | #define NMD_COLOR_GUI_WIDGET_HOVER nmd_rgb( 51, 91, 37) 515 | #define NMD_COLOR_GUI_BUTTON_BACKGROUND NMD_COLOR_GUI_WIDGET_HOVER 516 | #define NMD_COLOR_GUI_BUTTON_HOVER nmd_rgb( 60, 122, 37) 517 | #define NMD_COLOR_GUI_HOVER nmd_rgb( 91, 178, 62) 518 | #define NMD_COLOR_GUI_PRESSED nmd_rgb( 69, 160, 38) 519 | #define NMD_COLOR_GUI_ACTIVE nmd_rgb( 53, 160, 17) 520 | #define NMD_COLOR_GUI_BACKGROUND nmd_rgb( 20, 20, 20) 521 | 522 | #endif /* NMD_GRAPHICS_H */ 523 | -------------------------------------------------------------------------------- /graphics/nmd_gui.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | #ifdef _WIN32 4 | LRESULT nmd_win32_wnd_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 5 | { 6 | if (!_nmd_context.hWnd && uMsg == WM_MOUSEMOVE) 7 | { 8 | _nmd_context.io.mouse_pos.x = ((int)(short)LOWORD(lParam)); 9 | _nmd_context.io.mouse_pos.y = ((int)(short)HIWORD(lParam)); 10 | } 11 | 12 | /* Handle raw input */ 13 | if (uMsg == WM_INPUT) 14 | { 15 | RAWINPUT ri; 16 | UINT sz = sizeof(RAWINPUT); 17 | if (GetRawInputData((HRAWINPUT)lParam, RID_HEADER, &ri, &sz, sizeof(RAWINPUTHEADER)) > 0) 18 | { 19 | if (ri.header.dwType == RIM_TYPEMOUSE) 20 | { 21 | if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &ri, &sz, sizeof(RAWINPUTHEADER)) > 0) 22 | { 23 | if (ri.data.mouse.usFlags == MOUSE_MOVE_RELATIVE) 24 | { 25 | _nmd_context.io.mouse_pos.x += (float)ri.data.mouse.lLastX; 26 | _nmd_context.io.mouse_pos.y += (float)ri.data.mouse.lLastY; 27 | 28 | if (ri.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) 29 | _nmd_context.io.mouse_down[0] = true, _nmd_context.io.mouse_clicked_pos[0] = _nmd_context.io.mouse_pos; 30 | else if (ri.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) 31 | _nmd_context.io.mouse_down[0] = false, _nmd_context.io.mouse_released[0] = true; 32 | if (ri.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) 33 | _nmd_context.io.mouse_down[1] = true, _nmd_context.io.mouse_clicked_pos[1] = _nmd_context.io.mouse_pos; 34 | else if (ri.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) 35 | _nmd_context.io.mouse_down[1] = false, _nmd_context.io.mouse_released[1] = true; 36 | if (ri.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) 37 | _nmd_context.io.mouse_down[2] = true, _nmd_context.io.mouse_clicked_pos[2] = _nmd_context.io.mouse_pos; 38 | else if (ri.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) 39 | _nmd_context.io.mouse_down[2] = false, _nmd_context.io.mouse_released[2] = true; 40 | } 41 | } 42 | } 43 | } 44 | } 45 | 46 | switch (uMsg) 47 | { 48 | /* Handle keyboard keys */ 49 | case WM_KEYDOWN: 50 | case WM_SYSKEYDOWN: 51 | if(wParam < 256) 52 | _nmd_context.io.keys_down[wParam] = true; 53 | return 0; 54 | case WM_KEYUP: 55 | case WM_SYSKEYUP: 56 | if (wParam < 256) 57 | _nmd_context.io.keys_down[wParam] = false; 58 | return 0; 59 | 60 | /* Handle mouse buttons */ 61 | case WM_LBUTTONDOWN: _nmd_context.io.mouse_down[0] = true; _nmd_context.io.mouse_clicked_pos[0] = _nmd_context.io.mouse_pos; return 0; 62 | case WM_LBUTTONUP: _nmd_context.io.mouse_down[0] = false; _nmd_context.io.mouse_released[0] = true; return 0; 63 | 64 | case WM_RBUTTONDOWN: _nmd_context.io.mouse_down[1] = true; _nmd_context.io.mouse_clicked_pos[1] = _nmd_context.io.mouse_pos; return 0; 65 | case WM_RBUTTONUP: _nmd_context.io.mouse_down[1] = false; _nmd_context.io.mouse_released[1] = true; return 0; 66 | 67 | case WM_MBUTTONDOWN: _nmd_context.io.mouse_down[2] = true; _nmd_context.io.mouse_clicked_pos[2] = _nmd_context.io.mouse_pos; return 0; 68 | case WM_MBUTTONUP: _nmd_context.io.mouse_down[2] = false; _nmd_context.io.mouse_released[2] = true; return 0; 69 | 70 | case WM_XBUTTONDOWN: _nmd_context.io.mouse_down[GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 3 : 4] = true; return 0; 71 | case WM_XBUTTONUP: _nmd_context.io.mouse_down[GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 3 : 4] = false; return 0; 72 | } 73 | 74 | return 0; 75 | } 76 | #endif /* _WIN32 */ 77 | 78 | /* This is a very simple hash function which takes a string and returns a 32-bit number which should be unique for the string */ 79 | uint32_t _nmd_hash_string_to_uint32(const char* string) 80 | { 81 | if (!*string) 82 | return 0; 83 | 84 | /* Starting hash */ 85 | uint32_t hash = 0xDEADC0DE + *string; 86 | 87 | /* This 2-byte pointer is used to constantly shift between different parts of 'hash' */ 88 | uint16_t* p; 89 | 90 | for (size_t i = 1; string[i]; i++) 91 | { 92 | /* 93 | If 'i' modulo 3 is 0, then point to the first and second bytes of 'hash' 94 | If 'i' modulo 3 is 1, then point to the second and third bytes of 'hash' 95 | If 'i' modulo 3 is 2, then point to the third and fourth bytes of 'hash' 96 | */ 97 | p = (uint16_t*)((uint8_t*)&hash+(i%3)); 98 | 99 | /* Do some random XOR between the two bytes pointed by 'p' and string[i] and string[i -1] */ 100 | *p = *p ^ ((string[i - 1] << 8) | string[i]); 101 | } 102 | 103 | return hash; 104 | } 105 | 106 | /* Iterates through all windows in the global context and return the window that has the ID equal to 'window_hash' */ 107 | nmd_window* _nmd_find_window_by_hash(uint32_t window_hash) 108 | { 109 | for (size_t i = 0; i < _nmd_context.gui.num_windows; i++) 110 | { 111 | if (_nmd_context.gui.windows[i].id == window_hash) 112 | return _nmd_context.gui.windows + i; 113 | } 114 | 115 | return 0; 116 | } 117 | 118 | /* Helper function. Wrapper around '_nmd_find_window_by_hash' but it takes a string */ 119 | nmd_window* _nmd_find_window_by_name(const char* window_name) 120 | { 121 | return _nmd_find_window_by_hash(_nmd_hash_string_to_uint32(window_name)); 122 | } 123 | 124 | /* Specifies the beginning of the window. Widgets can be added after calling this function. Returns true if the window is not minimized */ 125 | bool nmd_begin(const char* window_name) 126 | { 127 | nmd_window* window = _nmd_find_window_by_name(window_name); 128 | if (!window) 129 | { 130 | /* Add window */ 131 | 132 | /* Check if we need to resize the buffer */ 133 | if (_nmd_context.gui.num_windows == _nmd_context.gui.windows_capacity) 134 | { 135 | _nmd_context.gui.windows_capacity *= 2; 136 | void* mem = NMD_MALLOC(_nmd_context.gui.windows_capacity); 137 | if (!mem) 138 | return false; 139 | NMD_MEMCPY(mem, _nmd_context.gui.windows, _nmd_context.gui.num_windows); 140 | NMD_FREE(_nmd_context.gui.windows); 141 | } 142 | 143 | window = &_nmd_context.gui.windows[_nmd_context.gui.num_windows++]; 144 | window->id = _nmd_hash_string_to_uint32(window_name); 145 | window->rect.p0 = _nmd_context.gui.window_pos; 146 | window->rect.p1.x = window->rect.p0.x + 250; 147 | window->rect.p1.y = window->rect.p0.y + 230; 148 | window->visible = true; 149 | window->collapsed = false; 150 | window->allow_close = _nmd_context.gui.num_windows == 0 ? false : true; 151 | window->allow_collapse = true; 152 | window->allow_move_title_bar = true; 153 | window->allow_move_body = true; 154 | window->allow_resize = true; 155 | window->moving = false; 156 | } 157 | 158 | _nmd_context.gui.window = window; 159 | 160 | if (!window->visible) 161 | return false; 162 | 163 | if (window->moving) 164 | { 165 | if (_nmd_context.io.mouse_down[0]) 166 | { 167 | /* Move window */ 168 | const int width = window->rect.p1.x - window->rect.p0.x; 169 | const int height = window->rect.p1.y - window->rect.p0.y; 170 | 171 | window->rect.p0.x = _nmd_context.io.mouse_pos.x - _nmd_context.io.window_move_delta.x; 172 | window->rect.p0.y = _nmd_context.io.mouse_pos.y - _nmd_context.io.window_move_delta.y; 173 | window->rect.p1.x = window->rect.p0.x + width; 174 | window->rect.p1.y = window->rect.p0.y + height; 175 | } 176 | else 177 | window->moving = false; 178 | } 179 | 180 | /* Add top bar's background filled rect */ 181 | nmd_add_rect_filled(window->rect.p0.x, window->rect.p0.y, window->rect.p1.x, window->rect.p0.y + 18.0f, NMD_COLOR_GUI_MAIN, 5.0f, window->collapsed ? NMD_CORNER_ALL : NMD_CORNER_TOP); 182 | 183 | /* Add window name */ 184 | nmd_add_text(&_nmd_context.draw_list.default_atlas, window->rect.p0.x + (window->allow_collapse ? 20 : 0), window->rect.p0.y + 13, window_name, 0, NMD_COLOR_WHITE); 185 | 186 | /* Check if window can be collapsed and if the mouse is over the collapse/expand triangle */ 187 | if (window->allow_collapse && _nmd_context.io.mouse_pos.x >= window->rect.p0.x + 1 && _nmd_context.io.mouse_pos.x < window->rect.p0.x + 17 && _nmd_context.io.mouse_pos.y >= window->rect.p0.y + 1 && _nmd_context.io.mouse_pos.y < window->rect.p0.y + 17) 188 | { 189 | /* Check if we properly clicked the triangle */ 190 | if (_nmd_context.io.mouse_released[0]) 191 | { 192 | if (_nmd_context.io.mouse_clicked_pos[0].x >= window->rect.p0.x + 1 && _nmd_context.io.mouse_clicked_pos[0].x < window->rect.p0.x + 17 && _nmd_context.io.mouse_clicked_pos[0].y >= window->rect.p0.y + 1 && _nmd_context.io.mouse_clicked_pos[0].y < window->rect.p0.y + 17) 193 | window->collapsed = !window->collapsed; 194 | } 195 | 196 | /* Add filled circle behind triangle */ 197 | nmd_add_circle_filled(window->rect.p0.x + 9.0f, window->rect.p0.y + 9.0f, 7.5f, _nmd_context.io.mouse_down[0] ? NMD_COLOR_GUI_PRESSED : NMD_COLOR_GUI_HOVER, 12); 198 | } 199 | /* Check if the window can be closed and if the mouse is over the close button */ 200 | else if (window->allow_close && _nmd_context.io.mouse_pos.x >= window->rect.p1.x - 17 && _nmd_context.io.mouse_pos.x < window->rect.p1.x - 1 && _nmd_context.io.mouse_pos.y >= window->rect.p0.y + 1 && _nmd_context.io.mouse_pos.y < window->rect.p0.y + 17) 201 | { 202 | /* Check if we properly clicked the close button */ 203 | if (_nmd_context.io.mouse_released[0]) 204 | { 205 | if (_nmd_context.io.mouse_clicked_pos[0].x >= window->rect.p1.x - 10 && _nmd_context.io.mouse_clicked_pos[0].x < window->rect.p1.x - 1 && _nmd_context.io.mouse_clicked_pos[0].y >= window->rect.p0.y + 1 && _nmd_context.io.mouse_clicked_pos[0].y < window->rect.p0.y + 17) 206 | window->visible = false; 207 | } 208 | 209 | /* Add filled circle behind triangle */ 210 | nmd_add_circle_filled(window->rect.p1.x - 9.5f, window->rect.p0.y + 9.0f, 7.5f, _nmd_context.io.mouse_down[0] ? NMD_COLOR_GUI_PRESSED : NMD_COLOR_GUI_HOVER, 12); 211 | } 212 | /* Check if the window's title bar can be dragged and if the mouse is over the title bar */ 213 | else if (window->allow_move_title_bar && _nmd_context.io.mouse_pos.x >= window->rect.p0.x && _nmd_context.io.mouse_pos.x < window->rect.p1.x && _nmd_context.io.mouse_pos.y >= window->rect.p0.y && _nmd_context.io.mouse_pos.y < window->rect.p0.y + 18.0f && !window->moving) 214 | { 215 | /* Determine if the window is being moved */ 216 | window->moving = _nmd_context.io.mouse_down[0]; 217 | if (window->moving) 218 | { 219 | _nmd_context.io.window_move_delta.x = _nmd_context.io.mouse_pos.x - window->rect.p0.x; 220 | _nmd_context.io.window_move_delta.y = _nmd_context.io.mouse_pos.y - window->rect.p0.y; 221 | } 222 | } 223 | 224 | if (window->allow_close) 225 | { 226 | /* Add close cross("button)" to the top right corner */ 227 | nmd_add_line(window->rect.p1.x - 13, window->rect.p0.y + 5.0f, window->rect.p1.x - 5.9f, window->rect.p0.y + 12.1f, NMD_COLOR_WHITE, 1.0f); 228 | nmd_add_line(window->rect.p1.x - 13, window->rect.p0.y + 12.0f, window->rect.p1.x - 5.9f, window->rect.p0.y + 4.9f, NMD_COLOR_WHITE, 1.0f); 229 | } 230 | 231 | /* Return 'false' if the window is mimized, this tells the user he shouldn't call any widgets */ 232 | if (window->collapsed) 233 | { 234 | /* Add triangle facing right */ 235 | nmd_add_triangle_filled(window->rect.p0.x + 6, window->rect.p0.y + 5, window->rect.p0.x + 15, window->rect.p0.y + 9, window->rect.p0.x + 6, window->rect.p0.y + 13, NMD_COLOR_WHITE); 236 | return false; 237 | } 238 | else 239 | { 240 | if (window->allow_collapse) 241 | { 242 | /* Add triangle facing bottom */ 243 | nmd_add_triangle_filled(window->rect.p0.x + 5, window->rect.p0.y + 5, window->rect.p0.x + 13, window->rect.p0.y + 5, window->rect.p0.x + 9, window->rect.p0.y + 14, NMD_COLOR_WHITE); 244 | } 245 | } 246 | 247 | /* Add body's background filled rect */ 248 | nmd_add_rect_filled(window->rect.p0.x, window->rect.p0.y + 18.0f, window->rect.p1.x, window->rect.p1.y, NMD_COLOR_GUI_BACKGROUND, 5.0f, NMD_CORNER_BOTTOM); 249 | 250 | window->y_offset = window->rect.p0.y + 18 + 6; 251 | 252 | return true; 253 | } 254 | 255 | /* Specifies the end of the window. Widgets won't be added after calling this function */ 256 | void nmd_end() 257 | { 258 | _nmd_context.gui.window = 0; 259 | } 260 | 261 | void nmd_text(const char* fmt, ...) 262 | { 263 | /* Make sure we can draw this widget */ 264 | nmd_window* window = _nmd_context.gui.window; 265 | if (!window->visible || window->collapsed) 266 | return; 267 | 268 | va_list args; 269 | va_start(args, fmt); 270 | const int size = NMD_VSPRINTF(_nmd_context.gui.fmt_buffer, fmt, args); 271 | va_end(args); 272 | 273 | nmd_add_text(&_nmd_context.draw_list.default_atlas, window->rect.p0.x + 6, window->y_offset + 10, _nmd_context.gui.fmt_buffer, _nmd_context.gui.fmt_buffer + size, NMD_COLOR_WHITE); 274 | 275 | window->y_offset += 10 + 5; 276 | } 277 | 278 | bool nmd_button(const char* label) 279 | { 280 | /* Make sure we can draw this widget */ 281 | nmd_window* window = _nmd_context.gui.window; 282 | if (!window->visible || window->collapsed) 283 | return false; 284 | 285 | nmd_vec2 size; 286 | nmd_get_text_size(&_nmd_context.draw_list.default_atlas, label, 0, &size); 287 | 288 | const bool is_mouse_hovering = _nmd_context.io.mouse_pos.x >= window->rect.p0.x + 6 && _nmd_context.io.mouse_pos.x < window->rect.p0.x + 6 + size.x + 8 && _nmd_context.io.mouse_pos.y >= window->y_offset && _nmd_context.io.mouse_pos.y < window->y_offset + 16; 289 | 290 | const bool clicked_button = is_mouse_hovering && _nmd_context.io.mouse_released[0] && _nmd_context.io.mouse_clicked_pos[0].x >= window->rect.p0.x + 6 && _nmd_context.io.mouse_clicked_pos[0].x < window->rect.p0.x + 6 + size.x + 8 && _nmd_context.io.mouse_clicked_pos[0].y >= window->y_offset && _nmd_context.io.mouse_clicked_pos[0].y < window->y_offset + 16; 291 | 292 | /* Add background filled rect */ 293 | nmd_add_rect_filled(window->rect.p0.x + 6, window->y_offset, window->rect.p0.x + 6 + size.x + 8, window->y_offset + 16, is_mouse_hovering ? NMD_COLOR_GUI_BUTTON_HOVER : NMD_COLOR_GUI_BUTTON_BACKGROUND, 0, 0); 294 | 295 | nmd_add_text(&_nmd_context.draw_list.default_atlas, window->rect.p0.x + 6 + 4, window->y_offset + 11, label, 0, NMD_COLOR_WHITE); 296 | 297 | window->y_offset += 16 + 5; 298 | 299 | return clicked_button; 300 | } 301 | 302 | bool nmd_checkbox(const char* label, bool* checked) 303 | { 304 | /* Make sure we can draw this widget */ 305 | nmd_window* window = _nmd_context.gui.window; 306 | if (!window->visible || window->collapsed) 307 | return false; 308 | 309 | const bool is_mouse_hovering = _nmd_context.io.mouse_pos.x >= window->rect.p0.x + 6 && _nmd_context.io.mouse_pos.x < window->rect.p0.x + 6 + 16 && _nmd_context.io.mouse_pos.y >= window->y_offset && _nmd_context.io.mouse_pos.y < window->y_offset + 16; 310 | 311 | bool state_changed = false; 312 | 313 | if (is_mouse_hovering && _nmd_context.io.mouse_released[0] && _nmd_context.io.mouse_clicked_pos[0].x >= window->rect.p0.x + 6 && _nmd_context.io.mouse_clicked_pos[0].x < window->rect.p0.x + 6 + 16 && _nmd_context.io.mouse_clicked_pos[0].y >= window->y_offset && _nmd_context.io.mouse_clicked_pos[0].y < window->y_offset + 16) 314 | { 315 | *checked = !*checked; 316 | state_changed = true; 317 | } 318 | 319 | /* Add background filled rect */ 320 | nmd_add_rect_filled(window->rect.p0.x + 6, window->y_offset, window->rect.p0.x + 6 + 16, window->y_offset + 16, is_mouse_hovering ? NMD_COLOR_GUI_WIDGET_HOVER : NMD_COLOR_GUI_WIDGET_BACKGROUND, 0, 0); 321 | 322 | /* Add filled square if 'state' is true */ 323 | if (*checked) 324 | nmd_add_rect_filled(window->rect.p0.x + 6 + 3, window->y_offset + 3, window->rect.p0.x + 6 + 16 - 3, window->y_offset + 16 - 3, NMD_COLOR_GUI_ACTIVE, 0, 0); 325 | 326 | window->y_offset += 16 + 4; 327 | 328 | nmd_add_text(&_nmd_context.draw_list.default_atlas, window->rect.p0.x + 6 + 16 + 4, window->y_offset - 9, label, 0, NMD_COLOR_WHITE); 329 | 330 | return state_changed; 331 | } 332 | 333 | #define _NMD_SLIDER_WIDTH 160 334 | bool nmd_slider_float(const char* label, float* value, float min_value, float max_value) 335 | { 336 | /* Make sure we can draw this widget */ 337 | nmd_window* window = _nmd_context.gui.window; 338 | if (!window->visible || window->collapsed || *value < min_value || *value > max_value) 339 | return false; 340 | 341 | float offset; 342 | 343 | bool value_changed = false; 344 | 345 | /* Check if the user is sliding the slider */ 346 | if (_nmd_context.io.mouse_down[0] && _nmd_context.io.mouse_clicked_pos[0].x >= window->rect.p0.x + 6 && _nmd_context.io.mouse_clicked_pos[0].x < window->rect.p0.x + 6 + _NMD_SLIDER_WIDTH && _nmd_context.io.mouse_clicked_pos[0].y >= window->y_offset && _nmd_context.io.mouse_clicked_pos[0].y < window->y_offset + 16) 347 | { 348 | const float last_value = *value; 349 | 350 | /* Calculte the new offset */ 351 | if (_nmd_context.io.mouse_pos.x < window->rect.p0.x + 6 + 6) 352 | { 353 | offset = 0; 354 | *value = min_value; 355 | } 356 | else if (_nmd_context.io.mouse_pos.x >= window->rect.p0.x + 6 + _NMD_SLIDER_WIDTH - 6) 357 | { 358 | offset = _NMD_SLIDER_WIDTH - 12; 359 | *value = max_value; 360 | } 361 | else 362 | { 363 | offset = _nmd_context.io.mouse_pos.x - (window->rect.p0.x + 6) - 6; 364 | *value = (offset / (_NMD_SLIDER_WIDTH -6)) * (max_value - min_value) + min_value; 365 | } 366 | 367 | if (*value != last_value) 368 | value_changed = true; 369 | } 370 | else 371 | { 372 | if (*value == max_value) 373 | offset = _NMD_SLIDER_WIDTH - 12; 374 | else 375 | offset = ((*value - min_value) / (max_value - min_value)) * (_NMD_SLIDER_WIDTH - 6); 376 | } 377 | //offset = (*value / max_value) * (120-12) - min_value; 378 | 379 | const bool is_mouse_hovering = _nmd_context.io.mouse_pos.x >= window->rect.p0.x + 6 && _nmd_context.io.mouse_pos.x < window->rect.p0.x + 6 + _NMD_SLIDER_WIDTH && _nmd_context.io.mouse_pos.y >= window->y_offset && _nmd_context.io.mouse_pos.y < window->y_offset + 16; 380 | 381 | /* Add background filled rect */ 382 | nmd_add_rect_filled(window->rect.p0.x + 6, window->y_offset, window->rect.p0.x + 6 + _NMD_SLIDER_WIDTH, window->y_offset + 16, is_mouse_hovering ? NMD_COLOR_GUI_WIDGET_HOVER : NMD_COLOR_GUI_WIDGET_BACKGROUND, 0, 0); 383 | 384 | /* Add indicator bar */ 385 | nmd_add_rect_filled(window->rect.p0.x + 6 + 2 + offset, window->y_offset + 2, window->rect.p0.x + 6 + 2 + offset + 8, window->y_offset + 16 - 2, NMD_COLOR_GUI_ACTIVE, 0, 0); 386 | 387 | /* Add value text */ 388 | const int size = NMD_SPRINTF(_nmd_context.gui.fmt_buffer, "%.3f", *value); 389 | nmd_add_text(&_nmd_context.draw_list.default_atlas, window->rect.p0.x + 6 + (_NMD_SLIDER_WIDTH/2-15), window->y_offset + 12, _nmd_context.gui.fmt_buffer, _nmd_context.gui.fmt_buffer + size, NMD_COLOR_WHITE); 390 | 391 | /* Add label text */ 392 | nmd_add_text(&_nmd_context.draw_list.default_atlas, window->rect.p0.x + 6 + _NMD_SLIDER_WIDTH + 4, window->y_offset + 12, label, 0, NMD_COLOR_WHITE); 393 | 394 | window->y_offset += 16 + 5; 395 | 396 | return value_changed; 397 | } -------------------------------------------------------------------------------- /graphics/nmd_renderer_d3d11.cpp: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | #ifdef NMD_GRAPHICS_D3D11 4 | 5 | #pragma comment(lib, "d3d11") 6 | #include 7 | #pragma comment(lib, "d3dcompiler") 8 | 9 | struct 10 | { 11 | ID3D11Device* device; 12 | ID3D11DeviceContext* device_context; 13 | ID3D11Buffer* vertex_buffer; 14 | ID3D11Buffer* index_buffer; 15 | int vertex_buffer_size = 5000, index_buffer_size = 10000; /*The number of vertices and indices respectively. */ 16 | ID3D11VertexShader* vertex_shader; 17 | ID3D11PixelShader* pixel_shader; 18 | ID3D11InputLayout* input_layout; 19 | D3D11_VIEWPORT viewport; 20 | ID3D11Buffer* const_buffer; 21 | ID3D11SamplerState* font_sampler = NULL; 22 | ID3D11RasterizerState* rasterizer_state; 23 | ID3D11BlendState* blend_state; 24 | ID3D11DepthStencilState* depth_stencil_state; 25 | } _nmd_d3d11; 26 | 27 | void nmd_d3d11_set_device_context(ID3D11DeviceContext* device_context) 28 | { 29 | _nmd_d3d11.device_context = device_context; 30 | _nmd_d3d11.device_context->GetDevice(&_nmd_d3d11.device); 31 | } 32 | 33 | nmd_tex_id nmd_d3d11_create_texture(void* pixels, int width, int height) 34 | { 35 | if (!_nmd_d3d11.device) 36 | return 0; 37 | 38 | D3D11_TEXTURE2D_DESC tex_desc; 39 | NMD_MEMSET(&tex_desc, 0, sizeof(tex_desc)); 40 | tex_desc.Width = width; 41 | tex_desc.Height = height; 42 | tex_desc.MipLevels = 1; 43 | tex_desc.ArraySize = 1; 44 | tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 45 | tex_desc.SampleDesc.Count = 1; 46 | tex_desc.Usage = D3D11_USAGE_DEFAULT; 47 | tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 48 | tex_desc.CPUAccessFlags = 0; 49 | 50 | ID3D11Texture2D* p_texture = NULL; 51 | D3D11_SUBRESOURCE_DATA sub_resource; 52 | sub_resource.pSysMem = pixels; 53 | sub_resource.SysMemPitch = tex_desc.Width * 4; 54 | sub_resource.SysMemSlicePitch = 0; 55 | if(FAILED(_nmd_d3d11.device->CreateTexture2D(&tex_desc, &sub_resource, &p_texture))) 56 | return 0; 57 | 58 | /* Create texture view */ 59 | D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; 60 | NMD_MEMSET(&srv_desc, 0, sizeof(srv_desc)); 61 | srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 62 | srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 63 | srv_desc.Texture2D.MipLevels = tex_desc.MipLevels; 64 | srv_desc.Texture2D.MostDetailedMip = 0; 65 | ID3D11ShaderResourceView* shader_resource_view; 66 | const bool failed = FAILED(_nmd_d3d11.device->CreateShaderResourceView(p_texture, &srv_desc, &shader_resource_view)); 67 | p_texture->Release(); 68 | 69 | return failed ? 0 : (nmd_tex_id)shader_resource_view; 70 | } 71 | 72 | bool _nmd_d3d11_create_objects() 73 | { 74 | _nmd_d3d11.viewport.MinDepth = 0.0f; 75 | _nmd_d3d11.viewport.MaxDepth = 1.0f; 76 | _nmd_d3d11.viewport.TopLeftX = 0.0f; 77 | _nmd_d3d11.viewport.TopLeftY = 0; 78 | 79 | static const char* vertex_shader = 80 | "cbuffer vertexBuffer : register(b0) \ 81 | {\ 82 | float4x4 ProjectionMatrix; \ 83 | };\ 84 | struct VS_INPUT\ 85 | {\ 86 | float2 pos : POSITION;\ 87 | float4 col : COLOR0;\ 88 | float2 uv : TEXCOORD0;\ 89 | };\ 90 | \ 91 | struct PS_INPUT\ 92 | {\ 93 | float4 pos : SV_POSITION;\ 94 | float4 col : COLOR0;\ 95 | float2 uv : TEXCOORD0;\ 96 | };\ 97 | \ 98 | PS_INPUT main(VS_INPUT input)\ 99 | {\ 100 | PS_INPUT output;\ 101 | output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ 102 | output.col = input.col;\ 103 | output.uv = input.uv;\ 104 | return output;\ 105 | }"; 106 | 107 | ID3DBlob* vertex_shader_blob; 108 | if (FAILED(D3DCompile(vertex_shader, NMD_STRLEN(vertex_shader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertex_shader_blob, NULL))) 109 | return false; 110 | 111 | if (FAILED(_nmd_d3d11.device->CreateVertexShader(vertex_shader_blob->GetBufferPointer(), vertex_shader_blob->GetBufferSize(), NULL, &_nmd_d3d11.vertex_shader))) 112 | { 113 | vertex_shader_blob->Release(); 114 | return false; 115 | } 116 | 117 | /* Create the input layout */ 118 | D3D11_INPUT_ELEMENT_DESC local_layout[] = 119 | { 120 | { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)_NMD_OFFSETOF(nmd_vertex, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 121 | { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)_NMD_OFFSETOF(nmd_vertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 122 | { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)_NMD_OFFSETOF(nmd_vertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 123 | }; 124 | 125 | if (FAILED(_nmd_d3d11.device->CreateInputLayout(local_layout, 3, vertex_shader_blob->GetBufferPointer(), vertex_shader_blob->GetBufferSize(), &_nmd_d3d11.input_layout))) 126 | { 127 | vertex_shader_blob->Release(); 128 | return false; 129 | } 130 | 131 | vertex_shader_blob->Release(); 132 | 133 | /* Create the constant buffer */ 134 | D3D11_BUFFER_DESC buffer_desc; 135 | buffer_desc.ByteWidth = sizeof(float) * 4 * 4; 136 | buffer_desc.Usage = D3D11_USAGE_DYNAMIC; 137 | buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 138 | buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 139 | buffer_desc.MiscFlags = 0; 140 | _nmd_d3d11.device->CreateBuffer(&buffer_desc, NULL, &_nmd_d3d11.const_buffer); 141 | 142 | /* Create the pixel shader */ 143 | static const char* pixel_shader = 144 | "struct PS_INPUT\ 145 | {\ 146 | float4 pos : SV_POSITION;\ 147 | float4 col : COLOR0;\ 148 | float2 uv : TEXCOORD0;\ 149 | };\ 150 | sampler sampler0;\ 151 | Texture2D texture0;\ 152 | \ 153 | float4 main(PS_INPUT input) : SV_Target\ 154 | {\ 155 | float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ 156 | return out_col; \ 157 | }"; 158 | 159 | ID3DBlob* pixel_shader_blob; 160 | if (FAILED(D3DCompile(pixel_shader, NMD_STRLEN(pixel_shader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixel_shader_blob, NULL))) 161 | return false; 162 | if (_nmd_d3d11.device->CreatePixelShader(pixel_shader_blob->GetBufferPointer(), pixel_shader_blob->GetBufferSize(), NULL, &_nmd_d3d11.pixel_shader) != S_OK) 163 | { 164 | pixel_shader_blob->Release(); 165 | return false; 166 | } 167 | pixel_shader_blob->Release(); 168 | 169 | /* Create the blending setup */ 170 | D3D11_BLEND_DESC blend_desc; 171 | NMD_MEMSET(&blend_desc, 0, sizeof(blend_desc)); 172 | blend_desc.AlphaToCoverageEnable = false; 173 | blend_desc.RenderTarget[0].BlendEnable = true; 174 | blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; 175 | blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 176 | blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 177 | blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; 178 | blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; 179 | blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 180 | blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 181 | _nmd_d3d11.device->CreateBlendState(&blend_desc, &_nmd_d3d11.blend_state); 182 | 183 | /* Create the rasterizer state */ 184 | D3D11_RASTERIZER_DESC rasterizer_desc; 185 | NMD_MEMSET(&rasterizer_desc, 0, sizeof(rasterizer_desc)); 186 | rasterizer_desc.FillMode = D3D11_FILL_SOLID; 187 | rasterizer_desc.CullMode = D3D11_CULL_NONE; 188 | rasterizer_desc.ScissorEnable = true; 189 | rasterizer_desc.DepthClipEnable = true; 190 | _nmd_d3d11.device->CreateRasterizerState(&rasterizer_desc, &_nmd_d3d11.rasterizer_state); 191 | 192 | /* Create depth-stencil State */ 193 | D3D11_DEPTH_STENCIL_DESC depth_stencil_desc; 194 | NMD_MEMSET(&depth_stencil_desc, 0, sizeof(depth_stencil_desc)); 195 | depth_stencil_desc.DepthEnable = false; 196 | depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 197 | depth_stencil_desc.DepthFunc = D3D11_COMPARISON_ALWAYS; 198 | depth_stencil_desc.StencilEnable = false; 199 | depth_stencil_desc.FrontFace.StencilFailOp = depth_stencil_desc.FrontFace.StencilDepthFailOp = depth_stencil_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 200 | depth_stencil_desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 201 | depth_stencil_desc.BackFace = depth_stencil_desc.FrontFace; 202 | _nmd_d3d11.device->CreateDepthStencilState(&depth_stencil_desc, &_nmd_d3d11.depth_stencil_state); 203 | 204 | if (!_nmd_context.draw_list.default_atlas.font_id) 205 | { 206 | if (!nmd_bake_font_from_memory(nmd_karla_ttf_regular, &_nmd_context.draw_list.default_atlas, 14.0f)) 207 | return false; 208 | 209 | /* Upload texture to graphics system */ 210 | if (!(_nmd_context.draw_list.default_atlas.font_id = nmd_d3d11_create_texture(_nmd_context.draw_list.default_atlas.pixels32, 512, 512))) 211 | return false; 212 | 213 | uint32_t tmp = 0xffffffff; 214 | if (!(_nmd_context.draw_list.blank_tex_id = nmd_d3d11_create_texture(&tmp, 1, 1))) 215 | return false; 216 | } 217 | 218 | /* Create texture sampler */ 219 | D3D11_SAMPLER_DESC sampler_desc; 220 | NMD_MEMSET(&sampler_desc, 0, sizeof(sampler_desc)); 221 | sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; 222 | sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; 223 | sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 224 | sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; 225 | sampler_desc.MipLODBias = 0.f; 226 | sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; 227 | sampler_desc.MinLOD = 0.f; 228 | sampler_desc.MaxLOD = 0.f; 229 | _nmd_d3d11.device->CreateSamplerState(&sampler_desc, &_nmd_d3d11.font_sampler); 230 | 231 | return true; 232 | } 233 | 234 | void nmd_d3d11_delete_objects() 235 | { 236 | _nmd_d3d11.vertex_shader->Release(); 237 | _nmd_d3d11.vertex_shader = 0; 238 | 239 | _nmd_d3d11.pixel_shader->Release(); 240 | _nmd_d3d11.pixel_shader = 0; 241 | 242 | _nmd_d3d11.input_layout->Release(); 243 | _nmd_d3d11.input_layout = 0; 244 | 245 | _nmd_d3d11.const_buffer->Release(); 246 | _nmd_d3d11.const_buffer = 0; 247 | 248 | _nmd_d3d11.font_sampler->Release(); 249 | _nmd_d3d11.font_sampler = 0; 250 | 251 | _nmd_d3d11.rasterizer_state->Release(); 252 | _nmd_d3d11.rasterizer_state = 0; 253 | 254 | _nmd_d3d11.blend_state->Release(); 255 | _nmd_d3d11.blend_state = 0; 256 | 257 | _nmd_d3d11.depth_stencil_state = 0; 258 | 259 | _nmd_d3d11.vertex_buffer_size = 5000; 260 | _nmd_d3d11.index_buffer_size = 10000; 261 | 262 | _nmd_d3d11.vertex_buffer->Release(); 263 | _nmd_d3d11.vertex_buffer = 0; 264 | 265 | _nmd_d3d11.index_buffer->Release(); 266 | _nmd_d3d11.index_buffer = 0; 267 | 268 | _nmd_d3d11.device_context = 0; 269 | _nmd_d3d11.device->Release(); 270 | 271 | _nmd_d3d11.device = 0; 272 | } 273 | 274 | bool nmd_d3d11_resize(int width, int height) 275 | { 276 | if (!_nmd_d3d11.font_sampler && !_nmd_d3d11_create_objects()) 277 | return false; 278 | 279 | D3D11_MAPPED_SUBRESOURCE mapped_resource; 280 | if (_nmd_d3d11.device_context->Map(_nmd_d3d11.const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) 281 | return false; 282 | 283 | float L = 0; 284 | float R = width; 285 | float T = 0; 286 | float B = height; 287 | float mvp[4][4] = 288 | { 289 | { 2.0f / (R - L), 0.0f, 0.0f, 0.0f }, 290 | { 0.0f, 2.0f / (T - B), 0.0f, 0.0f }, 291 | { 0.0f, 0.0f, 0.5f, 0.0f }, 292 | { (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f }, 293 | }; 294 | NMD_MEMCPY(mapped_resource.pData, mvp, sizeof(mvp)); 295 | _nmd_d3d11.device_context->Unmap(_nmd_d3d11.const_buffer, 0); 296 | 297 | /* Setup viewport */ 298 | _nmd_d3d11.viewport.Width = width; 299 | _nmd_d3d11.viewport.Height = height; 300 | 301 | return true; 302 | } 303 | 304 | void _nmd_d3d11_set_render_state() 305 | { 306 | if (!_nmd_d3d11.font_sampler && !_nmd_d3d11_create_objects()) 307 | return; 308 | 309 | unsigned int stride = sizeof(nmd_vertex); 310 | unsigned int offset = 0; 311 | _nmd_d3d11.device_context->IASetInputLayout(_nmd_d3d11.input_layout); 312 | _nmd_d3d11.device_context->IASetVertexBuffers(0, 1, &_nmd_d3d11.vertex_buffer, &stride, &offset); 313 | _nmd_d3d11.device_context->IASetIndexBuffer(_nmd_d3d11.index_buffer, sizeof(nmd_index) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); 314 | _nmd_d3d11.device_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 315 | _nmd_d3d11.device_context->VSSetShader(_nmd_d3d11.vertex_shader, NULL, 0); 316 | _nmd_d3d11.device_context->VSSetConstantBuffers(0, 1, &_nmd_d3d11.const_buffer); 317 | _nmd_d3d11.device_context->PSSetShader(_nmd_d3d11.pixel_shader, NULL, 0); 318 | _nmd_d3d11.device_context->PSSetSamplers(0, 1, &_nmd_d3d11.font_sampler); 319 | _nmd_d3d11.device_context->GSSetShader(NULL, NULL, 0); 320 | _nmd_d3d11.device_context->HSSetShader(NULL, NULL, 0); 321 | _nmd_d3d11.device_context->DSSetShader(NULL, NULL, 0); 322 | _nmd_d3d11.device_context->CSSetShader(NULL, NULL, 0); 323 | _nmd_d3d11.device_context->RSSetViewports(1, &_nmd_d3d11.viewport); 324 | const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; 325 | _nmd_d3d11.device_context->OMSetBlendState(_nmd_d3d11.blend_state, blend_factor, 0xffffffff); 326 | _nmd_d3d11.device_context->OMSetDepthStencilState(_nmd_d3d11.depth_stencil_state, 0); 327 | _nmd_d3d11.device_context->RSSetState(_nmd_d3d11.rasterizer_state); 328 | } 329 | 330 | void nmd_d3d11_render() 331 | { 332 | if (!_nmd_d3d11.font_sampler && !_nmd_d3d11_create_objects()) 333 | return; 334 | 335 | /* Create/Recreate vertex/index buffers if needed */ 336 | if (!_nmd_d3d11.vertex_buffer || _nmd_d3d11.vertex_buffer_size < _nmd_context.draw_list.num_vertices) 337 | { 338 | if (_nmd_d3d11.vertex_buffer) 339 | _nmd_d3d11.vertex_buffer->Release(); 340 | 341 | _nmd_d3d11.vertex_buffer_size = _nmd_context.draw_list.num_vertices + NMD_VERTEX_BUFFER_INITIAL_SIZE; 342 | 343 | D3D11_BUFFER_DESC desc; 344 | NMD_MEMSET(&desc, 0, sizeof(desc)); 345 | desc.Usage = D3D11_USAGE_DYNAMIC; 346 | desc.ByteWidth = _nmd_d3d11.vertex_buffer_size * sizeof(nmd_vertex); 347 | desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 348 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 349 | desc.MiscFlags = 0; 350 | if (FAILED(_nmd_d3d11.device->CreateBuffer(&desc, NULL, &_nmd_d3d11.vertex_buffer))) 351 | return; 352 | 353 | #ifdef NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE 354 | _nmd_d3d11_set_render_state(); 355 | #endif /* NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE */ 356 | } 357 | 358 | if (!_nmd_d3d11.index_buffer || _nmd_d3d11.index_buffer_size < _nmd_context.draw_list.num_indices) 359 | { 360 | if (_nmd_d3d11.index_buffer) 361 | _nmd_d3d11.index_buffer->Release(); 362 | 363 | _nmd_d3d11.index_buffer_size = _nmd_context.draw_list.num_indices + NMD_INDEX_BUFFER_INITIAL_SIZE; 364 | 365 | D3D11_BUFFER_DESC desc; 366 | NMD_MEMSET(&desc, 0, sizeof(desc)); 367 | desc.Usage = D3D11_USAGE_DYNAMIC; 368 | desc.ByteWidth = _nmd_d3d11.index_buffer_size * sizeof(nmd_index); 369 | desc.BindFlags = D3D11_BIND_INDEX_BUFFER; 370 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 371 | if (FAILED(_nmd_d3d11.device->CreateBuffer(&desc, NULL, &_nmd_d3d11.index_buffer))) 372 | return; 373 | 374 | #ifdef NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE 375 | _nmd_d3d11_set_render_state(); 376 | #endif /* NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE */ 377 | } 378 | 379 | /* Copy vertices and indices and to the GPU */ 380 | D3D11_MAPPED_SUBRESOURCE mapped_resource; 381 | if (_nmd_d3d11.device_context->Map(_nmd_d3d11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) 382 | return; 383 | NMD_MEMCPY(mapped_resource.pData, _nmd_context.draw_list.vertices, _nmd_context.draw_list.num_vertices * sizeof(nmd_vertex)); 384 | _nmd_d3d11.device_context->Unmap(_nmd_d3d11.vertex_buffer, 0); 385 | 386 | if (_nmd_d3d11.device_context->Map(_nmd_d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) 387 | return; 388 | NMD_MEMCPY(mapped_resource.pData, _nmd_context.draw_list.indices, _nmd_context.draw_list.num_indices * sizeof(nmd_index)); 389 | _nmd_d3d11.device_context->Unmap(_nmd_d3d11.index_buffer, 0); 390 | 391 | #ifndef NMD_GRAPHICS_D3D11_DONT_BACKUP_RENDER_STATE 392 | /* Backup the current render state */ 393 | struct 394 | { 395 | UINT ScissorRectsCount, ViewportsCount; 396 | D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; 397 | D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; 398 | ID3D11RasterizerState* RS; 399 | ID3D11BlendState* BlendState; 400 | FLOAT BlendFactor[4]; 401 | UINT SampleMask; 402 | UINT StencilRef; 403 | ID3D11DepthStencilState* DepthStencilState; 404 | ID3D11ShaderResourceView* PSShaderResource; 405 | ID3D11SamplerState* PSSampler; 406 | ID3D11PixelShader* PS; 407 | ID3D11VertexShader* VS; 408 | ID3D11GeometryShader* GS; 409 | UINT PSInstancesCount, VSInstancesCount, GSInstancesCount; 410 | ID3D11ClassInstance* PSInstances[128], *VSInstances[128], *GSInstances[128]; 411 | D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology; 412 | ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; 413 | UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; 414 | DXGI_FORMAT IndexBufferFormat; 415 | ID3D11InputLayout* InputLayout; 416 | } old; 417 | old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; 418 | _nmd_d3d11.device_context->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); 419 | _nmd_d3d11.device_context->RSGetViewports(&old.ViewportsCount, old.Viewports); 420 | _nmd_d3d11.device_context->RSGetState(&old.RS); 421 | _nmd_d3d11.device_context->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); 422 | _nmd_d3d11.device_context->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); 423 | _nmd_d3d11.device_context->PSGetShaderResources(0, 1, &old.PSShaderResource); 424 | _nmd_d3d11.device_context->PSGetSamplers(0, 1, &old.PSSampler); 425 | old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 128; 426 | _nmd_d3d11.device_context->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); 427 | _nmd_d3d11.device_context->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); 428 | _nmd_d3d11.device_context->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); 429 | _nmd_d3d11.device_context->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount); 430 | _nmd_d3d11.device_context->IAGetPrimitiveTopology(&old.PrimitiveTopology); 431 | _nmd_d3d11.device_context->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); 432 | _nmd_d3d11.device_context->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); 433 | _nmd_d3d11.device_context->IAGetInputLayout(&old.InputLayout); 434 | #endif /* NMD_GRAPHICS_D3D11_DONT_BACKUP_RENDER_STATE */ 435 | 436 | #ifndef NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE 437 | /* Set render state */ 438 | _nmd_d3d11_set_render_state(); 439 | #endif /* NMD_GRAPHICS_D3D11_OPTIMIZE_RENDER_STATE */ 440 | 441 | /* Render draw commands */ 442 | size_t index_offset = 0; 443 | for (int i = 0; i < _nmd_context.draw_list.num_draw_commands; i++) 444 | { 445 | /* Apply scissor rectangle */ 446 | D3D11_RECT r; 447 | if (_nmd_context.draw_list.draw_commands[i].rect.p1.x == -1.0f) 448 | r = { (LONG)_nmd_d3d11.viewport.TopLeftX, (LONG)_nmd_d3d11.viewport.TopLeftY, (LONG)_nmd_d3d11.viewport.Width, (LONG)_nmd_d3d11.viewport.Height }; 449 | else 450 | r = { (LONG)_nmd_context.draw_list.draw_commands[i].rect.p0.x, (LONG)_nmd_context.draw_list.draw_commands[i].rect.p0.y, (LONG)_nmd_context.draw_list.draw_commands[i].rect.p1.x, (LONG)_nmd_context.draw_list.draw_commands[i].rect.p1.y }; 451 | _nmd_d3d11.device_context->RSSetScissorRects(1, &r); 452 | 453 | /* Set texture */ 454 | ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)_nmd_context.draw_list.draw_commands[i].user_texture_id; 455 | _nmd_d3d11.device_context->PSSetShaderResources(0, 1, &texture_srv); 456 | 457 | /* Issue draw call */ 458 | _nmd_d3d11.device_context->DrawIndexed(_nmd_context.draw_list.draw_commands[i].num_indices, index_offset, 0); 459 | 460 | /* Update offset */ 461 | index_offset += _nmd_context.draw_list.draw_commands[i].num_indices; 462 | } 463 | 464 | #ifndef NMD_GRAPHICS_D3D11_DONT_BACKUP_RENDER_STATE 465 | /* Restore previous render state */ 466 | _nmd_d3d11.device_context->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); 467 | _nmd_d3d11.device_context->RSSetViewports(old.ViewportsCount, old.Viewports); 468 | _nmd_d3d11.device_context->RSSetState(old.RS); if (old.RS) old.RS->Release(); 469 | _nmd_d3d11.device_context->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); 470 | _nmd_d3d11.device_context->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); 471 | _nmd_d3d11.device_context->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); 472 | _nmd_d3d11.device_context->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); 473 | _nmd_d3d11.device_context->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); 474 | for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release(); 475 | _nmd_d3d11.device_context->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); 476 | _nmd_d3d11.device_context->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); 477 | _nmd_d3d11.device_context->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release(); 478 | for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release(); 479 | _nmd_d3d11.device_context->IASetPrimitiveTopology(old.PrimitiveTopology); 480 | _nmd_d3d11.device_context->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); 481 | _nmd_d3d11.device_context->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); 482 | _nmd_d3d11.device_context->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); 483 | #endif /* NMD_GRAPHICS_D3D11_DONT_BACKUP_RENDER_STATE */ 484 | } 485 | 486 | #endif /* NMD_GRAPHICS_D3D11 */ 487 | -------------------------------------------------------------------------------- /graphics/nmd_renderer_d3d9.cpp: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | 3 | #ifdef NMD_GRAPHICS_D3D9 4 | #pragma comment(lib, "d3d9.lib") 5 | struct 6 | { 7 | LPDIRECT3DDEVICE9 device = 0; 8 | LPDIRECT3DVERTEXBUFFER9 vb = 0; /* vertex buffer */ 9 | LPDIRECT3DINDEXBUFFER9 ib = 0; /* index buffer*/ 10 | int vb_size, ib_size; /* The number of vertices and indices respectively. */ 11 | D3DMATRIX proj; 12 | D3DVIEWPORT9 viewport; 13 | } _nmd_d3d9; 14 | 15 | typedef struct 16 | { 17 | float pos[3]; 18 | D3DCOLOR color; 19 | float uv[2]; 20 | } _nmd_d3d9_custom_vertex; 21 | 22 | #define _NMD_D3D9_CUSTOM_VERTEX_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) 23 | 24 | void nmd_d3d9_set_device(LPDIRECT3DDEVICE9 p_d3d9_device) 25 | { 26 | _nmd_d3d9.device = p_d3d9_device; 27 | 28 | _nmd_d3d9.viewport.X; 29 | _nmd_d3d9.viewport.Y = 0; 30 | _nmd_d3d9.viewport.MinZ = 0.0f; 31 | _nmd_d3d9.viewport.MaxZ = 1.0f; 32 | 33 | int width = 16, height = 16; 34 | unsigned char* pixels = (unsigned char*)NMD_MALLOC(width * height * 4); 35 | 36 | NMD_MEMSET(pixels, 0xff, width * height * 4); 37 | 38 | _nmd_context.draw_list.default_atlas.font_id = nmd_d3d9_create_texture(pixels, width, height); 39 | } 40 | 41 | nmd_tex_id nmd_d3d9_create_texture(void* pixels, int width, int height) 42 | { 43 | IDirect3DTexture9* texture; 44 | if (_nmd_d3d9.device->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, NULL) != D3D_OK) 45 | return 0; 46 | 47 | D3DLOCKED_RECT tex_locked_rect; 48 | if (texture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) 49 | return 0; 50 | 51 | for (int y = 0; y < height; y++) 52 | NMD_MEMCPY((unsigned char*)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, (unsigned char*)pixels + (width * 4) * y, (width * 4)); 53 | 54 | texture->UnlockRect(0); 55 | 56 | return (nmd_tex_id)texture; 57 | } 58 | 59 | void nmd_d3d9_resize(int width, int height) 60 | { 61 | const float L = 0.0f; 62 | const float R = (float)width + 0.0f; 63 | const float T = 0.0f; 64 | const float B = (float)height + 0.0f; 65 | float matrix[4][4] = { 66 | { 2.0f / (R - L), 0.0f, 0.0f, 0.0f }, 67 | { 0.0f, 2.0f / (T - B), 0.0f, 0.0f }, 68 | { 0.0f, 0.0f, 0.0f, 0.0f }, 69 | { (R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f }, 70 | }; 71 | NMD_MEMCPY(&_nmd_d3d9.proj, matrix, sizeof(matrix)); 72 | 73 | _nmd_d3d9.viewport.Width = width; 74 | _nmd_d3d9.viewport.Height = height; 75 | } 76 | 77 | void _nmd_d3d9_set_render_state() 78 | { 79 | _nmd_d3d9.device->SetStreamSource(0, _nmd_d3d9.vb, 0, sizeof(_nmd_d3d9_custom_vertex)); 80 | _nmd_d3d9.device->SetIndices(_nmd_d3d9.ib); 81 | _nmd_d3d9.device->SetFVF(_NMD_D3D9_CUSTOM_VERTEX_FVF); 82 | _nmd_d3d9.device->SetTransform(D3DTS_PROJECTION, &_nmd_d3d9.proj); 83 | _nmd_d3d9.device->SetViewport(&_nmd_d3d9.viewport); 84 | _nmd_d3d9.device->SetPixelShader(NULL); 85 | _nmd_d3d9.device->SetVertexShader(NULL); 86 | _nmd_d3d9.device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); 87 | _nmd_d3d9.device->SetRenderState(D3DRS_LIGHTING, false); 88 | _nmd_d3d9.device->SetRenderState(D3DRS_ZENABLE, false); 89 | _nmd_d3d9.device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); 90 | _nmd_d3d9.device->SetRenderState(D3DRS_ALPHATESTENABLE, false); 91 | _nmd_d3d9.device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); 92 | _nmd_d3d9.device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 93 | _nmd_d3d9.device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 94 | _nmd_d3d9.device->SetRenderState(D3DRS_SCISSORTESTENABLE, true); 95 | _nmd_d3d9.device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); 96 | _nmd_d3d9.device->SetRenderState(D3DRS_FOGENABLE, false); 97 | _nmd_d3d9.device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); 98 | _nmd_d3d9.device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); 99 | _nmd_d3d9.device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); 100 | _nmd_d3d9.device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); 101 | _nmd_d3d9.device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); 102 | _nmd_d3d9.device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); 103 | _nmd_d3d9.device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 104 | _nmd_d3d9.device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 105 | } 106 | 107 | void nmd_d3d9_render() 108 | { 109 | /* Create/recreate vertex buffer if it doesn't exist or more space is needed */ 110 | if (!_nmd_d3d9.vb || _nmd_d3d9.vb_size < _nmd_context.draw_list.num_vertices) 111 | { 112 | if (_nmd_d3d9.vb) 113 | { 114 | _nmd_d3d9.vb->Release(); 115 | _nmd_d3d9.vb = 0; 116 | } 117 | 118 | _nmd_d3d9.vb_size = _nmd_context.draw_list.num_vertices + NMD_VERTEX_BUFFER_INITIAL_SIZE; 119 | if (_nmd_d3d9.device->CreateVertexBuffer(_nmd_d3d9.vb_size * sizeof(_nmd_d3d9_custom_vertex), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, _NMD_D3D9_CUSTOM_VERTEX_FVF, D3DPOOL_DEFAULT, &_nmd_d3d9.vb, NULL) != D3D_OK) 120 | return; 121 | 122 | #ifdef NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE 123 | _nmd_d3d9_set_render_state(); 124 | #endif /* NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE */ 125 | } 126 | 127 | /* Create/recreate index buffer if it doesn't exist or more space is needed */ 128 | if (!_nmd_d3d9.ib || _nmd_d3d9.ib_size < _nmd_context.draw_list.num_indices) 129 | { 130 | if (_nmd_d3d9.ib) 131 | { 132 | _nmd_d3d9.ib->Release(); 133 | _nmd_d3d9.ib = 0; 134 | } 135 | 136 | _nmd_d3d9.ib_size = _nmd_context.draw_list.num_indices + NMD_INDEX_BUFFER_INITIAL_SIZE; 137 | if (_nmd_d3d9.device->CreateIndexBuffer(_nmd_d3d9.ib_size * sizeof(nmd_index), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(nmd_index) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &_nmd_d3d9.ib, NULL) < 0) 138 | return; 139 | 140 | #ifdef NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE 141 | _nmd_d3d9_set_render_state(); 142 | #endif /* NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE */ 143 | } 144 | 145 | /* Copy vertices to the gpu */ 146 | _nmd_d3d9_custom_vertex* p_vertices = 0; 147 | if (_nmd_d3d9.vb->Lock(0, (UINT)(_nmd_context.draw_list.num_vertices * sizeof(_nmd_d3d9_custom_vertex)), (void**)&p_vertices, D3DLOCK_DISCARD) != D3D_OK) 148 | return; 149 | size_t i = 0; 150 | for (; i < _nmd_context.draw_list.num_vertices; i++) 151 | { 152 | p_vertices[i].pos[0] = _nmd_context.draw_list.vertices[i].pos.x; 153 | p_vertices[i].pos[1] = _nmd_context.draw_list.vertices[i].pos.y; 154 | p_vertices[i].pos[2] = 0.0f; 155 | 156 | p_vertices[i].uv[0] = _nmd_context.draw_list.vertices[i].uv.x; 157 | p_vertices[i].uv[1] = _nmd_context.draw_list.vertices[i].uv.y; 158 | 159 | const nmd_color color = _nmd_context.draw_list.vertices[i].color; 160 | p_vertices[i].color = D3DCOLOR_RGBA(color.r, color.g, color.b, color.a); 161 | } 162 | _nmd_d3d9.vb->Unlock(); 163 | 164 | /* Copy indices to the gpu */ 165 | nmd_index* p_indices = 0; 166 | if (_nmd_d3d9.ib->Lock(0, (UINT)(_nmd_context.draw_list.num_indices * sizeof(nmd_index)), (void**)&p_indices, D3DLOCK_DISCARD) != D3D_OK) 167 | return; 168 | NMD_MEMCPY(p_indices, _nmd_context.draw_list.indices, _nmd_context.draw_list.num_indices * sizeof(nmd_index)); 169 | _nmd_d3d9.ib->Unlock(); 170 | 171 | #ifndef NMD_GRAPHICS_D3D9_DONT_BACKUP_RENDER_STATE 172 | /* Backup the current render state */ 173 | IDirect3DStateBlock9* d3d9_state_block = NULL; 174 | if (_nmd_d3d9.device->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) 175 | return; 176 | D3DMATRIX last_world, last_view, last_projection; 177 | _nmd_d3d9.device->GetTransform(D3DTS_WORLD, &last_world); 178 | _nmd_d3d9.device->GetTransform(D3DTS_VIEW, &last_view); 179 | _nmd_d3d9.device->GetTransform(D3DTS_PROJECTION, &last_projection); 180 | #endif /* NMD_GRAPHICS_D3D9_DONT_BACKUP_RENDER_STATE */ 181 | 182 | #ifndef NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE 183 | /* Set render state */ 184 | _nmd_d3d9_set_render_state(); 185 | #endif /* NMD_GRAPHICS_D3D9_OPTIMIZE_RENDER_STATE */ 186 | 187 | /* Render draw commands */ 188 | size_t index_offset = 0; 189 | for (i = 0; i < _nmd_context.draw_list.num_draw_commands; i++) 190 | { 191 | /* Apply scissor rectangle */ 192 | RECT r; 193 | if (_nmd_context.draw_list.draw_commands[i].rect.p1.x == -1.0f) 194 | r = { (LONG)_nmd_d3d9.viewport.X, (LONG)_nmd_d3d9.viewport.Y, (LONG)_nmd_d3d9.viewport.Width, (LONG)_nmd_d3d9.viewport.Height }; 195 | else 196 | r = { (LONG)_nmd_context.draw_list.draw_commands[i].rect.p0.x, (LONG)_nmd_context.draw_list.draw_commands[i].rect.p0.y, (LONG)_nmd_context.draw_list.draw_commands[i].rect.p1.x, (LONG)_nmd_context.draw_list.draw_commands[i].rect.p1.y }; 197 | _nmd_d3d9.device->SetScissorRect(&r); 198 | 199 | /* Set texture */ 200 | const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)_nmd_context.draw_list.draw_commands[i].user_texture_id; 201 | _nmd_d3d9.device->SetTexture(0, texture); 202 | 203 | /* Issue draw calls */ 204 | _nmd_d3d9.device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, (UINT)_nmd_context.draw_list.draw_commands[i].num_vertices, index_offset, _nmd_context.draw_list.draw_commands[i].num_indices / 3); 205 | 206 | /* Update offsets */ 207 | index_offset += _nmd_context.draw_list.draw_commands[i].num_indices; 208 | } 209 | 210 | #ifndef NMD_GRAPHICS_D3D9_DONT_BACKUP_RENDER_STATE 211 | /* Restore previous render state */ 212 | _nmd_d3d9.device->SetTransform(D3DTS_WORLD, &last_world); 213 | _nmd_d3d9.device->SetTransform(D3DTS_VIEW, &last_view); 214 | _nmd_d3d9.device->SetTransform(D3DTS_PROJECTION, &last_projection); 215 | d3d9_state_block->Apply(); 216 | d3d9_state_block->Release(); 217 | #endif /* NMD_GRAPHICS_D3D9_DONT_BACKUP_RENDER_STATE */ 218 | } 219 | #endif /* NMD_GRAPHICS_D3D9 */ 220 | -------------------------------------------------------------------------------- /graphics/nmd_renderer_opengl.c: -------------------------------------------------------------------------------- 1 | #include "nmd_common.h" 2 | #ifdef NMD_GRAPHICS_OPENGL 3 | struct 4 | { 5 | GLuint vbo, vao, ebo; 6 | GLuint vs, fs, program; 7 | GLuint uniform_tex, uniform_proj, attrib_pos, attrib_uv, attrib_color; 8 | GLsizei width, height; 9 | GLfloat ortho[4][4]; 10 | } _nmd_opengl; 11 | bool _nmd_opengl_initialized = false; 12 | 13 | nmd_tex_id nmd_opengl_create_texture(void* pixels, int width, int height) 14 | { 15 | GLint last_texture; 16 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 17 | GLuint texture; 18 | 19 | glGenTextures(1, &texture); 20 | glBindTexture(GL_TEXTURE_2D, texture); 21 | 22 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 23 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 24 | 25 | #ifdef GL_UNPACK_ROW_LENGTH 26 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 27 | #endif 28 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 29 | 30 | glBindTexture(GL_TEXTURE_2D, last_texture); 31 | 32 | return texture; 33 | } 34 | 35 | #ifdef __APPLE__ 36 | #define _NMD_OPENGL_SHADER_VERSION "#version 150\n" 37 | #else 38 | #define _NMD_OPENGL_SHADER_VERSION "#version 300 es\n" 39 | #endif 40 | 41 | bool _nmd_opengl_create_objects() 42 | { 43 | if (_nmd_opengl_initialized) 44 | return true; 45 | 46 | _nmd_opengl_initialized = true; 47 | 48 | GLfloat ortho[4][4] = { 49 | {2.0f, 0.0f, 0.0f, 0.0f}, 50 | {0.0f,-2.0f, 0.0f, 0.0f}, 51 | {0.0f, 0.0f,-1.0f, 0.0f}, 52 | {-1.0f,1.0f, 0.0f, 1.0f}, 53 | }; 54 | NMD_MEMCPY(_nmd_opengl.ortho, ortho, sizeof(GLfloat) * 4 * 4); 55 | 56 | // Backup GL state 57 | GLint last_texture, last_array_buffer; 58 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 59 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 60 | #ifndef IMGUI_IMPL_OPENGL_ES2 61 | GLint last_vertex_array; 62 | glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 63 | #endif 64 | 65 | const GLchar* vertex_shader = 66 | "#version 300 es\n" 67 | "precision mediump float;\n" 68 | "layout (location = 0) in vec2 Position;\n" 69 | "layout (location = 1) in vec2 UV;\n" 70 | "layout (location = 2) in vec4 Color;\n" 71 | "uniform mat4 ProjMtx;\n" 72 | "out vec2 Frag_UV;\n" 73 | "out vec4 Frag_Color;\n" 74 | "void main()\n" 75 | "{\n" 76 | " Frag_UV = UV;\n" 77 | " Frag_Color = Color;\n" 78 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 79 | "}\n"; 80 | const GLchar* fragment_shader = 81 | "#version 300 es\n" 82 | "precision mediump float;\n" 83 | "uniform sampler2D Texture;\n" 84 | "in vec2 Frag_UV;\n" 85 | "in vec4 Frag_Color;\n" 86 | "layout (location = 0) out vec4 Out_Color;\n" 87 | "void main()\n" 88 | "{\n" 89 | " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" 90 | "}\n"; 91 | GLint status; 92 | 93 | _nmd_opengl.vs = glCreateShader(GL_VERTEX_SHADER); 94 | glShaderSource(_nmd_opengl.vs, 1, &vertex_shader, 0); 95 | glCompileShader(_nmd_opengl.vs); 96 | glGetShaderiv(_nmd_opengl.vs, GL_COMPILE_STATUS, &status); 97 | if(status != GL_TRUE) 98 | return false; 99 | 100 | _nmd_opengl.fs = glCreateShader(GL_FRAGMENT_SHADER); 101 | glShaderSource(_nmd_opengl.fs, 1, &fragment_shader, 0); 102 | glCompileShader(_nmd_opengl.fs); 103 | glGetShaderiv(_nmd_opengl.fs, GL_COMPILE_STATUS, &status); 104 | if (status != GL_TRUE) 105 | return false; 106 | 107 | _nmd_opengl.program = glCreateProgram(); 108 | glAttachShader(_nmd_opengl.program, _nmd_opengl.vs); 109 | glAttachShader(_nmd_opengl.program, _nmd_opengl.fs); 110 | glLinkProgram(_nmd_opengl.program); 111 | glGetProgramiv(_nmd_opengl.program, GL_LINK_STATUS, &status); 112 | if (status != GL_TRUE) 113 | return false; 114 | 115 | _nmd_opengl.uniform_tex = glGetUniformLocation(_nmd_opengl.program, "Texture"); 116 | _nmd_opengl.uniform_proj = glGetUniformLocation(_nmd_opengl.program, "ProjMtx"); 117 | _nmd_opengl.attrib_pos = (GLuint)glGetAttribLocation(_nmd_opengl.program, "Position"); 118 | _nmd_opengl.attrib_uv = (GLuint)glGetAttribLocation(_nmd_opengl.program, "UV"); 119 | _nmd_opengl.attrib_color = (GLuint)glGetAttribLocation(_nmd_opengl.program, "Color"); 120 | 121 | /* Create buffers */ 122 | glGenBuffers(1, &_nmd_opengl.vbo); 123 | glGenBuffers(1, &_nmd_opengl.ebo); 124 | 125 | int width = 16, height = 16; 126 | char* pixels = malloc(width * height * 4); 127 | NMD_MEMSET(pixels, 255, width * height * 4); 128 | _nmd_context.draw_list.font = nmd_opengl_create_texture(pixels, width, height); 129 | 130 | /* Restore modified GL state */ 131 | glBindTexture(GL_TEXTURE_2D, last_texture); 132 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 133 | #ifndef IMGUI_IMPL_OPENGL_ES2 134 | glBindVertexArray(last_vertex_array); 135 | #endif 136 | 137 | return true; 138 | } 139 | 140 | bool nmd_opengl_resize(int width, int height) 141 | { 142 | if (!_nmd_opengl_create_objects()) 143 | return false; 144 | 145 | glViewport(0, 0, (GLsizei)width, (GLsizei)height); 146 | _nmd_opengl.ortho[0][0] /= (GLfloat)width; 147 | _nmd_opengl.ortho[1][1] /= (GLfloat)height; 148 | 149 | _nmd_opengl.width = width; 150 | _nmd_opengl.height = height; 151 | 152 | return true; 153 | } 154 | 155 | void _nmd_opengl_set_render_state() 156 | { 157 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill 158 | glEnable(GL_BLEND); 159 | glBlendEquation(GL_FUNC_ADD); 160 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 161 | glDisable(GL_CULL_FACE); 162 | glDisable(GL_DEPTH_TEST); 163 | glEnable(GL_SCISSOR_TEST); 164 | #ifdef GL_POLYGON_MODE 165 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 166 | #endif 167 | 168 | // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) 169 | bool clip_origin_lower_left = true; 170 | #if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) 171 | GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); 172 | if (current_clip_origin == GL_UPPER_LEFT) 173 | clip_origin_lower_left = false; 174 | #endif 175 | 176 | glViewport(0, 0, (GLsizei)_nmd_opengl.width, (GLsizei)_nmd_opengl.height); 177 | glUseProgram(_nmd_opengl.program); 178 | glUniform1i(_nmd_opengl.uniform_tex, 0); 179 | glUniformMatrix4fv(_nmd_opengl.uniform_proj, 1, GL_FALSE, &_nmd_opengl.ortho[0][0]); 180 | #ifdef GL_SAMPLER_BINDING 181 | glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. 182 | #endif 183 | 184 | // (void)vertex_array_object; 185 | //#ifndef IMGUI_IMPL_OPENGL_ES2 186 | // glBindVertexArray(vertex_array_object); 187 | //#endif 188 | 189 | // Bind vertex/index buffers and setup attributes for ImDrawVert 190 | glBindBuffer(GL_ARRAY_BUFFER, _nmd_opengl.vbo); 191 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _nmd_opengl.ebo); 192 | glEnableVertexAttribArray(_nmd_opengl.attrib_pos); 193 | glEnableVertexAttribArray(_nmd_opengl.attrib_uv); 194 | glEnableVertexAttribArray(_nmd_opengl.attrib_color); 195 | glVertexAttribPointer(_nmd_opengl.attrib_pos, 2, GL_FLOAT, GL_FALSE, sizeof(nmd_vertex), (GLvoid*)_NMD_OFFSETOF(nmd_vertex, pos)); 196 | glVertexAttribPointer(_nmd_opengl.attrib_uv, 2, GL_FLOAT, GL_FALSE, sizeof(nmd_vertex), (GLvoid*)_NMD_OFFSETOF(nmd_vertex, uv)); 197 | glVertexAttribPointer(_nmd_opengl.attrib_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(nmd_vertex), (GLvoid*)_NMD_OFFSETOF(nmd_vertex, color)); 198 | } 199 | 200 | void nmd_opengl_render() 201 | { 202 | if (!_nmd_opengl_create_objects()) 203 | return false; 204 | 205 | #ifndef NMD_GRAPHICS_OPENGL_DONT_BACKUP_RENDER_STATE 206 | /* Backup the current render state */ 207 | GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); 208 | glActiveTexture(GL_TEXTURE0); 209 | GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program); 210 | GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture); 211 | #ifdef GL_SAMPLER_BINDING 212 | GLuint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); 213 | #endif 214 | GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer); 215 | #ifndef IMGUI_IMPL_OPENGL_ES2 216 | GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object); 217 | #endif 218 | #ifdef GL_POLYGON_MODE 219 | GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); 220 | #endif 221 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); 222 | GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); 223 | GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); 224 | GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); 225 | GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); 226 | GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); 227 | GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); 228 | GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); 229 | GLboolean last_enable_blend = glIsEnabled(GL_BLEND); 230 | GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); 231 | GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); 232 | GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); 233 | #endif /* NMD_GRAPHICS_OPENGL_DONT_BACKUP_RENDER_STATE */ 234 | 235 | /* Set render state */ 236 | _nmd_opengl_set_render_state(); 237 | 238 | /* Copy vertices and indices and to the GPU */ 239 | glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)_nmd_context.draw_list.num_vertices * (int)sizeof(nmd_vertex), (const GLvoid*)_nmd_context.draw_list.vertices, GL_STREAM_DRAW); 240 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)_nmd_context.draw_list.num_indices * (int)sizeof(nmd_index), (const GLvoid*)_nmd_context.draw_list.indices, GL_STREAM_DRAW); 241 | 242 | /* Render command buffers */ 243 | size_t i = 0; 244 | size_t index_offset = 0; 245 | for (; i < _nmd_context.draw_list.num_draw_commands; i++) 246 | { 247 | /* Apply scissor rectangle */ 248 | if (_nmd_context.draw_list.draw_commands[i].rect.p1.x == -1.0f) 249 | glScissor(0, 0, (GLsizei)_nmd_opengl.width, (GLsizei)_nmd_opengl.height); 250 | else 251 | glScissor((GLint)_nmd_context.draw_list.draw_commands[i].rect.p0.x, (GLint)_nmd_context.draw_list.draw_commands[i].rect.p0.y, (GLsizei)_nmd_context.draw_list.draw_commands[i].rect.p1.x, (GLsizei)_nmd_context.draw_list.draw_commands[i].rect.p1.y); 252 | 253 | /* Set texture */ 254 | glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)_nmd_context.draw_list.draw_commands[i].user_texture_id); 255 | 256 | /* Issue draw call */ 257 | glDrawElements(GL_TRIANGLES, (GLsizei)_nmd_context.draw_list.draw_commands[i].num_indices, sizeof(nmd_index) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(index_offset * sizeof(nmd_index))); 258 | 259 | /* Update offset */ 260 | index_offset += _nmd_context.draw_list.draw_commands[i].num_indices; 261 | } 262 | 263 | #ifndef NMD_GRAPHICS_OPENGL_DONT_BACKUP_RENDER_STATE 264 | /* Restore previous render state */ 265 | glUseProgram(last_program); 266 | glBindTexture(GL_TEXTURE_2D, last_texture); 267 | #ifdef GL_SAMPLER_BINDING 268 | glBindSampler(0, last_sampler); 269 | #endif 270 | glActiveTexture(last_active_texture); 271 | #ifndef IMGUI_IMPL_OPENGL_ES2 272 | glBindVertexArray(last_vertex_array_object); 273 | #endif 274 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 275 | glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); 276 | glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); 277 | if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); 278 | if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); 279 | if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); 280 | if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); 281 | #ifdef GL_POLYGON_MODE 282 | glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); 283 | #endif 284 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); 285 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); 286 | #endif /* NMD_GRAPHICS_OPENGL_DONT_BACKUP_RENDER_STATE */ 287 | } 288 | 289 | #endif /* NMD_GRAPHICS_OPENGL */ 290 | -------------------------------------------------------------------------------- /graphics/nmd_stb_truetype.c: -------------------------------------------------------------------------------- 1 | #define STB_TRUETYPE_IMPLEMENTATION --------------------------------------------------------------------------------