├── .clang-format ├── .github └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── THIRDPARTY.md ├── assets ├── jkgm.json ├── sample_matpack │ ├── 00abb3_base.png │ ├── 00abb3_base_ruined.png │ ├── 00abb3_cel_2_e.png │ ├── 00abb3_cel_3_e.png │ ├── 00abb3_cel_4_e.png │ ├── 08tgrate_cel0.png │ ├── 08tgrate_d_cel0.png │ ├── 19cpipe2.png │ ├── 19cpipe2_d.png │ ├── saberbase0.png │ ├── saberbase1.png │ └── script.json └── shaders │ ├── game.vert │ ├── game_opaque_pass.frag │ ├── game_trns_pass.frag │ ├── menu.frag │ ├── menu.vert │ ├── post_box4.frag │ ├── post_gauss15.frag │ ├── post_gauss3.frag │ ├── post_gauss7.frag │ ├── post_gauss9.frag │ ├── post_low_pass.frag │ ├── post_opaque_composite.frag │ ├── post_scale.frag │ ├── post_ssao.frag │ ├── post_to_srgb.frag │ └── postprocess.vert ├── base ├── base.vcxproj ├── base.vcxproj.filters ├── buffered_input_stream.hpp ├── buffered_output_stream.hpp ├── build_traits.hpp ├── char.cpp ├── char.hpp ├── constants.hpp ├── cstring_view.hpp ├── default_logger.cpp ├── default_logger.hpp ├── diagnostic_context.cpp ├── diagnostic_context.hpp ├── diagnostic_context_location.cpp ├── diagnostic_context_location.hpp ├── env.cpp ├── env.hpp ├── fd_input_stream.cpp ├── fd_input_stream.hpp ├── fd_output_stream.cpp ├── fd_output_stream.hpp ├── file_block.cpp ├── file_block.hpp ├── file_log_backend.cpp ├── file_log_backend.hpp ├── file_stream.cpp ├── file_stream.hpp ├── filesystem.hpp ├── flag_set.hpp ├── format.hpp ├── format_base.cpp ├── format_base.hpp ├── format_numeric.hpp ├── global.cpp ├── global.hpp ├── hash_combine.hpp ├── id.hpp ├── input_block.hpp ├── input_stream.cpp ├── input_stream.hpp ├── lexical_cast.hpp ├── local.cpp ├── local.hpp ├── log.cpp ├── log.hpp ├── log_backend.hpp ├── log_frontend.cpp ├── log_frontend.hpp ├── log_level.cpp ├── log_level.hpp ├── log_midend.cpp ├── log_midend.hpp ├── md5.cpp ├── md5.hpp ├── memory_block.cpp ├── memory_block.hpp ├── narrow.hpp ├── output_block.hpp ├── output_stream.cpp ├── output_stream.hpp ├── oxford_join.hpp ├── pipe.cpp ├── pipe.hpp ├── range.hpp ├── runtime_assert.hpp ├── span.hpp ├── std_input_stream.cpp ├── std_input_stream.hpp ├── std_output_log_backend.cpp ├── std_output_log_backend.hpp ├── std_output_stream.cpp ├── std_output_stream.hpp ├── string_search.cpp ├── string_search.hpp ├── system_string.cpp ├── system_string.hpp ├── tagged.hpp ├── uid.hpp ├── unique_handle.hpp ├── win32.cpp └── win32.hpp ├── common ├── common.vcxproj ├── common.vcxproj.filters ├── config.cpp ├── config.hpp ├── error_reporter.cpp ├── error_reporter.hpp ├── image.cpp ├── image.hpp ├── json.hpp ├── json_incl.hpp ├── material.cpp ├── material.hpp ├── material_map.cpp ├── material_map.hpp ├── stb_image.h ├── stb_image_impl.cpp └── stb_image_write.h ├── compile ├── colormap.cpp ├── colormap.hpp ├── compile.vcxproj ├── compile.vcxproj.filters ├── gob_file.cpp ├── gob_file.hpp ├── gob_virtual_container.cpp ├── gob_virtual_container.hpp ├── gob_virtual_file.cpp ├── gob_virtual_file.hpp ├── jk_virtual_file_system.cpp ├── jk_virtual_file_system.hpp ├── main.cpp ├── native_file_system.cpp ├── native_file_system.hpp ├── raw_material.cpp ├── raw_material.hpp ├── virtual_container.cpp ├── virtual_container.hpp ├── virtual_container_iterator.cpp ├── virtual_container_iterator.hpp ├── virtual_file.cpp ├── virtual_file.hpp ├── virtual_file_system.cpp └── virtual_file_system.hpp ├── detours ├── CREDITS.TXT ├── LICENSE.md ├── README.md ├── creatwth.cpp ├── detours.cpp ├── detours.h ├── detours.vcxproj ├── detours.vcxproj.filters ├── detver.h ├── disasm.cpp ├── disolarm.cpp ├── disolarm64.cpp ├── disolia64.cpp ├── disolx64.cpp ├── disolx86.cpp ├── image.cpp ├── modules.cpp └── uimports.cpp ├── doc ├── compile.md ├── config.md └── install.md ├── glad ├── gl.h ├── glad.cpp ├── glad.h ├── glad.vcxproj ├── glad.vcxproj.filters └── khrplatform.h ├── glutil ├── buffer.cpp ├── buffer.hpp ├── framebuffer.cpp ├── framebuffer.hpp ├── gl.cpp ├── gl.hpp ├── gl_types.cpp ├── gl_types.hpp ├── glutil.vcxproj ├── glutil.vcxproj.filters ├── program.cpp ├── program.hpp ├── renderbuffer.cpp ├── renderbuffer.hpp ├── shader.cpp ├── shader.hpp ├── texture.cpp ├── texture.hpp ├── vertex_array.cpp └── vertex_array.hpp ├── inject ├── inject.vcxproj ├── inject.vcxproj.filters └── main.cpp ├── jkgfxmod.sln ├── math ├── abstract_vector.hpp ├── abstract_vector_def.hpp ├── abstract_vector_simd.hpp ├── almost_equal.hpp ├── box.hpp ├── clamp.hpp ├── color.hpp ├── color_conv.cpp ├── color_conv.hpp ├── colors.hpp ├── constants.hpp ├── direction.hpp ├── math.vcxproj ├── math.vcxproj.filters ├── point.hpp ├── size.hpp └── utility.hpp ├── program ├── abstract_argument_queue.cpp ├── abstract_argument_queue.hpp ├── abstract_bare_option.cpp ├── abstract_bare_option.hpp ├── abstract_option.cpp ├── abstract_option.hpp ├── at_least_one_input.cpp ├── at_least_one_input.hpp ├── bare_multi_value_option.hpp ├── dependent_option.cpp ├── dependent_option.hpp ├── multi_value_option.hpp ├── mutual_exclusion.cpp ├── mutual_exclusion.hpp ├── option_constraint.cpp ├── option_constraint.hpp ├── options.cpp ├── options.hpp ├── program.cpp ├── program.hpp ├── program.vcxproj ├── program.vcxproj.filters ├── range_argument_queue.hpp ├── required_option.cpp ├── required_option.hpp ├── switch_option.cpp ├── switch_option.hpp └── value_option.hpp └── renderer ├── backbuffer_menu_surface.cpp ├── backbuffer_menu_surface.hpp ├── backbuffer_surface.cpp ├── backbuffer_surface.hpp ├── d3d_impl.cpp ├── d3d_impl.hpp ├── d3ddevice_impl.cpp ├── d3ddevice_impl.hpp ├── d3dtexture_impl.cpp ├── d3dtexture_impl.hpp ├── d3dviewport_impl.cpp ├── d3dviewport_impl.hpp ├── ddraw2_impl.cpp ├── ddraw2_impl.hpp ├── ddraw_impl.cpp ├── ddraw_impl.hpp ├── ddrawpalette_impl.cpp ├── ddrawpalette_impl.hpp ├── ddrawsurface_impl.cpp ├── ddrawsurface_impl.hpp ├── dxguids.cpp ├── dxguids.hpp ├── execute_buffer.cpp ├── execute_buffer.hpp ├── exports.def ├── main.cpp ├── offscreen_menu_surface.cpp ├── offscreen_menu_surface.hpp ├── offscreen_surface.cpp ├── offscreen_surface.hpp ├── opengl_state.cpp ├── opengl_state.hpp ├── primary_menu_surface.cpp ├── primary_menu_surface.hpp ├── primary_surface.cpp ├── primary_surface.hpp ├── renderer.cpp ├── renderer.hpp ├── renderer.vcxproj ├── renderer.vcxproj.filters ├── renderer_ao.cpp ├── renderer_ao.hpp ├── renderer_ao_basic.cpp ├── renderer_ao_basic.hpp ├── renderer_ao_ssao.cpp ├── renderer_ao_ssao.hpp ├── renderer_compositor.cpp ├── renderer_compositor.hpp ├── renderer_compositor_basic.cpp ├── renderer_compositor_basic.hpp ├── renderer_compositor_bloom.cpp ├── renderer_compositor_bloom.hpp ├── renderer_fwd.hpp ├── renderer_screen.cpp ├── renderer_screen.hpp ├── renderer_screen_basic.cpp ├── renderer_screen_basic.hpp ├── renderer_screen_msaa.cpp ├── renderer_screen_msaa.hpp ├── shaders.cpp ├── shaders.hpp ├── sysmem_texture.cpp ├── sysmem_texture.hpp ├── texture_cache.cpp ├── texture_cache.hpp ├── triangle_batch.cpp ├── triangle_batch.hpp ├── vidmem_texture.cpp ├── vidmem_texture.hpp ├── zbuffer_surface.cpp └── zbuffer_surface.hpp /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: windows-latest 9 | 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v1 13 | - name: Enable Developer Command Prompt 14 | uses: ilammy/msvc-dev-cmd@v1.4.1 15 | - name: Build 16 | run: MSBuild.exe -t:Build -p:Configuration=Release -p:Platform=x86 jkgfxmod.sln 17 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v1 14 | 15 | - name: Enable Developer Command Prompt 16 | uses: ilammy/msvc-dev-cmd@v1.4.1 17 | 18 | - name: Build 19 | run: MSBuild.exe -t:Build -p:Configuration=Release -p:Platform=x86 jkgfxmod.sln 20 | 21 | - name: Assemble JkGfxMod 22 | shell: bash 23 | run: | 24 | export MOD_DIR=Artifacts/JkGfxMod 25 | mkdir -p ${MOD_DIR}/jkgm/materials 26 | echo "Copy material pack directories here" > ${MOD_DIR}/jkgm/materials/placeholder.txt 27 | cp -r assets/shaders ${MOD_DIR}/jkgm/shaders 28 | mkdir -p ${MOD_DIR}/doc 29 | cp doc/config.md ${MOD_DIR}/doc/config.md 30 | cp doc/install.md ${MOD_DIR}/doc/install.md 31 | cp assets/jkgm.json ${MOD_DIR} 32 | cp Release/inject.exe ${MOD_DIR} 33 | cp Release/renderer.dll ${MOD_DIR} 34 | cp README.md ${MOD_DIR} 35 | cp LICENSE.md ${MOD_DIR} 36 | cp THIRDPARTY.md ${MOD_DIR} 37 | 38 | - name: Assemble Compiler 39 | shell: bash 40 | run: | 41 | export CMP_DIR=Artifacts/Compile 42 | mkdir -p ${CMP_DIR}/doc 43 | cp doc/compile.md ${CMP_DIR}/doc/compile.md 44 | cp -r assets/sample_matpack ${CMP_DIR} 45 | cp Release/compile.exe ${CMP_DIR} 46 | cp README.md ${CMP_DIR} 47 | cp LICENSE.md ${CMP_DIR} 48 | cp THIRDPARTY.md ${CMP_DIR} 49 | 50 | - name: Upload JkGfxMod Artifact 51 | uses: actions/upload-artifact@v1.0.0 52 | with: 53 | name: JkGfxMod 54 | path: Artifacts/JkGfxMod 55 | 56 | - name: Upload Compile Artifact 57 | uses: actions/upload-artifact@v1.0.0 58 | with: 59 | name: Compile 60 | path: Artifacts/Compile 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Visual Studio artifacts 2 | 3 | ## User specific files 4 | *.user 5 | 6 | ## Build results 7 | [Dd]ebug/ 8 | [Rr]elease/ 9 | x86/ 10 | 11 | ## Caches 12 | .vs/ 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jonathan Clark 2 | 3 | All rights reserved. 4 | 5 | # MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 11 | of the Software, and to permit persons to whom the Software is furnished to do 12 | so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /assets/jkgm.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": [ 1024, 768 ], 3 | "fullscreen": true, 4 | "correct_game_aspect_ratio": false, 5 | "correct_menu_aspect_ratio": true, 6 | "hud_scale": 1.0, 7 | "max_anisotropy": 2.0, 8 | "antialiasing": { 9 | "type": "MSAA", 10 | "samples": 2 11 | }, 12 | "enable_bloom": true, 13 | "enable_ssao": true, 14 | "enable_parallax": true, 15 | "enable_texture_filtering": true, 16 | "enable_posterized_lighting": false, 17 | "enable_vsync": false, 18 | "command": "jk.exe" 19 | } -------------------------------------------------------------------------------- /assets/sample_matpack/00abb3_base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/00abb3_base.png -------------------------------------------------------------------------------- /assets/sample_matpack/00abb3_base_ruined.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/00abb3_base_ruined.png -------------------------------------------------------------------------------- /assets/sample_matpack/00abb3_cel_2_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/00abb3_cel_2_e.png -------------------------------------------------------------------------------- /assets/sample_matpack/00abb3_cel_3_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/00abb3_cel_3_e.png -------------------------------------------------------------------------------- /assets/sample_matpack/00abb3_cel_4_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/00abb3_cel_4_e.png -------------------------------------------------------------------------------- /assets/sample_matpack/08tgrate_cel0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/08tgrate_cel0.png -------------------------------------------------------------------------------- /assets/sample_matpack/08tgrate_d_cel0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/08tgrate_d_cel0.png -------------------------------------------------------------------------------- /assets/sample_matpack/19cpipe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/19cpipe2.png -------------------------------------------------------------------------------- /assets/sample_matpack/19cpipe2_d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/19cpipe2_d.png -------------------------------------------------------------------------------- /assets/sample_matpack/saberbase0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/saberbase0.png -------------------------------------------------------------------------------- /assets/sample_matpack/saberbase1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdmclark/jkgfxmod/6612413810129ebeae2affeb956d0a5fdb41dd0e/assets/sample_matpack/saberbase1.png -------------------------------------------------------------------------------- /assets/shaders/game.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(location = 0) in vec4 vertex_position; 4 | layout(location = 1) in vec2 vertex_texcoords; 5 | layout(location = 2) in vec4 vertex_color; 6 | layout(location = 3) in vec3 vertex_normal; 7 | 8 | uniform vec2 screen_resolution; 9 | 10 | out vec3 vp_pos; 11 | out vec2 vp_texcoords; 12 | out vec4 vp_color; 13 | out vec3 vp_normal; 14 | out float vp_z; 15 | 16 | void main() 17 | { 18 | gl_Position = vertex_position; 19 | 20 | vp_pos = vec3(vertex_position.xy, vertex_position.w); 21 | vp_texcoords = vertex_texcoords; 22 | vp_color = vertex_color; 23 | vp_normal = vertex_normal; 24 | vp_z = vertex_position.w; 25 | } 26 | -------------------------------------------------------------------------------- /assets/shaders/menu.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D tex; 4 | 5 | in vec2 vp_texcoords; 6 | 7 | layout(location = 0) out vec4 out_color; 8 | 9 | void main() 10 | { 11 | out_color = texture(tex, vp_texcoords); 12 | } 13 | -------------------------------------------------------------------------------- /assets/shaders/menu.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(location = 0) in vec2 vertex_position; 4 | layout(location = 1) in vec2 vertex_texcoords; 5 | 6 | out vec2 vp_texcoords; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(vertex_position, 0.0, 1.0); 11 | vp_texcoords = vertex_texcoords; 12 | } 13 | -------------------------------------------------------------------------------- /assets/shaders/post_gauss15.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | uniform ivec2 blur_direction; 5 | 6 | layout(location = 0) out vec4 out_color; 7 | 8 | vec4 fetch_sym(ivec2 tc, int radius, float fac) 9 | { 10 | vec4 rv = texelFetch(fbuf_image, tc + radius * blur_direction, 0); 11 | rv += texelFetch(fbuf_image, tc - radius * blur_direction, 0); 12 | return rv * fac; 13 | } 14 | 15 | void main() 16 | { 17 | ivec2 tc = ivec2(gl_FragCoord.xy); 18 | 19 | out_color = texelFetch(fbuf_image, tc + blur_direction, 0); 20 | out_color += texelFetch(fbuf_image, tc - blur_direction, 0); 21 | out_color *= 0.1478352381802946; 22 | 23 | out_color += texelFetch(fbuf_image, tc, 0) * 0.1601799366950943; 24 | 25 | out_color += fetch_sym(tc, 2, 0.11622102852187252); 26 | out_color += fetch_sym(tc, 3, 0.07782622199643041); 27 | out_color += fetch_sym(tc, 4, 0.04439114149471707); 28 | out_color += fetch_sym(tc, 5, 0.021566692402713306); 29 | out_color += fetch_sym(tc, 6, 0.008924355643617059); 30 | out_color += fetch_sym(tc, 7, 0.003145353412807818); 31 | } 32 | -------------------------------------------------------------------------------- /assets/shaders/post_gauss3.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | uniform ivec2 blur_direction; 5 | 6 | layout(location = 0) out vec4 out_color; 7 | 8 | void main() 9 | { 10 | ivec2 tc = ivec2(gl_FragCoord.xy); 11 | 12 | out_color = texelFetch(fbuf_image, tc + blur_direction, 0); 13 | out_color += texelFetch(fbuf_image, tc - blur_direction, 0); 14 | out_color *= 0.157731; 15 | 16 | out_color += texelFetch(fbuf_image, tc, 0) * 0.684538; 17 | } -------------------------------------------------------------------------------- /assets/shaders/post_gauss7.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | uniform ivec2 blur_direction; 5 | 6 | layout(location = 0) out vec4 out_color; 7 | 8 | vec4 fetch_sym(ivec2 tc, int radius, float fac) 9 | { 10 | vec4 rv = texelFetch(fbuf_image, tc + radius * blur_direction, 0); 11 | rv += texelFetch(fbuf_image, tc - radius * blur_direction, 0); 12 | return rv * fac; 13 | } 14 | 15 | void main() 16 | { 17 | ivec2 tc = ivec2(gl_FragCoord.xy); 18 | 19 | out_color = texelFetch(fbuf_image, tc + blur_direction, 0); 20 | out_color += texelFetch(fbuf_image, tc - blur_direction, 0); 21 | out_color *= 0.235836; 22 | 23 | out_color += texelFetch(fbuf_image, tc, 0) * 0.33441; 24 | 25 | out_color += fetch_sym(tc, 2, 0.082624); 26 | out_color += fetch_sym(tc, 3, 0.014335); 27 | } -------------------------------------------------------------------------------- /assets/shaders/post_gauss9.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | uniform ivec2 blur_direction; 5 | 6 | layout(location = 0) out vec4 out_color; 7 | 8 | vec4 fetch_sym(ivec2 tc, int radius, float fac) 9 | { 10 | vec4 rv = texelFetch(fbuf_image, tc + radius * blur_direction, 0); 11 | rv += texelFetch(fbuf_image, tc - radius * blur_direction, 0); 12 | return rv * fac; 13 | } 14 | 15 | void main() 16 | { 17 | ivec2 tc = ivec2(gl_FragCoord.xy); 18 | 19 | out_color = texelFetch(fbuf_image, tc + blur_direction, 0); 20 | out_color += texelFetch(fbuf_image, tc - blur_direction, 0); 21 | out_color *= 0.22248396662566527; 22 | 23 | out_color += texelFetch(fbuf_image, tc, 0) * 0.289141483254238; 24 | 25 | out_color += fetch_sym(tc, 2, 0.10132378056964125); 26 | out_color += fetch_sym(tc, 3, 0.02728409576222039); 27 | out_color += fetch_sym(tc, 4, 0.004337415415354041); 28 | } -------------------------------------------------------------------------------- /assets/shaders/post_low_pass.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | 5 | in vec2 vp_texcoords; 6 | 7 | layout(location = 0) out vec4 out_color; 8 | 9 | void main() 10 | { 11 | ivec2 sc = ivec2(gl_FragCoord.xy); 12 | vec4 samp = texelFetch(fbuf_image, sc, 0); 13 | 14 | vec3 col = samp.rgb; 15 | 16 | float lum = dot(vec3(0.2125, 0.7154, 0.0721), col); 17 | lum = max(0.0, lum * 0.5); 18 | 19 | float x = lum * lum * lum; 20 | float fac = smoothstep(0.0, 1.0, x); 21 | 22 | out_color = vec4(col * fac, samp.a); 23 | } 24 | -------------------------------------------------------------------------------- /assets/shaders/post_opaque_composite.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D color_image; 4 | uniform sampler2D emissive_image; 5 | uniform sampler2D occlusion_image; 6 | 7 | layout(location = 0) out vec4 out_color; 8 | 9 | void main() 10 | { 11 | ivec2 tc = ivec2(gl_FragCoord.xy); 12 | 13 | vec4 albedo = texelFetch(color_image, tc, 0); 14 | vec4 emissive = texelFetch(emissive_image, tc, 0); 15 | float occlusion = 1.0 - texelFetch(occlusion_image, tc, 0).r; 16 | 17 | out_color = vec4(emissive.rgb + (albedo.rgb * occlusion), albedo.a); 18 | } -------------------------------------------------------------------------------- /assets/shaders/post_scale.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | 5 | layout(location = 0) out vec4 out_color; 6 | 7 | void main() 8 | { 9 | ivec2 base_tc = ivec2(gl_FragCoord.xy) * 2; 10 | 11 | vec4 a = texelFetchOffset(fbuf_image, base_tc, /*lod*/ 0, ivec2(0, 0)); 12 | vec4 b = texelFetchOffset(fbuf_image, base_tc, /*lod*/ 0, ivec2(1, 0)); 13 | vec4 c = texelFetchOffset(fbuf_image, base_tc, /*lod*/ 0, ivec2(0, 1)); 14 | vec4 d = texelFetchOffset(fbuf_image, base_tc, /*lod*/ 0, ivec2(1, 1)); 15 | 16 | out_color = (a + b + c + d) * 0.25; 17 | } -------------------------------------------------------------------------------- /assets/shaders/post_ssao.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D normal_image; 4 | uniform sampler2D depth_image; 5 | uniform sampler2D noise_image; 6 | 7 | const int num_kernel_samples = 16; 8 | uniform vec3[num_kernel_samples] samples; 9 | 10 | in vec2 vp_texcoords; 11 | 12 | layout(location = 0) out vec4 out_color; 13 | 14 | const float ssao_power = 2.2; 15 | 16 | const float kernel_size = 3.0; 17 | const float kernel_thickness = 1.0; 18 | const float kernel_cutoff = 1.0; 19 | const float kernel_bias = 0.25; 20 | 21 | float sample_depth_direct(vec2 pos) 22 | { 23 | float depth_samp = texture(depth_image, pos).r; 24 | return depth_samp; 25 | 26 | const float z_near = 0.1; 27 | const float z_far = 100.0; 28 | 29 | float z_n = 2.0 * depth_samp; 30 | float z_e = (2.0 * z_near * z_far) / (z_far + z_near - z_n * (z_far - z_near)); 31 | 32 | return z_e; 33 | } 34 | 35 | // Returns 1 if the sample is occluded, 0 otherwise 36 | float sample_depth(vec3 origin, vec3 offset) 37 | { 38 | float depth_radius = kernel_size / max(32.0, origin.z); 39 | 40 | vec2 sample_tc = origin.xy + (offset.xy * depth_radius); 41 | float sample_z = origin.z + (offset.z * kernel_thickness); 42 | 43 | float occ_depth = sample_depth_direct(sample_tc); 44 | 45 | float range_check = smoothstep(0.0, 1.0, kernel_cutoff / abs(origin.z - occ_depth)); 46 | return float(occ_depth < (sample_z - kernel_bias)) * range_check; 47 | } 48 | 49 | void main() 50 | { 51 | vec3 rndnrm = normalize(texture(normal_image, vp_texcoords).rgb); 52 | float origin_depth = texture(depth_image, vp_texcoords).r; 53 | 54 | vec3 rndvec = texture(noise_image, gl_FragCoord.xy / 4.0).xyz; 55 | 56 | vec3 tangent = normalize(rndvec - rndnrm * dot(rndvec, rndnrm)); 57 | vec3 bitangent = cross(rndnrm, tangent); 58 | mat3 basis = mat3(tangent, bitangent, rndnrm); 59 | 60 | vec3 origin = vec3(vp_texcoords, origin_depth); 61 | 62 | float num_fail_samps = 0.0; 63 | for(int i = 0; i < num_kernel_samples; ++i) { 64 | num_fail_samps += sample_depth(origin, basis * samples[i]); 65 | } 66 | 67 | float fail_frac = num_fail_samps / num_kernel_samples; 68 | 69 | float occlusion = pow(1.0 - fail_frac, ssao_power); 70 | 71 | out_color = vec4(1.0 - occlusion, 0.0, 0.0, 0.0); 72 | } 73 | -------------------------------------------------------------------------------- /assets/shaders/post_to_srgb.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | uniform sampler2D fbuf_image; 4 | 5 | const int num_bloom_layers = 5; 6 | uniform sampler2D bloom_fbuf[num_bloom_layers]; 7 | uniform float bloom_weight[num_bloom_layers]; 8 | 9 | in vec2 vp_texcoords; 10 | 11 | layout(location = 0) out vec4 out_color; 12 | 13 | void main() 14 | { 15 | ivec2 sc = ivec2(gl_FragCoord.xy); 16 | vec4 samp = texelFetch(fbuf_image, sc, 0); 17 | 18 | vec4 bloom_samp = vec4(0.0); 19 | bloom_samp += texture(bloom_fbuf[0], vp_texcoords) * bloom_weight[0]; 20 | bloom_samp += texture(bloom_fbuf[1], vp_texcoords) * bloom_weight[1]; 21 | bloom_samp += texture(bloom_fbuf[2], vp_texcoords) * bloom_weight[2]; 22 | bloom_samp += texture(bloom_fbuf[3], vp_texcoords) * bloom_weight[3]; 23 | bloom_samp += texture(bloom_fbuf[4], vp_texcoords) * bloom_weight[4]; 24 | 25 | vec3 combined_color = samp.rgb + bloom_samp.rgb; 26 | out_color = vec4(combined_color, samp.a); 27 | } -------------------------------------------------------------------------------- /assets/shaders/postprocess.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | 3 | layout(location = 0) in vec2 vertex_position; 4 | 5 | out vec2 vp_texcoords; 6 | 7 | void main() 8 | { 9 | gl_Position = vec4(vertex_position, 0.0, 1.0); 10 | vp_texcoords = (vertex_position + 1.0) / 2.0; 11 | } 12 | -------------------------------------------------------------------------------- /base/buffered_input_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "constants.hpp" 4 | #include "input_stream.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | template 9 | class basic_buffered_input_stream : public input_stream { 10 | static_assert(N != 0, "buffer size cannot be zero"); 11 | 12 | private: 13 | input_stream *underlying_stream; 14 | std::array buffer; 15 | span read_span; 16 | 17 | public: 18 | explicit basic_buffered_input_stream(input_stream *underlying_stream) noexcept 19 | : underlying_stream(underlying_stream) 20 | , read_span(buffer.data(), 0) 21 | { 22 | } 23 | 24 | size_t read_some(span dest) override 25 | { 26 | if(read_span.empty()) { 27 | // Refill buffer 28 | size_t amount_buffered = underlying_stream->read_some(make_span(buffer)); 29 | if(amount_buffered == 0) { 30 | // Reached end of stream 31 | return 0; 32 | } 33 | 34 | read_span = make_span(buffer.data(), amount_buffered); 35 | } 36 | 37 | size_t amount_read = std::min(dest.size(), read_span.size()); 38 | 39 | auto read_subspan = read_span.subspan(0, amount_read); 40 | std::copy(read_subspan.begin(), read_subspan.end(), dest.begin()); 41 | 42 | read_span = read_span.subspan(amount_read, read_span.size() - amount_read); 43 | return amount_read; 44 | } 45 | }; 46 | 47 | using buffered_input_stream = basic_buffered_input_stream; 48 | } 49 | -------------------------------------------------------------------------------- /base/buffered_output_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "constants.hpp" 4 | #include "output_stream.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | template 9 | class basic_buffered_output_stream : public output_stream { 10 | static_assert(N != 0, "buffer size cannot be zero"); 11 | 12 | private: 13 | output_stream *underlying_stream; 14 | std::vector buffer; 15 | 16 | protected: 17 | void flush() 18 | { 19 | underlying_stream->write(make_span(buffer)); 20 | buffer.clear(); 21 | } 22 | 23 | public: 24 | explicit basic_buffered_output_stream(output_stream *underlying_stream) noexcept 25 | : underlying_stream(underlying_stream) 26 | { 27 | buffer.reserve(N); 28 | } 29 | 30 | ~basic_buffered_output_stream() override 31 | { 32 | flush(); 33 | } 34 | 35 | basic_buffered_output_stream(basic_buffered_output_stream const &) = delete; 36 | basic_buffered_output_stream(basic_buffered_output_stream &&) = delete; 37 | basic_buffered_output_stream &operator=(basic_buffered_output_stream const &) = delete; 38 | basic_buffered_output_stream &operator=(basic_buffered_output_stream &&) = delete; 39 | 40 | size_t write_some(span src) override 41 | { 42 | size_t max_write_step = std::min(src.size(), N - buffer.size()); 43 | 44 | if(max_write_step > 0) { 45 | // Copy into buffer 46 | auto src_subspan = src.subspan(0, max_write_step); 47 | buffer.insert(buffer.end(), src_subspan.begin(), src_subspan.end()); 48 | } 49 | 50 | if(buffer.size() == N) { 51 | // Buffer is full 52 | flush(); 53 | } 54 | 55 | return max_write_step; 56 | } 57 | }; 58 | 59 | using buffered_output_stream = basic_buffered_output_stream; 60 | } 61 | -------------------------------------------------------------------------------- /base/char.cpp: -------------------------------------------------------------------------------- 1 | #include "char.hpp" 2 | 3 | namespace { 4 | template 5 | bool in_range(char ch) 6 | { 7 | static_assert(lower <= upper, "lower end of range must be less than upper"); 8 | static_assert(lower != upper, 9 | "lower end of range is equal to upper, consider using equality"); 10 | return lower <= ch && ch <= upper; 11 | } 12 | } 13 | 14 | bool jkgm::is_space(char ch) 15 | { 16 | return in_range<0x09, 0x0D>(ch) || ch == 0x20; 17 | } 18 | 19 | bool jkgm::is_digit(char ch) 20 | { 21 | return in_range<'0', '9'>(ch); 22 | } 23 | 24 | bool jkgm::is_xdigit(char ch) 25 | { 26 | return in_range<'0', '9'>(ch) || in_range<'a', 'f'>(ch) || in_range<'A', 'F'>(ch); 27 | } 28 | 29 | bool jkgm::is_upper(char ch) 30 | { 31 | return in_range<'A', 'Z'>(ch); 32 | } 33 | 34 | bool jkgm::is_lower(char ch) 35 | { 36 | return in_range<'a', 'z'>(ch); 37 | } 38 | 39 | bool jkgm::is_alpha(char ch) 40 | { 41 | return is_upper(ch) || is_lower(ch); 42 | } 43 | 44 | bool jkgm::is_alnum(char ch) 45 | { 46 | return is_digit(ch) || is_alpha(ch); 47 | } 48 | 49 | bool jkgm::is_punct(char ch) 50 | { 51 | switch(ch) { 52 | case '!': 53 | case '\"': 54 | case '#': 55 | case '$': 56 | case '%': 57 | case '&': 58 | case '\'': 59 | case '(': 60 | case ')': 61 | case '*': 62 | case '+': 63 | case ',': 64 | case '-': 65 | case '.': 66 | case '/': 67 | case ':': 68 | case ';': 69 | case '<': 70 | case '=': 71 | case '>': 72 | case '?': 73 | case '@': 74 | case '[': 75 | case '\\': 76 | case ']': 77 | case '^': 78 | case '_': 79 | case '`': 80 | case '{': 81 | case '|': 82 | case '}': 83 | case '~': 84 | return true; 85 | 86 | default: 87 | return false; 88 | } 89 | } 90 | 91 | char jkgm::to_lower(char ch) 92 | { 93 | if(in_range<'A', 'Z'>(ch)) { 94 | return ('a' - 'A') + ch; 95 | } 96 | 97 | return ch; 98 | } 99 | -------------------------------------------------------------------------------- /base/char.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace jkgm { 4 | bool is_space(char ch); 5 | bool is_digit(char ch); 6 | bool is_xdigit(char ch); 7 | bool is_upper(char ch); 8 | bool is_lower(char ch); 9 | bool is_alpha(char ch); 10 | bool is_alnum(char ch); 11 | bool is_punct(char ch); 12 | 13 | char to_lower(char ch); 14 | } -------------------------------------------------------------------------------- /base/constants.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "build_traits.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | template 8 | constexpr size_t platform_io_buffer_size = 4096U; 9 | 10 | template <> 11 | constexpr size_t platform_io_buffer_size = 131072U; 12 | 13 | constexpr size_t io_buffer_size = platform_io_buffer_size; 14 | } 15 | -------------------------------------------------------------------------------- /base/default_logger.cpp: -------------------------------------------------------------------------------- 1 | #include "default_logger.hpp" 2 | #include "env.hpp" 3 | #include "file_log_backend.hpp" 4 | #include "log.hpp" 5 | 6 | void jkgm::setup_default_logging() 7 | { 8 | // Initialize logging 9 | auto maybe_log_file = get_environment_variable("JKGM_LOG_FILE"); 10 | if(maybe_log_file.has_value()) { 11 | emplace_log_backend({log_level::error, 12 | log_level::warning, 13 | log_level::info, 14 | log_level::debug, 15 | log_level::trace}, 16 | *maybe_log_file); 17 | } 18 | } 19 | 20 | void jkgm::add_file_logging(std::string const &path) 21 | { 22 | emplace_log_backend( 23 | {log_level::error, log_level::warning, log_level::info, log_level::debug, log_level::trace}, 24 | path); 25 | } -------------------------------------------------------------------------------- /base/default_logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace jkgm { 6 | void setup_default_logging(); 7 | void add_file_logging(std::string const &fn); 8 | } -------------------------------------------------------------------------------- /base/diagnostic_context.cpp: -------------------------------------------------------------------------------- 1 | #include "diagnostic_context.hpp" 2 | #include "log_frontend.hpp" 3 | 4 | jkgm::diagnostic_context::diagnostic_context(diagnostic_context_location loc) 5 | { 6 | diagnostic_context_handle = get_local()->push_diagnostic_context( 7 | std::move(loc.filename), loc.first_line, loc.first_col, loc.last_line, loc.last_col); 8 | } 9 | 10 | jkgm::diagnostic_context::diagnostic_context(std::optional filename, 11 | int first_line, 12 | int first_col, 13 | int last_line, 14 | int last_col) 15 | { 16 | diagnostic_context_handle = get_local()->push_diagnostic_context( 17 | std::move(filename), first_line, first_col, last_line, last_col); 18 | } 19 | 20 | void jkgm::diagnostic_context::release() 21 | { 22 | if(diagnostic_context_handle.has_value()) { 23 | get_local()->release_diagnostic_context(*diagnostic_context_handle); 24 | diagnostic_context_handle.reset(); 25 | } 26 | } 27 | 28 | jkgm::diagnostic_context::~diagnostic_context() 29 | { 30 | try { 31 | release(); 32 | } 33 | catch(...) { 34 | // Nothing to do 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /base/diagnostic_context.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "diagnostic_context_location.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | class diagnostic_context { 9 | private: 10 | std::optional diagnostic_context_handle; 11 | 12 | public: 13 | explicit diagnostic_context(diagnostic_context_location loc); 14 | explicit diagnostic_context(std::optional filename, 15 | int first_line = 0, 16 | int first_col = 0, 17 | int last_line = 0, 18 | int last_col = 0); 19 | 20 | void release(); 21 | ~diagnostic_context(); 22 | 23 | diagnostic_context(diagnostic_context const &) = delete; 24 | diagnostic_context(diagnostic_context &&) = delete; 25 | diagnostic_context &operator=(diagnostic_context const &) = delete; 26 | diagnostic_context &operator=(diagnostic_context &&) = delete; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /base/diagnostic_context_location.cpp: -------------------------------------------------------------------------------- 1 | #include "diagnostic_context_location.hpp" 2 | #include 3 | #include 4 | 5 | jkgm::diagnostic_context_location::diagnostic_context_location(std::optional filename, 6 | int first_line, 7 | int first_col, 8 | int last_line, 9 | int last_col) 10 | : filename(std::move(filename)) 11 | , first_line(first_line) 12 | , first_col(first_col) 13 | , last_line(last_line) 14 | , last_col(last_col) 15 | { 16 | } 17 | 18 | bool jkgm::diagnostic_context_location::operator==(diagnostic_context_location const &loc) const 19 | { 20 | return std::tie(filename, first_line, first_col, last_line, last_col) == 21 | std::tie(loc.filename, loc.first_line, loc.first_col, loc.last_line, loc.last_col); 22 | } 23 | 24 | jkgm::diagnostic_context_location jkgm::location_union(diagnostic_context_location start, 25 | diagnostic_context_location const &stop) 26 | { 27 | assert((start.filename == stop.filename || !stop.filename.has_value()) && 28 | "cannot union diagnostic context locations from two different file contexts"); 29 | return diagnostic_context_location(std::move(start.filename), 30 | start.first_line, 31 | start.first_col, 32 | stop.last_line, 33 | stop.last_col); 34 | } 35 | -------------------------------------------------------------------------------- /base/diagnostic_context_location.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace jkgm { 7 | class diagnostic_context_location { 8 | public: 9 | std::optional filename; 10 | int first_line = 0; 11 | int first_col = 0; 12 | int last_line = 0; 13 | int last_col = 0; 14 | 15 | diagnostic_context_location() = default; 16 | explicit diagnostic_context_location(std::optional filename, 17 | int first_line, 18 | int first_col, 19 | int last_line = 0, 20 | int last_col = 0); 21 | 22 | bool operator==(diagnostic_context_location const &loc) const; 23 | }; 24 | 25 | diagnostic_context_location location_union(diagnostic_context_location start, 26 | diagnostic_context_location const &stop); 27 | } 28 | -------------------------------------------------------------------------------- /base/env.cpp: -------------------------------------------------------------------------------- 1 | #include "env.hpp" 2 | #include "build_traits.hpp" 3 | #include "win32.hpp" 4 | 5 | bool jkgm::has_environment_variable(cstring_view key) 6 | { 7 | std::optional rv; 8 | 9 | if constexpr(build_traits::is_windows) { 10 | rv = win32::get_environment_variable(key); 11 | } 12 | 13 | return rv.has_value() && !rv->empty(); 14 | } 15 | 16 | std::optional jkgm::get_environment_variable(cstring_view key) 17 | { 18 | std::optional rv; 19 | 20 | if constexpr(build_traits::is_windows) { 21 | rv = win32::get_environment_variable(key); 22 | } 23 | 24 | if(!rv.has_value() || rv->empty()) { 25 | return std::nullopt; 26 | } 27 | 28 | return rv; 29 | } 30 | 31 | void jkgm::set_environment_variable(cstring_view key, std::optional value) 32 | { 33 | if constexpr(build_traits::is_windows) { 34 | win32::set_environment_variable(key, value); 35 | } 36 | } 37 | 38 | jkgm::environment jkgm::get_environment() 39 | { 40 | environment rv; 41 | if constexpr(build_traits::is_windows) { 42 | *rv = win32::get_environment_strings(); 43 | } 44 | 45 | return rv; 46 | } 47 | 48 | jkgm::environment jkgm::patch_environment(environment env, environment_delta const &delta) 49 | { 50 | environment rv = std::move(env); 51 | for(auto const &var : *delta) { 52 | if(var.second.has_value()) { 53 | rv->insert_or_assign(var.first, *var.second); 54 | } 55 | else { 56 | rv->erase(var.first); 57 | } 58 | } 59 | 60 | return rv; 61 | } 62 | -------------------------------------------------------------------------------- /base/env.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cstring_view.hpp" 4 | #include "tagged.hpp" 5 | #include 6 | #include 7 | 8 | namespace jkgm { 9 | using environment_map = std::unordered_map; 10 | MAKE_TAGGED_RANGE_TYPE(environment, environment_map, environment_map::value_type); 11 | 12 | using environment_delta_map = std::unordered_map>; 13 | MAKE_TAGGED_RANGE_TYPE(environment_delta, 14 | environment_delta_map, 15 | environment_delta_map::value_type); 16 | 17 | bool has_environment_variable(cstring_view key); 18 | std::optional get_environment_variable(cstring_view key); 19 | void set_environment_variable(cstring_view key, std::optional value); 20 | 21 | environment get_environment(); 22 | environment patch_environment(environment env, environment_delta const &delta); 23 | } 24 | -------------------------------------------------------------------------------- /base/fd_input_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "fd_input_stream.hpp" 2 | 3 | namespace jkgm { 4 | namespace { 5 | template 6 | struct helper_impl; 7 | 8 | template <> 9 | struct helper_impl { 10 | static size_t read_some(win32::handle_id fd, span dest) 11 | { 12 | return win32::read_file(fd, dest); 13 | } 14 | 15 | static win32::unique_handle duplicate(win32::handle_id fd) 16 | { 17 | return win32::duplicate_handle(fd, 18 | /*children inherit*/ false, 19 | {win32::duplicate_flag::same_access}); 20 | } 21 | 22 | static void close(win32::handle_id fd) 23 | { 24 | win32::close_handle(fd); 25 | } 26 | }; 27 | 28 | using helper = helper_impl; 29 | } 30 | } 31 | 32 | jkgm::shared_fd_input_stream::shared_fd_input_stream(detail::fd_s_utype fd) noexcept 33 | : fd(fd) 34 | { 35 | } 36 | 37 | size_t jkgm::shared_fd_input_stream::read_some(span dest) 38 | { 39 | return helper::read_some(fd, dest); 40 | } 41 | 42 | jkgm::fd_input_stream::fd_input_stream(detail::fd_s_type &&fd) 43 | : fd(std::move(fd)) 44 | { 45 | } 46 | 47 | jkgm::detail::fd_s_utype jkgm::fd_input_stream::get() const 48 | { 49 | return fd.value(); 50 | } 51 | 52 | jkgm::detail::fd_s_utype jkgm::fd_input_stream::release() 53 | { 54 | return fd.release(); 55 | } 56 | 57 | jkgm::fd_input_stream jkgm::fd_input_stream::duplicate() const 58 | { 59 | return fd_input_stream(helper::duplicate(*fd)); 60 | } 61 | 62 | void jkgm::fd_input_stream::close() 63 | { 64 | helper::close(fd.release()); 65 | } 66 | 67 | size_t jkgm::fd_input_stream::read_some(span dest) 68 | { 69 | return helper::read_some(*fd, dest); 70 | } 71 | -------------------------------------------------------------------------------- /base/fd_input_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "build_traits.hpp" 4 | #include "input_stream.hpp" 5 | #include "win32.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | namespace detail { 10 | using fd_s_utype = specialization_t>; 11 | using fd_s_type = specialization_t>; 12 | } 13 | 14 | class shared_fd_input_stream : public input_stream { 15 | private: 16 | detail::fd_s_utype fd; 17 | 18 | public: 19 | explicit shared_fd_input_stream(detail::fd_s_utype fd) noexcept; 20 | size_t read_some(span dest) override; 21 | }; 22 | 23 | class fd_input_stream : public input_stream { 24 | private: 25 | detail::fd_s_type fd; 26 | 27 | public: 28 | explicit fd_input_stream(detail::fd_s_type &&fd); 29 | detail::fd_s_utype get() const; 30 | detail::fd_s_utype release(); 31 | fd_input_stream duplicate() const; 32 | void close(); 33 | size_t read_some(span dest) override; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /base/fd_output_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "fd_output_stream.hpp" 2 | 3 | namespace jkgm { 4 | namespace { 5 | template 6 | struct helper_impl; 7 | 8 | template <> 9 | struct helper_impl { 10 | static size_t write_some(win32::handle_id fd, span src) 11 | { 12 | return win32::write_file(fd, src); 13 | } 14 | 15 | static win32::unique_handle duplicate(win32::handle_id fd) 16 | { 17 | return win32::duplicate_handle( 18 | fd, /*children inherit*/ false, {win32::duplicate_flag::same_access}); 19 | } 20 | 21 | static void close(win32::handle_id fd) 22 | { 23 | win32::close_handle(fd); 24 | } 25 | }; 26 | 27 | using helper = helper_impl; 28 | } 29 | } 30 | 31 | jkgm::shared_fd_output_stream::shared_fd_output_stream(detail::fd_os_utype fd) 32 | : fd(fd) 33 | { 34 | } 35 | 36 | size_t jkgm::shared_fd_output_stream::write_some(span src) 37 | { 38 | return helper::write_some(fd, src); 39 | } 40 | 41 | jkgm::fd_output_stream::fd_output_stream(detail::fd_os_type &&fd) 42 | : fd(std::move(fd)) 43 | { 44 | } 45 | 46 | jkgm::detail::fd_os_utype jkgm::fd_output_stream::get() const 47 | { 48 | return fd.value(); 49 | } 50 | 51 | jkgm::detail::fd_os_utype jkgm::fd_output_stream::release() 52 | { 53 | return fd.release(); 54 | } 55 | 56 | jkgm::fd_output_stream jkgm::fd_output_stream::duplicate() const 57 | { 58 | return fd_output_stream(helper::duplicate(*fd)); 59 | } 60 | 61 | void jkgm::fd_output_stream::close() 62 | { 63 | helper::close(fd.release()); 64 | } 65 | 66 | size_t jkgm::fd_output_stream::write_some(span dest) 67 | { 68 | return helper::write_some(*fd, dest); 69 | } 70 | -------------------------------------------------------------------------------- /base/fd_output_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "build_traits.hpp" 4 | #include "output_stream.hpp" 5 | #include "win32.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | namespace detail { 10 | using fd_os_utype = specialization_t>; 11 | using fd_os_type = specialization_t>; 12 | } 13 | 14 | class shared_fd_output_stream : public output_stream { 15 | private: 16 | detail::fd_os_utype fd; 17 | 18 | public: 19 | explicit shared_fd_output_stream(detail::fd_os_utype fd); 20 | size_t write_some(span src) override; 21 | }; 22 | 23 | class fd_output_stream : public output_stream { 24 | private: 25 | detail::fd_os_type fd; 26 | 27 | public: 28 | explicit fd_output_stream(detail::fd_os_type &&fd); 29 | detail::fd_os_utype get() const; 30 | detail::fd_os_utype release(); 31 | fd_output_stream duplicate() const; 32 | void close(); 33 | size_t write_some(span dest) override; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /base/file_block.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "build_traits.hpp" 4 | #include "filesystem.hpp" 5 | #include "input_block.hpp" 6 | #include "output_block.hpp" 7 | #include "win32.hpp" 8 | #include 9 | 10 | namespace jkgm { 11 | namespace detail { 12 | using fb_s_type = specialization_t>; 13 | } 14 | 15 | class file_output_block : public output_block { 16 | private: 17 | detail::fb_s_type fd; 18 | 19 | public: 20 | explicit file_output_block(fs::path const &filename); 21 | size_t write_some(span src) override; 22 | void set_position(size_t offset) override; 23 | size_t position() override; 24 | }; 25 | 26 | class file_input_block : public input_block { 27 | private: 28 | detail::fb_s_type fd; 29 | 30 | public: 31 | explicit file_input_block(fs::path const &filename); 32 | size_t read_some(span dest) override; 33 | void seek(int offset) override; 34 | void set_position(size_t offset) override; 35 | size_t position() override; 36 | size_t size() override; 37 | }; 38 | 39 | std::unique_ptr make_file_output_block(fs::path const &filename); 40 | std::unique_ptr make_file_input_block(fs::path const &filename); 41 | } 42 | -------------------------------------------------------------------------------- /base/file_log_backend.cpp: -------------------------------------------------------------------------------- 1 | #include "file_log_backend.hpp" 2 | #include "format.hpp" 3 | #include "pipe.hpp" 4 | 5 | jkgm::file_log_backend::file_log_backend(fs::path const &log_filename) 6 | : file(std::make_unique(make_output_file_append_pipe(log_filename))) 7 | { 8 | } 9 | 10 | void jkgm::file_log_backend::write_message(std::string_view filename, 11 | int line_number, 12 | log_level level, 13 | std::string_view message) 14 | { 15 | file->write(make_span( 16 | str(fmt(filename, "|", line_number, "|", to_string(level), "> ", message, "\n")))); 17 | } -------------------------------------------------------------------------------- /base/file_log_backend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "filesystem.hpp" 4 | #include "log_backend.hpp" 5 | #include "output_stream.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | class file_log_backend : public log_backend { 10 | private: 11 | std::unique_ptr file; 12 | 13 | public: 14 | explicit file_log_backend(fs::path const &log_filename); 15 | 16 | void write_message(std::string_view filename, 17 | int line_number, 18 | log_level level, 19 | std::string_view message) override; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /base/file_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "file_stream.hpp" 2 | #include "buffered_input_stream.hpp" 3 | #include "buffered_output_stream.hpp" 4 | #include "file_block.hpp" 5 | 6 | namespace { 7 | class file_output_stream : public jkgm::output_stream { 8 | private: 9 | jkgm::file_output_block fb; 10 | jkgm::buffered_output_stream fs; 11 | 12 | public: 13 | explicit file_output_stream(fs::path const &filename) 14 | : fb(filename) 15 | , fs(&fb) 16 | { 17 | } 18 | 19 | size_t write_some(jkgm::span src) override 20 | { 21 | return fs.write_some(src); 22 | } 23 | }; 24 | 25 | class file_input_stream : public jkgm::input_stream { 26 | private: 27 | jkgm::file_input_block fb; 28 | jkgm::buffered_input_stream fs; 29 | 30 | public: 31 | explicit file_input_stream(fs::path const &filename) 32 | : fb(filename) 33 | , fs(&fb) 34 | { 35 | } 36 | 37 | size_t read_some(jkgm::span dest) override 38 | { 39 | return fs.read_some(dest); 40 | } 41 | }; 42 | } 43 | 44 | std::unique_ptr jkgm::make_file_output_stream(fs::path const &filename) 45 | { 46 | return std::make_unique(filename); 47 | } 48 | 49 | std::unique_ptr jkgm::make_file_input_stream(fs::path const &filename) 50 | { 51 | return std::make_unique(filename); 52 | } 53 | -------------------------------------------------------------------------------- /base/file_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "filesystem.hpp" 4 | #include "input_stream.hpp" 5 | #include "output_stream.hpp" 6 | 7 | namespace jkgm { 8 | std::unique_ptr make_file_output_stream(fs::path const &filename); 9 | std::unique_ptr make_file_input_stream(fs::path const &filename); 10 | } 11 | -------------------------------------------------------------------------------- /base/filesystem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace fs = std::filesystem; 6 | -------------------------------------------------------------------------------- /base/format_base.cpp: -------------------------------------------------------------------------------- 1 | #include "format_base.hpp" 2 | 3 | jkgm::detail::formatter_fill_op::formatter_fill_op(jkgm::format_buffer *buffer) 4 | : buffer(buffer) 5 | { 6 | } 7 | 8 | jkgm::detail::formatter_sequence_fill_op::formatter_sequence_fill_op(jkgm::format_buffer *buffer) 9 | : buffer(buffer) 10 | { 11 | } 12 | 13 | jkgm::detail::string_format_buffer::string_format_buffer(std::string *buffer) 14 | : buffer(buffer) 15 | { 16 | } 17 | 18 | void jkgm::detail::string_format_buffer::append(std::string_view value) 19 | { 20 | buffer->append(value); 21 | } 22 | -------------------------------------------------------------------------------- /base/global.cpp: -------------------------------------------------------------------------------- 1 | #include "global.hpp" 2 | #include 3 | #include 4 | 5 | namespace { 6 | using global_map = std::unordered_map>; 7 | using global_registry = std::tuple; 8 | 9 | global_registry *get_global_registry() 10 | { 11 | static global_registry reg; 12 | return ® 13 | } 14 | } 15 | 16 | jkgm::global::global(global_constructor_protector_tag /* unused */) {} 17 | 18 | std::shared_ptr jkgm::global::reserve_global_dependency_with_factory( 19 | std::type_index tid, 20 | detail::abstract_global_factory const &factory) 21 | { 22 | auto &gr = std::get<0>(*get_global_registry()); 23 | 24 | auto it = gr.find(tid); 25 | if(it == gr.end()) { 26 | it = gr.emplace(tid, factory.make_global()).first; 27 | } 28 | 29 | reserved_global_dependencies.push_back(it->second); 30 | 31 | return it->second; 32 | } 33 | 34 | std::shared_ptr 35 | jkgm::detail::get_or_create_global(std::type_index tid, abstract_global_factory const &factory) 36 | { 37 | auto *gr_pair = get_global_registry(); 38 | auto &gr = std::get<0>(*gr_pair); 39 | auto &grmut = std::get<1>(*gr_pair); 40 | 41 | std::lock_guard lk(grmut); 42 | 43 | auto it = gr.find(tid); 44 | if(it == gr.end()) { 45 | it = gr.emplace(tid, factory.make_global()).first; 46 | } 47 | 48 | return it->second; 49 | } 50 | -------------------------------------------------------------------------------- /base/hash_combine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace jkgm { 6 | template > 7 | size_t hash_combine(size_t curr, T const &v) 8 | { 9 | SubHashT hasher; 10 | return curr ^ (hasher(v) + 0x9e3779b9U + (curr << 6U) + (curr >> 2U)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /base/input_block.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "input_stream.hpp" 4 | 5 | namespace jkgm { 6 | 7 | class input_block : public input_stream { 8 | public: 9 | virtual void seek(int offset) = 0; 10 | virtual void set_position(size_t offset) = 0; 11 | virtual size_t position() = 0; 12 | 13 | virtual size_t size() = 0; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /base/input_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "input_stream.hpp" 2 | #include "constants.hpp" 3 | #include "output_stream.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | void jkgm::input_stream::read(span dest) 9 | { 10 | size_t amount_remaining = dest.size(); 11 | while(amount_remaining > 0) { 12 | size_t amount_read = read_some(dest); 13 | if(amount_read == 0) { 14 | // Reached end of file inside read 15 | throw std::runtime_error("input_stream::read size exceeds bounds"); 16 | } 17 | 18 | amount_remaining -= amount_read; 19 | if(amount_remaining > 0) { 20 | dest = dest.subspan(amount_read, amount_remaining); 21 | } 22 | } 23 | } 24 | 25 | void jkgm::input_stream::copy_to(output_stream *s) 26 | { 27 | char buffer[io_buffer_size]; 28 | for(;;) { 29 | size_t amt = read_some(make_span(buffer)); 30 | if(amt == 0) { 31 | break; 32 | } 33 | 34 | s->write(make_span(buffer).subspan(0, amt)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /base/input_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "span.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | class output_stream; 9 | 10 | class input_stream { 11 | protected: 12 | input_stream() = default; 13 | 14 | public: 15 | virtual ~input_stream() = default; 16 | 17 | input_stream(input_stream const &) = default; 18 | input_stream(input_stream &&) = default; 19 | input_stream &operator=(input_stream const &) = default; 20 | input_stream &operator=(input_stream &&) = default; 21 | 22 | void read(span dest); 23 | virtual size_t read_some(span dest) = 0; 24 | 25 | void copy_to(output_stream *s); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /base/local.cpp: -------------------------------------------------------------------------------- 1 | #include "local.hpp" 2 | #include 3 | 4 | namespace { 5 | using local_map = std::unordered_map>; 6 | thread_local std::unique_ptr local_registry; 7 | } 8 | 9 | jkgm::local::local(local_constructor_protector_tag /*unused*/) {} 10 | 11 | std::shared_ptr 12 | jkgm::detail::get_or_create_local(std::type_index tid, 13 | detail::abstract_local_factory const &factory) 14 | { 15 | if(!local_registry) { 16 | local_registry = std::make_unique(); 17 | } 18 | 19 | auto it = local_registry->find(tid); 20 | if(it == local_registry->end()) { 21 | it = local_registry->emplace(tid, factory.make_local()).first; 22 | } 23 | 24 | return it->second; 25 | } 26 | -------------------------------------------------------------------------------- /base/local.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | class local; 9 | 10 | namespace detail { 11 | template 12 | class local_factory; 13 | } 14 | 15 | class local_constructor_protector_tag { 16 | template 17 | friend class jkgm::detail::local_factory; 18 | 19 | private: 20 | local_constructor_protector_tag() = default; 21 | }; 22 | 23 | namespace detail { 24 | class abstract_local_factory { 25 | public: 26 | abstract_local_factory() = default; 27 | virtual ~abstract_local_factory() = default; 28 | 29 | abstract_local_factory(abstract_local_factory const &) = delete; 30 | abstract_local_factory(abstract_local_factory &&) = delete; 31 | abstract_local_factory &operator=(abstract_local_factory const &) = delete; 32 | abstract_local_factory &operator=(abstract_local_factory &&) = delete; 33 | 34 | virtual std::shared_ptr make_local() const = 0; 35 | }; 36 | 37 | template 38 | class local_factory : public abstract_local_factory { 39 | public: 40 | std::shared_ptr make_local() const override 41 | { 42 | return std::make_shared(local_constructor_protector_tag()); 43 | } 44 | }; 45 | 46 | std::shared_ptr get_or_create_local(std::type_index tid, 47 | abstract_local_factory const &factory); 48 | } 49 | 50 | class local { 51 | protected: 52 | explicit local(local_constructor_protector_tag /*tag*/); 53 | 54 | public: 55 | virtual ~local() = default; 56 | 57 | local() = delete; 58 | local(local const &) = delete; 59 | local(local &&) = delete; 60 | local &operator=(local const &) = delete; 61 | local &operator=(local &&) = delete; 62 | }; 63 | 64 | template 65 | std::shared_ptr get_local() 66 | { 67 | auto g = get_or_create_local(typeid(LocalT), detail::local_factory()); 68 | return std::dynamic_pointer_cast(g); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /base/log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.hpp" 2 | 3 | void jkgm::erase_log_backends() 4 | { 5 | get_global()->erase_log_backends(); 6 | } 7 | 8 | void jkgm::write_log_message(std::string_view src_filename, 9 | int src_line_number, 10 | log_level level, 11 | format_script const &fmt) 12 | { 13 | get_local()->write_log_message(src_filename, src_line_number, level, fmt); 14 | } 15 | -------------------------------------------------------------------------------- /base/log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "format.hpp" 4 | #include "log_backend.hpp" 5 | #include "log_frontend.hpp" 6 | #include "log_midend.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace jkgm { 13 | template 14 | void emplace_log_backend(log_levels filter, ArgT &&...arg) 15 | { 16 | get_global()->insert_log_backend( 17 | filter, std::make_unique(std::forward(arg)...)); 18 | } 19 | 20 | void erase_log_backends(); 21 | 22 | void write_log_message(std::string_view src_filename, 23 | int src_line_number, 24 | log_level level, 25 | format_script const &fmt); 26 | } 27 | 28 | #define LOG_WITH_LEVEL(level, ...) \ 29 | ::jkgm::write_log_message(__FILE__, __LINE__, (level), (::jkgm::fmt(__VA_ARGS__))) 30 | 31 | #define LOG_ERROR(...) LOG_WITH_LEVEL(::jkgm::log_level::error, __VA_ARGS__) 32 | 33 | #define LOG_WARNING(...) LOG_WITH_LEVEL(::jkgm::log_level::warning, __VA_ARGS__) 34 | 35 | #define LOG_INFO(...) LOG_WITH_LEVEL(::jkgm::log_level::info, __VA_ARGS__) 36 | 37 | #define LOG_DEBUG(...) LOG_WITH_LEVEL(::jkgm::log_level::debug, __VA_ARGS__) 38 | 39 | #define LOG_TRACE(...) LOG_WITH_LEVEL(::jkgm::log_level::trace, __VA_ARGS__) 40 | -------------------------------------------------------------------------------- /base/log_backend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "log_level.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class log_backend { 8 | protected: 9 | log_backend() = default; 10 | 11 | public: 12 | virtual ~log_backend() = default; 13 | 14 | log_backend(log_backend const &) = delete; 15 | log_backend(log_backend &&) = delete; 16 | log_backend &operator=(log_backend const &) = delete; 17 | log_backend &operator=(log_backend &&) = delete; 18 | 19 | virtual void write_message(std::string_view filename, 20 | int line_number, 21 | log_level level, 22 | std::string_view message) = 0; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /base/log_frontend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "diagnostic_context.hpp" 4 | #include "log_midend.hpp" 5 | #include "format.hpp" 6 | #include "local.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace jkgm { 12 | class log_frontend : public local { 13 | friend class diagnostic_context; 14 | 15 | private: 16 | class diagnostic_context_frame { 17 | public: 18 | bool referenced = true; 19 | std::optional> filename; 20 | int first_line; 21 | int first_col; 22 | int last_line; 23 | int last_col; 24 | int internal_error_count = 0; 25 | size_t error_count_index; 26 | 27 | diagnostic_context_frame(std::optional> filename, 28 | int first_line, 29 | int first_col, 30 | int last_line, 31 | int last_col, 32 | size_t error_count_index); 33 | }; 34 | 35 | std::shared_ptr midend; 36 | std::vector diagnostic_context; 37 | bool diagnostic_preamble_dirty = false; 38 | std::string computed_diagnostic_preamble; 39 | 40 | void update_diagnostic_preamble(); 41 | 42 | size_t push_diagnostic_context(std::optional filename, 43 | int first_line, 44 | int first_col, 45 | int last_line, 46 | int last_col); 47 | 48 | void release_diagnostic_context(size_t index); 49 | 50 | public: 51 | explicit log_frontend(local_constructor_protector_tag tag); 52 | 53 | void write_log_message(std::string_view filename, 54 | int line_number, 55 | log_level level, 56 | format_script const &message); 57 | 58 | int diagnostic_file_error_count() const; 59 | std::string diagnostic_file_name() const; 60 | size_t get_diagnostic_frame_count() const; 61 | }; 62 | 63 | int diagnostic_file_error_count(); 64 | std::string diagnostic_file_name(); 65 | size_t get_diagnostic_frame_count(); 66 | } 67 | -------------------------------------------------------------------------------- /base/log_level.cpp: -------------------------------------------------------------------------------- 1 | #include "log_level.hpp" 2 | #include 3 | #include 4 | 5 | namespace { 6 | std::map str_log_level_map{{jkgm::log_level::error, "error"}, 7 | {jkgm::log_level::warning, "warning"}, 8 | {jkgm::log_level::info, "info"}, 9 | {jkgm::log_level::debug, "debug"}, 10 | {jkgm::log_level::trace, "trace"}}; 11 | } 12 | 13 | std::string const &jkgm::to_string(log_level v) 14 | { 15 | return str_log_level_map.at(v); 16 | } -------------------------------------------------------------------------------- /base/log_level.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "flag_set.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | enum class log_level : uint8_t { error = 1, warning = 2, info = 4, debug = 8, trace = 16 }; 9 | 10 | using log_levels = flag_set; 11 | 12 | std::string const &to_string(log_level v); 13 | } -------------------------------------------------------------------------------- /base/log_midend.cpp: -------------------------------------------------------------------------------- 1 | #include "log_midend.hpp" 2 | 3 | jkgm::log_midend::log_midend(global_constructor_protector_tag tag) 4 | : global(tag) 5 | { 6 | } 7 | 8 | void jkgm::log_midend::insert_log_backend(log_levels filter, std::unique_ptr &&b) 9 | { 10 | std::lock_guard lock(log_backend_lock); 11 | log_backends.emplace_back(filter, std::move(b)); 12 | present_log_levels += filter; 13 | } 14 | 15 | void jkgm::log_midend::erase_log_backends() 16 | { 17 | std::lock_guard lock(log_backend_lock); 18 | present_log_levels = {}; 19 | log_backends.clear(); 20 | } 21 | 22 | void jkgm::log_midend::write_log_message(std::string_view filename, 23 | int line_number, 24 | log_level level, 25 | std::string_view diagnostic_context, 26 | format_script const &message) 27 | { 28 | std::lock_guard lock(log_backend_lock); 29 | 30 | // Check backends to see if the message needs to be formatted 31 | if(!(present_log_levels & level)) { 32 | return; 33 | } 34 | 35 | auto msg = str(fmt(diagnostic_context, message)); 36 | 37 | for(auto &b : log_backends) { 38 | if(std::get<0>(b) & level) { 39 | std::get<1>(b)->write_message(filename, line_number, level, msg); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /base/log_midend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "log_backend.hpp" 4 | #include "format.hpp" 5 | #include "global.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace jkgm { 11 | class log_midend : public global { 12 | private: 13 | log_levels present_log_levels; 14 | std::vector>> log_backends; 15 | std::mutex log_backend_lock; 16 | 17 | public: 18 | explicit log_midend(global_constructor_protector_tag tag); 19 | 20 | void insert_log_backend(log_levels filter, std::unique_ptr &&b); 21 | void erase_log_backends(); 22 | 23 | void write_log_message(std::string_view filename, 24 | int line_number, 25 | log_level level, 26 | std::string_view diagnostic_context, 27 | format_script const &message); 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /base/md5.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "span.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace jkgm { 10 | class md5 { 11 | private: 12 | std::tuple values; 13 | 14 | public: 15 | constexpr md5(uint32_t a, uint32_t b, uint32_t c, uint32_t d) 16 | : values(a, b, c, d) 17 | { 18 | } 19 | 20 | explicit md5(std::string_view m); 21 | explicit operator std::string() const; 22 | 23 | bool operator<(md5 const &m) const; 24 | bool operator==(md5 const &m) const; 25 | bool operator!=(md5 const &m) const; 26 | 27 | size_t hash() const; 28 | 29 | std::tuple as_tuple() const; 30 | }; 31 | 32 | class md5_hasher { 33 | private: 34 | uint32_t a0 = 0; 35 | uint32_t b0 = 0; 36 | uint32_t c0 = 0; 37 | uint32_t d0 = 0; 38 | 39 | uint32_t chunk[16] = {0}; 40 | span chunk_span; 41 | uint64_t total_bytes = 0; 42 | 43 | void add_chunk(); 44 | 45 | public: 46 | md5_hasher(); 47 | 48 | void clear(); 49 | void add(span src); 50 | md5 finish(); 51 | }; 52 | } 53 | 54 | namespace std { 55 | template <> 56 | struct hash { 57 | size_t operator()(jkgm::md5 const &m) const 58 | { 59 | return m.hash(); 60 | } 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /base/memory_block.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "input_block.hpp" 4 | #include "output_block.hpp" 5 | #include 6 | #include 7 | 8 | namespace jkgm { 9 | class memory_block; 10 | 11 | class memory_input_block : public input_block { 12 | private: 13 | memory_block const *mf; 14 | size_t offset = 0; 15 | 16 | public: 17 | explicit memory_input_block(memory_block const *mf); 18 | 19 | size_t read_some(span dest) override; 20 | 21 | void seek(int off) override; 22 | void set_position(size_t off) override; 23 | size_t position() override; 24 | 25 | size_t size() override; 26 | }; 27 | 28 | class memory_output_block : public output_block { 29 | private: 30 | memory_block *mf; 31 | size_t offset = 0; 32 | 33 | public: 34 | explicit memory_output_block(memory_block *mf); 35 | 36 | size_t write_some(span src) override; 37 | void set_position(size_t off) override; 38 | size_t position() override; 39 | }; 40 | 41 | class memory_block { 42 | friend class memory_input_block; 43 | friend class memory_output_block; 44 | 45 | private: 46 | std::vector buffer; 47 | 48 | public: 49 | char const *data() const; 50 | size_t size() const; 51 | bool empty() const; 52 | 53 | std::string_view str() const; 54 | void str(std::string_view value); 55 | 56 | void clear(); 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /base/narrow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | template 9 | inline constexpr T narrow_cast(U &&u) 10 | { 11 | return static_cast(std::forward(u)); 12 | } 13 | 14 | template 15 | inline constexpr T narrow(U u) 16 | { 17 | auto t = narrow_cast(u); 18 | if(static_cast(t) != u) { 19 | throw std::runtime_error("Bad narrow cast"); 20 | } 21 | 22 | return t; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /base/output_block.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "output_stream.hpp" 4 | 5 | namespace jkgm { 6 | 7 | class output_block : public output_stream { 8 | public: 9 | virtual void set_position(size_t offset) = 0; 10 | virtual size_t position() = 0; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /base/output_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "output_stream.hpp" 2 | 3 | void jkgm::output_stream::write(span src) 4 | { 5 | size_t amount_remaining = src.size(); 6 | while(amount_remaining > 0) { 7 | size_t amount_written = write_some(src); 8 | amount_remaining -= amount_written; 9 | if(amount_remaining > 0) { 10 | src = src.subspan(amount_written, amount_remaining); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /base/output_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "span.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | class output_stream { 9 | protected: 10 | output_stream() = default; 11 | 12 | public: 13 | virtual ~output_stream() = default; 14 | 15 | output_stream(output_stream const &) = default; 16 | output_stream(output_stream &&) = default; 17 | output_stream &operator=(output_stream const &) = default; 18 | output_stream &operator=(output_stream &&) = default; 19 | 20 | void write(span src); 21 | virtual size_t write_some(span src) = 0; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /base/pipe.cpp: -------------------------------------------------------------------------------- 1 | #include "pipe.hpp" 2 | 3 | namespace jkgm { 4 | namespace { 5 | template 6 | struct pipe_maker_impl; 7 | 8 | template <> 9 | struct pipe_maker_impl { 10 | static auto make_pipe() 11 | { 12 | return win32::create_pipe(/*children inherit handles*/ false); 13 | } 14 | 15 | static auto make_input_file_pipe(fs::path const &p) 16 | { 17 | return win32::create_file(p, 18 | {win32::file_access_right::read_data}, 19 | {win32::file_share_mode::share_read}, 20 | /*children inherit*/ false, 21 | win32::creation_disposition::open_existing, 22 | {win32::file_attribute::normal}); 23 | } 24 | 25 | static auto make_output_file_pipe(fs::path const &p) 26 | { 27 | return win32::create_file(p, 28 | {win32::file_access_right::append_data}, 29 | {win32::file_share_mode::share_write}, 30 | /*children inherit*/ false, 31 | win32::creation_disposition::create_always, 32 | {win32::file_attribute::normal}); 33 | } 34 | 35 | static auto make_output_file_append_pipe(fs::path const &p) 36 | { 37 | return win32::create_file(p, 38 | {win32::file_access_right::append_data}, 39 | {win32::file_share_mode::share_write}, 40 | /*children inherit*/ false, 41 | win32::creation_disposition::open_always, 42 | {win32::file_attribute::normal}); 43 | } 44 | }; 45 | 46 | using pipe_maker = pipe_maker_impl; 47 | } 48 | } 49 | 50 | jkgm::fd_output_stream jkgm::make_output_file_append_pipe(fs::path const &p) 51 | { 52 | return jkgm::fd_output_stream(pipe_maker::make_output_file_append_pipe(p)); 53 | } 54 | -------------------------------------------------------------------------------- /base/pipe.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fd_output_stream.hpp" 4 | #include "filesystem.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | fd_output_stream make_output_file_append_pipe(fs::path const &p); 9 | } 10 | -------------------------------------------------------------------------------- /base/range.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace jkgm { 6 | using std::get; 7 | using std::tuple_size; 8 | 9 | template 10 | class range { 11 | private: 12 | It first, last; 13 | 14 | public: 15 | range(It first, It last) 16 | : first(std::move(first)) 17 | , last(std::move(last)) 18 | { 19 | } 20 | 21 | It const &begin() const 22 | { 23 | return first; 24 | } 25 | 26 | It const &end() const 27 | { 28 | return last; 29 | } 30 | 31 | inline bool empty() const 32 | { 33 | return first == last; 34 | } 35 | }; 36 | 37 | template 38 | range make_range(It const &first, It const &last) 39 | { 40 | return range(first, last); 41 | } 42 | 43 | template 44 | auto make_range(TupleT const &tuple) -> decltype(make_range(get<0>(tuple), get<1>(tuple))) 45 | { 46 | static_assert(tuple_size::value == 2, "tuple must be a pair"); 47 | return make_range(get<0>(tuple), get<1>(tuple)); 48 | } 49 | 50 | template 51 | auto make_range(RangeT &rng) -> decltype(make_range(rng.begin(), rng.end())) 52 | { 53 | return make_range(rng.begin(), rng.end()); 54 | } 55 | 56 | template 57 | auto make_reverse_range(ContainerT &rng) -> decltype(make_range(rng.rbegin(), rng.rend())) 58 | { 59 | return make_range(rng.rbegin(), rng.rend()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /base/runtime_assert.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace jkgm { 6 | template 7 | inline void throw_std_exception_assert(bool e, char const *msg) 8 | { 9 | if(!e) { 10 | throw ExceptT(msg); 11 | } 12 | } 13 | 14 | inline void runtime_assert(bool e, char const *msg) 15 | { 16 | throw_std_exception_assert(e, msg); 17 | } 18 | 19 | inline void logic_assert(bool e, char const *msg) 20 | { 21 | throw_std_exception_assert(e, msg); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /base/std_input_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "std_input_stream.hpp" 2 | #include "buffered_input_stream.hpp" 3 | #include "fd_input_stream.hpp" 4 | #include "win32.hpp" 5 | 6 | namespace jkgm { 7 | namespace { 8 | template 9 | struct helper_impl; 10 | 11 | template <> 12 | struct helper_impl { 13 | static win32::handle_id get_stdin() 14 | { 15 | return win32::get_std_handle(win32::std_device::std_input); 16 | } 17 | }; 18 | 19 | using helper = helper_impl; 20 | 21 | shared_fd_input_stream full_std_input(helper::get_stdin()); 22 | } 23 | } 24 | 25 | jkgm::input_stream &jkgm::std_input = jkgm::full_std_input; 26 | 27 | void jkgm::refresh_std_input() 28 | { 29 | full_std_input = shared_fd_input_stream(helper::get_stdin()); 30 | } 31 | -------------------------------------------------------------------------------- /base/std_input_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "input_stream.hpp" 4 | 5 | namespace jkgm { 6 | extern input_stream &std_input; 7 | 8 | void refresh_std_input(); 9 | } 10 | -------------------------------------------------------------------------------- /base/std_output_log_backend.cpp: -------------------------------------------------------------------------------- 1 | #include "std_output_log_backend.hpp" 2 | #include "base/cstring_view.hpp" 3 | #include "format.hpp" 4 | #include "span.hpp" 5 | #include 6 | 7 | void jkgm::std_output_log_backend::write_message(std::string_view /*filename*/, 8 | int /*line_number*/, 9 | log_level level, 10 | std::string_view message) 11 | { 12 | std::string_view tag(nullptr, 0); 13 | 14 | switch(level) { 15 | case log_level::error: 16 | tag = "[ERROR] "; 17 | break; 18 | 19 | case log_level::warning: 20 | tag = "[WARNING] "; 21 | break; 22 | 23 | case log_level::debug: 24 | tag = "[DEBUG] "; 25 | break; 26 | 27 | default: 28 | break; 29 | } 30 | 31 | std::cerr << str(fmt(tag, message, "\n")); 32 | } 33 | -------------------------------------------------------------------------------- /base/std_output_log_backend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "log_backend.hpp" 4 | 5 | namespace jkgm { 6 | class std_output_log_backend : public log_backend { 7 | public: 8 | void write_message(std::string_view filename, 9 | int line_number, 10 | log_level level, 11 | std::string_view message) override; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /base/std_output_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "std_output_stream.hpp" 2 | #include "fd_output_stream.hpp" 3 | #include "win32.hpp" 4 | 5 | namespace jkgm { 6 | namespace { 7 | template 8 | struct helper_impl; 9 | 10 | template <> 11 | struct helper_impl { 12 | static win32::handle_id get_stdout() 13 | { 14 | return win32::get_std_handle(win32::std_device::std_output); 15 | } 16 | 17 | static win32::handle_id get_stderr() 18 | { 19 | return win32::get_std_handle(win32::std_device::std_error); 20 | } 21 | }; 22 | 23 | using helper = helper_impl; 24 | 25 | jkgm::shared_fd_output_stream full_std_output(helper::get_stdout()); 26 | 27 | jkgm::shared_fd_output_stream full_std_error(helper::get_stderr()); 28 | } 29 | } 30 | 31 | jkgm::output_stream &jkgm::std_output = jkgm::full_std_output; 32 | jkgm::output_stream &jkgm::std_error = jkgm::full_std_error; 33 | 34 | void jkgm::refresh_std_output() 35 | { 36 | full_std_output = shared_fd_output_stream(helper::get_stdout()); 37 | } 38 | 39 | void jkgm::refresh_std_error() 40 | { 41 | full_std_output = shared_fd_output_stream(helper::get_stderr()); 42 | } 43 | -------------------------------------------------------------------------------- /base/std_output_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "output_stream.hpp" 4 | 5 | namespace jkgm { 6 | extern output_stream &std_output; 7 | extern output_stream &std_error; 8 | 9 | void refresh_std_output(); 10 | void refresh_std_error(); 11 | } 12 | -------------------------------------------------------------------------------- /base/string_search.cpp: -------------------------------------------------------------------------------- 1 | #include "string_search.hpp" 2 | #include "char.hpp" 3 | 4 | bool jkgm::begins_with(std::string_view searched, std::string_view prefix) 5 | { 6 | auto it = searched.begin(); 7 | auto jt = prefix.begin(); 8 | 9 | while(it != searched.end() && jt != prefix.end() && *it == *jt) { 10 | ++it; 11 | ++jt; 12 | } 13 | 14 | return jt == prefix.end(); 15 | } 16 | 17 | bool jkgm::iends_with(std::string_view searched, std::string_view prefix) 18 | { 19 | auto it = searched.rbegin(); 20 | auto jt = prefix.rbegin(); 21 | 22 | while(it != searched.rend() && jt != prefix.rend() && to_lower(*it) == to_lower(*jt)) { 23 | ++it; 24 | ++jt; 25 | } 26 | 27 | return jt == prefix.rend(); 28 | } 29 | -------------------------------------------------------------------------------- /base/string_search.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "char.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | bool begins_with(std::string_view searched, std::string_view prefix); 8 | bool iends_with(std::string_view searched, std::string_view suffix); 9 | 10 | template 11 | bool iequal(LeftRngT const &left, RightRngT const &right) 12 | { 13 | auto it = left.begin(); 14 | auto jt = right.begin(); 15 | 16 | while(it != left.end() && jt != right.end() && to_lower(*it) == to_lower(*jt)) { 17 | ++it; 18 | ++jt; 19 | } 20 | 21 | return it == left.end() && jt == right.end(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /base/system_string.cpp: -------------------------------------------------------------------------------- 1 | #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 2 | 3 | #include "system_string.hpp" 4 | #include "span.hpp" 5 | #include 6 | #include 7 | 8 | std::string jkgm::detail::ss_to_u8(detail::ss_u16_view sv) 9 | { 10 | std::wstring_convert, detail::ss_u16_char> wsc; 11 | return wsc.to_bytes(sv.data(), sv.data() + sv.size()); 12 | } 13 | 14 | jkgm::detail::ss_u16_str jkgm::detail::ss_to_u16(std::string_view sv) 15 | { 16 | std::wstring_convert, detail::ss_u16_char> wsc; 17 | return wsc.from_bytes(sv.data(), sv.data() + sv.size()); 18 | } 19 | 20 | std::string jkgm::escape_windows_cmdline_arg(std::string arg) 21 | { 22 | if(!arg.empty() && arg.find_first_of(" \t\n\v\"") == std::string::npos) { 23 | return arg; 24 | } 25 | 26 | std::string rv; 27 | rv.reserve(arg.size() + 2); 28 | 29 | rv.push_back('\"'); 30 | 31 | size_t num_bs = 0; 32 | for(char ch : arg) { 33 | if(ch == '\\') { 34 | ++num_bs; 35 | } 36 | else if(ch == '\"') { 37 | // Backslashes followed by quote must be escaped. 38 | rv.append((num_bs * 2) + 1, '\\'); 39 | rv.push_back('\"'); 40 | num_bs = 0; 41 | } 42 | else { 43 | // Backslashes not followed by quote are unspecial 44 | rv.append(num_bs, '\\'); 45 | rv.push_back(ch); 46 | num_bs = 0; 47 | } 48 | } 49 | 50 | // Backslashes at the end will be followed by a quote, so they should also be escaped. 51 | rv.append(num_bs * 2, '\\'); 52 | rv.push_back('"'); 53 | 54 | return rv; 55 | } 56 | 57 | std::string jkgm::argv_to_windows_cmdline(fs::path const &progname, argument_list const &args) 58 | { 59 | std::string cmdline; 60 | cmdline.append(escape_windows_cmdline_arg(native_to_utf8(progname.native()))); 61 | 62 | for(auto const &arg : *args) { 63 | cmdline.push_back(' '); 64 | cmdline.append(escape_windows_cmdline_arg(arg)); 65 | } 66 | 67 | return cmdline; 68 | } 69 | -------------------------------------------------------------------------------- /base/system_string.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "build_traits.hpp" 4 | #include "filesystem.hpp" 5 | #include "tagged.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace jkgm { 12 | namespace detail { 13 | using ss_u16_char = specialization_t>; 14 | using ss_u16_str = specialization_t>; 15 | using ss_u16_view = specialization_t>; 16 | } 17 | 18 | using system_string = specialization_t>; 19 | using system_string_view = specialization_t>; 20 | 21 | namespace detail { 22 | detail::ss_u16_str ss_to_u16(std::string_view sv); 23 | std::string ss_to_u8(detail::ss_u16_view sv); 24 | 25 | template 26 | struct ss_converter; 27 | 28 | template <> 29 | struct ss_converter { 30 | static std::string native_to_utf8(detail::ss_u16_view sv) 31 | { 32 | return ss_to_u8(sv); 33 | } 34 | 35 | static detail::ss_u16_str utf8_to_native(std::string_view sv) 36 | { 37 | return ss_to_u16(sv); 38 | } 39 | }; 40 | 41 | using ss_conv_spec = ss_converter; 42 | } 43 | 44 | template 45 | auto native_to_utf8(T &&sv) 46 | { 47 | return detail::ss_conv_spec::native_to_utf8(std::forward(sv)); 48 | } 49 | 50 | template 51 | auto utf8_to_native(T &&sv) 52 | { 53 | return detail::ss_conv_spec::utf8_to_native(std::forward(sv)); 54 | } 55 | 56 | using argument_list_vec = std::vector; 57 | MAKE_TAGGED_RANGE_TYPE(argument_list, argument_list_vec, std::string); 58 | 59 | std::string escape_windows_cmdline_arg(std::string arg); 60 | std::string argv_to_windows_cmdline(fs::path const &progname, argument_list const &args); 61 | } 62 | -------------------------------------------------------------------------------- /base/uid.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "id.hpp" 4 | 5 | namespace jkgm { 6 | class uid_tag { 7 | }; 8 | using uid = id; 9 | 10 | template 11 | uid uid_of() 12 | { 13 | return uid(static_cast(T::UID::UID)); 14 | } 15 | 16 | template 17 | uid uid_of(T const & /*value*/) 18 | { 19 | return uid(static_cast(T::UID::UID)); 20 | } 21 | } 22 | 23 | #define UID(x) enum class UID : uint32_t { UID = x##UL } 24 | -------------------------------------------------------------------------------- /base/unique_handle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace jkgm { 7 | template 8 | class unique_handle { 9 | private: 10 | std::optional id; 11 | 12 | public: 13 | unique_handle(unique_handle const &) = delete; 14 | unique_handle &operator=(unique_handle const &) = delete; 15 | 16 | template 17 | explicit unique_handle(ArgT &&... args) 18 | : id(TraitsT::create(std::forward(args)...)) 19 | { 20 | } 21 | 22 | unique_handle(unique_handle &&obj) noexcept 23 | : id(std::move(obj.id)) 24 | { 25 | obj.id.reset(); 26 | } 27 | 28 | ~unique_handle() 29 | { 30 | if(id.has_value()) { 31 | TraitsT::destroy(*id); 32 | id.reset(); 33 | } 34 | } 35 | 36 | unique_handle &operator=(unique_handle &&obj) noexcept 37 | { 38 | if(this != &obj && id.has_value()) { 39 | TraitsT::destroy(*id); 40 | id.reset(); 41 | } 42 | 43 | std::swap(id, obj.id); 44 | return *this; 45 | } 46 | 47 | inline typename TraitsT::value_type value() const 48 | { 49 | return id.value(); 50 | } 51 | 52 | inline typename TraitsT::value_type operator*() const 53 | { 54 | return *id; 55 | } 56 | 57 | typename TraitsT::value_type release() 58 | { 59 | typename TraitsT::value_type rv(std::move(id.value())); 60 | id.reset(); 61 | return rv; 62 | } 63 | }; 64 | 65 | template 66 | class unique_handle_view { 67 | private: 68 | typename TraitsT::value_type id; 69 | 70 | public: 71 | explicit constexpr unique_handle_view(typename TraitsT::value_type id) 72 | : id(id) 73 | { 74 | } 75 | 76 | unique_handle_view(unique_handle const &uh) 77 | : id(uh.value()) 78 | { 79 | } 80 | 81 | inline typename TraitsT::value_type value() const 82 | { 83 | return id; 84 | } 85 | 86 | inline typename TraitsT::value_type operator*() const 87 | { 88 | return id; 89 | } 90 | }; 91 | } 92 | -------------------------------------------------------------------------------- /common/config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace jkgm { 9 | struct antialiasing_config { 10 | std::string type; 11 | int samples = 2; 12 | float min_sample_factor = 0.0f; 13 | }; 14 | 15 | class config { 16 | public: 17 | std::tuple resolution = std::make_tuple(640, 480); 18 | bool fullscreen = false; 19 | bool correct_game_aspect_ratio = false; 20 | bool correct_menu_aspect_ratio = true; 21 | float hud_scale = 1.0f; 22 | float max_anisotropy = 2.0f; 23 | std::optional antialiasing; 24 | bool enable_bloom = true; 25 | bool enable_ssao = true; 26 | bool enable_parallax = true; 27 | bool enable_texture_filtering = true; 28 | bool enable_posterized_lighting = false; 29 | bool enable_vsync = false; 30 | std::string command = "jk.exe"; 31 | std::string data_path = "jkgm"; 32 | std::optional log_path; 33 | uint64_t vram_texture_preload_size = 0U; 34 | }; 35 | 36 | std::unique_ptr load_config_file(); 37 | } -------------------------------------------------------------------------------- /common/error_reporter.cpp: -------------------------------------------------------------------------------- 1 | #include "error_reporter.hpp" 2 | #include "base/log.hpp" 3 | #include "base/system_string.hpp" 4 | #include 5 | 6 | namespace { 7 | constexpr wchar_t const *appname = L"JkGfxMod"; 8 | 9 | void error_dialog(std::string_view message) 10 | { 11 | MessageBoxW(NULL, 12 | jkgm::utf8_to_native(message).c_str(), 13 | appname, 14 | MB_OK | MB_ICONERROR | MB_TASKMODAL); 15 | } 16 | 17 | void warning_dialog(std::string_view message) 18 | { 19 | MessageBoxW(NULL, 20 | jkgm::utf8_to_native(message).c_str(), 21 | appname, 22 | MB_OK | MB_ICONWARNING | MB_TASKMODAL); 23 | } 24 | } 25 | 26 | void jkgm::report_fatal_message(std::string_view msg) 27 | { 28 | LOG_ERROR(msg); 29 | error_dialog(msg); 30 | abort(); 31 | } 32 | 33 | void jkgm::report_error_message(std::string_view msg) 34 | { 35 | LOG_ERROR(msg); 36 | error_dialog(msg); 37 | } 38 | 39 | void jkgm::report_warning_message(std::string_view msg) 40 | { 41 | LOG_WARNING(msg); 42 | warning_dialog(msg); 43 | } 44 | 45 | void jkgm::report_unimplemented_function(std::string_view function_name) 46 | { 47 | LOG_ERROR(function_name, " unimplemented"); 48 | error_dialog(str(fmt("The program called an undefined function in JkGfxMod. The program may " 49 | "not be compatible with JkGfxMod, or it may have been modified in an " 50 | "unsupported way.\n\nDetails: Failed to call \"", 51 | function_name, 52 | "\", because it is not implemented"))); 53 | abort(); 54 | } -------------------------------------------------------------------------------- /common/error_reporter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/format.hpp" 4 | 5 | namespace jkgm { 6 | [[noreturn]] void report_fatal_message(std::string_view msg); 7 | void report_error_message(std::string_view msg); 8 | void report_warning_message(std::string_view msg); 9 | 10 | [[noreturn]] void report_unimplemented_function(std::string_view name); 11 | } -------------------------------------------------------------------------------- /common/image.cpp: -------------------------------------------------------------------------------- 1 | #include "image.hpp" 2 | #include "base/log.hpp" 3 | #include "base/memory_block.hpp" 4 | #include "stb_image.h" 5 | #include "stb_image_write.h" 6 | 7 | jkgm::image::image(size<2, int> dimensions) 8 | : dimensions(dimensions) 9 | { 10 | data.resize(volume(dimensions), color_rgba8::zero()); 11 | } 12 | 13 | std::unique_ptr jkgm::load_image(input_stream *is) 14 | { 15 | memory_block mb; 16 | memory_output_block mob(&mb); 17 | is->copy_to(&mob); 18 | 19 | auto dat_span = make_span(mb).as_unsigned_const_bytes(); 20 | 21 | int width, height, channels; 22 | unsigned char *data = stbi_load_from_memory( 23 | dat_span.data(), dat_span.size(), &width, &height, &channels, STBI_rgb_alpha); 24 | 25 | if(data == nullptr) { 26 | LOG_ERROR("Error loading image"); 27 | throw std::runtime_error("invalid image"); 28 | } 29 | 30 | auto in_span = make_span(data, width * height * 4); 31 | 32 | auto rv = std::make_unique(make_size(width, height)); 33 | auto out_span = make_span(rv->data).as_unsigned_bytes(); 34 | 35 | std::copy(in_span.begin(), in_span.end(), out_span.begin()); 36 | 37 | stbi_image_free(data); 38 | 39 | return rv; 40 | } 41 | 42 | void jkgm::store_image_png(output_stream *os, image const &img) 43 | { 44 | auto write_func = [](void *context, void *data, int size) { 45 | auto *os = (output_stream *)context; 46 | os->write(make_span((char const *)data, size)); 47 | }; 48 | 49 | int result = stbi_write_png_to_func(write_func, 50 | (void *)os, 51 | get(img.dimensions), 52 | get(img.dimensions), 53 | /*components*/ 4, 54 | img.data.data(), 55 | /*stride*/ get(img.dimensions) * sizeof(color_rgba8)); 56 | } -------------------------------------------------------------------------------- /common/image.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/input_stream.hpp" 4 | #include "base/output_stream.hpp" 5 | #include "math/color.hpp" 6 | #include "math/size.hpp" 7 | #include 8 | #include 9 | 10 | namespace jkgm { 11 | class image { 12 | public: 13 | size<2, int> dimensions; 14 | std::vector data; 15 | 16 | explicit image(size<2, int> dimensions); 17 | }; 18 | 19 | std::unique_ptr load_image(input_stream *is); 20 | void store_image_png(output_stream *os, image const &img); 21 | } -------------------------------------------------------------------------------- /common/json_incl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "json.hpp" 4 | 5 | namespace json = nlohmann; -------------------------------------------------------------------------------- /common/material.cpp: -------------------------------------------------------------------------------- 1 | #include "material.hpp" -------------------------------------------------------------------------------- /common/material.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/filesystem.hpp" 4 | #include "math/color.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | enum class material_alpha_mode { blend, mask }; 9 | 10 | class material { 11 | public: 12 | std::optional albedo_map; 13 | color albedo_factor = color::fill(1.0f); 14 | 15 | std::optional emissive_map; 16 | color_rgb emissive_factor = color_rgb::zero(); 17 | 18 | std::optional displacement_map; 19 | float displacement_factor = 0.0f; 20 | 21 | material_alpha_mode alpha_mode = material_alpha_mode::blend; 22 | float alpha_cutoff = 0.5f; 23 | }; 24 | } -------------------------------------------------------------------------------- /common/material_map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/md5.hpp" 4 | #include "json.hpp" 5 | #include "material.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | class material_map { 10 | private: 11 | std::vector> materials; 12 | std::unordered_map signature_map; 13 | 14 | void add_metadata(fs::path const &metadata_file); 15 | 16 | public: 17 | void create_map(fs::path const &materials_dir); 18 | 19 | std::optional get_material(md5 const &sig) const; 20 | std::vector> const &get_materials() const; 21 | }; 22 | } -------------------------------------------------------------------------------- /common/stb_image_impl.cpp: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #include "stb_image.h" 3 | 4 | #define STB_IMAGE_WRITE_IMPLEMENTATION 5 | #include "stb_image_write.h" -------------------------------------------------------------------------------- /compile/colormap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/input_stream.hpp" 4 | #include "math/color.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace jkgm { 11 | class colormap_palette { 12 | public: 13 | std::vector data; 14 | 15 | colormap_palette(); 16 | explicit colormap_palette(jkgm::input_stream *is); 17 | }; 18 | 19 | class colormap_light_level { 20 | public: 21 | std::array, 64> data; 22 | 23 | colormap_light_level() = default; 24 | explicit colormap_light_level(jkgm::input_stream *is); 25 | }; 26 | 27 | class colormap_transparency_table { 28 | public: 29 | std::array, 256> data; 30 | 31 | colormap_transparency_table() = default; 32 | explicit colormap_transparency_table(jkgm::input_stream *is); 33 | }; 34 | 35 | class colormap { 36 | public: 37 | std::array magic; 38 | uint32_t version; 39 | bool transparency; 40 | 41 | jkgm::color_rgb tint = jkgm::color_rgb::zero(); 42 | 43 | // These values are always 0 44 | std::array unknown; 45 | 46 | std::unique_ptr palette; 47 | std::unique_ptr light_levels; 48 | std::unique_ptr transparency_tables; 49 | 50 | colormap() = default; 51 | explicit colormap(jkgm::input_stream *is); 52 | 53 | jkgm::color_rgb8 get_direct_color(int color_index) const; 54 | 55 | jkgm::color_rgb8 get_color(int color_index, int light_level) const; 56 | 57 | jkgm::color_rgb8 get_color(int color_index) const; 58 | jkgm::color_rgb8 get_light_color(int color_index) const; 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /compile/gob_file.cpp: -------------------------------------------------------------------------------- 1 | #include "gob_file.hpp" 2 | #include "base/file_block.hpp" 3 | 4 | jkgm::gob_file::gob_file(fs::path const &container_filename, 5 | size_t chunk_offset, 6 | size_t chunk_length) 7 | : file(jkgm::make_file_input_block(container_filename)) 8 | , chunk_end(chunk_offset + chunk_length) 9 | { 10 | file->set_position(chunk_offset); 11 | } 12 | 13 | size_t jkgm::gob_file::read_some(jkgm::span dest) 14 | { 15 | size_t desired_size = dest.size(); 16 | 17 | size_t read_ceil = chunk_end - file->position(); 18 | size_t actual_want = std::min(read_ceil, desired_size); 19 | 20 | return file->read_some(dest.subspan(0, actual_want)); 21 | } -------------------------------------------------------------------------------- /compile/gob_file.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/filesystem.hpp" 4 | #include "base/input_block.hpp" 5 | #include "base/input_stream.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | class gob_file : public jkgm::input_stream { 10 | private: 11 | std::unique_ptr file; 12 | size_t const chunk_end; 13 | 14 | public: 15 | gob_file(fs::path const &container_filename, size_t chunk_offset, size_t chunk_length); 16 | 17 | virtual size_t read_some(jkgm::span dest) override; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /compile/gob_virtual_container.cpp: -------------------------------------------------------------------------------- 1 | #include "gob_virtual_container.hpp" 2 | #include "base/file_block.hpp" 3 | #include "base/log.hpp" 4 | 5 | namespace { 6 | struct gob_header { 7 | char magic[4]; 8 | uint32_t first_index_offset; 9 | uint32_t unknown; 10 | uint32_t index_count; 11 | }; 12 | 13 | struct gob_entry { 14 | uint32_t chunk_offset; 15 | uint32_t chunk_length; 16 | char chunk_name[128]; 17 | }; 18 | } 19 | 20 | jkgm::gob_virtual_container::gob_virtual_container(fs::path const &container_filename) 21 | : virtual_container(container_filename) 22 | { 23 | std::string stk_filename = container_filename.generic_string(); 24 | jkgm::diagnostic_context dc(stk_filename.c_str()); 25 | 26 | auto file = jkgm::make_file_input_block(container_filename); 27 | 28 | gob_header header; 29 | file->read(jkgm::make_span(&header, 1).as_bytes()); 30 | 31 | if(strncmp(header.magic, "GOB ", 4) != 0) { 32 | LOG_ERROR("container is not a valid GOB"); 33 | throw std::runtime_error("Invalid GOB file"); 34 | } 35 | 36 | gob_entry entry; 37 | for(uint32_t i = 0; i < header.index_count; ++i) { 38 | file->read(jkgm::make_span(&entry, 1).as_bytes()); 39 | 40 | // Convert path separators for boost path. 41 | std::replace_if( 42 | entry.chunk_name, entry.chunk_name + 128, [](char ch) { return ch == '\\'; }, '/'); 43 | 44 | // Convert entry to lowercase. 45 | std::transform(entry.chunk_name, entry.chunk_name + 128, entry.chunk_name, tolower); 46 | 47 | entry.chunk_name[127] = '\0'; 48 | 49 | files.emplace_back(entry.chunk_name, *this, entry.chunk_offset, entry.chunk_length); 50 | } 51 | 52 | return; 53 | } 54 | 55 | size_t jkgm::gob_virtual_container::size() const 56 | { 57 | return files.size(); 58 | } 59 | 60 | jkgm::gob_virtual_file const &jkgm::gob_virtual_container::get_file(size_t index) const 61 | { 62 | return files[index]; 63 | } 64 | -------------------------------------------------------------------------------- /compile/gob_virtual_container.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gob_virtual_file.hpp" 4 | #include "virtual_container.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class gob_virtual_container : public virtual_container { 9 | private: 10 | std::vector files; 11 | 12 | public: 13 | explicit gob_virtual_container(fs::path const &container_filename); 14 | 15 | virtual gob_virtual_file const &get_file(size_t index) const override; 16 | virtual size_t size() const override; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /compile/gob_virtual_file.cpp: -------------------------------------------------------------------------------- 1 | #include "gob_virtual_file.hpp" 2 | #include "gob_file.hpp" 3 | #include "gob_virtual_container.hpp" 4 | 5 | jkgm::gob_virtual_file::gob_virtual_file(fs::path const &name, 6 | gob_virtual_container const &parent_container, 7 | size_t chunk_offset, 8 | size_t chunk_length) 9 | : virtual_file(name) 10 | , parent_container(parent_container) 11 | , chunk_offset(chunk_offset) 12 | , chunk_length(chunk_length) 13 | { 14 | return; 15 | } 16 | 17 | std::unique_ptr jkgm::gob_virtual_file::open() const 18 | { 19 | return std::make_unique( 20 | parent_container.container_filename, chunk_offset, chunk_length); 21 | } 22 | 23 | jkgm::virtual_container const &jkgm::gob_virtual_file::get_parent_container() const 24 | { 25 | return parent_container; 26 | } 27 | -------------------------------------------------------------------------------- /compile/gob_virtual_file.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "virtual_file.hpp" 4 | 5 | namespace jkgm { 6 | class gob_virtual_container; 7 | 8 | class gob_virtual_file : public virtual_file { 9 | public: 10 | gob_virtual_container const &parent_container; 11 | size_t chunk_offset; 12 | size_t chunk_length; 13 | 14 | gob_virtual_file(fs::path const &name, 15 | gob_virtual_container const &pc, 16 | size_t chunk_offset, 17 | size_t chunk_length); 18 | 19 | virtual std::unique_ptr open() const override; 20 | virtual virtual_container const &get_parent_container() const override; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /compile/jk_virtual_file_system.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "virtual_container.hpp" 4 | #include "virtual_file_system.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace jkgm { 13 | 14 | typedef std::unordered_map vfs_map; 15 | 16 | class jk_virtual_file_system : public virtual_file_system { 17 | private: 18 | fs::path const resource_path; 19 | std::optional const game_path; 20 | 21 | vfs_map resource_file_map; 22 | vfs_map game_file_map; 23 | vfs_map episode_file_map; 24 | 25 | std::vector> containers; 26 | 27 | public: 28 | jk_virtual_file_system(fs::path const &resource_path); 29 | jk_virtual_file_system(fs::path const &resource_path, fs::path const &game_path); 30 | 31 | void set_current_episode(virtual_container const &episode_ctr); 32 | 33 | virtual std::unique_ptr open(fs::path const &filename) const override; 34 | virtual std::tuple> 35 | find(fs::path const &filename, std::vector const &prefixes) const override; 36 | 37 | std::map list_files() const; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /compile/native_file_system.cpp: -------------------------------------------------------------------------------- 1 | #include "native_file_system.hpp" 2 | #include "base/file_block.hpp" 3 | #include "base/filesystem.hpp" 4 | #include "base/log.hpp" 5 | 6 | jkgm::native_file_system::native_file_system(fs::path const &base_path) 7 | : base_path(base_path) 8 | { 9 | return; 10 | } 11 | 12 | std::unique_ptr jkgm::native_file_system::open(fs::path const &filename) const 13 | { 14 | try { 15 | return jkgm::make_file_input_block(base_path / filename); 16 | } 17 | catch(std::exception const &e) { 18 | std::string generic_fn = filename.generic_string(); 19 | jkgm::diagnostic_context dc(generic_fn.c_str()); 20 | LOG_ERROR(e.what()); 21 | throw; 22 | } 23 | } 24 | 25 | std::tuple> 26 | jkgm::native_file_system::find(fs::path const &filename, 27 | std::vector const &prefixes) const 28 | { 29 | for(auto const &prefix : prefixes) { 30 | fs::path assembled = base_path / prefix / filename; 31 | if(fs::is_regular_file(assembled)) { 32 | return std::make_tuple(assembled, jkgm::make_file_input_block(assembled)); 33 | } 34 | } 35 | 36 | // Check in the same directory 37 | return make_tuple(filename, open(filename)); 38 | } 39 | -------------------------------------------------------------------------------- /compile/native_file_system.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "virtual_file_system.hpp" 4 | 5 | namespace jkgm { 6 | 7 | class native_file_system : public virtual_file_system { 8 | private: 9 | fs::path const base_path; 10 | 11 | public: 12 | native_file_system() = default; 13 | explicit native_file_system(fs::path const &base_path); 14 | 15 | virtual std::unique_ptr open(fs::path const &filename) const override; 16 | virtual std::tuple> 17 | find(fs::path const &filename, std::vector const &prefixes) const override; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /compile/raw_material.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/filesystem.hpp" 4 | #include "base/input_stream.hpp" 5 | #include "colormap.hpp" 6 | #include "common/json_incl.hpp" 7 | #include "math/color.hpp" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace jkgm { 15 | class raw_material_cel_record { 16 | public: 17 | uint32_t type; 18 | uint32_t color_index; 19 | std::array unknown_color; 20 | std::array unknown_texture; 21 | uint32_t texture_index; 22 | 23 | explicit raw_material_cel_record(jkgm::input_stream *is); 24 | }; 25 | 26 | class raw_material_texture_record { 27 | public: 28 | uint32_t width; 29 | uint32_t height; 30 | bool uses_transparency; 31 | std::array unknown; 32 | uint32_t mipmap_count; 33 | std::vector> image_data; 34 | 35 | raw_material_texture_record(jkgm::input_stream *is, uint32_t bitdepth); 36 | }; 37 | 38 | class raw_material { 39 | public: 40 | std::array magic; 41 | uint32_t version; 42 | 43 | uint32_t type; 44 | uint32_t record_count; 45 | uint32_t texture_count; 46 | 47 | uint32_t transparency; 48 | uint32_t bitdepth; 49 | 50 | std::array unknown; 51 | 52 | std::vector cel_records; 53 | std::vector texture_records; 54 | 55 | explicit raw_material(jkgm::input_stream *is); 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /compile/virtual_container.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_container.hpp" 2 | #include "base/log.hpp" 3 | 4 | jkgm::virtual_container::virtual_container(fs::path const &container_filename) 5 | : container_filename(container_filename) 6 | { 7 | return; 8 | } 9 | 10 | jkgm::virtual_container::~virtual_container() 11 | { 12 | return; 13 | } 14 | 15 | jkgm::virtual_container_iterator jkgm::virtual_container::begin() const 16 | { 17 | return virtual_container_iterator(*this, 0); 18 | } 19 | 20 | jkgm::virtual_container_iterator jkgm::virtual_container::end() const 21 | { 22 | return virtual_container_iterator(*this, size()); 23 | } 24 | -------------------------------------------------------------------------------- /compile/virtual_container.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "virtual_container_iterator.hpp" 4 | #include "virtual_file.hpp" 5 | 6 | namespace jkgm { 7 | 8 | class virtual_container { 9 | friend class virtual_container_iterator; 10 | 11 | protected: 12 | virtual virtual_file const &get_file(size_t index) const = 0; 13 | 14 | public: 15 | fs::path const container_filename; 16 | 17 | explicit virtual_container(fs::path const &container_filename); 18 | virtual ~virtual_container(); 19 | 20 | virtual size_t size() const = 0; 21 | 22 | virtual_container_iterator begin() const; 23 | virtual_container_iterator end() const; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /compile/virtual_container_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_container_iterator.hpp" 2 | #include "base/log.hpp" 3 | #include "virtual_container.hpp" 4 | 5 | void jkgm::virtual_container_iterator::set_index(size_t new_index) 6 | { 7 | current_index = new_index; 8 | if(new_index < underlying_container->size()) { 9 | current_file = &underlying_container->get_file(new_index); 10 | } 11 | else { 12 | current_file = std::nullopt; 13 | } 14 | } 15 | 16 | jkgm::virtual_container_iterator::virtual_container_iterator(virtual_container const &cnt, 17 | size_t current_index) 18 | : underlying_container(&cnt) 19 | , current_index(0) 20 | { 21 | set_index(current_index); 22 | } 23 | 24 | jkgm::virtual_file const &jkgm::virtual_container_iterator::operator*() const 25 | { 26 | if(!current_file.has_value()) { 27 | throw std::logic_error("virtual container iterator out of bounds"); 28 | } 29 | 30 | return *current_file.value(); 31 | } 32 | 33 | jkgm::virtual_file const *jkgm::virtual_container_iterator::operator->() const 34 | { 35 | if(!current_file.has_value()) { 36 | throw std::logic_error("virtual container iterator out of bounds"); 37 | } 38 | 39 | return current_file.value(); 40 | } 41 | 42 | jkgm::virtual_container_iterator &jkgm::virtual_container_iterator::operator++() 43 | { 44 | set_index(current_index + 1); 45 | return *this; 46 | } 47 | 48 | jkgm::virtual_container_iterator jkgm::virtual_container_iterator::operator++(int) 49 | { 50 | virtual_container_iterator vci(*this); 51 | set_index(current_index + 1); 52 | return vci; 53 | } 54 | 55 | bool jkgm::virtual_container_iterator::operator==(virtual_container_iterator const &it) const 56 | { 57 | size_t uc_sz = underlying_container->size(); 58 | bool indices_oob = (current_index >= uc_sz) && (it.current_index >= uc_sz); 59 | bool indices_equal = (current_index == it.current_index) || indices_oob; 60 | return (underlying_container == it.underlying_container) && indices_equal; 61 | } 62 | 63 | bool jkgm::virtual_container_iterator::operator!=(virtual_container_iterator const &it) const 64 | { 65 | return !(*this == it); 66 | } 67 | -------------------------------------------------------------------------------- /compile/virtual_container_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "virtual_file.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | 9 | class virtual_container; 10 | 11 | class virtual_container_iterator { 12 | private: 13 | virtual_container const *underlying_container = nullptr; 14 | size_t current_index; 15 | std::optional current_file; 16 | 17 | void set_index(size_t new_index); 18 | 19 | public: 20 | virtual_container_iterator(virtual_container const &underlying_container, 21 | size_t current_index); 22 | 23 | virtual_file const &operator*() const; 24 | virtual_file const *operator->() const; 25 | 26 | virtual_container_iterator &operator++(); 27 | virtual_container_iterator operator++(int); 28 | 29 | bool operator==(virtual_container_iterator const &it) const; 30 | bool operator!=(virtual_container_iterator const &it) const; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /compile/virtual_file.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_file.hpp" 2 | 3 | jkgm::virtual_file::virtual_file(fs::path const &fn) 4 | : name(fn) 5 | { 6 | return; 7 | } 8 | 9 | jkgm::virtual_file::~virtual_file() 10 | { 11 | return; 12 | } 13 | -------------------------------------------------------------------------------- /compile/virtual_file.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/filesystem.hpp" 4 | #include "base/input_stream.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class virtual_container; 9 | 10 | class virtual_file { 11 | public: 12 | fs::path const name; 13 | 14 | explicit virtual_file(fs::path const &fn); 15 | virtual ~virtual_file(); 16 | 17 | virtual std::unique_ptr open() const = 0; 18 | virtual virtual_container const &get_parent_container() const = 0; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /compile/virtual_file_system.cpp: -------------------------------------------------------------------------------- 1 | #include "virtual_file_system.hpp" 2 | 3 | jkgm::virtual_file_system::~virtual_file_system() 4 | { 5 | return; 6 | } 7 | -------------------------------------------------------------------------------- /compile/virtual_file_system.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/filesystem.hpp" 4 | #include "base/input_stream.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace jkgm { 11 | class virtual_file_system { 12 | public: 13 | virtual ~virtual_file_system(); 14 | 15 | virtual std::unique_ptr open(fs::path const &filename) const = 0; 16 | 17 | virtual std::tuple> 18 | find(fs::path const &filename, std::vector const &prefixes) const = 0; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /detours/LICENSE.md: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | # MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 11 | of the Software, and to permit persons to whom the Software is furnished to do 12 | so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /detours/detours.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /detours/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | #include "winver.h" 12 | #if 0 13 | #include 14 | #include 15 | #else 16 | #ifndef DETOURS_STRINGIFY 17 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 18 | #define DETOURS_STRINGIFY_(x) #x 19 | #endif 20 | 21 | #define VER_FILEFLAGSMASK 0x3fL 22 | #define VER_FILEFLAGS 0x0L 23 | #define VER_FILEOS 0x00040004L 24 | #define VER_FILETYPE 0x00000002L 25 | #define VER_FILESUBTYPE 0x00000000L 26 | #endif 27 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 28 | -------------------------------------------------------------------------------- /detours/disolarm.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_ARM_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /detours/disolarm64.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_ARM64_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /detours/disolia64.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_IA64_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /detours/disolx64.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_X64_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /detours/disolx86.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_X86_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /glad/gl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef PLATFORM_WINDOWS 4 | #define APIENTRY __stdcall 5 | #endif 6 | 7 | #include "glad.h" 8 | 9 | /*#if __has_include() 10 | #error "windows.h is included" 11 | #endif*/ 12 | -------------------------------------------------------------------------------- /glad/glad.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /glutil/buffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/span.hpp" 4 | #include "base/unique_handle.hpp" 5 | #include "gl.hpp" 6 | #include 7 | 8 | namespace jkgm::gl { 9 | struct buffer_traits { 10 | using value_type = uint_type; 11 | 12 | static uint_type create(); 13 | static void destroy(uint_type id); 14 | }; 15 | 16 | using buffer = unique_handle; 17 | using buffer_view = unique_handle_view; 18 | 19 | enum class buffer_bind_target : enum_type { array = 0x8892, element_array = 0x8893 }; 20 | 21 | enum class buffer_usage : enum_type { 22 | static_draw = 0x88E4, 23 | dynamic_draw = 0x88E8, 24 | stream_draw = 0x88E0 25 | }; 26 | 27 | enum class buffer_access : bitfield_type { 28 | read = 1, 29 | write = 2, 30 | invalidate_range = 4, 31 | invalidate_buffer = 8, 32 | flush_explicit = 16, 33 | unsynchronized = 32 34 | }; 35 | 36 | void bind_buffer(buffer_bind_target target, buffer_view buf); 37 | void buffer_reserve(buffer_bind_target target, size_t size, buffer_usage usage); 38 | void buffer_data(buffer_bind_target target, span data, buffer_usage usage); 39 | void buffer_sub_data(buffer_bind_target target, size_t offset, span data); 40 | 41 | namespace detail { 42 | void *map_buffer_range(buffer_bind_target target, 43 | size_t offset, 44 | size_t length, 45 | flag_set access); 46 | } 47 | 48 | template 49 | span map_buffer_range(buffer_bind_target target, 50 | size_t offset, 51 | size_t num, 52 | flag_set access) 53 | { 54 | void *ptr = 55 | detail::map_buffer_range(target, offset * sizeof(EmT), num * sizeof(EmT), access); 56 | return make_span((EmT *)ptr, num); 57 | } 58 | 59 | void unmap_buffer(buffer_bind_target target); 60 | } 61 | -------------------------------------------------------------------------------- /glutil/gl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/flag_set.hpp" 4 | #include "gl_types.hpp" 5 | #include "math/box.hpp" 6 | #include "math/color.hpp" 7 | 8 | namespace jkgm::gl { 9 | enum class blend_function : enum_type { 10 | zero = 0x0, 11 | one = 0x1, 12 | one_minus_source_alpha = 0x0303 13 | }; 14 | 15 | enum class capability : enum_type { 16 | blend = 0x0BE2, 17 | cull_face = 0x0B44, 18 | depth_test = 0x0B71, 19 | framebuffer_srgb = 0x8DB9, 20 | multisample = 0x809D, 21 | sample_shading = 0x8C36 22 | }; 23 | 24 | enum class face_mode : enum_type { front = 0x0404, back = 0x0405, front_and_back = 0x0408 }; 25 | 26 | enum class comparison_function : enum_type { 27 | never = 0x0200, 28 | less = 0x0201, 29 | equal = 0x0202, 30 | less_equal = 0x0203, 31 | greater = 0x0204, 32 | not_equal = 0x0205, 33 | greater_equal = 0x0206, 34 | always = 0x0207 35 | }; 36 | 37 | enum class polygon_mode : enum_type { point = 0x1b00, line = 0x1b01, fill = 0x1b02 }; 38 | 39 | enum class clear_flag : bitfield_type { color = 0x00004000, depth = 0x00000100 }; 40 | using clear_flags = flag_set; 41 | 42 | void enable(capability cap); 43 | void disable(capability cap); 44 | 45 | void clear(clear_flags cf); 46 | 47 | void set_blend_function(blend_function sfactor, blend_function dfactor); 48 | void set_clear_color(color c); 49 | void set_depth_function(comparison_function func); 50 | void set_depth_mask(bool enable); 51 | void set_face_cull_mode(face_mode mode); 52 | void set_min_sample_shading_factor(float f); 53 | void set_polygon_mode(face_mode fm, polygon_mode pm); 54 | void set_viewport(box<2, int> vp); 55 | 56 | void log_errors(); 57 | } 58 | -------------------------------------------------------------------------------- /glutil/gl_types.cpp: -------------------------------------------------------------------------------- 1 | #include "gl_types.hpp" 2 | #include "glad/gl.h" 3 | #include 4 | 5 | namespace jkgm::gl { 6 | static_assert(std::is_same_v, "GLenum type mismatch"); 7 | static_assert(std::is_same_v, "GLboolean type mismatch"); 8 | static_assert(std::is_same_v, "GLbitfield type mismatch"); 9 | static_assert(std::is_same_v, "GLbyte type mismatch"); 10 | static_assert(std::is_same_v, "GLshort type mismatch"); 11 | static_assert(std::is_same_v, "GLint type mismatch"); 12 | static_assert(std::is_same_v, "GLubyte type mismatch"); 13 | static_assert(std::is_same_v, "GLushort type mismatch"); 14 | static_assert(std::is_same_v, "GLuint type mismatch"); 15 | static_assert(std::is_same_v, "GLsizei type mismatch"); 16 | 17 | static_assert(false_value == GL_FALSE, "GL_FALSE value mismatch"); 18 | static_assert(true_value == GL_TRUE, "GL_TRUE value mismatch"); 19 | } 20 | -------------------------------------------------------------------------------- /glutil/gl_types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/tagged.hpp" 4 | #include 5 | 6 | namespace jkgm::gl { 7 | using enum_type = unsigned int; 8 | using boolean_type = unsigned char; 9 | using bitfield_type = unsigned int; 10 | using byte_type = int8_t; 11 | using short_type = int16_t; 12 | using int_type = int32_t; 13 | using ubyte_type = uint8_t; 14 | using ushort_type = uint16_t; 15 | using uint_type = uint32_t; 16 | using size_type = int32_t; 17 | 18 | constexpr boolean_type false_value = boolean_type(0); 19 | constexpr boolean_type true_value = boolean_type(1); 20 | 21 | inline constexpr boolean_type to_gl_bool(bool value) 22 | { 23 | return value ? true_value : false_value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /glutil/renderbuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "renderbuffer.hpp" 2 | #include "glad/gl.h" 3 | 4 | GLuint jkgm::gl::renderbuffer_traits::create() 5 | { 6 | GLuint rv = 0; 7 | glGenRenderbuffers(1, &rv); 8 | return rv; 9 | } 10 | 11 | void jkgm::gl::renderbuffer_traits::destroy(GLuint id) 12 | { 13 | glDeleteRenderbuffers(1, &id); 14 | } 15 | 16 | void jkgm::gl::bind_renderbuffer(renderbuffer_view buf) 17 | { 18 | glBindRenderbuffer(GL_RENDERBUFFER, *buf); 19 | } 20 | 21 | void jkgm::gl::renderbuffer_storage(renderbuffer_format fmt, size<2, int> dimensions) 22 | { 23 | glRenderbufferStorage( 24 | GL_RENDERBUFFER, static_cast(fmt), get(dimensions), get(dimensions)); 25 | } 26 | 27 | void jkgm::gl::renderbuffer_storage_multisample(size_type num_samples, 28 | renderbuffer_format fmt, 29 | size<2, int> dimensions) 30 | { 31 | glRenderbufferStorageMultisample(GL_RENDERBUFFER, 32 | num_samples, 33 | static_cast(fmt), 34 | get(dimensions), 35 | get(dimensions)); 36 | } 37 | 38 | namespace jkgm::gl { 39 | static_assert(renderbuffer_format::depth == renderbuffer_format(GL_DEPTH_COMPONENT)); 40 | static_assert(renderbuffer_format::stencil == renderbuffer_format(GL_STENCIL_INDEX)); 41 | } 42 | -------------------------------------------------------------------------------- /glutil/renderbuffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gl.hpp" 4 | #include "base/unique_handle.hpp" 5 | 6 | namespace jkgm::gl { 7 | struct renderbuffer_traits { 8 | using value_type = uint_type; 9 | 10 | static uint_type create(); 11 | static void destroy(uint_type id); 12 | }; 13 | 14 | using renderbuffer = unique_handle; 15 | using renderbuffer_view = unique_handle_view; 16 | 17 | enum class renderbuffer_format { depth = 0x1902, stencil = 0x1901 }; 18 | 19 | void bind_renderbuffer(renderbuffer_view buf); 20 | void renderbuffer_storage(renderbuffer_format fmt, size<2, int> dimensions); 21 | void renderbuffer_storage_multisample(size_type num_samples, 22 | renderbuffer_format fmt, 23 | size<2, int> dimensions); 24 | } 25 | -------------------------------------------------------------------------------- /glutil/shader.cpp: -------------------------------------------------------------------------------- 1 | #include "shader.hpp" 2 | #include "glad/gl.h" 3 | #include 4 | 5 | GLuint jkgm::gl::shader_traits::create(shader_type type) 6 | { 7 | return glCreateShader(static_cast(type)); 8 | } 9 | 10 | void jkgm::gl::shader_traits::destroy(GLuint id) 11 | { 12 | glDeleteShader(id); 13 | } 14 | 15 | void jkgm::gl::shader_source(shader_view id, span prefix_text, span src_text) 16 | { 17 | std::array src_ptrs = {prefix_text.data(), src_text.data()}; 18 | std::array src_lens = {static_cast(prefix_text.size()), 19 | static_cast(src_text.size())}; 20 | 21 | glShaderSource(*id, 2, src_ptrs.data(), src_lens.data()); 22 | } 23 | 24 | void jkgm::gl::compile_shader(shader_view id) 25 | { 26 | glCompileShader(*id); 27 | } 28 | 29 | bool jkgm::gl::get_shader_compile_status(shader_view id) 30 | { 31 | GLint result = GL_FALSE; 32 | glGetShaderiv(*id, GL_COMPILE_STATUS, &result); 33 | 34 | return result != GL_FALSE; 35 | } 36 | 37 | std::string jkgm::gl::get_shader_info_log(shader_view id) 38 | { 39 | std::string rv; 40 | 41 | int log_length = 0; 42 | glGetShaderiv(*id, GL_INFO_LOG_LENGTH, &log_length); 43 | if(log_length > 0) { 44 | rv.resize(log_length, 'X'); 45 | glGetShaderInfoLog(*id, log_length, nullptr, rv.data()); 46 | } 47 | 48 | return rv; 49 | } 50 | 51 | namespace jkgm::gl { 52 | static_assert(shader_type::vertex == shader_type(GL_VERTEX_SHADER)); 53 | static_assert(shader_type::fragment == shader_type(GL_FRAGMENT_SHADER)); 54 | } 55 | -------------------------------------------------------------------------------- /glutil/shader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gl.hpp" 4 | #include "base/span.hpp" 5 | #include "base/unique_handle.hpp" 6 | #include 7 | 8 | namespace jkgm::gl { 9 | enum class shader_type : enum_type { vertex = 0x8B31, fragment = 0x8B30 }; 10 | 11 | struct shader_traits { 12 | using value_type = uint_type; 13 | 14 | static uint_type create(shader_type type); 15 | static void destroy(uint_type id); 16 | }; 17 | 18 | using shader = unique_handle; 19 | using shader_view = unique_handle_view; 20 | 21 | void shader_source(shader_view id, span prefix_text, span src_text); 22 | void compile_shader(shader_view id); 23 | 24 | bool get_shader_compile_status(shader_view id); 25 | std::string get_shader_info_log(shader_view id); 26 | } 27 | -------------------------------------------------------------------------------- /glutil/vertex_array.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/unique_handle.hpp" 4 | #include "gl.hpp" 5 | #include 6 | 7 | namespace jkgm::gl { 8 | struct vertex_array_traits { 9 | using value_type = uint_type; 10 | 11 | static uint_type create(); 12 | static void destroy(uint_type id); 13 | }; 14 | 15 | using vertex_array = unique_handle; 16 | using vertex_array_view = unique_handle_view; 17 | 18 | enum class vertex_element_type : enum_type { 19 | int8 = 0x1400, 20 | uint8 = 0x1401, 21 | int16 = 0x1402, 22 | uint16 = 0x1403, 23 | int32 = 0x1404, 24 | uint32 = 0x1405, 25 | float32 = 0x1406 26 | }; 27 | 28 | enum class element_type : enum_type { triangles = 0x0004 }; 29 | enum class index_type : enum_type { uint8 = 0x1401, uint16 = 0x1403, uint32 = 0x1405 }; 30 | 31 | void bind_vertex_array(vertex_array_view vao); 32 | void enable_vertex_attrib_array(uint_type index); 33 | void vertex_attrib_pointer(uint_type index, 34 | int_type num_components, 35 | vertex_element_type type, 36 | bool normalized, 37 | size_t stride = 0U, 38 | ptrdiff_t offset = 0); 39 | 40 | void draw_elements(element_type type, 41 | size_t num_indices, 42 | index_type itype, 43 | ptrdiff_t offset = 0); 44 | 45 | void draw_arrays(element_type type, size_t offset, size_t count); 46 | } 47 | -------------------------------------------------------------------------------- /inject/inject.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /math/abstract_vector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_vector_def.hpp" 4 | #include "abstract_vector_simd.hpp" -------------------------------------------------------------------------------- /math/almost_equal.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | template 9 | struct almost_equal_traits; 10 | 11 | template 12 | struct almost_equal_traits>> { 13 | using field_type = F; 14 | static constexpr auto default_threshold = F(1) * std::numeric_limits::epsilon(); 15 | static constexpr auto default_ulps = F(2) * std::numeric_limits::epsilon(); 16 | 17 | static inline constexpr bool almost_equal(F x, F y, F maxdiff, F reldiff) 18 | { 19 | auto absxmy = std::abs(x - y); 20 | return (absxmy <= maxdiff) || (absxmy <= (std::abs(x) + std::abs(y)) * reldiff); 21 | } 22 | }; 23 | 24 | template 25 | struct almost_equal_traits>> { 26 | using field_type = F; 27 | static constexpr auto default_threshold = F(0); 28 | static constexpr auto default_ulps = F(0); 29 | 30 | static inline constexpr bool almost_equal(F x, F y, F /*maxdiff*/, F /*reldiff*/) 31 | { 32 | return x == y; 33 | } 34 | }; 35 | 36 | template >> 37 | bool almost_equal(T const &x, 38 | T const &y, 39 | typename TraitsT::field_type maxdiff = TraitsT::default_threshold, 40 | typename TraitsT::field_type reldiff = TraitsT::default_ulps) 41 | { 42 | return TraitsT::almost_equal(x, y, maxdiff, reldiff); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /math/clamp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "box.hpp" 4 | 5 | namespace jkgm { 6 | namespace detail { 7 | template 8 | inline constexpr F inner_clamp(F &&value, F &&min, F &&max) noexcept 9 | { 10 | if(value < min) { 11 | return std::forward(min); 12 | } 13 | 14 | if(max < value) { 15 | return std::forward(max); 16 | } 17 | 18 | return std::forward(value); 19 | } 20 | 21 | template 22 | struct clamp_detail { 23 | template 24 | static inline constexpr auto op(VarT &&value, BoxT const &b) noexcept 25 | { 26 | return inner_clamp(std::forward(value), get<0>(b.start), get<0>(b.stop)); 27 | } 28 | }; 29 | 30 | template 31 | struct clamp_detail, D, I> { 32 | template 33 | static inline constexpr auto op(abstract_vector const &value, 34 | BoxT const &b, 35 | ArgT &&... args) noexcept 36 | { 37 | return clamp_detail, D, I + 1>::op( 38 | value, 39 | b, 40 | std::forward(args)..., 41 | inner_clamp(get(value), get(b.start), get(b.stop))); 42 | } 43 | }; 44 | 45 | template 46 | struct clamp_detail, D, D> { 47 | template 48 | static inline constexpr auto op(abstract_vector const & /*value*/, 49 | BoxT const & /*b*/, 50 | ArgT &&... args) noexcept 51 | { 52 | return abstract_vector(std::forward(args)...); 53 | } 54 | }; 55 | } 56 | 57 | template 58 | constexpr auto clamp(T &&value, box const &b) noexcept 59 | { 60 | return detail::clamp_detail, D, 0>::op(std::forward(value), b); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /math/color_conv.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "color.hpp" 4 | 5 | namespace jkgm { 6 | color gamma18_to_linear(color input); 7 | color srgb_to_linear(color input); 8 | color linear_to_srgb(color input); 9 | 10 | color_rgba8 rgb565_key_to_srgb_a8(uint16_t input, bool transparent); 11 | color_rgba8 rgb565_to_srgb_a8(uint16_t input); 12 | color_rgba8 rgba5551_to_srgb_a8(uint16_t input); 13 | 14 | uint16_t srgb_a8_to_rgb565(color_rgba8 input); 15 | uint16_t srgb_a8_to_rgba5551(color_rgba8 input); 16 | } -------------------------------------------------------------------------------- /math/colors.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "color.hpp" 4 | 5 | namespace jkgm::colors { 6 | static constexpr color transparent = color(0.0f, 0.0f, 0.0f, 0.0f); 7 | 8 | static constexpr color_rgb black = color_rgb(0.0f, 0.0f, 0.0f); 9 | static constexpr color_rgb white = color_rgb(1.0f, 1.0f, 1.0f); 10 | } 11 | -------------------------------------------------------------------------------- /math/constants.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace jkgm { 4 | template 5 | struct pi; 6 | 7 | template <> 8 | struct pi { 9 | static constexpr float value = 3.14159265358979323846264338327950288f; 10 | }; 11 | 12 | template <> 13 | struct pi { 14 | static constexpr double value = 3.14159265358979323846264338327950288; 15 | }; 16 | 17 | template 18 | inline constexpr F pi_v = pi::value; 19 | } 20 | -------------------------------------------------------------------------------- /math/math.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | 62 | 63 | Source Files 64 | 65 | 66 | -------------------------------------------------------------------------------- /math/point.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "direction.hpp" 4 | 5 | namespace jkgm { 6 | struct position_vector_tag { 7 | static constexpr bool has_dimension_swizzle = true; 8 | }; 9 | 10 | template 11 | using point = abstract_vector; 12 | 13 | template 14 | constexpr auto make_point(C0 &&c0, CN &&... cn) noexcept 15 | { 16 | return point>(std::forward(c0), 17 | std::forward(cn)...); 18 | } 19 | 20 | // Operators 21 | position_vector_tag operator+(position_vector_tag, direction_vector_tag); 22 | position_vector_tag operator-(position_vector_tag, direction_vector_tag); 23 | direction_vector_tag operator-(position_vector_tag, position_vector_tag); 24 | } 25 | -------------------------------------------------------------------------------- /math/size.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "direction.hpp" 4 | 5 | namespace jkgm { 6 | struct size_vector_tag { 7 | static constexpr bool has_dimension_swizzle = true; 8 | }; 9 | 10 | template 11 | using size = abstract_vector; 12 | 13 | template 14 | constexpr auto make_size(C0 &&c0, CN &&... cn) noexcept 15 | { 16 | return size>(std::forward(c0), 17 | std::forward(cn)...); 18 | } 19 | 20 | namespace detail { 21 | template 22 | struct volume_detail { 23 | template 24 | static inline constexpr auto op(VecT const &v, F c) 25 | { 26 | return volume_detail::op(v, c * get(v)); 27 | } 28 | }; 29 | 30 | template 31 | struct volume_detail { 32 | template 33 | static inline constexpr auto op(VecT const & /*v*/, F c) 34 | { 35 | return c; 36 | } 37 | }; 38 | } 39 | 40 | template 41 | constexpr F volume(size const &v) 42 | { 43 | return detail::volume_detail::op(v, F(1)); 44 | } 45 | 46 | namespace detail { 47 | template 48 | struct is_positive_detail { 49 | template 50 | static inline constexpr auto op(VecT const &v) 51 | { 52 | if(get(v) < F(0)) { 53 | return false; 54 | } 55 | 56 | return is_positive_detail::template op(v); 57 | } 58 | }; 59 | 60 | template 61 | struct is_positive_detail { 62 | template 63 | static inline constexpr auto op(VecT const & /*v*/) 64 | { 65 | return true; 66 | } 67 | }; 68 | } 69 | 70 | template 71 | constexpr bool is_positive(size const &v) 72 | { 73 | return detail::is_positive_detail::template op, F>(v); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /program/abstract_argument_queue.cpp: -------------------------------------------------------------------------------- 1 | #include "abstract_argument_queue.hpp" 2 | 3 | jkgm::abstract_argument_queue::~abstract_argument_queue() 4 | { 5 | return; 6 | } 7 | -------------------------------------------------------------------------------- /program/abstract_argument_queue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace jkgm { 6 | 7 | class abstract_argument_queue { 8 | public: 9 | virtual ~abstract_argument_queue(); 10 | 11 | virtual bool empty() const = 0; 12 | virtual std::string peek() const = 0; 13 | virtual void pop() = 0; 14 | }; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /program/abstract_bare_option.cpp: -------------------------------------------------------------------------------- 1 | #include "abstract_bare_option.hpp" 2 | 3 | jkgm::abstract_bare_option::abstract_bare_option() 4 | { 5 | return; 6 | } 7 | 8 | jkgm::abstract_bare_option::~abstract_bare_option() 9 | { 10 | return; 11 | } 12 | -------------------------------------------------------------------------------- /program/abstract_bare_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_argument_queue.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | 8 | class abstract_bare_option { 9 | protected: 10 | abstract_bare_option(); 11 | 12 | public: 13 | virtual ~abstract_bare_option(); 14 | 15 | virtual void reset() = 0; 16 | virtual void load_from_arg(std::string const &arg, 17 | abstract_argument_queue &arg_list) = 0; 18 | 19 | virtual bool has_value() const = 0; 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /program/abstract_option.cpp: -------------------------------------------------------------------------------- 1 | #include "abstract_option.hpp" 2 | 3 | jkgm::abstract_option::abstract_option(std::string const &name) 4 | : name(name) 5 | { 6 | return; 7 | } 8 | 9 | jkgm::abstract_option::~abstract_option() 10 | { 11 | return; 12 | } 13 | -------------------------------------------------------------------------------- /program/abstract_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_argument_queue.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class abstract_option { 8 | protected: 9 | abstract_option(std::string const &name); 10 | 11 | public: 12 | std::string const name; 13 | 14 | virtual ~abstract_option(); 15 | 16 | virtual void reset() = 0; 17 | virtual void load_from_arg_list(abstract_argument_queue &arg_list) = 0; 18 | 19 | virtual bool has_value() const = 0; 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /program/at_least_one_input.cpp: -------------------------------------------------------------------------------- 1 | #include "at_least_one_input.hpp" 2 | #include "base/log.hpp" 3 | #include "options.hpp" 4 | 5 | void jkgm::at_least_one_input::check_constraint(options const &opts) const 6 | { 7 | if(!opts.has_bare_value()) { 8 | LOG_ERROR("No input files specified"); 9 | throw std::runtime_error("Invalid arguments"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /program/at_least_one_input.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option_constraint.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | 8 | class at_least_one_input : public option_constraint { 9 | public: 10 | virtual void check_constraint(options const &opts) const; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /program/bare_multi_value_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_bare_option.hpp" 4 | #include "base/lexical_cast.hpp" 5 | #include "base/log.hpp" 6 | #include 7 | #include 8 | 9 | namespace jkgm { 10 | template 11 | class bare_multi_value_option : public abstract_bare_option { 12 | private: 13 | BindingItT binding; 14 | bool is_set = false; 15 | 16 | public: 17 | bare_multi_value_option(BindingItT &binding) 18 | : binding(binding) 19 | { 20 | return; 21 | } 22 | 23 | virtual void reset() override 24 | { 25 | is_set = false; 26 | return; 27 | } 28 | 29 | virtual void load_from_arg(std::string const &arg, abstract_argument_queue &) override 30 | { 31 | try { 32 | *binding = jkgm::lexical_cast(arg); 33 | } 34 | catch(std::exception const &e) { 35 | LOG_ERROR("Could not parse value for input: ", e.what()); 36 | throw; 37 | } 38 | 39 | ++binding; 40 | is_set = true; 41 | } 42 | 43 | virtual bool has_value() const override 44 | { 45 | return is_set; 46 | } 47 | }; 48 | 49 | template 50 | std::unique_ptr make_bare_multi_value_option(OutputItT output_iterator) 51 | { 52 | return std::make_unique>(output_iterator); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /program/dependent_option.cpp: -------------------------------------------------------------------------------- 1 | #include "dependent_option.hpp" 2 | #include "base/log.hpp" 3 | #include "options.hpp" 4 | 5 | jkgm::dependent_option::dependent_option(std::string const &option, std::string const &dependency) 6 | : option(option) 7 | , dependency(dependency) 8 | { 9 | return; 10 | } 11 | 12 | void jkgm::dependent_option::check_constraint(options const &opt) const 13 | { 14 | if(opt.has_value(option) && !opt.has_value(dependency)) { 15 | LOG_ERROR("option ", option, " requires option ", dependency); 16 | throw std::runtime_error("Invalid arguments"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /program/dependent_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option_constraint.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | 8 | class dependent_option : public option_constraint { 9 | private: 10 | std::string option; 11 | std::string dependency; 12 | 13 | public: 14 | dependent_option(std::string const &name, 15 | std::string const &dependency); 16 | 17 | virtual void check_constraint(options const &opt) const override; 18 | }; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /program/multi_value_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_option.hpp" 4 | #include "base/lexical_cast.hpp" 5 | #include "base/log.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | template 10 | class multi_value_option : public abstract_option { 11 | private: 12 | BindingItT binding; 13 | bool is_set = false; 14 | 15 | public: 16 | multi_value_option(std::string const &name, BindingItT &binding) 17 | : abstract_option(name) 18 | , binding(binding) 19 | { 20 | return; 21 | } 22 | 23 | virtual void reset() override 24 | { 25 | is_set = false; 26 | return; 27 | } 28 | 29 | virtual void load_from_arg_list(abstract_argument_queue &arg_list) override 30 | { 31 | if(arg_list.empty()) { 32 | LOG_ERROR("Option ", name, " requires a value"); 33 | throw std::runtime_error("Invalid arguments"); 34 | } 35 | 36 | auto em = arg_list.peek(); 37 | arg_list.pop(); 38 | 39 | try { 40 | *binding = jkgm::lexical_cast(em); 41 | } 42 | catch(std::exception const &e) { 43 | LOG_ERROR("Could not parse value for option ", name, ": ", e.what()); 44 | throw; 45 | } 46 | 47 | ++binding; 48 | is_set = true; 49 | } 50 | 51 | virtual bool has_value() const override 52 | { 53 | return is_set; 54 | } 55 | }; 56 | 57 | template 58 | std::unique_ptr make_multi_value_option(std::string const &name, 59 | OutputItT output_iterator) 60 | { 61 | return std::make_unique>(name, output_iterator); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /program/mutual_exclusion.cpp: -------------------------------------------------------------------------------- 1 | #include "mutual_exclusion.hpp" 2 | #include "base/log.hpp" 3 | #include "base/oxford_join.hpp" 4 | #include "options.hpp" 5 | 6 | jkgm::mutual_exclusion::mutual_exclusion(std::vector const &opts, 7 | int min_set, 8 | int max_set) 9 | : exclusive_options(opts) 10 | , min_set(min_set) 11 | , max_set(max_set) 12 | { 13 | return; 14 | } 15 | 16 | void jkgm::mutual_exclusion::check_constraint(options const &opt) const 17 | { 18 | int count = 0; 19 | for(auto const &exclusive_option : exclusive_options) { 20 | if(opt.has_value(exclusive_option)) { 21 | ++count; 22 | } 23 | } 24 | 25 | if(count < min_set) { 26 | LOG_ERROR("At least ", 27 | min_set, 28 | " of ", 29 | jkgm::oxford_join(exclusive_options), 30 | " must be specified"); 31 | throw std::runtime_error("Invalid arguments"); 32 | } 33 | else if(count > max_set) { 34 | LOG_ERROR( 35 | "At most ", max_set, " of ", jkgm::oxford_join(exclusive_options), " may be specified"); 36 | throw std::runtime_error("Invalid arguments"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /program/mutual_exclusion.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option_constraint.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | namespace jkgm { 9 | 10 | class mutual_exclusion : public option_constraint { 11 | private: 12 | std::vector exclusive_options; 13 | int min_set; 14 | int max_set; 15 | 16 | public: 17 | mutual_exclusion(std::vector const &exclusive_options, 18 | int min_set = 0, 19 | int max_set = 1); 20 | 21 | virtual void check_constraint(options const &opt) const override; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /program/option_constraint.cpp: -------------------------------------------------------------------------------- 1 | #include "option_constraint.hpp" 2 | 3 | jkgm::option_constraint::~option_constraint() 4 | { 5 | return; 6 | } 7 | -------------------------------------------------------------------------------- /program/option_constraint.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace jkgm { 4 | 5 | class options; 6 | 7 | class option_constraint { 8 | public: 9 | virtual ~option_constraint(); 10 | 11 | virtual void check_constraint(options const &opts) const = 0; 12 | }; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /program/program.cpp: -------------------------------------------------------------------------------- 1 | #include "program.hpp" 2 | #include "base/env.hpp" 3 | #include "base/file_log_backend.hpp" 4 | #include "base/std_output_log_backend.hpp" 5 | 6 | #include 7 | 8 | jkgm::program::program() 9 | { 10 | // Initialize logging 11 | 12 | // Logging to standard output shouldn't be too verbose 13 | jkgm::flag_set stdout_diagnostic_level{ 14 | jkgm::log_level::error, jkgm::log_level::warning, jkgm::log_level::info}; 15 | 16 | if(jkgm::has_environment_variable("JKGM_DEBUG")) { 17 | stdout_diagnostic_level += jkgm::log_level::debug; 18 | } 19 | 20 | jkgm::emplace_log_backend(stdout_diagnostic_level); 21 | 22 | // Enable file logging if the correct environment variables are set 23 | std::optional maybe_log_file = jkgm::get_environment_variable("JKGM_LOG_FILE"); 24 | if(maybe_log_file.has_value()) { 25 | jkgm::emplace_log_backend({jkgm::log_level::error, 26 | jkgm::log_level::warning, 27 | jkgm::log_level::info, 28 | jkgm::log_level::debug, 29 | jkgm::log_level::trace}, 30 | maybe_log_file.value()); 31 | } 32 | } 33 | 34 | int jkgm::program::start(jkgm::range const &args) 35 | { 36 | try { 37 | create_options(opts); 38 | opts.load_from_arg_list(args); 39 | 40 | return run(); 41 | } 42 | catch(std::exception const &e) { 43 | LOG_ERROR("Exception thrown: ", e.what()); 44 | return EXIT_FAILURE; 45 | } 46 | catch(...) { 47 | LOG_ERROR("Unknown exception thrown"); 48 | return EXIT_FAILURE; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /program/program.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/range.hpp" 4 | #include "options.hpp" 5 | 6 | namespace jkgm { 7 | class program { 8 | private: 9 | options opts; 10 | 11 | protected: 12 | virtual void create_options(options &) = 0; 13 | virtual int run() = 0; 14 | 15 | public: 16 | program(); 17 | int start(jkgm::range const &); 18 | }; 19 | } 20 | 21 | #define MAKE_MAIN(ProgramT) \ 22 | int main(int argc, char **argv) \ 23 | { \ 24 | ProgramT program; \ 25 | return program.start(jkgm::make_range(argv + 1, argv + argc)); \ 26 | } 27 | -------------------------------------------------------------------------------- /program/range_argument_queue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_argument_queue.hpp" 4 | 5 | namespace jkgm { 6 | 7 | template 8 | class range_argument_queue : public abstract_argument_queue { 9 | private: 10 | ItT range_begin, range_end; 11 | 12 | public: 13 | range_argument_queue(ItT const &range_begin, ItT const &range_end) 14 | : range_begin(range_begin) 15 | , range_end(range_end) 16 | { 17 | return; 18 | } 19 | 20 | virtual bool empty() const override 21 | { 22 | return range_begin == range_end; 23 | } 24 | 25 | virtual std::string peek() const override 26 | { 27 | return static_cast(*range_begin); 28 | } 29 | 30 | virtual void pop() override 31 | { 32 | ++range_begin; 33 | } 34 | }; 35 | 36 | template 37 | range_argument_queue make_range_argument_queue(ItT const &range_begin, 38 | ItT const &range_end) 39 | { 40 | return range_argument_queue(range_begin, range_end); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /program/required_option.cpp: -------------------------------------------------------------------------------- 1 | #include "required_option.hpp" 2 | #include "base/log.hpp" 3 | #include "base/oxford_join.hpp" 4 | #include "options.hpp" 5 | 6 | jkgm::required_option::required_option(std::string const &name) 7 | { 8 | names.push_back(name); 9 | return; 10 | } 11 | 12 | jkgm::required_option::required_option(std::vector const &names) 13 | : names(names) 14 | { 15 | return; 16 | } 17 | 18 | void jkgm::required_option::check_constraint(options const &opt) const 19 | { 20 | bool all_specified = true; 21 | for(auto const &name : names) { 22 | all_specified = all_specified && opt.has_value(name); 23 | } 24 | 25 | if(!all_specified) { 26 | LOG_ERROR(((names.size() > 1) ? "Options" : "Option"), 27 | " ", 28 | jkgm::oxford_join(names), 29 | " must be specified"); 30 | throw std::runtime_error("Invalid arguments"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /program/required_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option_constraint.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | 9 | class required_option : public option_constraint { 10 | private: 11 | std::vector names; 12 | 13 | public: 14 | required_option(std::string const &name); 15 | required_option(std::vector const &names); 16 | 17 | virtual void check_constraint(options const &opt) const override; 18 | }; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /program/switch_option.cpp: -------------------------------------------------------------------------------- 1 | #include "switch_option.hpp" 2 | #include "base/log.hpp" 3 | 4 | jkgm::switch_option::switch_option(std::string const &name, bool &binding) 5 | : abstract_option(name) 6 | , binding(binding) 7 | { 8 | return; 9 | } 10 | 11 | void jkgm::switch_option::reset() 12 | { 13 | binding = false; 14 | } 15 | 16 | void jkgm::switch_option::load_from_arg_list(abstract_argument_queue &) 17 | { 18 | if(binding) { 19 | // Switch is already set, and is being re-set. Raise a warning. 20 | LOG_WARNING("Option ", name, " is already set"); 21 | } 22 | 23 | binding = true; 24 | } 25 | 26 | bool jkgm::switch_option::has_value() const 27 | { 28 | return binding; 29 | } 30 | 31 | std::unique_ptr jkgm::make_switch_option(std::string const &name, 32 | bool &binding) 33 | { 34 | return std::make_unique(name, binding); 35 | } 36 | -------------------------------------------------------------------------------- /program/switch_option.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "abstract_option.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | 8 | class switch_option : public abstract_option { 9 | private: 10 | bool &binding; 11 | 12 | public: 13 | switch_option(std::string const &name, bool &binding); 14 | 15 | virtual void reset() override; 16 | virtual void load_from_arg_list(abstract_argument_queue &arg_list) override; 17 | 18 | virtual bool has_value() const override; 19 | }; 20 | 21 | std::unique_ptr make_switch_option(std::string const &name, bool &binding); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /renderer/backbuffer_menu_surface.cpp: -------------------------------------------------------------------------------- 1 | #include "backbuffer_menu_surface.hpp" 2 | #include "base/log.hpp" 3 | #include "dxguids.hpp" 4 | #include "primary_menu_surface.hpp" 5 | #include "renderer.hpp" 6 | 7 | jkgm::backbuffer_menu_surface::backbuffer_menu_surface(renderer *r, primary_menu_surface *surf) 8 | : DirectDrawSurface_impl("backbuffer menu") 9 | , r(r) 10 | , surf(surf) 11 | { 12 | } 13 | 14 | ULONG WINAPI jkgm::backbuffer_menu_surface::AddRef() 15 | { 16 | // Primary surface is managed by the renderer. Refcount is intentionally not used. 17 | return 1000; 18 | } 19 | 20 | ULONG WINAPI jkgm::backbuffer_menu_surface::Release() 21 | { 22 | // Primary surface is managed by the renderer. Refcount is intentionally not used. 23 | return 1000; 24 | } 25 | 26 | HRESULT WINAPI jkgm::backbuffer_menu_surface::Blt(LPRECT a, 27 | LPDIRECTDRAWSURFACE b, 28 | LPRECT c, 29 | DWORD d, 30 | LPDDBLTFX e) 31 | { 32 | surf->no_present_blt(a, b, c, d, e); 33 | return DD_OK; 34 | } 35 | 36 | HRESULT WINAPI jkgm::backbuffer_menu_surface::GetSurfaceDesc(LPDDSURFACEDESC a) 37 | { 38 | return surf->GetSurfaceDesc(a); 39 | } 40 | 41 | HRESULT WINAPI jkgm::backbuffer_menu_surface::Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) 42 | { 43 | return surf->Lock(a, b, c, d); 44 | } 45 | 46 | HRESULT WINAPI jkgm::backbuffer_menu_surface::SetPalette(LPDIRECTDRAWPALETTE a) 47 | { 48 | // Intentionally ignored: renderer tracks the global palette object 49 | return DD_OK; 50 | } 51 | 52 | HRESULT WINAPI jkgm::backbuffer_menu_surface::Unlock(LPVOID a) 53 | { 54 | return DD_OK; 55 | } -------------------------------------------------------------------------------- /renderer/backbuffer_menu_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include "renderer_fwd.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class primary_menu_surface; 9 | 10 | class backbuffer_menu_surface : public DirectDrawSurface_impl { 11 | private: 12 | renderer *r; 13 | primary_menu_surface *surf; 14 | 15 | public: 16 | backbuffer_menu_surface(renderer *r, primary_menu_surface *surf); 17 | 18 | ULONG WINAPI AddRef() override; 19 | ULONG WINAPI Release() override; 20 | 21 | HRESULT WINAPI 22 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 23 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 24 | HRESULT WINAPI Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) override; 25 | HRESULT WINAPI SetPalette(LPDIRECTDRAWPALETTE a) override; 26 | HRESULT WINAPI Unlock(LPVOID a) override; 27 | }; 28 | } -------------------------------------------------------------------------------- /renderer/backbuffer_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include "math/size.hpp" 5 | #include "renderer_fwd.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | class backbuffer_surface : public DirectDrawSurface_impl { 10 | private: 11 | renderer *r; 12 | 13 | public: 14 | std::vector buffer; 15 | size<2, int> dims; 16 | 17 | uint16_t color_key = 0xF81FUL; // Magenta in RGB555 18 | 19 | backbuffer_surface(renderer *r, size<2, int> dims); 20 | 21 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 22 | ULONG WINAPI AddRef() override; 23 | ULONG WINAPI Release() override; 24 | 25 | HRESULT WINAPI AddAttachedSurface(LPDIRECTDRAWSURFACE a) override; 26 | HRESULT WINAPI 27 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 28 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 29 | HRESULT WINAPI Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) override; 30 | HRESULT WINAPI Unlock(LPVOID a) override; 31 | }; 32 | } -------------------------------------------------------------------------------- /renderer/d3d_impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_fwd.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class Direct3D_impl : public IDirect3D { 8 | private: 9 | renderer *r; 10 | 11 | public: 12 | explicit Direct3D_impl(renderer *r); 13 | 14 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 15 | ULONG WINAPI AddRef() override; 16 | ULONG WINAPI Release() override; 17 | 18 | HRESULT WINAPI Initialize(REFCLSID a) override; 19 | HRESULT WINAPI EnumDevices(LPD3DENUMDEVICESCALLBACK a, LPVOID b) override; 20 | HRESULT WINAPI CreateLight(LPDIRECT3DLIGHT *a, IUnknown *b) override; 21 | HRESULT WINAPI CreateMaterial(LPDIRECT3DMATERIAL *a, IUnknown *b) override; 22 | HRESULT WINAPI CreateViewport(LPDIRECT3DVIEWPORT *a, IUnknown *b) override; 23 | HRESULT WINAPI FindDevice(LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b) override; 24 | }; 25 | } -------------------------------------------------------------------------------- /renderer/d3ddevice_impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_fwd.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class Direct3DDevice_impl : public IDirect3DDevice { 8 | private: 9 | renderer *r; 10 | 11 | public: 12 | explicit Direct3DDevice_impl(renderer *r); 13 | 14 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 15 | ULONG WINAPI AddRef() override; 16 | ULONG WINAPI Release() override; 17 | 18 | HRESULT WINAPI Initialize(LPDIRECT3D a, LPGUID b, LPD3DDEVICEDESC c) override; 19 | HRESULT WINAPI GetCaps(LPD3DDEVICEDESC, LPD3DDEVICEDESC) override; 20 | HRESULT WINAPI SwapTextureHandles(LPDIRECT3DTEXTURE a, LPDIRECT3DTEXTURE b) override; 21 | HRESULT WINAPI CreateExecuteBuffer(LPD3DEXECUTEBUFFERDESC a, 22 | LPDIRECT3DEXECUTEBUFFER *b, 23 | IUnknown *c) override; 24 | HRESULT WINAPI GetStats(LPD3DSTATS a) override; 25 | HRESULT WINAPI Execute(LPDIRECT3DEXECUTEBUFFER a, LPDIRECT3DVIEWPORT b, DWORD c) override; 26 | HRESULT WINAPI AddViewport(LPDIRECT3DVIEWPORT a) override; 27 | HRESULT WINAPI DeleteViewport(LPDIRECT3DVIEWPORT a) override; 28 | HRESULT WINAPI NextViewport(LPDIRECT3DVIEWPORT a, LPDIRECT3DVIEWPORT *b, DWORD c) override; 29 | HRESULT WINAPI Pick(LPDIRECT3DEXECUTEBUFFER a, 30 | LPDIRECT3DVIEWPORT b, 31 | DWORD c, 32 | LPD3DRECT d) override; 33 | HRESULT WINAPI GetPickRecords(LPDWORD a, LPD3DPICKRECORD b) override; 34 | HRESULT WINAPI EnumTextureFormats(LPD3DENUMTEXTUREFORMATSCALLBACK a, LPVOID b) override; 35 | HRESULT WINAPI CreateMatrix(LPD3DMATRIXHANDLE a) override; 36 | HRESULT WINAPI SetMatrix(D3DMATRIXHANDLE a, const LPD3DMATRIX b) override; 37 | HRESULT WINAPI GetMatrix(D3DMATRIXHANDLE a, LPD3DMATRIX b) override; 38 | HRESULT WINAPI DeleteMatrix(D3DMATRIXHANDLE a) override; 39 | HRESULT WINAPI BeginScene() override; 40 | HRESULT WINAPI EndScene() override; 41 | HRESULT WINAPI GetDirect3D(LPDIRECT3D *a) override; 42 | }; 43 | } -------------------------------------------------------------------------------- /renderer/d3dtexture_impl.cpp: -------------------------------------------------------------------------------- 1 | #include "d3dtexture_impl.hpp" 2 | #include "base/log.hpp" 3 | #include "common/error_reporter.hpp" 4 | #include "dxguids.hpp" 5 | 6 | jkgm::Direct3DTexture_impl::Direct3DTexture_impl(char const *obj_name) 7 | : obj_name(obj_name) 8 | { 9 | } 10 | 11 | HRESULT WINAPI jkgm::Direct3DTexture_impl::QueryInterface(REFIID riid, LPVOID *ppvObj) 12 | { 13 | report_unimplemented_function( 14 | str(fmt("Direct3DTexture(", obj_name, ")::QueryInterface(", to_string(riid), ")"))); 15 | } 16 | 17 | HRESULT WINAPI jkgm::Direct3DTexture_impl::Initialize(LPDIRECT3DDEVICE a, LPDIRECTDRAWSURFACE b) 18 | { 19 | report_unimplemented_function(str(fmt("Direct3DTexture(", obj_name, ")::Initialize"))); 20 | } 21 | 22 | HRESULT WINAPI jkgm::Direct3DTexture_impl::GetHandle(LPDIRECT3DDEVICE a, LPD3DTEXTUREHANDLE b) 23 | { 24 | report_unimplemented_function(str(fmt("Direct3DTexture(", obj_name, ")::GetHandle"))); 25 | } 26 | 27 | HRESULT WINAPI jkgm::Direct3DTexture_impl::PaletteChanged(DWORD a, DWORD b) 28 | { 29 | report_unimplemented_function(str(fmt("Direct3DTexture(", obj_name, ")::PaletteChanged"))); 30 | } 31 | 32 | HRESULT WINAPI jkgm::Direct3DTexture_impl::Load(LPDIRECT3DTEXTURE a) 33 | { 34 | report_unimplemented_function(str(fmt("Direct3DTexture(", obj_name, ")::Load"))); 35 | } 36 | 37 | HRESULT WINAPI jkgm::Direct3DTexture_impl::Unload() 38 | { 39 | report_unimplemented_function(str(fmt("Direct3DTexture(", obj_name, ")::Unload"))); 40 | } -------------------------------------------------------------------------------- /renderer/d3dtexture_impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace jkgm { 6 | class Direct3DTexture_impl : public IDirect3DTexture { 7 | private: 8 | char const *obj_name; 9 | 10 | public: 11 | explicit Direct3DTexture_impl(char const *obj_name); 12 | 13 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 14 | 15 | HRESULT WINAPI Initialize(LPDIRECT3DDEVICE a, LPDIRECTDRAWSURFACE b) override; 16 | HRESULT WINAPI GetHandle(LPDIRECT3DDEVICE a, LPD3DTEXTUREHANDLE b) override; 17 | HRESULT WINAPI PaletteChanged(DWORD a, DWORD b) override; 18 | HRESULT WINAPI Load(LPDIRECT3DTEXTURE a) override; 19 | HRESULT WINAPI Unload() override; 20 | }; 21 | } -------------------------------------------------------------------------------- /renderer/d3dviewport_impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_fwd.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class Direct3DViewport_impl : public IDirect3DViewport { 8 | private: 9 | renderer *r; 10 | D3DVIEWPORT data; 11 | 12 | public: 13 | explicit Direct3DViewport_impl(renderer *r); 14 | 15 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 16 | ULONG WINAPI AddRef() override; 17 | ULONG WINAPI Release() override; 18 | 19 | HRESULT WINAPI Initialize(LPDIRECT3D a) override; 20 | HRESULT WINAPI GetViewport(LPD3DVIEWPORT a) override; 21 | HRESULT WINAPI SetViewport(LPD3DVIEWPORT a) override; 22 | HRESULT WINAPI TransformVertices(DWORD a, 23 | LPD3DTRANSFORMDATA b, 24 | DWORD c, 25 | LPDWORD d) override; 26 | HRESULT WINAPI LightElements(DWORD a, LPD3DLIGHTDATA b) override; 27 | HRESULT WINAPI SetBackground(D3DMATERIALHANDLE a) override; 28 | HRESULT WINAPI GetBackground(LPD3DMATERIALHANDLE a, LPBOOL b) override; 29 | HRESULT WINAPI SetBackgroundDepth(LPDIRECTDRAWSURFACE a) override; 30 | HRESULT WINAPI GetBackgroundDepth(LPDIRECTDRAWSURFACE *a, LPBOOL b) override; 31 | HRESULT WINAPI Clear(DWORD a, LPD3DRECT b, DWORD c) override; 32 | HRESULT WINAPI AddLight(LPDIRECT3DLIGHT a) override; 33 | HRESULT WINAPI DeleteLight(LPDIRECT3DLIGHT a) override; 34 | HRESULT WINAPI NextLight(LPDIRECT3DLIGHT a, LPDIRECT3DLIGHT *b, DWORD c) override; 35 | }; 36 | } -------------------------------------------------------------------------------- /renderer/ddraw_impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_fwd.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class DirectDraw_impl : public IDirectDraw { 8 | private: 9 | renderer *r; 10 | 11 | public: 12 | explicit DirectDraw_impl(renderer *r); 13 | 14 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 15 | ULONG WINAPI AddRef() override; 16 | ULONG WINAPI Release() override; 17 | 18 | HRESULT WINAPI Compact() override; 19 | HRESULT WINAPI CreateClipper(DWORD a, LPDIRECTDRAWCLIPPER *b, IUnknown *c) override; 20 | HRESULT WINAPI CreatePalette(DWORD a, 21 | LPPALETTEENTRY b, 22 | LPDIRECTDRAWPALETTE *c, 23 | IUnknown *d) override; 24 | HRESULT WINAPI CreateSurface(LPDDSURFACEDESC a, 25 | LPDIRECTDRAWSURFACE *b, 26 | IUnknown *c) override; 27 | HRESULT WINAPI DuplicateSurface(LPDIRECTDRAWSURFACE a, LPDIRECTDRAWSURFACE *b) override; 28 | HRESULT WINAPI EnumDisplayModes(DWORD a, 29 | LPDDSURFACEDESC b, 30 | LPVOID c, 31 | LPDDENUMMODESCALLBACK d) override; 32 | HRESULT WINAPI EnumSurfaces(DWORD a, 33 | LPDDSURFACEDESC b, 34 | LPVOID c, 35 | LPDDENUMSURFACESCALLBACK d) override; 36 | HRESULT WINAPI FlipToGDISurface() override; 37 | HRESULT WINAPI GetCaps(LPDDCAPS a, LPDDCAPS b) override; 38 | HRESULT WINAPI GetDisplayMode(LPDDSURFACEDESC a) override; 39 | HRESULT WINAPI GetFourCCCodes(LPDWORD a, LPDWORD b) override; 40 | HRESULT WINAPI GetGDISurface(LPDIRECTDRAWSURFACE *a) override; 41 | HRESULT WINAPI GetMonitorFrequency(LPDWORD a) override; 42 | HRESULT WINAPI GetScanLine(LPDWORD a) override; 43 | HRESULT WINAPI GetVerticalBlankStatus(LPBOOL a) override; 44 | HRESULT WINAPI Initialize(GUID *a) override; 45 | HRESULT WINAPI RestoreDisplayMode() override; 46 | HRESULT WINAPI SetCooperativeLevel(HWND a, DWORD b) override; 47 | HRESULT WINAPI SetDisplayMode(DWORD a, DWORD b, DWORD c) override; 48 | HRESULT WINAPI WaitForVerticalBlank(DWORD a, HANDLE b) override; 49 | }; 50 | } -------------------------------------------------------------------------------- /renderer/ddrawpalette_impl.cpp: -------------------------------------------------------------------------------- 1 | #include "ddrawpalette_impl.hpp" 2 | #include "base/log.hpp" 3 | #include "common/error_reporter.hpp" 4 | #include "dxguids.hpp" 5 | #include "math/color_conv.hpp" 6 | #include "renderer.hpp" 7 | 8 | jkgm::DirectDrawPalette_impl::DirectDrawPalette_impl(renderer *r) 9 | : r(r) 10 | { 11 | srgb_entries.resize(256, color_rgba8::zero()); 12 | entries.resize(256); 13 | } 14 | 15 | void jkgm::DirectDrawPalette_impl::recompute_palette() 16 | { 17 | for(size_t i = 0; i < 256; ++i) { 18 | auto src_col = entries[i]; 19 | srgb_entries[i] = color_rgba8(src_col.peRed, src_col.peGreen, src_col.peBlue, uint8_t(255)); 20 | } 21 | } 22 | 23 | HRESULT WINAPI jkgm::DirectDrawPalette_impl::QueryInterface(REFIID riid, LPVOID *ppvObj) 24 | { 25 | report_unimplemented_function( 26 | str(fmt("DirectDrawPalette::QueryInterface(", to_string(riid), ")"))); 27 | } 28 | 29 | ULONG WINAPI jkgm::DirectDrawPalette_impl::AddRef() 30 | { 31 | // DirectDrawPalette is managed by the renderer. Refcount is intentionally not used. 32 | return 1000; 33 | } 34 | 35 | ULONG WINAPI jkgm::DirectDrawPalette_impl::Release() 36 | { 37 | // DirectDrawPalette is managed by the renderer. Refcount is intentionally not used. 38 | return 1000; 39 | } 40 | 41 | HRESULT WINAPI jkgm::DirectDrawPalette_impl::GetCaps(LPDWORD a) 42 | { 43 | report_unimplemented_function("DirectDrawPalette::GetCaps"); 44 | } 45 | 46 | HRESULT WINAPI jkgm::DirectDrawPalette_impl::GetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY d) 47 | { 48 | report_unimplemented_function("DirectDrawPalette::GetEntries"); 49 | } 50 | 51 | HRESULT WINAPI jkgm::DirectDrawPalette_impl::Initialize(LPDIRECTDRAW a, DWORD b, LPPALETTEENTRY d) 52 | { 53 | report_unimplemented_function("DirectDrawPalette::Initialize"); 54 | } 55 | 56 | HRESULT WINAPI jkgm::DirectDrawPalette_impl::SetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY d) 57 | { 58 | std::copy(d, d + c, &entries[b]); 59 | recompute_palette(); 60 | r->present_menu_surface_delayed(); 61 | return DD_OK; 62 | } -------------------------------------------------------------------------------- /renderer/ddrawpalette_impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "math/color.hpp" 4 | #include "renderer_fwd.hpp" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace jkgm { 10 | class DirectDrawPalette_impl : public IDirectDrawPalette { 11 | private: 12 | renderer *r; 13 | 14 | public: 15 | explicit DirectDrawPalette_impl(renderer *r); 16 | 17 | std::vector srgb_entries; 18 | std::vector entries; 19 | 20 | void recompute_palette(); 21 | 22 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 23 | ULONG WINAPI AddRef() override; 24 | ULONG WINAPI Release() override; 25 | 26 | HRESULT WINAPI GetCaps(LPDWORD a) override; 27 | HRESULT WINAPI GetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY d) override; 28 | HRESULT WINAPI Initialize(LPDIRECTDRAW a, DWORD b, LPPALETTEENTRY d) override; 29 | HRESULT WINAPI SetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY d) override; 30 | }; 31 | } -------------------------------------------------------------------------------- /renderer/execute_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "execute_buffer.hpp" 2 | #include "base/log.hpp" 3 | #include "common/error_reporter.hpp" 4 | #include "dxguids.hpp" 5 | 6 | jkgm::execute_buffer::execute_buffer(size_t bufsz) 7 | : bufsz(bufsz) 8 | { 9 | buffer.resize(bufsz); 10 | } 11 | 12 | HRESULT WINAPI jkgm::execute_buffer::QueryInterface(REFIID riid, LPVOID *ppvObj) 13 | { 14 | report_unimplemented_function( 15 | str(fmt("Direct3DExecuteBuffer::QueryInterface(", to_string(riid), ")"))); 16 | } 17 | 18 | ULONG WINAPI jkgm::execute_buffer::AddRef() 19 | { 20 | return ++refct; 21 | } 22 | 23 | ULONG WINAPI jkgm::execute_buffer::Release() 24 | { 25 | return --refct; 26 | } 27 | 28 | HRESULT WINAPI jkgm::execute_buffer::Initialize(LPDIRECT3DDEVICE a, LPD3DEXECUTEBUFFERDESC b) 29 | { 30 | report_unimplemented_function("Direct3DExecuteBuffer::Initialize"); 31 | } 32 | 33 | HRESULT WINAPI jkgm::execute_buffer::Lock(LPD3DEXECUTEBUFFERDESC a) 34 | { 35 | D3DEXECUTEBUFFERDESC desc; 36 | ZeroMemory(&desc, sizeof(desc)); 37 | 38 | desc.dwSize = sizeof(desc); 39 | desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_LPDATA; 40 | desc.dwBufferSize = bufsz; 41 | desc.lpData = buffer.data(); 42 | 43 | CopyMemory(a, &desc, sizeof(desc)); 44 | 45 | return D3D_OK; 46 | } 47 | 48 | HRESULT WINAPI jkgm::execute_buffer::Unlock() 49 | { 50 | return D3D_OK; 51 | } 52 | 53 | HRESULT WINAPI jkgm::execute_buffer::SetExecuteData(LPD3DEXECUTEDATA a) 54 | { 55 | exec_data = *a; 56 | return D3D_OK; 57 | } 58 | 59 | HRESULT WINAPI jkgm::execute_buffer::GetExecuteData(LPD3DEXECUTEDATA a) 60 | { 61 | *a = exec_data; 62 | return D3D_OK; 63 | } 64 | 65 | HRESULT WINAPI jkgm::execute_buffer::Validate(LPDWORD a, LPD3DVALIDATECALLBACK b, LPVOID c, DWORD d) 66 | { 67 | report_unimplemented_function("Direct3DExecuteBuffer::Validate"); 68 | } 69 | 70 | HRESULT WINAPI jkgm::execute_buffer::Optimize(DWORD a) 71 | { 72 | report_unimplemented_function("Direct3DExecuteBuffer::Optimize"); 73 | } -------------------------------------------------------------------------------- /renderer/execute_buffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_fwd.hpp" 4 | #include 5 | #include 6 | 7 | namespace jkgm { 8 | class execute_buffer : public IDirect3DExecuteBuffer { 9 | public: 10 | int refct = 0; 11 | size_t bufsz = 0; 12 | D3DEXECUTEDATA exec_data; 13 | std::vector buffer; 14 | 15 | explicit execute_buffer(size_t bufsz); 16 | 17 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 18 | ULONG WINAPI AddRef() override; 19 | ULONG WINAPI Release() override; 20 | 21 | HRESULT WINAPI Initialize(LPDIRECT3DDEVICE a, LPD3DEXECUTEBUFFERDESC b) override; 22 | HRESULT WINAPI Lock(LPD3DEXECUTEBUFFERDESC a) override; 23 | HRESULT WINAPI Unlock() override; 24 | HRESULT WINAPI SetExecuteData(LPD3DEXECUTEDATA a) override; 25 | HRESULT WINAPI GetExecuteData(LPD3DEXECUTEDATA a) override; 26 | HRESULT WINAPI Validate(LPDWORD a, LPD3DVALIDATECALLBACK b, LPVOID c, DWORD d) override; 27 | HRESULT WINAPI Optimize(DWORD a) override; 28 | }; 29 | } -------------------------------------------------------------------------------- /renderer/exports.def: -------------------------------------------------------------------------------- 1 | LIBRARY RENDERER 2 | EXPORTS 3 | DetourFinishHelperProcess @1 4 | -------------------------------------------------------------------------------- /renderer/offscreen_menu_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class offscreen_menu_surface : public DirectDrawSurface_impl { 8 | public: 9 | DDSURFACEDESC sd; 10 | std::vector buffer; 11 | uint8_t color_key; 12 | 13 | offscreen_menu_surface(); 14 | 15 | void set_surface_desc(DDSURFACEDESC const &sd); 16 | 17 | ULONG WINAPI AddRef() override; 18 | ULONG WINAPI Release() override; 19 | 20 | HRESULT WINAPI 21 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 22 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 23 | HRESULT WINAPI Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) override; 24 | HRESULT WINAPI SetColorKey(DWORD a, LPDDCOLORKEY b) override; 25 | HRESULT WINAPI SetPalette(LPDIRECTDRAWPALETTE a) override; 26 | HRESULT WINAPI Unlock(LPVOID a) override; 27 | }; 28 | } -------------------------------------------------------------------------------- /renderer/offscreen_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class offscreen_surface : public DirectDrawSurface_impl { 8 | public: 9 | DDSURFACEDESC sd; 10 | std::vector buffer; 11 | uint16_t color_key; 12 | 13 | offscreen_surface(); 14 | 15 | void set_surface_desc(DDSURFACEDESC const &sd); 16 | 17 | ULONG WINAPI AddRef() override; 18 | ULONG WINAPI Release() override; 19 | 20 | HRESULT WINAPI 21 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 22 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 23 | HRESULT WINAPI Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) override; 24 | HRESULT WINAPI SetColorKey(DWORD a, LPDDCOLORKEY b) override; 25 | HRESULT WINAPI Unlock(LPVOID a) override; 26 | }; 27 | } -------------------------------------------------------------------------------- /renderer/primary_menu_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include "renderer_fwd.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class primary_menu_surface : public DirectDrawSurface_impl { 9 | private: 10 | renderer *r; 11 | DDSURFACEDESC sd; 12 | 13 | public: 14 | std::vector buffer; 15 | 16 | explicit primary_menu_surface(renderer *r); 17 | 18 | ULONG WINAPI AddRef() override; 19 | ULONG WINAPI Release() override; 20 | 21 | void no_present_blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e); 22 | 23 | HRESULT WINAPI 24 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 25 | HRESULT WINAPI Flip(LPDIRECTDRAWSURFACE a, DWORD b) override; 26 | HRESULT WINAPI GetAttachedSurface(LPDDSCAPS a, LPDIRECTDRAWSURFACE *b) override; 27 | HRESULT WINAPI GetBltStatus(DWORD a) override; 28 | HRESULT WINAPI GetFlipStatus(DWORD a) override; 29 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 30 | HRESULT WINAPI Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) override; 31 | HRESULT WINAPI SetPalette(LPDIRECTDRAWPALETTE a) override; 32 | HRESULT WINAPI Unlock(LPVOID a) override; 33 | }; 34 | } -------------------------------------------------------------------------------- /renderer/primary_surface.cpp: -------------------------------------------------------------------------------- 1 | #include "primary_surface.hpp" 2 | #include "base/log.hpp" 3 | #include "common/error_reporter.hpp" 4 | #include "dxguids.hpp" 5 | #include "renderer.hpp" 6 | 7 | jkgm::primary_surface::primary_surface(renderer *r) 8 | : DirectDrawSurface_impl("primary") 9 | , r(r) 10 | { 11 | } 12 | 13 | ULONG WINAPI jkgm::primary_surface::AddRef() 14 | { 15 | // Primary surface is managed by the renderer. Refcount is intentionally not used. 16 | return 1000; 17 | } 18 | 19 | ULONG WINAPI jkgm::primary_surface::Release() 20 | { 21 | // Primary surface is managed by the renderer. Refcount is intentionally not used. 22 | return 1000; 23 | } 24 | 25 | HRESULT WINAPI 26 | jkgm::primary_surface::Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) 27 | { 28 | // Intentionally ignored 29 | return DD_OK; 30 | } 31 | 32 | HRESULT WINAPI jkgm::primary_surface::Flip(LPDIRECTDRAWSURFACE a, DWORD b) 33 | { 34 | r->present_game(); 35 | return DD_OK; 36 | } 37 | 38 | HRESULT WINAPI jkgm::primary_surface::GetAttachedSurface(LPDDSCAPS a, LPDIRECTDRAWSURFACE *b) 39 | { 40 | if(a->dwCaps & DDSCAPS_BACKBUFFER) { 41 | *b = r->get_directdraw_backbuffer_surface(); 42 | return DD_OK; 43 | } 44 | 45 | report_unimplemented_function( 46 | str(fmt("DirectDrawSurface(primary)::GetAttachedSurface(", a->dwCaps, ")"))); 47 | } 48 | 49 | HRESULT WINAPI jkgm::primary_surface::GetBltStatus(DWORD a) 50 | { 51 | return DD_OK; 52 | } 53 | 54 | HRESULT WINAPI jkgm::primary_surface::GetFlipStatus(DWORD a) 55 | { 56 | return DD_OK; 57 | } 58 | 59 | HRESULT WINAPI jkgm::primary_surface::GetSurfaceDesc(LPDDSURFACEDESC a) 60 | { 61 | // Jedi Knight only asks for the surface caps and the number of back buffers 62 | a->dwBackBufferCount = 1; 63 | a->ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; 64 | 65 | return DD_OK; 66 | } -------------------------------------------------------------------------------- /renderer/primary_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include "renderer_fwd.hpp" 5 | 6 | namespace jkgm { 7 | class primary_surface : public DirectDrawSurface_impl { 8 | private: 9 | renderer *r; 10 | 11 | public: 12 | explicit primary_surface(renderer *r); 13 | 14 | ULONG WINAPI AddRef() override; 15 | ULONG WINAPI Release() override; 16 | 17 | HRESULT WINAPI 18 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 19 | HRESULT WINAPI Flip(LPDIRECTDRAWSURFACE a, DWORD b) override; 20 | HRESULT WINAPI GetAttachedSurface(LPDDSCAPS a, LPDIRECTDRAWSURFACE *b) override; 21 | HRESULT WINAPI GetBltStatus(DWORD a) override; 22 | HRESULT WINAPI GetFlipStatus(DWORD a) override; 23 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 24 | }; 25 | } -------------------------------------------------------------------------------- /renderer/renderer_ao.cpp: -------------------------------------------------------------------------------- 1 | #include "renderer_ao.hpp" 2 | #include "common/config.hpp" 3 | #include "renderer_ao_basic.hpp" 4 | #include "renderer_ao_ssao.hpp" 5 | 6 | std::unique_ptr jkgm::create_renderer_ao(config const *the_config, 7 | size<2, int> screen_res) 8 | { 9 | if(the_config->enable_ssao) { 10 | return std::make_unique(screen_res); 11 | } 12 | 13 | return std::make_unique(); 14 | } -------------------------------------------------------------------------------- /renderer/renderer_ao.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "glutil/texture.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | class config; 8 | struct opengl_state; 9 | 10 | class renderer_ao { 11 | public: 12 | virtual ~renderer_ao() = default; 13 | 14 | virtual void update_ssao_texture(opengl_state *ogs, 15 | gl::texture_view normal_tex, 16 | gl::texture_view depth_tex) = 0; 17 | virtual gl::texture_view get_ssao_texture() const = 0; 18 | }; 19 | 20 | std::unique_ptr create_renderer_ao(config const *the_config, 21 | size<2, int> screen_res); 22 | } -------------------------------------------------------------------------------- /renderer/renderer_ao_basic.cpp: -------------------------------------------------------------------------------- 1 | #include "renderer_ao_basic.hpp" 2 | 3 | void jkgm::renderer_ao_basic::update_ssao_texture(opengl_state * /*ogs*/, 4 | gl::texture_view /*normal_tex*/, 5 | gl::texture_view /*depth_tex*/) 6 | { 7 | } 8 | 9 | jkgm::gl::texture_view jkgm::renderer_ao_basic::get_ssao_texture() const 10 | { 11 | return gl::default_texture; 12 | } -------------------------------------------------------------------------------- /renderer/renderer_ao_basic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_ao.hpp" 4 | 5 | namespace jkgm { 6 | class renderer_ao_basic : public renderer_ao { 7 | public: 8 | void update_ssao_texture(opengl_state *ogs, 9 | gl::texture_view normal_tex, 10 | gl::texture_view depth_tex) override; 11 | gl::texture_view get_ssao_texture() const override; 12 | }; 13 | } -------------------------------------------------------------------------------- /renderer/renderer_ao_ssao.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "glutil/framebuffer.hpp" 4 | #include "glutil/texture.hpp" 5 | #include "renderer_ao.hpp" 6 | #include 7 | 8 | namespace jkgm { 9 | class ssao_occlusion_buffer { 10 | public: 11 | gl::framebuffer fbo; 12 | gl::texture tex; 13 | box<2, int> viewport; 14 | 15 | explicit ssao_occlusion_buffer(size<2, int> dims); 16 | }; 17 | 18 | class renderer_ao_ssao : public renderer_ao { 19 | private: 20 | ssao_occlusion_buffer ssao_occlusionbuffer; 21 | ssao_occlusion_buffer ssao_occlusionbuffer2; 22 | gl::texture ssao_noise_texture; 23 | std::vector> ssao_kernel; 24 | 25 | public: 26 | explicit renderer_ao_ssao(size<2, int> screen_res); 27 | 28 | void update_ssao_texture(opengl_state *ogs, 29 | gl::texture_view normal_tex, 30 | gl::texture_view depth_tex) override; 31 | gl::texture_view get_ssao_texture() const override; 32 | }; 33 | } -------------------------------------------------------------------------------- /renderer/renderer_compositor.cpp: -------------------------------------------------------------------------------- 1 | #include "renderer_compositor.hpp" 2 | #include "common/config.hpp" 3 | #include "renderer_compositor_basic.hpp" 4 | #include "renderer_compositor_bloom.hpp" 5 | 6 | std::unique_ptr 7 | jkgm::create_renderer_compositor(config const *the_config) 8 | { 9 | if(the_config->enable_bloom) { 10 | return std::make_unique(); 11 | } 12 | 13 | return std::make_unique(); 14 | } -------------------------------------------------------------------------------- /renderer/renderer_compositor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "glutil/texture.hpp" 4 | #include "math/size.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class config; 9 | struct opengl_state; 10 | 11 | class renderer_compositor { 12 | public: 13 | virtual ~renderer_compositor() = default; 14 | 15 | virtual void end_frame(opengl_state *ogs, 16 | size<2, int> screen_size, 17 | gl::texture_view composed_screen) = 0; 18 | }; 19 | 20 | std::unique_ptr create_renderer_compositor(config const *the_config); 21 | } 22 | -------------------------------------------------------------------------------- /renderer/renderer_compositor_basic.cpp: -------------------------------------------------------------------------------- 1 | #include "renderer_compositor_basic.hpp" 2 | #include "math/colors.hpp" 3 | #include "opengl_state.hpp" 4 | 5 | void jkgm::renderer_compositor_basic::end_frame(opengl_state *ogs, 6 | size<2, int> screen_size, 7 | gl::texture_view composed_screen) 8 | { 9 | // Compose renderbuffer onto window: 10 | gl::bind_vertex_array(ogs->postmdl.vao); 11 | 12 | gl::bind_framebuffer(gl::framebuffer_bind_target::any, gl::default_framebuffer); 13 | gl::set_viewport(make_box(make_point(0, 0), screen_size)); 14 | 15 | gl::set_clear_color(solid(colors::black)); 16 | gl::clear({gl::clear_flag::color, gl::clear_flag::depth}); 17 | gl::disable(gl::capability::depth_test); 18 | gl::disable(gl::capability::cull_face); 19 | 20 | // Copy to front buffer while converting to srgb 21 | ogs->post_to_srgb.use_program(); 22 | 23 | ogs->post_to_srgb.set_fbuf_sampler(0); 24 | 25 | gl::set_active_texture_unit(0); 26 | gl::bind_texture(gl::texture_bind_target::texture_2d, composed_screen); 27 | 28 | std::array bloom_samplers; 29 | std::array bloom_weights; 30 | 31 | int curr_sampler = 1; 32 | for(int i = 0; i < shaders::post_to_srgb_shader::num_bloom_layers; ++i) { 33 | auto const &hdr_stack_em = ogs->bloom_layers.elements.at(i); 34 | 35 | bloom_samplers.at(i) = curr_sampler; 36 | gl::set_active_texture_unit(curr_sampler); 37 | gl::bind_texture(gl::texture_bind_target::texture_2d, gl::default_texture); 38 | ++curr_sampler; 39 | 40 | bloom_weights.at(i) = hdr_stack_em.weight; 41 | } 42 | 43 | ogs->post_to_srgb.set_bloom_samplers(make_span(bloom_samplers)); 44 | ogs->post_to_srgb.set_bloom_weights(make_span(bloom_weights)); 45 | 46 | gl::draw_elements( 47 | gl::element_type::triangles, ogs->postmdl.num_indices, gl::index_type::uint32); 48 | } -------------------------------------------------------------------------------- /renderer/renderer_compositor_basic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_compositor.hpp" 4 | 5 | namespace jkgm { 6 | class renderer_compositor_basic : public renderer_compositor { 7 | public: 8 | void end_frame(opengl_state *ogs, 9 | size<2, int> screen_size, 10 | gl::texture_view composed_screen) override; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /renderer/renderer_compositor_bloom.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer_compositor.hpp" 4 | 5 | namespace jkgm { 6 | class renderer_compositor_bloom : public renderer_compositor { 7 | public: 8 | void end_frame(opengl_state *ogs, 9 | size<2, int> screen_size, 10 | gl::texture_view composed_screen) override; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /renderer/renderer_fwd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/id.hpp" 4 | #include 5 | 6 | namespace jkgm { 7 | MAKE_ID_TYPE(srgb_texture, size_t); 8 | MAKE_ID_TYPE(linear_texture, size_t); 9 | MAKE_ID_TYPE(material_instance, size_t); 10 | 11 | class renderer; 12 | } -------------------------------------------------------------------------------- /renderer/renderer_screen.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "glutil/texture.hpp" 4 | #include "math/size.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class config; 9 | 10 | class renderer_screen { 11 | public: 12 | virtual ~renderer_screen() = default; 13 | 14 | virtual void begin_frame() = 0; 15 | 16 | virtual void begin_opaque_pass() = 0; 17 | virtual void end_opaque_pass() = 0; 18 | virtual gl::texture_view get_resolved_color_texture() = 0; 19 | virtual gl::texture_view get_resolved_emissive_texture() = 0; 20 | virtual gl::texture_view get_resolved_normal_texture() = 0; 21 | virtual gl::texture_view get_resolved_depth_texture() = 0; 22 | 23 | virtual void begin_compose_opaque_pass() = 0; 24 | virtual void end_compose_opaque_pass() = 0; 25 | 26 | virtual void begin_transparency_pass() = 0; 27 | virtual void end_transparency_pass() = 0; 28 | 29 | virtual void end_frame() = 0; 30 | 31 | virtual gl::texture_view get_resolved_final_texture() = 0; 32 | }; 33 | 34 | std::unique_ptr create_renderer_screen(config const *the_config, 35 | size<2, int> screen_res); 36 | } -------------------------------------------------------------------------------- /renderer/renderer_screen_basic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "glutil/framebuffer.hpp" 4 | #include "glutil/renderbuffer.hpp" 5 | #include "glutil/texture.hpp" 6 | #include "renderer_screen.hpp" 7 | 8 | namespace jkgm { 9 | class render_depthbuffer { 10 | public: 11 | gl::renderbuffer rbo; 12 | 13 | box<2, int> viewport; 14 | 15 | explicit render_depthbuffer(size<2, int> dims); 16 | }; 17 | 18 | class render_buffer { 19 | public: 20 | gl::framebuffer fbo; 21 | gl::texture tex; 22 | 23 | box<2, int> viewport; 24 | 25 | render_buffer(size<2, int> dims, render_depthbuffer *rbo); 26 | }; 27 | 28 | class render_gbuffer { 29 | public: 30 | gl::framebuffer fbo; 31 | gl::texture color_tex; 32 | gl::texture emissive_tex; 33 | gl::texture normal_tex; 34 | gl::texture depth_tex; 35 | 36 | box<2, int> viewport; 37 | 38 | render_gbuffer(size<2, int> dims, render_depthbuffer *rbo); 39 | }; 40 | 41 | class renderer_screen_basic : public renderer_screen { 42 | private: 43 | render_depthbuffer shared_depthbuffer; 44 | render_buffer screen_buffer; 45 | render_gbuffer screen_gbuffer; 46 | 47 | public: 48 | explicit renderer_screen_basic(size<2, int> screen_res); 49 | 50 | void begin_frame() override; 51 | 52 | void begin_opaque_pass() override; 53 | void end_opaque_pass() override; 54 | gl::texture_view get_resolved_color_texture() override; 55 | gl::texture_view get_resolved_emissive_texture() override; 56 | gl::texture_view get_resolved_normal_texture() override; 57 | gl::texture_view get_resolved_depth_texture() override; 58 | 59 | void begin_compose_opaque_pass() override; 60 | void end_compose_opaque_pass() override; 61 | 62 | void begin_transparency_pass() override; 63 | void end_transparency_pass() override; 64 | 65 | void end_frame() override; 66 | 67 | gl::texture_view get_resolved_final_texture() override; 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /renderer/sysmem_texture.cpp: -------------------------------------------------------------------------------- 1 | #include "sysmem_texture.hpp" 2 | #include "base/log.hpp" 3 | #include "common/error_reporter.hpp" 4 | #include "dxguids.hpp" 5 | 6 | jkgm::sysmem_texture::sysmem_texture(sysmem_texture_surface *surf) 7 | : Direct3DTexture_impl("sysmem") 8 | , surf(surf) 9 | { 10 | } 11 | 12 | ULONG WINAPI jkgm::sysmem_texture::AddRef() 13 | { 14 | return surf->AddRef(); 15 | } 16 | 17 | ULONG WINAPI jkgm::sysmem_texture::Release() 18 | { 19 | return surf->Release(); 20 | } 21 | 22 | jkgm::sysmem_texture_surface::sysmem_texture_surface(size_t num_pixels) 23 | : DirectDrawSurface_impl("sysmem texture") 24 | , d3dtexture(this) 25 | , num_pixels(num_pixels) 26 | { 27 | buffer.resize(num_pixels * 2); 28 | conv_buffer.resize(num_pixels, color_rgba8::zero()); 29 | } 30 | 31 | void jkgm::sysmem_texture_surface::set_surface_desc(DDSURFACEDESC const &desc) 32 | { 33 | // Basic sanity checking 34 | if(desc.lpSurface != nullptr) { 35 | report_unimplemented_function( 36 | "DirectDraw::CreateSurface(sysmem texture) with a creation-time buffer"); 37 | } 38 | 39 | if(desc.ddpfPixelFormat.dwRGBBitCount != 16) { 40 | report_unimplemented_function( 41 | "DirectDraw::CreateSurface(sysmem texture) for a non-16 bit texture"); 42 | } 43 | 44 | this->desc = desc; 45 | this->desc.lPitch = desc.dwWidth * (desc.ddpfPixelFormat.dwRGBBitCount / 8); 46 | } 47 | 48 | HRESULT WINAPI jkgm::sysmem_texture_surface::QueryInterface(REFIID riid, LPVOID *ppvObj) 49 | { 50 | if(riid == IID_IDirect3DTexture) { 51 | *ppvObj = &d3dtexture; 52 | AddRef(); 53 | return S_OK; 54 | } 55 | 56 | return DirectDrawSurface_impl::QueryInterface(riid, ppvObj); 57 | } 58 | 59 | ULONG WINAPI jkgm::sysmem_texture_surface::AddRef() 60 | { 61 | return ++refct; 62 | } 63 | 64 | ULONG WINAPI jkgm::sysmem_texture_surface::Release() 65 | { 66 | return --refct; 67 | } 68 | 69 | HRESULT WINAPI jkgm::sysmem_texture_surface::GetSurfaceDesc(LPDDSURFACEDESC a) 70 | { 71 | *a = desc; 72 | return DD_OK; 73 | } 74 | 75 | HRESULT WINAPI jkgm::sysmem_texture_surface::Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) 76 | { 77 | *b = desc; 78 | b->dwFlags = b->dwFlags | DDSD_LPSURFACE; 79 | b->lpSurface = buffer.data(); 80 | return DD_OK; 81 | } 82 | 83 | HRESULT WINAPI jkgm::sysmem_texture_surface::Unlock(LPVOID a) 84 | { 85 | return DD_OK; 86 | } -------------------------------------------------------------------------------- /renderer/sysmem_texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "d3dtexture_impl.hpp" 4 | #include "ddrawsurface_impl.hpp" 5 | #include "math/color.hpp" 6 | #include "renderer.hpp" 7 | #include 8 | 9 | namespace jkgm { 10 | class sysmem_texture_surface; 11 | 12 | class sysmem_texture : public Direct3DTexture_impl { 13 | public: 14 | sysmem_texture_surface *surf; 15 | 16 | explicit sysmem_texture(sysmem_texture_surface *surf); 17 | 18 | ULONG WINAPI AddRef() override; 19 | ULONG WINAPI Release() override; 20 | }; 21 | 22 | class sysmem_texture_surface : public DirectDrawSurface_impl { 23 | private: 24 | sysmem_texture d3dtexture; 25 | 26 | public: 27 | int refct = 0; 28 | size_t num_pixels; 29 | 30 | DDSURFACEDESC desc; 31 | std::vector buffer; 32 | std::vector conv_buffer; 33 | 34 | explicit sysmem_texture_surface(size_t num_pixels); 35 | 36 | void set_surface_desc(DDSURFACEDESC const &desc); 37 | 38 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 39 | ULONG WINAPI AddRef() override; 40 | ULONG WINAPI Release() override; 41 | 42 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 43 | HRESULT WINAPI Lock(LPRECT a, LPDDSURFACEDESC b, DWORD c, HANDLE d) override; 44 | HRESULT WINAPI Unlock(LPVOID a) override; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /renderer/texture_cache.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/filesystem.hpp" 4 | #include "base/md5.hpp" 5 | #include "common/config.hpp" 6 | #include "common/material.hpp" 7 | #include "glutil/texture.hpp" 8 | #include "math/size.hpp" 9 | #include "renderer_fwd.hpp" 10 | #include 11 | #include 12 | 13 | namespace jkgm { 14 | class texture_cache { 15 | public: 16 | virtual ~texture_cache() = default; 17 | 18 | virtual std::optional get_replacement_material(md5 const &sig) = 0; 19 | 20 | virtual srgb_texture_id create_srgb_texture_from_buffer(size<2, int> const &dims, 21 | span data) = 0; 22 | virtual srgb_texture_id get_srgb_texture_from_filename(fs::path const &file) = 0; 23 | virtual linear_texture_id get_linear_texture_from_filename(fs::path const &file) = 0; 24 | 25 | virtual void release_srgb_texture(srgb_texture_id id) = 0; 26 | virtual void release_linear_texture(linear_texture_id id) = 0; 27 | 28 | virtual gl::texture_view get_texture_handle(srgb_texture_id id) const = 0; 29 | virtual gl::texture_view get_texture_handle(linear_texture_id id) const = 0; 30 | }; 31 | 32 | std::unique_ptr create_texture_cache(config const *the_config); 33 | } -------------------------------------------------------------------------------- /renderer/triangle_batch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "math/color.hpp" 4 | #include "math/direction.hpp" 5 | #include "math/point.hpp" 6 | #include "renderer_fwd.hpp" 7 | #include 8 | 9 | namespace jkgm { 10 | struct triangle_vertex { 11 | point<4, float> pos; 12 | point<2, float> texcoords; 13 | jkgm::color color; 14 | 15 | triangle_vertex(); 16 | triangle_vertex(point<4, float> pos, point<2, float> texcoords, jkgm::color color); 17 | }; 18 | 19 | struct triangle { 20 | triangle_vertex v0, v1, v2; 21 | material_instance_id material = material_instance_id(0U); 22 | direction<3, float> normal; 23 | int num_sup = 0; 24 | 25 | triangle(); 26 | triangle(triangle_vertex v0, 27 | triangle_vertex v1, 28 | triangle_vertex v2, 29 | material_instance_id material); 30 | }; 31 | 32 | class triangle_batch { 33 | protected: 34 | std::vector buffer; 35 | size_t num_triangles = 0U; 36 | 37 | void expand(); 38 | 39 | public: 40 | triangle_batch(); 41 | virtual ~triangle_batch() = default; 42 | 43 | size_t size() const; 44 | size_t capacity() const; 45 | void clear(); 46 | void insert(triangle const &tri); 47 | 48 | virtual void sort(); 49 | 50 | inline auto begin() const 51 | { 52 | return buffer.begin(); 53 | } 54 | 55 | inline auto end() const 56 | { 57 | return buffer.begin() + num_triangles; 58 | } 59 | 60 | inline auto begin() 61 | { 62 | return buffer.begin(); 63 | } 64 | 65 | inline auto end() 66 | { 67 | return buffer.begin() + num_triangles; 68 | } 69 | }; 70 | 71 | class sorted_triangle_batch : public triangle_batch { 72 | protected: 73 | std::vector buffer; 74 | size_t num_triangles = 0U; 75 | 76 | public: 77 | void sort() override; 78 | }; 79 | } -------------------------------------------------------------------------------- /renderer/vidmem_texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/material.hpp" 4 | #include "d3dtexture_impl.hpp" 5 | #include "ddrawsurface_impl.hpp" 6 | #include "renderer_fwd.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace jkgm { 12 | class vidmem_texture_surface; 13 | 14 | class vidmem_texture : public Direct3DTexture_impl { 15 | private: 16 | vidmem_texture_surface *surf; 17 | 18 | public: 19 | explicit vidmem_texture(vidmem_texture_surface *surf); 20 | 21 | ULONG WINAPI AddRef() override; 22 | ULONG WINAPI Release() override; 23 | 24 | HRESULT WINAPI GetHandle(LPDIRECT3DDEVICE a, LPD3DTEXTUREHANDLE b) override; 25 | HRESULT WINAPI Load(LPDIRECT3DTEXTURE a) override; 26 | }; 27 | 28 | class vidmem_texture_surface : public DirectDrawSurface_impl { 29 | private: 30 | vidmem_texture d3dtexture; 31 | 32 | public: 33 | renderer *r; 34 | 35 | int refct = 0; 36 | DDSURFACEDESC desc; 37 | 38 | material_instance_id material_id; 39 | 40 | // Vidmem textures embody a material instance: 41 | std::optional albedo_map; 42 | color albedo_factor = color::fill(1.0f); 43 | 44 | std::optional emissive_map; 45 | color_rgb emissive_factor = color_rgb::fill(0.0f); 46 | 47 | std::optional displacement_map; 48 | float displacement_factor = 0.0f; 49 | 50 | material_alpha_mode alpha_mode = material_alpha_mode::blend; 51 | float alpha_cutoff = 0.5f; 52 | 53 | vidmem_texture_surface(renderer *r, material_instance_id material_id); 54 | 55 | void clear(); 56 | void set_surface_desc(DDSURFACEDESC const &desc); 57 | 58 | HRESULT WINAPI QueryInterface(REFIID riid, LPVOID *ppvObj) override; 59 | ULONG WINAPI AddRef() override; 60 | ULONG WINAPI Release() override; 61 | 62 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 63 | }; 64 | } -------------------------------------------------------------------------------- /renderer/zbuffer_surface.cpp: -------------------------------------------------------------------------------- 1 | #include "zbuffer_surface.hpp" 2 | #include "base/log.hpp" 3 | #include "dxguids.hpp" 4 | #include "renderer.hpp" 5 | 6 | jkgm::zbuffer_surface::zbuffer_surface(renderer *r) 7 | : DirectDrawSurface_impl("zbuffer") 8 | , r(r) 9 | { 10 | } 11 | 12 | ULONG WINAPI jkgm::zbuffer_surface::AddRef() 13 | { 14 | // Primary surface is managed by the renderer. Refcount is intentionally not used. 15 | return 1000; 16 | } 17 | 18 | ULONG WINAPI jkgm::zbuffer_surface::Release() 19 | { 20 | // Primary surface is managed by the renderer. Refcount is intentionally not used. 21 | return 1000; 22 | } 23 | 24 | HRESULT WINAPI 25 | jkgm::zbuffer_surface::Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) 26 | { 27 | // This is most likely an old hack used to clear the z-buffer. 28 | r->depth_clear_game(); 29 | return DD_OK; 30 | } 31 | 32 | HRESULT WINAPI jkgm::zbuffer_surface::GetSurfaceDesc(LPDDSURFACEDESC a) 33 | { 34 | *a = sd; 35 | return DD_OK; 36 | } -------------------------------------------------------------------------------- /renderer/zbuffer_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ddrawsurface_impl.hpp" 4 | #include "renderer_fwd.hpp" 5 | #include 6 | 7 | namespace jkgm { 8 | class zbuffer_surface : public DirectDrawSurface_impl { 9 | private: 10 | renderer *r; 11 | 12 | public: 13 | DDSURFACEDESC sd; 14 | 15 | explicit zbuffer_surface(renderer *r); 16 | 17 | ULONG WINAPI AddRef() override; 18 | ULONG WINAPI Release() override; 19 | 20 | HRESULT WINAPI 21 | Blt(LPRECT a, LPDIRECTDRAWSURFACE b, LPRECT c, DWORD d, LPDDBLTFX e) override; 22 | HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC a) override; 23 | }; 24 | } --------------------------------------------------------------------------------