├── .gitignore ├── main.cpp ├── projects └── msvc │ ├── README.txt │ └── Yune │ ├── Yune │ ├── Yune.vcxproj.user │ ├── Yune.vcxproj.filters │ └── Yune.vcxproj │ └── Yune.sln ├── imgui.ini ├── geometry ├── cornellbox.mtl └── cornellbox.obj ├── template ├── testmat.mtl └── kernel.cl ├── Dear-IMGUI ├── LICENSE.txt ├── imgui_impl_glfw.h ├── imgui_impl_opengl3.h ├── imconfig.h ├── imgui_impl_glfw.cpp └── imstb_rectpack.h ├── RESOURCES.md ├── include ├── BVHNodeCPU.h ├── TriangleCPU.h ├── Scene.h ├── BVH.h ├── RendererGUI.h ├── CL_headers.h ├── RendererCore.h ├── Camera.h ├── GlfwManager.h └── CLManager.h ├── kernels └── post-proc │ └── tonemap.cl ├── src ├── BVHNodeCPU.cpp ├── TriangleCPU.cpp ├── Camera.cpp ├── GlfwManager.cpp ├── BVH.cpp └── Scene.cpp ├── README.md └── FileBrowser └── ImGuiFileBrowser.h /.gitignore: -------------------------------------------------------------------------------- 1 | # specific to CodeBlocks IDE 2 | 3 | *.layout 4 | *.depend 5 | *.cbp 6 | 7 | # specific to VisualStudio 8 | 9 | .vs 10 | *.pdb 11 | *.idb 12 | *.obj 13 | 14 | # generated directories 15 | 16 | bin/ 17 | obj/ 18 | Debug/ 19 | 20 | # any images generated 21 | 22 | *.jpg 23 | *.png 24 | *.exr 25 | 26 | #imgui settings 27 | *.ini 28 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "RendererGUI.h" 5 | 6 | using namespace yune; 7 | 8 | int main() 9 | { 10 | try 11 | { 12 | RendererGUI renderer; 13 | renderer.run(); 14 | } 15 | catch(const std::exception& err) 16 | { 17 | std::cout << err.what() << std::endl; 18 | std::cout << "\nPress Enter to continue..." << std::endl; 19 | std::cin.ignore(); 20 | return EXIT_FAILURE; 21 | } 22 | 23 | return EXIT_SUCCESS; 24 | } 25 | -------------------------------------------------------------------------------- /projects/msvc/README.txt: -------------------------------------------------------------------------------- 1 | Yune - Building with Visual Studio 2 | ================================== 3 | 4 | Use Visual Studio 2017 or later. Project was created using Visual Studio 2017 (v15.9.17) 5 | 6 | To obtain dependencies, set up vcpkg (https://github.com/microsoft/vcpkg) 7 | and install the following packages: 8 | - glad 9 | - glfw3 10 | - glm 11 | - opencl 12 | 13 | After installing dependencies, open the solution (.sln), 14 | select your platform (x86/x64) and hit F5 to build and run. 15 | Dependencies should be located automatically via vcpkg integration. 16 | 17 | Tested on Windows10 (x64) -------------------------------------------------------------------------------- /projects/msvc/Yune/Yune/Yune.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(ProjectDir)..\..\..\..\ 5 | WindowsLocalDebugger 6 | 7 | 8 | $(ProjectDir)..\..\..\..\ 9 | WindowsLocalDebugger 10 | 11 | -------------------------------------------------------------------------------- /imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | [Window][Misc Settings##window] 7 | Pos=10,35 8 | Size=330,512 9 | Collapsed=0 10 | 11 | [Window][Dear ImGui Demo] 12 | Pos=469,69 13 | Size=550,680 14 | Collapsed=1 15 | 16 | [Window][Example: Console] 17 | Pos=143,139 18 | Size=520,600 19 | Collapsed=0 20 | 21 | [Window][Example: Log] 22 | Pos=87,95 23 | Size=500,400 24 | Collapsed=0 25 | 26 | [Window][Style Editor] 27 | Pos=60,60 28 | Size=353,762 29 | Collapsed=0 30 | 31 | [Window][Dear ImGui Metrics] 32 | Pos=60,60 33 | Size=338,222 34 | Collapsed=0 35 | 36 | [Window][Example: Long text display] 37 | Pos=59,16 38 | Size=282,600 39 | Collapsed=0 40 | 41 | -------------------------------------------------------------------------------- /geometry/cornellbox.mtl: -------------------------------------------------------------------------------- 1 | newmtl grey-walls-cubes 2 | ke 0 0 0 3 | kd 0.9 0.9 0.9 4 | ks 0 0 0 5 | 6 | newmtl red-wall 7 | ke 0 0 0 8 | kd 0.8 0 0 9 | ks 0 0 0 10 | 11 | newmtl green-wall 12 | ke 0 0 0 13 | kd 0 0.8 0 14 | ks 0 0 0 15 | 16 | newmtl teapot 17 | ke 0 0 0 18 | kd 0.6 0.6 0.6 19 | ks 0.2 0.2 0.2 20 | px 20 21 | py 20 22 | 23 | newmtl mirror-transmissive 24 | ke 0 0 0 25 | kd 0.7 0.7 0.7 26 | ks 0.08 0.08 0.08 27 | n 1.6 28 | px 1000 29 | py 1000 30 | is_specular 1 31 | is_transmissive 1 32 | 33 | newmtl mirror 34 | ke 0 0 0 35 | kd 0.7 0.7 0.7 36 | ks 0.08 0.08 0.08 37 | n 1.6 38 | px 1000 39 | py 1000 40 | is_specular 1 41 | is_transmissive 0 42 | 43 | newmtl glossy 44 | ke 0 0 0 45 | kd 0.1 0.1 0.1 46 | ks 0.767 0.767 0.767 47 | n 1.0 48 | px 1000 49 | py 1000 50 | is_specular 0 51 | is_transmissive 0 -------------------------------------------------------------------------------- /template/testmat.mtl: -------------------------------------------------------------------------------- 1 | # Template for material file required by Yune. It's a very dumb down version of the original ".mtl" file. 2 | # "ke", "kd" and "ks" define the emissive, diffuse and specular color respectively. 3 | # "n" and "k" are the real and complex Index of refraction. "k" can be considered as the extinction coefficient for metals. 4 | # "px" and "py" are the phong exponent for anisotropic surfaces. 5 | # "alpha_x" and "alpha_y" are parameters that control slope distribution of microfacets for anisotropic materials. They are equal for isotropic materials. 6 | # "is_specular" and "is_transmissive" determine whether the material is perfectly specular and transparent. 7 | # Each and every property is optional. If not provided, a default value will be loaded. 8 | 9 | newmtl mynew-mat-123 10 | ke 1 2 3 11 | kd 4 5 6 12 | ks 5 6 5 13 | n 1.5 14 | k 2.2 15 | px 100 16 | py 200 17 | alpha_x 100 18 | alpha_y 200 19 | is_specular 0 20 | is_transmissive 0 -------------------------------------------------------------------------------- /Dear-IMGUI/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2019 Omar Cornut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /projects/msvc/Yune/Yune.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.902 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Yune", "Yune\Yune.vcxproj", "{43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Debug|x64.ActiveCfg = Debug|x64 17 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Debug|x64.Build.0 = Debug|x64 18 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Debug|x86.ActiveCfg = Debug|Win32 19 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Debug|x86.Build.0 = Debug|Win32 20 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Release|x64.ActiveCfg = Release|x64 21 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Release|x64.Build.0 = Release|x64 22 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Release|x86.ActiveCfg = Release|Win32 23 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {DF02E8D7-773D-46C7-A1BF-334B68A71B95} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /RESOURCES.md: -------------------------------------------------------------------------------- 1 | This is a dump of all the resources we used to get this thing up :) 2 | 3 | ## Pathtracing 4 | 5 | 1. *[1986-Kajiya] The Rendering Equation* - (The main paper, gotta read it) 6 | 2. *[1996-Lafortune] Mathematical Models and Monte Carlo algorithms -* (General Maths) 7 | 3. *[1996-Shirley] Monte Carlo Techniques for Direct Lighting Calculations -* (Explicit Light Sampling) 8 | 4. *[1993-Lafortune] Bi-directional Path Tracing* 9 | 5. *[1997-Veach] Robust MC methods for Light Transport Simulation -* (Multiple Importance Sampling and BDPT) 10 | 6. *[1990-Arvo, Kirk] Particle transport for Image synthesis -* (Russian Roulette logic) 11 | 7. *Physically based rendering from theory to Implementation (PBRT)* - (For implementation and logic) 12 | 8. *[1994-Lafortune]-Using the modified Phong reflectance model for Physically based rendering* 13 | 14 | ## Geometry and Acceleration Data Structure 15 | 16 | 1. *[1986-Kajiya, Kay] Raytracing Complex Scenes* 17 | 2. *[1987-Goldsmith, Salmon] Automatic creation of object hierarchies* 18 | 3. *[1997-Moller,Trumbore] Fast Minimum Storage Ray-Triangle Intersection* 19 | 20 | ## HDR and Tonemapping 21 | 22 | 1. *[2010- Erik Reinhard] High Dynamic Range Imaging Acquisition, Display, and Image-Based Lighting* 23 | 24 | ## PBR based Models - (not implemented yet) 25 | 26 | 1. *[2012-Naty Hoffman] Physics and math of shading* 27 | 2. *[2014-Siggraph-Sebastian] - Moving Frostbite To PBR* 28 | 3. *[2012-Burley] Physically Based Shading at Disney* 29 | 4. *[2000- Ashikhmin, Shirley] An anisotropic Phong BRDF model* 30 | 5. *[Andrea] Arbitrarily Layerd MicroFacet Surfaces* 31 | 32 | ## Books 33 | 1. *PBRT* 34 | 2. *Fundamentals of Computer Graphics - P. Shirley* 35 | 3. *Essential Mathematics for games - Van Verth* - (Camera and other basic Linear Algebra) 36 | -------------------------------------------------------------------------------- /include/BVHNodeCPU.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef BVHNODECPU_H 27 | #define BVHNODECPU_H 28 | 29 | #include 30 | 31 | #include "CL_headers.h" 32 | #include "TriangleCPU.h" 33 | 34 | namespace yune 35 | { 36 | class BVHNodeCPU 37 | { 38 | public: 39 | BVHNodeCPU(); 40 | BVHNodeCPU(AABB aabb); 41 | BVHNodeGPU gpu_node; 42 | std::vector primitives; 43 | }; 44 | } 45 | 46 | 47 | #endif // BVHNODECPU_H 48 | -------------------------------------------------------------------------------- /include/TriangleCPU.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef TRIANGLECPU_H 27 | #define TRIANGLECPU_H 28 | 29 | #include "CL_headers.h" 30 | 31 | namespace yune 32 | { 33 | class TriangleCPU 34 | { 35 | public: 36 | TriangleCPU(); 37 | ~TriangleCPU(); 38 | TriangleGPU props; 39 | AABB aabb; 40 | cl_float4 centroid; 41 | void computeCentroid(); 42 | void computeAABB(); 43 | }; 44 | } 45 | #endif // TRIANGLECPU_H 46 | -------------------------------------------------------------------------------- /kernels/post-proc/tonemap.cl: -------------------------------------------------------------------------------- 1 | #yune-preproc kernel-name tonemap 2 | 3 | #define SATURATION_EXP 1.0f 4 | #define GAMMA 2.2f 5 | #define EPSILON 0.001f 6 | __constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | 7 | CLK_ADDRESS_CLAMP_TO_EDGE | 8 | CLK_FILTER_NEAREST; 9 | 10 | float getYluminance(float4 color); 11 | float4 tonemapReinhard(float4 col, float lum_white); 12 | float4 tonemapJohnHable(float4 col); 13 | 14 | __kernel void tonemap(__read_only image2d_t current_frame, __read_only image2d_t prev_frame, 15 | __write_only image2d_t outputImage, int reset) 16 | { 17 | int img_width = get_image_width(outputImage); 18 | int img_height = get_image_height(outputImage); 19 | 20 | int2 pixel = (int2)(get_global_id(0), get_global_id(1)); 21 | 22 | if (pixel.x >= img_width || pixel.y >= img_height) 23 | return; 24 | 25 | float4 hdr_color = read_imagef(current_frame, sampler, pixel); 26 | float4 ldr_color = hdr_color; 27 | 28 | ldr_color = tonemapReinhard(hdr_color, 1.0f); 29 | //ldr_color = tonemapJohnHable(hdr_color); 30 | 31 | //Apply Gamma correction 32 | clamp(ldr_color, (float4) 0.0f, (float4) 1.0f); 33 | ldr_color = pow(ldr_color, (float4) (1/GAMMA) ); 34 | write_imagef(outputImage, pixel, ldr_color); 35 | } 36 | 37 | float getYluminance(float4 color) 38 | { 39 | return 0.212671f*color.x + 0.715160f*color.y + 0.072169f*color.z + EPSILON; 40 | } 41 | 42 | float4 tonemapReinhard(float4 col, float lum_white) 43 | { 44 | float lum_world = getYluminance(col); 45 | float lum_display = lum_world * (1 + lum_world/(lum_white * lum_white) ) / (1+lum_world); 46 | return lum_display * pow(col/lum_world, (float4) (SATURATION_EXP)); 47 | } 48 | 49 | float4 tonemapJohnHable(float4 col) 50 | { 51 | float A = 0.15; 52 | float B = 0.50; 53 | float C = 0.10; 54 | float D = 0.20; 55 | float E = 0.02; 56 | float F = 0.30; 57 | float W = 11.2; 58 | return ((col*(A*col+C*B)+D*E)/(col*(A*col+B)+D*F))-E/F; 59 | } -------------------------------------------------------------------------------- /src/BVHNodeCPU.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #include "BVHNodeCPU.h" 27 | 28 | namespace yune 29 | { 30 | BVHNodeCPU::BVHNodeCPU() 31 | { 32 | gpu_node.vert_len = -1; 33 | gpu_node.child_idx = -2; 34 | gpu_node.vert_list[0] = -1; 35 | gpu_node.vert_list[1] = -1; 36 | gpu_node.vert_list[2] = -1; 37 | gpu_node.vert_list[3] = -1; 38 | primitives.clear(); 39 | //ctor 40 | } 41 | 42 | BVHNodeCPU::BVHNodeCPU(AABB aabb) : gpu_node{aabb, {-1,-1,-1,-1}, -1, -1} 43 | { 44 | gpu_node.vert_len = -1; 45 | gpu_node.child_idx = -2; 46 | gpu_node.vert_list[0] = -1; 47 | gpu_node.vert_list[1] = -1; 48 | gpu_node.vert_list[2] = -1; 49 | gpu_node.vert_list[3] = -1; 50 | primitives.clear(); 51 | //ctor 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Dear-IMGUI/imgui_impl_glfw.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for GLFW 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Clipboard support. 7 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 8 | // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. 9 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). 10 | 11 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 12 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 13 | // https://github.com/ocornut/imgui 14 | 15 | // About GLSL version: 16 | // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. 17 | // Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! 18 | 19 | #pragma once 20 | 21 | struct GLFWwindow; 22 | 23 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); 24 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); 25 | IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); 26 | IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); 27 | 28 | // InitXXX function with 'install_callbacks=true': install GLFW callbacks. They will call user's previously installed callbacks, if any. 29 | // InitXXX function with 'install_callbacks=false': do not install GLFW callbacks. You will need to call them yourself from your own GLFW callbacks. 30 | IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 31 | IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); 32 | IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 33 | IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); 34 | -------------------------------------------------------------------------------- /include/Scene.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef SCENE_H 27 | #define SCENE_H 28 | 29 | #include "CL_headers.h" 30 | #include "Camera.h" 31 | #include "TriangleCPU.h" 32 | #include "BVH.h" 33 | 34 | #include 35 | #include 36 | 37 | namespace yune 38 | { 39 | class Scene 40 | { 41 | public: 42 | Scene(); 43 | ~Scene(); 44 | void setBuffer( ); 45 | void loadModel(std::string filepath, std::string filename); 46 | void loadBVH(int bvh_bins); 47 | void reloadMatFile(); 48 | 49 | Camera main_camera; 50 | std::vector vert_data; 51 | std::vector mat_data; 52 | std::string scene_file, mat_file, mat_filename; 53 | AABB root; 54 | BVH bvh; 55 | int num_triangles; 56 | float scene_size_kb, scene_size_mb; 57 | 58 | private: 59 | void clearValues(); 60 | std::string getMatFileName(std::string filepath); 61 | std::vector cpu_tri_list; 62 | }; 63 | } 64 | #endif // SCENE_H 65 | -------------------------------------------------------------------------------- /src/TriangleCPU.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #include "TriangleCPU.h" 27 | #include 28 | #include 29 | namespace yune 30 | { 31 | TriangleCPU::TriangleCPU() 32 | { 33 | //ctor 34 | } 35 | 36 | TriangleCPU::~TriangleCPU() 37 | { 38 | //dtor 39 | } 40 | 41 | void TriangleCPU::computeCentroid() 42 | { 43 | centroid = props.v1 + props.v2; 44 | centroid = centroid + props.v3; 45 | centroid = centroid/3.0f; 46 | centroid.s[3] = 1.0f; 47 | 48 | computeAABB(); 49 | } 50 | 51 | void TriangleCPU::computeAABB() 52 | { 53 | cl_float4 p_min = {0,0,0,1}; 54 | cl_float4 p_max = {0,0,0,1}; 55 | 56 | for(int i = 0; i < 3; i++) 57 | { 58 | p_min.s[i] = std::min(props.v1.s[i], std::min(props.v2.s[i], props.v3.s[i])); 59 | p_max.s[i] = std::max(props.v1.s[i], std::max(props.v2.s[i], props.v3.s[i])); 60 | } 61 | cl_float4 diff = p_max - p_min; 62 | 63 | for(int i = 0; i < 3; i++) 64 | { 65 | if(diff.s[i] == 0.0f) 66 | p_max.s[i] += 0.2f; 67 | } 68 | 69 | aabb.p_min = p_min; 70 | aabb.p_max = p_max; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /include/BVH.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef BVH_H 27 | #define BVH_H 28 | 29 | #include "CL_headers.h" 30 | #include "TriangleCPU.h" 31 | #include "BVHNodeCPU.h" 32 | 33 | #include 34 | 35 | namespace yune 36 | { 37 | class BVH 38 | { 39 | public: 40 | BVH(); 41 | ~BVH(); 42 | std::vector gpu_node_list; 43 | void createBVH(AABB root, const std::vector& cpu_tri_list, int bvh_bins = 20); 44 | int bins; 45 | float bvh_size_kb, bvh_size_mb; 46 | 47 | private: 48 | enum SplitAxis 49 | { 50 | X = 0, 51 | Y = 1, 52 | Z = 2 53 | }; 54 | 55 | SplitAxis findSplitAxis(const std::vector& cpu_tri_list, std::vector& child_list); 56 | AABB getExtent(const AABB& bb1, const AABB& bb2); 57 | 58 | void clearValues(); 59 | void populateChildNodes(const BVHNodeCPU& parent, BVHNodeCPU& c1, BVHNodeCPU& c2, const std::vector& cpu_tri_list); 60 | void resizeBvh(const std::vector& cpu_tri_list); 61 | void resizeBvhNode(BVHNodeCPU& node, const std::vector& cpu_tri_list); 62 | float getSurfaceArea(AABB aabb); 63 | 64 | std::vector cpu_node_list; 65 | int leaf_primitives; 66 | float cost_isect, cost_trav; 67 | }; 68 | } 69 | 70 | #endif // BVH_H 71 | -------------------------------------------------------------------------------- /template/kernel.cl: -------------------------------------------------------------------------------- 1 | #yune-preproc kernel-name pathtracer 2 | 3 | typedef struct Triangle{ 4 | 5 | float4 v1; 6 | float4 v2; 7 | float4 v3; 8 | float4 vn1; 9 | float4 vn2; 10 | float4 vn3; 11 | int matID; // total size till here = 100 bytes 12 | float pad[3]; // padding 12 bytes - to make it 112 bytes (next multiple of 16 13 | } Triangle; 14 | 15 | //For use with Triangle geometry. 16 | typedef struct Material{ 17 | 18 | float4 ke; 19 | float4 kd; 20 | float4 ks; 21 | float n; 22 | float k; 23 | float px; 24 | float py; 25 | float alpha_x; 26 | float alpha_y; 27 | int is_specular; 28 | int is_transmissive; // total 80 bytes. 29 | } Material; 30 | 31 | typedef struct AABB{ 32 | float4 p_min; 33 | float4 p_max; 34 | } AABB; 35 | 36 | typedef struct BVHNodeGPU{ 37 | AABB aabb; //32 38 | int vert_list[10]; //40 39 | int child_idx; //4 40 | int vert_len; //4 - total 80 41 | } BVHNodeGPU; 42 | 43 | typedef struct Mat4x4{ 44 | float4 r1; 45 | float4 r2; 46 | float4 r3; 47 | float4 r4; 48 | } Mat4x4; 49 | 50 | typedef struct Camera{ 51 | Mat4x4 view_mat; 52 | float view_plane_dist; // total 68 bytes 53 | float pad[3]; // 12 bytes padding to reach 80 (next multiple of 16) 54 | } Camera; 55 | 56 | __constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | 57 | CLK_ADDRESS_CLAMP_TO_EDGE | 58 | CLK_FILTER_NEAREST; 59 | 60 | //The Camera parameter provided to the kernel follows the struct definition defined above. It contains a view to world matrix. And a view plane distance 61 | //parameter which is the length of the view plane from the camera. The camera is initially looking in the -Z direction and origin at (0,0,0) 62 | 63 | //The rand parameter contains a 32 bit random number on each iteration. In order to use different seeds for every pixel, you can use the wang hash algorithm 64 | // to generate uncorrelated seed values from pixel IDs. You can check the given implementation for details on how to produce random numbers. 65 | 66 | __kernel void pathtracer(__write_only image2d_t outputImage, __read_only image2d_t inputImage, __constant Camera* main_cam, 67 | int scene_size, __global Triangle* vert_data, __global Material* mat_data, int bvh_size, __global BVHNodeGPU* bvh, 68 | int GI_CHECK, int reset, uint rand, int block, int block_x, int block_y) 69 | { 70 | int img_width = get_image_width(outputImage); 71 | int img_height = get_image_height(outputImage); 72 | int2 pixel = (int2)(get_global_id(0), get_global_id(1)); 73 | 74 | pixel.x += ceil((float)img_width / block_x) * (block % block_x); 75 | pixel.y += ceil((float)img_height / block_y) * (block / block_x); 76 | 77 | if (pixel.x >= img_width || pixel.y >= img_height) 78 | return; 79 | 80 | //Start your code from here. It's not necessary to use Triangles/BVH. If you don't read any triangles, these buffers will be null 81 | } 82 | -------------------------------------------------------------------------------- /Dear-IMGUI/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline 2 | // - Desktop GL: 2.x 3.x 4.x 3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) 4 | // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) 5 | 6 | // Implemented features: 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! 8 | // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. 9 | 10 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 11 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 12 | // https://github.com/ocornut/imgui 13 | 14 | // About Desktop OpenGL function loaders: 15 | // Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. 16 | // Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). 17 | // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. 18 | 19 | // About GLSL version: 20 | // The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. 21 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" 22 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. 23 | 24 | #pragma once 25 | 26 | // Backend API 27 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); 28 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 29 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 30 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 31 | 32 | // (Optional) Called by Init/NewFrame/Shutdown 33 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 34 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 35 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 36 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 37 | 38 | // Specific OpenGL versions 39 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten 40 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android 41 | 42 | // Desktop OpenGL: attempt to detect default GL loader based on available header files. 43 | // If auto-detection fails or doesn't select the same GL loader file as used by your application, 44 | // you are likely to get a crash in ImGui_ImplOpenGL3_Init(). 45 | // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 46 | #if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ 47 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ 48 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ 49 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING) \ 50 | && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) 51 | #if defined(__has_include) 52 | #if __has_include() 53 | #define IMGUI_IMPL_OPENGL_LOADER_GLEW 54 | #elif __has_include() 55 | #define IMGUI_IMPL_OPENGL_LOADER_GLAD 56 | #elif __has_include() 57 | #define IMGUI_IMPL_OPENGL_LOADER_GL3W 58 | #elif __has_include() 59 | #define IMGUI_IMPL_OPENGL_LOADER_GLBINDING 60 | #else 61 | #error "Cannot detect OpenGL loader!" 62 | #endif 63 | #else 64 | #define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W 65 | #endif 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /include/RendererGUI.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef RENDERERGUI_H 27 | #define RENDERERGUI_H 28 | 29 | #define IMGUI_IMPL_OPENGL_LOADER_GLAD 30 | 31 | #include "GlfwManager.h" 32 | #include "CLManager.h" 33 | #include "RendererCore.h" 34 | #include "glm/vec4.hpp" 35 | #include "imgui.h" 36 | #include "imgui_impl_glfw.h" 37 | #include "imgui_impl_opengl3.h" 38 | #include "ImGuiFileBrowser.h" 39 | 40 | namespace yune 41 | { 42 | /** \brief This class is body of the renderer. It manages and connects different parts of the renderer with each other. 43 | * It contains instances to CLManager, GlfwManager and RendererCore which is the core part dealing with 44 | * enqueuing kernels. 45 | */ 46 | class RendererGUI 47 | { 48 | public: 49 | RendererGUI(int window_width = 1024, int window_height = 768); 50 | ~RendererGUI(); 51 | void run(); 52 | 53 | private: 54 | struct WindowSize 55 | { 56 | int width; 57 | int height; 58 | }; 59 | 60 | bool setup(); 61 | void startFrame(); 62 | void renderFrame(); 63 | bool showMenu(); 64 | void showBenchmarkWindow(unsigned long time_passed); 65 | void showSceneInfo(); 66 | void showMiscSettings(); 67 | void showMessageBox(std::string title, std::string msg, std::string log = ""); 68 | void showHelpMarker(std::string desc); 69 | void renderExtBox(); 70 | 71 | static void setMessage(const std::string& msg, const std::string& title, const std::string& log); 72 | static std::string mb_msg, mb_title, mb_log; 73 | 74 | GlfwManager glfw_manager; 75 | CLManager cl_manager; 76 | RendererCore renderer; 77 | std::vector supported_sizes; 78 | std::vector supported_exts; 79 | imgui_addons::ImGuiFileBrowser file_dialog; 80 | 81 | char input_fn[256]; 82 | int benchmark_wheight, bvh_bins, selected_size; 83 | bool benchmark_shown, scene_info_shown, misc_settings_shown, renderer_start; 84 | bool is_fullscreen, update_vertex_buffer, update_mat_buffer, update_image_buffer, update_bvh_buffer, load_bvh, gi_check, cap_fps, do_postproc; 85 | }; 86 | } 87 | #endif // RENDERERGUI_H 88 | -------------------------------------------------------------------------------- /include/CL_headers.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef CL_HEADERS_H 27 | #define CL_HEADERS_H 28 | 29 | #ifndef CL_MINIMUM_OPENCL_VERSION 30 | #define CL_MINIMUM_OPENCL_VERSION 120 31 | #endif // CL_MINIMUM_OPENCL_VERSION 32 | 33 | #ifndef CL_TARGET_OPENCL_VERSION 34 | #define CL_TARGET_OPENCL_VERSION 120 35 | #endif // CL_TARGET_OPENCL_VERSION 36 | 37 | #if defined(__APPLE__) || defined(__MACOSX) 38 | #include 39 | #include 40 | #define CL_GL_SHARING_EXT "cl_apple_gl_sharing" 41 | 42 | #else 43 | #if defined (__linux) 44 | #include 45 | #elif defined( __WIN32 ) 46 | #include 47 | #endif // (__linux) 48 | 49 | #include 50 | #include 51 | #define CL_GL_SHARING_EXT "cl_khr_gl_sharing" 52 | #endif // if defined(__APPLE__) || defined(__MACOSX) 53 | 54 | /* When using CL_MEM_ALLOC_HOST_PTR we don't need to worry about alignment. However when using the "USE_HOST_PTR" flag we have 55 | * to provide aligned data. We try to ensure aligned memory anyways in-case we want to measure performance difference between the two flags. 56 | */ 57 | struct alignas(16) Cam 58 | { 59 | cl_float4 r1; 60 | cl_float4 r2; 61 | cl_float4 r3; 62 | cl_float4 r4; 63 | cl_float view_plane_dist; // total 68 bytes 64 | cl_float pad[3]; // padding 12 bytes to reach 80 (next multiple of 16) 65 | }; 66 | 67 | struct alignas(16) TriangleGPU 68 | { 69 | cl_float4 v1; 70 | cl_float4 v2; 71 | cl_float4 v3; 72 | cl_float4 vn1; 73 | cl_float4 vn2; 74 | cl_float4 vn3; 75 | cl_int matID; // total size till here = 100 bytes 76 | cl_float pad[3]; // padding 12 bytes - to make it 112 (next multiple of 16) 77 | }; 78 | 79 | struct alignas(16) AABB 80 | { 81 | cl_float4 p_min; 82 | cl_float4 p_max; 83 | 84 | }; 85 | 86 | struct alignas(16) BVHNodeGPU 87 | { 88 | AABB aabb; //32 89 | cl_int vert_list[10];//40 90 | cl_int child_idx; //4 91 | cl_int vert_len; //4 - total 80 92 | }; 93 | 94 | struct alignas(16) Material 95 | { 96 | cl_float4 ke; 97 | cl_float4 kd; 98 | cl_float4 ks; 99 | cl_float n; 100 | cl_float k; 101 | cl_float px; 102 | cl_float py; 103 | cl_float alpha_x; 104 | cl_float alpha_y; 105 | cl_int is_specular; 106 | cl_int is_transmissive; // total 80 bytes. 107 | }; 108 | 109 | inline Material newMaterial() 110 | { 111 | return { 112 | {0,0,0,1}, //ke 113 | {0.3,0.3,0.3,1}, //kd 114 | {0,0,0,1}, //ks 115 | 1, //n 116 | 1, //k 117 | 1, //px 118 | 1, //py 119 | 100, //alpha_x 120 | 100, //alpha_y 121 | 0, //is_specular 122 | 0 //is_transmissive 123 | }; 124 | } 125 | 126 | inline cl_float4 operator+ (cl_float4& a, cl_float4& b) 127 | { 128 | return {a.s[0] + b.s[0], a.s[1] + b.s[1], a.s[2] + b.s[2], ((a.s[3] + b.s[3]) >= 1) ? 1.0f : 0.0f }; 129 | } 130 | 131 | inline cl_float4 operator- (cl_float4& a, cl_float4& b) 132 | { 133 | return {a.s[0] - b.s[0], a.s[1] - b.s[1], a.s[2] - b.s[2], (a.s[3] == 1 || b.s[3] == 1) ? 1.0f : 0.0f }; 134 | } 135 | 136 | inline cl_float4 operator/ (cl_float4& a, const cl_float& b) 137 | { 138 | return {a.s[0] / b, a.s[1] / b, a.s[2] / b, (a.s[3] == 1) ? 1.0f : 0.0f }; 139 | } 140 | 141 | inline cl_float4 operator* (cl_float4& a, cl_float& b) 142 | { 143 | return {a.s[0] * b, a.s[1] * b, a.s[2] * b, (a.s[3] == 1) ? 1.0f : 0.0f }; 144 | } 145 | 146 | #endif // CL_HEADERS_H 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *Editor-Screen. Simple Primitives using Oren-Nayar for diffuse and Phong for glossy materials.* 2 | ![Yune Results2](https://github.com/gallickgunner/Yune/blob/Pictures/Images/editor.jpg?raw=true) 3 | 4 | *Utah teapot rendered using transmissive material.* 5 | ![teapot](https://github.com/gallickgunner/Yune/blob/Pictures/Images/teapot-2kspp-refr.jpg?raw=true) 6 | 7 | *Ico Sphere rendered using transmissive material.* 8 | ![cbwith-refractive-sphere](https://github.com/gallickgunner/Yune/blob/Pictures/Images/5kspp-CB-Sphere.jpg?raw=true) 9 | 10 | 11 | # Yune 12 | 13 | Yune started off as a personal toy pathtracer on the GPU using OpenCL. However, we've tried our best to mature it into a form of an educational raytracer/pathtracer. It's a framework for writing interactive raytracers, pathracers based on the GPU using OpenCL. It is mainly aimed towards young programmers and researchers who are looking to write their own Ray tracers, Path tracers and implementing other advanced techniques like Physically based Reflection models, etc but don't want to deal with the whole boilerplate code to set things up. It provides the basic funtionality to open up a window, display and save Images. We also provide some basic profiling functionality. *FPS, ms/frame, ms/kernel, total render time and samples per pixel (spp)* are updated in real-time. You can save the image at specific **spp** by providing the value in options. Although not something extravagant, it can help in seeing performance gains if you are working on optimizing the code or comparing different implementations, reflection models, etc. 14 | 15 | If you are familiar with [Nori](https://github.com/wjakob/nori), this gets easier. Yune is more like a dumbed down Nori but on the GPU. As described earlier the host portion provides all the basic functionalities to open up a window, display the image and setup minimal buffers that would be required by a normal Pathtracer or Raytracer. What happens to the Image next, depends on the Kernel which is upto the programmer that is **you**. 16 | 17 | That being said as this was part of our bachelor thesis on Physically Based Rendering and our personal project, we will be upgrading the GPU portion as well and keep adding new techniques as we study. 18 | 19 | You can use this software in two ways. 20 | 21 | 1. Clone the project as it is, link it's dependencies manually and then start programming as if the whole project was coded by you. This may sound daunting but it's actually pretty easy and recommended if you want to mature it into something else or implement multipass kernels, etc. 22 | 23 | 2. You can use only the executable. You can then only do OpenCL programming in a separate file and load it through GUI. This means you can keep on changing the kernel file, material files, or even use many different files with different algorithms without compiling at all provided that the new algorithms don't need change in host (CPU side) logic :) 24 | 25 | Yune uses OpenCL-GL interoperability as the main core for processing images on the kernel and displaying them on the window. Aside from that it uses 26 | 27 | * [GLFW](https://github.com/glfw/glfw), for window and input managment. 28 | * [GLAD](https://github.com/Dav1dde/glad) for OpenGL 3.x and higher windows. 29 | * [GLM](https://github.com/g-truc/glm) for basic Vector types and math. 30 | * [STB Image](https://github.com/nothings/stb) for saving screenshots. 31 | * [Dear-ImGui](https://github.com/ocornut/imgui) for GUI and basic widgets. 32 | 33 | You need an OpenCL 1.1 or higher compatible CPU/GPU that also supports the CL extension *cl_khr_gl_sharing* (CL-GL interoperability) You don't have to fret over it though as the extension is supported by many old GPUs as well. The program will also list down whether the extension is available or not. 34 | 35 | I haven't added support for build system like Cmake yet. If anybody still wants to compile, I've written some steps in the [wiki](https://github.com/gallickgunner/Yune/wiki/Getting-Started). 36 | 37 | ***Check WIKI for guides regarding how to load model files.*** 38 | 39 | Currently Implemented features, 40 | * Next Event Estimation aka Explicit direct light sampling 41 | * Russian Roulette path termination 42 | * Modified Phong BRDF (1994 - Lafortune) 43 | * Multiple Light Source heuristic (chooses a single light source out of multiple ones) 44 | * Multiple Importance Sampling 45 | * Support for saving HDR Images 46 | * Tone mapping and Gamma Correction 47 | * Naive Bidirectional Pathtracing as in Lafortune's paper 48 | * SAH-based BVH 49 | 50 | #### Check the [RESOURCES.MD](https://github.com/gallickgunner/Yune/blob/master/RESOURCES.md) file for a list of reference material (research papers and books) used. 51 | 52 | Watch it in action below, (click for full video) 53 | 54 | [![Demo](https://i.imgur.com/5JVNva4.gif)](https://www.youtube.com/watch?v=VdJDk3MgG9A) 55 | 56 | ## TODO 57 | 58 | - ~~Revamp UI by using Dear-ImGui~~ 59 | - ~~Use ImGui to get rid of the ***yune-options.yun*** file. All configurable parameters should be through UI.~~ 60 | - Provide more profiling and benchmarking functionality like comparison of Images with reference Images from other Renderers like Mitsuba, etc. 61 | - ~~Remove custom geometry files and add support for directly reading from .OBJ~~ 62 | - ~~Add support to leave out post-processing kernel.~~ 63 | - Compare our own images with Reference ones from Mitsuba.* (personal) 64 | -------------------------------------------------------------------------------- /FileBrowser/ImGuiFileBrowser.h: -------------------------------------------------------------------------------- 1 | #ifndef IMGUIFILEBROWSER_H 2 | #define IMGUIFILEBROWSER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace imgui_addons 9 | { 10 | class ImGuiFileBrowser 11 | { 12 | public: 13 | ImGuiFileBrowser(); 14 | ~ImGuiFileBrowser(); 15 | 16 | enum class DialogMode 17 | { 18 | SELECT, //Select Directory Mode 19 | OPEN, //Open File mode 20 | SAVE //Save File mode. 21 | }; 22 | 23 | /* Use this to show an open file dialog. The function takes label for the window, 24 | * the size, a DialogMode enum value defining in which mode the dialog should operate and optionally the extensions that are valid for opening. 25 | * Note that the select directory mode doesn't need any extensions. 26 | */ 27 | bool showFileDialog(const std::string& label, const DialogMode mode, const ImVec2& sz_xy = ImVec2(0,0), const std::string& valid_types = "*.*"); 28 | 29 | /* Store the opened/saved file name or dir name (incase of selectDirectoryDialog) and the absolute path to the selection 30 | * Should only be accessed when above functions return true else may contain garbage. 31 | */ 32 | std::string selected_fn; 33 | std::string selected_path; 34 | std::string ext; // Store the saved file extension 35 | 36 | 37 | private: 38 | struct Info 39 | { 40 | Info(std::string name, bool is_hidden) : name(name), is_hidden(is_hidden) 41 | { 42 | } 43 | std::string name; 44 | bool is_hidden; 45 | }; 46 | 47 | //Enum used as bit flags. 48 | enum FilterMode 49 | { 50 | FilterMode_Files = 0x01, 51 | FilterMode_Dirs = 0x02 52 | }; 53 | 54 | //Helper Functions 55 | static std::string wStringToString(const wchar_t* wchar_arr); 56 | static bool alphaSortComparator(const Info& a, const Info& b); 57 | ImVec2 getButtonSize(std::string button_text); 58 | 59 | /* Helper Functions that render secondary modals 60 | * and help in validating file extensions and for filtering, parsing top navigation bar. 61 | */ 62 | void setValidExtTypes(const std::string& valid_types_string); 63 | bool validateFile(); 64 | void showErrorModal(); 65 | void showInvalidFileModal(); 66 | bool showReplaceFileModal(); 67 | void showHelpMarker(std::string desc); 68 | void parsePathTabs(std::string str); 69 | void filterFiles(int filter_mode); 70 | 71 | /* Core Functions that render the 4 different regions making up 72 | * a simple file dialog 73 | */ 74 | bool renderNavAndSearchBarRegion(); 75 | bool renderFileListRegion(); 76 | bool renderInputTextAndExtRegion(); 77 | bool renderButtonsAndCheckboxRegion(); 78 | bool renderInputComboBox(); 79 | void renderExtBox(); 80 | 81 | /* Core Functions that handle navigation and 82 | * reading directories/files 83 | */ 84 | bool readDIR(std::string path); 85 | bool onNavigationButtonClick(int idx); 86 | bool onDirClick(int idx); 87 | 88 | // Functions that reset state and/or clear file list when reading new directory 89 | void clearFileList(); 90 | void closeDialog(); 91 | 92 | #if defined (WIN32) || defined (_WIN32) || defined (__WIN32) 93 | bool loadWindowsDrives(); // Helper Function for Windows to load Drive Letters. 94 | #endif 95 | 96 | #if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) 97 | void initCurrentPath(); // Helper function for UNIX based system to load Absolute path using realpath 98 | #endif 99 | 100 | ImVec2 min_size, max_size, input_combobox_pos, input_combobox_sz; 101 | DialogMode dialog_mode; 102 | int filter_mode, col_items_limit, selected_idx, selected_ext_idx; 103 | float col_width, ext_box_width; 104 | bool show_hidden, show_inputbar_combobox, is_dir, is_appearing, filter_dirty, validate_file; 105 | char input_fn[256]; 106 | 107 | std::vector valid_exts; 108 | std::vector current_dirlist; 109 | std::vector subdirs; 110 | std::vector subfiles; 111 | std::string current_path, error_msg, error_title, invfile_modal_id, repfile_modal_id; 112 | 113 | ImGuiTextFilter filter; 114 | std::string valid_types; 115 | std::vector filtered_dirs; // Note: We don't need to call delete. It's just for storing filtered items from subdirs and subfiles so we don't use PassFilter every frame. 116 | std::vector filtered_files; 117 | std::vector< std::reference_wrapper > inputcb_filter_files; 118 | }; 119 | } 120 | 121 | 122 | #endif // IMGUIFILEBROWSER_H 123 | -------------------------------------------------------------------------------- /geometry/cornellbox.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.82 (sub 7) OBJ File: 'cb.blend' 2 | # www.blender.org 3 | mtllib cornellbox.mtl 4 | o shortBox_shortBox_.005 5 | v 0.700000 -0.403829 -3.048277 6 | v -0.050000 -0.403830 -2.648277 7 | v 0.530000 -0.403830 -2.468277 8 | v -0.050000 -0.403830 -2.648277 9 | v 0.130000 -1.003829 -3.218277 10 | v -0.050000 -1.003829 -2.648277 11 | v 0.530000 -0.403830 -2.468277 12 | v -0.050000 -1.003829 -2.648277 13 | v 0.530000 -1.003830 -2.468277 14 | v 0.130000 -0.403828 -3.218277 15 | v 0.700000 -1.003829 -3.048277 16 | v 0.130000 -1.003829 -3.218277 17 | v 0.700000 -0.403829 -3.048277 18 | v 0.530000 -1.003830 -2.468277 19 | v 0.700000 -1.003829 -3.048277 20 | v 0.130000 -0.403828 -3.218277 21 | v 0.130000 -0.403828 -3.218277 22 | v -0.050000 -0.403830 -2.648277 23 | v 0.700000 -0.403829 -3.048277 24 | v 0.530000 -0.403830 -2.468277 25 | vn -0.0000 1.0000 0.0000 26 | vn -0.9536 0.0000 -0.3011 27 | vn -0.2964 -0.0000 0.9551 28 | vn 0.2858 0.0000 -0.9583 29 | vn 0.9596 -0.0000 0.2813 30 | usemtl grey-walls-cubes 31 | s 1 32 | f 1//1 2//1 3//1 33 | f 4//2 5//2 6//2 34 | f 7//3 8//3 9//3 35 | f 10//4 11//4 12//4 36 | f 13//5 14//5 15//5 37 | f 1//1 16//1 2//1 38 | f 4//2 17//2 5//2 39 | f 7//3 18//3 8//3 40 | f 10//4 19//4 11//4 41 | f 13//5 20//5 14//5 42 | o longBox_shortBox.007 43 | v 0.040000 0.196172 -3.099096 44 | v -0.710000 0.196172 -3.499096 45 | v -0.530000 0.196170 -2.919096 46 | v -0.530000 0.196170 -2.919096 47 | v -0.710000 -1.003828 -3.499096 48 | v -0.530000 -1.003829 -2.919096 49 | v -0.710000 0.196172 -3.499096 50 | v -0.140000 -1.003828 -3.679096 51 | v -0.710000 -1.003828 -3.499096 52 | v -0.140000 0.196172 -3.679096 53 | v 0.040000 -1.003829 -3.099096 54 | v -0.140000 -1.003828 -3.679096 55 | v 0.040000 0.196172 -3.099096 56 | v -0.530000 -1.003829 -2.919096 57 | v 0.040000 -1.003829 -3.099096 58 | v -0.140000 0.196172 -3.679096 59 | v -0.710000 0.196172 -3.499096 60 | v -0.140000 0.196172 -3.679096 61 | v 0.040000 0.196172 -3.099096 62 | v -0.530000 0.196170 -2.919096 63 | vn -0.0000 1.0000 0.0000 64 | vn -0.9551 -0.0000 0.2964 65 | vn -0.3011 0.0000 -0.9536 66 | vn 0.9551 0.0000 -0.2964 67 | vn 0.3011 -0.0000 0.9536 68 | usemtl grey-walls-cubes 69 | s 1 70 | f 21//6 22//6 23//6 71 | f 24//7 25//7 26//7 72 | f 27//8 28//8 29//8 73 | f 30//9 31//9 32//9 74 | f 33//10 34//10 35//10 75 | f 21//6 36//6 22//6 76 | f 24//7 37//7 25//7 77 | f 27//8 38//8 28//8 78 | f 30//9 39//9 31//9 79 | f 33//10 40//10 34//10 80 | o ceiling.008 81 | v -1.020000 0.986172 -4.049096 82 | v -0.010000 0.986170 -3.034096 83 | v -1.020000 0.986170 -3.034096 84 | v -0.010000 0.986172 -4.049096 85 | v 1.000000 0.986170 -3.034096 86 | v 1.000000 0.986170 -2.019096 87 | v 1.000000 0.986172 -4.049096 88 | v -0.010000 0.986170 -2.019096 89 | v -1.020000 0.986170 -2.019096 90 | vn 0.0000 -1.0000 -0.0000 91 | usemtl grey-walls-cubes 92 | s 1 93 | f 41//11 42//11 43//11 94 | f 41//11 44//11 42//11 95 | f 42//11 45//11 46//11 96 | f 42//11 44//11 45//11 97 | f 44//11 47//11 45//11 98 | f 43//11 48//11 49//11 99 | f 43//11 42//11 48//11 100 | f 42//11 46//11 48//11 101 | o leftWall.009 102 | v -1.010000 -1.003830 -2.019096 103 | v -1.015000 -0.008830 -3.034096 104 | v -1.015000 -0.008830 -2.019096 105 | v -1.000000 -1.003829 -3.034096 106 | v -1.005000 -0.008828 -4.049096 107 | v -1.020000 0.986172 -4.049096 108 | v -0.990000 -1.003828 -4.049096 109 | v -1.020000 0.986170 -3.034096 110 | v -1.020000 0.986170 -2.019096 111 | vn 0.9999 0.0100 0.0049 112 | vn 1.0000 0.0050 0.0000 113 | vn 0.9998 0.0151 0.0099 114 | vn 0.9999 0.0101 0.0050 115 | usemtl red-wall 116 | s 1 117 | f 50//12 51//12 52//13 118 | f 50//12 53//14 51//12 119 | f 51//12 54//14 55//15 120 | f 51//12 53//14 54//14 121 | f 53//14 56//14 54//14 122 | f 52//13 57//13 58//13 123 | f 52//13 51//12 57//13 124 | f 51//12 55//15 57//13 125 | o backWall.008 126 | v -0.990000 -1.003828 -4.049096 127 | v 0.005000 -0.008828 -4.049096 128 | v -1.005000 -0.008828 -4.049096 129 | v 0.005000 -1.003828 -4.049096 130 | v 1.000000 -0.008828 -4.049096 131 | v 1.000000 0.986172 -4.049096 132 | v 1.000000 -1.003828 -4.049096 133 | v -0.010000 0.986172 -4.049096 134 | v -1.020000 0.986172 -4.049096 135 | vn 0.0000 0.0000 1.0000 136 | usemtl grey-walls-cubes 137 | s 1 138 | f 59//16 60//16 61//16 139 | f 59//16 62//16 60//16 140 | f 60//16 63//16 64//16 141 | f 60//16 62//16 63//16 142 | f 62//16 65//16 63//16 143 | f 61//16 66//16 67//16 144 | f 61//16 60//16 66//16 145 | f 60//16 64//16 66//16 146 | o rightWall.008 147 | v 1.000000 -1.003830 -2.019096 148 | v 1.000000 -0.008830 -3.034096 149 | v 1.000000 -1.003829 -3.034096 150 | v 1.000000 -0.008830 -2.019096 151 | v 1.000000 0.986170 -3.034096 152 | v 1.000000 0.986172 -4.049096 153 | v 1.000000 0.986170 -2.019096 154 | v 1.000000 -0.008828 -4.049096 155 | v 1.000000 -1.003828 -4.049096 156 | vn -1.0000 0.0000 0.0000 157 | usemtl green-wall 158 | s 1 159 | f 68//17 69//17 70//17 160 | f 68//17 71//17 69//17 161 | f 69//17 72//17 73//17 162 | f 69//17 71//17 72//17 163 | f 71//17 74//17 72//17 164 | f 70//17 75//17 76//17 165 | f 70//17 69//17 75//17 166 | f 69//17 73//17 75//17 167 | o floor.008 168 | v 1.000000 -1.003830 -2.019096 169 | v 0.005000 -1.003829 -3.034096 170 | v -0.005000 -1.003830 -2.019096 171 | v 1.000000 -1.003829 -3.034096 172 | v 0.005000 -1.003828 -4.049096 173 | v -0.990000 -1.003828 -4.049096 174 | v 1.000000 -1.003828 -4.049096 175 | v -1.000000 -1.003829 -3.034096 176 | v -1.010000 -1.003830 -2.019096 177 | vn 0.0000 1.0000 0.0000 178 | usemtl grey-walls-cubes 179 | s 1 180 | f 77//18 78//18 79//18 181 | f 77//18 80//18 78//18 182 | f 78//18 81//18 82//18 183 | f 78//18 80//18 81//18 184 | f 80//18 83//18 81//18 185 | f 79//18 84//18 85//18 186 | f 79//18 78//18 84//18 187 | f 78//18 82//18 84//18 188 | -------------------------------------------------------------------------------- /projects/msvc/Yune/Yune/Yune.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {32f570ba-c899-4537-a9a3-225eb3fbc400} 18 | 19 | 20 | {ad1f2ab0-4203-430f-91d7-e8c3bbc31daf} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | DearIMGUI 29 | 30 | 31 | DearIMGUI 32 | 33 | 34 | DearIMGUI 35 | 36 | 37 | DearIMGUI 38 | 39 | 40 | DearIMGUI 41 | 42 | 43 | DearIMGUI 44 | 45 | 46 | DearIMGUI\FileBrowser 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | DearIMGUI 112 | 113 | 114 | DearIMGUI 115 | 116 | 117 | DearIMGUI 118 | 119 | 120 | DearIMGUI 121 | 122 | 123 | DearIMGUI 124 | 125 | 126 | DearIMGUI 127 | 128 | 129 | DearIMGUI 130 | 131 | 132 | DearIMGUI 133 | 134 | 135 | DearIMGUI\FileBrowser 136 | 137 | 138 | -------------------------------------------------------------------------------- /include/RendererCore.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef RENDERERCORE_H 27 | #define RENDERERCORE_H 28 | 29 | #include "Scene.h" 30 | #include "CLManager.h" 31 | #include "GlfwManager.h" 32 | #include "glm/vec2.hpp" 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace yune 40 | { 41 | /** \brief This is the logical counterpart to RendererGUI. Mainly responsible for setting kernel arguments, enqueuing kernels and blitting the resulting image to default framebuffer. 42 | */ 43 | class RendererCore 44 | { 45 | public: 46 | RendererCore(CLManager& cl_manager, GlfwManager& glfw_manager); 47 | ~RendererCore(); /**< Default Destructor. */ 48 | 49 | /** \brief A function to setup the \ref RendererCore object. 50 | * 51 | * \param[in] update_image_buffer Whether to create CL memory object for image 52 | * \param[in] update_vertex_buffer Whether to create CL memory object for vertex data 53 | * \param[in] update_mat_buffer Whether to create CL memory object for material data 54 | * \param[in] update_bvh_buffer Whether to create CL memory object for bvh 55 | * \param[in] do_postproc If post-processing kernel is loaded or not. 56 | * 57 | */ 58 | bool setup(bool& update_image_buffer, bool& update_scene_buffer, bool& update_mat_buffer, bool& update_bvh_buffer, bool do_postproc); 59 | 60 | /** \brief Enqueues kernel in blocks. 61 | * This function enqueues kernels in blocks. After one whole frame is processed. Post processing kernel is enqueued if present. 62 | */ 63 | bool enqueueKernels(bool new_gi_check, bool cap_fps); 64 | 65 | /** \brief Blit the last frame to the default framebuffer 66 | */ 67 | void render(); 68 | 69 | /** \brief Set the callback function to set messages shown by GUI incase of any event 70 | */ 71 | void setGuiMessageCb(std::function); 72 | 73 | bool loadScene(std::string path, std::string fn); 74 | void updateKernelWGSize(bool reset = false); 75 | bool reloadMatFile(); 76 | void resetValues(); 77 | void stop(); 78 | 79 | Scene render_scene; 80 | std::string save_fn, save_ext, save_samples_fn, save_samples_ext; 81 | bool save_pending, save_editor, new_gi_check; 82 | unsigned long samples_taken, save_at_samples, time_passed; 83 | float ms_per_rk, ms_per_ppk, mspf_avg; 84 | int fps; 85 | 86 | glm::ivec2 blocks; 87 | size_t rk_gws[2]; /**< Global workgroup size for Rendeirng Kernel.*/ 88 | size_t ppk_gws[2]; /**< Global workgroup size for Post-processing Kernel.*/ 89 | size_t rk_lws[2]; /**< Local workgroup size for Rendering Kernel.*/ 90 | size_t ppk_lws[2]; /**< Local workgroup size for Post-processing Kernel.*/ 91 | 92 | private: 93 | void loadOptions(); 94 | void updateRenderKernelArgs(bool new_gi_check, cl_uint seed); 95 | void updatePostProcessingKernelArgs(); 96 | bool saveImage(std::string save_fn, std::string save_ext); 97 | void endFrame(); 98 | 99 | static std::function setMessageCb; /**< The function pointer to the RendererGUI message callback function. */ 100 | 101 | CLManager& cl_manager; /**< A \ref CLManager object. */ 102 | GlfwManager& glfw_manager; /**< A \ref GlfwManager object. */ 103 | std::mt19937 mt_engine; 104 | std::uniform_int_distribution dist; 105 | 106 | bool buffer_switch, gi_check, rk_enqueued, ppk_enqueued, do_postproc, render_nextframe; 107 | cl_int reset, rk_status, ppk_status; 108 | cl_uint seed; 109 | cl_event rk_event, ppk_event; 110 | int curr_block, frame_count; 111 | float skip_ticks, sum_mspf, mspf_uncapped_avg; 112 | double exec_time_rk, exec_time_ppk, last_time, start_time; 113 | unsigned int mt_seed; 114 | Cam cam_data; /**< A Cam structure containing Camera data for passing to the GPU. A similar structure resides on GPU.*/ 115 | }; 116 | } 117 | #endif // RENDERERCORE_H 118 | -------------------------------------------------------------------------------- /include/Camera.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef CAMERA_H 27 | #define CAMERA_H 28 | 29 | #include "CL_headers.h" 30 | #include "glm/vec4.hpp" 31 | #include "glm/mat4x4.hpp" 32 | 33 | #include 34 | namespace yune 35 | { 36 | /** \brief This class defines a Camera based on the standard right handed system approach used in OpenGL. 37 | * 38 | * The View to World Matrix is based on the basis vectors of the Camera and thus contains the complete information of 39 | * the orientation and the position. The Camera determines the it's view plane distance by varying values of Vertical Field of View. 40 | * Greater values of Camera::y_FOV generate a smaller Camera::view_plane_dist and vice versa. 41 | * 42 | * The Camera has a right handed coordinate system, and initially the side vector (right side of camera) represents the +X-axis, the Up vector 43 | * represents the +Y-axis and the look at vector represents the -Z-axis. Note that we do not need to store the World to View matrix as 44 | * Rays are already generated in Camera/View Space inside the kernel. Thus a View to World matrix is needed to transform them to World Space. 45 | * 46 | * The class keeps an up-to-date copy of all the basis vectors as public members. Note that setting them directly doesn't change the matrix. 47 | * These are only given for reading/checking the current values. 48 | */ 49 | class Camera 50 | { 51 | public: 52 | Camera(); /**< Default Constructor. */ 53 | 54 | /** \brief Overloaded Constructor. 55 | * 56 | * \param[in] y_FOV The vertical field of view in degrees. 57 | */ 58 | Camera(float y_FOV, float rot_speed = 0.25f, float mov_speed = 0.1f); 59 | ~Camera(); /**< Default Destructor. */ 60 | 61 | /** \brief Set the Orientation of the Camera when moved by mouse/keyboard. 62 | * 63 | * \param[in] dir A vec4 determining the direction vector in which the camera moves. 64 | * \param[in] pitch The angles in radian by which to rotate around the X-axis. 65 | * \param[in] yaw The angles in radian by which to rotate around the Y-axis. 66 | * 67 | */ 68 | void setOrientation(const glm::vec4& dir, float pitch, float yaw); 69 | 70 | /** \brief Set the View Matrix of the camera. 71 | * 72 | * \param[in] side A vec4 determining the Side basis vector of the Camera. 73 | * \param[in] up A vec4 determining the Up basis vector of the Camera. 74 | * \param[in] look_at A vec4 determining the LookAt basis vector of the Camera. 75 | * \param[in] eye A vec4 determining the position of the Camera. 76 | * 77 | */ 78 | void setViewMatrix(const glm::vec4& side, const glm::vec4& up, const glm::vec4& look_at, const glm::vec4& eye); 79 | 80 | /** \brief Set values to be passed on to the Camera buffer. 81 | * 82 | * \param[in,out] cam_data The strucutre holding the camera data which is passed on to the OpenCL buffer object. 83 | * 84 | */ 85 | void setBuffer(Cam* cam_data); 86 | 87 | void resetCamera(); 88 | void updateViewPlaneDist(); 89 | void updateViewMatrix(); 90 | 91 | bool is_changed; /**< A flag determining if the Camera changed orientation, hence if the buffer needs to be updated. */ 92 | glm::vec4 side; /**< The Camera's Side vector. */ 93 | glm::vec4 up; /**< The Camera's Up vector. */ 94 | glm::vec4 look_at; /**< The Camera's Look At vector. */ 95 | glm::vec4 eye; /**< The Camera's Eye/Position vector. */ 96 | float y_FOV; /**< The vertical Field of View in degrees. */ 97 | float rotation_speed; /**< The rotation speed of the camera. Range between 0 and 1. Values closer to 0 guarantess a more smooth and slower rotation. */ 98 | float move_speed; /**< The movement speed of the camera. Range between 0 and 1. Values closer to 0 guarantess a more smooth and slower movement. */ 99 | glm::mat4x4 view2world_mat; /**< A glm mat4x4 defining the View to World Matrix. Values in here aren't guaranteed to be normalized. */ 100 | private: 101 | float view_plane_dist; /**< The distance of the View Plane from the Camera; This is determined based on the vertical field of view. */ 102 | 103 | 104 | }; 105 | } 106 | #endif // CAMERA_H 107 | -------------------------------------------------------------------------------- /include/GlfwManager.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef GLFWMANAGER_H 27 | #define GLFWMANAGER_H 28 | 29 | #include "glad/glad.h" 30 | #include "GLFW/glfw3.h" 31 | #include "glm/vec4.hpp" 32 | #include 33 | 34 | namespace yune 35 | { 36 | /** \brief This class manages the OpenGL context, Window creation and other input related functions through GLFW. 37 | * The release of OpenGL context and other resources is done in the desturctor. This class is intended for 38 | * 1 time use only i.e. no more than one instance 39 | */ 40 | class GlfwManager 41 | { 42 | public: 43 | /** \brief Overloaded Constructor. 44 | * 45 | * \param[in] window_width The width of the window. 46 | * \param[in] window_height The height of the window. 47 | */ 48 | GlfwManager(int window_width = 1024, int window_height = 768); 49 | ~GlfwManager(); /**< Default Destructor. */ 50 | 51 | /** \brief Setup OpenGL Framebuffer and RenderBuffer objects. 52 | * 53 | * The OpenCL Image Object is created on top of this RBO which will then be used to draw the Image object data returned by the kernel on the window. 54 | * \return True or false depending on if the Buffers are created successfully 55 | */ 56 | bool setupGlBuffer(); 57 | 58 | /** \brief Show the created Window. 59 | * 60 | * Windows are created hidden initially. This functions is called just before entering the event processing loop to display the window. 61 | */ 62 | void showWindow(); 63 | 64 | /** \brief Set the callback function to be called when Camera is moved through keyboard/mouse. 65 | */ 66 | void setCameraUpdateCallback(std::function); 67 | 68 | /** \brief Set the callback function to set messages shown by GUI incase of any event 69 | */ 70 | void setGuiMessageCb(std::function); 71 | 72 | GLFWwindow* window; /**< A GLFW Window pointer for rendering GUI and displaying image output from kernel. */ 73 | int window_width; /**< Width of the window. */ 74 | int window_height; /**< Height of the window. */ 75 | int framebuffer_width; /**< Width of the Framebuffer. */ 76 | int framebuffer_height; /**< Height of the Framebuffer. */ 77 | GLFWmonitor* prim_monitor; /**< GLFW monitor pointer storing primary monitor. */ 78 | const GLFWvidmode* mode; /**< GLFW Video mode pointer. */ 79 | 80 | private: 81 | friend class RendererCore; 82 | 83 | void initImGui(); 84 | 85 | /** \brief Creates a GLFW window encapsulating an OpenGL context. 86 | * 87 | * \param[in] width The Width in screen coordinates determining the size of the window or the initial framebuffer. This is passed on from the Renderer object. 88 | * \param[in] height The Height in screen coordinates determining the size of the window or the initial framebuffer. This is passed on from the Renderer object. 89 | * 90 | */ 91 | void createWindow(int width, int height); 92 | 93 | static std::function cameraUpdateCallback; /**< The function pointer to the Camera Update Callback function. */ 94 | static std::function setMessageCb; /**< The function pointer to the RendererGUI message callback function. */ 95 | 96 | GLuint fbo_ID; /**< OpenGL FrameBuffer Object ID */ 97 | GLuint rbo_IDs[4]; /**< OpenGL RenderBuffer Object IDs for OpenCL read and write only Images and post-processing. The fourth RBO is temporary for storing a copy of latest output image by kernel. */ 98 | float old_cursor_x; /**< Store the previous cursor X coordinate.*/ 99 | float old_cursor_y; /**< Store the previous cursor Y coordinate.*/ 100 | bool space_flag; /**< Store if the Space Key is in pressed state.*/ 101 | 102 | /** \name GLFW Callbacks 103 | * Refer to the GLFW docs for details on the callback function syntax. 104 | */ 105 | ///@{ 106 | static void errorCallback(int error, const char* msg); 107 | static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 108 | static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 109 | static void cursorPosCallback(GLFWwindow* window, double new_cursor_x, double new_cursor_y); 110 | static void framebufferSizeCallback(GLFWwindow* window, int width, int height); 111 | ///@} 112 | }; 113 | } 114 | 115 | #endif // GLFWMANAGER_H 116 | -------------------------------------------------------------------------------- /src/Camera.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #include "Camera.h" 27 | #include "glm/gtc/matrix_transform.hpp" 28 | #include "glm/gtc/matrix_access.hpp" 29 | #include "glm/vec3.hpp" 30 | 31 | #include 32 | 33 | namespace yune 34 | { 35 | 36 | Camera::Camera() : y_FOV(60.0f), view2world_mat(), rotation_speed(0.25f), move_speed(0.1f) 37 | { 38 | //ctor 39 | resetCamera(); 40 | } 41 | 42 | Camera::Camera(float y_FOV, float rot_speed, float mov_speed) : y_FOV(y_FOV), view2world_mat(), rotation_speed(rot_speed), move_speed(mov_speed) 43 | { 44 | setViewMatrix(glm::vec4(1.f, 0.f, 0.f, 0.f), // side 45 | glm::vec4(0.f, 1.f, 0.f, 0.f), // up 46 | glm::vec4(0.f, 0.f, -1.f, 0.f), // look_at 47 | glm::vec4(0.f, 0.f, 0.f, 1.f) // eye 48 | ); 49 | view_plane_dist = 1/tan(y_FOV*3.14/360); 50 | is_changed = true; 51 | 52 | //ctor 53 | } 54 | 55 | Camera::~Camera() 56 | { 57 | //dtor 58 | } 59 | 60 | void Camera::updateViewPlaneDist() 61 | { 62 | view_plane_dist = 1/tan(y_FOV*3.14/360); 63 | is_changed = true; 64 | } 65 | 66 | void Camera::setBuffer(Cam* cam_data) 67 | { 68 | glm::vec4 temp = glm::row(view2world_mat, 0); 69 | cam_data->r1 = cl_float4{temp.x, temp.y, temp.z, temp.w}; 70 | 71 | temp = glm::row(view2world_mat, 1); 72 | cam_data->r2 = cl_float4{temp.x, temp.y, temp.z, temp.w}; 73 | 74 | temp = glm::row(view2world_mat, 2); 75 | cam_data->r3 = cl_float4{temp.x, temp.y, temp.z, temp.w}; 76 | 77 | temp = glm::row(view2world_mat, 3); 78 | cam_data->r4 = cl_float4{temp.x, temp.y, temp.z, temp.w}; 79 | 80 | cam_data->view_plane_dist = view_plane_dist; 81 | is_changed = false; 82 | } 83 | 84 | void Camera::updateViewMatrix() 85 | { 86 | side = glm::normalize(glm::column(view2world_mat, 0)); 87 | up = glm::normalize(glm::column(view2world_mat, 1)); 88 | look_at = -glm::normalize(glm::column(view2world_mat, 2)); 89 | eye = glm::column(view2world_mat, 3); 90 | is_changed = true; 91 | } 92 | 93 | void Camera::resetCamera() 94 | { 95 | setViewMatrix(glm::vec4(1.f, 0.f, 0.f, 0.f), // side 96 | glm::vec4(0.f, 1.f, 0.f, 0.f), // up 97 | glm::vec4(0.f, 0.f, -1.f, 0.f), // look_at 98 | glm::vec4(0.f, 0.f, 0.f, 1.f) // eye 99 | ); 100 | y_FOV = 60; 101 | view_plane_dist = 1/tan(y_FOV*3.14/360); 102 | is_changed = true; 103 | } 104 | 105 | void Camera::setViewMatrix(const glm::vec4& side, const glm::vec4& up, const glm::vec4& look_at, const glm::vec4& eye) 106 | { 107 | this->eye = eye; 108 | this->side = glm::normalize(side); 109 | this->up = glm::normalize(up); 110 | this->look_at = glm::normalize(look_at); 111 | 112 | /* Always Remember that for Right Handed Coordinate Systems, the Camera (initially aligned with World Reference frame) 113 | * has the look direction negative to that of the Z axis. Hence to get the basis vector in Z we have to invert the look vector. 114 | */ 115 | view2world_mat = glm::mat4(side, up, -look_at, eye); 116 | is_changed = true; 117 | } 118 | 119 | void Camera::setOrientation(const glm::vec4& dir, float pitch, float yaw) 120 | { 121 | if(dir.length() > 0) 122 | { 123 | if(dir.z > 0) 124 | eye += look_at * move_speed; 125 | else if (dir.z < 0) 126 | eye -= look_at * move_speed; 127 | else if (dir.x > 0) 128 | eye += side * move_speed; 129 | else if (dir.x < 0) 130 | eye -= side * move_speed; 131 | else if (dir.y > 0) 132 | eye += up * move_speed; 133 | else if (dir.y < 0) 134 | eye -= up * move_speed; 135 | 136 | if(pitch == 0 && yaw == 0) 137 | { 138 | view2world_mat = glm::column(view2world_mat, 3, eye); 139 | is_changed = true; 140 | return; 141 | } 142 | } 143 | 144 | glm::mat4x4 rotx, roty; 145 | rotx = glm::rotate(glm::mat4(1.0f), pitch * rotation_speed, glm::vec3(side.x, side.y, side.z) ); 146 | roty = glm::rotate(glm::mat4(1.0f), yaw * rotation_speed, glm::vec3(0, 1, 0) ); 147 | 148 | glm::vec4 temp = rotx * this->up; 149 | 150 | //Move to origin 151 | view2world_mat = glm::column(view2world_mat, 3, glm::vec4(0,0,0,1)); 152 | 153 | // Rotate around local X axis in the range -90 to +90. 154 | if(temp.y >= 0) 155 | view2world_mat = rotx * view2world_mat; 156 | view2world_mat = roty * view2world_mat; 157 | 158 | //Move back to eye 159 | view2world_mat = glm::column(view2world_mat, 3, eye); 160 | 161 | side = glm::normalize(glm::column(view2world_mat, 0)); 162 | up = glm::normalize(glm::column(view2world_mat, 1)); 163 | look_at = -glm::normalize(glm::column(view2world_mat, 2)); 164 | 165 | is_changed = true; 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /Dear-IMGUI/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) 7 | // B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" 8 | // If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include 9 | // the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 10 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 11 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 12 | //----------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | //---- Define assertion handler. Defaults to calling assert(). 17 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 18 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 19 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 20 | 21 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 22 | // Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 23 | //#define IMGUI_API __declspec( dllexport ) 24 | //#define IMGUI_API __declspec( dllimport ) 25 | 26 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 27 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 28 | 29 | //---- Disable all of Dear ImGui or don't implement standard windows. 30 | // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. 31 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 32 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. 33 | //#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty. 34 | 35 | //---- Don't implement some functions to reduce linkage requirements. 36 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 37 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 38 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 39 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 40 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 41 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 42 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 43 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 44 | 45 | //---- Include imgui_user.h at the end of imgui.h as a convenience 46 | //#define IMGUI_INCLUDE_IMGUI_USER_H 47 | 48 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 49 | //#define IMGUI_USE_BGRA_PACKED_COLOR 50 | 51 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 52 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 53 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 54 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 55 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 56 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 57 | 58 | //---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library. 59 | // Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. 60 | // #define IMGUI_USE_STB_SPRINTF 61 | 62 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 63 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 64 | /* 65 | #define IM_VEC2_CLASS_EXTRA \ 66 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 67 | operator MyVec2() const { return MyVec2(x,y); } 68 | 69 | #define IM_VEC4_CLASS_EXTRA \ 70 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 71 | operator MyVec4() const { return MyVec4(x,y,z,w); } 72 | */ 73 | 74 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 75 | // Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices). 76 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 77 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 78 | //#define ImDrawIdx unsigned int 79 | 80 | //---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) 81 | //struct ImDrawList; 82 | //struct ImDrawCmd; 83 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 84 | //#define ImDrawCallback MyImDrawCallback 85 | 86 | //---- Debug Tools: Macro to break in Debugger 87 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 88 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 89 | //#define IM_DEBUG_BREAK __debugbreak() 90 | 91 | //---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), 92 | // (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) 93 | // This adds a small runtime cost which is why it is not enabled by default. 94 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 95 | 96 | //---- Debug Tools: Enable slower asserts 97 | //#define IMGUI_DEBUG_PARANOID 98 | 99 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 100 | /* 101 | namespace ImGui 102 | { 103 | void MyFunction(const char* name, const MyMatrix44& v); 104 | } 105 | */ 106 | -------------------------------------------------------------------------------- /include/CLManager.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #ifndef CLMANAGER_H 27 | #define CLMANAGER_H 28 | 29 | #include "BVH.h" 30 | #include "CL_headers.h" 31 | #include "glad/glad.h" 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | namespace yune 38 | { 39 | 40 | /** \brief This class manages the OpenCL context and Buffers. The class manages the releasing of memory objects, kernels etc in 41 | * RAII fashion. This class is intended for 1 time use only i.e. no more than one instance. 42 | */ 43 | class CLManager 44 | { 45 | public: 46 | CLManager(); /**< Default Constructor. */ 47 | ~CLManager(); /**< Default Destructor. */ 48 | 49 | 50 | void setup(); /**< Setup OpenCL platforms, devices and context*/ 51 | 52 | /** \brief Create OpenCL Rendering program and setup kernel. 53 | * 54 | * \param[in] fn The file name containing the kernel for Path tracer/Ray-tracer or any similar Rendering tehcnique. 55 | * \param[in] path The full path of the file name above 56 | * \return True if the function succeeds, else false. Error message will be stored in CLManager::error_msg 57 | */ 58 | bool createRenderProgram(std::string fn, std::string path, bool reload); 59 | 60 | /** \brief Create OpenCL Rendering program and setup kernel. 61 | * 62 | * \param[in] fn The file name containing the kernel for Post-Processing/Tonemapping 63 | * \param[in] path The full path of the file name above 64 | * \return True if the function succeeds, else false. Error message will be stored in CLManager::error_msg 65 | */ 66 | bool createPostProcProgram(std::string fn, std::string path, bool reload); 67 | 68 | /** \brief Display the Error message for the error code. 69 | * 70 | * \param err_code The error code returned by OpenCL functions. 71 | * \param filename The file name where the error occurred. Used for pin-pointing where the exception occurred. 72 | * \param line_number The line number at which the error occurred. Used for pin-pointing where the exception occurred. 73 | */ 74 | static void checkError(cl_int err_code, std::string filename, int line_number); 75 | 76 | /** \brief Set the callback function to set messages shown by GUI incase of any event 77 | */ 78 | void setGuiMessageCb(std::function); 79 | 80 | 81 | //Setup Buffer Objects 82 | void setupCameraBuffer(Cam* cam_data); 83 | bool setupImageBuffers(GLuint rbo_IDs[]); 84 | bool setupBVHBuffer(std::vector& bvh_data, float bvh_size, float scene_size); 85 | bool setupVertexBuffer(std::vector& vert_data, float scene_size); 86 | bool setupMatBuffer(std::vector& mat_data); 87 | 88 | std::string rk_file, rk_file_path, rk_name, ppk_file, ppk_file_path, ppk_name, rk_compiler_opts, ppk_compiler_opts; 89 | 90 | private: 91 | class Device 92 | { 93 | public: 94 | Device(); 95 | ~Device(); 96 | void loadInfo(cl_device_id dev_id); 97 | void displayInfo(int i); 98 | 99 | cl_device_id device_id; 100 | std::string name; 101 | std::string type; 102 | std::string device_ver; 103 | std::string device_openclC_ver; 104 | std::string driver_ver; 105 | std::string ext; 106 | std::vector max_workitem_size; 107 | cl_device_type device_type; 108 | cl_bool availability; 109 | cl_device_fp_config fp_support; 110 | cl_uint compute_units; 111 | size_t wg_size; 112 | cl_ulong global_mem_size; 113 | cl_ulong local_mem_size; 114 | cl_ulong constant_mem_size; 115 | bool clgl_event_ext; 116 | bool clgl_sharing_ext; 117 | }; 118 | 119 | class Platform 120 | { 121 | public: 122 | Platform(); 123 | ~Platform(); 124 | void loadInfo(cl_platform_id plat_id); 125 | void displayInfo(int i); 126 | 127 | cl_platform_id platform_id; 128 | std::string name; 129 | std::string vendor; 130 | std::string version; 131 | std::string profile; 132 | std::vector device_list; 133 | }; 134 | 135 | enum class Vendor 136 | { 137 | UNKNOWN, 138 | AMD, 139 | NVIDIA, 140 | INTEL 141 | }; 142 | 143 | Vendor mapPlatformToVendor(std::string str); /**< Helper function that maps arbitrary vendor names to a well defined Enum. */ 144 | void setupDevices(cl_context_properties* properties); /**< Load the device currently assosciated with OpenGL. */ 145 | void setupPlatforms(); /**< Display a list of OpenCL platforms and devices and select a platform. */ 146 | 147 | static std::function setMessageCb; /**< The function pointer to the RendererGUI message callback function. */ 148 | 149 | Platform target_platform; /**< The OpenCL platform ID fo the selected platform. */ 150 | Device target_device; /**< The OpenCL device ID of the selected device. */ 151 | cl_context context; /**< The OpenCL context. */ 152 | cl_program rk_program; /**< The OpenCL program object containing the Rendering kernel data. */ 153 | cl_program ppk_program; /**< The OpenCL program object containing the Post-processing kernel data. */ 154 | cl_command_queue comm_queue; /**< The OpenCL command queue.*/ 155 | cl_kernel rend_kernel; /**< The main path-tracer kernel.*/ 156 | cl_kernel pp_kernel; /**< The kernel for post processing effects like Tone mapping and Gamma Correction.*/ 157 | cl_mem image_buffers[4]; /**< Image Buffer Objects. There are 2 for swapping role between read and write-only images. Third is for postprocessing*/ 158 | cl_mem vert_buffer; /**< The Buffer Object used to hold Scene model data. */ 159 | cl_mem mat_buffer; /**< The Buffer Object used to hold material data. */ 160 | cl_mem bvh_buffer; /**< The Buffer Object used to hold bvh data. */ 161 | cl_mem binary_heap_buffer; /**< The Buffer Object used to hold binary heap which is used to traverse bvh. */ 162 | cl_mem camera_buffer; /**< The Buffer Object used to hold Camera data. */ 163 | 164 | size_t rendk_wgs; /**< The maximum nubmer of Work Items in a Workgroup the rendering kernel can afford due to memory limitations. */ 165 | size_t ppk_wgs; /**< The maximum nubmer of Work Items in a Workgroup the post processing kernel can afford due to memory limitations. */ 166 | size_t preferred_workgroup_multiple; /**< The preferred multiple the of the local workgroup size (depends on the device). */ 167 | 168 | 169 | friend class RendererCore; 170 | }; 171 | } 172 | #endif // CLMANAGER_H 173 | -------------------------------------------------------------------------------- /projects/msvc/Yune/Yune/Yune.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {43F019EE-1926-4F12-8CA1-77ABFDDEBAA5} 24 | Win32Proj 25 | Yune 26 | 10.0.17763.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | Level3 90 | Disabled 91 | true 92 | WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | pch.h 95 | %(AdditionalIncludeDirectories) 96 | 97 | 98 | Console 99 | true 100 | opengl32.lib;%(AdditionalDependencies) 101 | 102 | 103 | 104 | 105 | NotUsing 106 | Level3 107 | Disabled 108 | true 109 | _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | true 111 | pch.h 112 | ..\..\..\..\Dear-IMGUI;..\..\..\..\FileBrowser;..\..\..\..\include;%(AdditionalIncludeDirectories) 113 | 114 | 115 | Console 116 | true 117 | opengl32.lib;%(AdditionalDependencies) 118 | 119 | 120 | 121 | 122 | NotUsing 123 | Level3 124 | MaxSpeed 125 | true 126 | true 127 | true 128 | WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 129 | true 130 | pch.h 131 | %(AdditionalIncludeDirectories) 132 | 133 | 134 | Console 135 | true 136 | true 137 | true 138 | opengl32.lib;%(AdditionalDependencies) 139 | 140 | 141 | 142 | 143 | NotUsing 144 | Level3 145 | MaxSpeed 146 | true 147 | true 148 | true 149 | _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 150 | true 151 | pch.h 152 | ..\..\..\..\Dear-IMGUI;..\..\..\..\FileBrowser;..\..\..\..\include;%(AdditionalIncludeDirectories) 153 | 154 | 155 | Console 156 | true 157 | true 158 | true 159 | opengl32.lib;%(AdditionalDependencies) 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /src/GlfwManager.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #include "GlfwManager.h" 27 | #include "imgui.h" 28 | #include "imgui_impl_glfw.h" 29 | #include "imgui_impl_opengl3.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace yune 39 | { 40 | std::function GlfwManager::cameraUpdateCallback; 41 | std::function GlfwManager::setMessageCb; 42 | 43 | GlfwManager::GlfwManager(int window_width, int window_height) 44 | { 45 | //ctor 46 | glfwSetErrorCallback(errorCallback); 47 | if(!glfwInit()) 48 | throw std::runtime_error("GLFW failed to initialize."); 49 | window = NULL; 50 | space_flag = false; 51 | createWindow(window_width, window_height); 52 | initImGui(); 53 | } 54 | 55 | GlfwManager::~GlfwManager() 56 | { 57 | //Release OpenGL RBOs and FBO 58 | if(window) 59 | { 60 | glDeleteRenderbuffers(3, rbo_IDs); 61 | glDeleteFramebuffers(1, &fbo_ID); 62 | } 63 | 64 | ImGui_ImplOpenGL3_Shutdown(); 65 | ImGui_ImplGlfw_Shutdown(); 66 | ImGui::DestroyContext(); 67 | 68 | if(window) 69 | glfwDestroyWindow(window); 70 | glfwTerminate(); 71 | } 72 | 73 | void GlfwManager::initImGui() 74 | { 75 | // Setup Dear ImGui context 76 | IMGUI_CHECKVERSION(); 77 | ImGui::CreateContext(); 78 | ImGuiIO& io = ImGui::GetIO(); 79 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; 80 | 81 | // Setup Dear ImGui style 82 | ImGui::StyleColorsDark(); 83 | 84 | // Setup Platform/Renderer bindings 85 | ImGui_ImplGlfw_InitForOpenGL(window, true); 86 | ImGui_ImplOpenGL3_Init("#version 330"); 87 | } 88 | 89 | void GlfwManager::createWindow(int window_width, int window_height) 90 | { 91 | // get Primary Monitor and default Video Mode 92 | prim_monitor = glfwGetPrimaryMonitor(); 93 | mode = glfwGetVideoMode(prim_monitor); 94 | 95 | // Context Hints. 96 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 97 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 98 | glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); 99 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); 100 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 101 | 102 | //FrameBuffer Hints. 103 | glfwWindowHint(GLFW_RED_BITS, mode->redBits); 104 | glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); 105 | glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); 106 | glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); 107 | glfwWindowHint(GLFW_ALPHA_BITS, 8); 108 | glfwWindowHint(GLFW_STENCIL_BITS, 8); 109 | glfwWindowHint(GLFW_DEPTH_BITS, 24); 110 | 111 | 112 | //Window Hints 113 | glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); 114 | glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); 115 | 116 | this->window_width = window_width; 117 | this->window_height = window_height; 118 | window = glfwCreateWindow(window_width, window_height, "Yune", NULL, NULL); 119 | 120 | if(!window) 121 | { 122 | glfwTerminate(); 123 | throw std::runtime_error("Window creation failed.."); 124 | } 125 | 126 | glfwMakeContextCurrent(window); 127 | if( !gladLoadGLLoader( (GLADloadproc) glfwGetProcAddress) ) 128 | throw std::runtime_error("Couldn't Initialize GLAD.."); 129 | if(!GLAD_GL_VERSION_3_3) 130 | throw std::runtime_error("OpenGL version 3.3 not supported"); 131 | 132 | glGetError(); 133 | glfwSetWindowUserPointer(window, this); 134 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); 135 | glfwSetKeyCallback(window, keyCallback); 136 | glfwSetCursorPosCallback(window, cursorPosCallback); 137 | glfwSetFramebufferSizeCallback(window, framebufferSizeCallback); 138 | 139 | glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height); 140 | glViewport(0,0, framebuffer_width, framebuffer_height); 141 | glfwIconifyWindow(window); 142 | glClear(GL_COLOR_BUFFER_BIT); 143 | glfwSwapInterval(0); 144 | glfwPollEvents(); 145 | } 146 | 147 | bool GlfwManager::setupGlBuffer() 148 | { 149 | //Delete any previous RenderBuffer/FrameBuffer. Note that delete calls silently ignore any unused names and 0's 150 | glDeleteRenderbuffers(4, rbo_IDs); 151 | glDeleteFramebuffers(1, &fbo_ID); 152 | 153 | glGenFramebuffers(1,&fbo_ID); 154 | glBindFramebuffer(GL_FRAMEBUFFER,fbo_ID); 155 | 156 | glGenRenderbuffers(4, rbo_IDs); 157 | 158 | glBindRenderbuffer(GL_RENDERBUFFER, rbo_IDs[0]); 159 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, framebuffer_width, framebuffer_height); 160 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo_IDs[0]); 161 | 162 | glBindRenderbuffer(GL_RENDERBUFFER, rbo_IDs[1]); 163 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, framebuffer_width, framebuffer_height); 164 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rbo_IDs[1]); 165 | 166 | glBindRenderbuffer(GL_RENDERBUFFER, rbo_IDs[2]); 167 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, framebuffer_width, framebuffer_height); 168 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, rbo_IDs[2]); 169 | 170 | glBindRenderbuffer(GL_RENDERBUFFER, rbo_IDs[3]); 171 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, framebuffer_width, framebuffer_height); 172 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_RENDERBUFFER, rbo_IDs[3]); 173 | 174 | GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 175 | 176 | if(status != GL_FRAMEBUFFER_COMPLETE) 177 | { 178 | if(status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) 179 | setMessageCb("Framebuffer not complete. Error code: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", "FrameBuffer Incomplete!", ""); 180 | else if(status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) 181 | setMessageCb("Framebuffer not complete. Error code: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", "FrameBuffer Incomplete!", ""); 182 | else if(status == GL_FRAMEBUFFER_UNDEFINED) 183 | setMessageCb("Framebuffer not complete. Error code: GL_FRAMEBUFFER_UNDEFINED", "FrameBuffer Incomplete!", ""); 184 | else if(status == GL_FRAMEBUFFER_UNSUPPORTED) 185 | setMessageCb("Framebuffer not complete. Error code: GL_FRAMEBUFFER_UNSUPPORTED", "FrameBuffer Incomplete!", ""); 186 | else if(status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) 187 | setMessageCb("Framebuffer not complete. Error code: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER", "FrameBuffer Incomplete!", ""); 188 | else if(status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) 189 | setMessageCb("Framebuffer not complete. Error code: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER", "FrameBuffer Incomplete!", ""); 190 | else 191 | setMessageCb("Framebuffer not complete. Error code: " + std::to_string((int)status), "FrameBuffer Incomplete!", ""); 192 | return false; 193 | } 194 | 195 | glClearColor(0.f, 0.f, 0.f, 1.0f); 196 | glDrawBuffer(GL_COLOR_ATTACHMENT0); 197 | glClear(GL_COLOR_BUFFER_BIT); 198 | 199 | glDrawBuffer(GL_COLOR_ATTACHMENT1); 200 | glClear(GL_COLOR_BUFFER_BIT); 201 | 202 | glDrawBuffer(GL_COLOR_ATTACHMENT2); 203 | glClear(GL_COLOR_BUFFER_BIT); 204 | 205 | glDrawBuffer(GL_COLOR_ATTACHMENT3); 206 | glClear(GL_COLOR_BUFFER_BIT); 207 | 208 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 209 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 210 | return true; 211 | } 212 | 213 | void GlfwManager::showWindow() 214 | { 215 | glfwRestoreWindow(window); 216 | glfwFocusWindow(window); 217 | } 218 | 219 | void GlfwManager::errorCallback(int error, const char* msg) 220 | { 221 | std::cout << msg << std::endl; 222 | } 223 | 224 | void GlfwManager::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) 225 | { 226 | if(ImGui::GetIO().WantCaptureKeyboard) 227 | return; 228 | GlfwManager* ptr = (GlfwManager*) glfwGetWindowUserPointer(window); 229 | 230 | if(key == GLFW_KEY_UP && (action == GLFW_PRESS || action == GLFW_REPEAT) ) 231 | GlfwManager::cameraUpdateCallback(glm::vec4(0,0,1,0), 0, 0); 232 | 233 | if(key == GLFW_KEY_DOWN && (action == GLFW_PRESS || action == GLFW_REPEAT) ) 234 | cameraUpdateCallback(glm::vec4(0,0, -1,0), 0, 0); 235 | 236 | if(key == GLFW_KEY_LEFT && (action == GLFW_PRESS || action == GLFW_REPEAT) ) 237 | cameraUpdateCallback(glm::vec4(-1,0,0,0), 0, 0); 238 | 239 | if(key == GLFW_KEY_RIGHT && (action == GLFW_PRESS || action == GLFW_REPEAT) ) 240 | cameraUpdateCallback(glm::vec4(1,0,0,0), 0, 0); 241 | 242 | if(key == GLFW_KEY_HOME && (action == GLFW_PRESS || action == GLFW_REPEAT) ) 243 | GlfwManager::cameraUpdateCallback(glm::vec4(0,1,0,0), 0, 0); 244 | 245 | if(key == GLFW_KEY_END && (action == GLFW_PRESS || action == GLFW_REPEAT) ) 246 | cameraUpdateCallback(glm::vec4(0,-1, 0,0), 0, 0); 247 | 248 | if(key == GLFW_KEY_SPACE && action == GLFW_PRESS ) 249 | ptr->space_flag = true; 250 | if(key == GLFW_KEY_SPACE && action == GLFW_RELEASE ) 251 | ptr->space_flag = false; 252 | 253 | } 254 | 255 | void GlfwManager::cursorPosCallback(GLFWwindow* window, double new_cursor_x, double new_cursor_y) 256 | { 257 | GlfwManager* ptr = (GlfwManager*) glfwGetWindowUserPointer(window); 258 | if(ptr->space_flag) 259 | { 260 | float delta_x, delta_y; 261 | float x_rad = 0.06, y_rad = 0.06; 262 | 263 | delta_x = new_cursor_x - ptr->old_cursor_x; 264 | delta_y = new_cursor_y - ptr->old_cursor_y; 265 | 266 | if(delta_x < 1 && delta_x > -1) 267 | y_rad = 0; 268 | else if (delta_x > 0) 269 | y_rad *= -1.0; 270 | 271 | if(delta_y < 1 && delta_y > -1) 272 | x_rad = 0; 273 | else if(delta_y > 0) 274 | x_rad *= -1.0; 275 | cameraUpdateCallback(glm::vec4(0,0,0,0), x_rad, y_rad); 276 | ptr->old_cursor_x = new_cursor_x; 277 | ptr->old_cursor_y = new_cursor_y; 278 | } 279 | else 280 | { 281 | ptr->old_cursor_x = new_cursor_x; 282 | ptr->old_cursor_y = new_cursor_y; 283 | } 284 | } 285 | 286 | void GlfwManager::framebufferSizeCallback(GLFWwindow* window, int width, int height) 287 | { 288 | GlfwManager* ptr = (GlfwManager*) glfwGetWindowUserPointer(window); 289 | glViewport(0, 0, width, height); 290 | ptr->framebuffer_width = width; 291 | ptr->framebuffer_height = height; 292 | } 293 | 294 | void GlfwManager::setCameraUpdateCallback(std::function cb) 295 | { 296 | GlfwManager::cameraUpdateCallback = cb; 297 | } 298 | 299 | void GlfwManager::setGuiMessageCb(std::function cb) 300 | { 301 | GlfwManager::setMessageCb = cb; 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /src/BVH.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #include "BVH.h" 27 | #include 28 | 29 | #include 30 | #include // min(); max(); 31 | 32 | namespace yune 33 | { 34 | BVH::BVH() 35 | { 36 | bins = 20; 37 | leaf_primitives = 10; 38 | cost_isect = 1; 39 | cost_trav = 1/8.0f; 40 | clearValues(); 41 | //ctor 42 | } 43 | 44 | BVH::~BVH() 45 | { 46 | //dtor 47 | } 48 | 49 | void BVH::clearValues() 50 | { 51 | bvh_size_kb = 0, bvh_size_mb = 0; 52 | cpu_node_list.clear(); 53 | gpu_node_list.clear(); 54 | } 55 | 56 | void BVH::createBVH(AABB root, const std::vector& cpu_tri_list, int bvh_bins) 57 | { 58 | clearValues(); 59 | bins = bvh_bins; 60 | 61 | cpu_node_list.push_back(BVHNodeCPU(root)); 62 | for(int i = 0; i < cpu_tri_list.size(); i++) 63 | cpu_node_list[0].primitives.push_back(i); 64 | 65 | for(int i = 0; i < cpu_node_list.size(); i++) 66 | { 67 | bool switch_to_median = false; 68 | BVHNodeCPU parent_node = cpu_node_list[i]; 69 | AABB parent_aabb = parent_node.gpu_node.aabb; 70 | 71 | //If node is empty, no need to split 72 | if(parent_node.primitives.empty()) 73 | continue; 74 | 75 | if(parent_node.primitives.size() <= leaf_primitives) 76 | { 77 | cpu_node_list[i].gpu_node.vert_len = parent_node.primitives.size(); 78 | cpu_node_list[i].gpu_node.child_idx = -1; 79 | for(int j = 0; j < parent_node.primitives.size(); j++) 80 | cpu_node_list[i].gpu_node.vert_list[j] = parent_node.primitives[j]; 81 | continue; 82 | } 83 | //Find the axis across which to split to form 2 BVH nodes 84 | BVH::SplitAxis split_axis = findSplitAxis(cpu_tri_list, parent_node.primitives); 85 | 86 | //If the Node is big enough use SAH else just split in middle 87 | BVHNodeCPU node_c1, node_c2; 88 | int selection = 0; 89 | if(bins > 2 && parent_node.primitives.size() > 20 && !switch_to_median) 90 | { 91 | float cost = getSurfaceArea(parent_aabb) * cost_isect * parent_node.primitives.size(); 92 | float initial_cost = cost; 93 | float increment = parent_aabb.p_max.s[split_axis] - parent_aabb.p_min.s[split_axis]; 94 | increment /= bins; 95 | 96 | //Find the best possible split location 97 | for(int i = 0; i < bins-1; i++) 98 | { 99 | AABB c1_aabb, c2_aabb; 100 | 101 | c1_aabb.p_min = parent_aabb.p_min; 102 | c1_aabb.p_max = parent_aabb.p_max; 103 | c1_aabb.p_max.s[split_axis] = parent_aabb.p_min.s[split_axis] + (i+1)*increment; 104 | 105 | c2_aabb.p_min = parent_aabb.p_min; 106 | c2_aabb.p_min.s[split_axis] = c1_aabb.p_max.s[split_axis]; 107 | c2_aabb.p_max = parent_aabb.p_max; 108 | 109 | BVHNodeCPU temp_c1(c1_aabb), temp_c2(c2_aabb); 110 | 111 | //Find the child primitives of each temporary node 112 | populateChildNodes(parent_node, temp_c1, temp_c2, cpu_tri_list); 113 | float new_cost = cost_trav + 114 | (getSurfaceArea(c1_aabb)/getSurfaceArea(parent_aabb)) * (cost_isect * temp_c1.primitives.size()) + 115 | getSurfaceArea(c2_aabb)/getSurfaceArea(parent_aabb) * (cost_isect * temp_c2.primitives.size()); 116 | 117 | //If new cost is less than previous cost we choose this split location. 118 | if(new_cost < cost) 119 | { 120 | node_c1.gpu_node.aabb = c1_aabb; 121 | node_c2.gpu_node.aabb = c2_aabb; 122 | node_c1.primitives = temp_c1.primitives; 123 | node_c2.primitives = temp_c2.primitives; 124 | cost = new_cost; 125 | } 126 | } 127 | if(cost == initial_cost && parent_node.primitives.size() > leaf_primitives) 128 | switch_to_median = true; 129 | else if(cost == initial_cost && parent_node.primitives.size() <= leaf_primitives) 130 | { 131 | cpu_node_list[i].gpu_node.vert_len = parent_node.primitives.size(); 132 | cpu_node_list[i].gpu_node.child_idx = -1; 133 | if(parent_node.primitives.size() > 0) 134 | { 135 | for(int j = 0; j < parent_node.primitives.size(); j++) 136 | cpu_node_list[i].gpu_node.vert_list[j] = parent_node.primitives[j]; 137 | } 138 | continue; 139 | } 140 | } 141 | else 142 | switch_to_median = true; 143 | 144 | // IF SAH decided not to split and primitives are greater than leaf primitives, we still need to split so switch to median splitting... 145 | if(switch_to_median) 146 | { 147 | cl_float4 center = parent_aabb.p_min + parent_aabb.p_max; 148 | center = center / 2.0f; 149 | 150 | node_c1.gpu_node.aabb.p_min = parent_aabb.p_min; 151 | node_c1.gpu_node.aabb.p_max = parent_aabb.p_max; 152 | node_c1.gpu_node.aabb.p_max.s[split_axis] = center.s[split_axis]; 153 | 154 | node_c2.gpu_node.aabb.p_max = parent_aabb.p_max; 155 | node_c2.gpu_node.aabb.p_min = parent_aabb.p_min; 156 | node_c2.gpu_node.aabb.p_min.s[split_axis] = center.s[split_axis]; 157 | 158 | //Find the child primitives of each temporary node 159 | populateChildNodes(parent_node, node_c1, node_c2, cpu_tri_list); 160 | } 161 | cpu_node_list[i].gpu_node.child_idx = cpu_node_list.size(); 162 | cpu_node_list.push_back(node_c1); 163 | cpu_node_list.push_back(node_c2); 164 | 165 | } 166 | 167 | resizeBvh(cpu_tri_list); 168 | for(int i = 0; i < cpu_node_list.size(); i++) 169 | gpu_node_list.push_back(cpu_node_list[i].gpu_node); 170 | 171 | bvh_size_kb = (float)gpu_node_list.size() * sizeof(BVHNodeGPU) / 1024; 172 | bvh_size_mb = bvh_size_kb / 1024; 173 | } 174 | 175 | void BVH::populateChildNodes(const BVHNodeCPU& parent, BVHNodeCPU& c1, BVHNodeCPU& c2, const std::vector& cpu_tri_list) 176 | { 177 | int child_empty = -1; // 0 == c1 empty, 1 == c2 empty 178 | 179 | if(getSurfaceArea(c1.gpu_node.aabb) == 0.0f) 180 | child_empty = 0; 181 | else if(getSurfaceArea(c2.gpu_node.aabb) == 0.0f) 182 | child_empty = 1; 183 | 184 | if(child_empty == 0) 185 | { 186 | for(int i = 0; i < parent.primitives.size(); i++) 187 | c2.primitives.push_back(parent.primitives[i]); 188 | } 189 | else if(child_empty == 1) 190 | { 191 | for(int i = 0; i < parent.primitives.size(); i++) 192 | c1.primitives.push_back(parent.primitives[i]); 193 | } 194 | else 195 | { 196 | for(int i = 0; i < parent.primitives.size(); i++) 197 | { 198 | cl_float4 center; 199 | center = cpu_tri_list[parent.primitives[i]].centroid; 200 | bool in_c1 = true; 201 | for(int i = 0; i < 3; i++) 202 | { 203 | if(center.s[i] < c1.gpu_node.aabb.p_min.s[i] || center.s[i] > c1.gpu_node.aabb.p_max.s[i]) 204 | { 205 | in_c1 = false; 206 | break; 207 | } 208 | } 209 | if(in_c1) 210 | c1.primitives.push_back(parent.primitives[i]); 211 | else 212 | c2.primitives.push_back(parent.primitives[i]); 213 | } 214 | } 215 | 216 | } 217 | 218 | void BVH::resizeBvh(const std::vector& cpu_tri_list) 219 | { 220 | float fmax = std::numeric_limits::max(); 221 | float fmin = -std::numeric_limits::max(); 222 | 223 | AABB parent; 224 | parent.p_min = {fmax, fmax, fmax, 1.0f}; 225 | parent.p_max = {fmin, fmin, fmin, 1.0f}; 226 | 227 | for(int j = cpu_node_list.size() - 1; j >= 0; j--) 228 | { 229 | BVHNodeCPU node = cpu_node_list[j]; 230 | if(node.gpu_node.vert_len > 0) 231 | { 232 | for(int i = 0; i < node.primitives.size(); i++) 233 | parent = getExtent(parent, cpu_tri_list[node.primitives[i]].aabb); 234 | 235 | cpu_node_list[j].gpu_node.aabb.p_min = parent.p_min; 236 | cpu_node_list[j].gpu_node.aabb.p_max = parent.p_max; 237 | 238 | parent.p_min = {fmax, fmax, fmax, 1.0f}; 239 | parent.p_max = {fmin, fmin, fmin, 1.0f}; 240 | } 241 | else if(node.gpu_node.child_idx > 0) 242 | { 243 | int c_idx = node.gpu_node.child_idx; 244 | cpu_node_list[j].gpu_node.aabb = getExtent(cpu_node_list[c_idx].gpu_node.aabb, cpu_node_list[c_idx+1].gpu_node.aabb); 245 | } 246 | } 247 | } 248 | 249 | void BVH::resizeBvhNode(BVHNodeCPU& node, const std::vector& cpu_tri_list) 250 | { 251 | float fmax = std::numeric_limits::max(); 252 | float fmin = -std::numeric_limits::max(); 253 | 254 | AABB parent; 255 | parent.p_min = {fmax, fmax, fmax, 1.0f}; 256 | parent.p_max = {fmin, fmin, fmin, 1.0f}; 257 | 258 | for(int j = 0; j < node.primitives.size(); j--) 259 | { 260 | int idx = node.primitives[j]; 261 | parent = getExtent(parent, cpu_tri_list[idx].aabb); 262 | } 263 | 264 | node.gpu_node.aabb.p_min = parent.p_min; 265 | node.gpu_node.aabb.p_max = parent.p_max; 266 | } 267 | 268 | AABB BVH::getExtent(const AABB& bb1, const AABB& bb2) 269 | { 270 | AABB parent = bb1; 271 | 272 | for(int i = 0; i < 3; i++) 273 | { 274 | parent.p_min.s[i] = std::min(bb2.p_min.s[i], bb1.p_min.s[i]); 275 | parent.p_max.s[i] = std::max(bb2.p_max.s[i], bb1.p_max.s[i]); 276 | } 277 | return parent; 278 | } 279 | 280 | BVH::SplitAxis BVH::findSplitAxis(const std::vector& cpu_tri_list, std::vector& child_list) 281 | { 282 | AABB parent; 283 | float fmax = std::numeric_limits::max(); 284 | float fmin = -fmax; 285 | float diff = -fmax; 286 | BVH::SplitAxis split_axis = SplitAxis::X; 287 | 288 | parent.p_min = {fmax, fmax, fmax, 1.0f}; 289 | parent.p_max = {fmin, fmin, fmin, 1.0f}; 290 | 291 | for(int j = 0; j < child_list.size(); j++) 292 | { 293 | int k = child_list[j]; 294 | //Find min/max X 295 | parent = getExtent(parent, cpu_tri_list[k].aabb); 296 | } 297 | 298 | cl_float4 diag = parent.p_max - parent.p_min; 299 | 300 | for(int i = 0; i < 3; i++) 301 | { 302 | if(diag.s[i] > diff) 303 | { 304 | diff = diag.s[i]; 305 | if(i == 0) 306 | split_axis = SplitAxis::X; 307 | else if(i == 1) 308 | split_axis = SplitAxis::Y; 309 | else 310 | split_axis = SplitAxis::Z; 311 | } 312 | } 313 | return split_axis; 314 | } 315 | 316 | float BVH::getSurfaceArea(AABB aabb) 317 | { 318 | cl_float4 diag = aabb.p_max - aabb.p_min; 319 | return 2 * (diag.s[0] * diag.s[1] + diag.s[0] * diag.s[2] + diag.s[1] * diag.s[2]); 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/Scene.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * This file is part of Yune". 3 | * 4 | * Copyright (C) 2018 by Umair Ahmed and Syed Moiz Hussain. 5 | * 6 | * "Yune" is a personal project and an educational raytracer/pathtracer. It's aimed at young 7 | * researchers trying to implement raytracing/pathtracing but don't want to mess with boilerplate code. 8 | * It provides all basic functionality to open a window, save images, etc. Since it's GPU based, you only need to modify 9 | * the kernel file and see your program in action. For details, check 10 | * 11 | * "Yune" is a free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * "Yune" is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | ******************************************************************************/ 25 | 26 | #include "Scene.h" 27 | #include "glm/vec3.hpp" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace yune 40 | { 41 | Scene::Scene() 42 | { 43 | clearValues(); 44 | } 45 | 46 | Scene::~Scene() 47 | { 48 | } 49 | 50 | void Scene::clearValues() 51 | { 52 | num_triangles = scene_size_kb = scene_size_mb =0; 53 | mat_filename.clear(); 54 | mat_file.clear(); 55 | scene_file.clear(); 56 | vert_data.clear(); 57 | mat_data.clear(); 58 | cpu_tri_list.clear(); 59 | cpu_tri_list.reserve(6000); 60 | } 61 | 62 | void Scene::reloadMatFile() 63 | { 64 | std::fstream file; 65 | file.open(mat_file); 66 | 67 | if(file.is_open()) 68 | { 69 | mat_data.clear(); 70 | std::cout << "\nReloading Material File..." << std::endl; 71 | std::string extract, line; 72 | cl_float x,y,z,w = 1.0f; 73 | 74 | while(getline(file, line)) 75 | { 76 | std::stringstream ss; 77 | // skip comments and empty lines 78 | if(line[0] == '#' || line.empty()) 79 | continue; 80 | 81 | ss.str(line); 82 | ss >> extract; 83 | 84 | if(extract == "newmtl") 85 | { 86 | std::string id; 87 | ss >> id; 88 | mat_data.push_back(newMaterial()); 89 | } 90 | else if(extract == "ke") 91 | { 92 | ss >> x >> y >> z; 93 | mat_data.back().ke = {x,y,z,w}; 94 | } 95 | else if(extract == "kd") 96 | { 97 | ss >> x >> y >> z; 98 | mat_data.back().kd = {x,y,z,w}; 99 | } 100 | else if(extract == "ks") 101 | { 102 | ss >> x >> y >> z; 103 | mat_data.back().ks = {x,y,z,w}; 104 | } 105 | else if(extract == "n") 106 | ss >> mat_data.back().n; 107 | else if(extract == "k") 108 | ss >> mat_data.back().k; 109 | 110 | else if(extract == "px") 111 | ss >> mat_data.back().py; 112 | else if(extract == "py") 113 | ss >> mat_data.back().px; 114 | 115 | else if(extract == "alpha_x") 116 | ss >> mat_data.back().alpha_x; 117 | else if(extract == "alpha_y") 118 | ss >> mat_data.back().alpha_y; 119 | 120 | else if(extract == "is_specular") 121 | ss >> mat_data.back().is_specular; 122 | else if(extract == "is_transmissive") 123 | ss >> mat_data.back().is_transmissive; 124 | } 125 | if(mat_data.empty()) 126 | throw std::runtime_error("Bad Material file."); 127 | } 128 | else 129 | throw std::runtime_error("Error opening material file."); 130 | std::cout << "Reloaded successfully!" << std::endl; 131 | } 132 | 133 | void Scene::loadModel(std::string filepath, std::string filename) 134 | { 135 | clearValues(); 136 | std::string mat_fn = getMatFileName(filepath); 137 | std::string mat_fp = filepath; 138 | bool create_new_matfile = false; 139 | if(mat_fn.empty()) 140 | { 141 | create_new_matfile = true; 142 | mat_fn = filename; 143 | mat_fn.replace(filename.size() - 3, 3, "mtl"); 144 | } 145 | mat_fp.erase(mat_fp.find_last_of("/")+1); 146 | mat_fp += mat_fn; 147 | std::fstream file; 148 | std::map mat_index; 149 | 150 | if(create_new_matfile) 151 | file.open(mat_fp, std::fstream::out); 152 | else 153 | file.open(mat_fp); 154 | 155 | if(file.is_open()) 156 | { 157 | if(create_new_matfile) 158 | { 159 | std::cout << "\nMaterial File Not Found. Creating Default File..." << std::endl; 160 | mat_index["default"] = 0; 161 | mat_data.push_back(newMaterial()); 162 | file << "ke " << "0 0 0" << "\n" 163 | << "kd " << "0.3 0.3 0.3" << "\n" 164 | << "ks " << "0 0 0" << "\n" 165 | << "n 1" << "\n" << "k 1" << "\n" << "px 0" << "\n" << "py 0" << "\n" 166 | << "alpha_x 100" << "\n" << "alpha_y 100" << "\n" << "is_specular 0" << "\n" << "is_transmissive 0"; 167 | std::cout << "File created successfully!" << std::endl; 168 | } 169 | else 170 | { 171 | std::cout << "\nReading Material File..." << std::endl; 172 | std::string extract, line; 173 | cl_float x,y,z,w = 1.0f; 174 | 175 | while(getline(file, line)) 176 | { 177 | std::stringstream ss; 178 | // skip comments and empty lines 179 | if(line[0] == '#' || line.empty()) 180 | continue; 181 | 182 | ss.str(line); 183 | ss >> extract; 184 | 185 | if(extract == "newmtl") 186 | { 187 | std::string id; 188 | ss >> id; 189 | mat_index[id] = mat_data.size(); 190 | mat_data.push_back(newMaterial()); 191 | } 192 | else if(extract == "ke") 193 | { 194 | ss >> x >> y >> z; 195 | mat_data.back().ke = {x,y,z,w}; 196 | } 197 | else if(extract == "kd") 198 | { 199 | ss >> x >> y >> z; 200 | mat_data.back().kd = {x,y,z,w}; 201 | } 202 | else if(extract == "ks") 203 | { 204 | ss >> x >> y >> z; 205 | mat_data.back().ks = {x,y,z,w}; 206 | } 207 | else if(extract == "n") 208 | ss >> mat_data.back().n; 209 | else if(extract == "k") 210 | ss >> mat_data.back().k; 211 | 212 | else if(extract == "px") 213 | ss >> mat_data.back().py; 214 | else if(extract == "py") 215 | ss >> mat_data.back().px; 216 | 217 | else if(extract == "alpha_x") 218 | ss >> mat_data.back().alpha_x; 219 | else if(extract == "alpha_y") 220 | ss >> mat_data.back().alpha_y; 221 | 222 | else if(extract == "is_specular") 223 | ss >> mat_data.back().is_specular; 224 | else if(extract == "is_transmissive") 225 | ss >> mat_data.back().is_transmissive; 226 | } 227 | if(mat_data.empty()) 228 | throw std::runtime_error("Bad Material file."); 229 | std::cout << "Material File read successfully!" << std::endl; 230 | } 231 | 232 | file.close(); 233 | } 234 | else 235 | throw std::runtime_error("Error opening material file."); 236 | 237 | //Read Vertex Data 238 | file.open(filepath); 239 | if(file.is_open()) 240 | { 241 | std::cout << "\nReading Object File..." << std::endl; 242 | float inf = std::numeric_limits::max(); 243 | root.p_min = {inf, inf, inf, 1.0}; 244 | root.p_max = {-inf, -inf, -inf, 1.0}; 245 | std::string extract, line; 246 | 247 | std::vector vertices; 248 | std::vector normals; 249 | std::string matID = ""; 250 | int idx = -1; 251 | while(getline(file, line)) 252 | { 253 | std::stringstream ss; 254 | 255 | // skip comments and empty lines 256 | if(line[0] == '#' || line.empty()) 257 | continue; 258 | 259 | ss.str(line); 260 | ss >> extract; 261 | 262 | if(extract == "mtllib") 263 | continue; 264 | 265 | if(extract == "o") 266 | { 267 | //vertices.clear(); 268 | //normals.clear(); 269 | matID.clear(); 270 | } 271 | else if(extract == "v") 272 | { 273 | vertices.push_back(glm::vec3()); 274 | ss >> vertices.back().x >> vertices.back().y >> vertices.back().z; 275 | } 276 | else if(extract == "vn") 277 | { 278 | normals.push_back(glm::vec3()); 279 | ss >> normals.back().x >> normals.back().y >> normals.back().z; 280 | } 281 | else if(extract == "usemtl") 282 | { 283 | ss >> matID; 284 | if(mat_index.find(matID) != mat_index.end()) 285 | idx = mat_index.at(matID); 286 | else 287 | idx = 0; 288 | } 289 | else if(extract == "f") 290 | { 291 | //If this is the first face read, we need to initialize material information if usemtl was not present 292 | if(idx < 0) 293 | { 294 | if(mat_index.find(matID) != mat_index.end()) 295 | idx = mat_index.at(matID); 296 | else 297 | idx = 0; 298 | } 299 | 300 | cpu_tri_list.push_back(TriangleCPU()); 301 | cpu_tri_list.back().props.matID = idx; 302 | std::string token; 303 | 304 | for(int i = 0; i < 3; i++) 305 | { 306 | std::stringstream sstr; 307 | ss >> extract; 308 | sstr.str(extract); 309 | int j = 0; 310 | while(getline(sstr, token, '/')) 311 | { 312 | //Skip Vt 313 | if(j == 1) 314 | { 315 | j++; 316 | continue; 317 | } 318 | 319 | glm::vec3 vec; 320 | if(j == 0) 321 | vec = vertices[std::stoi(token)-1]; 322 | else if(j == 2) 323 | vec = normals[std::stoi(token)-1]; 324 | 325 | if(i == 0) 326 | { 327 | if(j == 0) 328 | cpu_tri_list.back().props.v1 = {vec.x, vec.y, vec.z, 1.0f}; 329 | else if(j == 2) 330 | cpu_tri_list.back().props.vn1 = {vec.x, vec.y, vec.z, 0.0f}; 331 | } 332 | else if(i == 1) 333 | { 334 | if(j == 0) 335 | cpu_tri_list.back().props.v2 = {vec.x, vec.y, vec.z, 1.0f}; 336 | else if(j == 2) 337 | cpu_tri_list.back().props.vn2 = {vec.x, vec.y, vec.z, 0.0f}; 338 | } 339 | else if(i == 2) 340 | { 341 | if(j == 0) 342 | cpu_tri_list.back().props.v3 = {vec.x, vec.y, vec.z, 1.0f}; 343 | else if(j == 2) 344 | cpu_tri_list.back().props.vn3 = {vec.x, vec.y, vec.z, 0.0f}; 345 | } 346 | j++; 347 | } 348 | } 349 | 350 | //Compute AABB after 3rd vertex is fed. 351 | cpu_tri_list.back().computeCentroid(); 352 | for(int k = 0; k < 3; k++) 353 | { 354 | root.p_min.s[k] = std::min(root.p_min.s[k], cpu_tri_list.back().aabb.p_min.s[k]); 355 | root.p_max.s[k] = std::max(root.p_max.s[k], cpu_tri_list.back().aabb.p_max.s[k]); 356 | } 357 | } 358 | } 359 | std::cout << "Object File read successfully!" << std::endl; 360 | file.close(); 361 | 362 | for(int i = 0; i < cpu_tri_list.size(); i++) 363 | vert_data.push_back(cpu_tri_list[i].props); 364 | 365 | std::cout << "Total Triangles Loaded: " << vert_data.size() << std::endl; 366 | if(bvh.bins > 0) 367 | { 368 | std::cout << "\nCreating BVH..." << std::endl; 369 | bvh.createBVH(root, cpu_tri_list); 370 | std::cout << "BVH created successfully!" << std::endl; 371 | std::cout << "BVH Size: " << bvh.gpu_node_list.size() << " Nodes" << std::endl; 372 | } 373 | } 374 | else 375 | throw std::runtime_error("Error opening object file..."); 376 | scene_file = filename; 377 | mat_file = mat_fp; 378 | mat_filename = mat_fn; 379 | num_triangles = vert_data.size(); 380 | scene_size_kb = (float) vert_data.size() * sizeof(TriangleGPU) / 1024; 381 | scene_size_kb += (float) mat_data.size() * sizeof(Material) / 1024; 382 | scene_size_mb = scene_size_kb / 1024; 383 | } 384 | 385 | std::string Scene::getMatFileName(std::string filepath) 386 | { 387 | std::fstream file; 388 | file.open(filepath); 389 | if(file.is_open()) 390 | { 391 | std::string extract, line; 392 | while(getline(file, line)) 393 | { 394 | std::stringstream ss; 395 | // skip comments and empty lines 396 | if(line[0] == '#' || line.empty()) 397 | continue; 398 | 399 | ss.str(line); 400 | ss >> extract; 401 | 402 | if(extract != "mtllib") 403 | return ""; 404 | 405 | ss >> extract; 406 | return extract; 407 | } 408 | } 409 | return ""; 410 | } 411 | 412 | void Scene::loadBVH(int bvh_bins) 413 | { 414 | bvh.createBVH(root, cpu_tri_list, bvh_bins); 415 | } 416 | } 417 | 418 | -------------------------------------------------------------------------------- /Dear-IMGUI/imgui_impl_glfw.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for GLFW 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) 4 | // (Requires: GLFW 3.1+) 5 | 6 | // Implemented features: 7 | // [X] Platform: Clipboard support. 8 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). 10 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). 11 | 12 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 13 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 14 | // https://github.com/ocornut/imgui 15 | 16 | // CHANGELOG 17 | // (minor and older changes stripped away, please see git history for details) 18 | // 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors. 19 | // 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor). 20 | // 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown. 21 | // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. 22 | // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). 23 | // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. 24 | // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. 25 | // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. 26 | // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. 27 | // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. 28 | // 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. 29 | // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. 30 | // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). 31 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 32 | // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. 33 | // 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. 34 | // 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). 35 | // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. 36 | // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. 37 | // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). 38 | // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. 39 | 40 | #include "imgui.h" 41 | #include "imgui_impl_glfw.h" 42 | 43 | // GLFW 44 | #include 45 | #ifdef _WIN32 46 | #undef APIENTRY 47 | #define GLFW_EXPOSE_NATIVE_WIN32 48 | #include // for glfwGetWin32Window 49 | #endif 50 | #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING 51 | #define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED 52 | #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity 53 | #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale 54 | #define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface 55 | #ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? 56 | #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR 57 | #else 58 | #define GLFW_HAS_NEW_CURSORS (0) 59 | #endif 60 | 61 | // Data 62 | enum GlfwClientApi 63 | { 64 | GlfwClientApi_Unknown, 65 | GlfwClientApi_OpenGL, 66 | GlfwClientApi_Vulkan 67 | }; 68 | static GLFWwindow* g_Window = NULL; // Main window 69 | static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; 70 | static double g_Time = 0.0; 71 | static bool g_MouseJustPressed[5] = { false, false, false, false, false }; 72 | static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {}; 73 | static bool g_InstalledCallbacks = false; 74 | 75 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. 76 | static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; 77 | static GLFWscrollfun g_PrevUserCallbackScroll = NULL; 78 | static GLFWkeyfun g_PrevUserCallbackKey = NULL; 79 | static GLFWcharfun g_PrevUserCallbackChar = NULL; 80 | 81 | static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) 82 | { 83 | return glfwGetClipboardString((GLFWwindow*)user_data); 84 | } 85 | 86 | static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) 87 | { 88 | glfwSetClipboardString((GLFWwindow*)user_data, text); 89 | } 90 | 91 | void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) 92 | { 93 | if (g_PrevUserCallbackMousebutton != NULL) 94 | g_PrevUserCallbackMousebutton(window, button, action, mods); 95 | 96 | if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed)) 97 | g_MouseJustPressed[button] = true; 98 | } 99 | 100 | void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) 101 | { 102 | if (g_PrevUserCallbackScroll != NULL) 103 | g_PrevUserCallbackScroll(window, xoffset, yoffset); 104 | 105 | ImGuiIO& io = ImGui::GetIO(); 106 | io.MouseWheelH += (float)xoffset; 107 | io.MouseWheel += (float)yoffset; 108 | } 109 | 110 | void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) 111 | { 112 | if (g_PrevUserCallbackKey != NULL) 113 | g_PrevUserCallbackKey(window, key, scancode, action, mods); 114 | 115 | ImGuiIO& io = ImGui::GetIO(); 116 | if (action == GLFW_PRESS) 117 | io.KeysDown[key] = true; 118 | if (action == GLFW_RELEASE) 119 | io.KeysDown[key] = false; 120 | 121 | // Modifiers are not reliable across systems 122 | io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; 123 | io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; 124 | io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; 125 | #ifdef _WIN32 126 | io.KeySuper = false; 127 | #else 128 | io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; 129 | #endif 130 | } 131 | 132 | void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) 133 | { 134 | if (g_PrevUserCallbackChar != NULL) 135 | g_PrevUserCallbackChar(window, c); 136 | 137 | ImGuiIO& io = ImGui::GetIO(); 138 | io.AddInputCharacter(c); 139 | } 140 | 141 | static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) 142 | { 143 | g_Window = window; 144 | g_Time = 0.0; 145 | 146 | // Setup back-end capabilities flags 147 | ImGuiIO& io = ImGui::GetIO(); 148 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) 149 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) 150 | io.BackendPlatformName = "imgui_impl_glfw"; 151 | 152 | // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. 153 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; 154 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; 155 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; 156 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; 157 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; 158 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; 159 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; 160 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; 161 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; 162 | io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; 163 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; 164 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; 165 | io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; 166 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; 167 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; 168 | io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; 169 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; 170 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; 171 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; 172 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; 173 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; 174 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; 175 | 176 | io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; 177 | io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; 178 | io.ClipboardUserData = g_Window; 179 | #if defined(_WIN32) 180 | io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window); 181 | #endif 182 | 183 | // Create mouse cursors 184 | // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, 185 | // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. 186 | // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.) 187 | GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL); 188 | g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); 189 | g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); 190 | g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); 191 | g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); 192 | g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); 193 | #if GLFW_HAS_NEW_CURSORS 194 | g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR); 195 | g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR); 196 | g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR); 197 | g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR); 198 | #else 199 | g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); 200 | g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); 201 | g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); 202 | g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); 203 | #endif 204 | glfwSetErrorCallback(prev_error_callback); 205 | 206 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. 207 | g_PrevUserCallbackMousebutton = NULL; 208 | g_PrevUserCallbackScroll = NULL; 209 | g_PrevUserCallbackKey = NULL; 210 | g_PrevUserCallbackChar = NULL; 211 | if (install_callbacks) 212 | { 213 | g_InstalledCallbacks = true; 214 | g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); 215 | g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); 216 | g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); 217 | g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); 218 | } 219 | 220 | g_ClientApi = client_api; 221 | return true; 222 | } 223 | 224 | bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) 225 | { 226 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); 227 | } 228 | 229 | bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) 230 | { 231 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); 232 | } 233 | 234 | void ImGui_ImplGlfw_Shutdown() 235 | { 236 | if (g_InstalledCallbacks) 237 | { 238 | glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton); 239 | glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll); 240 | glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey); 241 | glfwSetCharCallback(g_Window, g_PrevUserCallbackChar); 242 | g_InstalledCallbacks = false; 243 | } 244 | 245 | for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) 246 | { 247 | glfwDestroyCursor(g_MouseCursors[cursor_n]); 248 | g_MouseCursors[cursor_n] = NULL; 249 | } 250 | g_ClientApi = GlfwClientApi_Unknown; 251 | } 252 | 253 | static void ImGui_ImplGlfw_UpdateMousePosAndButtons() 254 | { 255 | // Update buttons 256 | ImGuiIO& io = ImGui::GetIO(); 257 | for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) 258 | { 259 | // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. 260 | io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; 261 | g_MouseJustPressed[i] = false; 262 | } 263 | 264 | // Update mouse position 265 | const ImVec2 mouse_pos_backup = io.MousePos; 266 | io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 267 | #ifdef __EMSCRIPTEN__ 268 | const bool focused = true; // Emscripten 269 | #else 270 | const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0; 271 | #endif 272 | if (focused) 273 | { 274 | if (io.WantSetMousePos) 275 | { 276 | glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); 277 | } 278 | else 279 | { 280 | double mouse_x, mouse_y; 281 | glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); 282 | io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); 283 | } 284 | } 285 | } 286 | 287 | static void ImGui_ImplGlfw_UpdateMouseCursor() 288 | { 289 | ImGuiIO& io = ImGui::GetIO(); 290 | if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) 291 | return; 292 | 293 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); 294 | if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) 295 | { 296 | // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor 297 | glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); 298 | } 299 | else 300 | { 301 | // Show OS mouse cursor 302 | // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. 303 | glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); 304 | glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); 305 | } 306 | } 307 | 308 | static void ImGui_ImplGlfw_UpdateGamepads() 309 | { 310 | ImGuiIO& io = ImGui::GetIO(); 311 | memset(io.NavInputs, 0, sizeof(io.NavInputs)); 312 | if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) 313 | return; 314 | 315 | // Update gamepad inputs 316 | #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } 317 | #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } 318 | int axes_count = 0, buttons_count = 0; 319 | const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); 320 | const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); 321 | MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A 322 | MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B 323 | MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X 324 | MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y 325 | MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left 326 | MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right 327 | MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up 328 | MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down 329 | MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB 330 | MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB 331 | MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB 332 | MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB 333 | MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); 334 | MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); 335 | MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); 336 | MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); 337 | #undef MAP_BUTTON 338 | #undef MAP_ANALOG 339 | if (axes_count > 0 && buttons_count > 0) 340 | io.BackendFlags |= ImGuiBackendFlags_HasGamepad; 341 | else 342 | io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; 343 | } 344 | 345 | void ImGui_ImplGlfw_NewFrame() 346 | { 347 | ImGuiIO& io = ImGui::GetIO(); 348 | IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); 349 | 350 | // Setup display size (every frame to accommodate for window resizing) 351 | int w, h; 352 | int display_w, display_h; 353 | glfwGetWindowSize(g_Window, &w, &h); 354 | glfwGetFramebufferSize(g_Window, &display_w, &display_h); 355 | io.DisplaySize = ImVec2((float)w, (float)h); 356 | if (w > 0 && h > 0) 357 | io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); 358 | 359 | // Setup time step 360 | double current_time = glfwGetTime(); 361 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); 362 | g_Time = current_time; 363 | 364 | ImGui_ImplGlfw_UpdateMousePosAndButtons(); 365 | ImGui_ImplGlfw_UpdateMouseCursor(); 366 | 367 | // Update game controllers (if enabled and available) 368 | ImGui_ImplGlfw_UpdateGamepads(); 369 | } 370 | -------------------------------------------------------------------------------- /Dear-IMGUI/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.00. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Added STBRP__CDECL 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_rect_pack.h - v1.00 - public domain - rectangle packing 8 | // Sean Barrett 2014 9 | // 10 | // Useful for e.g. packing rectangular textures into an atlas. 11 | // Does not do rotation. 12 | // 13 | // Not necessarily the awesomest packing method, but better than 14 | // the totally naive one in stb_truetype (which is primarily what 15 | // this is meant to replace). 16 | // 17 | // Has only had a few tests run, may have issues. 18 | // 19 | // More docs to come. 20 | // 21 | // No memory allocations; uses qsort() and assert() from stdlib. 22 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 23 | // 24 | // This library currently uses the Skyline Bottom-Left algorithm. 25 | // 26 | // Please note: better rectangle packers are welcome! Please 27 | // implement them to the same API, but with a different init 28 | // function. 29 | // 30 | // Credits 31 | // 32 | // Library 33 | // Sean Barrett 34 | // Minor features 35 | // Martins Mozeiko 36 | // github:IntellectualKitty 37 | // 38 | // Bugfixes / warning fixes 39 | // Jeremy Jaussaud 40 | // Fabian Giesen 41 | // 42 | // Version history: 43 | // 44 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 | // 0.99 (2019-02-07) warning fixes 46 | // 0.11 (2017-03-03) return packing success/fail result 47 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 48 | // 0.09 (2016-08-27) fix compiler warnings 49 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 50 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 51 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 52 | // 0.05: added STBRP_ASSERT to allow replacing assert 53 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 54 | // 0.01: initial release 55 | // 56 | // LICENSE 57 | // 58 | // See end of file for license information. 59 | 60 | ////////////////////////////////////////////////////////////////////////////// 61 | // 62 | // INCLUDE SECTION 63 | // 64 | 65 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 66 | #define STB_INCLUDE_STB_RECT_PACK_H 67 | 68 | #define STB_RECT_PACK_VERSION 1 69 | 70 | #ifdef STBRP_STATIC 71 | #define STBRP_DEF static 72 | #else 73 | #define STBRP_DEF extern 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" { 78 | #endif 79 | 80 | typedef struct stbrp_context stbrp_context; 81 | typedef struct stbrp_node stbrp_node; 82 | typedef struct stbrp_rect stbrp_rect; 83 | 84 | #ifdef STBRP_LARGE_RECTS 85 | typedef int stbrp_coord; 86 | #else 87 | typedef unsigned short stbrp_coord; 88 | #endif 89 | 90 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 | // Assign packed locations to rectangles. The rectangles are of type 92 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 | // are 'num_rects' many of them. 94 | // 95 | // Rectangles which are successfully packed have the 'was_packed' flag 96 | // set to a non-zero value and 'x' and 'y' store the minimum location 97 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 | // if you imagine y increasing downwards). Rectangles which do not fit 99 | // have the 'was_packed' flag set to 0. 100 | // 101 | // You should not try to access the 'rects' array from another thread 102 | // while this function is running, as the function temporarily reorders 103 | // the array while it executes. 104 | // 105 | // To pack into another rectangle, you need to call stbrp_init_target 106 | // again. To continue packing into the same rectangle, you can call 107 | // this function again. Calling this multiple times with multiple rect 108 | // arrays will probably produce worse packing results than calling it 109 | // a single time with the full rectangle array, but the option is 110 | // available. 111 | // 112 | // The function returns 1 if all of the rectangles were successfully 113 | // packed and 0 otherwise. 114 | 115 | struct stbrp_rect 116 | { 117 | // reserved for your use: 118 | int id; 119 | 120 | // input: 121 | stbrp_coord w, h; 122 | 123 | // output: 124 | stbrp_coord x, y; 125 | int was_packed; // non-zero if valid packing 126 | 127 | }; // 16 bytes, nominally 128 | 129 | 130 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 | // Initialize a rectangle packer to: 132 | // pack a rectangle that is 'width' by 'height' in dimensions 133 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 | // 135 | // You must call this function every time you start packing into a new target. 136 | // 137 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 | // the following stbrp_pack_rects() call (or calls), but can be freed after 139 | // the call (or calls) finish. 140 | // 141 | // Note: to guarantee best results, either: 142 | // 1. make sure 'num_nodes' >= 'width' 143 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 | // 145 | // If you don't do either of the above things, widths will be quantized to multiples 146 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 | // 148 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 | // may run out of temporary storage and be unable to pack some rectangles. 150 | 151 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 | // Optionally call this function after init but before doing any packing to 153 | // change the handling of the out-of-temp-memory scenario, described above. 154 | // If you call init again, this will be reset to the default (false). 155 | 156 | 157 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 | // Optionally select which packing heuristic the library should use. Different 159 | // heuristics will produce better/worse results for different data sets. 160 | // If you call init again, this will be reset to the default. 161 | 162 | enum 163 | { 164 | STBRP_HEURISTIC_Skyline_default=0, 165 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 | STBRP_HEURISTIC_Skyline_BF_sortHeight 167 | }; 168 | 169 | 170 | ////////////////////////////////////////////////////////////////////////////// 171 | // 172 | // the details of the following structures don't matter to you, but they must 173 | // be visible so you can handle the memory allocations for them 174 | 175 | struct stbrp_node 176 | { 177 | stbrp_coord x,y; 178 | stbrp_node *next; 179 | }; 180 | 181 | struct stbrp_context 182 | { 183 | int width; 184 | int height; 185 | int align; 186 | int init_mode; 187 | int heuristic; 188 | int num_nodes; 189 | stbrp_node *active_head; 190 | stbrp_node *free_head; 191 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 | }; 193 | 194 | #ifdef __cplusplus 195 | } 196 | #endif 197 | 198 | #endif 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | // 202 | // IMPLEMENTATION SECTION 203 | // 204 | 205 | #ifdef STB_RECT_PACK_IMPLEMENTATION 206 | #ifndef STBRP_SORT 207 | #include 208 | #define STBRP_SORT qsort 209 | #endif 210 | 211 | #ifndef STBRP_ASSERT 212 | #include 213 | #define STBRP_ASSERT assert 214 | #endif 215 | 216 | // [DEAR IMGUI] Added STBRP__CDECL 217 | #ifdef _MSC_VER 218 | #define STBRP__NOTUSED(v) (void)(v) 219 | #define STBRP__CDECL __cdecl 220 | #else 221 | #define STBRP__NOTUSED(v) (void)sizeof(v) 222 | #define STBRP__CDECL 223 | #endif 224 | 225 | enum 226 | { 227 | STBRP__INIT_skyline = 1 228 | }; 229 | 230 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 231 | { 232 | switch (context->init_mode) { 233 | case STBRP__INIT_skyline: 234 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 | context->heuristic = heuristic; 236 | break; 237 | default: 238 | STBRP_ASSERT(0); 239 | } 240 | } 241 | 242 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 243 | { 244 | if (allow_out_of_mem) 245 | // if it's ok to run out of memory, then don't bother aligning them; 246 | // this gives better packing, but may fail due to OOM (even though 247 | // the rectangles easily fit). @TODO a smarter approach would be to only 248 | // quantize once we've hit OOM, then we could get rid of this parameter. 249 | context->align = 1; 250 | else { 251 | // if it's not ok to run out of memory, then quantize the widths 252 | // so that num_nodes is always enough nodes. 253 | // 254 | // I.e. num_nodes * align >= width 255 | // align >= width / num_nodes 256 | // align = ceil(width/num_nodes) 257 | 258 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 259 | } 260 | } 261 | 262 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 263 | { 264 | int i; 265 | #ifndef STBRP_LARGE_RECTS 266 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 267 | #endif 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | #ifdef STBRP_LARGE_RECTS 287 | context->extra[1].y = (1<<30); 288 | #else 289 | context->extra[1].y = 65535; 290 | #endif 291 | context->extra[1].next = NULL; 292 | } 293 | 294 | // find minimum y position if it starts at x1 295 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 296 | { 297 | stbrp_node *node = first; 298 | int x1 = x0 + width; 299 | int min_y, visited_width, waste_area; 300 | 301 | STBRP__NOTUSED(c); 302 | 303 | STBRP_ASSERT(first->x <= x0); 304 | 305 | #if 0 306 | // skip in case we're past the node 307 | while (node->next->x <= x0) 308 | ++node; 309 | #else 310 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 311 | #endif 312 | 313 | STBRP_ASSERT(node->x <= x0); 314 | 315 | min_y = 0; 316 | waste_area = 0; 317 | visited_width = 0; 318 | while (node->x < x1) { 319 | if (node->y > min_y) { 320 | // raise min_y higher. 321 | // we've accounted for all waste up to min_y, 322 | // but we'll now add more waste for everything we've visted 323 | waste_area += visited_width * (node->y - min_y); 324 | min_y = node->y; 325 | // the first time through, visited_width might be reduced 326 | if (node->x < x0) 327 | visited_width += node->next->x - x0; 328 | else 329 | visited_width += node->next->x - node->x; 330 | } else { 331 | // add waste area 332 | int under_width = node->next->x - node->x; 333 | if (under_width + visited_width > width) 334 | under_width = width - visited_width; 335 | waste_area += under_width * (min_y - node->y); 336 | visited_width += under_width; 337 | } 338 | node = node->next; 339 | } 340 | 341 | *pwaste = waste_area; 342 | return min_y; 343 | } 344 | 345 | typedef struct 346 | { 347 | int x,y; 348 | stbrp_node **prev_link; 349 | } stbrp__findresult; 350 | 351 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 352 | { 353 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 354 | stbrp__findresult fr; 355 | stbrp_node **prev, *node, *tail, **best = NULL; 356 | 357 | // align to multiple of c->align 358 | width = (width + c->align - 1); 359 | width -= width % c->align; 360 | STBRP_ASSERT(width % c->align == 0); 361 | 362 | // if it can't possibly fit, bail immediately 363 | if (width > c->width || height > c->height) { 364 | fr.prev_link = NULL; 365 | fr.x = fr.y = 0; 366 | return fr; 367 | } 368 | 369 | node = c->active_head; 370 | prev = &c->active_head; 371 | while (node->x + width <= c->width) { 372 | int y,waste; 373 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 374 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 375 | // bottom left 376 | if (y < best_y) { 377 | best_y = y; 378 | best = prev; 379 | } 380 | } else { 381 | // best-fit 382 | if (y + height <= c->height) { 383 | // can only use it if it first vertically 384 | if (y < best_y || (y == best_y && waste < best_waste)) { 385 | best_y = y; 386 | best_waste = waste; 387 | best = prev; 388 | } 389 | } 390 | } 391 | prev = &node->next; 392 | node = node->next; 393 | } 394 | 395 | best_x = (best == NULL) ? 0 : (*best)->x; 396 | 397 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 398 | // 399 | // e.g, if fitting 400 | // 401 | // ____________________ 402 | // |____________________| 403 | // 404 | // into 405 | // 406 | // | | 407 | // | ____________| 408 | // |____________| 409 | // 410 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 411 | // 412 | // This makes BF take about 2x the time 413 | 414 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 415 | tail = c->active_head; 416 | node = c->active_head; 417 | prev = &c->active_head; 418 | // find first node that's admissible 419 | while (tail->x < width) 420 | tail = tail->next; 421 | while (tail) { 422 | int xpos = tail->x - width; 423 | int y,waste; 424 | STBRP_ASSERT(xpos >= 0); 425 | // find the left position that matches this 426 | while (node->next->x <= xpos) { 427 | prev = &node->next; 428 | node = node->next; 429 | } 430 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 431 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 432 | if (y + height <= c->height) { 433 | if (y <= best_y) { 434 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 435 | best_x = xpos; 436 | STBRP_ASSERT(y <= best_y); 437 | best_y = y; 438 | best_waste = waste; 439 | best = prev; 440 | } 441 | } 442 | } 443 | tail = tail->next; 444 | } 445 | } 446 | 447 | fr.prev_link = best; 448 | fr.x = best_x; 449 | fr.y = best_y; 450 | return fr; 451 | } 452 | 453 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 454 | { 455 | // find best position according to heuristic 456 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 457 | stbrp_node *node, *cur; 458 | 459 | // bail if: 460 | // 1. it failed 461 | // 2. the best node doesn't fit (we don't always check this) 462 | // 3. we're out of memory 463 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 464 | res.prev_link = NULL; 465 | return res; 466 | } 467 | 468 | // on success, create new node 469 | node = context->free_head; 470 | node->x = (stbrp_coord) res.x; 471 | node->y = (stbrp_coord) (res.y + height); 472 | 473 | context->free_head = node->next; 474 | 475 | // insert the new node into the right starting point, and 476 | // let 'cur' point to the remaining nodes needing to be 477 | // stiched back in 478 | 479 | cur = *res.prev_link; 480 | if (cur->x < res.x) { 481 | // preserve the existing one, so start testing with the next one 482 | stbrp_node *next = cur->next; 483 | cur->next = node; 484 | cur = next; 485 | } else { 486 | *res.prev_link = node; 487 | } 488 | 489 | // from here, traverse cur and free the nodes, until we get to one 490 | // that shouldn't be freed 491 | while (cur->next && cur->next->x <= res.x + width) { 492 | stbrp_node *next = cur->next; 493 | // move the current node to the free list 494 | cur->next = context->free_head; 495 | context->free_head = cur; 496 | cur = next; 497 | } 498 | 499 | // stitch the list back in 500 | node->next = cur; 501 | 502 | if (cur->x < res.x + width) 503 | cur->x = (stbrp_coord) (res.x + width); 504 | 505 | #ifdef _DEBUG 506 | cur = context->active_head; 507 | while (cur->x < context->width) { 508 | STBRP_ASSERT(cur->x < cur->next->x); 509 | cur = cur->next; 510 | } 511 | STBRP_ASSERT(cur->next == NULL); 512 | 513 | { 514 | int count=0; 515 | cur = context->active_head; 516 | while (cur) { 517 | cur = cur->next; 518 | ++count; 519 | } 520 | cur = context->free_head; 521 | while (cur) { 522 | cur = cur->next; 523 | ++count; 524 | } 525 | STBRP_ASSERT(count == context->num_nodes+2); 526 | } 527 | #endif 528 | 529 | return res; 530 | } 531 | 532 | // [DEAR IMGUI] Added STBRP__CDECL 533 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 534 | { 535 | const stbrp_rect *p = (const stbrp_rect *) a; 536 | const stbrp_rect *q = (const stbrp_rect *) b; 537 | if (p->h > q->h) 538 | return -1; 539 | if (p->h < q->h) 540 | return 1; 541 | return (p->w > q->w) ? -1 : (p->w < q->w); 542 | } 543 | 544 | // [DEAR IMGUI] Added STBRP__CDECL 545 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 546 | { 547 | const stbrp_rect *p = (const stbrp_rect *) a; 548 | const stbrp_rect *q = (const stbrp_rect *) b; 549 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 550 | } 551 | 552 | #ifdef STBRP_LARGE_RECTS 553 | #define STBRP__MAXVAL 0xffffffff 554 | #else 555 | #define STBRP__MAXVAL 0xffff 556 | #endif 557 | 558 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 559 | { 560 | int i, all_rects_packed = 1; 561 | 562 | // we use the 'was_packed' field internally to allow sorting/unsorting 563 | for (i=0; i < num_rects; ++i) { 564 | rects[i].was_packed = i; 565 | } 566 | 567 | // sort according to heuristic 568 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 569 | 570 | for (i=0; i < num_rects; ++i) { 571 | if (rects[i].w == 0 || rects[i].h == 0) { 572 | rects[i].x = rects[i].y = 0; // empty rect needs no space 573 | } else { 574 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 575 | if (fr.prev_link) { 576 | rects[i].x = (stbrp_coord) fr.x; 577 | rects[i].y = (stbrp_coord) fr.y; 578 | } else { 579 | rects[i].x = rects[i].y = STBRP__MAXVAL; 580 | } 581 | } 582 | } 583 | 584 | // unsort 585 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 586 | 587 | // set was_packed flags and all_rects_packed status 588 | for (i=0; i < num_rects; ++i) { 589 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 590 | if (!rects[i].was_packed) 591 | all_rects_packed = 0; 592 | } 593 | 594 | // return the all_rects_packed status 595 | return all_rects_packed; 596 | } 597 | #endif 598 | 599 | /* 600 | ------------------------------------------------------------------------------ 601 | This software is available under 2 licenses -- choose whichever you prefer. 602 | ------------------------------------------------------------------------------ 603 | ALTERNATIVE A - MIT License 604 | Copyright (c) 2017 Sean Barrett 605 | Permission is hereby granted, free of charge, to any person obtaining a copy of 606 | this software and associated documentation files (the "Software"), to deal in 607 | the Software without restriction, including without limitation the rights to 608 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 | of the Software, and to permit persons to whom the Software is furnished to do 610 | so, subject to the following conditions: 611 | The above copyright notice and this permission notice shall be included in all 612 | copies or substantial portions of the Software. 613 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 619 | SOFTWARE. 620 | ------------------------------------------------------------------------------ 621 | ALTERNATIVE B - Public Domain (www.unlicense.org) 622 | This is free and unencumbered software released into the public domain. 623 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 | software, either in source code form or as a compiled binary, for any purpose, 625 | commercial or non-commercial, and by any means. 626 | In jurisdictions that recognize copyright laws, the author or authors of this 627 | software dedicate any and all copyright interest in the software to the public 628 | domain. We make this dedication for the benefit of the public at large and to 629 | the detriment of our heirs and successors. We intend this dedication to be an 630 | overt act of relinquishment in perpetuity of all present and future rights to 631 | this software under copyright law. 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 637 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 638 | ------------------------------------------------------------------------------ 639 | */ 640 | --------------------------------------------------------------------------------