├── Application ├── .gitignore ├── plaform_tools.cpp ├── views │ ├── 3dView │ │ └── view.cpp │ ├── 2dView │ │ └── view.cpp │ └── ModelView │ │ └── view.cpp ├── platform_tools.h ├── sprite_window.h ├── application_ui.h ├── texture_manager.h ├── ui_window.h ├── platform_tools_platforms.cpp ├── application_context.h ├── ui_window.cpp ├── shader_manager.h ├── common_utils.h ├── inspector_window.h ├── common_utils.cpp ├── shader_manager.cpp ├── main_view.h ├── drawing_utils.h ├── model_outliner.h ├── main.cpp └── application_ui.cpp ├── premake-2019.bat ├── resources ├── parrots.png ├── credits.txt ├── Daylight Box UV.png └── shaders │ ├── glsl330 │ ├── cubemap.vs │ ├── skybox.vs │ ├── cubemap.fs │ ├── brdf.vs │ ├── skybox.fs │ ├── pbr.vs │ ├── irradiance.fs │ ├── prefilter.fs │ └── brdf.fs │ └── glsl100 │ ├── cubemap.vs │ ├── skybox.vs │ ├── cubemap.fs │ └── skybox.fs ├── .gitmodules ├── clip ├── CONTRIBUTING.md ├── examples │ ├── CMakeLists.txt │ ├── random.h │ ├── paste.cpp │ ├── helloworld.cpp │ ├── copy.cpp │ ├── put_image.cpp │ ├── int_format.cpp │ └── show_image.cpp ├── tests │ ├── CMakeLists.txt │ ├── test.h │ ├── text_tests.cpp │ ├── image_tests.cpp │ └── user_format_tests.cpp ├── .github │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows │ │ └── build.yml ├── clip_lock_impl.h ├── LICENSE.txt ├── image.cpp ├── clip_none.cpp ├── README.md ├── clip_common.h ├── CMakeLists.txt ├── clip.cpp ├── clip.h ├── clip_x11_png.h ├── clip_win_wic.h └── clip_osx.mm ├── LICENSE ├── README.md ├── premake5.lua └── .gitignore /Application/.gitignore: -------------------------------------------------------------------------------- 1 | /imgui.ini 2 | -------------------------------------------------------------------------------- /premake-2019.bat: -------------------------------------------------------------------------------- 1 | premake5 vs2019 2 | 3 | PAUSE -------------------------------------------------------------------------------- /resources/parrots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffM2501/TestFrame/HEAD/resources/parrots.png -------------------------------------------------------------------------------- /resources/credits.txt: -------------------------------------------------------------------------------- 1 | Daylight Box UV.png CC-BY 3.0 KIIRA https://opengameart.org/content/sky-box-sunny-day -------------------------------------------------------------------------------- /resources/Daylight Box UV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffM2501/TestFrame/HEAD/resources/Daylight Box UV.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "raylib"] 2 | path = raylib 3 | url = https://github.com/raysan5/raylib.git 4 | [submodule "raylibExtras"] 5 | path = raylibExtras 6 | url = https://github.com/JeffM2501/raylibExtras.git 7 | -------------------------------------------------------------------------------- /clip/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | By submitting a pull request, you represent that you have the right to 2 | license your contribution to the Clip project owners and the community, 3 | agree by submitting the patch that your contributions are licensed under 4 | the [Clip license](https://raw.githubusercontent.com/dacap/clip/main/LICENSE.txt), 5 | and agree to future changes to the licensing. 6 | -------------------------------------------------------------------------------- /clip/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Clip Library 2 | # Copyright (C) 2015-2016 David Capello 3 | 4 | function(add_example name) 5 | add_executable(${name} ${name}.cpp) 6 | target_link_libraries(${name} clip) 7 | endfunction() 8 | 9 | add_example(copy) 10 | add_example(helloworld) 11 | add_example(int_format) 12 | add_example(paste) 13 | add_example(put_image) 14 | add_example(show_image) 15 | -------------------------------------------------------------------------------- /clip/examples/random.h: -------------------------------------------------------------------------------- 1 | #include 2 | #pragma once 3 | 4 | class RandomInt { 5 | public: 6 | RandomInt(int a, int b) 7 | : m_mt(m_device()) 8 | , m_dist(a, b) { 9 | } 10 | 11 | int generate() { 12 | return m_dist(m_mt); 13 | } 14 | 15 | private: 16 | std::random_device m_device; 17 | std::mt19937 m_mt; 18 | std::uniform_int_distribution m_dist; 19 | }; 20 | -------------------------------------------------------------------------------- /clip/examples/paste.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015 David Capello 3 | 4 | #include "clip.h" 5 | #include 6 | 7 | int main() { 8 | if (clip::has(clip::text_format())) { 9 | std::string value; 10 | clip::get_text(value); 11 | 12 | std::cout << "Clipboard content is '" << value << "'\n"; 13 | } 14 | else { 15 | std::cout << "Clipboard doesn't contain text\n"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /clip/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Clip Library 2 | # Copyright (C) 2018 David Capello 3 | 4 | function(add_clip_test name) 5 | add_executable(clip_${name} ${name}.cpp) 6 | add_test(NAME clip_${name} COMMAND clip_${name}) 7 | target_link_libraries(clip_${name} clip) 8 | set_tests_properties(clip_${name} PROPERTIES RUN_SERIAL TRUE) 9 | endfunction() 10 | 11 | add_clip_test(text_tests) 12 | add_clip_test(user_format_tests) 13 | add_clip_test(image_tests) 14 | -------------------------------------------------------------------------------- /clip/examples/helloworld.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015 David Capello 3 | 4 | #include "clip.h" 5 | #include 6 | #include 7 | 8 | int main() { 9 | clip::set_text("Hello World"); 10 | 11 | std::string value; 12 | bool result = clip::get_text(value); 13 | 14 | assert(result); 15 | assert(clip::has(clip::text_format())); 16 | assert(value == "Hello World"); 17 | 18 | std::cout << "'" << value << "' was copied to the clipboard\n"; 19 | } 20 | -------------------------------------------------------------------------------- /clip/examples/copy.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2016 David Capello 3 | 4 | #include "clip.h" 5 | #include 6 | 7 | int main(int argc, char* argv[]) { 8 | std::string new_content; 9 | for (int i=1; i 2 | 5 | 7 | 8 | I agree that my contributions are licensed under the Clip license, and agree to future changes to the licensing. 9 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/cubemap.vs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes 4 | in vec3 vertexPosition; 5 | 6 | // Input uniform values 7 | uniform mat4 matProjection; 8 | uniform mat4 matView; 9 | 10 | // Output vertex attributes (to fragment shader) 11 | out vec3 fragPosition; 12 | 13 | void main() 14 | { 15 | // Calculate fragment position based on model transformations 16 | fragPosition = vertexPosition; 17 | 18 | // Calculate final vertex position 19 | gl_Position = matProjection*matView*vec4(vertexPosition, 1.0); 20 | } 21 | -------------------------------------------------------------------------------- /resources/shaders/glsl100/cubemap.vs: -------------------------------------------------------------------------------- 1 | #version 100 2 | 3 | // Input vertex attributes 4 | attribute vec3 vertexPosition; 5 | 6 | // Input uniform values 7 | uniform mat4 matProjection; 8 | uniform mat4 matView; 9 | 10 | // Output vertex attributes (to fragment shader) 11 | varying vec3 fragPosition; 12 | 13 | void main() 14 | { 15 | // Calculate fragment position based on model transformations 16 | fragPosition = vertexPosition; 17 | 18 | // Calculate final vertex position 19 | gl_Position = matProjection*matView*vec4(vertexPosition, 1.0); 20 | } 21 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/skybox.vs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes 4 | in vec3 vertexPosition; 5 | 6 | // Input uniform values 7 | uniform mat4 matProjection; 8 | uniform mat4 matView; 9 | 10 | // Output vertex attributes (to fragment shader) 11 | out vec3 fragPosition; 12 | 13 | void main() 14 | { 15 | // Calculate fragment position based on model transformations 16 | fragPosition = vertexPosition; 17 | 18 | // Remove translation from the view matrix 19 | mat4 rotView = mat4(mat3(matView)); 20 | vec4 clipPos = matProjection*rotView*vec4(vertexPosition, 1.0); 21 | 22 | // Calculate final vertex position 23 | gl_Position = clipPos; 24 | } 25 | -------------------------------------------------------------------------------- /resources/shaders/glsl100/skybox.vs: -------------------------------------------------------------------------------- 1 | #version 100 2 | 3 | // Input vertex attributes 4 | attribute vec3 vertexPosition; 5 | 6 | // Input uniform values 7 | uniform mat4 matProjection; 8 | uniform mat4 matView; 9 | 10 | // Output vertex attributes (to fragment shader) 11 | varying vec3 fragPosition; 12 | 13 | void main() 14 | { 15 | // Calculate fragment position based on model transformations 16 | fragPosition = vertexPosition; 17 | 18 | // Remove translation from the view matrix 19 | mat4 rotView = mat4(mat3(matView)); 20 | vec4 clipPos = matProjection*rotView*vec4(vertexPosition, 1.0); 21 | 22 | // Calculate final vertex position 23 | gl_Position = clipPos; 24 | } 25 | -------------------------------------------------------------------------------- /clip/examples/put_image.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2016 David Capello 3 | 4 | #include "clip.h" 5 | #include 6 | 7 | int main() { 8 | uint32_t data[] = { 9 | 0xffff0000, 0xff00ff00, 0xff0000ff, 10 | 0x7fff0000, 0x7f00ff00, 0x7f0000ff, 11 | }; 12 | clip::image_spec spec; 13 | spec.width = 3; 14 | spec.height = 2; 15 | spec.bits_per_pixel = 32; 16 | spec.bytes_per_row = spec.width*4; 17 | spec.red_mask = 0xff; 18 | spec.green_mask = 0xff00; 19 | spec.blue_mask = 0xff0000; 20 | spec.alpha_mask = 0xff000000; 21 | spec.red_shift = 0; 22 | spec.green_shift = 8; 23 | spec.blue_shift = 16; 24 | spec.alpha_shift = 24; 25 | clip::image img(data, spec); 26 | clip::set_image(img); 27 | } 28 | -------------------------------------------------------------------------------- /resources/shaders/glsl100/cubemap.fs: -------------------------------------------------------------------------------- 1 | #version 100 2 | 3 | precision mediump float; 4 | 5 | // Input vertex attributes (from vertex shader) 6 | varying vec3 fragPosition; 7 | 8 | // Input uniform values 9 | uniform sampler2D equirectangularMap; 10 | 11 | vec2 SampleSphericalMap(vec3 v) 12 | { 13 | vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); 14 | uv *= vec2(0.1591, 0.3183); 15 | uv += 0.5; 16 | return uv; 17 | } 18 | 19 | void main() 20 | { 21 | // Normalize local position 22 | vec2 uv = SampleSphericalMap(normalize(fragPosition)); 23 | 24 | // Fetch color from texture map 25 | vec3 color = texture2D(equirectangularMap, uv).rgb; 26 | 27 | // Calculate final fragment color 28 | gl_FragColor = vec4(color, 1.0); 29 | } 30 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/cubemap.fs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes (from vertex shader) 4 | in vec3 fragPosition; 5 | 6 | // Input uniform values 7 | uniform sampler2D equirectangularMap; 8 | 9 | // Output fragment color 10 | out vec4 finalColor; 11 | 12 | vec2 SampleSphericalMap(vec3 v) 13 | { 14 | vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); 15 | uv *= vec2(0.1591, 0.3183); 16 | uv += 0.5; 17 | return uv; 18 | } 19 | 20 | void main() 21 | { 22 | // Normalize local position 23 | vec2 uv = SampleSphericalMap(normalize(fragPosition)); 24 | 25 | // Fetch color from texture map 26 | vec3 color = texture(equirectangularMap, uv).rgb; 27 | 28 | // Calculate final fragment color 29 | finalColor = vec4(color, 1.0); 30 | } 31 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/brdf.vs: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * rPBR [shader] - Bidirectional reflectance distribution function vertex shader 4 | * 5 | * Copyright (c) 2017 Victor Fisac 6 | * 7 | **********************************************************************************************/ 8 | 9 | #version 330 10 | 11 | // Input vertex attributes 12 | in vec3 vertexPosition; 13 | in vec2 vertexTexCoord; 14 | 15 | // Output vertex attributes (to fragment shader) 16 | out vec2 fragTexCoord; 17 | 18 | void main() 19 | { 20 | // Calculate fragment position based on model transformations 21 | fragTexCoord = vertexTexCoord; 22 | 23 | // Calculate final vertex position 24 | gl_Position = vec4(vertexPosition, 1.0); 25 | } -------------------------------------------------------------------------------- /resources/shaders/glsl330/skybox.fs: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | // Input vertex attributes (from vertex shader) 4 | in vec3 fragPosition; 5 | 6 | // Input uniform values 7 | uniform samplerCube environmentMap; 8 | uniform bool vflipped; 9 | uniform bool doGamma; 10 | 11 | // Output fragment color 12 | out vec4 finalColor; 13 | 14 | void main() 15 | { 16 | // Fetch color from texture map 17 | vec3 color = vec3(0.0); 18 | 19 | if (vflipped) color = texture(environmentMap, vec3(fragPosition.x, -fragPosition.y, fragPosition.z)).rgb; 20 | else color = texture(environmentMap, fragPosition).rgb; 21 | 22 | if (doGamma)// Apply gamma correction 23 | { 24 | color = color/(color + vec3(1.0)); 25 | color = pow(color, vec3(1.0/2.2)); 26 | } 27 | 28 | // Calculate final fragment color 29 | finalColor = vec4(color, 1.0); 30 | } 31 | -------------------------------------------------------------------------------- /clip/tests/test.h: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (C) 2018 David Capello 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | template 10 | inline void expect_eq(const T& expected, const U& value, 11 | const char* file, const int line) { 12 | if (expected != value) { 13 | std::cout << file << ":" << line << ": failed\n" 14 | << " Expected: " << expected << "\n" 15 | << " Actual: " << value << std::endl; 16 | std::abort(); 17 | } 18 | } 19 | 20 | #define EXPECT_EQ(expected, value) \ 21 | expect_eq(expected, value, __FILE__, __LINE__); 22 | 23 | #define EXPECT_TRUE(value) \ 24 | expect_eq(true, value, __FILE__, __LINE__); 25 | 26 | #define EXPECT_FALSE(value) \ 27 | expect_eq(false, value, __FILE__, __LINE__); 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Jeffery Myers. 2 | 3 | This software is provided "as-is", without any express or implied warranty. In no event 4 | will the authors be held liable for any damages arising from the use of this software. 5 | 6 | Permission is granted to anyone to use this software for any purpose, including commercial 7 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 8 | 9 | 1. The origin of this software must not be misrepresented; you must not claim that you 10 | wrote the original software. If you use this software in a product, an acknowledgment 11 | in the product documentation would be appreciated but is not required. 12 | 13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 14 | as being the original software. 15 | 16 | 3. This notice may not be removed or altered from any source distribution. 17 | -------------------------------------------------------------------------------- /clip/clip_lock_impl.h: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #ifndef CLIP_LOCK_IMPL_H_INCLUDED 8 | #define CLIP_LOCK_IMPL_H_INCLUDED 9 | 10 | namespace clip { 11 | 12 | class lock::impl { 13 | public: 14 | impl(void* native_window_handle); 15 | ~impl(); 16 | 17 | bool locked() const { return m_locked; } 18 | bool clear(); 19 | bool is_convertible(format f) const; 20 | bool set_data(format f, const char* buf, size_t len); 21 | bool get_data(format f, char* buf, size_t len) const; 22 | size_t get_data_length(format f) const; 23 | bool set_image(const image& image); 24 | bool get_image(image& image) const; 25 | bool get_image_spec(image_spec& spec) const; 26 | 27 | private: 28 | bool m_locked; 29 | }; 30 | 31 | } // namespace clip 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /resources/shaders/glsl100/skybox.fs: -------------------------------------------------------------------------------- 1 | #version 100 2 | 3 | precision mediump float; 4 | 5 | // Input vertex attributes (from vertex shader) 6 | varying vec3 fragPosition; 7 | 8 | // Input uniform values 9 | uniform samplerCube environmentMap; 10 | uniform bool vflipped; 11 | uniform bool doGamma; 12 | 13 | void main() 14 | { 15 | // Fetch color from texture map 16 | vec4 texelColor = vec4(0.0); 17 | 18 | if (vflipped) texelColor = textureCube(environmentMap, vec3(fragPosition.x, -fragPosition.y, fragPosition.z)); 19 | else texelColor = textureCube(environmentMap, fragPosition); 20 | 21 | vec3 color = vec3(texelColor.x, texelColor.y, texelColor.z); 22 | 23 | if (doGamma)// Apply gamma correction 24 | { 25 | color = color/(color + vec3(1.0)); 26 | color = pow(color, vec3(1.0/2.2)); 27 | } 28 | 29 | // Calculate final fragment color 30 | gl_FragColor = vec4(color, 1.0); 31 | } 32 | -------------------------------------------------------------------------------- /clip/.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | fail-fast: false 8 | matrix: 9 | os: [windows-latest, macos-latest, ubuntu-latest] 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: ilammy/msvc-dev-cmd@v1 13 | if: runner.os == 'Windows' 14 | - name: Generating Makefiles 15 | shell: bash 16 | run: | 17 | if [[ "${{ runner.os }}" == "Windows" ]] ; then 18 | cmake . -G "NMake Makefiles" 19 | else 20 | cmake . -G "Unix Makefiles" 21 | fi 22 | - name: Compiling 23 | shell: bash 24 | run: | 25 | if [[ "${{ runner.os }}" == "Windows" ]] ; then 26 | nmake 27 | else 28 | make 29 | fi 30 | - name: Running Tests 31 | shell: bash 32 | run: | 33 | if [[ "${{ runner.os }}" == "Linux" ]] ; then 34 | export XVFB=xvfb-run 35 | fi 36 | $XVFB ctest --output-on-failure 37 | -------------------------------------------------------------------------------- /clip/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2021 David Capello 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /clip/tests/text_tests.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (C) 2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "test.h" 8 | 9 | #include "clip.h" 10 | 11 | #include 12 | #include 13 | 14 | using namespace clip; 15 | 16 | int main(int argc, char** argv) 17 | { 18 | // High API 19 | { 20 | std::string value; 21 | set_text("hello"); 22 | EXPECT_TRUE(get_text(value)); 23 | EXPECT_EQ("hello", value); 24 | EXPECT_TRUE(has(text_format())); 25 | 26 | set_text("world"); 27 | EXPECT_TRUE(get_text(value)); 28 | EXPECT_EQ("world", value); 29 | 30 | clear(); 31 | EXPECT_FALSE(has(text_format())); 32 | } 33 | 34 | // Lock API 35 | { 36 | lock l; 37 | EXPECT_TRUE(l.locked()); 38 | l.set_data(text_format(), "hello world", 11); 39 | 40 | // get_data_length() must return the extra zero character at the end 41 | EXPECT_EQ(12, l.get_data_length(text_format())); 42 | 43 | // Get the whole data 44 | std::vector buf(12); 45 | EXPECT_TRUE(l.get_data(text_format(), &buf[0], buf.size())); 46 | EXPECT_EQ("hello world", std::string(&buf[0])); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /clip/examples/int_format.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2017 David Capello 3 | 4 | #include "clip.h" 5 | #include "random.h" 6 | #include 7 | #include 8 | 9 | int main() { 10 | clip::format int_format = clip::register_format("com.github.clip.CustomInt"); 11 | 12 | { 13 | clip::lock l; 14 | if (l.is_convertible(int_format)) { 15 | int data = 0; 16 | if (l.get_data(int_format, (char*)&data, sizeof(int))) 17 | std::cout << "Existing custom data in clipboard: " << data << "\n"; 18 | else 19 | std::cout << "Error getting existing custom data from clipboard\n"; 20 | } 21 | else 22 | std::cout << "Clipboard doesn't have custom data\n"; 23 | } 24 | 25 | int newData = RandomInt(0, 9999).generate(); 26 | { 27 | clip::lock l; 28 | l.clear(); 29 | l.set_data(int_format, (const char*)&newData, sizeof(int)); 30 | 31 | std::cout << "Set custom data in clipboard: " << newData << "\n"; 32 | } 33 | 34 | { 35 | clip::lock l; 36 | 37 | int data = 0; 38 | l.get_data(int_format, (char*)&data, sizeof(int)); 39 | 40 | // This could fail if we are running several instances of this 41 | // example at the same time. 42 | assert(data == newData); 43 | 44 | std::cout << "Get custom data in clipboard: " << data << "\n"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/pbr.vs: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * rPBR [shader] - Physically based rendering vertex shader 4 | * 5 | * Copyright (c) 2017 Victor Fisac 6 | * 7 | **********************************************************************************************/ 8 | 9 | #version 330 10 | 11 | // Input vertex attributes 12 | in vec3 vertexPosition; 13 | in vec2 vertexTexCoord; 14 | in vec3 vertexNormal; 15 | in vec4 vertexTangent; 16 | 17 | // Input uniform values 18 | uniform mat4 mvp; 19 | uniform mat4 matModel; 20 | 21 | // Output vertex attributes (to fragment shader) 22 | out vec3 fragPosition; 23 | out vec2 fragTexCoord; 24 | out vec3 fragNormal; 25 | out vec3 fragTangent; 26 | out vec3 fragBinormal; 27 | 28 | void main() 29 | { 30 | // Calculate binormal from vertex normal and tangent 31 | vec3 vertexBinormal = cross(vertexNormal, vec3(vertexTangent)); 32 | 33 | // Calculate fragment normal based on normal transformations 34 | mat3 normalMatrix = transpose(inverse(mat3(matModel))); 35 | 36 | // Calculate fragment position based on model transformations 37 | fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); 38 | 39 | // Send vertex attributes to fragment shader 40 | fragTexCoord = vertexTexCoord; 41 | fragNormal = normalize(normalMatrix*vertexNormal); 42 | fragTangent = normalize(normalMatrix*vec3(vertexTangent)); 43 | fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal); 44 | fragBinormal = normalize(normalMatrix*vertexBinormal); 45 | fragBinormal = cross(fragNormal, fragTangent); 46 | 47 | // Calculate final vertex position 48 | gl_Position = mvp*vec4(vertexPosition, 1.0); 49 | } -------------------------------------------------------------------------------- /Application/plaform_tools.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "platform_tools.h" 3 | 4 | #include "../clip/clip.h" 5 | 6 | std::string OpenFileDialog(const char* filename, std::vector> filterValues); 7 | std::string SaveFileDialog(const char* filename, std::vector> filterValues); 8 | 9 | namespace PlatformTools 10 | { 11 | void CopyImageToClipboard(Image& image) 12 | { 13 | clip::image_spec spec; 14 | spec.width = image.width; 15 | spec.height = image.height; 16 | spec.bits_per_pixel = 32; 17 | spec.bytes_per_row = spec.width * 4; 18 | spec.red_mask = 0xff; 19 | spec.green_mask = 0xff00; 20 | spec.blue_mask = 0xff0000; 21 | spec.alpha_mask = 0xff000000; 22 | spec.red_shift = 0; 23 | spec.green_shift = 8; 24 | spec.blue_shift = 16; 25 | spec.alpha_shift = 24; 26 | clip::image img(image.data, spec); 27 | clip::set_image(img); 28 | } 29 | 30 | std::string ShowOpenFileDialog(const char* filename, std::vector> filterValues) 31 | { 32 | return OpenFileDialog(filename, filterValues); 33 | } 34 | 35 | std::string ShowOpenFileDialog(const char* filename) 36 | { 37 | std::vector> filterValues; 38 | return OpenFileDialog(filename, filterValues); 39 | } 40 | 41 | std::string ShowSaveFileDialog(const char* filename, std::vector> filterValues) 42 | { 43 | return SaveFileDialog(filename, filterValues); 44 | } 45 | 46 | std::string ShowSaveFileDialog(const char* filename) 47 | { 48 | std::vector> filterValues; 49 | return SaveFileDialog(filename, filterValues); 50 | } 51 | } -------------------------------------------------------------------------------- /clip/image.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "clip.h" 8 | 9 | namespace clip { 10 | 11 | image::image() 12 | : m_own_data(false), 13 | m_data(nullptr) 14 | { 15 | } 16 | 17 | image::image(const image_spec& spec) 18 | : m_own_data(true), 19 | m_data(new char[spec.bytes_per_row*spec.height]), 20 | m_spec(spec) { 21 | } 22 | 23 | image::image(const void* data, const image_spec& spec) 24 | : m_own_data(false), 25 | m_data((char*)data), 26 | m_spec(spec) { 27 | } 28 | 29 | image::image(const image& image) 30 | : m_own_data(false), 31 | m_data(nullptr), 32 | m_spec(image.m_spec) { 33 | copy_image(image); 34 | } 35 | 36 | image::image(image&& image) 37 | : m_own_data(false), 38 | m_data(nullptr) { 39 | move_image(std::move(image)); 40 | } 41 | 42 | image::~image() { 43 | reset(); 44 | } 45 | 46 | image& image::operator=(const image& image) { 47 | copy_image(image); 48 | return *this; 49 | } 50 | 51 | image& image::operator=(image&& image) { 52 | move_image(std::move(image)); 53 | return *this; 54 | } 55 | 56 | void image::reset() { 57 | if (m_own_data) { 58 | delete[] m_data; 59 | m_own_data = false; 60 | m_data = nullptr; 61 | } 62 | } 63 | 64 | void image::copy_image(const image& image) { 65 | reset(); 66 | 67 | m_spec = image.spec(); 68 | std::size_t n = m_spec.bytes_per_row*m_spec.height; 69 | 70 | m_own_data = true; 71 | m_data = new char[n]; 72 | std::copy(image.data(), 73 | image.data()+n, 74 | m_data); 75 | } 76 | 77 | void image::move_image(image&& image) { 78 | std::swap(m_own_data, image.m_own_data); 79 | std::swap(m_data, image.m_data); 80 | std::swap(m_spec, image.m_spec); 81 | } 82 | 83 | } // namespace clip 84 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/irradiance.fs: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * rPBR [shader] - Irradiance cubemap fragment shader 4 | * 5 | * Copyright (c) 2017 Victor Fisac 6 | * 7 | **********************************************************************************************/ 8 | 9 | #version 330 10 | 11 | // Input vertex attributes (from vertex shader) 12 | in vec3 fragPosition; 13 | 14 | // Input uniform values 15 | uniform samplerCube environmentMap; 16 | 17 | // Constant values 18 | const float PI = 3.14159265359; 19 | 20 | // Output fragment color 21 | out vec4 finalColor; 22 | 23 | void main() 24 | { 25 | // The sample direction equals the hemisphere's orientation 26 | vec3 normal = normalize(fragPosition); 27 | 28 | vec3 irradiance = vec3(0.0); 29 | 30 | vec3 up = vec3(0.0, 1.0, 0.0); 31 | vec3 right = cross(up, normal); 32 | up = cross(normal, right); 33 | 34 | float sampleDelta = 0.025; 35 | float nrSamples = 0.0; 36 | 37 | for (float phi = 0.0; phi < 2.0*PI; phi += sampleDelta) 38 | { 39 | for (float theta = 0.0; theta < 0.5*PI; theta += sampleDelta) 40 | { 41 | // Spherical to cartesian (in tangent space) 42 | vec3 tangentSample = vec3(sin(theta)*cos(phi), sin(theta)*sin(phi), cos(theta)); 43 | 44 | // tangent space to world 45 | vec3 sampleVec = tangentSample.x*right + tangentSample.y*up + tangentSample.z*normal; 46 | 47 | // Fetch color from environment cubemap 48 | irradiance += texture(environmentMap, sampleVec).rgb*cos(theta)*sin(theta); 49 | nrSamples++; 50 | } 51 | } 52 | 53 | // Calculate irradiance average value from samples 54 | irradiance = PI*irradiance*(1.0/float(nrSamples)); 55 | 56 | // Calculate final fragment color 57 | finalColor = vec4(irradiance, 1.0); 58 | } 59 | -------------------------------------------------------------------------------- /clip/clip_none.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "clip.h" 8 | #include "clip_lock_impl.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace clip { 15 | 16 | typedef std::vector Buffer; 17 | typedef std::map Map; 18 | 19 | static format g_last_format = 100; // TODO create an enum with common formats 20 | static Map g_data; 21 | 22 | lock::impl::impl(void* native_handle) : m_locked(true) { 23 | } 24 | 25 | lock::impl::~impl() { 26 | } 27 | 28 | bool lock::impl::clear() { 29 | g_data.clear(); 30 | return true; 31 | } 32 | 33 | bool lock::impl::is_convertible(format f) const { 34 | return (g_data.find(f) != g_data.end()); 35 | } 36 | 37 | bool lock::impl::set_data(format f, const char* buf, size_t len) { 38 | Buffer& dst = g_data[f]; 39 | 40 | dst.resize(len); 41 | if (buf && len > 0) 42 | std::copy(buf, buf+len, dst.begin()); 43 | 44 | return true; 45 | } 46 | 47 | bool lock::impl::get_data(format f, char* buf, size_t len) const { 48 | assert(buf); 49 | 50 | if (!buf || !is_convertible(f)) 51 | return false; 52 | 53 | const Buffer& src = g_data[f]; 54 | std::copy(src.begin(), src.end(), buf); 55 | return true; 56 | } 57 | 58 | size_t lock::impl::get_data_length(format f) const { 59 | if (is_convertible(f)) 60 | return g_data[f].size(); 61 | else 62 | return 0; 63 | } 64 | 65 | bool lock::impl::set_image(const image& image) { 66 | return false; // TODO 67 | } 68 | 69 | bool lock::impl::get_image(image& image) const { 70 | return false; // TODO 71 | } 72 | 73 | bool lock::impl::get_image_spec(image_spec& spec) const { 74 | return false; // TODO 75 | } 76 | 77 | format register_format(const std::string& name) { 78 | return g_last_format++; 79 | } 80 | 81 | } // namespace clip 82 | -------------------------------------------------------------------------------- /clip/README.md: -------------------------------------------------------------------------------- 1 | # Clip Library 2 | *Copyright (c) 2015-2021 David Capello* 3 | 4 | [![build](https://github.com/dacap/clip/workflows/build/badge.svg)](https://github.com/dacap/clip/actions?query=workflow%3Abuild) 5 | [![MIT Licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt) 6 | 7 | Library to copy/retrieve content to/from the clipboard/pasteboard. 8 | 9 | ## Features 10 | 11 | Available features on Windows, macOS, and Linux (X11): 12 | 13 | * Copy/paste UTF-8 text. 14 | * Copy/paste user-defined data. 15 | * Copy/paste RGB/RGBA images. This library use non-premultiplied alpha RGB values. 16 | 17 | ## Example 18 | 19 | ```cpp 20 | #include "clip.h" 21 | #include 22 | 23 | int main() { 24 | clip::set_text("Hello World"); 25 | 26 | std::string value; 27 | clip::get_text(value); 28 | std::cout << value << "\n"; 29 | } 30 | ``` 31 | 32 | ## User-defined clipboard formats 33 | 34 | ```cpp 35 | #include "clip.h" 36 | 37 | int main() { 38 | clip::format my_format = 39 | clip::register_format("com.appname.FormatName"); 40 | 41 | int value = 32; 42 | 43 | clip::lock l; 44 | l.clear(); 45 | l.set_data(clip::text_format(), "Alternative text for value 32"); 46 | l.set_data(my_format, &value, sizeof(int)); 47 | } 48 | ``` 49 | 50 | ## Platform specific details 51 | 52 | * If two versions of your application (32-bit and 64-bit) can run at 53 | at the same time, remember to avoid storing data types that could 54 | change depending on the platform (e.g. `size_t`) in your custom 55 | format data. 56 | * **Windows**: 57 | - [Limited number of clipboard formats on Windows](http://blogs.msdn.com/b/oldnewthing/archive/2015/03/19/10601208.aspx) 58 | * **Linux**: 59 | - To be able to copy/paste on Linux you need `libx11-dev`/`libX11-devel` package. 60 | - To copy/paste images you will need `libpng-dev`/`libpng-devel` package. 61 | 62 | ## Who is using this library? 63 | 64 | [Check the wiki](https://github.com/dacap/clip/wiki#who-is-using-clip) 65 | to know what projects are using the `clip` library. 66 | -------------------------------------------------------------------------------- /clip/tests/image_tests.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (C) 2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "test.h" 8 | 9 | #include "clip.h" 10 | 11 | #include 12 | 13 | using namespace clip; 14 | 15 | int main(int argc, char** argv) 16 | { 17 | clear(); 18 | EXPECT_FALSE(has(image_format())); 19 | 20 | uint32_t data[] = { 21 | 0xffff0000, 0xff00ff00, 0xff0000ff, 22 | 0x7fff0000, 0x7f00ff00, 0x7f0000ff, 23 | }; 24 | { 25 | image_spec spec; 26 | spec.width = 3; 27 | spec.height = 2; 28 | spec.bits_per_pixel = 32; 29 | spec.bytes_per_row = spec.width*4; 30 | spec.red_mask = 0xff; 31 | spec.green_mask = 0xff00; 32 | spec.blue_mask = 0xff0000; 33 | spec.alpha_mask = 0xff000000; 34 | spec.red_shift = 0; 35 | spec.green_shift = 8; 36 | spec.blue_shift = 16; 37 | spec.alpha_shift = 24; 38 | image img(data, spec); 39 | EXPECT_TRUE(set_image(img)); 40 | } 41 | EXPECT_TRUE(has(image_format())); 42 | 43 | { 44 | image_spec spec; 45 | EXPECT_TRUE(get_image_spec(spec)); 46 | EXPECT_EQ(3, spec.width); 47 | EXPECT_EQ(2, spec.height); 48 | EXPECT_EQ(32, spec.bits_per_pixel); 49 | EXPECT_EQ(spec.width*4, spec.bytes_per_row); 50 | } 51 | 52 | { 53 | image img; 54 | EXPECT_TRUE(get_image(img)); 55 | EXPECT_EQ(3, img.spec().width); 56 | EXPECT_EQ(2, img.spec().height); 57 | 58 | image_spec spec = img.spec(); 59 | auto data2 = (const uint32_t*)img.data(); 60 | for (int i=0; i<6; ++i) { 61 | uint32_t c = data2[i]; 62 | c = 63 | (( c & spec.red_mask ) >> spec.red_shift ) | 64 | (((c & spec.green_mask) >> spec.green_shift) << 8) | 65 | (((c & spec.blue_mask ) >> spec.blue_shift ) << 16) | 66 | (((c & spec.alpha_mask) >> spec.alpha_shift) << 24); 67 | EXPECT_EQ(data[i], c); 68 | } 69 | } 70 | 71 | clear(); 72 | EXPECT_FALSE(has(image_format())); 73 | } 74 | -------------------------------------------------------------------------------- /Application/views/3dView/view.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "application_context.h" 32 | #include "main_view.h" 33 | #include "drawing_utils.h" 34 | 35 | #include "RaylibColors.h" 36 | 37 | #include "raylib.h" 38 | #include "rlgl.h" 39 | #include "raymath.h" 40 | 41 | class SceneView : public ThreeDView 42 | { 43 | protected: 44 | 45 | public: 46 | inline const char* GetName() override { return "3D View"; } 47 | 48 | void OnSetup() override 49 | { 50 | 51 | } 52 | 53 | void OnShutdown() override 54 | { 55 | 56 | } 57 | 58 | void OnShow(const Rectangle& contentArea) override 59 | { 60 | DrawCube(Vector3{ 0,1,0 }, 1, 1, 1, Colors::DarkGreen); 61 | } 62 | 63 | }; 64 | 65 | REGISTER_VIEW(SceneView); 66 | -------------------------------------------------------------------------------- /Application/platform_tools.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "raylib.h" 34 | #include 35 | #include 36 | 37 | namespace PlatformTools 38 | { 39 | enum class ClipboardFormats 40 | { 41 | Text, 42 | PNG, 43 | }; 44 | 45 | void CopyImageToClipboard(Image& image); 46 | 47 | std::string ShowOpenFileDialog(const char* filename, std::vector> filterValues); 48 | std::string ShowOpenFileDialog(const char* filename); 49 | 50 | std::string ShowSaveFileDialog(const char* filename, std::vector> filterValues); 51 | std::string ShowSaveFileDialog(const char* filename); 52 | 53 | void SetWindowHandle(void* handle); 54 | } -------------------------------------------------------------------------------- /clip/tests/user_format_tests.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (C) 2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "test.h" 8 | 9 | #include "clip.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace clip; 16 | 17 | int main(int argc, char** argv) 18 | { 19 | format intF = register_format("com.github.clip.int"); 20 | format doubleF = register_format("com.github.clip.double"); 21 | EXPECT_TRUE(intF != empty_format()); 22 | EXPECT_TRUE(doubleF != empty_format()); 23 | 24 | // Clear clipboard content 25 | { 26 | clear(); 27 | EXPECT_FALSE(has(text_format())); 28 | EXPECT_FALSE(has(intF)); 29 | EXPECT_FALSE(has(doubleF)); 30 | } 31 | 32 | // Set int and double formats 33 | { 34 | lock l; 35 | int intV = 32; 36 | double doubleV = 32.48; 37 | EXPECT_TRUE(l.set_data(intF, (const char*)&intV, sizeof(int))); 38 | EXPECT_TRUE(l.set_data(doubleF, (const char*)&doubleV, sizeof(double))); 39 | } 40 | EXPECT_FALSE(has(text_format())); 41 | EXPECT_TRUE(has(intF)); 42 | EXPECT_TRUE(has(doubleF)); 43 | 44 | // Get int and double formats 45 | { 46 | lock l; 47 | int intV = 0; 48 | double doubleV = 0.0; 49 | EXPECT_TRUE(l.get_data(intF, (char*)&intV, sizeof(int))); 50 | EXPECT_TRUE(l.get_data(doubleF, (char*)&doubleV, sizeof(double))); 51 | EXPECT_EQ(32, intV); 52 | EXPECT_EQ(32.48, doubleV); 53 | } 54 | 55 | // Add text to clipboard 56 | { 57 | lock l; 58 | EXPECT_TRUE(l.set_data(text_format(), (const char*)"thirty-two", 10)); 59 | } 60 | EXPECT_TRUE(has(text_format())); 61 | EXPECT_TRUE(has(intF)); 62 | EXPECT_TRUE(has(doubleF)); 63 | 64 | // Get all formats 65 | { 66 | lock l; 67 | int intV = 0; 68 | double doubleV = 0.0; 69 | char buf[11]; 70 | EXPECT_EQ(11, l.get_data_length(text_format())); 71 | EXPECT_TRUE(l.get_data(text_format(), (char*)buf, 11)); 72 | EXPECT_TRUE(l.get_data(intF, (char*)&intV, sizeof(int))); 73 | EXPECT_TRUE(l.get_data(doubleF, (char*)&doubleV, sizeof(double))); 74 | EXPECT_EQ("thirty-two", std::string(buf)); 75 | EXPECT_EQ(32, intV); 76 | EXPECT_EQ(32.48, doubleV); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Application/sprite_window.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "ui_window.h" 34 | 35 | #include "raylib.h" 36 | 37 | class SpriteWindow : public UIWindow 38 | { 39 | public: 40 | SpriteWindow() : UIWindow() 41 | { 42 | Shown = false; 43 | Name = "2D Window"; 44 | } 45 | 46 | void OnShow(MainView* view) override 47 | { 48 | Vector2 mouse = GetMousePosition(); 49 | ImGui::Text("Mouse X%.0f Y%.0f", mouse.x, mouse.y); 50 | 51 | Vector3 camPos = view->Camera.GetCameraPosition(); 52 | ImGui::TextUnformatted("Camera"); 53 | ImGui::Text("X % .2f Y % .2f Z % .2f", camPos.x, camPos.y, camPos.z); 54 | Vector2 camAngles = view->Camera.GetViewAngles(); 55 | ImGui::Text("Yaw%.2f Pitch%.2f", camAngles.y, camAngles.x); 56 | } 57 | }; -------------------------------------------------------------------------------- /Application/views/2dView/view.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "application_context.h" 32 | #include "inspector_window.h" 33 | #include "main_view.h" 34 | #include "drawing_utils.h" 35 | 36 | class SpriteView : public TwoDView 37 | { 38 | protected: 39 | Texture Tx; 40 | public: 41 | inline const char* GetName() override { return "2D View"; } 42 | 43 | void OnSetup() override 44 | { 45 | Tx = LoadTexture("parrots.png"); 46 | } 47 | 48 | void OnShutdown() override 49 | { 50 | UnloadTexture(Tx); 51 | } 52 | 53 | void OnShow(const Rectangle& contentArea) override 54 | { 55 | DrawTexture(Tx, Tx.width / -2, Tx.height / -2, Colors::White); 56 | } 57 | 58 | void OnShowInspector(const InspectorWindow& window) override 59 | { 60 | ImGui::TextUnformatted("Texture"); 61 | Inspectors::ShowTextureInspector(Tx); 62 | Inspectors::ShowSetTextureFilter(Tx); 63 | } 64 | }; 65 | 66 | REGISTER_VIEW(SpriteView); -------------------------------------------------------------------------------- /Application/application_ui.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "raylib.h" 34 | #include "imgui.h" 35 | 36 | #include 37 | #include 38 | 39 | class UIWindow; 40 | class MainView; 41 | 42 | class UIManager 43 | { 44 | public: 45 | void Startup(); 46 | void Shutdown(); 47 | void Update(); 48 | void Show(MainView* view = nullptr); 49 | void Resized(); 50 | 51 | inline const Rectangle& GetContentArea() { return ContentArea; } 52 | 53 | void AddWindow(std::shared_ptr window); 54 | void RemoveWindow(std::shared_ptr window); 55 | 56 | protected: 57 | void SetupUI(); 58 | void ShowMenu(); 59 | 60 | protected: 61 | ImGuiID DockspaceId; 62 | 63 | bool LogWindowOpen = true; 64 | 65 | std::vector> Windows; 66 | 67 | private: 68 | bool ShowStyleEditor = false; 69 | bool ShowDemoWindow = false; 70 | bool ShowMetricsWindow = false; 71 | bool ShowAboutImGuiWindow = false; 72 | bool ShowAboutWindow = false; 73 | 74 | Rectangle ContentArea = { 0 }; 75 | 76 | private: 77 | void ShowDebugWindows(); 78 | }; -------------------------------------------------------------------------------- /Application/texture_manager.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | #include "raylib.h" 33 | 34 | #include 35 | 36 | class TextureInstance 37 | { 38 | public: 39 | size_t RefCount = 0; 40 | Texture2D Tx; 41 | }; 42 | 43 | class TextureManager 44 | { 45 | public: 46 | std::map TextureCache; 47 | 48 | void AddTexture(Texture tx) 49 | { 50 | if (TextureCache.find(tx.id) != TextureCache.end()) 51 | TextureCache[tx.id] = TextureInstance{ 0,tx }; 52 | 53 | TextureCache[tx.id].RefCount++; 54 | } 55 | 56 | void RemoveTexture(Texture tx) 57 | { 58 | std::map::iterator itr = TextureCache.find(tx.id); 59 | if (itr == TextureCache.end()) 60 | return; 61 | 62 | itr->second.RefCount--; 63 | if (itr->second.RefCount <= 0) 64 | { 65 | UnloadTexture(itr->second.Tx); 66 | TextureCache.erase(itr); 67 | } 68 | } 69 | 70 | void Clear() 71 | { 72 | for (auto& tx : TextureCache) 73 | UnloadTexture(tx.second.Tx); 74 | 75 | TextureCache.clear(); 76 | } 77 | }; 78 | 79 | -------------------------------------------------------------------------------- /clip/clip_common.h: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (C) 2020 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #ifndef CLIP_COMMON_H_INCLUDED 8 | #define CLIP_COMMON_H_INCLUDED 9 | #pragma once 10 | 11 | namespace clip { 12 | namespace details { 13 | 14 | inline void divide_rgb_by_alpha(image& img, 15 | bool hasAlphaGreaterThanZero = false) { 16 | const image_spec& spec = img.spec(); 17 | 18 | bool hasValidPremultipliedAlpha = true; 19 | 20 | for (unsigned long y=0; y> spec.red_shift ); 25 | const int g = ((c & spec.green_mask) >> spec.green_shift); 26 | const int b = ((c & spec.blue_mask ) >> spec.blue_shift ); 27 | const int a = ((c & spec.alpha_mask) >> spec.alpha_shift); 28 | 29 | if (a > 0) 30 | hasAlphaGreaterThanZero = true; 31 | if (r > a || g > a || b > a) 32 | hasValidPremultipliedAlpha = false; 33 | } 34 | } 35 | 36 | for (unsigned long y=0; y> spec.red_shift ); 41 | int g = ((c & spec.green_mask) >> spec.green_shift); 42 | int b = ((c & spec.blue_mask ) >> spec.blue_shift ); 43 | int a = ((c & spec.alpha_mask) >> spec.alpha_shift); 44 | 45 | // If all alpha values = 0, we make the image opaque. 46 | if (!hasAlphaGreaterThanZero) { 47 | a = 255; 48 | 49 | // We cannot change the image spec (e.g. spec.alpha_mask=0) to 50 | // make the image opaque, because the "spec" of the image is 51 | // read-only. The image spec used by the client is the one 52 | // returned by get_image_spec(). 53 | } 54 | // If there is alpha information and it's pre-multiplied alpha 55 | else if (hasValidPremultipliedAlpha) { 56 | if (a > 0) { 57 | // Convert it to straight alpha 58 | r = r * 255 / a; 59 | g = g * 255 / a; 60 | b = b * 255 / a; 61 | } 62 | } 63 | 64 | *dst = 65 | (r << spec.red_shift ) | 66 | (g << spec.green_shift) | 67 | (b << spec.blue_shift ) | 68 | (a << spec.alpha_shift); 69 | } 70 | } 71 | } 72 | 73 | } // namespace details 74 | } // namespace clip 75 | 76 | #endif // CLIP_H_INCLUDED 77 | -------------------------------------------------------------------------------- /Application/ui_window.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #include "application_context.h" 38 | #include "main_view.h" 39 | 40 | class UIWindow 41 | { 42 | public: 43 | UIWindow() {} 44 | virtual ~UIWindow(){} 45 | 46 | bool Shown = false; 47 | inline virtual void GetName(std::string& name, MainView* view) const { name = "BaseWindow"; } 48 | inline virtual const char* GetMenuName() const { return "Base"; } 49 | 50 | void Show(MainView* view = nullptr); 51 | 52 | virtual void Update(); 53 | virtual void Resize(); 54 | 55 | virtual void Shutdown() {} 56 | 57 | protected: 58 | virtual void OnShow(MainView* view) {} 59 | std::string Name; 60 | }; 61 | 62 | constexpr char LogWindowName[] = "Log###RaylibLogWindow"; 63 | 64 | class LogWindow : public UIWindow 65 | { 66 | public: 67 | LogWindow(); 68 | inline void GetName(std::string& name, MainView* view) const override { name = LogWindowName; } 69 | inline const char* GetMenuName() const override { return "Log"; } 70 | void OnShow(MainView* view) override; 71 | 72 | private: 73 | std::deque LogLines; 74 | 75 | int ShowLevel = 0; 76 | 77 | char FilterText[512] = { 0 }; 78 | }; -------------------------------------------------------------------------------- /clip/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Clip Library 2 | # Copyright (c) 2015-2020 David Capello 3 | 4 | cmake_minimum_required(VERSION 3.1.2) 5 | 6 | project(clip) 7 | 8 | set(CMAKE_CXX_STANDARD 11) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 12 | # Use libc++ explicitly so we can compile for 13 | # CMAKE_OSX_DEPLOYMENT_TARGET=10.7 or 10.8 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 15 | endif() 16 | 17 | option(CLIP_EXAMPLES "Compile clip examples" on) 18 | option(CLIP_TESTS "Compile clip tests" on) 19 | if(UNIX AND NOT APPLE) 20 | option(CLIP_X11_WITH_PNG "Compile with libpng to support copy/paste image in png format" on) 21 | endif() 22 | 23 | include_directories(.) 24 | set(CLIP_SOURCES clip.cpp image.cpp) 25 | 26 | if(WIN32) 27 | add_definitions(-D_SCL_SECURE_NO_WARNINGS) 28 | list(APPEND CLIP_SOURCES clip_win.cpp) 29 | elseif(APPLE) 30 | add_definitions(-fobjc-arc) 31 | 32 | find_library(COCOA_LIBRARY Cocoa) 33 | if(COCOA_LIBRARY) 34 | list(APPEND CLIP_SOURCES clip_osx.mm) 35 | else() 36 | list(APPEND CLIP_SOURCES clip_none.cpp) 37 | endif() 38 | elseif(UNIX) 39 | include(CheckIncludeFiles) 40 | check_include_files(xcb/xcb.h HAVE_XCB_XLIB_H) 41 | 42 | if(HAVE_XCB_XLIB_H) 43 | add_definitions(-DHAVE_XCB_XLIB_H) 44 | 45 | if(CLIP_X11_WITH_PNG) 46 | check_include_files(png.h HAVE_PNG_H) 47 | if(CLIP_X11_PNG_LIBRARY) 48 | set(PNG_LIBRARY ${CLIP_X11_PNG_LIBRARY}) 49 | else() 50 | find_library(PNG_LIBRARY png) 51 | endif() 52 | if(HAVE_PNG_H AND PNG_LIBRARY) 53 | add_definitions(-DHAVE_PNG_H) 54 | endif() 55 | endif() 56 | 57 | list(APPEND CLIP_SOURCES clip_x11.cpp) 58 | else() 59 | list(APPEND CLIP_SOURCES clip_none.cpp) 60 | endif() 61 | else() 62 | list(APPEND CLIP_SOURCES clip_none.cpp) 63 | endif() 64 | 65 | add_library(clip ${CLIP_SOURCES}) 66 | 67 | if(WIN32) 68 | target_link_libraries(clip shlwapi) 69 | 70 | # MinGW requires the windowscodecs just because CLSIDs are defined 71 | # in the windowscodecs.a file instead of the wincodec.h file (?!) 72 | if(MINGW) 73 | find_library(CLIP_WINDOWSCODECS_LIBRARY windowscodecs) 74 | if(CLIP_WINDOWSCODECS_LIBRARY) 75 | target_link_libraries(clip ${CLIP_WINDOWSCODECS_LIBRARY}) 76 | endif() 77 | endif() 78 | elseif(APPLE) 79 | if(COCOA_LIBRARY) 80 | target_link_libraries(clip ${COCOA_LIBRARY}) 81 | endif() 82 | elseif(UNIX) 83 | if(HAVE_XCB_XLIB_H) 84 | target_link_libraries(clip xcb pthread) 85 | if(CLIP_X11_WITH_PNG AND HAVE_PNG_H AND PNG_LIBRARY) 86 | target_link_libraries(clip ${PNG_LIBRARY}) 87 | endif() 88 | endif() 89 | endif() 90 | 91 | if(CLIP_EXAMPLES) 92 | add_subdirectory(examples) 93 | endif() 94 | 95 | if(CLIP_TESTS) 96 | enable_testing() 97 | add_subdirectory(tests) 98 | endif() 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raylib/ImGui TestFrame 2 | This is a test framework that uses Raylib and ImGui together to help test and develop concepts. 3 | It is made using C++ because it uses classes for windows and views. 4 | 5 | The idea is you add code to places in the test frame to get something showing quickly with access to common features such as resources, cameras, and other tools. 6 | 7 | ![image](https://user-images.githubusercontent.com/322174/120928519-d02f7880-c699-11eb-9bb7-5a47564ca80d.png) 8 | 9 | ## Building 10 | 11 | 1. Make sure you have the submodules 12 | 2. Make sure that you have ImGui in raylibExtras/imgui 13 | 1. Be sure to use the docking branch of ImGui 14 | 2. Download from https://github.com/ocornut/imgui/tree/docking 15 | 3. Get the premake5 for your platform 16 | 1. Download https://premake.github.io/download 17 | 2. Don't get Premake4 18 | 5. Run premake 19 | 1. Batch file for visual studio 2019 is included 20 | 2. Other targets will need the command line (premake5 gmake) 21 | 6. Build 22 | 23 | 24 | # What this does 25 | The testframe has two main concepts Views and Windows. Each exist to display data and work with each other. 26 | 27 | # Views 28 | Views are shown in the background window in the area that is not covered by docked windows. There is only ever one view up at a time. Each View uses a render texture so you can draw to it as if it was a little screen. A rectangle is passed to the view for the vissible area. Views are based on the MainView class and have an OnShow virtual method where you can put drawing code. You can have as many view types as you want and setup the View menu to swap between them. 29 | 30 | ## SceneView 31 | This is the default view and is 3d. It sets up a first person camera, skybox and ground grid by default. 32 | 33 | ## SpriteView 34 | This is a 2d View used for sprite-like drawing. 35 | 36 | # Windows 37 | Windows are ImGui windows that are docked around the view. They are used to display information about the view. They are based on the UIWindow base class and have a virtual OnShow method that is passed the view. You can use this to get data from the view and display it. There are two default Windows, but you can add as many as you want. The Window menu will display the status of all known windows. 38 | 39 | ## LogWindow 40 | This shows the raylib log output. Has filters for type and by text to search for specific issues in the log. 41 | 42 | ## Inspector 43 | This shows data from the view. It is meant to be extended with more info. 44 | 45 | # Other services 46 | Testframe is setup with RLAssets, FPCamera, TPCamera and other items from RaylibExtras. There are also several utilities to help with drawing in draw_utils.h 47 | 48 | # Tools 49 | The tools menu has several things to help debug ImGui. 50 | 51 | ## Item Picker 52 | This will start an ImGui Item Picker, the next gui element you click on will trigger a breakpoint in the debugger so you can see where in the callstack the code that makes the GUI is. 53 | 54 | ## Style Editor 55 | This is a realtime style editor 56 | 57 | ## Metrics 58 | This shows debug info about ImGui 59 | 60 | ## Demo 61 | This is the ImGui Demo window 62 | 63 | ## About 64 | The ImGui version 65 | -------------------------------------------------------------------------------- /clip/examples/show_image.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2016 David Capello 3 | 4 | #include "clip.h" 5 | #include 6 | #include 7 | 8 | template 9 | static void print_channel(const clip::image& img, 10 | const clip::image_spec& spec, 11 | const std::string& channel_name, 12 | const int channel_mask, 13 | const int channel_shift, 14 | const int channel_fill_width, 15 | const int pixel_size) { 16 | std::cout << channel_name << ":\n"; 17 | for (unsigned long y=0; y> channel_shift) << " "; 25 | } 26 | std::cout << "\n"; 27 | } 28 | } 29 | 30 | template 31 | static void print_channels(const clip::image& img, 32 | const clip::image_spec& spec, 33 | const int channel_fill_width, 34 | int pixel_size = sizeof(T)) { 35 | print_channel(img, spec, "Red", spec.red_mask, spec.red_shift, channel_fill_width, pixel_size); 36 | print_channel(img, spec, "Green", spec.green_mask, spec.green_shift, channel_fill_width, pixel_size); 37 | print_channel(img, spec, "Blue", spec.blue_mask, spec.blue_shift, channel_fill_width, pixel_size); 38 | if (spec.alpha_mask) 39 | print_channel(img, spec, "Alpha", spec.alpha_mask, spec.alpha_shift, channel_fill_width, pixel_size); 40 | } 41 | 42 | int main() { 43 | if (!clip::has(clip::image_format())) { 44 | std::cout << "Clipboard doesn't contain an image\n"; 45 | return 1; 46 | } 47 | 48 | clip::image img; 49 | if (!clip::get_image(img)) { 50 | std::cout << "Error getting image from clipboard\n"; 51 | return 1; 52 | } 53 | 54 | clip::image_spec spec = img.spec(); 55 | 56 | std::cout << "Image in clipboard " 57 | << spec.width << "x" << spec.height 58 | << " (" << spec.bits_per_pixel << "bpp)\n" 59 | << "Format:" << "\n" 60 | << std::hex 61 | << " Red mask: " << spec.red_mask << "\n" 62 | << " Green mask: " << spec.green_mask << "\n" 63 | << " Blue mask: " << spec.blue_mask << "\n" 64 | << " Alpha mask: " << spec.alpha_mask << "\n" 65 | << std::dec 66 | << " Red shift: " << spec.red_shift << "\n" 67 | << " Green shift: " << spec.green_shift << "\n" 68 | << " Blue shift: " << spec.blue_shift << "\n" 69 | << " Alpha shift: " << spec.alpha_shift << "\n"; 70 | 71 | std::cout << "Bytes:\n"; 72 | for (unsigned long y=0; y(img, spec, 2); break; 84 | case 24: print_channels(img, spec, 2, 3); break; 85 | case 32: print_channels(img, spec, 2); break; 86 | case 64: print_channels(img, spec, 4); break; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /clip/clip.cpp: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "clip.h" 8 | #include "clip_lock_impl.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace clip { 14 | 15 | namespace { 16 | 17 | void default_error_handler(ErrorCode code) { 18 | static const char* err[] = { 19 | "Cannot lock clipboard", 20 | "Image format is not supported" 21 | }; 22 | throw std::runtime_error(err[static_cast(code)]); 23 | } 24 | 25 | } // anonymous namespace 26 | 27 | error_handler g_error_handler = default_error_handler; 28 | 29 | lock::lock(void* native_window_handle) 30 | : p(new impl(native_window_handle)) { 31 | } 32 | 33 | lock::~lock() = default; 34 | 35 | bool lock::locked() const { 36 | return p->locked(); 37 | } 38 | 39 | bool lock::clear() { 40 | return p->clear(); 41 | } 42 | 43 | bool lock::is_convertible(format f) const { 44 | return p->is_convertible(f); 45 | } 46 | 47 | bool lock::set_data(format f, const char* buf, size_t length) { 48 | return p->set_data(f, buf, length); 49 | } 50 | 51 | bool lock::get_data(format f, char* buf, size_t len) const { 52 | return p->get_data(f, buf, len); 53 | } 54 | 55 | size_t lock::get_data_length(format f) const { 56 | return p->get_data_length(f); 57 | } 58 | 59 | bool lock::set_image(const image& img) { 60 | return p->set_image(img); 61 | } 62 | 63 | bool lock::get_image(image& img) const { 64 | return p->get_image(img); 65 | } 66 | 67 | bool lock::get_image_spec(image_spec& spec) const { 68 | return p->get_image_spec(spec); 69 | } 70 | 71 | format empty_format() { return 0; } 72 | format text_format() { return 1; } 73 | format image_format() { return 2; } 74 | 75 | bool has(format f) { 76 | lock l; 77 | if (l.locked()) 78 | return l.is_convertible(f); 79 | else 80 | return false; 81 | } 82 | 83 | bool clear() { 84 | lock l; 85 | if (l.locked()) 86 | return l.clear(); 87 | else 88 | return false; 89 | } 90 | 91 | bool set_text(const std::string& value) { 92 | lock l; 93 | if (l.locked()) { 94 | l.clear(); 95 | return l.set_data(text_format(), value.c_str(), value.size()); 96 | } 97 | else 98 | return false; 99 | } 100 | 101 | bool get_text(std::string& value) { 102 | lock l; 103 | if (!l.locked()) 104 | return false; 105 | 106 | format f = text_format(); 107 | if (!l.is_convertible(f)) 108 | return false; 109 | 110 | size_t len = l.get_data_length(f); 111 | if (len > 0) { 112 | std::vector buf(len); 113 | l.get_data(f, &buf[0], len); 114 | value = &buf[0]; 115 | return true; 116 | } 117 | else { 118 | value.clear(); 119 | return true; 120 | } 121 | } 122 | 123 | bool set_image(const image& img) { 124 | lock l; 125 | if (l.locked()) { 126 | l.clear(); 127 | return l.set_image(img); 128 | } 129 | else 130 | return false; 131 | } 132 | 133 | bool get_image(image& img) { 134 | lock l; 135 | if (!l.locked()) 136 | return false; 137 | 138 | format f = image_format(); 139 | if (!l.is_convertible(f)) 140 | return false; 141 | 142 | return l.get_image(img); 143 | } 144 | 145 | bool get_image_spec(image_spec& spec) { 146 | lock l; 147 | if (!l.locked()) 148 | return false; 149 | 150 | format f = image_format(); 151 | if (!l.is_convertible(f)) 152 | return false; 153 | 154 | return l.get_image_spec(spec); 155 | } 156 | 157 | void set_error_handler(error_handler handler) { 158 | g_error_handler = handler; 159 | } 160 | 161 | error_handler get_error_handler() { 162 | return g_error_handler; 163 | } 164 | 165 | #ifdef HAVE_XCB_XLIB_H 166 | static int g_x11_timeout = 1000; 167 | void set_x11_wait_timeout(int msecs) { g_x11_timeout = msecs; } 168 | int get_x11_wait_timeout() { return g_x11_timeout; } 169 | #else 170 | void set_x11_wait_timeout(int) { } 171 | int get_x11_wait_timeout() { return 1000; } 172 | #endif 173 | 174 | } // namespace clip 175 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/prefilter.fs: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * rPBR [shader] - Prefiltered environment for reflections fragment shader 4 | * 5 | * Copyright (c) 2017 Victor Fisac 6 | * 7 | **********************************************************************************************/ 8 | 9 | #version 330 10 | #define MAX_SAMPLES 1024u 11 | #define CUBEMAP_RESOLUTION 1024.0 12 | 13 | // Input vertex attributes (from vertex shader) 14 | in vec3 fragPosition; 15 | 16 | // Input uniform values 17 | uniform samplerCube environmentMap; 18 | uniform float roughness; 19 | 20 | // Constant values 21 | const float PI = 3.14159265359; 22 | 23 | // Output fragment color 24 | out vec4 finalColor; 25 | 26 | float DistributionGGX(vec3 N, vec3 H, float roughness); 27 | float RadicalInverse_VdC(uint bits); 28 | vec2 Hammersley(uint i, uint N); 29 | vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness); 30 | 31 | float DistributionGGX(vec3 N, vec3 H, float roughness) 32 | { 33 | float a = roughness*roughness; 34 | float a2 = a*a; 35 | float NdotH = max(dot(N, H), 0.0); 36 | float NdotH2 = NdotH*NdotH; 37 | 38 | float nom = a2; 39 | float denom = (NdotH2*(a2 - 1.0) + 1.0); 40 | denom = PI*denom*denom; 41 | 42 | return nom/denom; 43 | } 44 | 45 | float RadicalInverse_VdC(uint bits) 46 | { 47 | bits = (bits << 16u) | (bits >> 16u); 48 | bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); 49 | bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); 50 | bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); 51 | bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); 52 | return float(bits)*2.3283064365386963e-10; // / 0x100000000 53 | } 54 | 55 | vec2 Hammersley(uint i, uint N) 56 | { 57 | return vec2(float(i)/float(N), RadicalInverse_VdC(i)); 58 | } 59 | 60 | vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) 61 | { 62 | float a = roughness*roughness; 63 | float phi = 2.0*PI*Xi.x; 64 | float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y)); 65 | float sinTheta = sqrt(1.0 - cosTheta*cosTheta); 66 | 67 | // Transform from spherical coordinates to cartesian coordinates (halfway vector) 68 | vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta); 69 | 70 | // Transform from tangent space H vector to world space sample vector 71 | vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0)); 72 | vec3 tangent = normalize(cross(up, N)); 73 | vec3 bitangent = cross(N, tangent); 74 | vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z; 75 | 76 | return normalize(sampleVec); 77 | } 78 | 79 | void main() 80 | { 81 | // Make the simplyfying assumption that V equals R equals the normal 82 | vec3 N = normalize(fragPosition); 83 | vec3 R = N; 84 | vec3 V = R; 85 | 86 | vec3 prefilteredColor = vec3(0.0); 87 | float totalWeight = 0.0; 88 | 89 | for (uint i = 0u; i < MAX_SAMPLES; i++) 90 | { 91 | // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling) 92 | vec2 Xi = Hammersley(i, MAX_SAMPLES); 93 | vec3 H = ImportanceSampleGGX(Xi, N, roughness); 94 | vec3 L = normalize(2.0*dot(V, H)*H - V); 95 | 96 | float NdotL = max(dot(N, L), 0.0); 97 | if(NdotL > 0.0) 98 | { 99 | // Sample from the environment's mip level based on roughness/pdf 100 | float D = DistributionGGX(N, H, roughness); 101 | float NdotH = max(dot(N, H), 0.0); 102 | float HdotV = max(dot(H, V), 0.0); 103 | float pdf = D*NdotH/(4.0*HdotV) + 0.0001; 104 | 105 | float resolution = CUBEMAP_RESOLUTION; 106 | float saTexel = 4.0*PI/(6.0*resolution*resolution); 107 | float saSample = 1.0/(float(MAX_SAMPLES)*pdf + 0.0001); 108 | float mipLevel = ((roughness == 0.0) ? 0.0 : 0.5*log2(saSample/saTexel)); 109 | 110 | prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb*NdotL; 111 | totalWeight += NdotL; 112 | } 113 | } 114 | 115 | // Calculate prefilter average color 116 | prefilteredColor = prefilteredColor/totalWeight; 117 | 118 | // Calculate final fragment color 119 | finalColor = vec4(prefilteredColor, 1.0); 120 | } 121 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "TestFrame" 2 | configurations { "Debug","Debug.DLL", "Release", "Release.DLL" } 3 | platforms { "x64"} 4 | 5 | filter "configurations:Debug" 6 | defines { "DEBUG" } 7 | symbols "On" 8 | 9 | filter "configurations:Debug.DLL" 10 | defines { "DEBUG" } 11 | symbols "On" 12 | 13 | filter "configurations:Release" 14 | defines { "NDEBUG" } 15 | optimize "On" 16 | 17 | filter "configurations:Release.DLL" 18 | defines { "NDEBUG" } 19 | optimize "On" 20 | 21 | filter { "platforms:x64" } 22 | architecture "x86_64" 23 | 24 | targetdir "bin/%{cfg.buildcfg}/" 25 | 26 | defines{"PLATFORM_DESKTOP", "GRAPHICS_API_OPENGL_33"} 27 | 28 | project "raylib" 29 | filter "configurations:Debug.DLL OR Release.DLL" 30 | kind "SharedLib" 31 | defines {"BUILD_LIBTYPE_SHARED"} 32 | 33 | filter "configurations:Debug OR Release" 34 | kind "StaticLib" 35 | 36 | filter "action:vs*" 37 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "_WIN32"} 38 | links {"winmm"} 39 | 40 | filter "action:gmake*" 41 | links {"pthread", "GL", "m", "dl", "rt", "X11"} 42 | 43 | filter{} 44 | 45 | location "build" 46 | language "C++" 47 | targetdir "bin/%{cfg.buildcfg}" 48 | cppdialect "C++17" 49 | 50 | includedirs { "raylib/src", "raylib/src/external/glfw/include"} 51 | vpaths 52 | { 53 | ["Header Files"] = { "raylib/src/**.h"}, 54 | ["Source Files/*"] = {"raylib/src/**.c"}, 55 | } 56 | files {"raylib/src/*.h", "raylib/src/*.c"} 57 | 58 | project "rlExtrasCPP" 59 | kind "StaticLib" 60 | 61 | filter "action:vs*" 62 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "_WIN32"} 63 | links {"winmm"} 64 | 65 | filter{} 66 | 67 | location "raylibExtras/rlExtrasCPP/" 68 | language "C" 69 | targetdir "bin/%{cfg.buildcfg}" 70 | 71 | includedirs { "raylib/src","rlExtrasCPP"} 72 | vpaths 73 | { 74 | ["Header Files"] = { "raylibExtras/rlExtrasCPP/**.h"}, 75 | ["Source Files"] = {"raylibExtras/rlExtrasCPP/**.cpp"}, 76 | } 77 | files {"raylibExtras/rlExtrasCPP/**.h", "raylibExtras/rlExtrasCPP/**.cpp"} 78 | 79 | project "rlImGui" 80 | kind "StaticLib" 81 | 82 | filter "action:vs*" 83 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "_WIN32"} 84 | links {"winmm"} 85 | 86 | filter{} 87 | 88 | location "raylibExtras/rlImGui/" 89 | language "C++" 90 | targetdir "bin/%{cfg.buildcfg}" 91 | 92 | includedirs { "raylib/src","raylibExtras/rlImGui", "raylibExtras/imgui"} 93 | vpaths 94 | { 95 | ["Header Files"] = { "raylibExtras/lImGui/**.h"}, 96 | ["Source Files"] = {"raylibExtras/rlImGui/**.cpp"}, 97 | ["ImGui Files"] = { "raylibExtras/imgui/*.h","raylibExtras/imgui/*.cpp" }, 98 | } 99 | files {"raylibExtras/imgui/*.h", "raylibExtras/imgui/*.cpp", "raylibExtras/rlImGui/**.cpp", "raylibExtras/rlImGui/**.h"} 100 | 101 | project "clip" 102 | kind "StaticLib" 103 | 104 | filter "action:vs*" 105 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "_WIN32"} 106 | 107 | filter{} 108 | 109 | location "clip/" 110 | language "C++" 111 | targetdir "bin/%{cfg.buildcfg}" 112 | 113 | includedirs { "clip"} 114 | vpaths 115 | { 116 | ["Header Files"] = { "clip/**.h"}, 117 | ["Source Files"] = {"clip/**.cpp"}, 118 | } 119 | 120 | files {"clip/*.h", "clip/image.cpp", "clip/clip.cpp"} 121 | filter "action:vs*" 122 | files {"clip/clip_win.cpp"} 123 | filter "action:gmake*" 124 | files {"clip/clip_x11.cpp"} 125 | links {"x11", "libpng", "xcb", "pthread"} 126 | 127 | project "Application" 128 | kind "WindowedApp" 129 | location "./" 130 | language "C++" 131 | targetdir "bin/%{cfg.buildcfg}" 132 | cppdialect "C++17" 133 | 134 | includedirs {"src"} 135 | vpaths 136 | { 137 | ["Header Files"] = { "Application/*.h"}, 138 | ["Source Files"] = {"Application/*.c", "Application/*.cpp"}, 139 | } 140 | files {"Application/*.c", "Application/*.cpp", "Application/*.h", "Application/views/**.cpp", "Application/views/**.h"} 141 | 142 | links {"raylib", "rlExtrasCPP", "rlImGui", "clip"} 143 | 144 | includedirs { "Application", "Application/views", "raylib/src", "raylibExtras/rlExtrasCPP", "raylibExtras/rlImGui", "raylibExtras/imgui", "clip"} 145 | 146 | defines{"PLATFORM_DESKTOP", "GRAPHICS_API_OPENGL_33"} 147 | 148 | filter "action:vs*" 149 | defines{"_WINSOCK_DEPRECATED_NO_WARNINGS", "_CRT_SECURE_NO_WARNINGS", "_WIN32"} 150 | dependson {"raylib"} 151 | links {"winmm", "raylib.lib", "kernel32"," Shlwapi"} 152 | libdirs {"bin/%{cfg.buildcfg}"} 153 | characterset ("MBCS") 154 | 155 | filter "action:gmake*" 156 | links {"pthread", "GL", "m", "dl", "rt", "X11"} -------------------------------------------------------------------------------- /Application/platform_tools_platforms.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _WIN32 5 | 6 | #define WIN32_LEAN_AND_MEAN 7 | #include 8 | #include 9 | #include 10 | 11 | HWND WindowHandle; 12 | namespace PlatformTools 13 | { 14 | void SetWindowHandle(void* handle) 15 | { 16 | WindowHandle = HWND(handle); 17 | } 18 | } 19 | 20 | std::string wstrtostr(const std::wstring& wstr) 21 | { 22 | std::string strTo; 23 | char* szTo = new char[wstr.length() + 1]; 24 | szTo[wstr.size()] = '\0'; 25 | WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL); 26 | strTo = szTo; 27 | delete[] szTo; 28 | return strTo; 29 | } 30 | 31 | const char* BuildFilter(std::vector> filterValues) 32 | { 33 | size_t count = 0; 34 | for (auto& filterValue : filterValues) 35 | { 36 | count += filterValue.first.size() + 1; 37 | count += filterValue.first.size() + 3; 38 | } 39 | count += 1; 40 | if (count == 1) 41 | { 42 | count += strlen("All Files\t*.*\t"); 43 | } 44 | 45 | char* filter = new char[count]; 46 | 47 | if (filterValues.size() == 0) 48 | { 49 | memcpy(filter, "All Files\0*.*\0\0", count); 50 | } 51 | else 52 | { 53 | size_t offset = 0; 54 | for (auto& filterValue : filterValues) 55 | { 56 | const std::string& name = filterValue.first; 57 | std::string extension = "*." + filterValue.second; 58 | 59 | memcpy(filter + offset, name.c_str(), name.size()); 60 | offset += name.size(); 61 | 62 | memcpy(filter + offset, "\0", 1); 63 | offset += 1; 64 | 65 | memcpy(filter + offset, extension.c_str(), extension.size()); 66 | offset += extension.size(); 67 | 68 | memcpy(filter + offset, "\0", 1); 69 | offset += 1; 70 | } 71 | memcpy(filter + offset, "\0", 1); 72 | offset += 1; 73 | } 74 | 75 | return filter; 76 | } 77 | 78 | std::string OpenFileDialog(const char* filename, std::vector> filterValues) 79 | { 80 | std::string result; 81 | 82 | const char* filter = BuildFilter(filterValues); 83 | 84 | // common dialog box structure, setting all fields to 0 is important 85 | OPENFILENAME ofn = { 0 }; 86 | TCHAR szFile[260] = { 0 }; 87 | if (filename != nullptr) 88 | strcpy_s(szFile, 260, filename); 89 | 90 | // Initialize remaining fields of OPENFILENAME structure 91 | ofn.lStructSize = sizeof(ofn); 92 | ofn.hwndOwner = WindowHandle; 93 | ofn.lpstrFile = szFile; 94 | ofn.nMaxFile = sizeof(szFile); 95 | ofn.lpstrFilter = filter; 96 | ofn.nFilterIndex = 1; 97 | ofn.lpstrFileTitle = nullptr; 98 | ofn.nMaxFileTitle = 0; 99 | ofn.lpstrInitialDir = nullptr; 100 | ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 101 | 102 | if (GetOpenFileName(&ofn) == TRUE) 103 | { 104 | // use ofn.lpstrFile here 105 | result = ofn.lpstrFile; 106 | } 107 | 108 | delete[](filter); 109 | 110 | return result; 111 | } 112 | 113 | std::string SaveFileDialog(const char* filename, std::vector> filterValues) 114 | { 115 | std::string result; 116 | 117 | const char* filter = BuildFilter(filterValues); 118 | 119 | // common dialog box structure, setting all fields to 0 is important 120 | OPENFILENAME ofn = { 0 }; 121 | TCHAR szFile[260] = { 0 }; 122 | if (filename != nullptr) 123 | strcpy_s(szFile, filename); 124 | 125 | // Initialize remaining fields of OPENFILENAME structure 126 | ofn.lStructSize = sizeof(ofn); 127 | ofn.hwndOwner = WindowHandle; 128 | ofn.lpstrFile = szFile; 129 | ofn.nMaxFile = sizeof(szFile); 130 | ofn.lpstrFilter = filter; 131 | ofn.nFilterIndex = 1; 132 | ofn.lpstrFileTitle = nullptr; 133 | ofn.nMaxFileTitle = 0; 134 | ofn.lpstrInitialDir = nullptr; 135 | ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 136 | 137 | if (GetSaveFileName(&ofn) == TRUE) 138 | { 139 | // use ofn.lpstrFile here 140 | result = ofn.lpstrFile; 141 | } 142 | 143 | delete[](filter); 144 | 145 | return result; 146 | } 147 | 148 | #else 149 | 150 | void SetWindowHandle(void*) 151 | { 152 | } 153 | 154 | std::string OpenFileDialog(const char*, std::vector>) 155 | { 156 | return std::string(); 157 | } 158 | 159 | std::string SaveFileDialog(const char*, std::vector>) 160 | { 161 | return std::string(); 162 | } 163 | 164 | #endif -------------------------------------------------------------------------------- /Application/application_context.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "application_ui.h" 34 | 35 | #include "RLAssets.h" 36 | #include "imgui.h" 37 | 38 | #include 39 | #include 40 | 41 | class MainView; 42 | 43 | class ApplicationPrefs 44 | { 45 | protected: 46 | std::string PrefsFile; 47 | 48 | public: 49 | std::string LastView = "2d View"; 50 | int WindowHeight = 720; 51 | int WindowWidth = 1280; 52 | 53 | bool Maximized = false; 54 | 55 | void Setup() 56 | { 57 | PrefsFile = rlas_GetApplicationBasePath(); 58 | PrefsFile += "prefs.txt"; 59 | 60 | FILE* fp = fopen(PrefsFile.c_str(), "r"); 61 | if (fp == nullptr) 62 | return; 63 | 64 | char temp[1024] = { 0 }; 65 | int max = 0; 66 | char* p = temp; 67 | while (true) 68 | { 69 | fread(p, 1, 1, fp); 70 | if (*p == '\n') 71 | { 72 | *p = '\0'; 73 | break; 74 | } 75 | else 76 | p++; 77 | } 78 | fscanf(fp, "%d\n%d\n%d", &WindowHeight,&WindowWidth,&max); 79 | LastView = temp; 80 | Maximized = max != 0; 81 | fclose(fp); 82 | } 83 | 84 | void Save() 85 | { 86 | FILE* fp = fopen(PrefsFile.c_str(), "w"); 87 | if (fp == nullptr) 88 | return; 89 | 90 | Maximized = IsWindowMaximized(); 91 | if (!Maximized) 92 | { 93 | WindowHeight = GetScreenHeight(); 94 | WindowWidth = GetScreenWidth(); 95 | } 96 | 97 | int max = Maximized ? 1 : 0; 98 | 99 | fprintf(fp, "%s\n%d\n%d\n%d", LastView.c_str(), WindowHeight, WindowWidth, max); 100 | fclose(fp); 101 | } 102 | }; 103 | 104 | struct ApplicationContext 105 | { 106 | bool Quit = false; 107 | MainView* View = nullptr; 108 | UIManager UI; 109 | std::vector RegisteredViews; 110 | 111 | ApplicationPrefs Prefs; 112 | 113 | bool ScreenshotView = false; 114 | bool TakeScreenshot = false; 115 | bool CopyScreenshot = false; 116 | 117 | static void Screenshot(); 118 | 119 | void ChangeView(MainView* newView); 120 | 121 | MainView* FindView(const char* name); 122 | }; 123 | 124 | extern ApplicationContext GlobalContext; 125 | 126 | #define REGISTER_VIEW(viewType) \ 127 | static viewType View; 128 | 129 | namespace LogSink 130 | { 131 | struct LogItem 132 | { 133 | int Level = 0; 134 | std::string Prefix; 135 | std::string Text; 136 | ImVec4 Color = { 1,1,1,1 }; 137 | }; 138 | 139 | void Setup(); 140 | bool PopLogLine(LogItem& line); 141 | void Flush(); 142 | 143 | inline const char* GetLogLevelName(int logLevel) 144 | { 145 | switch (logLevel) 146 | { 147 | default: return "All"; 148 | case LOG_TRACE: return "Trace"; 149 | case LOG_DEBUG: return "DEBUG"; 150 | case LOG_INFO: return "Info"; 151 | case LOG_WARNING: return "Warning"; 152 | case LOG_ERROR: return "ERROR"; 153 | case LOG_FATAL: return "FATAL"; 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /Application/ui_window.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "application_context.h" 32 | #include "common_utils.h" 33 | #include "ui_window.h" 34 | 35 | #include "imgui.h" 36 | 37 | void UIWindow::Show(MainView* view) 38 | { 39 | if (Shown) 40 | { 41 | GetName(Name,view); 42 | if (ImGui::Begin(Name.c_str(), &Shown, ImGuiWindowFlags_None)) 43 | { 44 | OnShow(view); 45 | } 46 | ImGui::End(); 47 | } 48 | } 49 | 50 | void UIWindow::Update() 51 | { 52 | } 53 | 54 | void UIWindow::Resize() 55 | { 56 | } 57 | 58 | /// 59 | /// LogWindow 60 | /// 61 | LogWindow::LogWindow() : UIWindow() 62 | { 63 | Shown = true; 64 | } 65 | 66 | void LogWindow::OnShow(MainView*) 67 | { 68 | ImGui::TextUnformatted("Show:"); 69 | ImGui::SameLine(); 70 | ImGui::SetNextItemWidth(150); 71 | if (ImGui::BeginCombo("##LogLevel", LogSink::GetLogLevelName(ShowLevel))) 72 | { 73 | for (int i = 0; i < LOG_NONE; ++i) 74 | { 75 | bool is_selected = i == ShowLevel; 76 | if (ImGui::Selectable(LogSink::GetLogLevelName(i), is_selected)) 77 | ShowLevel = i; 78 | 79 | if (is_selected) 80 | ImGui::SetItemDefaultFocus(); 81 | } 82 | ImGui::EndCombo(); 83 | } 84 | 85 | ImGui::SameLine(); 86 | ImGui::SetNextItemWidth(200); 87 | ImGui::InputTextWithHint("###filterText", "Filter", FilterText, 512); 88 | 89 | ImGui::SameLine(); 90 | bool copy = false; 91 | if(ImGui::Button("Copy")) 92 | { 93 | copy = true; 94 | } 95 | 96 | ImGui::SameLine(); 97 | if (ImGui::Button("Clear")) 98 | { 99 | LogSink::Flush(); 100 | LogLines.clear(); 101 | } 102 | 103 | if (ImGui::BeginChild("###LogChild", ImGui::GetContentRegionAvail())) 104 | { 105 | bool scroollBottom = false; 106 | 107 | int count = 0; 108 | LogSink::LogItem item; 109 | while (LogSink::PopLogLine(item)/* && count <= 10*/) 110 | { 111 | LogLines.emplace_back(std::move(item)); 112 | 113 | while (LogLines.size() > 50) 114 | LogLines.pop_front(); 115 | 116 | scroollBottom = true; 117 | count++; 118 | } 119 | 120 | std::string copyBuffer; 121 | 122 | for (auto& line : LogLines) 123 | { 124 | if (ShowLevel != 0 && ShowLevel != line.Level) 125 | continue; 126 | 127 | if (FilterText[0] != '\0') 128 | { 129 | if (StringUtils::stristr(line.Text.c_str(), FilterText) == nullptr) 130 | continue; 131 | } 132 | 133 | ImGui::TextColored(line.Color, "%s", line.Prefix.c_str()); 134 | ImGui::SameLine(); 135 | ImGui::TextUnformatted(line.Text.c_str()); 136 | 137 | if (copy) 138 | copyBuffer += line.Prefix + line.Text + "\r\n"; 139 | } 140 | 141 | if (copy) 142 | { 143 | SetClipboardText(copyBuffer.c_str()); 144 | } 145 | 146 | if (scroollBottom) 147 | ImGui::SetScrollHereY(1.0f); 148 | 149 | ImGui::EndChild(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Application/shader_manager.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | #include "raylib.h" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | enum class ShaderTypes 39 | { 40 | Unknown = 0, 41 | Vertex, 42 | Fragment, 43 | }; 44 | 45 | enum class UniformTypes 46 | { 47 | Unknown = 0, 48 | Bool, 49 | Int, 50 | Float, 51 | Vec2, 52 | Vec3, 53 | Vec4, 54 | Mat4, 55 | Sampler2D, 56 | SamplerCube, 57 | }; 58 | 59 | struct UniformInfo 60 | { 61 | std::string Name; 62 | UniformTypes UniformType = UniformTypes::Unknown; 63 | bool UpdateEachFrame = false; 64 | void* ValuePtr = nullptr; 65 | 66 | void DeleteValue() 67 | { 68 | delete[](ValuePtr); 69 | } 70 | 71 | void InitDefaultValue() 72 | { 73 | switch (UniformType) 74 | { 75 | case UniformTypes::Unknown: 76 | ValuePtr = nullptr; 77 | break; 78 | case UniformTypes::Int: 79 | case UniformTypes::Bool: 80 | ValuePtr = new int[1]; 81 | memset(ValuePtr, 0, sizeof(int)); 82 | break; 83 | case UniformTypes::Float: 84 | ValuePtr = new float [1]; 85 | memset(ValuePtr, 0, sizeof(float)); 86 | break; 87 | case UniformTypes::Vec2: 88 | ValuePtr = new float[2]; 89 | memset(ValuePtr, 0, sizeof(float) * 2); 90 | break; 91 | case UniformTypes::Vec3: 92 | ValuePtr = new float[3]; 93 | memset(ValuePtr, 0, sizeof(float) * 3); 94 | break; 95 | case UniformTypes::Vec4: 96 | ValuePtr = new float[4]; 97 | memset(ValuePtr, 0, sizeof(float) * 4); 98 | ((float*)ValuePtr)[3] = 1.0f; 99 | break; 100 | case UniformTypes::Mat4: 101 | ValuePtr = new float[16]; 102 | memset(ValuePtr, 0, sizeof(float) * 16); 103 | ((float*)ValuePtr)[0] = 1.0f; 104 | ((float*)ValuePtr)[5] = 1.0f; 105 | ((float*)ValuePtr)[10] = 1.0f; 106 | break; 107 | case UniformTypes::Sampler2D: 108 | ValuePtr = new int[1]; 109 | memset(ValuePtr, 0, sizeof(int)); 110 | break; 111 | case UniformTypes::SamplerCube: 112 | ValuePtr = new int[1]; 113 | memset(ValuePtr, 0, sizeof(int)); 114 | break; 115 | default: 116 | break; 117 | } 118 | } 119 | }; 120 | 121 | class ShaderInfo 122 | { 123 | public: 124 | ~ShaderInfo() 125 | { 126 | for (auto& info : Uniforms) 127 | info.DeleteValue(); 128 | } 129 | 130 | std::string PathName; 131 | std::string Name; 132 | ShaderTypes ShaderType = ShaderTypes::Unknown; 133 | 134 | std::vector Uniforms; 135 | 136 | const char* GetFileName() 137 | { 138 | if (PathName.size() == 0) 139 | return nullptr; 140 | 141 | return PathName.c_str(); 142 | } 143 | }; 144 | 145 | class ShaderInstance 146 | { 147 | public: 148 | size_t RefCount = 0; 149 | 150 | Shader RaylibShader = { 0 }; 151 | 152 | ShaderInfo VertexShader; 153 | ShaderInfo FragmentShader; 154 | }; 155 | 156 | class ShaderManager 157 | { 158 | public: 159 | std::map ShaderCache; 160 | 161 | void Clear(); 162 | ShaderInstance& GetShader(int materialIndex); 163 | ShaderInstance& LoadShader(int materialIndex, const char* vertextShaderPath, const char* fragmentShaderPath); 164 | }; 165 | 166 | -------------------------------------------------------------------------------- /resources/shaders/glsl330/brdf.fs: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * 3 | * BRDF LUT Generation - Bidirectional reflectance distribution function fragment shader 4 | * 5 | * REF: https://github.com/HectorMF/BRDFGenerator 6 | * 7 | * Copyright (c) 2017 Victor Fisac 8 | * 9 | **********************************************************************************************/ 10 | 11 | #version 330 12 | 13 | 14 | // Input vertex attributes (from vertex shader) 15 | in vec2 fragTexCoord; 16 | 17 | // Constant values 18 | const float PI = 3.14159265359; 19 | const uint MAX_SAMPLES = 1024u; 20 | 21 | // Output fragment color 22 | out vec4 finalColor; 23 | 24 | vec2 Hammersley(uint i, uint N); 25 | float RadicalInverseVdC(uint bits); 26 | float GeometrySchlickGGX(float NdotV, float roughness); 27 | float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness); 28 | vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness); 29 | vec2 IntegrateBRDF(float NdotV, float roughness); 30 | 31 | float RadicalInverseVdC(uint bits) 32 | { 33 | bits = (bits << 16u) | (bits >> 16u); 34 | bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); 35 | bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); 36 | bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); 37 | bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); 38 | return float(bits) * 2.3283064365386963e-10; // / 0x100000000 39 | } 40 | 41 | // Compute Hammersley coordinates 42 | vec2 Hammersley(uint i, uint N) 43 | { 44 | return vec2(float(i)/float(N), RadicalInverseVdC(i)); 45 | } 46 | 47 | // Integrate number of importance samples for (roughness and NoV) 48 | vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) 49 | { 50 | float a = roughness*roughness; 51 | float phi = 2.0 * PI * Xi.x; 52 | float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y)); 53 | float sinTheta = sqrt(1.0 - cosTheta*cosTheta); 54 | 55 | // Transform from spherical coordinates to cartesian coordinates (halfway vector) 56 | vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta); 57 | 58 | // Transform from tangent space H vector to world space sample vector 59 | vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0)); 60 | vec3 tangent = normalize(cross(up, N)); 61 | vec3 bitangent = cross(N, tangent); 62 | vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z; 63 | 64 | return normalize(sampleVec); 65 | } 66 | 67 | float GeometrySchlickGGX(float NdotV, float roughness) 68 | { 69 | // For IBL k is calculated different 70 | float k = (roughness*roughness)/2.0; 71 | 72 | float nom = NdotV; 73 | float denom = NdotV*(1.0 - k) + k; 74 | 75 | return nom/denom; 76 | } 77 | 78 | // Compute the geometry term for the BRDF given roughness squared, NoV, NoL 79 | float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) 80 | { 81 | float NdotV = max(dot(N, V), 0.0); 82 | float NdotL = max(dot(N, L), 0.0); 83 | float ggx2 = GeometrySchlickGGX(NdotV, roughness); 84 | float ggx1 = GeometrySchlickGGX(NdotL, roughness); 85 | 86 | return ggx1*ggx2; 87 | } 88 | 89 | vec2 IntegrateBRDF(float NdotV, float roughness) 90 | { 91 | float A = 0.0; 92 | float B = 0.0; 93 | vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV); 94 | vec3 N = vec3(0.0, 0.0, 1.0); 95 | 96 | for (uint i = 0u; i < MAX_SAMPLES; i++) 97 | { 98 | // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling) 99 | 100 | vec2 Xi = Hammersley(i, MAX_SAMPLES); // Compute a Hammersely coordinate 101 | vec3 H = ImportanceSampleGGX(Xi, N, roughness); // Integrate number of importance samples for (roughness and NoV) 102 | vec3 L = normalize(2.0*dot(V, H)*H - V); // Compute reflection vector L 103 | 104 | float NdotL = max(L.z, 0.0); // Compute normal dot light 105 | float NdotH = max(H.z, 0.0); // Compute normal dot half 106 | float VdotH = max(dot(V, H), 0.0); // Compute view dot half 107 | 108 | if (NdotL > 0.0) 109 | { 110 | float G = GeometrySmith(N, V, L, roughness); // Compute the geometry term for the BRDF given roughness squared, NoV, NoL 111 | float GVis = (G*VdotH)/(NdotH*NdotV); // Compute the visibility term given G, VoH, NoH, NoV, NoL 112 | float Fc = pow(1.0 - VdotH, 5.0); // Compute the fresnel term given VoH 113 | 114 | A += (1.0 - Fc)*GVis; // Sum the result given fresnel, geometry, visibility 115 | B += Fc*GVis; 116 | } 117 | } 118 | 119 | // Calculate brdf average sample 120 | A /= float(MAX_SAMPLES); 121 | B /= float(MAX_SAMPLES); 122 | 123 | return vec2(A, B); 124 | } 125 | 126 | void main() 127 | { 128 | // Calculate brdf based on texture coordinates 129 | vec2 brdf = IntegrateBRDF(fragTexCoord.x, fragTexCoord.y); 130 | 131 | // Calculate final fragment color 132 | finalColor = vec4(brdf.r, brdf.g, 0.0, 1.0); 133 | } 134 | -------------------------------------------------------------------------------- /Application/common_utils.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include 34 | #include "raylib.h" 35 | #include "raymath.h" 36 | 37 | 38 | namespace MovementTools 39 | { 40 | inline Vector2 GetWADSVector(float speed = 1, bool flipY = false) 41 | { 42 | float yScale = 1; 43 | if (flipY) 44 | yScale = -1; 45 | Vector2 result = { 0,0 }; 46 | if (IsKeyDown(KEY_W)) 47 | result.y = -GetFrameTime() * speed * yScale; 48 | else if (IsKeyDown(KEY_S)) 49 | result.y = GetFrameTime() * speed * yScale; 50 | 51 | if (IsKeyDown(KEY_D)) 52 | result.x = GetFrameTime() * speed; 53 | else if (IsKeyDown(KEY_A)) 54 | result.x = -GetFrameTime() * speed; 55 | 56 | return result; 57 | } 58 | 59 | inline Vector2 GetArrowVector(float speed = 1, bool flipY = false) 60 | { 61 | float yScale = 1; 62 | if (flipY) 63 | yScale = -1; 64 | Vector2 result = { 0,0 }; 65 | if (IsKeyDown(KEY_UP)) 66 | result.y = -GetFrameTime() * speed * yScale; 67 | else if (IsKeyDown(KEY_DOWN)) 68 | result.y = GetFrameTime() * speed * yScale; 69 | 70 | if (IsKeyDown(KEY_RIGHT)) 71 | result.x = GetFrameTime() * speed; 72 | else if (IsKeyDown(KEY_LEFT)) 73 | result.x = -GetFrameTime() * speed; 74 | 75 | return result; 76 | } 77 | 78 | inline Vector2 RotateVector2Arrows(Vector2& vector, float speed = 90) 79 | { 80 | if (IsKeyDown(KEY_LEFT)) 81 | vector = Vector2Rotate(vector, -speed * GetFrameTime()); 82 | if (IsKeyDown(KEY_RIGHT)) 83 | vector = Vector2Rotate(vector, speed * GetFrameTime()); 84 | 85 | return vector; 86 | } 87 | } 88 | 89 | namespace KeyboardTools 90 | { 91 | inline bool IsShiftDown() 92 | { 93 | return IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT); 94 | } 95 | 96 | inline bool IsControlDown() 97 | { 98 | return IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL); 99 | } 100 | 101 | inline bool IsAltDown() 102 | { 103 | return IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT); 104 | } 105 | } 106 | 107 | namespace Base64 108 | { 109 | size_t GetSize(const char* input); 110 | void* Decode(const char* input, size_t* size); 111 | void FreeBuffer(void* buffer); 112 | char* Encode(const void* input, size_t len); 113 | } 114 | 115 | namespace StringUtils 116 | { 117 | inline char* stristr(const char* str1, const char* str2) 118 | { 119 | const char* p1 = str1; 120 | const char* p2 = str2; 121 | const char* r = *p2 == 0 ? str1 : 0; 122 | 123 | while (*p1 != 0 && *p2 != 0) 124 | { 125 | if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) 126 | { 127 | if (r == 0) 128 | { 129 | r = p1; 130 | } 131 | 132 | p2++; 133 | } 134 | else 135 | { 136 | p2 = str2; 137 | if (r != 0) 138 | { 139 | p1 = r + 1; 140 | } 141 | 142 | if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) 143 | { 144 | r = p1; 145 | p2++; 146 | } 147 | else 148 | { 149 | r = 0; 150 | } 151 | } 152 | 153 | p1++; 154 | } 155 | 156 | return *p2 == 0 ? (char*)r : 0; 157 | } 158 | } -------------------------------------------------------------------------------- /Application/inspector_window.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "ui_window.h" 34 | 35 | #include "raylib.h" 36 | #include "rlImGui.h" 37 | #include "raylib.h" 38 | 39 | 40 | namespace Inspectors 41 | { 42 | inline void ShowTextureInspector(const Texture& texture, float width = 0) 43 | { 44 | if (width <= 0) 45 | width = ImGui::GetContentRegionAvailWidth(); 46 | 47 | float height = width * (texture.height / (float)texture.width); 48 | RLImGuiImageSize(&texture, (int)width, (int)height); 49 | ImGui::Text("ID:%d W:%d H:%d", texture.id, texture.width, texture.height); 50 | if (texture.mipmaps > 1) 51 | ImGui::Text("Mipmap Levels:%d", texture.mipmaps); 52 | } 53 | 54 | inline void ShowSetTextureFilter(const Texture& texture) 55 | { 56 | if (ImGui::Button("Point")) 57 | SetTextureFilter(texture, TEXTURE_FILTER_POINT); 58 | 59 | ImGui::SameLine(); 60 | if (ImGui::Button("Bi")) 61 | SetTextureFilter(texture, TEXTURE_FILTER_BILINEAR); 62 | 63 | ImGui::SameLine(); 64 | if (ImGui::Button("Tri")) 65 | SetTextureFilter(texture, TEXTURE_FILTER_TRILINEAR); 66 | 67 | ImGui::SameLine(); 68 | if (ImGui::Button("A4x")) 69 | SetTextureFilter(texture, TEXTURE_FILTER_ANISOTROPIC_4X); 70 | 71 | ImGui::SameLine(); 72 | if (ImGui::Button("A8x")) 73 | SetTextureFilter(texture, TEXTURE_FILTER_ANISOTROPIC_8X); 74 | 75 | ImGui::SameLine(); 76 | if (ImGui::Button("A16x")) 77 | SetTextureFilter(texture, TEXTURE_FILTER_ANISOTROPIC_16X); 78 | 79 | ImGui::SameLine(); 80 | if (ImGui::Button("Mip")) 81 | GenTextureMipmaps((Texture*)&texture); 82 | 83 | } 84 | 85 | inline void ShowMeshInspector(const Mesh& mesh) 86 | { 87 | if (ImGui::BeginChild("Mesh Inspector")) 88 | { 89 | ImGui::TextUnformatted("Mesh"); 90 | ImGui::Separator(); 91 | 92 | ImGui::Text("Verts: %d Tris:%d", mesh.vertexCount, mesh.triangleCount); 93 | ImGui::EndChild(); 94 | } 95 | } 96 | 97 | inline void ShowMaterialMapInspector(MaterialMap& materialMap) 98 | { 99 | ImGui::TextUnformatted("Material Map"); 100 | ImGui::Separator(); 101 | ImColor color = ImGuiColors::Convert(materialMap.color); 102 | if (ImGui::ColorEdit4("Color###MatColor", &(color.Value.x), ImGuiColorEditFlags_NoBorder)) 103 | { 104 | materialMap.color.r = (unsigned char)(255 * color.Value.x); 105 | materialMap.color.g = (unsigned char)(255 * color.Value.y); 106 | materialMap.color.b = (unsigned char)(255 * color.Value.z); 107 | materialMap.color.a = (unsigned char)(255 * color.Value.w); 108 | } 109 | ImGui::Separator(); 110 | ImGui::DragFloat("Value", &materialMap.value, 0.001f, 0, 1.0f); 111 | ImGui::Separator(); 112 | ShowTextureInspector(materialMap.texture, 150); 113 | } 114 | } 115 | 116 | constexpr char InspectorWindowName[] = " Inspector###RaylibInspectorWindow"; 117 | 118 | class InspectorWindow : public UIWindow 119 | { 120 | public: 121 | InspectorWindow() : UIWindow() 122 | { 123 | Shown = true; 124 | } 125 | 126 | inline void GetName(std::string& name, MainView* view) const override 127 | { 128 | name = view->GetName(); 129 | name += InspectorWindowName; 130 | } 131 | 132 | inline const char* GetMenuName() const override { return "Inspector"; } 133 | 134 | inline void ShowCommonData(MainView* view) const 135 | { 136 | float frameTime = GetFrameTime(); 137 | float instantFPS = 0; 138 | if (frameTime > 0) 139 | instantFPS = 1 / frameTime; 140 | 141 | int avgFPS = GetFPS(); 142 | 143 | ImGui::Text("FPS %d:Avg %.0f:Inst DT:%.2fms", avgFPS, instantFPS, frameTime * 1000); 144 | Vector2 mouse = view->GetViewMousePosition(); 145 | ImGui::Text("Mouse X%.0f Y%.0f", mouse.x, mouse.y); 146 | } 147 | 148 | inline void OnShow(MainView* view) override 149 | { 150 | view->ShowInspectorContents(*this); 151 | } 152 | }; 153 | -------------------------------------------------------------------------------- /Application/common_utils.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "common_utils.h" 32 | 33 | #include "raylib.h" 34 | 35 | namespace Base64 36 | { 37 | static const unsigned char base64Table[] = { 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42 | 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 43 | 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 44 | 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 45 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 46 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 47 | 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 48 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 49 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50 | 49, 50, 51 51 | }; 52 | 53 | size_t GetSize(const char* input) 54 | { 55 | size_t size = 0; 56 | 57 | for (int i = 0; input[4 * i] != 0; i++) 58 | { 59 | if (input[4 * i + 3] == '=') 60 | { 61 | if (input[4 * i + 2] == '=') size += 1; 62 | else size += 2; 63 | } 64 | else size += 3; 65 | } 66 | 67 | return size; 68 | } 69 | 70 | void FreeBuffer(void* buffer) 71 | { 72 | delete[] (buffer); 73 | } 74 | 75 | const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 76 | 77 | size_t EncodedSize(size_t inlen) 78 | { 79 | size_t ret; 80 | 81 | ret = inlen; 82 | if (inlen % 3 != 0) 83 | ret += 3 - (inlen % 3); 84 | ret /= 3; 85 | ret *= 4; 86 | 87 | return ret; 88 | } 89 | 90 | char* Encode(const void* buffer, size_t len) 91 | { 92 | const char* in = static_cast(buffer); 93 | char* out = nullptr; 94 | size_t elen = 0; 95 | size_t i = 0; 96 | size_t j = 0; 97 | size_t v = 0; 98 | 99 | if (in == NULL || len == 0) 100 | return NULL; 101 | 102 | elen = EncodedSize(len); 103 | out = new char[elen + 1]; 104 | 105 | out[elen] = '\0'; 106 | 107 | for (i = 0, j = 0; i < len; i += 3, j += 4) { 108 | v = in[i]; 109 | v = i + 1 < len ? v << 8 | in[i + 1] : v << 8; 110 | v = i + 2 < len ? v << 8 | in[i + 2] : v << 8; 111 | 112 | out[j] = b64chars[(v >> 18) & 0x3F]; 113 | out[j + 1] = b64chars[(v >> 12) & 0x3F]; 114 | if (i + 1 < len) { 115 | out[j + 2] = b64chars[(v >> 6) & 0x3F]; 116 | } 117 | else { 118 | out[j + 2] = '='; 119 | } 120 | if (i + 2 < len) { 121 | out[j + 3] = b64chars[v & 0x3F]; 122 | } 123 | else { 124 | out[j + 3] = '='; 125 | } 126 | } 127 | 128 | return out; 129 | } 130 | 131 | void* Decode(const char* input, size_t* size) 132 | { 133 | *size = GetSize(input); 134 | 135 | unsigned char* buf = (unsigned char*)new char[*size]; 136 | for (int i = 0; i < *size / 3; i++) 137 | { 138 | unsigned char a = base64Table[(int)input[4 * i]]; 139 | unsigned char b = base64Table[(int)input[4 * i + 1]]; 140 | unsigned char c = base64Table[(int)input[4 * i + 2]]; 141 | unsigned char d = base64Table[(int)input[4 * i + 3]]; 142 | 143 | buf[3 * i] = (a << 2) | (b >> 4); 144 | buf[3 * i + 1] = (b << 4) | (c >> 2); 145 | buf[3 * i + 2] = (c << 6) | d; 146 | } 147 | 148 | if (*size % 3 == 1) 149 | { 150 | size_t n = *size / 3; 151 | unsigned char a = base64Table[(int)input[4 * n]]; 152 | unsigned char b = base64Table[(int)input[4 * n + 1]]; 153 | buf[*size - 1] = (a << 2) | (b >> 4); 154 | } 155 | else if (*size % 3 == 2) 156 | { 157 | size_t n = *size / 3; 158 | unsigned char a = base64Table[(int)input[4 * n]]; 159 | unsigned char b = base64Table[(int)input[4 * n + 1]]; 160 | unsigned char c = base64Table[(int)input[4 * n + 2]]; 161 | buf[*size - 2] = (a << 2) | (b >> 4); 162 | buf[*size - 1] = (b << 4) | (c >> 2); 163 | } 164 | return buf; 165 | } 166 | } -------------------------------------------------------------------------------- /clip/clip.h: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2018 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #ifndef CLIP_H_INCLUDED 8 | #define CLIP_H_INCLUDED 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace clip { 16 | 17 | // ====================================================================== 18 | // Low-level API to lock the clipboard/pasteboard and modify it 19 | // ====================================================================== 20 | 21 | // Clipboard format identifier. 22 | typedef size_t format; 23 | 24 | class image; 25 | struct image_spec; 26 | 27 | class lock { 28 | public: 29 | // You can give your current HWND as the "native_window_handle." 30 | // Windows clipboard functions use this handle to open/close 31 | // (lock/unlock) the clipboard. From the MSDN documentation we 32 | // need this handler so SetClipboardData() doesn't fail after a 33 | // EmptyClipboard() call. Anyway it looks to work just fine if we 34 | // call OpenClipboard() with a null HWND. 35 | lock(void* native_window_handle = nullptr); 36 | ~lock(); 37 | 38 | // Returns true if we've locked the clipboard successfully in 39 | // lock() constructor. 40 | bool locked() const; 41 | 42 | // Clears the clipboard content. If you don't clear the content, 43 | // previous clipboard content (in unknown formats) could persist 44 | // after the unlock. 45 | bool clear(); 46 | 47 | // Returns true if the clipboard can be converted to the given 48 | // format. 49 | bool is_convertible(format f) const; 50 | bool set_data(format f, const char* buf, size_t len); 51 | bool get_data(format f, char* buf, size_t len) const; 52 | size_t get_data_length(format f) const; 53 | 54 | // For images 55 | bool set_image(const image& image); 56 | bool get_image(image& image) const; 57 | bool get_image_spec(image_spec& spec) const; 58 | 59 | private: 60 | class impl; 61 | std::unique_ptr p; 62 | }; 63 | 64 | format register_format(const std::string& name); 65 | 66 | // This format is when the clipboard has no content. 67 | format empty_format(); 68 | 69 | // When the clipboard has UTF8 text. 70 | format text_format(); 71 | 72 | // When the clipboard has an image. 73 | format image_format(); 74 | 75 | // Returns true if the clipboard has content of the given type. 76 | bool has(format f); 77 | 78 | // Clears the clipboard content. 79 | bool clear(); 80 | 81 | // ====================================================================== 82 | // Error handling 83 | // ====================================================================== 84 | 85 | enum class ErrorCode { 86 | CannotLock, 87 | ImageNotSupported, 88 | }; 89 | 90 | typedef void (*error_handler)(ErrorCode code); 91 | 92 | void set_error_handler(error_handler f); 93 | error_handler get_error_handler(); 94 | 95 | // ====================================================================== 96 | // Text 97 | // ====================================================================== 98 | 99 | // High-level API to put/get UTF8 text in/from the clipboard. These 100 | // functions returns false in case of error. 101 | bool set_text(const std::string& value); 102 | bool get_text(std::string& value); 103 | 104 | // ====================================================================== 105 | // Image 106 | // ====================================================================== 107 | 108 | struct image_spec { 109 | unsigned long width = 0; 110 | unsigned long height = 0; 111 | unsigned long bits_per_pixel = 0; 112 | unsigned long bytes_per_row = 0; 113 | unsigned long red_mask = 0; 114 | unsigned long green_mask = 0; 115 | unsigned long blue_mask = 0; 116 | unsigned long alpha_mask = 0; 117 | unsigned long red_shift = 0; 118 | unsigned long green_shift = 0; 119 | unsigned long blue_shift = 0; 120 | unsigned long alpha_shift = 0; 121 | }; 122 | 123 | // The image data must contain straight RGB values 124 | // (non-premultiplied by alpha). The image retrieved from the 125 | // clipboard will be non-premultiplied too. Basically you will be 126 | // always dealing with straight alpha images. 127 | // 128 | // Details: Windows expects premultiplied images on its clipboard 129 | // content, so the library code make the proper conversion 130 | // automatically. macOS handles straight alpha directly, so there is 131 | // no conversion at all. Linux/X11 images are transferred in 132 | // image/png format which are specified in straight alpha. 133 | class image { 134 | public: 135 | image(); 136 | image(const image_spec& spec); 137 | image(const void* data, const image_spec& spec); 138 | image(const image& image); 139 | image(image&& image); 140 | ~image(); 141 | 142 | image& operator=(const image& image); 143 | image& operator=(image&& image); 144 | 145 | char* data() const { return m_data; } 146 | const image_spec& spec() const { return m_spec; } 147 | 148 | bool is_valid() const { return m_data != nullptr; } 149 | void reset(); 150 | 151 | private: 152 | void copy_image(const image& image); 153 | void move_image(image&& image); 154 | 155 | bool m_own_data; 156 | char* m_data; 157 | image_spec m_spec; 158 | }; 159 | 160 | // High-level API to set/get an image in/from the clipboard. These 161 | // functions returns false in case of error. 162 | bool set_image(const image& img); 163 | bool get_image(image& img); 164 | bool get_image_spec(image_spec& spec); 165 | 166 | // ====================================================================== 167 | // Platform-specific 168 | // ====================================================================== 169 | 170 | // Only for X11: Sets the time (in milliseconds) that we must wait 171 | // for the selection/clipboard owner to receive the content. This 172 | // value is 1000 (one second) by default. 173 | void set_x11_wait_timeout(int msecs); 174 | int get_x11_wait_timeout(); 175 | 176 | } // namespace clip 177 | 178 | #endif // CLIP_H_INCLUDED 179 | -------------------------------------------------------------------------------- /Application/shader_manager.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "shader_manager.h" 32 | 33 | 34 | std::vector GetFileLines(const char* fileName) 35 | { 36 | std::vector lines; 37 | 38 | FILE* fp = fopen(fileName, "r"); 39 | if (fp == nullptr) 40 | return lines; 41 | 42 | std::string line; 43 | char c = '1'; 44 | while (fread(&c,1,1,fp) != 0) 45 | { 46 | if (c == '\n') 47 | { 48 | if (line.size() > 0) 49 | lines.push_back(line); 50 | line.clear(); 51 | } 52 | else 53 | { 54 | line += c; 55 | } 56 | } 57 | if (line.size() > 0) 58 | lines.push_back(line); 59 | 60 | fclose(fp); 61 | return lines; 62 | } 63 | 64 | bool StartsWith(const char* prefix, const std::string& text) 65 | { 66 | size_t l = strlen(prefix); 67 | if (text.size() < l) 68 | return false; 69 | 70 | return strncmp(prefix, text.c_str(), l) == 0; 71 | } 72 | 73 | std::string ReadWord(const std::string& text, size_t& offset) 74 | { 75 | std::string value; 76 | while (offset < text.length()) 77 | { 78 | if (text.c_str()[offset] == ' ' || text.c_str()[offset] == ';' || text.c_str()[offset] == '/') 79 | return value; 80 | else 81 | value += text.c_str()[offset++]; 82 | } 83 | 84 | return value; 85 | } 86 | 87 | bool ParseUniformLine(const std::string& text, std::string& uniformType, std::string& uniformName) 88 | { 89 | size_t offset = 8; 90 | uniformType = ReadWord(text, offset); 91 | ++offset; 92 | 93 | uniformName = ReadWord(text, offset); 94 | 95 | return uniformName.size() > 0 && uniformType.size(); 96 | } 97 | 98 | UniformTypes ClassifyUniformType(const std::string& str) 99 | { 100 | if (str == "bool") 101 | return UniformTypes::Bool; 102 | if (str == "int") 103 | return UniformTypes::Int; 104 | if (str == "float") 105 | return UniformTypes::Float; 106 | if (str == "vec2") 107 | return UniformTypes::Vec2; 108 | if (str == "vec3") 109 | return UniformTypes::Vec3; 110 | if (str == "vec4") 111 | return UniformTypes::Vec4; 112 | if (str == "mat4") 113 | return UniformTypes::Mat4; 114 | if (str == "sampler2D") 115 | return UniformTypes::Sampler2D; 116 | if (str == "samplerCube") 117 | return UniformTypes::SamplerCube; 118 | 119 | return UniformTypes::Unknown; 120 | } 121 | 122 | void ParseUniforms(const char* filename, ShaderInfo& shaderInfo) 123 | { 124 | std::vector lines = GetFileLines(filename); 125 | for (std::string& line : lines) 126 | { 127 | if (!StartsWith("uniform ",line)) 128 | continue; 129 | 130 | std::string uniformType, uniformName; 131 | if (ParseUniformLine(line, uniformType, uniformName)) 132 | { 133 | UniformInfo info; 134 | info.UniformType = ClassifyUniformType(uniformType); 135 | info.Name = uniformName; 136 | 137 | shaderInfo.Uniforms.emplace_back(std::move(info)); 138 | } 139 | } 140 | } 141 | 142 | void ParseShader(const char* filename, ShaderInfo& shaderInfo) 143 | { 144 | shaderInfo.Name = GetFileNameWithoutExt(filename); 145 | shaderInfo.PathName = filename; 146 | 147 | ParseUniforms(filename, shaderInfo); 148 | } 149 | 150 | void ShaderManager::Clear() 151 | { 152 | ShaderCache.clear(); 153 | } 154 | 155 | ShaderInstance& ShaderManager::GetShader(int materialIndex) 156 | { 157 | return ShaderCache[materialIndex]; 158 | } 159 | 160 | ShaderInstance& ShaderManager::LoadShader(int materialIndex, const char* vertextShaderPath, const char* fragmentShaderPath) 161 | { 162 | ShaderInstance newInstance; 163 | if (vertextShaderPath == nullptr) 164 | { 165 | newInstance.VertexShader.Name = "Default"; 166 | newInstance.VertexShader.PathName = ""; 167 | } 168 | else 169 | { 170 | ParseShader(vertextShaderPath, newInstance.VertexShader); 171 | } 172 | 173 | if (fragmentShaderPath == nullptr) 174 | { 175 | newInstance.FragmentShader.Name = "Default"; 176 | newInstance.FragmentShader.PathName = ""; 177 | } 178 | else 179 | { 180 | ParseShader(fragmentShaderPath, newInstance.FragmentShader); 181 | } 182 | 183 | std::map::iterator itr = ShaderCache.find(materialIndex); 184 | 185 | if (itr != ShaderCache.end()) 186 | { 187 | UnloadShader(itr->second.RaylibShader); 188 | ShaderCache.erase(itr); 189 | } 190 | 191 | newInstance.RaylibShader = ::LoadShader(vertextShaderPath, fragmentShaderPath); 192 | 193 | ShaderCache[materialIndex] = newInstance; 194 | 195 | return ShaderCache[materialIndex]; 196 | } -------------------------------------------------------------------------------- /Application/main_view.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "raylib.h" 34 | #include "FPCamera.h" 35 | #include "imgui.h" 36 | 37 | class InspectorWindow; 38 | 39 | class MainView 40 | { 41 | public: 42 | MainView(); 43 | virtual ~MainView() = default; 44 | 45 | inline virtual const char* GetName() { return nullptr; } 46 | virtual void Setup() {} 47 | 48 | virtual void Update(); 49 | virtual void Show(const Rectangle& contentArea); 50 | virtual void ResizeContentArea(const Rectangle& contentArea); 51 | 52 | virtual void Shutdown(); 53 | 54 | inline virtual const char* GetViewName() const { return nullptr; } 55 | inline virtual Vector3 GetViewPos() const { return Vector3{ 0,0,0 }; } 56 | inline virtual Vector2 GetViewOrientation() const { return Vector2{ 0,0 }; } 57 | 58 | virtual void ShowInspectorContents(const InspectorWindow& window) {} 59 | 60 | // menu functions 61 | inline virtual void OnFileMenu() {} 62 | inline virtual void OnMenuBar() {} 63 | inline virtual void OnToolsMenu() {} 64 | 65 | inline Vector2 GetViewMousePosition() 66 | { 67 | Vector2 pos = GetMousePosition(); 68 | 69 | pos.x -= LastContentArea.x; 70 | pos.y -= LastContentArea.y; 71 | return pos; 72 | } 73 | 74 | inline Vector2 GetMouseDelta() 75 | { 76 | Vector2 pos = GetMousePosition(); 77 | 78 | pos.x -= LastMousePos.x; 79 | pos.y -= LastMousePos.y; 80 | return pos; 81 | } 82 | 83 | public: 84 | Rectangle LastContentArea = { 0 }; 85 | 86 | std::vector> OpenFileExtensions; 87 | 88 | protected: 89 | virtual void OnShow(const Rectangle& contentArea); 90 | 91 | bool OpenFileMenu(std::string& filename); 92 | 93 | private: 94 | Vector2 LastMousePos = { 0,0 }; 95 | 96 | }; 97 | 98 | class ThreeDView : public MainView 99 | { 100 | protected: 101 | RenderTexture SceneTexture = { 0 }; 102 | 103 | FPCamera Camera; 104 | TextureCubemap SkyboxTexture = { 0 }; 105 | Model Skybox = { 0 }; 106 | 107 | // options 108 | std::string SkyboxResource = "Daylight Box UV.png"; 109 | 110 | bool ShowSkybox = true; 111 | bool ShowGround = true; 112 | bool ShowOrigin = true; 113 | 114 | virtual void OnSetup() {} 115 | virtual void OnShutdown() {} 116 | virtual void OnShowInspector(const InspectorWindow& window) {} 117 | inline virtual void OnUpdate() {}; 118 | public: 119 | void Setup() override; 120 | void Shutdown() override; 121 | void Show(const Rectangle& contentArea) override; 122 | void ResizeContentArea(const Rectangle& contentArea) override; 123 | void ShowInspectorContents(const InspectorWindow& window) override; 124 | 125 | inline void Update() override { OnUpdate(); } 126 | protected: 127 | void DrawGizmo(float scale = 1); 128 | void SetupSkybox(); 129 | void DrawSkybox(); 130 | void DrawDefaultScene(); 131 | }; 132 | 133 | // 2d View 134 | 135 | class TwoDView : public MainView 136 | { 137 | protected: 138 | virtual void OnSetup() {} 139 | virtual void OnShutdown() {} 140 | virtual void OnShowInspector(const InspectorWindow& window) {} 141 | inline virtual void OnUpdate() {}; 142 | 143 | public: 144 | void Setup() override; 145 | 146 | virtual void Shutdown(); 147 | 148 | void Update() override; 149 | virtual void Show(const Rectangle& contentArea); 150 | void ResizeContentArea(const Rectangle& contentArea) override; 151 | 152 | inline Vector3 GetViewPos() const override { return Vector3{ Camera.target.x, Camera.target.y, 0 }; } 153 | inline Vector2 GetViewOrientation() const override { return Vector2{ Camera.rotation, 0 }; } 154 | 155 | inline Vector2 GetWorldMousePos() 156 | { 157 | Vector2 pos = GetViewMousePosition(); 158 | return GetScreenToWorld2D(pos, Camera); 159 | } 160 | 161 | void ShowInspectorContents(const InspectorWindow& window) override; 162 | 163 | protected: 164 | virtual void OnShow(const Rectangle& contentArea) {} 165 | 166 | protected: 167 | RenderTexture SceneTexture = { 0 }; 168 | Camera2D Camera = { 0 }; 169 | 170 | bool Dragging = false; 171 | Vector2 ClickPos = { 0,0 }; 172 | Vector2 ClickTarget = { 0,0 }; 173 | 174 | static const int MaxZoomLevels = 14; 175 | float ZoomLevels[MaxZoomLevels] = { 0.125f, 0.25f, 0.5f, 1, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f }; 176 | int ZoomLevel = 3; 177 | }; 178 | 179 | 180 | RLAPI Shader SetModelMaterialShader(Model* model, int materialIndex, Shader shader); 181 | RLAPI void SetModelMaterialShaderValue(Model* model, int materialIndex, const char* location, const void* value, int uniformType); 182 | RLAPI void SetModelMaterialShaderValueV(Model* model, int materialIndex, const char* location, const void* value, int uniformType, int count); 183 | RLAPI void SetModelMaterialTexture(Model* model, int materialIndex, int maptype, Texture2D texture); 184 | 185 | RLAPI Shader LoadShaderSet(const char* resourcePath, const char* name); 186 | RLAPI Shader LoadShaders(const char* resourcePath, const char* vsName, const char* fsName); -------------------------------------------------------------------------------- /Application/drawing_utils.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "raylib.h" 34 | #include "rlgl.h" 35 | #include "RaylibColors.h" 36 | 37 | #include 38 | 39 | 40 | namespace VectorTools 41 | { 42 | inline Vector2 HalfVector(const Vector2& vector) 43 | { 44 | return Vector2{ vector.x * 0.5f, vector.y * 0.5f }; 45 | } 46 | 47 | inline Vector3 HalfVector(const Vector3& vector) 48 | { 49 | return Vector3{ vector.x * 0.5f, vector.y * 0.5f, vector.z * 0.5f }; 50 | } 51 | } 52 | 53 | namespace RectTools 54 | { 55 | inline float MaxSize(const Rectangle& rect) 56 | { 57 | return std::max(rect.width, rect.height); 58 | } 59 | 60 | inline Vector2 CenterSize(const Rectangle& rect) 61 | { 62 | return Vector2{ rect.width / 2,rect.height / 2 }; 63 | } 64 | } 65 | 66 | namespace ScreenTools 67 | { 68 | inline Vector2 Center() 69 | { 70 | return Vector2{ GetScreenWidth() * 0.5f, GetScreenHeight() * 0.5f }; 71 | } 72 | 73 | inline Vector3 Center3D() 74 | { 75 | return Vector3{ GetScreenWidth() * 0.5f, GetScreenHeight() * 0.5f, 0 }; 76 | } 77 | } 78 | namespace DrawUtils 79 | { 80 | // Draw a grid centered at (0, 0, 0) 81 | inline void DrawGridXZ(Vector3 origin, float slices, float spacing, Color gridColor = Colors::LightGray, Color axisColor = Colors::DarkGray) 82 | { 83 | float halfSlices = slices / 2; 84 | 85 | rlCheckRenderBatchLimit(((int)slices + 2) * 4); 86 | 87 | rlPushMatrix(); 88 | rlTranslatef(origin.x, origin.y, origin.z); 89 | rlBegin(RL_LINES); 90 | for (float i = -halfSlices; i <= halfSlices; i++) 91 | { 92 | if (i == 0) 93 | { 94 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 95 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 96 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 97 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 98 | } 99 | else 100 | { 101 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 102 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 103 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 104 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 105 | } 106 | 107 | rlVertex3f(i * spacing, 0.0f, -halfSlices * spacing); 108 | rlVertex3f(i * spacing, 0.0f, halfSlices * spacing); 109 | 110 | rlVertex3f(-halfSlices * spacing, 0.0f, i * spacing); 111 | rlVertex3f(halfSlices * spacing, 0.0f, i * spacing); 112 | } 113 | rlEnd(); 114 | rlPopMatrix(); 115 | } 116 | 117 | inline void DrawGridXY(Vector3 origin, float slices, float spacing, Color gridColor = Colors::LightGray, Color axisColor = Colors::DarkGray) 118 | { 119 | float halfSlices = slices / 2; 120 | 121 | rlCheckRenderBatchLimit(((int)slices + 2) * 4); 122 | 123 | rlPushMatrix(); 124 | rlTranslatef(origin.x, origin.y, origin.z); 125 | rlBegin(RL_LINES); 126 | for (float i = -halfSlices; i <= halfSlices; i++) 127 | { 128 | if (i == 0) 129 | { 130 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 131 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 132 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 133 | rlColor4ub(axisColor.r, axisColor.g, axisColor.b, axisColor.a); 134 | } 135 | else 136 | { 137 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 138 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 139 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 140 | rlColor4ub(gridColor.r, gridColor.g, gridColor.b, gridColor.a); 141 | } 142 | 143 | rlVertex3f(i * spacing, -halfSlices * spacing, 0.0f); 144 | rlVertex3f(i * spacing, halfSlices * spacing, 0.0f); 145 | 146 | rlVertex3f(-halfSlices * spacing, i * spacing, 0.0f); 147 | rlVertex3f(halfSlices * spacing, i * spacing, 0.0f); 148 | } 149 | rlEnd(); 150 | rlPopMatrix(); 151 | } 152 | 153 | inline void DrawGrid2D(Vector2 origin, int slices, int spacing, Color gridColor = Colors::LightGray, Color axisColor = Colors::Gray) 154 | { 155 | int halfSlices = slices / 2; 156 | 157 | rlPushMatrix(); 158 | rlTranslatef(origin.x, origin.y, 0); 159 | 160 | for (int i = -halfSlices; i <= halfSlices; i++) 161 | { 162 | Color color = gridColor; 163 | if (i == 0) 164 | color = axisColor; 165 | 166 | DrawLine(i * spacing, -halfSlices * spacing, i * spacing, halfSlices * spacing, color); 167 | DrawLine(-halfSlices * spacing, i * spacing, halfSlices * spacing, i * spacing, color); 168 | 169 | } 170 | rlPopMatrix(); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /Application/model_outliner.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #include "ui_window.h" 34 | 35 | #include "raylib.h" 36 | #include "rlImGui.h" 37 | #include "raylib.h" 38 | 39 | 40 | constexpr char ModelOutlinerWindowName[] = " Model Outline###RaylibModelOutlinerWindow"; 41 | 42 | class ModelOutlinerWindow : public UIWindow 43 | { 44 | protected: 45 | Model& ModelFile; 46 | bool ShowEmptyMaps = false; 47 | 48 | public: 49 | int SelectedMesh = -1; 50 | int SelectedMaterial = -1; 51 | int SelectedMaterialMap = -1; 52 | 53 | ModelOutlinerWindow(Model& model) 54 | : UIWindow() 55 | , ModelFile(model) 56 | { 57 | Shown = true; 58 | } 59 | 60 | inline void GetName(std::string& name, MainView* view) const override 61 | { 62 | name = ModelOutlinerWindowName; 63 | } 64 | 65 | inline void SetModel(Model& model) 66 | { 67 | ModelFile = model; 68 | SelectedMesh = -1; 69 | SelectedMaterial = -1; 70 | SelectedMaterialMap = -1; 71 | } 72 | 73 | inline const char* GetMenuName() const override { return "Outline"; } 74 | 75 | inline void ShowMaterialMapTreeItem(const MaterialMap& mapItem, const char* name, int materialIndex, int mapIndex) 76 | { 77 | bool selected = (SelectedMaterial == materialIndex && SelectedMaterialMap == mapIndex); 78 | 79 | char* suffix = ""; 80 | 81 | ImGuiSelectableFlags flags = ImGuiSelectableFlags_None; 82 | if (mapItem.texture.id == 0) 83 | { 84 | if (!ShowEmptyMaps) 85 | return; 86 | else 87 | suffix = "(*)"; 88 | } 89 | 90 | if (ImGui::Selectable(TextFormat("%s%s###mat%d-map%d", name,suffix, materialIndex, mapIndex ), &selected, flags)) 91 | { 92 | SelectedMesh = -1; 93 | SelectedMaterial = materialIndex; 94 | SelectedMaterialMap = mapIndex; 95 | } 96 | } 97 | 98 | inline void OnShow(MainView* view) override 99 | { 100 | if (ImGui::BeginChild("ModelTree", ImVec2(ImGui::GetContentRegionAvailWidth(), ImGui::GetContentRegionAvail().y - 30), true)) 101 | { 102 | bool selected = false; 103 | if (ImGui::TreeNodeEx("Model Tree", ImGuiTreeNodeFlags_DefaultOpen)) 104 | { 105 | if (ImGui::TreeNodeEx("Meshes", ImGuiTreeNodeFlags_DefaultOpen)) 106 | { 107 | for (int i = 0; i < ModelFile.meshCount; i++) 108 | { 109 | selected = SelectedMesh == i; 110 | if (ImGui::Selectable(TextFormat("%d###mesh%d", i, i), &selected, ImGuiSelectableFlags_None)) 111 | { 112 | SelectedMesh = i; 113 | SelectedMaterial = -1; 114 | SelectedMaterialMap = -1; 115 | } 116 | } 117 | ImGui::TreePop(); 118 | } 119 | 120 | if (ImGui::TreeNodeEx("Materials", ImGuiTreeNodeFlags_DefaultOpen)) 121 | { 122 | for (int i = 0; i < ModelFile.materialCount; i++) 123 | { 124 | Material& mat = ModelFile.materials[i]; 125 | 126 | if (ImGui::TreeNodeEx(TextFormat("%d###material%d", i, i), ImGuiTreeNodeFlags_DefaultOpen)) 127 | { 128 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_ALBEDO], "Albedo", i, MATERIAL_MAP_ALBEDO); 129 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_METALNESS], "Metalness", i, MATERIAL_MAP_METALNESS); 130 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_NORMAL], "Normal", i, MATERIAL_MAP_NORMAL); 131 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_ROUGHNESS], "Roughness", i, MATERIAL_MAP_ROUGHNESS); 132 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_OCCLUSION], "Occlusion", i, MATERIAL_MAP_OCCLUSION); 133 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_EMISSION], "Emission", i, MATERIAL_MAP_EMISSION); 134 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_HEIGHT], "Height", i, MATERIAL_MAP_HEIGHT); 135 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_CUBEMAP], "CubeMap", i, MATERIAL_MAP_CUBEMAP); 136 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_IRRADIANCE], "Irradiance", i, MATERIAL_MAP_IRRADIANCE); 137 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_PREFILTER], "Prefilter", i, MATERIAL_MAP_PREFILTER); 138 | ShowMaterialMapTreeItem(mat.maps[MATERIAL_MAP_BRDG], "BRDG", i, MATERIAL_MAP_BRDG); 139 | ImGui::TreePop(); 140 | } 141 | if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) 142 | SelectedMaterial = i; 143 | } 144 | ImGui::TreePop(); 145 | } 146 | 147 | ImGui::TreePop(); 148 | } 149 | ImGui::EndChild(); 150 | } 151 | ImGui::Checkbox("Show Empty Maps", &ShowEmptyMaps); 152 | } 153 | }; 154 | -------------------------------------------------------------------------------- /clip/clip_x11_png.h: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2018-2021 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "clip.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "png.h" 13 | 14 | namespace clip { 15 | namespace x11 { 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | // Functions to convert clip::image into png data to store it in the 19 | // clipboard. 20 | 21 | void write_data_fn(png_structp png, png_bytep buf, png_size_t len) { 22 | std::vector& output = *(std::vector*)png_get_io_ptr(png); 23 | const size_t i = output.size(); 24 | output.resize(i+len); 25 | std::copy(buf, buf+len, output.begin()+i); 26 | } 27 | 28 | bool write_png(const image& image, 29 | std::vector& output) { 30 | png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 31 | nullptr, nullptr, nullptr); 32 | if (!png) 33 | return false; 34 | 35 | png_infop info = png_create_info_struct(png); 36 | if (!info) { 37 | png_destroy_write_struct(&png, nullptr); 38 | return false; 39 | } 40 | 41 | if (setjmp(png_jmpbuf(png))) { 42 | png_destroy_write_struct(&png, &info); 43 | return false; 44 | } 45 | 46 | png_set_write_fn(png, 47 | (png_voidp)&output, 48 | write_data_fn, 49 | nullptr); // No need for a flush function 50 | 51 | const image_spec& spec = image.spec(); 52 | int color_type = (spec.alpha_mask ? 53 | PNG_COLOR_TYPE_RGB_ALPHA: 54 | PNG_COLOR_TYPE_RGB); 55 | 56 | png_set_IHDR(png, info, 57 | spec.width, spec.height, 8, color_type, 58 | PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 59 | png_write_info(png, info); 60 | png_set_packing(png); 61 | 62 | png_bytep row = 63 | (png_bytep)png_malloc(png, png_get_rowbytes(png, info)); 64 | 65 | for (png_uint_32 y=0; y> spec.red_shift; 75 | *(dst++) = (c & spec.green_mask) >> spec.green_shift; 76 | *(dst++) = (c & spec.blue_mask ) >> spec.blue_shift; 77 | if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) 78 | *(dst++) = (c & spec.alpha_mask) >> spec.alpha_shift; 79 | } 80 | 81 | png_write_rows(png, &row, 1); 82 | } 83 | 84 | png_free(png, row); 85 | png_write_end(png, info); 86 | png_destroy_write_struct(&png, &info); 87 | return true; 88 | } 89 | 90 | ////////////////////////////////////////////////////////////////////// 91 | // Functions to convert png data stored in the clipboard to a 92 | // clip::image. 93 | 94 | struct read_png_io { 95 | const uint8_t* buf; 96 | size_t len; 97 | size_t pos; 98 | }; 99 | 100 | void read_data_fn(png_structp png, png_bytep buf, png_size_t len) { 101 | read_png_io& io = *(read_png_io*)png_get_io_ptr(png); 102 | if (io.pos < io.len) { 103 | size_t n = std::min(len, io.len-io.pos); 104 | if (n > 0) { 105 | std::copy(io.buf+io.pos, 106 | io.buf+io.pos+n, 107 | buf); 108 | io.pos += n; 109 | } 110 | } 111 | } 112 | 113 | bool read_png(const uint8_t* buf, 114 | const size_t len, 115 | image* output_image, 116 | image_spec* output_spec) { 117 | png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 118 | nullptr, nullptr, nullptr); 119 | if (!png) 120 | return false; 121 | 122 | png_infop info = png_create_info_struct(png); 123 | if (!info) { 124 | png_destroy_read_struct(&png, nullptr, nullptr); 125 | return false; 126 | } 127 | 128 | if (setjmp(png_jmpbuf(png))) { 129 | png_destroy_read_struct(&png, &info, nullptr); 130 | return false; 131 | } 132 | 133 | read_png_io io = { buf, len, 0 }; 134 | png_set_read_fn(png, (png_voidp)&io, read_data_fn); 135 | 136 | png_read_info(png, info); 137 | 138 | png_uint_32 width, height; 139 | int bit_depth, color_type, interlace_type; 140 | png_get_IHDR(png, info, &width, &height, 141 | &bit_depth, &color_type, 142 | &interlace_type, 143 | nullptr, nullptr); 144 | 145 | image_spec spec; 146 | spec.width = width; 147 | spec.height = height; 148 | spec.bits_per_pixel = 32; 149 | 150 | // Don't use png_get_rowbytes(png, info) here because this is the 151 | // bytes_per_row of the output clip::image (the png file could 152 | // contain 24bpp but we want to return a 32bpp anyway with alpha=255 153 | // in that case). 154 | spec.bytes_per_row = 4*width; 155 | 156 | spec.red_mask = 0x000000ff; 157 | spec.green_mask = 0x0000ff00; 158 | spec.blue_mask = 0x00ff0000; 159 | spec.red_shift = 0; 160 | spec.green_shift = 8; 161 | spec.blue_shift = 16; 162 | 163 | if ((color_type & PNG_COLOR_MASK_ALPHA) == PNG_COLOR_MASK_ALPHA) { 164 | spec.alpha_mask = 0xff000000; 165 | spec.alpha_shift = 24; 166 | } 167 | else { 168 | spec.alpha_mask = 0; 169 | spec.alpha_shift = 0; 170 | } 171 | 172 | if (output_spec) 173 | *output_spec = spec; 174 | 175 | if (output_image && 176 | width > 0 && 177 | height > 0) { 178 | image img(spec); 179 | 180 | // We want RGB 24-bit or RGBA 32-bit as a result 181 | png_set_strip_16(png); // Down to 8-bit (TODO we might support 16-bit values) 182 | png_set_packing(png); // Use one byte if color depth < 8-bit 183 | png_set_expand_gray_1_2_4_to_8(png); 184 | png_set_palette_to_rgb(png); 185 | png_set_gray_to_rgb(png); 186 | png_set_tRNS_to_alpha(png); 187 | 188 | int number_passes = png_set_interlace_handling(png); 189 | png_read_update_info(png, info); 190 | 191 | const int src_bytes_per_row = png_get_rowbytes(png, info); 192 | png_bytepp rows = (png_bytepp)png_malloc(png, sizeof(png_bytep)*height); 193 | png_uint_32 y; 194 | for (y=0; y 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace clip { 16 | namespace win { 17 | 18 | // Successful calls to CoInitialize() (S_OK or S_FALSE) must match 19 | // the calls to CoUninitialize(). 20 | // From: https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-couninitialize#remarks 21 | struct coinit { 22 | HRESULT hr; 23 | coinit() { 24 | hr = CoInitialize(nullptr); 25 | } 26 | ~coinit() { 27 | if (hr == S_OK || hr == S_FALSE) 28 | CoUninitialize(); 29 | } 30 | }; 31 | 32 | template 33 | class comptr { 34 | public: 35 | comptr() : m_ptr(nullptr) { } 36 | explicit comptr(T* ptr) : m_ptr(ptr) { } 37 | comptr(const comptr&) = delete; 38 | comptr& operator=(const comptr&) = delete; 39 | ~comptr() { reset(); } 40 | 41 | T** operator&() { return &m_ptr; } 42 | T* operator->() { return m_ptr; } 43 | bool operator!() const { return !m_ptr; } 44 | 45 | T* get() { return m_ptr; } 46 | void reset() { 47 | if (m_ptr) { 48 | m_ptr->Release(); 49 | m_ptr = nullptr; 50 | } 51 | } 52 | private: 53 | T* m_ptr; 54 | }; 55 | 56 | ////////////////////////////////////////////////////////////////////// 57 | // Encode the image as PNG format 58 | 59 | bool write_png_on_stream(const image& image, 60 | IStream* stream) { 61 | const image_spec& spec = image.spec(); 62 | 63 | comptr encoder; 64 | HRESULT hr = CoCreateInstance(CLSID_WICPngEncoder, 65 | nullptr, CLSCTX_INPROC_SERVER, 66 | IID_PPV_ARGS(&encoder)); 67 | if (FAILED(hr)) 68 | return false; 69 | 70 | hr = encoder->Initialize(stream, WICBitmapEncoderNoCache); 71 | if (FAILED(hr)) 72 | return false; 73 | 74 | comptr frame; 75 | comptr options; 76 | hr = encoder->CreateNewFrame(&frame, &options); 77 | if (FAILED(hr)) 78 | return false; 79 | 80 | hr = frame->Initialize(options.get()); 81 | if (FAILED(hr)) 82 | return false; 83 | 84 | // PNG encoder (and decoder) only supports GUID_WICPixelFormat32bppBGRA for 32bpp. 85 | // See: https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats#png-native-codec 86 | WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat32bppBGRA; 87 | hr = frame->SetPixelFormat(&pixelFormat); 88 | if (FAILED(hr)) 89 | return false; 90 | 91 | hr = frame->SetSize(spec.width, spec.height); 92 | if (FAILED(hr)) 93 | return false; 94 | 95 | std::vector buf; 96 | uint8_t* ptr = (uint8_t*)image.data(); 97 | int bytes_per_row = spec.bytes_per_row; 98 | 99 | // Convert to GUID_WICPixelFormat32bppBGRA if needed 100 | if (spec.red_mask != 0xff0000 || 101 | spec.green_mask != 0xff00 || 102 | spec.blue_mask != 0xff || 103 | spec.alpha_mask != 0xff000000) { 104 | buf.resize(spec.width * spec.height); 105 | uint32_t* dst = (uint32_t*)&buf[0]; 106 | uint32_t* src = (uint32_t*)image.data(); 107 | for (int y=0; y> spec.red_shift ) << 16) | 112 | (((c & spec.green_mask) >> spec.green_shift) << 8) | 113 | (((c & spec.blue_mask ) >> spec.blue_shift ) ) | 114 | (((c & spec.alpha_mask) >> spec.alpha_shift) << 24)); 115 | ++dst; 116 | ++src; 117 | } 118 | src = (uint32_t*)(((uint8_t*)src_line_start) + spec.bytes_per_row); 119 | } 120 | ptr = (uint8_t*)&buf[0]; 121 | bytes_per_row = 4 * spec.width; 122 | } 123 | 124 | hr = frame->WritePixels(spec.height, 125 | bytes_per_row, 126 | bytes_per_row * spec.height, 127 | (BYTE*)ptr); 128 | if (FAILED(hr)) 129 | return false; 130 | 131 | hr = frame->Commit(); 132 | if (FAILED(hr)) 133 | return false; 134 | 135 | hr = encoder->Commit(); 136 | if (FAILED(hr)) 137 | return false; 138 | 139 | return true; 140 | } 141 | 142 | HGLOBAL write_png(const image& image) { 143 | coinit com; 144 | 145 | comptr stream; 146 | HRESULT hr = CreateStreamOnHGlobal(nullptr, false, &stream); 147 | if (FAILED(hr)) 148 | return nullptr; 149 | 150 | bool result = write_png_on_stream(image, stream.get()); 151 | 152 | HGLOBAL handle; 153 | hr = GetHGlobalFromStream(stream.get(), &handle); 154 | if (result) 155 | return handle; 156 | 157 | GlobalFree(handle); 158 | return nullptr; 159 | } 160 | 161 | ////////////////////////////////////////////////////////////////////// 162 | // Decode the clipboard data from PNG format 163 | 164 | bool read_png(const uint8_t* buf, 165 | const UINT len, 166 | image* output_image, 167 | image_spec* output_spec) { 168 | coinit com; 169 | 170 | comptr stream(SHCreateMemStream(buf, len)); 171 | if (!stream) 172 | return false; 173 | 174 | comptr decoder; 175 | HRESULT hr = CoCreateInstance(CLSID_WICPngDecoder2, 176 | nullptr, CLSCTX_INPROC_SERVER, 177 | IID_PPV_ARGS(&decoder)); 178 | if (FAILED(hr)) { 179 | hr = CoCreateInstance(CLSID_WICPngDecoder1, 180 | nullptr, CLSCTX_INPROC_SERVER, 181 | IID_PPV_ARGS(&decoder)); 182 | if (FAILED(hr)) 183 | return false; 184 | } 185 | 186 | hr = decoder->Initialize(stream.get(), WICDecodeMetadataCacheOnDemand); 187 | if (FAILED(hr)) 188 | return false; 189 | 190 | comptr frame; 191 | hr = decoder->GetFrame(0, &frame); 192 | if (FAILED(hr)) 193 | return false; 194 | 195 | WICPixelFormatGUID pixelFormat; 196 | hr = frame->GetPixelFormat(&pixelFormat); 197 | if (FAILED(hr)) 198 | return false; 199 | 200 | // Only support this pixel format 201 | // TODO add support for more pixel formats 202 | if (pixelFormat != GUID_WICPixelFormat32bppBGRA) 203 | return false; 204 | 205 | UINT width = 0, height = 0; 206 | hr = frame->GetSize(&width, &height); 207 | if (FAILED(hr)) 208 | return false; 209 | 210 | image_spec spec; 211 | spec.width = width; 212 | spec.height = height; 213 | spec.bits_per_pixel = 32; 214 | spec.bytes_per_row = 4 * width; 215 | spec.red_mask = 0xff0000; 216 | spec.green_mask = 0xff00; 217 | spec.blue_mask = 0xff; 218 | spec.alpha_mask = 0xff000000; 219 | spec.red_shift = 16; 220 | spec.green_shift = 8; 221 | spec.blue_shift = 0; 222 | spec.alpha_shift = 24; 223 | 224 | if (output_spec) 225 | *output_spec = spec; 226 | 227 | if (output_image) { 228 | image img(spec); 229 | 230 | hr = frame->CopyPixels( 231 | nullptr, // Entire bitmap 232 | spec.bytes_per_row, 233 | spec.bytes_per_row * spec.height, 234 | (BYTE*)img.data()); 235 | if (FAILED(hr)) { 236 | return false; 237 | } 238 | 239 | std::swap(*output_image, img); 240 | } 241 | 242 | return true; 243 | } 244 | 245 | } // namespace win 246 | } // namespace clip 247 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | /GLMaze2/GLMaze2.exe 352 | /build/*.vcxproj 353 | /build/*.filters 354 | /Application/Application.vcxproj 355 | /Application/Application.vcxproj.filters 356 | /TestFrame.sln 357 | /TestFrame/Application.vcxproj 358 | /imgui.ini 359 | /premake5.exe 360 | /Application.vcxproj 361 | /Application.vcxproj.filters 362 | /clip/clip.vcxproj 363 | /clip/clip.vcxproj.filters 364 | -------------------------------------------------------------------------------- /Application/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "application_context.h" 32 | #include "application_ui.h" 33 | #include "main_view.h" 34 | 35 | #include "platform_tools.h" 36 | 37 | #include "raylib.h" 38 | #include "rlgl.h" 39 | #include "rlImGui.h" 40 | #include "RLAssets.h" 41 | 42 | #include 43 | 44 | ApplicationContext GlobalContext; 45 | 46 | void ApplicationContext::Screenshot() 47 | { 48 | if (GlobalContext.CopyScreenshot) 49 | { 50 | GlobalContext.CopyScreenshot = false; 51 | unsigned char* imgData = rlReadScreenPixels(GetScreenWidth(), GetScreenHeight()); 52 | Image image = { imgData, GetScreenWidth(), GetScreenHeight(), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; 53 | 54 | PlatformTools::CopyImageToClipboard(image); 55 | 56 | RL_FREE(imgData); 57 | TraceLog(LOG_INFO, "Copied Screenshot to Clipboard"); 58 | } 59 | 60 | if (GlobalContext.TakeScreenshot) 61 | { 62 | GlobalContext.TakeScreenshot = false; 63 | std::string path = PlatformTools::ShowSaveFileDialog(TextFormat("%d.png", GetRandomValue(1, 999999999))); 64 | if (path.size() > 0) 65 | ::TakeScreenshot(path.c_str()); 66 | } 67 | } 68 | 69 | void ApplicationContext::ChangeView(MainView* newView) 70 | { 71 | if (View != nullptr) 72 | View->Shutdown(); 73 | 74 | View = newView; 75 | if (View != nullptr) 76 | View->Setup(); 77 | 78 | if (View != nullptr) 79 | { 80 | Prefs.LastView = View->GetName(); 81 | Prefs.Save(); 82 | } 83 | } 84 | 85 | MainView* ApplicationContext::FindView(const char* name) 86 | { 87 | if (name == nullptr) 88 | return RegisteredViews[0]; 89 | 90 | std::string _name = name; 91 | for (MainView* view : RegisteredViews) 92 | { 93 | std::string _vName = view->GetName(); 94 | if (_name == _vName) 95 | return view; 96 | } 97 | 98 | return RegisteredViews[0]; 99 | } 100 | 101 | void ApplicationStartup(); 102 | void ApplicationShutdown(); 103 | 104 | bool ShowStartupLog = true; 105 | bool Start2D = false; 106 | 107 | #ifdef _WIN32 108 | int wWinMain(void* hInstance, void* hPrevInstance, char* cmdLine, int show) 109 | #else 110 | int main(int argc, char* argv[]) 111 | #endif 112 | { 113 | LogSink::Setup(); 114 | 115 | GlobalContext.Prefs.Setup(); 116 | 117 | unsigned int flags = FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE; 118 | 119 | if (GlobalContext.Prefs.Maximized) 120 | flags |= FLAG_WINDOW_MAXIMIZED; 121 | 122 | SetConfigFlags(flags); 123 | InitWindow(GlobalContext.Prefs.WindowWidth, GlobalContext.Prefs.WindowHeight, "TestBed Application"); 124 | 125 | if (GlobalContext.Prefs.Maximized) 126 | MaximizeWindow(); 127 | 128 | ApplicationStartup(); 129 | 130 | 131 | GlobalContext.ChangeView(GlobalContext.FindView(GlobalContext.Prefs.LastView.c_str())); 132 | GlobalContext.UI.Startup(); 133 | 134 | // Main game loop 135 | while (!GlobalContext.Quit && !WindowShouldClose()) // Detect window close button or ESC key 136 | { 137 | if (IsWindowResized()) 138 | GlobalContext.UI.Resized(); 139 | 140 | const Rectangle& contentArea = GlobalContext.UI.GetContentArea(); 141 | 142 | if (contentArea.x != GlobalContext.View->LastContentArea.x || contentArea.y != GlobalContext.View->LastContentArea.y || contentArea.width != GlobalContext.View->LastContentArea.width || contentArea.height != GlobalContext.View->LastContentArea.height) 143 | { 144 | GlobalContext.View->LastContentArea = contentArea; 145 | GlobalContext.View->ResizeContentArea(GlobalContext.View->LastContentArea); 146 | } 147 | 148 | GlobalContext.UI.Update(); 149 | GlobalContext.View->Update(); 150 | 151 | BeginDrawing(); 152 | ClearBackground(DARKGRAY); 153 | 154 | GlobalContext.View->Show(GlobalContext.View->LastContentArea); 155 | 156 | BeginRLImGui(); 157 | GlobalContext.UI.Show(GlobalContext.View); 158 | EndRLImGui(); 159 | 160 | EndDrawing(); 161 | 162 | if (!GlobalContext.ScreenshotView) 163 | ApplicationContext::Screenshot(); 164 | } 165 | 166 | GlobalContext.Prefs.Save(); 167 | 168 | GlobalContext.ChangeView(nullptr); 169 | GlobalContext.UI.Shutdown(); 170 | 171 | ApplicationShutdown(); 172 | 173 | ShutdownRLImGui(); 174 | CloseWindow(); 175 | } 176 | 177 | void ApplicationStartup() 178 | { 179 | if (!ShowStartupLog) 180 | LogSink::Flush(); 181 | 182 | TraceLog(LOG_INFO, "Testframe Startup"); 183 | 184 | rlas_SetAssetRootPath("resources/",false); 185 | 186 | InitRLGLImGui(); 187 | 188 | // load fonts here 189 | FinishRLGLImguSetup(); 190 | } 191 | 192 | void ApplicationShutdown() 193 | { 194 | rlas_Cleanup(); 195 | LogSink::Flush(); 196 | } 197 | 198 | namespace LogSink 199 | { 200 | std::deque LogLines; 201 | 202 | void GetLogLevelPrefix(int logLevel, LogItem& item) 203 | { 204 | item.Prefix = GetLogLevelName(logLevel); 205 | item.Prefix += ": "; 206 | switch (logLevel) 207 | { 208 | default: item.Prefix.clear(); item.Color = ImGuiColors::Convert(WHITE); break; 209 | case LOG_TRACE: item.Color = ImGuiColors::Convert(GRAY); break; 210 | case LOG_DEBUG: item.Color = ImGuiColors::Convert(SKYBLUE); break; 211 | case LOG_INFO: item.Color = ImGuiColors::Convert(GREEN); break; 212 | case LOG_WARNING: item.Color = ImGuiColors::Convert(YELLOW); break; 213 | case LOG_ERROR: item.Color = ImGuiColors::Convert(ORANGE); break; 214 | case LOG_FATAL: item.Color = ImGuiColors::Convert(RED); break; 215 | } 216 | } 217 | 218 | void TraceLog(int logLevel, const char* text, va_list args) 219 | { 220 | static char logText[2048] = { 0 }; 221 | LogItem item; 222 | item.Level = logLevel; 223 | GetLogLevelPrefix(logLevel, item); 224 | vsprintf(logText, text, args); 225 | item.Text += logText; 226 | LogLines.push_back(item); 227 | } 228 | 229 | void Setup() 230 | { 231 | SetTraceLogCallback(TraceLog); 232 | } 233 | 234 | bool PopLogLine(LogItem& line) 235 | { 236 | if (LogLines.size() == 0) 237 | return false; 238 | 239 | line = LogLines.front(); 240 | LogLines.pop_front(); 241 | return true; 242 | } 243 | 244 | void Flush() 245 | { 246 | LogLines.clear(); 247 | } 248 | } -------------------------------------------------------------------------------- /Application/application_ui.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "application_ui.h" 32 | #include "common_utils.h" 33 | #include "inspector_window.h" 34 | #include "platform_tools.h" 35 | #include "ui_window.h" 36 | 37 | #include "RLAssets.h" 38 | #include "raylib.h" 39 | #include "rlgl.h" 40 | #include "rlImGui.h" 41 | #include "imgui_internal.h" 42 | 43 | void UIManager::Startup() 44 | { 45 | ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable; 46 | ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = true; 47 | 48 | ImGui::GetStyle().WindowMenuButtonPosition = ImGuiDir_Right; 49 | 50 | ImGui::StyleColorsDark(); 51 | 52 | AddWindow(std::make_shared()); 53 | AddWindow(std::make_shared()); 54 | } 55 | 56 | void UIManager::Shutdown() 57 | { 58 | for (auto& window : Windows) 59 | window->Shutdown(); 60 | 61 | Windows.clear(); 62 | } 63 | 64 | void UIManager::AddWindow(std::shared_ptr window) 65 | { 66 | Windows.emplace_back(window); 67 | } 68 | 69 | void UIManager::RemoveWindow(std::shared_ptr window) 70 | { 71 | std::vector>::iterator itr = std::find(Windows.begin(), Windows.end(), window); 72 | if (itr != Windows.end()) 73 | Windows.erase(itr); 74 | } 75 | 76 | void UIManager::Resized() 77 | { 78 | for (auto& window : Windows) 79 | window->Resize(); 80 | } 81 | 82 | void UIManager::Show(MainView* view) 83 | { 84 | ImVec2 screenSize((float)GetScreenWidth(), (float)GetScreenHeight()); 85 | 86 | ImGui::SetNextWindowSize(screenSize, ImGuiCond_Always); 87 | ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); 88 | 89 | ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2()); 90 | 91 | if (ImGui::Begin("MainFrame", 92 | nullptr, 93 | ImGuiWindowFlags_MenuBar | 94 | ImGuiWindowFlags_NoDocking | 95 | ImGuiWindowFlags_NoBackground | 96 | ImGuiWindowFlags_NoDocking | 97 | ImGuiWindowFlags_NoMove | 98 | ImGuiWindowFlags_NoDecoration | 99 | ImGuiWindowFlags_NoSavedSettings)) 100 | { 101 | ImGui::PopStyleVar(); 102 | 103 | DockspaceId = ImGui::DockSpace(ImGui::GetID("MainWindowDock"), ImGui::GetContentRegionAvail(), ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingInCentralNode); 104 | 105 | if (ImGui::IsWindowAppearing()) 106 | SetupUI(); 107 | 108 | for (auto& window : Windows) 109 | window->Show(view); 110 | 111 | auto* rootNode = ImGui::DockBuilderGetNode(DockspaceId); 112 | if (rootNode != nullptr && rootNode->CentralNode != nullptr) 113 | { 114 | ContentArea.x = rootNode->CentralNode->Pos.x; 115 | ContentArea.y = rootNode->CentralNode->Pos.y; 116 | ContentArea.width = rootNode->CentralNode->Size.x; 117 | ContentArea.height = rootNode->CentralNode->Size.y; 118 | } 119 | ShowDebugWindows(); 120 | ShowMenu(); 121 | 122 | } 123 | else 124 | { 125 | ImGui::PopStyleVar(); 126 | } 127 | ImGui::End(); 128 | } 129 | 130 | void UIManager::Update() 131 | { 132 | for (auto& window : Windows) 133 | window->Update(); 134 | } 135 | 136 | void UIManager::SetupUI() 137 | { 138 | auto* rootNode = ImGui::DockBuilderGetNode(DockspaceId); 139 | if (rootNode == nullptr || rootNode->ChildNodes[0] == nullptr) 140 | { 141 | ImGuiID centralNode = DockspaceId; 142 | auto rightId = ImGui::DockBuilderSplitNode(centralNode, ImGuiDir_Right, 0.25f, nullptr, ¢ralNode); 143 | 144 | auto childId = ImGui::DockBuilderSplitNode(centralNode, ImGuiDir_Down, 0.25f, nullptr, nullptr); 145 | 146 | ImGui::DockBuilderDockWindow(InspectorWindowName, rightId); 147 | ImGui::DockBuilderDockWindow(LogWindowName, childId); 148 | } 149 | } 150 | 151 | void UIManager::ShowMenu() 152 | { 153 | bool openAbout = false; 154 | bool copyScreenshot = false; 155 | 156 | if (ImGui::BeginMenuBar()) 157 | { 158 | if (ImGui::BeginMenu("File")) 159 | { 160 | GlobalContext.View->OnFileMenu(); 161 | 162 | if (ImGui::MenuItem("Exit", "Alt+F4")) 163 | GlobalContext.Quit = true; 164 | 165 | ImGui::EndMenu(); 166 | } 167 | GlobalContext.View->OnMenuBar(); 168 | 169 | if (ImGui::BeginMenu("Views")) 170 | { 171 | for (MainView* view : GlobalContext.RegisteredViews) 172 | { 173 | bool selected = view == GlobalContext.View; 174 | 175 | if (ImGui::MenuItem(view->GetName(), nullptr, &selected, !selected)) 176 | { 177 | GlobalContext.ChangeView(view); 178 | } 179 | } 180 | 181 | ImGui::EndMenu(); 182 | } 183 | 184 | if (ImGui::BeginMenu("Window")) 185 | { 186 | for (auto& window : Windows) 187 | { 188 | ImGui::MenuItem(window->GetMenuName(), nullptr, &window->Shown); 189 | } 190 | 191 | ImGui::EndMenu(); 192 | } 193 | 194 | if (ImGui::BeginMenu("Tools")) 195 | { 196 | if (ImGui::BeginMenu("ImGui")) 197 | { 198 | if (ImGui::MenuItem("Item Picker")) 199 | ImGui::DebugStartItemPicker(); 200 | 201 | ImGui::MenuItem("Style Editor", nullptr, &ShowStyleEditor); 202 | ImGui::MenuItem("Metrics", nullptr, &ShowMetricsWindow); 203 | ImGui::MenuItem("Demo", nullptr, &ShowDemoWindow); 204 | if (ImGui::MenuItem("About")) 205 | ShowAboutImGuiWindow = true; 206 | 207 | ImGui::EndMenu(); 208 | } 209 | ImGui::Separator(); 210 | 211 | if (ImGui::BeginMenu("Screenshot")) 212 | { 213 | if (ImGui::MenuItem("Save Screenshot...")) 214 | GlobalContext.TakeScreenshot = true; 215 | 216 | if (ImGui::MenuItem("Copy Screenshot", "F11")) 217 | GlobalContext.CopyScreenshot = true; 218 | 219 | ImGui::Separator(); 220 | if (ImGui::MenuItem("Save View Screenshot...")) 221 | GlobalContext.ScreenshotView = GlobalContext.TakeScreenshot = true; 222 | 223 | if (ImGui::MenuItem("Copy View Screenshot", "Shift+F11")) 224 | GlobalContext.ScreenshotView = GlobalContext.CopyScreenshot = true; 225 | 226 | ImGui::EndMenu(); 227 | } 228 | GlobalContext.View->OnToolsMenu(); 229 | ImGui::EndMenu(); 230 | } 231 | if (ImGui::BeginMenu("Help")) 232 | { 233 | if (ImGui::MenuItem("About")) 234 | openAbout = true; 235 | 236 | ImGui::EndMenu(); 237 | } 238 | 239 | ImGui::EndMenuBar(); 240 | 241 | if (openAbout) 242 | ImGui::OpenPopup("About Testframe"); 243 | 244 | if (ImGui::BeginPopupModal("About Testbed", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize)) 245 | { 246 | ImGui::TextUnformatted("Raylib Testframe Copyright 2021 Jeffery Myers"); 247 | ImGui::TextUnformatted("A Test frame for trying out things in raylib and Dear ImGui"); 248 | if (ImGui::Button("Ok")) 249 | ImGui::CloseCurrentPopup(); 250 | 251 | ImGui::EndPopup(); 252 | } 253 | } 254 | 255 | if (IsKeyPressed(KEY_F11)) 256 | { 257 | if (IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)) 258 | GlobalContext.ScreenshotView = true; 259 | 260 | GlobalContext.CopyScreenshot = true; 261 | } 262 | } 263 | 264 | void UIManager::ShowDebugWindows() 265 | { 266 | if (ShowStyleEditor) 267 | { 268 | auto& style = ImGui::GetStyle(); 269 | if (ImGui::Begin("Style Editor", &ShowStyleEditor)) 270 | { 271 | ImGui::ShowStyleEditor(&style); 272 | 273 | } 274 | ImGui::End(); 275 | } 276 | 277 | if (ShowMetricsWindow) 278 | ImGui::ShowMetricsWindow(&ShowMetricsWindow); 279 | 280 | if (ShowDemoWindow) 281 | ImGui::ShowDemoWindow(&ShowDemoWindow); 282 | 283 | if (ShowAboutImGuiWindow) 284 | ImGui::ShowAboutWindow(&ShowAboutImGuiWindow); 285 | } -------------------------------------------------------------------------------- /Application/views/ModelView/view.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raylibExtras * Utilities and Shared Components for Raylib 4 | * 5 | * Testframe - a Raylib/ImGui test framework 6 | * 7 | * LICENSE: ZLIB 8 | * 9 | * Copyright (c) 2021 Jeffery Myers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************************************/ 30 | 31 | #include "application_context.h" 32 | #include "drawing_utils.h" 33 | #include "inspector_window.h" 34 | #include "model_outliner.h" 35 | #include "platform_tools.h" 36 | #include "shader_manager.h" 37 | #include "texture_manager.h" 38 | 39 | #include "RaylibColors.h" 40 | 41 | #include "raylib.h" 42 | #include "rlgl.h" 43 | #include "raymath.h" 44 | 45 | #include 46 | 47 | class ModelViewer : public ThreeDView 48 | { 49 | protected: 50 | Model ModelFile = { 0 }; 51 | 52 | Model sphereModel = { 0 }; 53 | 54 | Texture DefaultTexture; 55 | 56 | TextureManager TextureCache; 57 | ShaderManager ShaderCache; 58 | 59 | std::vector> ImageExtensions; 60 | std::vector> VertexShaderExensions; 61 | std::vector> FragmentShaderExtensions; 62 | 63 | std::shared_ptr Outliner; 64 | 65 | public: 66 | ModelViewer() 67 | { 68 | OpenFileExtensions.push_back({ "obj files","obj" }); 69 | OpenFileExtensions.push_back({ "gltf(binary) files","glb" }); 70 | OpenFileExtensions.push_back({ "gltf files","gltf" }); 71 | OpenFileExtensions.push_back({ "iqm files","iqm" }); 72 | 73 | ImageExtensions.push_back({ "png files","png" }); 74 | ImageExtensions.push_back({ "bmp files","bmp" }); 75 | ImageExtensions.push_back({ "tga files","tga" }); 76 | ImageExtensions.push_back({ "hdr files","hdr" }); 77 | 78 | VertexShaderExensions.push_back({ "vs files","vs" }); 79 | FragmentShaderExtensions.push_back({ "fs files","fs" }); 80 | } 81 | inline const char* GetName() override { return "Model View"; } 82 | 83 | void OnSetup() override 84 | { 85 | Image checkerboard = GenImageChecked(512, 512, 64, 64, Colors::RayWhite, Colors::Gray); 86 | DefaultTexture = LoadTextureFromImage(checkerboard); 87 | UnloadImage(checkerboard); 88 | 89 | Mesh cube = GenMeshCube(2, 2, 2); 90 | ModelFile = LoadModelFromMesh(cube); 91 | ModelFile.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = DefaultTexture; 92 | 93 | ShaderCache.Clear(); 94 | ShaderCache.LoadShader(0, nullptr, nullptr); 95 | 96 | ModelFile.transform = MatrixTranslate(0, 1, 0); 97 | 98 | Camera.SetCameraPosition(Vector3{ 0, 1, -5 }); 99 | 100 | Outliner = std::make_shared(ModelFile); 101 | GlobalContext.UI.AddWindow(Outliner); 102 | 103 | sphereModel = LoadModelFromMesh(GenMeshSphere(1, 20, 20)); 104 | } 105 | 106 | void OnShutdown() override 107 | { 108 | GlobalContext.UI.RemoveWindow(Outliner); 109 | Outliner.reset(); 110 | UnloadModel(ModelFile); 111 | } 112 | 113 | void ShowUniformEditor(ShaderInfo& shader) 114 | { 115 | for (auto uniform : shader.Uniforms) 116 | { 117 | bool selected = false; 118 | ImGui::Selectable(uniform.Name.c_str(),selected); 119 | } 120 | } 121 | 122 | void OpenShaderFile(bool vertex, int materialIndex) 123 | { 124 | std::string filename = PlatformTools::ShowOpenFileDialog(vertex ? "*.vs" : "*.fs", vertex ? VertexShaderExensions : FragmentShaderExtensions); 125 | 126 | if (filename.size() == 0 || !FileExists(filename.c_str())) 127 | return; 128 | 129 | ShaderInstance& shader = ShaderCache.GetShader(materialIndex); 130 | if (vertex) 131 | ModelFile.materials[materialIndex].shader = ShaderCache.LoadShader(materialIndex, filename.c_str(), shader.FragmentShader.GetFileName()).RaylibShader; 132 | else 133 | ModelFile.materials[materialIndex].shader = ShaderCache.LoadShader(materialIndex, shader.VertexShader.GetFileName(), filename.c_str()).RaylibShader; 134 | } 135 | 136 | void OnShowInspector(const InspectorWindow& window) override 137 | { 138 | // mesh inspector 139 | if (Outliner->SelectedMesh >= 0) 140 | { 141 | Inspectors::ShowMeshInspector(ModelFile.meshes[Outliner->SelectedMesh]); 142 | } 143 | 144 | // material inspector 145 | if (Outliner->SelectedMaterial >= 0) 146 | { 147 | // shader 148 | 149 | auto shader = ShaderCache.GetShader(Outliner->SelectedMaterial); 150 | 151 | ImGui::TextUnformatted("Shader"); 152 | ImGui::Text("Vertex: %s", shader.VertexShader.Name.c_str()); 153 | ImGui::SameLine(); 154 | if (ImGui::Button("Set###SetVertexShader")) 155 | { 156 | OpenShaderFile(true, Outliner->SelectedMaterial); 157 | } 158 | ImGui::SameLine(); 159 | if (ImGui::Button("Clear###ClearVertexShader")) 160 | { 161 | ShaderInstance& shader = ShaderCache.GetShader(Outliner->SelectedMaterial); 162 | ModelFile.materials[Outliner->SelectedMaterial].shader = ShaderCache.LoadShader(Outliner->SelectedMaterial, nullptr, shader.FragmentShader.GetFileName()).RaylibShader; 163 | } 164 | ShowUniformEditor(shader.VertexShader); 165 | 166 | ImGui::Text("Fragment: %s", shader.FragmentShader.Name.c_str()); 167 | ImGui::SameLine(); 168 | if (ImGui::Button("Set###SetFragmentShader")) 169 | { 170 | OpenShaderFile(false, Outliner->SelectedMaterial); 171 | } 172 | ImGui::SameLine(); 173 | if (ImGui::Button("Clear###ClearFragmentShader")) 174 | { 175 | ShaderInstance& shader = ShaderCache.GetShader(Outliner->SelectedMaterial); 176 | ModelFile.materials[Outliner->SelectedMaterial].shader = ShaderCache.LoadShader(Outliner->SelectedMaterial, shader.VertexShader.GetFileName(), nullptr).RaylibShader; 177 | } 178 | ShowUniformEditor(shader.FragmentShader); 179 | 180 | 181 | if (Outliner->SelectedMaterialMap >= 0) 182 | { 183 | ImGui::Separator(); 184 | 185 | Inspectors::ShowMaterialMapInspector(ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap]); 186 | 187 | if (ImGui::Button("SetTexture")) 188 | { 189 | std::string textureFile = PlatformTools::ShowOpenFileDialog(".png", ImageExtensions); 190 | if (textureFile.size() > 0) 191 | { 192 | Texture tx = LoadTexture(textureFile.c_str()); 193 | int id = ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap].texture.id; 194 | 195 | if (id > 0 && id != DefaultTexture.id) 196 | TextureCache.RemoveTexture(ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap].texture); 197 | 198 | ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap].texture = tx; 199 | TextureCache.AddTexture(tx); 200 | } 201 | } 202 | ImGui::SameLine(); 203 | if (ImGui::Button("Clear###ClearTexture")) 204 | { 205 | int id = ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap].texture.id; 206 | 207 | if (id > 0 && id != DefaultTexture.id) 208 | TextureCache.RemoveTexture(ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap].texture); 209 | 210 | ModelFile.materials[Outliner->SelectedMaterial].maps[Outliner->SelectedMaterialMap].texture = DefaultTexture; 211 | } 212 | } 213 | } 214 | } 215 | 216 | void OnShow(const Rectangle& contentArea) override 217 | { 218 | 219 | if (ModelFile.meshCount > 0) 220 | DrawModel(ModelFile, Vector3Zero(), 1, Colors::White); 221 | } 222 | 223 | void OnFileMenu() override 224 | { 225 | std::string file = "*.obj"; 226 | if (OpenFileMenu(file)) 227 | { 228 | Model newModel = LoadModel(file.c_str()); 229 | if (newModel.meshCount > 0) 230 | { 231 | UnloadModel(ModelFile); 232 | TextureCache.Clear(); 233 | ShaderCache.Clear(); 234 | 235 | float lowestY = std::numeric_limits::max(); 236 | 237 | for (int mesh = 0; mesh < newModel.meshCount; mesh++) 238 | { 239 | float y = GetMeshBoundingBox(newModel.meshes[mesh]).min.y; 240 | if (y < lowestY) 241 | lowestY = y; 242 | } 243 | 244 | newModel.transform = MatrixTranslate(0, -lowestY, 0); 245 | 246 | for (int material = 0; material < newModel.materialCount; material++) 247 | { 248 | newModel.materials[material].shader = ShaderCache.LoadShader(material, nullptr, nullptr).RaylibShader; 249 | 250 | for (int map = 0; map < MATERIAL_MAP_BRDG; map++) 251 | { 252 | if (newModel.materials[material].maps[map].texture.height > 1) 253 | TextureCache.AddTexture(newModel.materials[material].maps[map].texture); 254 | else if (map == 0) 255 | newModel.materials[material].maps[map].texture = DefaultTexture; 256 | } 257 | } 258 | 259 | ModelFile = newModel; 260 | Outliner->SetModel(ModelFile); 261 | 262 | } 263 | } 264 | } 265 | }; 266 | 267 | REGISTER_VIEW(ModelViewer); 268 | -------------------------------------------------------------------------------- /clip/clip_osx.mm: -------------------------------------------------------------------------------- 1 | // Clip Library 2 | // Copyright (c) 2015-2020 David Capello 3 | // 4 | // This file is released under the terms of the MIT license. 5 | // Read LICENSE.txt for more information. 6 | 7 | #include "clip.h" 8 | #include "clip_common.h" 9 | #include "clip_lock_impl.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace clip { 20 | 21 | namespace { 22 | 23 | format g_last_format = 100; 24 | std::map g_name_to_format; 25 | std::map g_format_to_name; 26 | 27 | bool get_image_from_clipboard(image* output_img, 28 | image_spec* output_spec) 29 | { 30 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 31 | NSString* result = [pasteboard availableTypeFromArray: 32 | [NSArray arrayWithObjects:NSPasteboardTypeTIFF,NSPasteboardTypePNG,nil]]; 33 | 34 | if (!result) 35 | return false; 36 | 37 | NSData* data = [pasteboard dataForType:result]; 38 | if (!data) 39 | return false; 40 | 41 | NSBitmapImageRep* bitmap = [NSBitmapImageRep imageRepWithData:data]; 42 | 43 | if ((bitmap.bitmapFormat & NSFloatingPointSamplesBitmapFormat) || 44 | (bitmap.planar)) { 45 | error_handler e = get_error_handler(); 46 | if (e) 47 | e(ErrorCode::ImageNotSupported); 48 | return false; 49 | } 50 | 51 | image_spec spec; 52 | spec.width = bitmap.pixelsWide; 53 | spec.height = bitmap.pixelsHigh; 54 | spec.bits_per_pixel = bitmap.bitsPerPixel; 55 | spec.bytes_per_row = bitmap.bytesPerRow; 56 | 57 | // We need three samples for Red/Green/Blue 58 | if (bitmap.samplesPerPixel >= 3) { 59 | int bits_per_sample = bitmap.bitsPerPixel / bitmap.samplesPerPixel; 60 | int bits_shift = 0; 61 | 62 | // With alpha 63 | if (bitmap.alpha) { 64 | if (bitmap.bitmapFormat & NSAlphaFirstBitmapFormat) { 65 | spec.alpha_shift = 0; 66 | bits_shift += bits_per_sample; 67 | } 68 | else { 69 | spec.alpha_shift = 3*bits_per_sample; 70 | } 71 | } 72 | 73 | unsigned long* masks = &spec.red_mask; 74 | unsigned long* shifts = &spec.red_shift; 75 | 76 | // Red/green/blue shifts 77 | for (unsigned long* shift=shifts; shift= 3 && 121 | !(bitmap.bitmapFormat & NSAlphaNonpremultipliedBitmapFormat)) { 122 | details::divide_rgb_by_alpha( 123 | img, 124 | true); // hasAlphaGreaterThanZero=true because we have valid alpha information 125 | } 126 | 127 | std::swap(*output_img, img); 128 | } 129 | 130 | return true; 131 | } 132 | 133 | } 134 | 135 | lock::impl::impl(void*) : m_locked(true) { 136 | } 137 | 138 | lock::impl::~impl() { 139 | } 140 | 141 | bool lock::impl::clear() { 142 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 143 | [pasteboard clearContents]; 144 | return true; 145 | } 146 | 147 | bool lock::impl::is_convertible(format f) const { 148 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 149 | NSString* result = nil; 150 | 151 | if (f == text_format()) { 152 | result = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:NSPasteboardTypeString]]; 153 | } 154 | else if (f == image_format()) { 155 | result = [pasteboard availableTypeFromArray: 156 | [NSArray arrayWithObjects:NSPasteboardTypeTIFF,NSPasteboardTypePNG,nil]]; 157 | } 158 | else { 159 | auto it = g_format_to_name.find(f); 160 | if (it != g_format_to_name.end()) { 161 | const std::string& name = it->second; 162 | NSString* string = [[NSString alloc] initWithBytesNoCopy:(void*)name.c_str() 163 | length:name.size() 164 | encoding:NSUTF8StringEncoding 165 | freeWhenDone:NO]; 166 | result = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:string]]; 167 | } 168 | } 169 | 170 | return (result ? true: false); 171 | } 172 | 173 | bool lock::impl::set_data(format f, const char* buf, size_t len) { 174 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 175 | 176 | if (f == text_format()) { 177 | NSString* string = [[NSString alloc] initWithBytesNoCopy:(void*)buf 178 | length:len 179 | encoding:NSUTF8StringEncoding 180 | freeWhenDone:NO]; 181 | [pasteboard setString:string forType:NSPasteboardTypeString]; 182 | return true; 183 | } 184 | else { 185 | auto it = g_format_to_name.find(f); 186 | if (it != g_format_to_name.end()) { 187 | const std::string& formatName = it->second; 188 | NSString* typeString = [[NSString alloc] 189 | initWithBytesNoCopy:(void*)formatName.c_str() 190 | length:formatName.size() 191 | encoding:NSUTF8StringEncoding 192 | freeWhenDone:NO]; 193 | NSData* data = [NSData dataWithBytesNoCopy:(void*)buf 194 | length:len 195 | freeWhenDone:NO]; 196 | 197 | if ([pasteboard setData:data forType:typeString]) 198 | return true; 199 | } 200 | } 201 | return false; 202 | } 203 | 204 | bool lock::impl::get_data(format f, char* buf, size_t len) const { 205 | assert(buf); 206 | if (!buf || !is_convertible(f)) 207 | return false; 208 | 209 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 210 | 211 | if (f == text_format()) { 212 | NSString* string = [pasteboard stringForType:NSPasteboardTypeString]; 213 | int reqsize = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]+1; 214 | 215 | assert(reqsize <= len); 216 | if (reqsize > len) { 217 | // Buffer is too small 218 | return false; 219 | } 220 | 221 | if (reqsize == 0) 222 | return true; 223 | 224 | memcpy(buf, [string UTF8String], reqsize); 225 | return true; 226 | } 227 | 228 | auto it = g_format_to_name.find(f); 229 | if (it == g_format_to_name.end()) 230 | return false; 231 | 232 | const std::string& formatName = it->second; 233 | NSString* typeString = 234 | [[NSString alloc] initWithBytesNoCopy:(void*)formatName.c_str() 235 | length:formatName.size() 236 | encoding:NSUTF8StringEncoding 237 | freeWhenDone:NO]; 238 | 239 | NSData* data = [pasteboard dataForType:typeString]; 240 | if (!data) 241 | return false; 242 | 243 | [data getBytes:buf length:len]; 244 | return true; 245 | } 246 | 247 | size_t lock::impl::get_data_length(format f) const { 248 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 249 | 250 | if (f == text_format()) { 251 | NSString* string = [pasteboard stringForType:NSPasteboardTypeString]; 252 | return [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]+1; 253 | } 254 | 255 | auto it = g_format_to_name.find(f); 256 | if (it == g_format_to_name.end()) 257 | return 0; 258 | 259 | const std::string& formatName = it->second; 260 | NSString* typeString = 261 | [[NSString alloc] initWithBytesNoCopy:(void*)formatName.c_str() 262 | length:formatName.size() 263 | encoding:NSUTF8StringEncoding 264 | freeWhenDone:NO]; 265 | 266 | NSData* data = [pasteboard dataForType:typeString]; 267 | if (!data) 268 | return 0; 269 | 270 | return data.length; 271 | } 272 | 273 | bool lock::impl::set_image(const image& image) { 274 | NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; 275 | const image_spec& spec = image.spec(); 276 | 277 | NSBitmapFormat bitmapFormat = 0; 278 | int samples_per_pixel = 0; 279 | if (spec.alpha_mask) { 280 | samples_per_pixel = 4; 281 | if (spec.alpha_shift == 0) 282 | bitmapFormat |= NSAlphaFirstBitmapFormat; 283 | bitmapFormat |= NSAlphaNonpremultipliedBitmapFormat; 284 | } 285 | else if (spec.red_mask || spec.green_mask || spec.blue_mask) { 286 | samples_per_pixel = 3; 287 | } 288 | else { 289 | samples_per_pixel = 1; 290 | } 291 | 292 | if (spec.bits_per_pixel == 32) 293 | bitmapFormat |= NS32BitLittleEndianBitmapFormat; 294 | else if (spec.bits_per_pixel == 16) 295 | bitmapFormat |= NS16BitLittleEndianBitmapFormat; 296 | 297 | std::vector planes(1); 298 | planes[0] = (unsigned char*)image.data(); 299 | 300 | NSBitmapImageRep* bitmap = 301 | [[NSBitmapImageRep alloc] 302 | initWithBitmapDataPlanes:&planes[0] 303 | pixelsWide:spec.width 304 | pixelsHigh:spec.height 305 | bitsPerSample:spec.bits_per_pixel / samples_per_pixel 306 | samplesPerPixel:samples_per_pixel 307 | hasAlpha:(spec.alpha_mask ? YES: NO) 308 | isPlanar:NO 309 | colorSpaceName:NSDeviceRGBColorSpace 310 | bitmapFormat:bitmapFormat 311 | bytesPerRow:spec.bytes_per_row 312 | bitsPerPixel:spec.bits_per_pixel]; 313 | if (!bitmap) 314 | return false; 315 | 316 | NSData* data = bitmap.TIFFRepresentation; 317 | if (!data) 318 | return false; 319 | 320 | if ([pasteboard setData:data forType:NSPasteboardTypeTIFF]) 321 | return true; 322 | 323 | return false; 324 | } 325 | 326 | bool lock::impl::get_image(image& img) const { 327 | return get_image_from_clipboard(&img, nullptr); 328 | } 329 | 330 | bool lock::impl::get_image_spec(image_spec& spec) const { 331 | return get_image_from_clipboard(nullptr, &spec); 332 | } 333 | 334 | format register_format(const std::string& name) { 335 | // Check if the format is already registered 336 | auto it = g_name_to_format.find(name); 337 | if (it != g_name_to_format.end()) 338 | return it->second; 339 | 340 | format new_format = g_last_format++; 341 | g_name_to_format[name] = new_format; 342 | g_format_to_name[new_format] = name; 343 | return new_format; 344 | } 345 | 346 | } // namespace clip 347 | --------------------------------------------------------------------------------