├── .gitignore ├── LICENSE ├── readme.md ├── synthrain.sln └── synthrain ├── .gitignore ├── CMakeLists.txt ├── DataSequence.cpp ├── DataSequence.h ├── Exporter.cpp ├── Exporter.h ├── FlowData.cpp ├── FlowData.h ├── LogWindow.cpp ├── LogWindow.h ├── OGLComputeShader.cpp ├── OGLComputeShader.h ├── OGLFloatTexture.cpp ├── OGLFloatTexture.h ├── OGLFrameBuffer.cpp ├── OGLFrameBuffer.h ├── OGLRenderStage.cpp ├── OGLRenderStage.h ├── OGLRenderer.cpp ├── OGLRenderer.h ├── OGLShader.cpp ├── OGLShader.h ├── OGLTexture.cpp ├── OGLTexture.h ├── OGLVideoTexture.cpp ├── OGLVideoTexture.h ├── RenderStageBokeh.cpp ├── RenderStageBokeh.h ├── RenderStageDrops.cpp ├── RenderStageDrops.h ├── RenderStageFog.cpp ├── RenderStageFog.h ├── RenderStageMaxPool.cpp ├── RenderStageMaxPool.h ├── RenderStageRefract.cpp ├── RenderStageRefract.h ├── cmake ├── FindFFmpeg.cmake ├── FindSDL2_image.cmake └── FindSWScale.cmake ├── fvector2.h ├── imgui.ini ├── imgui ├── LICENSE.txt ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_demo.cpp ├── imgui_draw.cpp ├── imgui_impl_opengl3.cpp ├── imgui_impl_opengl3.h ├── imgui_impl_sdl.cpp ├── imgui_impl_sdl.h ├── imgui_internal.h ├── stb_rect_pack.h ├── stb_textedit.h └── stb_truetype.h ├── json.hpp ├── main.cpp ├── rng.cpp ├── rng.h ├── shaders ├── .gitignore ├── basic.frag ├── basic.vert ├── basic_alpha.frag ├── blur.frag ├── bokeh-billboard.frag ├── bokeh-billboard.geom ├── bokeh-circle.geom ├── bokeh-hex.geom ├── bokeh-hex.png ├── bokeh-round2.png ├── bokeh.frag ├── drop.frag ├── drop.png ├── drop.vert ├── flow_average.comp ├── fog.frag ├── noise.frag ├── refract.frag └── scatter.frag ├── sort_bokeh.cu ├── synthrain.vcxproj └── synthrain.vcxproj.filters /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | 56 | # StyleCop 57 | StyleCopReport.xml 58 | 59 | # Files built by Visual Studio 60 | *_i.c 61 | *_p.c 62 | *_i.h 63 | *.ilk 64 | *.meta 65 | *.obj 66 | *.iobj 67 | *.pch 68 | *.pdb 69 | *.ipdb 70 | *.pgc 71 | *.pgd 72 | *.rsp 73 | *.sbr 74 | *.tlb 75 | *.tli 76 | *.tlh 77 | *.tmp 78 | *.tmp_proj 79 | *.log 80 | *.vspscc 81 | *.vssscc 82 | .builds 83 | *.pidb 84 | *.svclog 85 | *.scc 86 | 87 | # Chutzpah Test files 88 | _Chutzpah* 89 | 90 | # Visual C++ cache files 91 | ipch/ 92 | *.aps 93 | *.ncb 94 | *.opendb 95 | *.opensdf 96 | *.sdf 97 | *.cachefile 98 | *.VC.db 99 | *.VC.VC.opendb 100 | 101 | # Visual Studio profiler 102 | *.psess 103 | *.vsp 104 | *.vspx 105 | *.sap 106 | 107 | # Visual Studio Trace Files 108 | *.e2e 109 | 110 | # TFS 2012 Local Workspace 111 | $tf/ 112 | 113 | # Guidance Automation Toolkit 114 | *.gpState 115 | 116 | # ReSharper is a .NET coding add-in 117 | _ReSharper*/ 118 | *.[Rr]e[Ss]harper 119 | *.DotSettings.user 120 | 121 | # JustCode is a .NET coding add-in 122 | .JustCode 123 | 124 | # TeamCity is a build add-in 125 | _TeamCity* 126 | 127 | # DotCover is a Code Coverage Tool 128 | *.dotCover 129 | 130 | # AxoCover is a Code Coverage Tool 131 | .axoCover/* 132 | !.axoCover/settings.json 133 | 134 | # Visual Studio code coverage results 135 | *.coverage 136 | *.coveragexml 137 | 138 | # NCrunch 139 | _NCrunch_* 140 | .*crunch*.local.xml 141 | nCrunchTemp_* 142 | 143 | # MightyMoose 144 | *.mm.* 145 | AutoTest.Net/ 146 | 147 | # Web workbench (sass) 148 | .sass-cache/ 149 | 150 | # Installshield output folder 151 | [Ee]xpress/ 152 | 153 | # DocProject is a documentation generator add-in 154 | DocProject/buildhelp/ 155 | DocProject/Help/*.HxT 156 | DocProject/Help/*.HxC 157 | DocProject/Help/*.hhc 158 | DocProject/Help/*.hhk 159 | DocProject/Help/*.hhp 160 | DocProject/Help/Html2 161 | DocProject/Help/html 162 | 163 | # Click-Once directory 164 | publish/ 165 | 166 | # Publish Web Output 167 | *.[Pp]ublish.xml 168 | *.azurePubxml 169 | # Note: Comment the next line if you want to checkin your web deploy settings, 170 | # but database connection strings (with potential passwords) will be unencrypted 171 | *.pubxml 172 | *.publishproj 173 | 174 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 175 | # checkin your Azure Web App publish settings, but sensitive information contained 176 | # in these scripts will be unencrypted 177 | PublishScripts/ 178 | 179 | # NuGet Packages 180 | *.nupkg 181 | # The packages folder can be ignored because of Package Restore 182 | **/[Pp]ackages/* 183 | # except build/, which is used as an MSBuild target. 184 | !**/[Pp]ackages/build/ 185 | # Uncomment if necessary however generally it will be regenerated when needed 186 | #!**/[Pp]ackages/repositories.config 187 | # NuGet v3's project.json files produces more ignorable files 188 | *.nuget.props 189 | *.nuget.targets 190 | 191 | # Microsoft Azure Build Output 192 | csx/ 193 | *.build.csdef 194 | 195 | # Microsoft Azure Emulator 196 | ecf/ 197 | rcf/ 198 | 199 | # Windows Store app package directories and files 200 | AppPackages/ 201 | BundleArtifacts/ 202 | Package.StoreAssociation.xml 203 | _pkginfo.txt 204 | *.appx 205 | 206 | # Visual Studio cache files 207 | # files ending in .cache can be ignored 208 | *.[Cc]ache 209 | # but keep track of directories ending in .cache 210 | !*.[Cc]ache/ 211 | 212 | # Others 213 | ClientBin/ 214 | ~$* 215 | *~ 216 | *.dbmdl 217 | *.dbproj.schemaview 218 | *.jfm 219 | *.pfx 220 | *.publishsettings 221 | orleans.codegen.cs 222 | 223 | # Including strong name files can present a security risk 224 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 225 | #*.snk 226 | 227 | # Since there are multiple workflows, uncomment next line to ignore bower_components 228 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 229 | #bower_components/ 230 | 231 | # RIA/Silverlight projects 232 | Generated_Code/ 233 | 234 | # Backup & report files from converting an old project file 235 | # to a newer Visual Studio version. Backup files are not needed, 236 | # because we have git ;-) 237 | _UpgradeReport_Files/ 238 | Backup*/ 239 | UpgradeLog*.XML 240 | UpgradeLog*.htm 241 | ServiceFabricBackup/ 242 | *.rptproj.bak 243 | 244 | # SQL Server files 245 | *.mdf 246 | *.ldf 247 | *.ndf 248 | 249 | # Business Intelligence projects 250 | *.rdl.data 251 | *.bim.layout 252 | *.bim_*.settings 253 | *.rptproj.rsuser 254 | 255 | # Microsoft Fakes 256 | FakesAssemblies/ 257 | 258 | # GhostDoc plugin setting file 259 | *.GhostDoc.xml 260 | 261 | # Node.js Tools for Visual Studio 262 | .ntvs_analysis.dat 263 | node_modules/ 264 | 265 | # Visual Studio 6 build log 266 | *.plg 267 | 268 | # Visual Studio 6 workspace options file 269 | *.opt 270 | 271 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 272 | *.vbw 273 | 274 | # Visual Studio LightSwitch build output 275 | **/*.HTMLClient/GeneratedArtifacts 276 | **/*.DesktopClient/GeneratedArtifacts 277 | **/*.DesktopClient/ModelManifest.xml 278 | **/*.Server/GeneratedArtifacts 279 | **/*.Server/ModelManifest.xml 280 | _Pvt_Extensions 281 | 282 | # Paket dependency manager 283 | .paket/paket.exe 284 | paket-files/ 285 | 286 | # FAKE - F# Make 287 | .fake/ 288 | 289 | # JetBrains Rider 290 | .idea/ 291 | *.sln.iml 292 | 293 | # CodeRush 294 | .cr/ 295 | 296 | # Python Tools for Visual Studio (PTVS) 297 | __pycache__/ 298 | *.pyc 299 | 300 | # Cake - Uncomment if you are using it 301 | # tools/** 302 | # !tools/packages.config 303 | 304 | # Tabs Studio 305 | *.tss 306 | 307 | # Telerik's JustMock configuration file 308 | *.jmconfig 309 | 310 | # BizTalk build output 311 | *.btp.cs 312 | *.btm.cs 313 | *.odx.cs 314 | *.xsd.cs 315 | 316 | # OpenCover UI analysis results 317 | OpenCover/ 318 | 319 | # Azure Stream Analytics local run output 320 | ASALocalRun/ 321 | 322 | # MSBuild Binary and Structured Log 323 | *.binlog 324 | 325 | # NVidia Nsight GPU debugger configuration file 326 | *.nvuser 327 | 328 | # MFractors (Xamarin productivity tool) working folder 329 | .mfractor/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Panasonic ß 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # OpenSynthrain 2 | OpenSynthrain is a batch data synthesis tool with a built in preview. 3 | It was originally written to generate data in support of our paper on adherant raindrop removal: 4 | 5 | Adherent Raindrop Removal with Self-Supervised Attention Maps and Spatio-Temporal Generative Adversarial Networks 6 | 2019 IEEE/CVF International Conference On Computer Vision Workshop (ICCVW)2019 7 | Stefano Alletto, Casey Carlin, Luca Rigazio, Yasunori Ishii, Sotaro Tsukizawa 8 | 9 | ## Usage 10 | Data input and output directories are defined in `config.json` located in the working directory. A default config file will be created automatically on first run. 11 | 12 | Images should be prepared in the following manner: 13 | ### When non-sequential color data will be used 14 | Place images into one folder, e.g. 15 | - `\path\to\data\` 16 | 17 | In the configuration set 18 | - `"input_folder"` to `\path\to\data\` 19 | - `'use_sequences`' to `[""]` 20 | 21 | ### When sequences of color data will be used 22 | Place image sequences in sub folders, e.g. 23 | - `\path\to\data\seq1\` 24 | - `\path\to\data\seq2\` 25 | 26 | In the configuration set 27 | - `"input_folder"` to `\path\to\data\` 28 | - `'use_sequences`' to ["seq1", "seq2"] 29 | 30 | Use `use_sequences` to limit your data generation to one or more sequences from a larger data set. 31 | 32 | ### When using depth and/or flow data with sequences 33 | Using the sequences configuration, further divide data type into subfolders: 34 | - `\path\to\data\seq1\color` 35 | - `\path\to\data\seq1\depth` 36 | - `\path\to\data\seq1\flow` 37 | 38 | As noted in the known issues, some raindrop paramers can be adjusted at run time but they will not be saved. 39 | 40 | ## Building 41 | OpenSynthrain targets 64-bit OSes only, but it can be made to work on 32-bit if CUDA support is removed. 42 | 43 | ### Windows 44 | Install the following packages with vcpckg 45 | ``` 46 | vcpkg install glew:x64-windows libjpeg-turbo:x64-windows libpng:x64-windows sdl2-image:x64-windows sdl2-image[libjpeg-turbo]:x64-windows sdl2:x64-windows zlib:x64-windows 47 | ``` 48 | You will also need to install the CUDA toolkit (version 9 or greater) 49 | If compilation fails because of CUDA, you may need to edit 50 | C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.2\include\crt\host_config.h line 131 to read: 51 | `#if _MSC_VER < 1600` 52 | 53 | ### Ubuntu Linux 54 | Install the following packages: 55 | ``` 56 | libglew 57 | libsdl2-dev 58 | libsdl2-image-dev 59 | ```` 60 | You will also need to install the CUDA toolkit (version 9 or greater) using your preferred method. 61 | 62 | ## Known Issues 63 | * Source images larger than the half the size of the Window will case the resulting "rainy" image to be partially or completely drawn off screen. 64 | * Many raindrop parameters are hardcoded and/or not saved to disk after being modified. -------------------------------------------------------------------------------- /synthrain.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "synthrain", "synthrain\synthrain.vcxproj", "{04702296-C413-4849-B508-7ADC7827242D}" 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 | {04702296-C413-4849-B508-7ADC7827242D}.Debug|x64.ActiveCfg = Debug|x64 17 | {04702296-C413-4849-B508-7ADC7827242D}.Debug|x64.Build.0 = Debug|x64 18 | {04702296-C413-4849-B508-7ADC7827242D}.Debug|x86.ActiveCfg = Debug|Win32 19 | {04702296-C413-4849-B508-7ADC7827242D}.Debug|x86.Build.0 = Debug|Win32 20 | {04702296-C413-4849-B508-7ADC7827242D}.Release|x64.ActiveCfg = Release|x64 21 | {04702296-C413-4849-B508-7ADC7827242D}.Release|x64.Build.0 = Release|x64 22 | {04702296-C413-4849-B508-7ADC7827242D}.Release|x86.ActiveCfg = Release|Win32 23 | {04702296-C413-4849-B508-7ADC7827242D}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {DFE30E92-C8CB-454B-8AA1-9AA981938508} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /synthrain/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | config.json -------------------------------------------------------------------------------- /synthrain/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.7) 2 | project(synthrain) 3 | 4 | SET(CMAKE_C_COMPILER /usr/bin/gcc-8) 5 | SET(CMAKE_CXX_COMPILER /usr/bin/g++-8) 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | 11 | include_directories(${synthrain_SOURCE_DIR}) 12 | #include_directories("") 13 | #link_directories("") 14 | 15 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") 16 | 17 | INCLUDE(FindPkgConfig) 18 | find_package(GLEW REQUIRED) 19 | find_package(SDL2 REQUIRED) 20 | find_package(SDL2_image REQUIRED) 21 | find_package(OpenGL REQUIRED) 22 | find_package(PNG REQUIRED) 23 | find_package(ZLIB REQUIRED) 24 | find_package(FFmpeg REQUIRED) 25 | find_package(SWScale REQUIRED) 26 | 27 | INCLUDE_DIRECTORIES( ${SWScale_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIRS}) 28 | 29 | file(GLOB SOURCES "*.cpp") 30 | list(APPEND SOURCES "imgui/imgui.cpp" 31 | "imgui/imgui_impl_sdl.cpp" 32 | "imgui/imgui_impl_opengl3.cpp" 33 | "imgui/imgui_draw.cpp" 34 | "imgui/imgui_demo.cpp") 35 | 36 | add_definitions(-DNO_CUDA) 37 | 38 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 39 | # add_definitions(/DYOURDEFINITION) 40 | else() 41 | add_definitions(-DNDEBUG) 42 | endif() 43 | 44 | add_executable(synthrain ${SOURCES}) 45 | set_target_properties(synthrain PROPERTIES LINK_FLAGS "-Wl,-rpath,./") 46 | 47 | TARGET_LINK_LIBRARIES( ${PROJECT_NAME} pthread stdc++fs avcodec avformat avutil avdevice swscale ${SWScale_LIBRARIES} ${FFMPEG_LIBRARIES} ${PNG_LIBRARIES} ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES} ${FREETYPE_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES}) 48 | -------------------------------------------------------------------------------- /synthrain/DataSequence.cpp: -------------------------------------------------------------------------------- 1 | #include "DataSequence.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "imgui/imgui.h" 16 | 17 | DataSequence::DataSequence(std::shared_ptr bg_texture, std::shared_ptr flow_texture, std::shared_ptr depth_texture) : 18 | bg_texture(bg_texture), 19 | flow_texture(flow_texture), 20 | depth_texture(depth_texture), 21 | color_folder_name("frames"), 22 | sources{}, 23 | load_thread(&DataSequence::load_thread_func, this) 24 | { 25 | sequence_number = sources.begin(); 26 | subsequence_length = 0; 27 | cache_misses = 0; 28 | 29 | quit = false; 30 | } 31 | 32 | 33 | DataSequence::~DataSequence() 34 | { 35 | { 36 | std::lock_guard lock(mx); 37 | quit = true; 38 | } 39 | 40 | load_notify.notify_all(); 41 | load_thread.join(); 42 | 43 | } 44 | 45 | void DataSequence::setSequencesFolder(fs::path seq_folder) 46 | { 47 | base_dir = seq_folder; 48 | } 49 | 50 | void DataSequence::setSequences(std::vector _sources) 51 | { 52 | sources = _sources; 53 | } 54 | 55 | void DataSequence::setOutputFolder(fs::path out_folder) 56 | { 57 | baseoutput_dir = out_folder; 58 | } 59 | 60 | void DataSequence::setSequence(int idx) 61 | { 62 | sequence_number = sources.begin() + idx; 63 | loadSequence(); 64 | 65 | } 66 | 67 | void DataSequence::advanceSequence() 68 | { 69 | sequence_number++; 70 | loadSequence(); 71 | } 72 | 73 | void DataSequence::setFrame(int idx) 74 | { 75 | frame_number = color_files.begin() + idx; 76 | updateCache(); 77 | loadFiles(); 78 | } 79 | 80 | void DataSequence::advanceFrame() 81 | { 82 | frame_number++; 83 | if (frame_number == color_files.end()) frame_number = color_files.begin(); 84 | updateCache(); 85 | loadFiles(); 86 | 87 | } 88 | 89 | void DataSequence::setColorFolderName(std::string name) 90 | { 91 | color_folder_name = name; 92 | } 93 | 94 | bool DataSequence::isEndOfSequence() 95 | { 96 | if (subsequence_length > 0) 97 | { 98 | if (std::distance(color_files.begin(), frame_number) + subsequence_length >= color_files.size()) return true; 99 | } 100 | 101 | return frame_number == color_files.end(); 102 | } 103 | 104 | bool DataSequence::isEndOfAllSequences() 105 | { 106 | return sequence_number == sources.end(); 107 | } 108 | 109 | bool DataSequence::useNewParameters() 110 | { 111 | return subsequence_length == 0 || (std::distance(color_files.begin(), frame_number) % subsequence_length) == 0; 112 | } 113 | 114 | void DataSequence::showCacheUI() 115 | { 116 | int queue_size; 117 | int cache_size; 118 | { 119 | std::unique_lock lock(mx); 120 | queue_size = load_queue.size(); 121 | cache_size = data_cache.size(); 122 | } 123 | ImGui::Text("Queue Size: %d", queue_size); 124 | ImGui::Text("Cache Size: %d", cache_size); 125 | ImGui::Text("Cache misses: %d", cache_misses); 126 | } 127 | 128 | fs::path DataSequence::getCurrentOutputDirectory() 129 | { 130 | return output_dir; 131 | } 132 | 133 | std::string DataSequence::getCurrentOutputFileName() 134 | { 135 | if (subsequence_length > 0) 136 | { 137 | std::ostringstream name; 138 | 139 | int seq = std::distance(sources.begin(), sequence_number); 140 | int global_frame = std::distance(color_files.begin(), frame_number); 141 | int subseq = global_frame / subsequence_length; 142 | int frame = global_frame % subsequence_length; 143 | 144 | name << std::setfill('0') << std::setw(2) << seq << "_" << std::setw(3) << subseq << "_" << std::setw(4) << frame; 145 | return name.str(); 146 | } 147 | else { 148 | return frame_number->stem().string(); 149 | } 150 | } 151 | 152 | bool DataSequence::showUI() 153 | { 154 | bool changed_frame = false; 155 | 156 | ImGui::PushItemWidth(100); 157 | 158 | int seq = std::distance(sources.begin(), sequence_number); 159 | if (ImGui::InputInt("Sequence", &seq)) 160 | { 161 | if (seq <= 0) seq += sources.size(); 162 | seq %= sources.size(); 163 | setSequence(seq); 164 | changed_frame = true; 165 | } 166 | 167 | int frame = std::distance(color_files.begin(), frame_number); 168 | if (ImGui::InputInt("Start from image", &frame)) 169 | { 170 | if (frame <= 0) frame += color_files.size(); 171 | frame %= color_files.size(); 172 | setFrame(frame); 173 | changed_frame = true; 174 | } 175 | 176 | if (ImGui::InputInt("Subsequence length", &subsequence_length)) 177 | { 178 | if (subsequence_length <= 0) subsequence_length = 0; 179 | subsequence_length %= 300; 180 | } 181 | 182 | return changed_frame; 183 | } 184 | 185 | int DataSequence::getFileCount() 186 | { 187 | return color_files.size(); 188 | } 189 | 190 | int DataSequence::getCurrentFrame() 191 | { 192 | return std::distance(color_files.begin(), frame_number); 193 | } 194 | 195 | bool DataSequence::colorDataAvailable() 196 | { 197 | return color_files.empty() == false;; 198 | } 199 | 200 | bool DataSequence::depthDataAvailable() 201 | { 202 | return depth_files.empty() == false; 203 | } 204 | 205 | bool DataSequence::flowDataAvailable() 206 | { 207 | return flow_files.empty() == false; 208 | } 209 | 210 | void DataSequence::loadFiles() 211 | { 212 | if (isEndOfSequence() == true) return; 213 | 214 | { 215 | std::unique_lock lock(mx); 216 | if (data_cache[*frame_number].empty() == false) 217 | { 218 | auto ops = SDL_RWFromMem(data_cache[*frame_number].data(), data_cache[*frame_number].size()); 219 | bg_texture->loadFileRW(frame_number->filename().string(), ops); 220 | } 221 | else { 222 | lock.unlock(); 223 | bg_texture->loadFile((*frame_number).string()); 224 | cache_misses++; 225 | } 226 | } 227 | 228 | int frame_index = getCurrentFrame(); 229 | 230 | if (flow_files.empty() == false && frame_index < flow_files.size()) 231 | { 232 | std::unique_lock lock(mx); 233 | auto flow_path = flow_files[frame_index]; 234 | if (data_cache[flow_path].empty() == false) 235 | { 236 | auto ops = SDL_RWFromMem(data_cache[flow_path].data(), data_cache[flow_path].size()); 237 | flow_texture->loadFileRW(flow_path.string(), ops); 238 | } 239 | else 240 | { 241 | lock.unlock(); 242 | flow_texture->loadFile(flow_path.string()); 243 | cache_misses++; 244 | } 245 | } 246 | 247 | if (depth_files.empty() == false && frame_index < depth_files.size()) 248 | { 249 | std::unique_lock lock(mx); 250 | auto depth_path = depth_files[frame_index]; 251 | if (data_cache[depth_path].empty() == false) 252 | { 253 | auto ops = SDL_RWFromMem(data_cache[depth_path].data(), data_cache[depth_path].size()); 254 | depth_texture->loadFileRW(depth_path.string(), ops); 255 | } 256 | else 257 | { 258 | lock.unlock(); 259 | depth_texture->loadFile(depth_path.string()); 260 | cache_misses++; 261 | } 262 | } 263 | } 264 | 265 | void DataSequence::loadSequence() 266 | { 267 | if (isEndOfAllSequences() == true) return; 268 | color_files.clear(); 269 | flow_files.clear(); 270 | depth_files.clear(); 271 | 272 | std::string seq_folder = *sequence_number; 273 | 274 | input_dir_color = base_dir; 275 | input_dir_color.append(seq_folder).append(color_folder_name); 276 | 277 | input_dir_flow = base_dir; 278 | input_dir_flow.append(seq_folder).append("flows"); 279 | 280 | input_dir_depth = base_dir; 281 | input_dir_depth.append(seq_folder).append("depth"); 282 | 283 | output_dir = baseoutput_dir; 284 | output_dir.append(seq_folder); 285 | 286 | auto filter_func = [](const fs::path& p) { 287 | auto static const valid = std::set{".jpg", ".png", ".jpeg", ".bin", ".flow"}; 288 | return fs::is_regular_file(p) && valid.count(p.extension().string()) > 0; 289 | }; 290 | 291 | if (fs::exists(input_dir_color)) 292 | { 293 | bool color_only = true; 294 | 295 | fs::directory_iterator diff_iterator = fs::directory_iterator(input_dir_color); 296 | 297 | copy_if(fs::directory_iterator(diff_iterator), fs::directory_iterator(), back_inserter(color_files), filter_func); 298 | 299 | 300 | if (fs::exists(input_dir_flow)) { 301 | fs::directory_iterator flow_iterator = fs::directory_iterator(input_dir_flow); 302 | copy_if(fs::directory_iterator(flow_iterator), fs::directory_iterator(), back_inserter(flow_files), filter_func); 303 | color_only = false; 304 | } 305 | 306 | 307 | if (fs::exists(input_dir_depth)) { 308 | fs::directory_iterator depth_iterator = fs::directory_iterator(input_dir_depth); 309 | copy_if(fs::directory_iterator(depth_iterator), fs::directory_iterator(), back_inserter(depth_files), filter_func); 310 | color_only = false; 311 | } 312 | 313 | if (color_only == true) 314 | { 315 | std::sort(color_files.begin(), color_files.end()); 316 | } 317 | } 318 | else { 319 | input_dir_color = base_dir; 320 | input_dir_color.append(seq_folder); 321 | fs::directory_iterator diff_iterator = fs::directory_iterator(input_dir_color); 322 | copy_if(fs::directory_iterator(diff_iterator), fs::directory_iterator(), back_inserter(color_files), filter_func); 323 | } 324 | 325 | /* //TODO: What does this code do again??? 326 | if (depth_files.size() > 0 && depth_files.size() < color_files.size()) 327 | { 328 | std::set temp; 329 | temp.insert(make_move_iterator(color_files.begin()), make_move_iterator(color_files.end())); 330 | 331 | //std::copy(, , std::inserter(temp, temp.end())); 332 | 333 | color_files.clear(); 334 | 335 | for (auto depth : depth_files) 336 | { 337 | int fileno = 0; 338 | { 339 | std::stringstream s(depth.stem().string()); 340 | s >> fileno; 341 | } 342 | 343 | fileno += 1; 344 | std::stringstream s; 345 | s << std::setfill('0') << std::setw(6) << fileno<<".png"; 346 | fs::path colorpath = input_dir_color; 347 | colorpath.append(s.str()); 348 | color_files.push_back(colorpath); 349 | } 350 | }*/ 351 | 352 | 353 | frame_number = color_files.begin(); 354 | updateCache(); 355 | 356 | fs::create_directories(output_dir); 357 | 358 | setFrame(0); 359 | } 360 | 361 | void DataSequence::load_thread_func() 362 | { 363 | while (true) { 364 | std::unique_lock lock(mx); 365 | load_notify.wait(lock, [this] { return quit == true || load_queue.empty() == false; }); 366 | 367 | if (quit) break; 368 | 369 | auto path_in = load_queue.front(); 370 | load_queue.pop(); 371 | std::cout << "Loading " << path_in << std::endl; 372 | lock.unlock(); 373 | 374 | 375 | std::ifstream file(path_in.string(), std::ios::binary | std::ios::ate); 376 | std::streamsize size = file.tellg(); 377 | file.seekg(0, std::ios::beg); 378 | 379 | assert(size > 0); 380 | 381 | std::vector buf(size); 382 | 383 | if (!file.read(buf.data(), size)) 384 | { 385 | assert(false); 386 | //error! 387 | } 388 | 389 | lock.lock(); 390 | data_cache[path_in] = std::move(buf); 391 | lock.unlock(); 392 | } 393 | } 394 | 395 | void DataSequence::updateCache() 396 | { 397 | { 398 | std::lock_guard lock(mx); 399 | 400 | //auto find_and_cache = [this](std::vector::iterator begin, std::vector::iterator end) 401 | std::map> last; 402 | { 403 | last = std::move(data_cache); 404 | } 405 | 406 | auto find_and_cache = [this](std::vector list, std::map>& temp) 407 | { 408 | if (list.empty() == true) return; 409 | unsigned int idx = std::distance(color_files.begin(), frame_number); 410 | auto center = list.begin() + idx; 411 | std::vector::iterator begin = idx >= back_cache ? center - back_cache : list.begin(); 412 | std::vector::iterator end = idx + front_cache < list.size() ? (center + 1 + front_cache) : list.end(); 413 | assert(std::distance(begin, end) <= 1 + front_cache + back_cache); 414 | 415 | { 416 | for (auto it = begin; it != end; ++it) 417 | { 418 | if (temp[*it].empty() == false) 419 | { 420 | // std::cout << "Resuing " << *it << std::endl; 421 | data_cache[*it] = std::move(temp[*it]); 422 | } 423 | } 424 | 425 | /*for (auto it = temp.begin(); it != temp.end(); ++it) 426 | { 427 | if (it->second.empty() == false)std::cout << "Forgetting " << it->first.string() << std::endl; 428 | }*/ 429 | } 430 | 431 | for (auto it = begin; it != end; ++it) 432 | { 433 | auto& cached = data_cache[*it]; 434 | 435 | if (cached.empty() == true) 436 | { 437 | load_queue.push(*it); 438 | // std::cout << "Queued " << *it << std::endl; 439 | } 440 | } 441 | }; 442 | 443 | find_and_cache(color_files, last); 444 | find_and_cache(depth_files, last); 445 | find_and_cache(flow_files, last); 446 | } 447 | load_notify.notify_all(); 448 | //std::cout << std::endl; 449 | } 450 | 451 | -------------------------------------------------------------------------------- /synthrain/DataSequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "OGLTexture.h" 4 | #include "OGLFloatTexture.h" 5 | #include "FlowData.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef _WIN32 12 | namespace fs = std::experimental::filesystem; 13 | #else 14 | namespace fs = std::filesystem; 15 | #endif 16 | 17 | 18 | class DataSequence 19 | { 20 | public: 21 | DataSequence(std::shared_ptr bg_texture, std::shared_ptr flow_texture, std::shared_ptr depth_texture); 22 | ~DataSequence(); 23 | 24 | void setSequencesFolder(fs::path seq_folder); 25 | void setSequences(std::vector sources); 26 | void setOutputFolder(fs::path out_folder); 27 | 28 | void setSequence(int idx); 29 | void advanceSequence(); 30 | 31 | void setFrame(int idx); 32 | void advanceFrame(); 33 | 34 | void setColorFolderName(std::string name); 35 | 36 | bool isEndOfSequence(); 37 | bool isEndOfAllSequences(); 38 | bool useNewParameters(); 39 | 40 | void showCacheUI(); 41 | 42 | fs::path getCurrentOutputDirectory(); 43 | std::string getCurrentOutputFileName(); 44 | 45 | bool showUI(); 46 | 47 | int getFileCount(); 48 | 49 | int getCurrentFrame(); 50 | 51 | bool colorDataAvailable(); 52 | bool depthDataAvailable(); 53 | bool flowDataAvailable(); 54 | 55 | private: 56 | std::vector::iterator sequence_number; 57 | std::vector::iterator frame_number; 58 | 59 | fs::path base_dir; 60 | fs::path input_dir_color; 61 | fs::path input_dir_flow; 62 | fs::path input_dir_depth; 63 | 64 | fs::path baseoutput_dir; 65 | fs::path output_dir; 66 | 67 | std::string color_folder_name; 68 | 69 | std::vector color_files; 70 | std::vector flow_files; 71 | std::vector depth_files; 72 | std::vector sources; 73 | 74 | std::shared_ptr bg_texture; 75 | std::shared_ptr flow_texture; 76 | std::shared_ptr depth_texture; 77 | 78 | void loadFiles(); 79 | void loadSequence(); 80 | 81 | int subsequence_length; 82 | 83 | std::map> data_cache; 84 | 85 | std::queue load_queue; 86 | std::mutex mx; 87 | std::condition_variable load_notify; 88 | std::thread load_thread; 89 | 90 | static const int front_cache = 8; 91 | static const int back_cache = 2; 92 | int cache_misses; 93 | 94 | void load_thread_func(); 95 | void updateCache(); 96 | bool quit; 97 | }; 98 | 99 | -------------------------------------------------------------------------------- /synthrain/Exporter.cpp: -------------------------------------------------------------------------------- 1 | #include "Exporter.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "OGLTexture.h" 11 | 12 | 13 | Exporter::Exporter() 14 | { 15 | quit = false; 16 | std::generate(exporters, exporters + thread_count, [this]() {return std::thread(std::bind(&Exporter::output_images, this)); }); 17 | } 18 | 19 | void Exporter::shutdown() 20 | { 21 | { 22 | std::lock_guard lock(mx); 23 | quit = true; 24 | } 25 | 26 | export_notify.notify_all(); 27 | for (auto &exporter : exporters) exporter.join(); 28 | } 29 | 30 | void Exporter::enqueue(fs::path outfile, std::list textures) 31 | { 32 | img_save_data out; 33 | std::string outname; 34 | 35 | std::transform(textures.begin(), textures.end(), std::back_inserter(out.images), [](OGLImageLike* i) {return i->getAsSurface(); }); 36 | out.combine = textures.size() > 1; 37 | out.name = outfile.string(); 38 | 39 | { 40 | std::unique_lock lock(mx); 41 | export_notify.wait(lock, [this] { return output_queue.size() < 100; }); 42 | output_queue.push(out); 43 | } 44 | 45 | export_notify.notify_all(); 46 | } 47 | 48 | void Exporter::output_images() { 49 | static int active_threads = 0; 50 | static const unsigned int amask = 0xFF000000; 51 | static const unsigned int bmask = 0x00FF0000; 52 | static const unsigned int gmask = 0x0000FF00; 53 | static const unsigned int rmask = 0x000000FF; 54 | int thread_id = active_threads++; 55 | 56 | while (true) { 57 | std::unique_lock lock(mx); 58 | export_notify.wait(lock, [this] { return quit == true || output_queue.empty() == false; }); 59 | if (quit) break; 60 | 61 | img_save_data out = output_queue.front(); 62 | output_queue.pop(); 63 | lock.unlock(); 64 | 65 | if (out.combine == false) 66 | { 67 | for (auto img : out.images) 68 | { 69 | IMG_SavePNG(img, out.name.c_str()); 70 | // SDL_FreeSurface(out.clean); 71 | SDL_FreeSurface(img); 72 | // SDL_FreeSurface(out.ground_truth); 73 | } 74 | } 75 | else { 76 | 77 | int totalw = 0; 78 | int maxh = 0; 79 | 80 | for (auto img : out.images) 81 | { 82 | totalw += img->h; 83 | maxh = std::max(maxh, img->h); 84 | } 85 | 86 | SDL_Surface* output = SDL_CreateRGBSurface(0, totalw, maxh, 32, rmask, gmask, bmask, amask); 87 | int left = 0; 88 | 89 | for (auto img : out.images) 90 | { 91 | SDL_Rect dest = { left,0,img->w,img->h }; 92 | left += img->w; 93 | SDL_BlitSurface(img, NULL, output, &dest); 94 | SDL_FreeSurface(img); 95 | } 96 | 97 | IMG_SavePNG(output, out.name.c_str()); 98 | SDL_FreeSurface(output); 99 | } 100 | } 101 | } 102 | 103 | bool Exporter::export_queue_empty() 104 | { 105 | std::unique_lock lock(mx); 106 | return output_queue.empty(); 107 | } 108 | -------------------------------------------------------------------------------- /synthrain/Exporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #ifdef _WIN32 10 | namespace fs = std::experimental::filesystem; 11 | #else 12 | namespace fs = std::filesystem; 13 | #endif 14 | 15 | #include "OGLTexture.h" 16 | 17 | class Exporter 18 | 19 | { 20 | public: 21 | static const unsigned int thread_count = 12; 22 | std::thread exporters[thread_count]; 23 | 24 | Exporter(); 25 | 26 | void shutdown(); 27 | 28 | void enqueue(fs::path outfile, std::list textures); 29 | 30 | void output_images(); 31 | 32 | bool export_queue_empty(); 33 | 34 | private: 35 | bool quit; 36 | 37 | struct img_save_data 38 | { 39 | std::list images; 40 | std::string name; 41 | bool combine; 42 | }; 43 | 44 | std::mutex mx; 45 | std::condition_variable export_notify; 46 | std::queue output_queue; 47 | }; -------------------------------------------------------------------------------- /synthrain/FlowData.cpp: -------------------------------------------------------------------------------- 1 | #include "FlowData.h" 2 | #include "SDL2/SDL.h" 3 | #include 4 | #include 5 | #include "imgui/imgui.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #ifdef _WIN32 12 | namespace fs = std::experimental::filesystem; 13 | #else 14 | namespace fs = std::filesystem; 15 | #endif 16 | 17 | #ifndef _WIN32 18 | #include 19 | #endif 20 | 21 | static int id_num = 0; 22 | 23 | FlowData::FlowData() : flow{ 0 } 24 | { 25 | 26 | } 27 | 28 | FlowData::FlowData(std::string filepath) : flow{0} 29 | { 30 | loadFile(filepath); 31 | } 32 | 33 | void FlowData::loadFile(fs::path filepath) 34 | { 35 | loadFileRW( filepath.filename().string(), SDL_RWFromFile(filepath.string().c_str(), "rb") ); 36 | } 37 | 38 | 39 | void FlowData::loadFileRW(std::string filename, SDL_RWops* io) 40 | { 41 | const char* path = filename.c_str(); 42 | 43 | if (io != NULL) { 44 | size_t size = SDL_RWsize(io); 45 | assert(size == sizeof(fvector2)* flow.size()); 46 | 47 | if (size > 0) 48 | { 49 | if (SDL_RWread(io, flow.data(), size, 1) > 0) { 50 | // SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "Loaded flow file: %s", path); 51 | } 52 | SDL_RWclose(io); 53 | } 54 | else { 55 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Flow file was empty or invalid: %s", path); 56 | return; 57 | } 58 | } 59 | else { 60 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Failed to open flow file: %s", path); 61 | return; 62 | } 63 | } 64 | 65 | std::array FlowData::getFlowData() 66 | { 67 | return flow; 68 | } -------------------------------------------------------------------------------- /synthrain/FlowData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "fvector2.h" 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #ifdef _WIN32 10 | namespace fs = std::experimental::filesystem; 11 | #else 12 | namespace fs = std::filesystem; 13 | #endif 14 | 15 | 16 | class FlowData 17 | { 18 | public: 19 | 20 | FlowData(std::string filepath); 21 | FlowData(); 22 | 23 | void loadFile(fs::path filepath); 24 | void loadFileRW(std::string filename, SDL_RWops* filehandle); 25 | 26 | std::array getFlowData(); 27 | 28 | protected: 29 | 30 | std::array flow; 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /synthrain/LogWindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014-2020 Omar Cornut 5 | Modifications Copyright (c) 2020 Panasonic Corporation of North America 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | #include "LogWindow.h" 27 | #include "SDL2/SDL.h" 28 | #include "SDL2/SDL_log.h" 29 | 30 | #ifdef _WIN32 31 | #include 32 | #endif 33 | 34 | LogWindow LogWindow::instance; 35 | 36 | LogWindow* LogWindow::get() { return &instance; } 37 | 38 | static const char* priority[] = { "?","V","D","I","W","E","C" }; 39 | static const char* category[] = { "APP","ERR","ASRT","SYS","AUD","VID","RNDR","INP","TEST"}; 40 | 41 | inline const char* getCatStr(int cat) 42 | { 43 | return cat <= SDL_LOG_CATEGORY_TEST ? category[cat] : "UNK"; 44 | } 45 | 46 | inline const char* getPri(SDL_LogPriority pri) 47 | { 48 | return pri <= SDL_LOG_PRIORITY_CRITICAL ? priority[pri] : "U"; 49 | } 50 | 51 | void logfunc(void* userdata, 52 | int category, 53 | SDL_LogPriority priority, 54 | const char* message) 55 | { 56 | LogWindow* logwindow = reinterpret_cast(userdata); 57 | logwindow->AddLog("[%s]%s> %s\n", getPri(priority), getCatStr(category), message); 58 | #ifdef _WIN32 59 | OutputDebugStringA(message); 60 | OutputDebugStringA("\n"); 61 | #else 62 | printf("%s\n",message); 63 | #endif // _WIN32 64 | } 65 | 66 | LogWindow::LogWindow() 67 | { 68 | SDL_LogSetOutputFunction(logfunc, &instance); 69 | } 70 | 71 | 72 | LogWindow::~LogWindow() 73 | { 74 | } 75 | 76 | 77 | 78 | 79 | void LogWindow::AddLog(const char* fmt, ...) 80 | { 81 | int old_size = Buf.size(); 82 | va_list args; 83 | va_start(args, fmt); 84 | Buf.appendfv(fmt, args); 85 | va_end(args); 86 | for (int new_size = Buf.size(); old_size < new_size; old_size++) 87 | if (Buf[old_size] == '\n') 88 | LineOffsets.push_back(old_size); 89 | ScrollToBottom = true; 90 | } 91 | 92 | void LogWindow::Draw(const char* title, bool* p_opened) 93 | { 94 | ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiSetCond_FirstUseEver); 95 | if (ImGui::Begin(title, p_opened)) 96 | { 97 | if (ImGui::Button("Clear")) Clear(); 98 | ImGui::SameLine(); 99 | bool copy = ImGui::Button("Copy"); 100 | ImGui::SameLine(); 101 | Filter.Draw("Filter", -100.0f); 102 | ImGui::Separator(); 103 | ImGui::BeginChild("scrolling"); 104 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 1)); 105 | if (copy) ImGui::LogToClipboard(); 106 | 107 | if (Filter.IsActive()) 108 | { 109 | const char* buf_begin = Buf.begin(); 110 | const char* line = buf_begin; 111 | for (int line_no = 0; line != NULL; line_no++) 112 | { 113 | const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL; 114 | if (Filter.PassFilter(line, line_end)) 115 | ImGui::TextUnformatted(line, line_end); 116 | line = line_end && line_end[1] ? line_end + 1 : NULL; 117 | } 118 | } 119 | else 120 | { 121 | ImGui::TextUnformatted(Buf.begin()); 122 | } 123 | 124 | if (ScrollToBottom) 125 | ImGui::SetScrollHere(1.0f); 126 | ScrollToBottom = false; 127 | ImGui::PopStyleVar(); 128 | ImGui::EndChild(); 129 | } 130 | ImGui::End(); 131 | } 132 | 133 | void LogWindow::Clear() { Buf.clear(); LineOffsets.clear(); } -------------------------------------------------------------------------------- /synthrain/LogWindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014-2020 Omar Cornut 5 | Modifications Copyright (c) 2020 Panasonic Corporation of North America 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | // This class is based on sample code from the ImGui github repository 27 | // See https://github.com/ocornut/imgui/issues/300 28 | 29 | #pragma once 30 | #include "imgui/imgui.h" 31 | 32 | class LogWindow 33 | { 34 | public: 35 | ImGuiTextBuffer Buf; 36 | ImGuiTextFilter Filter; 37 | ImVector LineOffsets; // Index to lines offset 38 | bool ScrollToBottom; 39 | 40 | void Clear(); 41 | void AddLog(const char* fmt, ...); 42 | void Draw(const char* title, bool* p_opened = NULL); 43 | 44 | static LogWindow* get(); 45 | 46 | private: 47 | LogWindow(); 48 | ~LogWindow(); 49 | static LogWindow instance; 50 | }; 51 | 52 | -------------------------------------------------------------------------------- /synthrain/OGLComputeShader.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLComputeShader.h" 2 | #include 3 | #include 4 | #include 5 | #include "SDL2/SDL_log.h" 6 | 7 | #include "imgui/imgui.h" 8 | 9 | OGLComputeShader::OGLComputeShader(std::string file) 10 | { 11 | std::vector comp_shader_code = loadFile(file.c_str()); 12 | 13 | if (comp_shader_code.size() <= 0) return; 14 | 15 | GLuint comp_shader = compileShader(GL_COMPUTE_SHADER, file.c_str(), &comp_shader_code[0]); 16 | 17 | printf("Linking program\n"); 18 | program = glCreateProgram(); 19 | glAttachShader(program, comp_shader); 20 | glLinkProgram(program); 21 | 22 | GLint compile_result = GL_FALSE; 23 | int compile_log_len; 24 | 25 | glGetProgramiv(program, GL_LINK_STATUS, &compile_result); 26 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &compile_log_len); 27 | if (compile_log_len > 0) { 28 | std::vector errmsg(compile_log_len + 1); 29 | glGetProgramInfoLog(program, compile_log_len, NULL, &errmsg[0]); 30 | SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Shader link failed:\n%s", &errmsg[0]); 31 | } 32 | 33 | glDetachShader(program, comp_shader); 34 | glDeleteShader(comp_shader); 35 | 36 | //grab uniforms 37 | { 38 | GLint i; 39 | GLint count; 40 | 41 | const GLsizei bufSize = 64; 42 | GLchar name[bufSize]; 43 | GLsizei name_length; 44 | 45 | glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count); 46 | 47 | for (i = 0; i < count; i++) 48 | { 49 | unform_info out; 50 | out.position = i; 51 | glGetActiveUniform(program, (GLuint)i, bufSize, &name_length, &out.size, &out.type, name); 52 | if (out.type == GL_FLOAT) 53 | { 54 | float value; 55 | glGetUniformfv(program, i, &value); 56 | out.scale = value <= 0.01f ? 0.0001 : value <= 0.1f ? 0.001f : value <= 1.f ? 0.01f : 0.1f; 57 | } 58 | uniforms[name] = out; 59 | } 60 | } 61 | 62 | program_name = file; 63 | } 64 | 65 | OGLComputeShader::~OGLComputeShader() 66 | { 67 | } 68 | -------------------------------------------------------------------------------- /synthrain/OGLComputeShader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "OGLShader.h" 4 | #include 5 | #include 6 | #include 7 | 8 | class OGLComputeShader : public OGLShader 9 | { 10 | public: 11 | OGLComputeShader(std::string file); 12 | virtual ~OGLComputeShader(); 13 | private: 14 | 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /synthrain/OGLFloatTexture.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLFloatTexture.h" 2 | #include "SDL2/SDL.h" 3 | #include 4 | #include 5 | #include "imgui/imgui.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef _WIN32 11 | #include 12 | #endif 13 | 14 | static int id_num = 0; 15 | 16 | int format_to_channels(GLenum format) 17 | { 18 | int out = 0; 19 | 20 | switch (format) 21 | { 22 | case GL_RED: 23 | case GL_DEPTH_COMPONENT: 24 | out = 1; 25 | break; 26 | case GL_RG: 27 | out = 2; 28 | break; 29 | case GL_RGB: 30 | out = 3; 31 | break; 32 | case GL_RGBA: 33 | out = 4; 34 | break; 35 | } 36 | 37 | SDL_assert_always(out != 0); 38 | return out; 39 | } 40 | 41 | GLint format_to_internal(GLenum format) 42 | { 43 | GLint out = GL_NONE; 44 | switch (format) 45 | { 46 | case GL_DEPTH_COMPONENT: 47 | out = GL_DEPTH_COMPONENT32F; 48 | break; 49 | case GL_RED: 50 | out = GL_R32F; 51 | break; 52 | case GL_RG: 53 | out = GL_RG32F; 54 | break; 55 | case GL_RGB: 56 | out = GL_RGB32F; 57 | break; 58 | case GL_RGBA: 59 | out = GL_RGBA32F; 60 | break; 61 | } 62 | 63 | SDL_assert_always(out != GL_NONE); 64 | return out; 65 | } 66 | 67 | OGLFloatTexture::OGLFloatTexture() : OGLTexture(), flow{ 0 } 68 | { 69 | 70 | } 71 | 72 | OGLFloatTexture::OGLFloatTexture(GLenum format, fs::path filepath) : OGLTexture(), flow{0}, num_channels(format_to_channels(format)) 73 | { 74 | data_format = format; 75 | internal_format = format_to_internal(data_format); 76 | 77 | if(filepath.empty() == false) loadFile(filepath); 78 | } 79 | 80 | void OGLFloatTexture::loadFileRW(std::string filename, SDL_RWops *io) 81 | { 82 | data_type = GL_FLOAT; 83 | 84 | if (io != NULL) { 85 | size_t size = SDL_RWsize(io); 86 | if (size > 0) 87 | { 88 | raw_data.resize(size); 89 | if (SDL_RWread(io, &raw_data[0], raw_data.size(), 1) > 0) { 90 | //SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "Loaded float file: %s", path); 91 | } 92 | SDL_RWclose(io); 93 | } 94 | else { 95 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Flow file was empty or invalid: %s", filename.c_str()); 96 | return; 97 | } 98 | } 99 | else { 100 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Failed to open flow file: %s", filename.c_str()); 101 | return; 102 | } 103 | 104 | if (raw_data.size() > 0) { 105 | int new_width = *((float*)&raw_data[0]); 106 | int new_height = *((float*)&raw_data[4]);; 107 | 108 | if (handle == 0 || new_height != height || new_width != width) 109 | { 110 | if (handle != 0) glDeleteTextures(1, &handle); 111 | 112 | width = new_width; 113 | height = new_height; 114 | 115 | glGenTextures(1, &handle); 116 | 117 | glBindTexture(GL_TEXTURE_2D, handle); 118 | // glTexStorage2D(GL_TEXTURE_2D, 10, color_format, width, height); 119 | //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, color_mode, data_type, &out[8]); 120 | 121 | GLenum err; 122 | 123 | 124 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, data_format, data_type, &raw_data[8]); 125 | 126 | //glGenerateMipmap(GL_TEXTURE_2D); //free incremental downsample 127 | 128 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 129 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 130 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 131 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 132 | 133 | //glGetTexImage(GL_TEXTURE_2D, 8, color_mode, data_type, flow.data()); 134 | } else { 135 | width = new_width; 136 | height = new_height; 137 | 138 | glBindTexture(GL_TEXTURE_2D, handle); 139 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, data_format, data_type, &raw_data[8]); 140 | glGenerateMipmap(GL_TEXTURE_2D); //free inremental downsample 141 | } 142 | } 143 | else { 144 | SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Flow iamge error: %s\n...(from %s)", IMG_GetError(), filename.c_str()); 145 | } 146 | 147 | name = filename; 148 | } 149 | 150 | std::array OGLFloatTexture::getFlowData() 151 | { 152 | return flow; 153 | } 154 | 155 | std::vector OGLFloatTexture::valueAt(int x, int y) 156 | { 157 | size_t idx = y*width+x; 158 | std::vector out; 159 | float* pixel = &((float*)&raw_data[8])[idx*num_channels]; 160 | for (int i = 0; i < num_channels; ++i) out.push_back(pixel[i]); 161 | return out; 162 | } 163 | 164 | OGLFloatTexture::OGLFloatTexture(GLenum format, int width, int height, std::string name) : OGLTexture(width, height,name, format_to_internal(format), format), num_channels(format_to_channels(format)) 165 | { 166 | makeEmptyTexture(); 167 | 168 | if(name.size() <= 0) 169 | { 170 | std::stringstream fboname; 171 | fboname << "FBO " << id_num++; 172 | name = fboname.str(); 173 | } 174 | } 175 | 176 | 177 | -------------------------------------------------------------------------------- /synthrain/OGLFloatTexture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "OGLTexture.h" 4 | #include "fvector2.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class OGLFloatTexture : public OGLTexture 14 | { 15 | public: 16 | 17 | OGLFloatTexture(GLenum format, fs::path filepath = ""); 18 | OGLFloatTexture(GLenum format, int width, int height, std::string name = ""); 19 | 20 | virtual void loadFileRW(std::string filename, SDL_RWops* filehandle); 21 | 22 | std::array getFlowData(); 23 | operator GLuint() { return handle; } 24 | 25 | std::vector valueAt(int x, int y); 26 | 27 | protected: 28 | OGLFloatTexture(); 29 | int num_channels; 30 | 31 | std::array flow; 32 | 33 | std::vector raw_data; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /synthrain/OGLFrameBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLFrameBuffer.h" 2 | #include "OGLFloatTexture.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | std::string makeBufferName(std::string name, int count) 12 | { 13 | std::ostringstream out; 14 | out << name.c_str() << ":" << ++count; 15 | return out.str(); 16 | } 17 | 18 | OGLFrameBuffer::OGLFrameBuffer(int width, int height, std::string name) : OGLImageLike(width,height), name(name), framebuffer(0), depth_buffer(nullptr) 19 | { 20 | color_buffers.push_back(std::make_shared(width, height, makeBufferName(name,color_buffers.size()))); 21 | regenerateBuffer(); 22 | } 23 | 24 | OGLFrameBuffer::OGLFrameBuffer() 25 | { 26 | 27 | } 28 | 29 | void OGLFrameBuffer::initialize(int _width, int _height, std::string _name) 30 | { 31 | SDL_assert_always(color_buffers.empty() == true); 32 | 33 | name = _name; 34 | width = _width; 35 | height = _height; 36 | color_buffers.push_back(std::make_shared(width, height, makeBufferName(name, color_buffers.size()))); 37 | regenerateBuffer(); 38 | } 39 | 40 | void OGLFrameBuffer::initializeWithFloat(int _width, int _height, std::string _name) 41 | { 42 | SDL_assert_always(color_buffers.empty() == true); 43 | 44 | name = _name; 45 | width = _width; 46 | height = _height; 47 | color_buffers.push_back(std::make_shared(GL_RED, width, height, makeBufferName(name, color_buffers.size()))); 48 | regenerateBuffer(); 49 | } 50 | 51 | void OGLFrameBuffer::addDepthBuffer(std::shared_ptr tex) 52 | { 53 | depth_buffer = tex; 54 | regenerateBuffer(); 55 | } 56 | 57 | void OGLFrameBuffer::addColorBuffer() 58 | { 59 | color_buffers.push_back(std::make_shared(width, height, makeBufferName(name, color_buffers.size()))); 60 | regenerateBuffer(); 61 | } 62 | 63 | void OGLFrameBuffer::resize(int _width, int _height) 64 | { 65 | width = _width; 66 | height = _height; 67 | 68 | if(framebuffer != 0)glDeleteFramebuffers(1, &framebuffer); 69 | 70 | for (auto buffer : color_buffers) 71 | { 72 | buffer->resize(_width, _height); 73 | } 74 | 75 | regenerateBuffer(); 76 | } 77 | 78 | void OGLFrameBuffer::saveTo(std::string folder, std::string filename) const 79 | { 80 | unsigned int idx = 0; 81 | for (auto buffer : color_buffers) 82 | { 83 | std::ostringstream name; 84 | name << filename << "_" << idx++; 85 | buffer->saveTo(folder, filename.c_str()); 86 | } 87 | } 88 | 89 | void OGLFrameBuffer::activate() 90 | { 91 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); 92 | glViewport(0, 0, width, height); 93 | } 94 | 95 | void OGLFrameBuffer::deactivate() 96 | { 97 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 98 | } 99 | 100 | void OGLFrameBuffer::debugDraw() const 101 | { 102 | for (auto buffer : color_buffers) 103 | { 104 | buffer->debugDraw(); 105 | } 106 | } 107 | 108 | GLuint OGLFrameBuffer::getHandle(unsigned int idx) const 109 | { 110 | SDL_assert_always(idx < color_buffers.size()); 111 | 112 | return color_buffers[idx]->getHandle(); 113 | } 114 | 115 | SDL_Surface * OGLFrameBuffer::getAsSurface() const 116 | { 117 | return getAsSurface(0); 118 | } 119 | 120 | SDL_Surface * OGLFrameBuffer::getAsSurface(unsigned int idx) const 121 | { 122 | SDL_assert_always(idx < color_buffers.size()); 123 | 124 | return color_buffers[idx]->getAsSurface(); 125 | } 126 | 127 | std::shared_ptr OGLFrameBuffer::getColorBuffer(unsigned int idx) 128 | { 129 | SDL_assert_always(idx < color_buffers.size()); 130 | if (color_buffers.size() > idx) return color_buffers[idx]; 131 | return std::shared_ptr(nullptr); 132 | } 133 | 134 | OGLFrameBuffer::~OGLFrameBuffer() 135 | { 136 | 137 | } 138 | 139 | void OGLFrameBuffer::regenerateBuffer() 140 | { 141 | if (framebuffer != 0)glDeleteFramebuffers(1, &framebuffer); 142 | 143 | glGenFramebuffers(1, &framebuffer); 144 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); 145 | 146 | std::vector bufferlist; 147 | 148 | { 149 | unsigned int idx = 0; 150 | for (auto buffer : color_buffers) 151 | { 152 | SDL_assert_release(buffer->valid() == true); 153 | GLenum attach = GL_COLOR_ATTACHMENT0 + idx++; 154 | glFramebufferTexture2D(GL_FRAMEBUFFER, attach, GL_TEXTURE_2D, buffer->getHandle(), 0); 155 | auto err = glGetError(); 156 | assert(err == GL_NO_ERROR); 157 | bufferlist.push_back(attach); 158 | } 159 | } 160 | 161 | if (depth_buffer != nullptr) 162 | { 163 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_buffer->getHandle(), 0); 164 | } 165 | 166 | glDrawBuffers(bufferlist.size(), &bufferlist[0]); 167 | 168 | 169 | if (auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); status != GL_FRAMEBUFFER_COMPLETE) 170 | { 171 | SDL_Log("Framebuffer incomplete (%s)", name.c_str()); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /synthrain/OGLFrameBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "OGLTexture.h" 8 | #include "OGLFloatTexture.h" 9 | 10 | class OGLFrameBuffer : public OGLImageLike 11 | { 12 | public: 13 | OGLFrameBuffer(int width, int height, std::string name = ""); 14 | OGLFrameBuffer(); 15 | void initialize(int width, int height, std::string name = ""); 16 | void initializeWithFloat(int width, int height, std::string name = ""); 17 | void resize(int width, int height); 18 | void saveTo(std::string folder, std::string filename) const; 19 | void activate(); 20 | void deactivate(); 21 | 22 | void addDepthBuffer(std::shared_ptr tex); 23 | void addColorBuffer(); 24 | 25 | void debugDraw() const; 26 | GLuint getHandle(unsigned int idx = 0) const; 27 | 28 | SDL_Surface* getAsSurface() const override; 29 | SDL_Surface* getAsSurface(unsigned int idx = 0) const; 30 | std::shared_ptr getColorBuffer(unsigned int idx = 0); 31 | 32 | 33 | ~OGLFrameBuffer(); 34 | private: 35 | 36 | void regenerateBuffer(); 37 | GLuint framebuffer; 38 | std::vector> color_buffers; 39 | std::shared_ptr depth_buffer; 40 | std::string name; 41 | 42 | bool has_depth; 43 | 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /synthrain/OGLRenderStage.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLRenderStage.h" 2 | #include "SDL2/SDL.h" 3 | 4 | GLuint OGLRenderStage::vao_fs_quad = 0; 5 | GLuint OGLRenderStage::vao_center_origin_quad = 0; 6 | 7 | OGLRenderStage::OGLRenderStage(std::shared_ptr source, unsigned int divisor, std::string name) : source(source), fbo(source->getWidth()/divisor, source->getHeight()/divisor,name), name(name), source_divisor(divisor) 8 | { 9 | 10 | } 11 | 12 | 13 | OGLRenderStage::~OGLRenderStage() 14 | { 15 | 16 | } 17 | 18 | void OGLRenderStage::checkFBOSize() 19 | { 20 | if (source->sameSize(fbo, source_divisor) == false) 21 | { 22 | fbo.resize(source->getWidth() / source_divisor, source->getHeight() / source_divisor); 23 | } 24 | 25 | } 26 | 27 | void OGLRenderStage::debugDisplay() 28 | { 29 | fbo.debugDraw(); 30 | } 31 | 32 | OGLFrameBuffer * OGLRenderStage::getFBO() 33 | { 34 | return &fbo; 35 | } 36 | 37 | std::string OGLRenderStage::getName() 38 | { 39 | return name; 40 | } 41 | 42 | void OGLRenderStage::setSource(std::shared_ptr _source) 43 | { 44 | source = _source; 45 | } 46 | 47 | void OGLRenderStage::InitSharedResources() 48 | { 49 | static const GLfloat co_buffer_data[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; 50 | static const GLfloat fs_buffer_data[] = { 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f }; 51 | 52 | auto makeVao = [](GLuint& vao, GLfloat const* vtx_data,size_t size) { 53 | glGenVertexArrays(1, &vao); 54 | glBindVertexArray(vao); 55 | GLuint vtx_buffer; 56 | glGenBuffers(1, &vtx_buffer); 57 | glBindBuffer(GL_ARRAY_BUFFER, vtx_buffer); 58 | glBufferData(GL_ARRAY_BUFFER, size, vtx_data, GL_STATIC_DRAW); 59 | glEnableVertexAttribArray(0); 60 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 61 | glBindVertexArray(0); 62 | }; 63 | 64 | makeVao(vao_fs_quad, fs_buffer_data, sizeof(fs_buffer_data)); 65 | makeVao(vao_center_origin_quad, co_buffer_data, sizeof(co_buffer_data)); 66 | } 67 | -------------------------------------------------------------------------------- /synthrain/OGLRenderStage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLFrameBuffer.h" 3 | #include "OGLTexture.h" 4 | #include 5 | 6 | class OGLRenderStage 7 | { 8 | public: 9 | OGLRenderStage(std::shared_ptr source, unsigned int divisor, std::string name); 10 | virtual ~OGLRenderStage(); 11 | virtual void checkFBOSize(); 12 | virtual void draw(OGLRenderStage *previous) = 0; 13 | virtual void debugDisplay(); 14 | OGLFrameBuffer* getFBO(); 15 | std::string getName(); 16 | 17 | void setSource(std::shared_ptr source); 18 | 19 | static void InitSharedResources(); 20 | 21 | protected: 22 | OGLFrameBuffer fbo; 23 | std::shared_ptr source; 24 | unsigned int source_divisor; 25 | std::string name; 26 | 27 | static GLuint vao_fs_quad; 28 | static GLuint vao_center_origin_quad; 29 | }; -------------------------------------------------------------------------------- /synthrain/OGLRenderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "imgui/imgui.h" 7 | 8 | #include "rng.h" 9 | 10 | #include "OGLRenderer.h" 11 | #include "OGLTexture.h" 12 | #include "OGLFloatTexture.h" 13 | #include "RenderStageDrops.h" 14 | #include "OGLFrameBuffer.h" 15 | #include "OGLTexture.h" 16 | #include "OGLRenderStage.h" 17 | #include "RenderStageDrops.h" 18 | #include "RenderStageRefract.h" 19 | #include "RenderStageBokeh.h" 20 | #include "RenderStageFog.h" 21 | 22 | OGLRenderer::OGLRenderer(std::shared_ptr input_image, std::shared_ptr flow_texture, std::shared_ptr depth_texture) : 23 | dis_noise_layer(0, 1), 24 | dis_bokeh(0, 1), 25 | dis_focus(3, 8), 26 | dis_pattern(0, num_patterns - 1) 27 | { 28 | autoplay = false; 29 | 30 | available_effects = { Effect::Rain }; 31 | enabled_effects = available_effects; 32 | 33 | color_image = input_image; 34 | 35 | fog_stage = std::make_shared(color_image, depth_texture); 36 | drop_stage = std::make_shared(color_image, flow_texture); 37 | refract_stage = std::make_shared(color_image); 38 | bokeh_stage = std::make_shared(color_image); 39 | 40 | setUpRenderChain(); 41 | } 42 | 43 | OGLRenderer::~OGLRenderer() 44 | { 45 | 46 | } 47 | 48 | void OGLRenderer::draw() 49 | { 50 | for (auto stage : renderStages) 51 | { 52 | stage->checkFBOSize(); 53 | } 54 | 55 | OGLRenderStage* last = nullptr; 56 | for (auto stage : renderStages) 57 | { 58 | stage->draw(last); 59 | last = stage.get(); 60 | } 61 | } 62 | 63 | void OGLRenderer::onTick() // do physics simulation stuff 64 | { 65 | drop_stage->tickPhysics(); 66 | } 67 | 68 | void OGLRenderer::showSettingsUI() 69 | { 70 | // Definitely want a better way of doing this if we add any more effects... 71 | 72 | bool usefog = enabled_effects.count(Effect::Fog) > 0; 73 | bool userain = enabled_effects.count(Effect::Rain) > 0; 74 | 75 | bool dirty = false; 76 | std::set next_effects; 77 | 78 | if (ImGui::Checkbox("Show Rain", &userain)) 79 | { 80 | dirty = true; 81 | } 82 | 83 | if (available_effects.count(Effect::Fog) > 0 && ImGui::Checkbox("Show Fog", &usefog)) 84 | { 85 | dirty = true; 86 | } 87 | 88 | if (dirty) 89 | { 90 | if (userain) next_effects.insert(Effect::Rain); 91 | if (usefog) next_effects.insert(Effect::Fog); 92 | setActiveEffects(next_effects); 93 | } 94 | 95 | /* 96 | if (exporting == false) 97 | { 98 | if (ImGui::Button("Autoplay")) 99 | { 100 | autoplay = !autoplay; 101 | } 102 | } 103 | */ 104 | } 105 | 106 | void OGLRenderer::setAvailableEffects(std::set eff) 107 | { 108 | available_effects = eff; 109 | if (available_effects.count(Effect::Rain) == 0) available_effects.insert(Effect::Rain); 110 | setActiveEffects(enabled_effects); //re-sanitize the enabled effects and update the render chain 111 | } 112 | 113 | void OGLRenderer::setActiveEffects(std::set eff) 114 | { 115 | enabled_effects.clear(); 116 | std::set_intersection(eff.begin(), eff.end(), available_effects.begin(), available_effects.end(), std::inserter(enabled_effects, enabled_effects.begin())); 117 | if (enabled_effects.size() == 0) enabled_effects.insert(Effect::Rain); 118 | setUpRenderChain(); 119 | } 120 | 121 | void OGLRenderer::showDropGenerationUI() 122 | { 123 | if (ImGui::Button("Drop Generator", ImVec2(120, 30))) 124 | { 125 | ImGui::OpenPopup("Drop Generator"); 126 | } 127 | 128 | if (ImGui::BeginPopup("Drop Generator")) 129 | { 130 | ImGui::SliderInt("Preset", &selected_drop_layer, 0, num_patterns - 1); 131 | 132 | { 133 | RenderStageDrops::drop_gen_params* params[2] = { &noise_layer, &drop_distribution[selected_drop_layer] }; 134 | int idx = 1; 135 | 136 | for (auto &p : params) 137 | { 138 | if (ImGui::TreeNodeEx((void*)idx, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Framed, "Layer %d", idx++)) 139 | { 140 | ImGui::InputInt("Count", &p->count_avg); 141 | ImGui::SliderFloat("Count deviation%", &p->count_deviation, 0.01f, 1.f); 142 | ImGui::SliderFloat("Average Size", &p->size_avg, 0, 80); 143 | ImGui::SliderFloat("Size deviation%", &p->size_dev, 0.001f, 1.0f); 144 | 145 | if (p->count_avg <= 0) p->count_avg = 1; 146 | //if (params.count_deviation <= 0) params.count_deviation = 1; 147 | ImGui::TreePop(); 148 | } 149 | } 150 | if (ImGui::Button("Regenerate Drops")) 151 | { 152 | drop_stage->clearDrops(); 153 | for (auto p : params)drop_stage->addDrops(*p); 154 | } 155 | } 156 | ImGui::EndPopup(); 157 | } 158 | } 159 | 160 | void OGLRenderer::showStageDebugUI() 161 | { 162 | ImGui::BeginGroup(); 163 | 164 | for (auto stage : renderStages) 165 | { 166 | std::string namestr = stage->getName(); 167 | const char* name = namestr.c_str(); 168 | if (ImGui::Button(name, ImVec2(120, 30))) 169 | { 170 | ImGui::OpenPopup(name); 171 | } 172 | 173 | if (ImGui::BeginPopup(name)) 174 | { 175 | stage->debugDisplay(); 176 | ImGui::EndPopup(); 177 | } 178 | 179 | ImGui::SameLine(); 180 | /*ImGui::PushID(name); 181 | if (ImGui::CollapsingHeader(name)) 182 | { 183 | stage->debugDisplay(); 184 | } 185 | ImGui::PopID();*/ 186 | } 187 | 188 | ImGui::EndGroup(); 189 | } 190 | 191 | 192 | void OGLRenderer::showSideBySide() 193 | { 194 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 4.f)); 195 | ImGui::BeginGroup(); 196 | ImGui::SetCursorPosX(0); 197 | 198 | color_image->debugDraw(); 199 | 200 | ImGui::EndGroup(); 201 | ImGui::SameLine(); 202 | ImGui::BeginGroup(); 203 | 204 | renderStages.back()->getFBO()->getColorBuffer(0)->debugDraw(); 205 | 206 | ImGui::PopStyleVar(); 207 | ImGui::EndGroup(); 208 | } 209 | 210 | void OGLRenderer::setUpRenderChain() 211 | { 212 | if (enabled_effects.count(Effect::Fog) > 0) 213 | { 214 | auto fog_intermediate = fog_stage->getFBO()->getColorBuffer(0); 215 | drop_stage->setSource(fog_intermediate); 216 | refract_stage->setSource(fog_intermediate); 217 | bokeh_stage->setSource(fog_intermediate); 218 | } 219 | else { 220 | drop_stage->setSource(color_image); 221 | refract_stage->setSource(color_image); 222 | bokeh_stage->setSource(color_image); 223 | } 224 | 225 | renderStages.clear(); 226 | 227 | if (enabled_effects.count(Effect::Fog) > 0) 228 | { 229 | renderStages.push_back(fog_stage); 230 | } 231 | 232 | if (enabled_effects.count(Effect::Rain) > 0) 233 | { 234 | renderStages.push_back(drop_stage); 235 | renderStages.push_back(refract_stage); 236 | renderStages.push_back(bokeh_stage); 237 | } 238 | } 239 | 240 | void OGLRenderer::prepSequence() { 241 | drop_stage->clearDrops(); 242 | if (dis_noise_layer(RNG::mt) == 0)drop_stage->addDrops(noise_layer); 243 | drop_stage->addDrops(drop_distribution[dis_pattern(RNG::mt)]); 244 | //drop_stage->addDrops(drop_distribution[selected_drop_layer]); 245 | bokeh_stage->setBokehShape((BokehShape)dis_bokeh(RNG::mt)); 246 | bokeh_stage->setFocus(0.125f*dis_focus(RNG::mt)); 247 | fog_stage->randomizeParameters(); 248 | } 249 | 250 | OGLFrameBuffer* OGLRenderer::getOutputFBO() 251 | { 252 | return renderStages.back()->getFBO(); 253 | } 254 | 255 | -------------------------------------------------------------------------------- /synthrain/OGLRenderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "RenderStageDrops.h" 7 | 8 | class RenderStageFog;; 9 | class RenderStageRefract; 10 | class RenderStageBokeh; 11 | class FlowData; 12 | class OGLTexture; 13 | class OGLFloatTexture; 14 | class OGLRenderStage; 15 | 16 | class OGLRenderer 17 | { 18 | public: 19 | 20 | enum class Effect 21 | { 22 | Rain, 23 | Fog, 24 | Physics 25 | }; 26 | 27 | OGLRenderer(std::shared_ptr input_image, std::shared_ptr flow_texture, std::shared_ptr depth_texture); 28 | ~OGLRenderer(); 29 | 30 | void draw(); 31 | 32 | void onTick(); 33 | void showSettingsUI(); 34 | 35 | void setAvailableEffects(std::set eff); 36 | 37 | void setActiveEffects(std::set eff); 38 | 39 | void showDropGenerationUI(); 40 | void showStageDebugUI(); 41 | void showSideBySide(); 42 | void setUpRenderChain(); 43 | void prepSequence(); 44 | 45 | OGLFrameBuffer* getOutputFBO(); 46 | 47 | private: 48 | bool autoplay; 49 | 50 | std::set available_effects; 51 | std::set enabled_effects; 52 | 53 | std::shared_ptr fog_stage; 54 | std::shared_ptr drop_stage; 55 | std::shared_ptr refract_stage; 56 | std::shared_ptr bokeh_stage; 57 | 58 | std::shared_ptr color_image; 59 | 60 | static const int num_patterns = 8; 61 | RenderStageDrops::drop_gen_params noise_layer = { 200,2.0,3.8f,0.33f,1,1 }; 62 | //RenderStageDrops::drop_gen_params noise_layer = { 100,1.0,3.8f,0.33f,1,1 }; 63 | 64 | RenderStageDrops::drop_gen_params drop_distribution[num_patterns] = { 65 | { 100,1.0f,3.8f,0.33f,1,1 },{ 60,0.125f,1,1.0f,1,1 },{ 150,1.0f,7.835f,0.34f,1,1 },{ 15,1,20,0.25f,1,1 }, 66 | { 5,0.8f,16,0.55f,1,1 },{ 18,0.2f,15,0.2f,1,1 },{ 12,0.5f,20,0.3f,1,1 },{ 6,0.25f,37,0.3f,1,1 } }; 67 | 68 | std::uniform_int_distribution<> dis_noise_layer; 69 | std::uniform_int_distribution<> dis_bokeh; 70 | std::uniform_int_distribution<> dis_focus; 71 | std::uniform_int_distribution<> dis_pattern; 72 | int selected_drop_layer = 0; 73 | 74 | std::vector < std::shared_ptr> renderStages; 75 | 76 | //m_renderStages.push_back(fog_stage); 77 | }; -------------------------------------------------------------------------------- /synthrain/OGLShader.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLShader.h" 2 | #include 3 | #include 4 | #include 5 | #include "SDL2/SDL_log.h" 6 | 7 | #include "imgui/imgui.h" 8 | 9 | OGLShader::OGLShader(std::string vtx_file, std::string frag_file, std::string geom_file) : 10 | program(0), vtx_file(vtx_file), frag_file(frag_file), geom_file(geom_file) 11 | { 12 | reloadShaders(); 13 | } 14 | 15 | void OGLShader::reloadShaders() 16 | { 17 | GLuint old_program = program; 18 | 19 | std::vector vtx_shader_code = loadFile(vtx_file.c_str()); 20 | std::vector frag_shader_code = loadFile(frag_file.c_str()); 21 | std::vector geom_shader_code; 22 | 23 | if (geom_file.size() > 0) 24 | { 25 | geom_shader_code = loadFile(geom_file.c_str()); 26 | } 27 | 28 | if (vtx_shader_code.size() <= 0 || frag_shader_code.size() <= 0) return; 29 | 30 | GLuint vtx_shader = compileShader(GL_VERTEX_SHADER, vtx_file.c_str(), &vtx_shader_code[0]); 31 | GLuint frag_shader = compileShader(GL_FRAGMENT_SHADER, frag_file.c_str(), &frag_shader_code[0]); 32 | 33 | printf("Linking program\n"); 34 | program = glCreateProgram(); 35 | glAttachShader(program, vtx_shader); 36 | glAttachShader(program, frag_shader); 37 | if (geom_shader_code.size() > 0) 38 | { 39 | GLuint geom_shader = compileShader(GL_GEOMETRY_SHADER, geom_file.c_str(), &geom_shader_code[0]); 40 | glAttachShader(program, geom_shader); 41 | } 42 | 43 | glLinkProgram(program); 44 | 45 | GLint compile_result = GL_FALSE; 46 | int compile_log_len; 47 | 48 | glGetProgramiv(program, GL_LINK_STATUS, &compile_result); 49 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &compile_log_len); 50 | 51 | glDetachShader(program, vtx_shader); 52 | glDetachShader(program, frag_shader); 53 | 54 | glDeleteShader(vtx_shader); 55 | glDeleteShader(frag_shader); 56 | 57 | if (compile_result == GL_FALSE || compile_log_len > 0) { 58 | std::vector errmsg(compile_log_len + 1); 59 | glGetProgramInfoLog(program, compile_log_len, NULL, &errmsg[0]); 60 | SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Shader link failed:\n%s", &errmsg[0]); 61 | program = old_program; 62 | } 63 | else { 64 | if(old_program > 0) glDeleteProgram(old_program); 65 | 66 | //grab uniforms 67 | { 68 | uniforms.clear(); 69 | GLint i; 70 | GLint count; 71 | 72 | const GLsizei bufSize = 64; 73 | GLchar name[bufSize]; 74 | GLsizei name_length; 75 | 76 | glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count); 77 | 78 | for (i = 0; i < count; i++) 79 | { 80 | unform_info out; 81 | out.position = i; 82 | glGetActiveUniform(program, (GLuint)i, bufSize, &name_length, &out.size, &out.type, name); 83 | if (out.type == GL_FLOAT) 84 | { 85 | float values[4] = {0}; 86 | glGetUniformfv(program, i, values); 87 | out.scale = values[0] <= 0.01f ? 0.0001 : values[0] <= 0.1f ? 0.001f : values[0] <= 1.f ? 0.01f : 0.1f; 88 | } 89 | uniforms[name] = out; 90 | } 91 | } 92 | } 93 | 94 | program_name = vtx_file; 95 | if (geom_file.size() > 0) program_name += "\n" + geom_file; 96 | program_name += "\n" + frag_file; 97 | } 98 | 99 | void OGLShader::debug_uniforms() 100 | { 101 | if (ImGui::Begin("Shader Uniforms")) 102 | { 103 | if( ImGui::TreeNode(program_name.c_str()) ) 104 | { 105 | for (auto uniform : uniforms) 106 | { 107 | if (uniform.second.type == GL_FLOAT) 108 | { 109 | float value; 110 | glGetUniformfv(program, uniform.second.position, &value); 111 | 112 | if (ImGui::DragFloat(uniform.first.c_str(), &value,uniform.second.scale,0)) 113 | { 114 | glUniform1f(uniform.second.position, value); 115 | } 116 | } 117 | } 118 | 119 | ImGui::TreePop(); 120 | } 121 | } 122 | ImGui::End(); 123 | 124 | } 125 | 126 | OGLShader::~OGLShader() 127 | { 128 | } 129 | 130 | void OGLShader::activate() 131 | { 132 | glUseProgram(program); 133 | } 134 | 135 | void OGLShader::deactivate() 136 | { 137 | glUseProgram(0); 138 | } 139 | 140 | GLuint OGLShader::getProgram() 141 | { 142 | return program; 143 | } 144 | 145 | void OGLShader::showUI(const char* shader_name) 146 | { 147 | if (ImGui::TreeNode(shader_name)) 148 | { 149 | //ImGui::PushID(shader_name); 150 | 151 | if (ImGui::Button("Reload")) 152 | { 153 | reloadShaders(); 154 | } 155 | 156 | if (ImGui::TreeNode("Uniforms")) { 157 | ImGui::PushItemWidth(120); 158 | activate(); 159 | for (auto uniform : uniforms) 160 | { 161 | if (uniform.second.type == GL_FLOAT) 162 | { 163 | float value; 164 | glGetUniformfv(program, uniform.second.position, &value); 165 | 166 | if (ImGui::DragFloat(uniform.first.c_str(), &value, uniform.second.scale, 0)) 167 | { 168 | glUniform1f(uniform.second.position, value); 169 | } 170 | } 171 | } 172 | deactivate(); 173 | ImGui::PopItemWidth(); 174 | ImGui::TreePop(); 175 | } 176 | ImGui::TreePop(); 177 | } 178 | } 179 | 180 | std::vector OGLShader::loadFile(const char* path) { 181 | SDL_RWops *io = SDL_RWFromFile(path, "rb"); 182 | std::vector out; 183 | if (io != NULL) { 184 | size_t size = SDL_RWsize(io); 185 | if (size > 0) 186 | { 187 | out.resize(size + 1); 188 | if (SDL_RWread(io, &out[0], out.size(), 1) > 0) { 189 | SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "Loaded shader %s", path); 190 | } 191 | SDL_RWclose(io); 192 | out[size] = 0; //we're not using the string class so we have to null-terminate ourselves. 193 | } 194 | else { 195 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "File was empty or invalid for shader %s", path); 196 | } 197 | } 198 | else { 199 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Failed to open shader %s", path); 200 | } 201 | return out; 202 | }; 203 | 204 | GLuint OGLShader::compileShader(GLenum type, const char* name, const char* data){ 205 | GLuint shader_id = glCreateShader(type); 206 | GLint compile_result = GL_FALSE; 207 | int compile_log_len; 208 | 209 | glShaderSource(shader_id, 1, &data, NULL); 210 | glCompileShader(shader_id); 211 | // Check Vertex Shader 212 | glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compile_result); 213 | glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &compile_log_len); 214 | if (compile_log_len > 0) { 215 | std::vector errmsg(compile_log_len + 1); 216 | glGetShaderInfoLog(shader_id, compile_log_len, NULL, &errmsg[0]); 217 | SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Shader compile failed for [%s]:\n%s", name, &errmsg[0]); 218 | } 219 | return shader_id; 220 | } 221 | 222 | OGLShader::OGLShader() 223 | { 224 | 225 | } 226 | -------------------------------------------------------------------------------- /synthrain/OGLShader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define ShowShaderUI(shader) shader.showUI(#shader); 9 | 10 | class OGLShader 11 | { 12 | public: 13 | OGLShader(std::string vtx_file, std::string frag_file, std::string geom_file = ""); 14 | ~OGLShader(); 15 | 16 | void reloadShaders(); 17 | void activate(); 18 | void debug_uniforms(); 19 | void deactivate(); 20 | 21 | GLuint getProgram(); 22 | 23 | void showUI(const char* shader_name); 24 | 25 | protected: 26 | 27 | static std::vector loadFile(const char* path); 28 | static GLuint compileShader(GLenum type, const char* name, const char* data); 29 | 30 | OGLShader(); 31 | std::string program_name; 32 | 33 | GLuint program; 34 | 35 | struct unform_info 36 | { 37 | GLint position; 38 | GLint size; 39 | GLenum type; 40 | float scale; 41 | }; 42 | 43 | std::string vtx_file; 44 | std::string frag_file; 45 | std::string geom_file; 46 | 47 | std::map uniforms; //should replace this with json.hpp 48 | 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /synthrain/OGLTexture.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLTexture.h" 2 | #include "SDL2/SDL.h" 3 | #include 4 | #include 5 | #include "imgui/imgui.h" 6 | #include 7 | 8 | #ifndef _WIN32 9 | #include 10 | #endif 11 | 12 | static int id_num = 0; 13 | 14 | OGLTexture::OGLTexture() : OGLImageLike(), crop_h(0), crop_w(0), handle(0), internal_format(0), data_format(GL_NONE), data_type(GL_NONE) 15 | { 16 | 17 | } 18 | 19 | OGLTexture::OGLTexture(std::string filepath, int crop_w, int crop_h) : crop_w(crop_w), crop_h(crop_h), handle(0), internal_format(0), data_format(GL_NONE), data_type(GL_NONE) 20 | { 21 | loadFile(filepath); 22 | } 23 | 24 | SDL_Surface* crop_surface(SDL_Surface* input, int x, int y, int width, int height) 25 | { 26 | SDL_Surface* surface = SDL_CreateRGBSurface(input->flags, width, height, input->format->BitsPerPixel, input->format->Rmask, input->format->Gmask, input->format->Bmask, input->format->Amask); 27 | 28 | SDL_Rect rect = { x, y, width, height }; 29 | 30 | SDL_BlitSurface(input, &rect, surface, 0); 31 | 32 | return surface; 33 | } 34 | 35 | void OGLTexture::loadFileRW(std::string filename, SDL_RWops* filehandle) 36 | { 37 | SDL_Surface *surface = nullptr; 38 | SDL_Surface *cropped = nullptr; 39 | void *source; 40 | 41 | surface = IMG_Load_RW(filehandle,true); 42 | 43 | if (surface) { 44 | switch (surface->format->BytesPerPixel) 45 | { 46 | case 3: 47 | data_format = GL_RGB; 48 | break; 49 | case 4: 50 | data_format = GL_RGBA; 51 | break; 52 | default: //rut roh 53 | SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Unsupported image format\n...(from %s)", filename.c_str()); 54 | return; 55 | } 56 | 57 | internal_format = data_format; 58 | data_type = GL_UNSIGNED_BYTE; 59 | 60 | int new_width = surface->w; 61 | int new_height = surface->h; 62 | 63 | if (crop_w > 0 && crop_h > 0) 64 | { 65 | int xmargin = (new_width - crop_w) / 2; 66 | cropped = crop_surface(surface, xmargin, 0, crop_w, crop_h); 67 | 68 | new_width = crop_w; 69 | new_height = crop_h; 70 | source = cropped->pixels; 71 | } 72 | else { 73 | source = surface->pixels; 74 | } 75 | 76 | if (handle == 0 || new_height != height || new_width != width) 77 | { 78 | if (handle != 0) glDeleteTextures(1, &handle); 79 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 80 | 81 | glGenTextures(1, &handle); 82 | glBindTexture(GL_TEXTURE_2D, handle); 83 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, new_width, new_height, 0, data_format, data_type, source); 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 86 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 88 | } 89 | else { //update 90 | glBindTexture(GL_TEXTURE_2D, handle); 91 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, new_width, new_height, data_format, data_type, source); 92 | } 93 | 94 | width = new_width; 95 | height = new_height; 96 | if (cropped != nullptr)SDL_FreeSurface(cropped); 97 | if (surface != nullptr)SDL_FreeSurface(surface); 98 | } 99 | else { 100 | SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "IMG_Load error: %s\n...(from %s)", IMG_GetError(), filename.c_str()); 101 | } 102 | 103 | name = filename; 104 | } 105 | 106 | void OGLTexture::loadFile(fs::path filepath) 107 | { 108 | loadFileRW(filepath.filename().string(), SDL_RWFromFile(filepath.string().c_str(), "rb")); 109 | } 110 | 111 | 112 | OGLTexture::OGLTexture(int width, int height, std::string name, GLint internal_format, GLenum data_format) : 113 | OGLImageLike(width, height), name(name), internal_format(internal_format), data_format(data_format) 114 | { 115 | data_type = GL_FLOAT; 116 | 117 | makeEmptyTexture(); 118 | 119 | if(name.size() <= 0) 120 | { 121 | std::stringstream fboname; 122 | fboname << "FBO " << id_num++; 123 | name = fboname.str(); 124 | } 125 | } 126 | 127 | void OGLTexture::resize(int _width, int _height) 128 | { 129 | width = _width; 130 | height = _height; 131 | glDeleteTextures(1, &handle); 132 | makeEmptyTexture(); 133 | } 134 | 135 | 136 | int OGLTexture::getWidth() const 137 | { 138 | return width; 139 | } 140 | 141 | int OGLTexture::getHeight() const 142 | { 143 | return height; 144 | } 145 | 146 | void OGLTexture::setCrop(int _crop_w, int _crop_h) 147 | { 148 | crop_w = _crop_w; 149 | crop_h = _crop_h; 150 | } 151 | 152 | void OGLTexture::debugDraw() const 153 | { 154 | ImGui::Image((ImTextureID)handle, ImVec2(width, height)); 155 | 156 | std::string popupname = name + "popup"; 157 | 158 | if (ImGui::BeginPopupContextItem(popupname.c_str())) 159 | { 160 | ImGui::Text("%s", name.c_str()); 161 | ImGui::Separator(); 162 | if (ImGui::Selectable("Save")) saveTo("./shaders/debug", name); 163 | ImGui::Text("%d x %d", width, height); 164 | ImGui::EndPopup(); 165 | } 166 | } 167 | 168 | GLuint OGLTexture::getHandle() const 169 | { 170 | return handle; 171 | } 172 | 173 | SDL_Surface* OGLTexture::getAsSurface() const 174 | { 175 | static const unsigned int amask = 0xFF000000; 176 | static const unsigned int bmask = 0x00FF0000; 177 | static const unsigned int gmask = 0x0000FF00; 178 | static const unsigned int rmask = 0x000000FF; 179 | 180 | SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, rmask, gmask, bmask, amask); 181 | SDL_LockSurface(surface); 182 | glBindTexture(GL_TEXTURE_2D, handle); 183 | glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); 184 | SDL_UnlockSurface(surface); 185 | return surface; 186 | } 187 | 188 | void OGLTexture::saveTo(std::string folder, std::string filename) const 189 | { 190 | SDL_Surface* surface = getAsSurface(); 191 | IMG_SavePNG(surface, (folder + "/" + filename + ".png").c_str()); 192 | SDL_FreeSurface(surface); 193 | } 194 | 195 | void OGLTexture::makeEmptyTexture() 196 | { 197 | glGenTextures(1, &handle); 198 | 199 | glBindTexture(GL_TEXTURE_2D, handle); 200 | 201 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, data_format, data_type, 0); 202 | 203 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 204 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 205 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 206 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 207 | } 208 | 209 | 210 | OGLTexture::~OGLTexture() 211 | { 212 | } 213 | 214 | 215 | -------------------------------------------------------------------------------- /synthrain/OGLTexture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #ifdef _WIN32 9 | namespace fs = std::experimental::filesystem; 10 | #else 11 | namespace fs = std::filesystem; 12 | #endif 13 | 14 | 15 | class OGLImageLike 16 | { 17 | public: 18 | OGLImageLike() : width(0), height(0) {} 19 | OGLImageLike(int width, int height) : width(width), height(height) {} 20 | virtual void resize(int width, int height) = 0; 21 | virtual void saveTo(std::string folder, std::string filename) const = 0; 22 | virtual void debugDraw() const = 0; 23 | int getWidth() const { return width; } 24 | int getHeight() const { return height; } 25 | 26 | virtual bool valid() { return width != 0 && height != 0; } 27 | 28 | bool sameSize(const OGLImageLike & other, unsigned int divisor) const 29 | { 30 | return width / divisor == other.width && height / divisor == other.height; 31 | } 32 | 33 | virtual SDL_Surface* getAsSurface() const = 0; 34 | 35 | protected: 36 | int width; 37 | int height; 38 | }; 39 | 40 | 41 | class OGLTexture : public OGLImageLike 42 | { 43 | public: 44 | OGLTexture(); 45 | OGLTexture(std::string filepath, int crop_w = 0, int crop_h = 0); 46 | OGLTexture(int width, int height, std::string name = "", GLint format = GL_RGBA32F, GLenum layout = GL_RGBA); 47 | 48 | virtual void loadFileRW(std::string filename, SDL_RWops* filehandle); 49 | void loadFile(fs::path filepath); 50 | 51 | virtual void resize(int width, int height); 52 | 53 | operator GLuint() { return handle; } 54 | 55 | int getWidth() const; 56 | int getHeight() const; 57 | 58 | void setCrop(int crop_w, int crop_h); 59 | 60 | ~OGLTexture(); 61 | void debugDraw() const; 62 | GLuint getHandle() const; 63 | 64 | void saveTo(std::string folder, std::string filename) const; 65 | 66 | SDL_Surface* getAsSurface() const override; 67 | 68 | protected: 69 | void makeEmptyTexture(); 70 | 71 | int crop_h; 72 | int crop_w; 73 | 74 | GLuint handle; 75 | GLint internal_format; 76 | GLenum data_format; 77 | GLenum data_type; 78 | std::string name; 79 | }; -------------------------------------------------------------------------------- /synthrain/OGLVideoTexture.cpp: -------------------------------------------------------------------------------- 1 | #include "OGLVideoTexture.h" 2 | #include "SDL2/SDL.h" 3 | #include 4 | #include 5 | #include "imgui/imgui.h" 6 | #include 7 | 8 | #ifdef _WIN32 9 | extern "C"{ 10 | #include 11 | #include 12 | #include 13 | } 14 | #else 15 | extern "C" { 16 | #include 17 | #include 18 | #include 19 | } 20 | 21 | #endif 22 | 23 | 24 | #ifndef _WIN32 25 | #include 26 | #endif 27 | 28 | static int id_num = 0; 29 | 30 | #define INBUF_SIZE 4096 31 | 32 | void OGLVideoTexture::InitVideo() { 33 | av_register_all(); 34 | } 35 | 36 | OGLVideoTexture::OGLVideoTexture(std::string filepath) : OGLTexture() 37 | { 38 | pkt = av_packet_alloc(); 39 | SDL_assert(pkt != nullptr); 40 | // Allocate video frame 41 | frame = av_frame_alloc(); 42 | SDL_assert(frame != nullptr); 43 | frame_buffer.reset(new uint8_t[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]); 44 | 45 | reload(filepath); 46 | } 47 | 48 | OGLVideoTexture::~OGLVideoTexture() 49 | { 50 | 51 | } 52 | 53 | void OGLVideoTexture::reload(std::string filepath) 54 | { 55 | SDL_Log("Opening video: %s", filepath.c_str()); 56 | 57 | fmt_ctx = avformat_alloc_context(); 58 | SDL_Log("avformat_alloc_context = [%08X]", fmt_ctx); 59 | 60 | int result = avformat_open_input(&fmt_ctx, filepath.c_str(), NULL, NULL); 61 | SDL_Log("avformat_open_input = %d", result); 62 | SDL_assert(result == 0); 63 | 64 | result = avformat_find_stream_info(fmt_ctx, NULL); 65 | SDL_Log("avformat_find_stream_info = %d", result); 66 | SDL_assert(result >= 0); 67 | 68 | AVCodecParameters* params = nullptr; 69 | 70 | // Find the first video stream 71 | for(int i = 0; i< fmt_ctx->nb_streams; i++) 72 | { 73 | if(fmt_ctx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) { 74 | SDL_Log("using video stream %d", i); 75 | params = fmt_ctx->streams[i]->codecpar; 76 | break; 77 | } 78 | } 79 | 80 | SDL_assert(params != nullptr); 81 | 82 | // Get a pointer to the codec context for the video stream 83 | 84 | 85 | AVCodec *pCodec = nullptr; 86 | pCodec = avcodec_find_decoder(params->codec_id); 87 | SDL_Log("avcodec_find_decoder = [%08X]", pCodec); 88 | SDL_assert(pCodec != nullptr); 89 | 90 | // make our context 91 | codec_ctx = avcodec_alloc_context3(pCodec); 92 | result = avcodec_parameters_to_context(codec_ctx, params); 93 | SDL_Log("avcodec_parameters_to_context = %d", result); 94 | SDL_assert(result == 0); 95 | 96 | // Open codec 97 | result = avcodec_open2(codec_ctx, pCodec, NULL); 98 | SDL_Log("avcodec_open2 = %d", result); 99 | SDL_assert(result >= 0); 100 | 101 | // initialize SWS context for software scaling 102 | sws_ctx = sws_getContext(codec_ctx->width, 103 | codec_ctx->height, 104 | codec_ctx->pix_fmt, 105 | codec_ctx->width, 106 | codec_ctx->height, 107 | AV_PIX_FMT_RGB24, 108 | SWS_BILINEAR, 109 | NULL, 110 | NULL, 111 | NULL 112 | ); 113 | 114 | SDL_Log("sws_getContext = %d", sws_ctx); 115 | 116 | internal_format = GL_RGB; 117 | data_type = GL_UNSIGNED_BYTE; 118 | data_format = internal_format; 119 | 120 | width = codec_ctx->width; 121 | height = codec_ctx->height; 122 | 123 | SDL_Log("Make texture"); 124 | 125 | if (handle == 0) 126 | { 127 | glGenTextures(1, &handle); 128 | } 129 | 130 | glBindTexture(GL_TEXTURE_2D, handle); 131 | 132 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 133 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 134 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); 135 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 136 | 137 | glBindTexture(GL_TEXTURE_2D, 0); 138 | glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, data_format, data_type, NULL); 139 | 140 | next_frame(); 141 | } 142 | 143 | static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, 144 | const char *filename) 145 | { 146 | FILE *f; 147 | int i; 148 | 149 | fopen_s(&f, filename, "w"); 150 | fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255); 151 | for (i = 0; i < ysize; i++) 152 | fwrite(buf + i * wrap, 1, xsize, f); 153 | fclose(f); 154 | } 155 | 156 | void OGLVideoTexture::next_frame() 157 | { 158 | int frame_no; 159 | int rcv_result; 160 | 161 | while(true) 162 | { 163 | frame_no = av_read_frame(fmt_ctx, pkt); 164 | SDL_Log("Decoding frame %d", frame_no); 165 | 166 | int result = avcodec_send_packet(codec_ctx, pkt); 167 | SDL_Log("avcodec_send_packet = %d", result); 168 | SDL_assert(result <= 0); 169 | 170 | result = avcodec_receive_frame(codec_ctx, frame); 171 | if (result == AVERROR(EAGAIN)) continue; 172 | if ( result == AVERROR_EOF ) return; 173 | 174 | SDL_Log("avcodec_receive_frame = %d", result); 175 | SDL_assert(result <= 0); 176 | 177 | SDL_Log("saving frame %3d\n", codec_ctx->frame_number); 178 | 179 | /* the picture is allocated by the decoder. no need to 180 | free it */ 181 | std::ostringstream fname; 182 | fname << "frame " << codec_ctx->frame_number << ".pgm"; 183 | pgm_save(frame->data[0], frame->linesize[0], 184 | frame->width, frame->height, fname.str().c_str()); 185 | break; 186 | } 187 | } -------------------------------------------------------------------------------- /synthrain/OGLVideoTexture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLTexture.h" 3 | #include 4 | #include 5 | 6 | struct AVCodecContext; 7 | struct AVFormatContext; 8 | struct AVFrame; 9 | struct SwsContext; 10 | struct AVPacket; 11 | 12 | class OGLVideoTexture : public OGLTexture 13 | { 14 | public: 15 | static void InitVideo(); // init ffmpeg 16 | 17 | OGLVideoTexture(std::string filepath); 18 | ~OGLVideoTexture(); 19 | 20 | void reload(std::string filepath); 21 | void next_frame(); 22 | 23 | protected: 24 | AVPacket *pkt; 25 | AVFrame *frame; 26 | AVFormatContext* fmt_ctx; 27 | AVCodecContext* codec_ctx; 28 | SwsContext *sws_ctx; 29 | 30 | // AVFrame *pFrameRGB; 31 | 32 | std::shared_ptr frame_buffer; 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /synthrain/RenderStageBokeh.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderStageBokeh.h" 2 | #include "RenderStageRefract.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "imgui/imgui.h" 10 | 11 | static const GLfloat vtx_buffer_data[] = { 12 | 0.f, 0.f, 13 | 1.f, 0.f, 14 | 0.f, 1.f, 15 | 1.f, 1.f, 16 | }; 17 | 18 | RenderStageBokeh::RenderStageBokeh(std::shared_ptr source) : OGLRenderStage(source, 1, "Defocus"), 19 | bokeh_billboard{ OGLTexture("./shaders/bokeh-hex.png"), OGLTexture("./shaders/bokeh-round2.png") }, 20 | bokeh_shader("./shaders/basic.vert", "./shaders/bokeh.frag", "./shaders/bokeh-hex.geom"), 21 | bokeh_billboard_shader("./shaders/basic.vert", "./shaders/bokeh-billboard.frag", "./shaders/bokeh-billboard.geom"), 22 | trivial_shader("./shaders/basic.vert", "./shaders/basic.frag") 23 | { 24 | focus = 0.4f; 25 | brightness = 10.f; 26 | use_billboard = true; 27 | focus_dirty = false; 28 | current_billboard = Bokeh_Hex; 29 | 30 | fbo.addColorBuffer(); 31 | 32 | bokeh_billboard_shader.activate(); 33 | { 34 | GLint tex_uniform = glGetUniformLocation(bokeh_billboard_shader.getProgram(), "tex"); 35 | glUniform1i(tex_uniform, 0); 36 | 37 | tex_uniform = glGetUniformLocation(bokeh_billboard_shader.getProgram(), "billboard_tex"); 38 | glUniform1i(tex_uniform, 1); 39 | 40 | screen_uniform = glGetUniformLocation(bokeh_billboard_shader.getProgram(), "u_aspect"); 41 | glUniform1f(screen_uniform, (float)fbo.getWidth() / fbo.getHeight()); 42 | 43 | u_size = glGetUniformLocation(bokeh_billboard_shader.getProgram(), "u_size"); 44 | u_alpha_max = glGetUniformLocation(bokeh_billboard_shader.getProgram(), "u_alpha_max"); 45 | u_alpha_min = glGetUniformLocation(bokeh_billboard_shader.getProgram(), "u_alpha_min"); 46 | } 47 | bokeh_billboard_shader.deactivate(); 48 | 49 | /* bokeh_shader.activate(); 50 | { 51 | GLint tex_uniform = glGetUniformLocation(bokeh_shader.getProgram(), "tex"); 52 | glUniform1i(tex_uniform, 0); 53 | 54 | screen_uniform = glGetUniformLocation(bokeh_shader.getProgram(), "u_aspect"); 55 | glUniform1f(screen_uniform, (float)fbo.getWidth() / fbo.getHeight()); 56 | } 57 | bokeh_shader.deactivate();*/ 58 | 59 | 60 | vao = 0; 61 | } 62 | 63 | RenderStageBokeh::~RenderStageBokeh() 64 | { 65 | } 66 | 67 | void RenderStageBokeh::draw(OGLRenderStage *previous_stage) 68 | { 69 | RenderStageRefract* refract_stage = dynamic_cast(previous_stage); 70 | 71 | if (vao == 0) 72 | { 73 | glGenVertexArrays(1, &vao); 74 | glBindVertexArray(vao); 75 | glBindBuffer(GL_ARRAY_BUFFER, refract_stage->getBokehBuffer()); 76 | glEnableVertexAttribArray(0); 77 | glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void*)0); 78 | glBindVertexArray(0); 79 | } 80 | 81 | fbo.activate(); 82 | 83 | glEnable(GL_CULL_FACE); 84 | glBlendFunci(0,GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 85 | glBlendFunci(1, GL_ONE, GL_ONE); 86 | 87 | glEnable(GL_BLEND); 88 | glDisable(GL_DEPTH_TEST); 89 | glDisable(GL_SCISSOR_TEST); 90 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 91 | 92 | glClearColor(0, 0, 0, 1); 93 | glClear(GL_COLOR_BUFFER_BIT); 94 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); 95 | glFrontFace(GL_CCW); 96 | glActiveTexture(GL_TEXTURE0); 97 | glBindTexture(GL_TEXTURE_2D, source->getHandle()); 98 | 99 | glColorMaski(1, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 100 | trivial_shader.activate(); 101 | glBindVertexArray(vao_fs_quad); 102 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4,1); 103 | glBindVertexArray(0); 104 | trivial_shader.deactivate(); 105 | glColorMaski(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 106 | 107 | glActiveTexture(GL_TEXTURE0); 108 | glBindTexture(GL_TEXTURE_2D, refract_stage->getFBO()->getHandle()); 109 | 110 | 111 | if (use_billboard == true) 112 | { 113 | bokeh_billboard_shader.activate(); 114 | 115 | //if (focus_dirty == true) 116 | { 117 | computeFocus(); 118 | // focus_dirty = false; 119 | } 120 | 121 | glActiveTexture(GL_TEXTURE1); 122 | glBindTexture(GL_TEXTURE_2D, bokeh_billboard[current_billboard]); 123 | 124 | glUniform1f(screen_uniform, (float)fbo.getWidth() / fbo.getHeight()); 125 | glBindVertexArray(vao); 126 | glDrawArrays(GL_POINTS, 0, refract_stage->getBokehCount()); 127 | glBindVertexArray(0); 128 | 129 | bokeh_billboard_shader.deactivate(); 130 | } 131 | /*else { 132 | glFrontFace(GL_CW); 133 | 134 | bokeh_shader.activate(); 135 | 136 | // if (focus_dirty == true) 137 | { 138 | computeFocus(); 139 | // focus_dirty = false; 140 | } 141 | 142 | glUniform1f(screen_uniform, (float)fbo.getWidth() / fbo.getHeight()); 143 | bokeh_shader.debug_uniforms(); 144 | glBindVertexArray(vao); 145 | glDrawArrays(GL_POINTS, 0, refract_stage->getBokehCount()); 146 | glBindVertexArray(0); 147 | bokeh_shader.deactivate(); 148 | }*/ 149 | 150 | fbo.deactivate(); 151 | } 152 | 153 | void RenderStageBokeh::debugDisplay() 154 | { 155 | 156 | ImGui::Text("Parameters"); 157 | bool is_circle = current_billboard == Bokeh_Round; 158 | bool is_hex = current_billboard == Bokeh_Hex; 159 | 160 | if (ImGui::RadioButton("Circle", is_circle)) 161 | { 162 | current_billboard = Bokeh_Round; 163 | } 164 | if (ImGui::RadioButton("Hex", is_hex)) { 165 | current_billboard = Bokeh_Hex; 166 | } 167 | 168 | if (ImGui::SliderFloat("Focus", &focus, 0.125, 1)) 169 | { 170 | focus_dirty = true; 171 | } 172 | 173 | ImGui::SliderFloat("brightness", &brightness, 1, 100); 174 | 175 | ImGui::Separator(); 176 | if (ImGui::TreeNode("Shaders")) 177 | { 178 | ShowShaderUI(bokeh_billboard_shader); 179 | ImGui::TreePop(); 180 | } 181 | } 182 | 183 | void RenderStageBokeh::setBokehShape(BokehShape shape) 184 | { 185 | current_billboard = shape; 186 | } 187 | 188 | void RenderStageBokeh::setFocus(float _focus) 189 | { 190 | focus = std::clamp(_focus, 0.0f, 1.0f); 191 | focus_dirty = true; 192 | } 193 | 194 | 195 | void RenderStageBokeh::computeFocus() 196 | { 197 | auto bezier_lerp = [](float t, float p1, float p2, float p3, float p4)->float{ 198 | float u = 1.0f - t; 199 | float w1 = u * u*u; 200 | float w2 = 3 * u*u*t; 201 | float w3 = 3 * u*t*t; 202 | float w4 = t * t*t; 203 | return w1*p1 + w2 * p2 + w3 * p3 + w4 * p4; 204 | }; 205 | 206 | float norm_pixel = 1.f / (source->getWidth()); 207 | float size = norm_pixel + focus * (0.18f - norm_pixel);// 0.01f + focus * (0.18f - 0.01f); 208 | float radius = ((size * source->getWidth()))*0.4f; 209 | float area; 210 | 211 | switch (current_billboard) 212 | { 213 | case Bokeh_Hex: 214 | area = 6 * sqrt(3) / 4 * (radius*radius); 215 | break; 216 | case Bokeh_Round: 217 | default: 218 | area = (3.14159265359f*radius*radius); 219 | break; 220 | 221 | } 222 | float alpha_max = brightness / area; //0.005 + 0.01*(1-focus) + 0.904*exp(focus * -15.0f); 223 | alpha_max = std::clamp(alpha_max, 0.f, 1.f); 224 | 225 | float alpha_min = alpha_max * 0.8f;// 0.0025 + 0.996*exp(focus * -9.0f); 226 | alpha_min = std::clamp(alpha_min, 0.f, 1.f); 227 | 228 | 229 | // if (ImGui::Begin("Bokeh")) 230 | 231 | /*if (ImGui::Begin(name.c_str(), NULL, ImGuiWindowFlags_AlwaysAutoResize)) 232 | { 233 | ImGui::BeginChild("Config", ImVec2(400, fbo.getHeight()), true); 234 | { 235 | ImGui::Separator(); 236 | ImGui::Text("Focus vars"); 237 | ImGui::InputFloat("Normalized Size", &size, 0, 0, 5, ImGuiInputTextFlags_ReadOnly); 238 | ImGui::InputFloat("Pixel Radius", &radius, 0, 0, 5, ImGuiInputTextFlags_ReadOnly); 239 | ImGui::InputFloat("Pixel Area", &area, 0, 0, 5, ImGuiInputTextFlags_ReadOnly); 240 | ImGui::InputFloat("Alpha Min", &alpha_min, 0, 0, 5, ImGuiInputTextFlags_ReadOnly); 241 | ImGui::InputFloat("Alpha Max", &alpha_max, 0, 0, 5, ImGuiInputTextFlags_ReadOnly); 242 | } 243 | ImGui::EndChild(); 244 | } 245 | ImGui::End();*/ 246 | 247 | glUniform1f(u_size, size); 248 | glUniform1f(u_alpha_max, alpha_max); 249 | glUniform1f(u_alpha_min, alpha_min); 250 | } 251 | -------------------------------------------------------------------------------- /synthrain/RenderStageBokeh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLRenderStage.h" 3 | #include "OGLTexture.h" 4 | #include "OGLShader.h" 5 | 6 | enum BokehShape 7 | { 8 | Bokeh_Hex = 0, 9 | Bokeh_Round, 10 | Bokeh_Max 11 | }; 12 | 13 | class RenderStageBokeh: 14 | public OGLRenderStage 15 | { 16 | public: 17 | 18 | RenderStageBokeh(std::shared_ptr source); 19 | virtual ~RenderStageBokeh(); 20 | void draw(OGLRenderStage *previous_fbo); 21 | void debugDisplay(); 22 | void setBokehShape(BokehShape shape); 23 | void setFocus(float focus); 24 | 25 | 26 | private: 27 | void computeFocus(); 28 | 29 | OGLTexture bokeh_billboard[2]; 30 | BokehShape current_billboard; 31 | 32 | OGLShader trivial_shader; 33 | OGLShader bokeh_shader; 34 | OGLShader bokeh_billboard_shader; 35 | 36 | GLint screen_uniform; 37 | 38 | GLint u_size; 39 | GLint u_alpha_max; 40 | GLint u_alpha_min; 41 | 42 | GLuint vao; 43 | 44 | GLuint bokeh_ssbo; 45 | 46 | float focus; 47 | float brightness; 48 | bool focus_dirty; 49 | 50 | bool use_billboard; 51 | }; 52 | 53 | 54 | -------------------------------------------------------------------------------- /synthrain/RenderStageDrops.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderStageDrops.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "rng.h" 10 | #include "imgui/imgui.h" 11 | 12 | static const GLfloat vtx_buffer_data[] = { 13 | -0.5f, -0.5f, 14 | 0.5f, -0.5f, 15 | -0.5f, 0.5f, 16 | 0.5f, 0.5f, 17 | }; 18 | 19 | 20 | //first experiment 21 | //static const RenderStageDrops::drop_gen_params def = { 12,8,103,41,1,1 }; 22 | //second experiment 23 | static const RenderStageDrops::drop_gen_params def1 = { 15,1,20,0.25,1,1 }; 24 | static const RenderStageDrops::drop_gen_params def2 = { 400,1,6,0.5,1,1 }; 25 | 26 | RenderStageDrops::RenderStageDrops(std::shared_ptr source, std::shared_ptr flow_source) : 27 | OGLRenderStage(source, 1, "Raindrops"), raindrop("./shaders/drop.png"), drop_shader("./shaders/drop.vert", "./shaders/drop.frag"), /*adhesion(source->getWidth(),source->getHeight()),*/ flow(flow_source) 28 | { 29 | flow_multiplier = 1; 30 | num_drops = 0; 31 | scroll_drops = false; 32 | physics_frame = false; 33 | 34 | addDrops(def2); 35 | addDrops(def1); 36 | glGenVertexArrays(1, &vao); 37 | glBindVertexArray(vao); 38 | 39 | GLuint vtx_buffer; 40 | glGenBuffers(1, &vtx_buffer); 41 | glBindBuffer(GL_ARRAY_BUFFER, vtx_buffer); 42 | glBufferData(GL_ARRAY_BUFFER, sizeof(vtx_buffer_data), vtx_buffer_data, GL_STATIC_DRAW); 43 | glEnableVertexAttribArray(0); 44 | glVertexAttribDivisor(0, 0); //Always use the same set of data for channel 0 (vertices) 45 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 46 | 47 | glGenBuffers(1, &drop_xform); 48 | glBindBuffer(GL_ARRAY_BUFFER, drop_xform); 49 | glBufferData(GL_ARRAY_BUFFER, max_drops * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); 50 | glEnableVertexAttribArray(1); 51 | glVertexAttribDivisor(1, 1); //Use 1 set of data (position etc) per run of channel 0 52 | glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)0); 53 | 54 | glBindVertexArray(0); 55 | 56 | drop_shader.activate(); 57 | screen_uniform = glGetUniformLocation(drop_shader.getProgram(), "inv_half_screen_size"); 58 | glUniform2f(screen_uniform, 2.0f / fbo.getWidth() , 2.0f / fbo.getHeight()); 59 | drop_shader.deactivate(); 60 | } 61 | 62 | 63 | RenderStageDrops::~RenderStageDrops() 64 | { 65 | } 66 | 67 | void RenderStageDrops::draw(OGLRenderStage* previous_stage) 68 | { 69 | if (physics_frame) 70 | { 71 | std::uniform_real_distribution uni(0, 1.0); 72 | 73 | for (int i = 0; i < num_drops; ++i) 74 | { 75 | auto& x = drops[i].x; 76 | auto& y = drops[i].y; 77 | auto& xs = drops[i].sizex; 78 | auto& ys = drops[i].sizey; 79 | 80 | 81 | if (x - xs > this->source->getWidth() || x + xs < 0 || 82 | y - ys > this->source->getWidth() || y + ys < 0 ) 83 | { 84 | x = uni(RNG::mt) * this->source->getWidth(); 85 | y = uni(RNG::mt) * this->source->getHeight(); 86 | physic_drops.x[i] = drops[i].x; 87 | physic_drops.y[i] = drops[i].y; 88 | } 89 | } 90 | 91 | processFlow(); 92 | 93 | for (int i = 0; i < num_drops; ++i) 94 | { 95 | if (physic_drops.adhesion[i] <= 0) 96 | { 97 | fvector2 natural_direction{ (physic_drops.x[i] / source->getWidth()) - 0.5, -1 }; 98 | natural_direction.normalize(); 99 | 100 | float base_speed = std::min(physic_drops.mass[i] * flow_speed, 3.f); 101 | 102 | physic_drops.vx[i] = base_speed * (0.3f*(natural_direction.x) + 0.2f*flow_direction.x); 103 | physic_drops.vy[i] = base_speed * (0.3f*(natural_direction.y) - 0.2f*flow_direction.y); 104 | 105 | if (fvector2{ physic_drops.vx[i], physic_drops.vy[i] }.len() > 0.2f) 106 | { 107 | 108 | } 109 | 110 | physic_drops.x[i] += physic_drops.vx[i]; 111 | physic_drops.y[i] += physic_drops.vy[i]; 112 | } 113 | 114 | drops[i].x = physic_drops.x[i]; 115 | drops[i].y = physic_drops.y[i]; 116 | } 117 | } 118 | 119 | physics_frame = false; 120 | 121 | 122 | fbo.activate(); 123 | 124 | 125 | glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 126 | //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 127 | glEnable(GL_CULL_FACE); 128 | glFrontFace(GL_CCW); 129 | glEnable(GL_BLEND); 130 | glDisable(GL_DEPTH_TEST); 131 | glDisable(GL_SCISSOR_TEST); 132 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 133 | 134 | glClearColor(0, 0, 0, 0); 135 | glClear(GL_COLOR_BUFFER_BIT); 136 | 137 | if (num_drops > 0) 138 | { 139 | drop_shader.activate(); 140 | glUniform2f(screen_uniform, 2.0f / fbo.getWidth(), 2.0f / fbo.getHeight()); 141 | glBindBuffer(GL_ARRAY_BUFFER, drop_xform); 142 | glBufferData(GL_ARRAY_BUFFER, max_drops * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); // disown old buffer 143 | glBufferSubData(GL_ARRAY_BUFFER, 0, num_drops * sizeof(GLfloat) * 4, drops); 144 | 145 | glActiveTexture(GL_TEXTURE0); 146 | glBindTexture(GL_TEXTURE_2D, raindrop.getHandle()); 147 | //update buffers 148 | glBindVertexArray(vao); 149 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, num_drops); 150 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, num_drops); 151 | glBindVertexArray(0); 152 | 153 | drop_shader.deactivate(); 154 | } 155 | 156 | fbo.deactivate(); 157 | 158 | } 159 | 160 | 161 | 162 | void RenderStageDrops::debugDisplay() 163 | { 164 | 165 | static bool move_flow = true; 166 | 167 | 168 | ImGui::Text("Optical Flow Movement"); 169 | ImGui::Checkbox("flow enabled", &move_flow); 170 | 171 | 172 | if (move_flow && flow != nullptr) 173 | { 174 | auto flowdata = flow->getFlowData(); 175 | 176 | //ImGui::BeginChild("Flow"); 177 | ImGui::DragFloat("flow multiplier", &flow_multiplier, 0.01, 0, 100); 178 | 179 | ImDrawList* draw_list = ImGui::GetWindowDrawList(); 180 | 181 | ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 182 | ImVec2 canvas_size(96.0f, 96.0f); 183 | 184 | draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); 185 | draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255)); 186 | ImGui::InvisibleButton("canvas", canvas_size); 187 | 188 | draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.) 189 | 190 | for (int i = 0; i < flowdata.size(); i += 1) 191 | { 192 | int x = i % 3; 193 | int y = i / 3; 194 | ImVec2 center(canvas_pos.x + (x * 32) + 16, canvas_pos.y + (y * 32) + 16); 195 | ImVec2 direction(center); 196 | direction.x += flowdata[i].x; 197 | direction.y += flowdata[i].y; 198 | 199 | draw_list->AddLine(center, direction, IM_COL32(255, 255, 0, 255), 2.0f); 200 | } 201 | draw_list->PopClipRect(); 202 | 203 | ImGui::SameLine(); 204 | ImGui::BeginGroup(); 205 | ImGui::Columns(3); 206 | static bool selected[16] = { 0 }; 207 | for (int i = 0; i < flowdata.size(); i += 1) 208 | { 209 | if (ImGui::GetColumnIndex() == 0) ImGui::Separator(); 210 | ImGui::Text("%7.3f,%7.3f", flowdata[i].x, flowdata[i].y); 211 | ImGui::NextColumn(); 212 | } 213 | ImGui::Columns(1); 214 | ImGui::Separator(); 215 | ImGui::EndGroup(); 216 | 217 | if (flow_direction.y < 0) 218 | { 219 | ImGui::Text("BACKWARDS\n Speed: %f\nDirection: (%f,%f)", flow_speed, flow_direction.x, flow_direction.y); 220 | } 221 | else { 222 | ImGui::Text("FORWARDS\n Speed: %f\nDirection: (%f,%f)", flow_speed, flow_direction.x, flow_direction.y); 223 | } 224 | } 225 | 226 | } 227 | 228 | void RenderStageDrops::clearDrops() 229 | { 230 | num_drops = 0; 231 | } 232 | 233 | void RenderStageDrops::addDrops(drop_gen_params params) 234 | { 235 | std::uniform_real_distribution uni(0, 1.0); 236 | std::lognormal_distribution norm_size{ 1, params.size_dev }; 237 | std::normal_distribution norm_count{ 2, 0.7f*(float)params.count_deviation }; 238 | 239 | size_t new_drops = std::round((float)params.count_avg*norm_count(RNG::mt)); 240 | 241 | if (new_drops > 3*params.count_avg ) { 242 | new_drops = 3*params.count_avg; 243 | } 244 | 245 | if (new_drops + num_drops > max_drops)new_drops = max_drops - num_drops; 246 | 247 | for (int i = num_drops; i < num_drops+ new_drops; ++i) 248 | { 249 | drops[i].x = uni(RNG::mt) * this->source->getWidth(); 250 | drops[i].y = uni(RNG::mt) * this->source->getHeight(); 251 | drops[i].sizey = params.size_avg*norm_size(RNG::mt); 252 | drops[i].sizex = drops[i].sizey*0.8f + 0.2*uni(RNG::mt); 253 | 254 | physic_drops.x[i] = drops[i].x; 255 | physic_drops.y[i] = drops[i].y; 256 | physic_drops.vx[i] = 0; 257 | physic_drops.vy[i] = 0; 258 | physic_drops.adhesion[i] = 0; 259 | physic_drops.mass[i] = pow(drops[i].sizey/100.f, 2); 260 | } 261 | num_drops += new_drops; 262 | } 263 | 264 | 265 | void RenderStageDrops::tickPhysics() 266 | { 267 | physics_frame = true; 268 | } 269 | 270 | void RenderStageDrops::processFlow() 271 | { 272 | auto flowdata = flow->getFlowData(); 273 | 274 | int usable_samples = 0; 275 | 276 | for (auto& vec : flowdata) 277 | { 278 | if (vec.lenSq() < 4 * 4) 279 | { 280 | vec = fvector2{ 0 }; 281 | } 282 | else { 283 | ++usable_samples; 284 | } 285 | } 286 | 287 | // could dot the vectors used with speeds against the direction of their quadrant 288 | // maybe better for determining forward and/or backward motion 289 | std::vector speeds; 290 | std::transform(flowdata.begin(), flowdata.end(), std::back_inserter(speeds), 291 | [](fvector2 v) -> float { return v.len(); }); 292 | 293 | /* if (usable_samples > 0) 294 | { 295 | float avgmag = std::accumulate(speeds.begin(), speeds.end(), 0) / usable_samples; 296 | 297 | for (auto& vec : flowdata) 298 | { 299 | if (vec.lenSq() > avgmag2*avgmag2 * 3) 300 | { 301 | vec = fvector2{ 0 }; 302 | --usable_samples; 303 | } 304 | } 305 | 306 | if (usable_samples > 0) 307 | { 308 | avg = std::accumulate(flowdata.begin(), flowdata.end(), fvector2{ 0 }) / usable_samples; 309 | } 310 | else { 311 | avg = fvector2{ 0 }; 312 | } 313 | }*/ 314 | 315 | 316 | flow_speed = usable_samples > 0 ? flow_multiplier*std::accumulate(speeds.begin(), speeds.end(), 0) / usable_samples : 0; 317 | fvector2 bottom_avg{ 0 }; 318 | 319 | for (int i = 6; i < 9; ++i) if (speeds[i] > 0) bottom_avg += (flowdata[i] / speeds[i]); 320 | 321 | flow_direction = bottom_avg.len() > 0 ? bottom_avg / 3 : fvector2{ 0 }; 322 | } 323 | -------------------------------------------------------------------------------- /synthrain/RenderStageDrops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLRenderStage.h" 3 | #include "OGLFloatTexture.h" 4 | #include "FlowData.h" 5 | #include "OGLTexture.h" 6 | #include "OGLShader.h" 7 | #include "OGLShader.h" 8 | #include 9 | 10 | class RenderStageDrops : 11 | public OGLRenderStage 12 | { 13 | public: 14 | 15 | struct drop_gen_params 16 | { 17 | int count_avg; 18 | float count_deviation; 19 | float size_avg; 20 | float size_dev; 21 | float gather_strength; 22 | float gather_iterations; 23 | }; 24 | 25 | RenderStageDrops(std::shared_ptr source, std::shared_ptr flow_source); 26 | virtual ~RenderStageDrops(); 27 | void draw(OGLRenderStage* previous_stage); 28 | void debugDisplay(); 29 | void clearDrops(); 30 | void addDrops(drop_gen_params params); 31 | void tickPhysics(); 32 | 33 | private: 34 | 35 | void processFlow(); 36 | 37 | float flow_speed; 38 | fvector2 flow_direction; 39 | 40 | static const int max_drops = 5000; 41 | 42 | bool scroll_drops; 43 | 44 | struct DropData 45 | { 46 | GLfloat x; 47 | GLfloat y; 48 | GLfloat sizex; 49 | GLfloat sizey; 50 | }drops[max_drops]; 51 | 52 | struct DropPhysicsData 53 | { 54 | float x[max_drops]; 55 | float y[max_drops]; 56 | float vx[max_drops]; 57 | float vy[max_drops]; 58 | float mass[max_drops]; 59 | float adhesion[max_drops]; 60 | }physic_drops; 61 | 62 | size_t num_drops; 63 | float flow_multiplier; 64 | std::shared_ptr flow; 65 | OGLTexture raindrop; 66 | //OGLTexture adhesion; 67 | 68 | GLint screen_uniform; 69 | GLuint vao; 70 | GLuint drop_xform; 71 | OGLShader drop_shader; 72 | bool physics_frame; 73 | //OGLShader noise_shader; 74 | }; 75 | -------------------------------------------------------------------------------- /synthrain/RenderStageFog.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderStageFog.h" 2 | #include "imgui/imgui.h" 3 | #include 4 | #include "rng.h" 5 | 6 | static const GLfloat fs_vtx_buffer_data[] = { 7 | 0.f, 0.f, 8 | 1.f, 0.f, 9 | 0.f, 1.f, 10 | 1.f, 1.f, 11 | }; 12 | 13 | RenderStageFog::RenderStageFog(std::shared_ptr source, std::shared_ptr depth_source) : 14 | OGLRenderStage(source, 1, "Fog"), 15 | depth(depth_source), 16 | blur_buffer(source->getWidth(), source->getHeight(), "blur buffer"), 17 | blur_shader("./shaders/basic.vert", "./shaders/blur.frag"), 18 | scatter_shader("./shaders/basic.vert", "./shaders/scatter.frag"), 19 | fog_shader("./shaders/basic.vert", "./shaders/fog.frag"), 20 | max_blur_radius(3.3f), 21 | fog_near(0.063), 22 | fog_far(0.000), 23 | density(0.23f), 24 | scattering(0.53), 25 | fog_color{0.8f,0.8f,0.8f} 26 | { 27 | // fbo.addDepthBuffer(depth_source); 28 | 29 | depth_blur_buffer.initializeWithFloat(source->getWidth(), source->getHeight(), "depth buffer"); 30 | 31 | shaders_dirty = true; 32 | 33 | glGenVertexArrays(1, &bg_vao); 34 | glBindVertexArray(bg_vao); 35 | GLuint vtx_buffer; 36 | glGenBuffers(1, &vtx_buffer); 37 | glBindBuffer(GL_ARRAY_BUFFER, vtx_buffer); 38 | glBufferData(GL_ARRAY_BUFFER, sizeof(fs_vtx_buffer_data), fs_vtx_buffer_data, GL_STATIC_DRAW); 39 | glEnableVertexAttribArray(0); 40 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 41 | glBindVertexArray(0); 42 | 43 | 44 | u_blur_direction = glGetUniformLocation(blur_shader.getProgram(), "direction"); 45 | 46 | u_fog_radius = glGetUniformLocation(scatter_shader.getProgram(), "fog_max"); 47 | u_scatter_direction = glGetUniformLocation(scatter_shader.getProgram(), "direction"); 48 | u_res = glGetUniformLocation(scatter_shader.getProgram(), "resolution"); 49 | 50 | u_alpha = glGetUniformLocation(fog_shader.getProgram(), "alpha"); 51 | u_fog_color = glGetUniformLocation(fog_shader.getProgram(), "fog_color"); 52 | 53 | u_density[0] = glGetUniformLocation(fog_shader.getProgram(), "density"); 54 | u_density[1] = glGetUniformLocation(scatter_shader.getProgram(), "density"); 55 | 56 | u_fog_near[0] = glGetUniformLocation(fog_shader.getProgram(), "near_fog_plane"); 57 | u_fog_near[1] = glGetUniformLocation(scatter_shader.getProgram(), "near_fog_plane"); 58 | 59 | u_fog_far[0] = glGetUniformLocation(fog_shader.getProgram(), "far_fog_plane"); 60 | u_fog_far[1] = glGetUniformLocation(scatter_shader.getProgram(), "far_fog_plane"); 61 | 62 | scatter_shader.activate(); 63 | glUniform2f(u_res, fbo.getWidth(), fbo.getHeight()); 64 | scatter_shader.deactivate(); 65 | } 66 | 67 | RenderStageFog::~RenderStageFog() 68 | { 69 | } 70 | 71 | void RenderStageFog::draw(OGLRenderStage * previous_fbo) 72 | { 73 | OGLFrameBuffer* read_fbo = &blur_buffer; 74 | OGLFrameBuffer* write_fbo = &fbo; 75 | GLuint read_tex = source->getHandle(); 76 | 77 | 78 | glEnable(GL_CULL_FACE); 79 | glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 80 | glDisable(GL_BLEND); 81 | glDisable(GL_DEPTH_TEST); 82 | glDisable(GL_SCISSOR_TEST); 83 | glFrontFace(GL_CCW); 84 | 85 | glActiveTexture(GL_TEXTURE0); 86 | glBindTexture(GL_TEXTURE_2D, depth->getHandle()); 87 | 88 | glBindVertexArray(vao_fs_quad); 89 | 90 | blur_shader.activate(); 91 | depth_blur_buffer.activate(); 92 | glUniform2f(u_blur_direction, 1.f, 0.f); 93 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); 94 | glUniform2f(u_blur_direction, 0.f, 1.f); 95 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); 96 | depth_blur_buffer.deactivate(); 97 | blur_shader.deactivate(); 98 | 99 | 100 | glActiveTexture(GL_TEXTURE1); 101 | //glBindTexture(GL_TEXTURE_2D, depth->getHandle()); 102 | glBindTexture(GL_TEXTURE_2D, depth_blur_buffer.getHandle()); 103 | glActiveTexture(GL_TEXTURE0); 104 | 105 | // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); 106 | 107 | 108 | 109 | 110 | scatter_shader.activate(); 111 | 112 | if (shaders_dirty) 113 | { 114 | glUniform1f(u_density[1], density); 115 | glUniform1f(u_fog_near[1], fog_near); 116 | glUniform1f(u_fog_far[1], fog_far); 117 | } 118 | 119 | int iterations = 6; 120 | float radius_scale = 1.f/iterations; 121 | 122 | for (int i = 0; i < iterations; ++i) 123 | { 124 | write_fbo->activate(); 125 | 126 | glBindTexture(GL_TEXTURE_2D, read_tex); 127 | 128 | 129 | if (i % 2 == 0) 130 | { 131 | glUniform2f(u_scatter_direction, 0, (iterations - i)*max_blur_radius*radius_scale); 132 | } 133 | else { 134 | glUniform2f(u_scatter_direction, (iterations - i)*max_blur_radius*radius_scale,0); 135 | } 136 | 137 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); 138 | 139 | write_fbo->deactivate(); 140 | 141 | std::swap(read_fbo, write_fbo); 142 | read_tex = read_fbo->getHandle(); 143 | } 144 | 145 | scatter_shader.deactivate(); 146 | 147 | glActiveTexture(GL_TEXTURE2); 148 | glBindTexture(GL_TEXTURE_2D, blur_buffer.getHandle()); 149 | 150 | glActiveTexture(GL_TEXTURE0); 151 | glBindTexture(GL_TEXTURE_2D, source->getHandle()); 152 | 153 | fbo.activate(); 154 | fog_shader.activate(); 155 | 156 | if (shaders_dirty) 157 | { 158 | glUniform1f(u_density[0], density); 159 | glUniform1f(u_fog_near[0], fog_near); 160 | glUniform1f(u_fog_far[0], fog_far); 161 | glUniform1f(u_alpha, 1 - scattering); 162 | glUniform3f(u_fog_color, fog_color[0], fog_color[1], fog_color[2]); 163 | shaders_dirty = false; 164 | } 165 | 166 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); 167 | fog_shader.deactivate(); 168 | fbo.deactivate(); 169 | 170 | glBindVertexArray(0); 171 | 172 | 173 | } 174 | 175 | void RenderStageFog::debugDisplay() 176 | { 177 | ImGui::Text("Parameters"); 178 | 179 | 180 | if (ImGui::Button("Randomize")) { 181 | randomizeParameters(); 182 | shaders_dirty = true; 183 | } 184 | 185 | ImGui::Separator(); 186 | 187 | ImGui::DragFloat("Max Blur Radius", &max_blur_radius, 0.1f, 0.f, 30.f); 188 | 189 | if (ImGui::SliderFloat("Density", &density, 0.f, 1.f)) { 190 | shaders_dirty = true; 191 | } 192 | 193 | if (ImGui::SliderFloat("Scattering", &scattering, 0.f, 1.f)) { 194 | shaders_dirty = true; 195 | } 196 | 197 | if (ImGui::SliderFloat("Fog near cutoff", &fog_near, 0.f, 0.1f)) { 198 | shaders_dirty = true; 199 | } 200 | 201 | if (ImGui::SliderFloat("Fog far cutoff", &fog_far, 0.f, 0.1f)) { 202 | shaders_dirty = true; 203 | } 204 | 205 | if (ImGui::ColorEdit3("Fog Color", fog_color)) 206 | { 207 | shaders_dirty = true; 208 | } 209 | 210 | ImGui::Separator(); 211 | 212 | if (ImGui::TreeNode("Shaders")) 213 | { 214 | ShowShaderUI(fog_shader); 215 | ShowShaderUI(scatter_shader); 216 | ShowShaderUI(blur_shader); 217 | ImGui::TreePop(); 218 | } 219 | } 220 | 221 | void RenderStageFog::randomizeParameters() 222 | { 223 | static std::uniform_real_distribution rng_fog_far(0.000f, 0.017f); 224 | static std::uniform_real_distribution rng_fog_near(0.f, 0.0800f); 225 | static std::uniform_real_distribution rng_density(0.1f, 1.000f); 226 | static std::uniform_real_distribution rng_scattering(0.0f, 1.00f); 227 | static std::uniform_real_distribution rng_blur(0.0f, 8.00f); 228 | static std::uniform_real_distribution rng_color_balance(-0.05, 0.05f); 229 | 230 | 231 | //fog_far = rng_fog_far(RNG::mt); 232 | fog_near = fog_far + 0.02f + rng_fog_near(RNG::mt); 233 | 234 | 235 | 236 | density = rng_density(RNG::mt); 237 | scattering = rng_scattering(RNG::mt); 238 | max_blur_radius = rng_blur(RNG::mt); 239 | 240 | float balance = rng_color_balance(RNG::mt); 241 | fog_color[0] = 0.84 - balance; 242 | fog_color[1] = 0.84 - balance; 243 | fog_color[2] = 0.84 + balance; 244 | shaders_dirty = true; 245 | } 246 | -------------------------------------------------------------------------------- /synthrain/RenderStageFog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLRenderStage.h" 3 | #include "OGLShader.h" 4 | #include "OGLTexture.h" 5 | #include "OGLFloatTexture.h" 6 | 7 | 8 | class RenderStageFog : 9 | public OGLRenderStage 10 | { 11 | public: 12 | RenderStageFog(std::shared_ptr source, std::shared_ptr depth_source); 13 | virtual ~RenderStageFog(); 14 | 15 | void draw(OGLRenderStage *previous_fbo); 16 | void debugDisplay(); 17 | void randomizeParameters(); 18 | 19 | private: 20 | 21 | std::shared_ptr depth; 22 | 23 | OGLFrameBuffer blur_buffer; 24 | OGLFrameBuffer depth_blur_buffer; 25 | 26 | OGLShader scatter_shader; 27 | OGLShader blur_shader; 28 | OGLShader fog_shader; 29 | 30 | float fog_near; 31 | float fog_far; 32 | float density; 33 | float scattering; 34 | float fog_color[3]; 35 | 36 | GLint u_density[2]; 37 | GLint u_fog_near[2]; 38 | GLint u_fog_far[2]; 39 | GLint u_alpha; 40 | GLint u_fog_color; 41 | 42 | GLint u_fog_radius; 43 | GLint u_blur_direction; 44 | GLint u_scatter_direction; 45 | GLint u_res; 46 | 47 | GLuint bg_vao; 48 | 49 | float max_blur_radius; 50 | 51 | 52 | bool shaders_dirty; 53 | }; 54 | 55 | -------------------------------------------------------------------------------- /synthrain/RenderStageMaxPool.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderStageMaxPool.h" 2 | #include 3 | #include 4 | #include 5 | #include "imgui/imgui.h" 6 | 7 | static const GLfloat vtx_buffer_data[] = { 8 | 0.f, 0.f, 9 | 1.f, 0.f, 10 | 0.f, 1.f, 11 | 1.f, 1.f, 12 | }; 13 | 14 | 15 | RenderStageMaxPool::RenderStageMaxPool(std::shared_ptr source) : OGLRenderStage(source, 4, "maxpool"), 16 | pool_shader("./shaders/basic.vert", "./shaders/pool.frag") 17 | { 18 | glGenVertexArrays(1, &vao); 19 | glBindVertexArray(vao); 20 | 21 | GLuint vtx_buffer; 22 | glGenBuffers(1, &vtx_buffer); 23 | glBindBuffer(GL_ARRAY_BUFFER, vtx_buffer); 24 | glBufferData(GL_ARRAY_BUFFER, sizeof(vtx_buffer_data), vtx_buffer_data, GL_STATIC_DRAW); 25 | glEnableVertexAttribArray(0); 26 | glVertexAttribDivisor(0, 0); //Always use the same set of data for channel 0 (vertices) 27 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 28 | glBindVertexArray(0); 29 | 30 | pool_shader.activate(); 31 | GLint tex_uniform = glGetUniformLocation(pool_shader.getProgram(), "tex"); 32 | glUniform1i(tex_uniform, 0); 33 | pool_shader.deactivate(); 34 | 35 | 36 | } 37 | 38 | 39 | RenderStageMaxPool::~RenderStageMaxPool() 40 | { 41 | } 42 | 43 | void RenderStageMaxPool::draw(OGLRenderStage *previous_stage) 44 | { 45 | fbo.activate(); 46 | 47 | 48 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 49 | glEnable(GL_CULL_FACE); 50 | glFrontFace(GL_CCW); 51 | glDisable(GL_BLEND); 52 | glDisable(GL_DEPTH_TEST); 53 | glDisable(GL_SCISSOR_TEST); 54 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 55 | glClearColor(0, 0, 0, 0); 56 | glClear(GL_COLOR_BUFFER_BIT); 57 | 58 | 59 | glActiveTexture(GL_TEXTURE0); 60 | //glBindTexture(GL_TEXTURE_2D, background.getHandle()); 61 | 62 | 63 | 64 | pool_shader.activate(); 65 | pool_shader.debug_uniforms(); 66 | glBindVertexArray(vao); 67 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); 68 | glBindVertexArray(0); 69 | pool_shader.deactivate(); 70 | 71 | 72 | fbo.deactivate(); 73 | } 74 | 75 | void RenderStageMaxPool::debugDisplay() 76 | { 77 | fbo.debugDraw(); 78 | } 79 | -------------------------------------------------------------------------------- /synthrain/RenderStageMaxPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLRenderStage.h" 3 | #include "OGLTexture.h" 4 | #include "OGLShader.h" 5 | 6 | class RenderStageMaxPool : 7 | public OGLRenderStage 8 | { 9 | public: 10 | RenderStageMaxPool(std::shared_ptr source); 11 | virtual ~RenderStageMaxPool(); 12 | void draw(OGLRenderStage *previous_fbo); 13 | void debugDisplay(); 14 | 15 | private: 16 | GLuint vao; 17 | GLuint u_input_size; 18 | GLuint input_size; 19 | OGLShader pool_shader; 20 | }; 21 | 22 | 23 | -------------------------------------------------------------------------------- /synthrain/RenderStageRefract.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderStageRefract.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "imgui/imgui.h" 7 | 8 | static const GLfloat vtx_buffer_data[] = { 9 | 0.f, 0.f, 10 | 1.f, 0.f, 11 | 0.f, 1.f, 12 | 1.f, 1.f, 13 | }; 14 | 15 | #ifndef NO_CUDA 16 | extern "C" void sort_pixels(size_t num_pixels); 17 | extern "C" void register_buffer(GLuint buffer); 18 | #endif 19 | 20 | RenderStageRefract::RenderStageRefract(std::shared_ptr source) : OGLRenderStage(source, 1, "Refract"), refract_shader("./shaders/basic.vert", "./shaders/refract.frag"), bokeh_data{ 0 } 21 | { 22 | glGenVertexArrays(1, &vao); 23 | glBindVertexArray(vao); 24 | 25 | GLuint vtx_buffer; 26 | glGenBuffers(1, &vtx_buffer); 27 | glBindBuffer(GL_ARRAY_BUFFER, vtx_buffer); 28 | glBufferData(GL_ARRAY_BUFFER, sizeof(vtx_buffer_data), vtx_buffer_data, GL_STATIC_DRAW); 29 | glEnableVertexAttribArray(0); 30 | glVertexAttribDivisor(0, 0); //Always use the same set of data for channel 0 (vertices) 31 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); 32 | glBindVertexArray(0); 33 | 34 | refract_shader.activate(); 35 | GLint tex_uniform = glGetUniformLocation(refract_shader.getProgram(), "bg_tex"); 36 | glUniform1i(tex_uniform, 0); 37 | tex_uniform = glGetUniformLocation(refract_shader.getProgram(), "bg_blur_tex"); 38 | glUniform1i(tex_uniform, 1); 39 | tex_uniform = glGetUniformLocation(refract_shader.getProgram(), "drop_tex"); 40 | glUniform1i(tex_uniform, 2); 41 | /*GLint screen_uniform = glGetUniformLocation(drop_shader.getProgram(), "inv_half_screen_size"); 42 | glUniform2f(screen_uniform, 2.0f / width , 2.0f / height );*/ 43 | refract_shader.deactivate(); 44 | 45 | glGenBuffers(1, &bokeh_ssbo); 46 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, bokeh_ssbo); 47 | glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(bokeh_data), bokeh_data, GL_DYNAMIC_DRAW); 48 | glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, bokeh_ssbo); 49 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 50 | 51 | GLuint counter = 0; 52 | glGenBuffers(1, &bokeh_counter); 53 | glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, bokeh_counter); 54 | glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, bokeh_counter); 55 | 56 | GLuint buffer_flags = GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; 57 | glBufferStorage(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), &counter, buffer_flags); 58 | 59 | // force cast to unsigned int pointer because I know that it is a buffer of unsigned integers 60 | void* counter_pointer = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), buffer_flags); 61 | assert(counter_pointer != nullptr); 62 | counter_value = static_cast(counter_pointer); 63 | *counter_value = 0; 64 | 65 | glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); 66 | 67 | 68 | #ifndef NO_CUDA 69 | register_buffer(bokeh_ssbo); 70 | #endif 71 | } 72 | 73 | 74 | RenderStageRefract::~RenderStageRefract() 75 | { 76 | glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 77 | glDeleteBuffers(1, &bokeh_counter); 78 | glDeleteBuffers(1, &bokeh_ssbo); 79 | } 80 | 81 | void RenderStageRefract::draw(OGLRenderStage *previous_stage) 82 | { 83 | num_bokeh = 0; 84 | 85 | fbo.activate(); 86 | 87 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 88 | glEnable(GL_CULL_FACE); 89 | glFrontFace(GL_CCW); 90 | glDisable(GL_BLEND); 91 | glDisable(GL_DEPTH_TEST); 92 | glDisable(GL_SCISSOR_TEST); 93 | glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 94 | glClearColor(0, 0, 0, 0); 95 | glClear(GL_COLOR_BUFFER_BIT); 96 | 97 | 98 | glActiveTexture(GL_TEXTURE0); 99 | glBindTexture(GL_TEXTURE_2D, source->getHandle()); 100 | 101 | glActiveTexture(GL_TEXTURE2); 102 | glBindTexture(GL_TEXTURE_2D, previous_stage->getFBO()->getHandle()); 103 | 104 | glBindBuffer(GL_SHADER_STORAGE_BUFFER, bokeh_ssbo); 105 | glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, bokeh_counter); 106 | 107 | { 108 | // Equavlient to: 109 | // glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &num_bokeh); 110 | // without copying from CPU to GPU 111 | 112 | GLuint zero = 0; 113 | glInvalidateBufferData(bokeh_counter); 114 | glClearBufferData(GL_ATOMIC_COUNTER_BUFFER, GL_R32UI, GL_RED, GL_UNSIGNED_INT, &zero); 115 | } 116 | 117 | 118 | refract_shader.activate(); 119 | glBindVertexArray(vao); 120 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1); 121 | glBindVertexArray(0); 122 | refract_shader.deactivate(); 123 | 124 | 125 | //Copy the number of bokeh slient side and read in locally 126 | /*glBindBuffer(GL_COPY_READ_BUFFER, bokeh_counter); 127 | glBindBuffer(GL_COPY_WRITE_BUFFER, bokeh_counter_local); 128 | glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(GLuint)); 129 | glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, bokeh_counter_local); 130 | glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &num_bokeh);*/ 131 | 132 | num_bokeh = std::clamp(*counter_value, 0U, MAX_BOKEH); 133 | 134 | #ifdef NO_CUDA 135 | glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(bokeh_data), &bokeh_data); 136 | std::sort(bokeh_data, bokeh_data + num_bokeh); 137 | glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(bokeh_data), bokeh_data); 138 | #else 139 | sort_pixels(num_bokeh); 140 | #endif 141 | 142 | fbo.deactivate(); 143 | } 144 | 145 | GLuint RenderStageRefract::getBokehCount() 146 | { 147 | return num_bokeh; 148 | } 149 | 150 | GLuint RenderStageRefract::getBokehBuffer() 151 | { 152 | return bokeh_ssbo; 153 | } 154 | 155 | void RenderStageRefract::debugDisplay() 156 | { 157 | if (ImGui::TreeNode("Shaders")) 158 | { 159 | ShowShaderUI(refract_shader) 160 | ImGui::TreePop(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /synthrain/RenderStageRefract.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "OGLRenderStage.h" 3 | #include "OGLTexture.h" 4 | #include "OGLShader.h" 5 | 6 | #define MAX_BOKEH (256000U) 7 | 8 | class RenderStageRefract : 9 | public OGLRenderStage 10 | { 11 | public: 12 | RenderStageRefract(std::shared_ptr source); 13 | virtual ~RenderStageRefract(); 14 | void draw(OGLRenderStage *previous_fbo); 15 | void debugDisplay(); 16 | GLuint getBokehCount(); 17 | GLuint getBokehBuffer(); 18 | 19 | 20 | private: 21 | GLuint vao; 22 | OGLShader refract_shader; 23 | 24 | GLuint bokeh_ssbo; 25 | GLuint bokeh_counter; 26 | unsigned int* counter_value; 27 | 28 | GLuint num_bokeh; 29 | 30 | GLuint u_alphaMultiply; 31 | GLuint u_alphaSubtract; 32 | GLuint u_minRefraction; 33 | GLuint u_refractionDelta; 34 | 35 | struct bokeh 36 | { 37 | float x; 38 | float y; 39 | float l; 40 | float u; 41 | bool operator<(bokeh &other) 42 | { 43 | return l < other.l; 44 | } 45 | }bokeh_data[MAX_BOKEH]; 46 | 47 | }; 48 | 49 | 50 | -------------------------------------------------------------------------------- /synthrain/cmake/FindFFmpeg.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil) 2 | # Once done this will define 3 | # 4 | # FFMPEG_FOUND - system has ffmpeg or libav 5 | # FFMPEG_INCLUDE_DIR - the ffmpeg include directory 6 | # FFMPEG_LIBRARIES - Link these to use ffmpeg 7 | # FFMPEG_LIBAVCODEC 8 | # FFMPEG_LIBAVFORMAT 9 | # FFMPEG_LIBAVUTIL 10 | # 11 | # Copyright (c) 2008 Andreas Schneider 12 | # Modified for other libraries by Lasse Kärkkäinen 13 | # Modified for Hedgewars by Stepik777 14 | # Modified for FFmpeg-example Tuukka Pasanen 2018 15 | # 16 | # Redistribution and use is allowed according to the terms of the New 17 | # BSD license. 18 | # 19 | 20 | include(FindPackageHandleStandardArgs) 21 | 22 | find_package_handle_standard_args(FFMPEG 23 | FOUND_VAR FFMPEG_FOUND 24 | REQUIRED_VARS 25 | FFMPEG_LIBRARY 26 | FFMPEG_INCLUDE_DIR 27 | VERSION_VAR FFMPEG_VERSION 28 | ) 29 | 30 | if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) 31 | # in cache already 32 | set(FFMPEG_FOUND TRUE) 33 | else() 34 | # use pkg-config to get the directories and then use these values 35 | # in the FIND_PATH() and FIND_LIBRARY() calls 36 | find_package(PkgConfig) 37 | if(PKG_CONFIG_FOUND) 38 | pkg_check_modules(_FFMPEG_AVCODEC libavcodec) 39 | pkg_check_modules(_FFMPEG_AVFORMAT libavformat) 40 | pkg_check_modules(_FFMPEG_AVUTIL libavutil) 41 | endif() 42 | 43 | find_path(FFMPEG_AVCODEC_INCLUDE_DIR 44 | NAMES libavcodec/avcodec.h 45 | PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS} 46 | /usr/include 47 | /usr/local/include 48 | /opt/local/include 49 | /sw/include 50 | PATH_SUFFIXES ffmpeg libav) 51 | 52 | find_library(FFMPEG_LIBAVCODEC 53 | NAMES avcodec 54 | PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS} 55 | /usr/lib 56 | /usr/local/lib 57 | /opt/local/lib 58 | /sw/lib) 59 | 60 | find_library(FFMPEG_LIBAVFORMAT 61 | NAMES avformat 62 | PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS} 63 | /usr/lib 64 | /usr/local/lib 65 | /opt/local/lib 66 | /sw/lib) 67 | 68 | find_library(FFMPEG_LIBAVUTIL 69 | NAMES avutil 70 | PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS} 71 | /usr/lib 72 | /usr/local/lib 73 | /opt/local/lib 74 | /sw/lib) 75 | 76 | if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT) 77 | set(FFMPEG_FOUND TRUE) 78 | endif() 79 | 80 | if(FFMPEG_FOUND) 81 | set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR}) 82 | set(FFMPEG_LIBRARIES 83 | ${FFMPEG_LIBAVCODEC} 84 | ${FFMPEG_LIBAVFORMAT} 85 | ${FFMPEG_LIBAVUTIL}) 86 | endif() 87 | 88 | if(FFMPEG_FOUND) 89 | if(NOT FFMPEG_FIND_QUIETLY) 90 | message(STATUS 91 | "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}") 92 | endif() 93 | else() 94 | if(FFMPEG_FIND_REQUIRED) 95 | message(FATAL_ERROR 96 | "Could not find libavcodec or libavformat or libavutil") 97 | endif() 98 | endif() 99 | endif() 100 | -------------------------------------------------------------------------------- /synthrain/cmake/FindSDL2_image.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #.rst: 5 | # FindSDL2_image 6 | # ------------- 7 | # 8 | # Locate SDL2_image library 9 | # 10 | # This module defines: 11 | # 12 | # :: 13 | # 14 | # SDL2_IMAGE_LIBRARIES, the name of the library to link against 15 | # SDL2_IMAGE_INCLUDE_DIRS, where to find the headers 16 | # SDL2_IMAGE_FOUND, if false, do not try to link against 17 | # SDL2_IMAGE_VERSION_STRING - human-readable string containing the 18 | # version of SDL_image 19 | # 20 | # 21 | # 22 | # For backward compatibility the following variables are also set: 23 | # 24 | # :: 25 | # 26 | # SDL2IMAGE_LIBRARY (same value as SDL_IMAGE_LIBRARIES) 27 | # SDL2IMAGE_INCLUDE_DIR (same value as SDL_IMAGE_INCLUDE_DIRS) 28 | # SDL2IMAGE_FOUND (same value as SDL_IMAGE_FOUND) 29 | # 30 | # 31 | # 32 | # $SDL2DIR is an environment variable that would correspond to the 33 | # ./configure --prefix=$SDL2DIR used in building SDL. 34 | # 35 | # Created by Eric Wing. This was influenced by the FindSDL.cmake 36 | # module, but with modifications to recognize OS X frameworks and 37 | # additional Unix paths (FreeBSD, etc). 38 | 39 | if(NOT SDL2_IMAGE_INCLUDE_DIR AND SDL2IMAGE_INCLUDE_DIR) 40 | set(SDL2_IMAGE_INCLUDE_DIR ${SDL2IMAGE_INCLUDE_DIR} CACHE PATH "directory cache entry initialized from old variable name") 41 | endif() 42 | find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h 43 | HINTS 44 | ENV SDL2IMAGEDIR 45 | ENV SDL2DIR 46 | ${SDL2_DIR} 47 | PATH_SUFFIXES SDL2 48 | # path suffixes to search inside ENV{SDL2DIR} 49 | include/SDL2 include 50 | ) 51 | 52 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 53 | set(VC_LIB_PATH_SUFFIX lib/x64) 54 | else() 55 | set(VC_LIB_PATH_SUFFIX lib/x86) 56 | endif() 57 | 58 | if(NOT SDL2_IMAGE_LIBRARY AND SDL2IMAGE_LIBRARY) 59 | set(SDL2_IMAGE_LIBRARY ${SDL2IMAGE_LIBRARY} CACHE FILEPATH "file cache entry initialized from old variable name") 60 | endif() 61 | find_library(SDL2_IMAGE_LIBRARY 62 | NAMES SDL2_image 63 | HINTS 64 | ENV SDL2IMAGEDIR 65 | ENV SDL2DIR 66 | ${SDL2_DIR} 67 | PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} 68 | ) 69 | 70 | if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h") 71 | file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$") 72 | file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$") 73 | file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$") 74 | string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL_IMAGE_VERSION_MAJOR_LINE}") 75 | string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL_IMAGE_VERSION_MINOR_LINE}") 76 | string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL_IMAGE_VERSION_PATCH_LINE}") 77 | set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH}) 78 | unset(SDL2_IMAGE_VERSION_MAJOR_LINE) 79 | unset(SDL2_IMAGE_VERSION_MINOR_LINE) 80 | unset(SDL2_IMAGE_VERSION_PATCH_LINE) 81 | unset(SDL2_IMAGE_VERSION_MAJOR) 82 | unset(SDL2_IMAGE_VERSION_MINOR) 83 | unset(SDL2_IMAGE_VERSION_PATCH) 84 | endif() 85 | 86 | set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY}) 87 | set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR}) 88 | 89 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image 90 | REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS 91 | VERSION_VAR SDL2_IMAGE_VERSION_STRING) 92 | 93 | # for backward compatibility 94 | set(SDL2IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES}) 95 | set(SDL2IMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS}) 96 | set(SDL2IMAGE_FOUND ${SDL2_IMAGE_FOUND}) 97 | 98 | mark_as_advanced(SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR) 99 | -------------------------------------------------------------------------------- /synthrain/cmake/FindSWScale.cmake: -------------------------------------------------------------------------------- 1 | # Locate libswscale (part of ffmpeg) 2 | # 3 | # SWSCALE_FOUND - system has swscale 4 | # SWSCALE_INCLUDE_DIR - the swscale include directory 5 | # SWSCALE_LIBRARIES - the libraries needed to use swscale 6 | # SWSCALE_DEFINITIONS - Compiler switches required for using swscale 7 | 8 | # Copyright (c) 2010, Maciej Mrozowski 9 | # 10 | # Redistribution and use is allowed according to the terms of the BSD license. 11 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 12 | 13 | include(FindPackageHandleStandardArgs) 14 | 15 | find_package(PkgConfig) 16 | pkg_check_modules(PC_SWSCALE libswscale) 17 | set(SWSCALE_DEFINITIONS ${PC_SWSCALE_CFLAGS_OTHER}) 18 | 19 | find_library(SWSCALE_LIBRARIES swscale 20 | HINTS ${PC_SWSCALE_LIBDIR} ${PC_SWSCALE_LIBRARY_DIRS} 21 | ) 22 | 23 | find_path(SWSCALE_INCLUDE_DIR swscale.h 24 | HINTS ${PC_SWSCALE_INCLUDEDIR} ${PC_SWSCALE_INCLUDE_DIRS} 25 | PATH_SUFFIXES libswscale 26 | ) 27 | 28 | find_package_handle_standard_args(Swscale "Could not find libswscale; available at www.ffmpeg.org" SWSCALE_LIBRARIES SWSCALE_INCLUDE_DIR) 29 | 30 | mark_as_advanced(SWSCALE_INCLUDE_DIR SWSCALE_LIBRARIES) 31 | -------------------------------------------------------------------------------- /synthrain/fvector2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct fvector2{ 5 | float x, y; 6 | 7 | float len() { 8 | return std::sqrt(x*x+y*y); 9 | } 10 | 11 | float lenSq() { 12 | return x * x + y * y; 13 | } 14 | 15 | float dot(fvector2 const &other) const 16 | { 17 | return x*other.x + y*other.y; 18 | } 19 | 20 | fvector2 operator+(const fvector2& other) const 21 | { 22 | return fvector2{ x + other.x, y + other.y }; 23 | } 24 | 25 | fvector2& operator+=(const fvector2& other) 26 | { 27 | this->x += other.x; 28 | this->y += other.y; 29 | return *this; 30 | } 31 | 32 | fvector2 operator-(const fvector2& other) const 33 | { 34 | return fvector2{ x - other.x, y - other.y }; 35 | } 36 | 37 | fvector2 operator/(const float div) const 38 | { 39 | return fvector2{ x/div, y/div }; 40 | } 41 | 42 | fvector2& operator/=(const float div) 43 | { 44 | this->x /= div; 45 | this->y /= div; 46 | return *this; 47 | } 48 | 49 | fvector2& normalize() 50 | { 51 | *this /= len(); 52 | return *this; 53 | } 54 | }; 55 | 56 | -------------------------------------------------------------------------------- /synthrain/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][main] 2 | Pos=0,0 3 | Size=2560,1387 4 | Collapsed=0 5 | 6 | [Window][Debug##Default] 7 | Pos=1336,75 8 | Size=400,400 9 | Collapsed=0 10 | 11 | [Window][RenderControl] 12 | Pos=583,705 13 | Size=260,194 14 | Collapsed=1 15 | 16 | [Window][Data Synthesis] 17 | Pos=39,96 18 | Size=231,123 19 | Collapsed=0 20 | 21 | [Window][Drop Generator] 22 | Pos=731,49 23 | Size=360,307 24 | Collapsed=0 25 | 26 | [Window][Log] 27 | Pos=633,160 28 | Size=1060,643 29 | Collapsed=0 30 | 31 | [Window][Physics] 32 | Pos=107,341 33 | Size=332,237 34 | Collapsed=0 35 | 36 | [Window][Config] 37 | Pos=127,34 38 | Size=458,146 39 | Collapsed=0 40 | 41 | [Window][ImGui Demo] 42 | Pos=1169,7 43 | Size=550,680 44 | Collapsed=1 45 | 46 | [Window][Style Editor] 47 | Pos=60,60 48 | Size=543,908 49 | Collapsed=0 50 | 51 | [Window][Locate data] 52 | Pos=40,29 53 | Size=699,321 54 | Collapsed=0 55 | 56 | -------------------------------------------------------------------------------- /synthrain/imgui/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2020 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 | -------------------------------------------------------------------------------- /synthrain/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 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 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 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 18 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 19 | 20 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. 21 | //#define IMGUI_API __declspec( dllexport ) 22 | //#define IMGUI_API __declspec( dllimport ) 23 | 24 | //---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 25 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 26 | 27 | //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) 28 | //---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. 29 | //#define IMGUI_DISABLE_DEMO_WINDOWS 30 | 31 | //---- Don't implement some functions to reduce linkage requirements. 32 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 33 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 34 | //#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf. 35 | //#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h. 36 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free(). You will need to call ImGui::SetAllocatorFunctions(). 37 | 38 | //---- Include imgui_user.h at the end of imgui.h as a convenience 39 | //#define IMGUI_INCLUDE_IMGUI_USER_H 40 | 41 | //---- Pack colors to BGRA8 instead of RGBA8 (if you needed to convert from one to another anyway) 42 | //#define IMGUI_USE_BGRA_PACKED_COLOR 43 | 44 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 45 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 46 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 47 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 48 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 49 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 50 | 51 | //---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. 52 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 53 | /* 54 | #define IM_VEC2_CLASS_EXTRA \ 55 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 56 | operator MyVec2() const { return MyVec2(x,y); } 57 | 58 | #define IM_VEC4_CLASS_EXTRA \ 59 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 60 | operator MyVec4() const { return MyVec4(x,y,z,w); } 61 | */ 62 | 63 | //---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it. 64 | //#define ImDrawIdx unsigned int 65 | 66 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 67 | /* 68 | namespace ImGui 69 | { 70 | void MyFunction(const char* name, const MyMatrix44& v); 71 | } 72 | */ 73 | -------------------------------------------------------------------------------- /synthrain/imgui/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // ImGui Renderer for: OpenGL3 (modern OpenGL with shaders / programmatic pipeline) 2 | // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) 3 | // (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..) 4 | 5 | // Implemented features: 6 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. 7 | 8 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 9 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 10 | // https://github.com/ocornut/imgui 11 | 12 | // About GLSL version: 13 | // The 'glsl_version' initialization parameter defaults to "#version 130" if NULL. 14 | // Only override if your GL version doesn't handle this GLSL version (see table at the top of imgui_impl_opengl3.cpp). Keep NULL if unsure! 15 | 16 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); 17 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 18 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 19 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 20 | 21 | // Called by Init/NewFrame/Shutdown 22 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 23 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 24 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 25 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 26 | -------------------------------------------------------------------------------- /synthrain/imgui/imgui_impl_sdl.cpp: -------------------------------------------------------------------------------- 1 | // ImGui Platform Binding for: SDL2 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | // (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Clipboard support. 8 | // [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE). 9 | // Missing features: 10 | // [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. 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 | // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. 19 | // 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples. 20 | // 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter. 21 | // 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText). 22 | // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. 23 | // 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value. 24 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 25 | // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. 26 | // 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS). 27 | // 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes. 28 | // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. 29 | // 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS. 30 | // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. 31 | // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). 32 | // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. 33 | 34 | #include "imgui.h" 35 | #include "imgui_impl_sdl.h" 36 | 37 | // SDL 38 | // (the multi-viewports feature requires SDL features supported from SDL 2.0.5+) 39 | #include 40 | #include 41 | #define SDL_HAS_WARP_MOUSE_GLOBAL SDL_VERSION_ATLEAST(2,0,4) 42 | 43 | #define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4) 44 | #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) 45 | #define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5) 46 | #if !SDL_HAS_VULKAN 47 | static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; 48 | #endif 49 | 50 | // Data 51 | static SDL_Window* g_Window = NULL; 52 | static Uint64 g_Time = 0; 53 | static bool g_MousePressed[3] = { false, false, false }; 54 | static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 }; 55 | static char* g_ClipboardTextData = NULL; 56 | 57 | static const char* ImGui_ImplSDL2_GetClipboardText(void*) 58 | { 59 | if (g_ClipboardTextData) 60 | SDL_free(g_ClipboardTextData); 61 | g_ClipboardTextData = SDL_GetClipboardText(); 62 | return g_ClipboardTextData; 63 | } 64 | 65 | static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text) 66 | { 67 | SDL_SetClipboardText(text); 68 | } 69 | 70 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 71 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 72 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 73 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 74 | bool ImGui_ImplSDL2_ProcessEvent(SDL_Event* event) 75 | { 76 | ImGuiIO& io = ImGui::GetIO(); 77 | switch (event->type) 78 | { 79 | case SDL_MOUSEWHEEL: 80 | { 81 | if (event->wheel.x > 0) io.MouseWheelH += 1; 82 | if (event->wheel.x < 0) io.MouseWheelH -= 1; 83 | if (event->wheel.y > 0) io.MouseWheel += 1; 84 | if (event->wheel.y < 0) io.MouseWheel -= 1; 85 | return true; 86 | } 87 | case SDL_MOUSEBUTTONDOWN: 88 | { 89 | if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true; 90 | if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true; 91 | if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true; 92 | return true; 93 | } 94 | case SDL_TEXTINPUT: 95 | { 96 | io.AddInputCharactersUTF8(event->text.text); 97 | return true; 98 | } 99 | case SDL_KEYDOWN: 100 | case SDL_KEYUP: 101 | { 102 | int key = event->key.keysym.scancode; 103 | IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)); 104 | io.KeysDown[key] = (event->type == SDL_KEYDOWN); 105 | io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); 106 | io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); 107 | io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); 108 | io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); 109 | return true; 110 | } 111 | } 112 | return false; 113 | } 114 | 115 | static bool ImGui_ImplSDL2_Init(SDL_Window* window) 116 | { 117 | g_Window = window; 118 | 119 | // Setup back-end capabilities flags 120 | ImGuiIO& io = ImGui::GetIO(); 121 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) 122 | #if SDL_HAS_WARP_MOUSE_GLOBAL 123 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) 124 | #endif 125 | 126 | // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. 127 | io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; 128 | io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; 129 | io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; 130 | io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP; 131 | io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN; 132 | io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP; 133 | io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN; 134 | io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME; 135 | io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END; 136 | io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT; 137 | io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE; 138 | io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE; 139 | io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE; 140 | io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN; 141 | io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE; 142 | io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A; 143 | io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C; 144 | io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V; 145 | io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X; 146 | io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y; 147 | io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z; 148 | 149 | io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; 150 | io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; 151 | io.ClipboardUserData = NULL; 152 | 153 | g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); 154 | g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); 155 | g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); 156 | g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); 157 | g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); 158 | g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); 159 | g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); 160 | g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); 161 | 162 | #ifdef _WIN32 163 | SDL_SysWMinfo wmInfo; 164 | SDL_VERSION(&wmInfo.version); 165 | SDL_GetWindowWMInfo(window, &wmInfo); 166 | io.ImeWindowHandle = wmInfo.info.win.window; 167 | #else 168 | (void)window; 169 | #endif 170 | 171 | return true; 172 | } 173 | 174 | bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context) 175 | { 176 | (void)sdl_gl_context; // Viewport branch will need this. 177 | return ImGui_ImplSDL2_Init(window); 178 | } 179 | 180 | bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window) 181 | { 182 | #if !SDL_HAS_VULKAN 183 | IM_ASSERT(0 && "Unsupported"); 184 | #endif 185 | return ImGui_ImplSDL2_Init(window); 186 | } 187 | 188 | void ImGui_ImplSDL2_Shutdown() 189 | { 190 | g_Window = NULL; 191 | 192 | // Destroy last known clipboard data 193 | if (g_ClipboardTextData) 194 | SDL_free(g_ClipboardTextData); 195 | g_ClipboardTextData = NULL; 196 | 197 | // Destroy SDL mouse cursors 198 | for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) 199 | SDL_FreeCursor(g_MouseCursors[cursor_n]); 200 | memset(g_MouseCursors, 0, sizeof(g_MouseCursors)); 201 | } 202 | 203 | static void ImGui_ImplSDL2_UpdateMousePosAndButtons() 204 | { 205 | ImGuiIO& io = ImGui::GetIO(); 206 | const ImVec2 mouse_pos_backup = io.MousePos; 207 | io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 208 | 209 | // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) 210 | // (When multi-viewports are enabled, all imgui positions are same as OS positions.) 211 | #if SDL_HAS_WARP_MOUSE_GLOBAL 212 | if (io.WantSetMousePos) 213 | SDL_WarpMouseGlobal((int)mouse_pos_backup.x, (int)mouse_pos_backup.y); 214 | #endif 215 | 216 | int mx, my; 217 | Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); 218 | io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // 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. 219 | io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; 220 | io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; 221 | g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; 222 | 223 | #if SDL_HAS_CAPTURE_MOUSE 224 | SDL_Window* focused_window = SDL_GetKeyboardFocus(); 225 | if (g_Window == focused_window) 226 | { 227 | // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?) 228 | // The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally. 229 | int wx, wy; 230 | SDL_GetWindowPosition(focused_window, &wx, &wy); 231 | SDL_GetGlobalMouseState(&mx, &my); 232 | mx -= wx; 233 | my -= wy; 234 | io.MousePos = ImVec2((float)mx, (float)my); 235 | } 236 | 237 | // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. 238 | // The function is only supported from SDL 2.0.4 (released Jan 2016) 239 | bool any_mouse_button_down = ImGui::IsAnyMouseDown(); 240 | SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); 241 | #else 242 | if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) 243 | io.MousePos = ImVec2((float)mx, (float)my); 244 | #endif 245 | } 246 | 247 | static void ImGui_ImplSDL2_UpdateMouseCursor() 248 | { 249 | ImGuiIO& io = ImGui::GetIO(); 250 | if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) 251 | return; 252 | 253 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); 254 | if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) 255 | { 256 | // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor 257 | SDL_ShowCursor(SDL_FALSE); 258 | } 259 | else 260 | { 261 | // Show OS mouse cursor 262 | SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); 263 | SDL_ShowCursor(SDL_TRUE); 264 | } 265 | } 266 | 267 | void ImGui_ImplSDL2_NewFrame(SDL_Window* window) 268 | { 269 | ImGuiIO& io = ImGui::GetIO(); 270 | IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame() 271 | 272 | // Setup display size (every frame to accommodate for window resizing) 273 | int w, h; 274 | int display_w, display_h; 275 | SDL_GetWindowSize(window, &w, &h); 276 | SDL_GL_GetDrawableSize(window, &display_w, &display_h); 277 | io.DisplaySize = ImVec2((float)w, (float)h); 278 | io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); 279 | 280 | // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) 281 | static Uint64 frequency = SDL_GetPerformanceFrequency(); 282 | Uint64 current_time = SDL_GetPerformanceCounter(); 283 | io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f); 284 | g_Time = current_time; 285 | 286 | ImGui_ImplSDL2_UpdateMousePosAndButtons(); 287 | ImGui_ImplSDL2_UpdateMouseCursor(); 288 | } 289 | -------------------------------------------------------------------------------- /synthrain/imgui/imgui_impl_sdl.h: -------------------------------------------------------------------------------- 1 | // ImGui Platform Binding for: SDL2 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | // (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Clipboard support. 8 | // [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE). 9 | // Missing features: 10 | // [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. 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 | struct SDL_Window; 17 | typedef union SDL_Event SDL_Event; 18 | 19 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); 20 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); 21 | IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); 22 | IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window); 23 | IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(SDL_Event* event); 24 | -------------------------------------------------------------------------------- /synthrain/main.cpp: -------------------------------------------------------------------------------- 1 | #ifndef NO_CUDA 2 | #ifdef _WIN32 3 | #pragma comment(lib, "cudart_static") 4 | #endif 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef _WIN32 23 | #define VC_EXTRALEAN 24 | #define WIN32_LEAN_AND_MEAN 25 | #include 26 | #include 27 | 28 | namespace fs = std::experimental::filesystem; 29 | #else 30 | namespace fs = std::filesystem; 31 | #endif 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "imgui/imgui.h" 39 | #include "imgui/imgui_impl_sdl.h" 40 | #include "imgui/imgui_impl_opengl3.h" 41 | 42 | #ifdef _WIN32 43 | #define _CRTDBG_MAP_ALLOC 44 | #include 45 | #endif 46 | 47 | #include 48 | 49 | #include "Exporter.h" 50 | #include "LogWindow.h" 51 | #include "rng.h" 52 | #include "DataSequence.h" 53 | 54 | #include 55 | #include 56 | 57 | #include "OGLFloatTexture.h" 58 | #include "FlowData.h" 59 | #include "json.hpp" 60 | 61 | #include "OGLRenderer.h" 62 | #include "OGLRenderStage.h" 63 | #include "RenderStageBokeh.h" 64 | 65 | static const int SCREEN_WIDTH = 240; 66 | static const int SCREEN_HEIGHT = 240; 67 | 68 | SDL_Surface* surface = nullptr; 69 | SDL_Window* window = nullptr; 70 | SDL_Texture* texture = nullptr; 71 | 72 | #ifdef NDEBUG 73 | bool dry_run = false; 74 | #else 75 | bool dry_run = true; 76 | #endif 77 | 78 | bool exporting = false; 79 | 80 | void ogl_debugmsg(GLenum source, 81 | GLenum type, 82 | GLuint id, 83 | GLenum severity, 84 | GLsizei length, 85 | const GLchar* message, 86 | const void* userParam) 87 | { 88 | SDL_Log("OGL(%d):%s", id , message); 89 | } 90 | 91 | int main(int, char**) 92 | { 93 | { 94 | 95 | srand((unsigned int)time(0)); 96 | SDL_LogSetAllPriority(SDL_LOG_PRIORITY_INFO); 97 | 98 | SDL_Log("Rain Simulator started up"); 99 | 100 | // Setup SDL 101 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) 102 | { 103 | printf("Error: %s\n", SDL_GetError()); 104 | return -1; 105 | } 106 | 107 | const char* glsl_version = "#version 450"; 108 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); 109 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 110 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 111 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); 112 | 113 | 114 | // Create window with graphics context 115 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 116 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 117 | SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 118 | SDL_DisplayMode current; 119 | SDL_GetCurrentDisplayMode(0, ¤t); 120 | window = SDL_CreateWindow("Synthetic Rainmaker", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1920, 1080, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); 121 | SDL_GLContext gl_context = SDL_GL_CreateContext(window); 122 | SDL_GL_SetSwapInterval(1); // Enable vsync 123 | glewInit(); 124 | 125 | 126 | GLint flags; 127 | glGetIntegerv(GL_CONTEXT_FLAGS, &flags); 128 | assert(flags & GL_CONTEXT_FLAG_DEBUG_BIT); 129 | 130 | glDebugMessageCallback(ogl_debugmsg, nullptr); 131 | glEnable(GL_DEBUG_OUTPUT); 132 | glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 133 | 134 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE); 135 | //glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW,0,nullptr, GL_TRUE); 136 | //glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW,0,nullptr, GL_TRUE); 137 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE); 138 | glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE); 139 | 140 | // Setup Dear ImGui binding 141 | ImGui::CreateContext(); 142 | ImGuiIO& io = ImGui::GetIO(); (void)io; 143 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 144 | 145 | ImGui_ImplSDL2_InitForOpenGL(window, gl_context); 146 | ImGui_ImplOpenGL3_Init(glsl_version); 147 | 148 | glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); 149 | 150 | int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG; 151 | if (!(IMG_Init(imgFlags) & imgFlags)) 152 | { 153 | SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "SDL_image could not initialize! SDL_image Error: %s", IMG_GetError()); 154 | } 155 | 156 | // Setup style 157 | ImGui::StyleColorsDark(); 158 | //ImGui::StyleColorsClassic(); 159 | 160 | OGLRenderStage::InitSharedResources(); 161 | 162 | // --- Fundamental init done --- // 163 | 164 | 165 | //TODO: App should not crash or throw when there's no data to load 166 | //TODO: Add data folder config to app with https://github.com/samhocevar/portable-file-dialogs 167 | //TODO: Move drop generation to a config file 168 | //TODO: Move automated generation distribution to config file 169 | //TODO: Update imgui? 170 | //TODO: Update json++? 171 | 172 | { 173 | auto input_image = std::make_shared(); 174 | auto flow_texture = std::make_shared(); 175 | auto depth_texture = std::make_shared(GL_RED); 176 | 177 | DataSequence sequencer(input_image, flow_texture, depth_texture); 178 | Exporter exporter; 179 | std::unique_ptr renderer; 180 | 181 | auto load_config = [&]() { 182 | 183 | nlohmann::json config; 184 | 185 | { 186 | if (std::ifstream cfgfile("./config.json"); cfgfile.good() == true) 187 | { 188 | cfgfile >> config; 189 | } 190 | else { //make new config 191 | std::ofstream out_cfgfile("./config.json"); 192 | config["data"]["input_folder"] = "./examples"; 193 | config["data"]["use_sequences"] = { "00" }; 194 | config["data"]["output_folder"] = "./out"; 195 | 196 | { 197 | std::ofstream cfgfile("config.json"); 198 | if (cfgfile.good()) 199 | { 200 | cfgfile << std::setw(4) << config << std::endl; 201 | } 202 | } 203 | } 204 | } 205 | 206 | std::string ifolder = config["data"]["input_folder"]; 207 | std::string ofolder = config["data"]["output_folder"]; 208 | std::vector seqs; 209 | 210 | for (auto& e : config["data"]["use_sequences"].items()) { 211 | seqs.push_back(e.value()); 212 | } 213 | 214 | sequencer.setSequencesFolder(ifolder); 215 | sequencer.setSequences(seqs); 216 | sequencer.setOutputFolder(ofolder); 217 | sequencer.setSequence(0); 218 | 219 | if (sequencer.colorDataAvailable() == true) 220 | { 221 | renderer = std::make_unique< OGLRenderer>(input_image, flow_texture, depth_texture); 222 | 223 | if (sequencer.depthDataAvailable() == true) 224 | { 225 | renderer->setAvailableEffects({ OGLRenderer::Effect::Fog, OGLRenderer::Effect::Rain }); 226 | renderer->setActiveEffects({ OGLRenderer::Effect::Fog, OGLRenderer::Effect::Rain }); 227 | } 228 | } 229 | 230 | }; 231 | 232 | load_config(); 233 | 234 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 235 | 236 | // Main loop 237 | bool done = false; 238 | bool autoplay = false; 239 | 240 | while (!done) 241 | { 242 | SDL_Event event; 243 | while (SDL_PollEvent(&event)) 244 | { 245 | ImGui_ImplSDL2_ProcessEvent(&event); 246 | if (event.type == SDL_QUIT) 247 | done = true; 248 | if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) 249 | done = true; 250 | } 251 | 252 | // Start the ImGui frame 253 | ImGui_ImplOpenGL3_NewFrame(); 254 | ImGui_ImplSDL2_NewFrame(window); 255 | ImGui::NewFrame(); 256 | 257 | #ifndef NDEBUG 258 | ImGui::ShowDemoWindow(); 259 | #endif 260 | 261 | { 262 | int w, h; 263 | SDL_GetWindowSize(window, &w, &h); 264 | ImGui::SetNextWindowPos(ImVec2(0, 0)); 265 | ImGui::SetNextWindowSize(ImVec2((float)w, (float)h));; 266 | ImGui::SetNextWindowBgAlpha(1); 267 | } 268 | 269 | ImGui::Begin("main", NULL, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove); 270 | 271 | if (renderer == nullptr) 272 | { 273 | ImGui::Begin("Locate data"); 274 | 275 | ImGui::Text("No valid image data at location specified by config file."); 276 | 277 | ImGui::Text("Images should be prepared in the following manner:\n" 278 | "When only color data is present:\n" 279 | "Place image sequences in sub folders, e.g. \n\\path\\to\\data\\seq1\\\n\\path\\to\\data\\seq1\\\n" 280 | "In the configuration, \n\"input_folder\" is \\path\\to\\data\\,\n'use_sequences' is [\"seq1\", \"seq2\"]\n" 281 | "Additionally, when using depth and/or flow data:\n" 282 | "Place image sequences in sub folders, and divide data into subfolders e.g.\n" 283 | "\\path\\to\\data\\seq1\\color\\\n" 284 | "\\path\\to\\data\\seq1\\depth\\\n" 285 | "\\path\\to\\data\\seq1\\flow\\\n" 286 | ); 287 | 288 | if (ImGui::Button("Open config file")) 289 | { 290 | #ifdef _WIN32 291 | ShellExecute(0, 0, ".\\config.json", 0, 0, SW_SHOW); 292 | #elif __linux__ 293 | system("xdg-open ./config.json"); 294 | #endif 295 | } 296 | 297 | if (ImGui::Button("Open config file location")) 298 | { 299 | #ifdef _WIN32 300 | ShellExecute(0, "open", "explorer.exe", "/select, \".\\config.json\"", 0, SW_SHOW); 301 | #else 302 | #endif 303 | } 304 | 305 | if (ImGui::Button("Reload config file")) 306 | { 307 | load_config(); 308 | } 309 | 310 | ImGui::End(); 311 | }else{ 312 | //if (ImGui::Begin("Data Synthesis"), NULL, ImGuiWindowFlags_AlwaysAutoResize) 313 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.f, 4.f)); 314 | ImGui::BeginGroup(); 315 | 316 | if (autoplay == false) 317 | { 318 | if (exporting == false) 319 | { 320 | ImGui::PushItemWidth(100); 321 | 322 | bool ticked = sequencer.showUI(); 323 | if (ticked == true) renderer->onTick(); 324 | 325 | ImGui::PopItemWidth(); 326 | 327 | ImGui::Checkbox("Dry run", &dry_run); 328 | ImGui::SameLine(); 329 | 330 | if (ImGui::Button("Begin Synthesis")) 331 | { 332 | renderer->prepSequence(); 333 | exporting = true; 334 | //bokeh_stage->setFocus(0.125f); 335 | } 336 | } 337 | else { 338 | 339 | int counter = sequencer.getCurrentFrame(); 340 | ImGui::Text("Processing %d", counter); 341 | //ImGui::Text("Sequence No %d/%d", counter/out_seq_len, sequencer.getFileCount()/out_seq_len); 342 | 343 | if (ImGui::Button("Stop Synthesis")) 344 | { 345 | exporting = false; 346 | } 347 | } 348 | 349 | } 350 | 351 | ImGui::EndGroup(); 352 | ImGui::SameLine(); 353 | 354 | 355 | ImGui::BeginGroup(); 356 | renderer->showSettingsUI(); 357 | ImGui::EndGroup(); 358 | 359 | ImGui::SameLine(); 360 | renderer->showDropGenerationUI(); 361 | ImGui::SameLine(); 362 | 363 | renderer->showStageDebugUI(); 364 | 365 | ImGui::SameLine(); 366 | 367 | { 368 | static bool show_log = false; 369 | if (ImGui::Button(show_log ? "Hide Log" : "Show Log", ImVec2(120, 30))) 370 | { 371 | show_log = !show_log; 372 | } 373 | 374 | if (show_log)LogWindow::get()->Draw("Log"); 375 | } 376 | 377 | //ImGui::End(); 378 | ImGui::PopStyleVar(); 379 | ImGui::Spacing(); 380 | 381 | renderer->showSideBySide(); 382 | 383 | if (autoplay == true) { 384 | sequencer.advanceFrame(); 385 | renderer->onTick(); 386 | SDL_Delay(1000 / 30); 387 | } 388 | else if (exporting == false) 389 | { 390 | SDL_Delay(1000 / 60); 391 | } 392 | 393 | SDL_GL_MakeCurrent(window, gl_context); 394 | 395 | renderer->draw(); 396 | 397 | 398 | if (exporting == true) 399 | { 400 | 401 | 402 | if (dry_run == false) 403 | { 404 | fs::path outfile = sequencer.getCurrentOutputDirectory(); 405 | outfile.append(sequencer.getCurrentOutputFileName()); 406 | outfile += ".png"; 407 | 408 | exporter.enqueue(outfile, { input_image.get(), renderer->getOutputFBO() }); 409 | } 410 | 411 | sequencer.advanceFrame(); 412 | renderer->onTick(); 413 | 414 | if (sequencer.isEndOfSequence() == true) 415 | { 416 | sequencer.advanceSequence(); 417 | 418 | if (sequencer.isEndOfAllSequences()) 419 | { 420 | exporting = false; 421 | } 422 | } 423 | else { 424 | if (sequencer.useNewParameters() == true) renderer->prepSequence(); 425 | } 426 | } 427 | } 428 | 429 | ImGui::End(); 430 | // Rendering 431 | ImGui::Render(); 432 | 433 | glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); 434 | glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); 435 | glClear(GL_COLOR_BUFFER_BIT); 436 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 437 | SDL_GL_SwapWindow(window); 438 | } 439 | 440 | exporter.shutdown(); 441 | 442 | 443 | // Cleanup 444 | ImGui_ImplOpenGL3_Shutdown(); 445 | ImGui_ImplSDL2_Shutdown(); 446 | ImGui::DestroyContext(); 447 | 448 | SDL_GL_DeleteContext(gl_context); 449 | SDL_DestroyWindow(window); 450 | SDL_Quit(); 451 | 452 | } 453 | } 454 | 455 | #ifdef _WIN32 456 | _CrtDumpMemoryLeaks(); 457 | #endif 458 | 459 | return 0; 460 | } 461 | 462 | -------------------------------------------------------------------------------- /synthrain/rng.cpp: -------------------------------------------------------------------------------- 1 | #include "rng.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::mt19937 RNG::mt; 11 | 12 | namespace RNG 13 | { 14 | static class InitRNG 15 | { 16 | public: 17 | InitRNG() 18 | { 19 | std::random_device rd; 20 | std::array seed_data; 21 | std::generate_n(seed_data.data(), seed_data.size(), std::ref(rd)); 22 | std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); 23 | RNG::mt.seed(seq); 24 | } 25 | } init; 26 | } 27 | -------------------------------------------------------------------------------- /synthrain/rng.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace RNG 5 | { 6 | extern std::mt19937 mt; 7 | //TODO: Add ability to set the seed 8 | } -------------------------------------------------------------------------------- /synthrain/shaders/.gitignore: -------------------------------------------------------------------------------- 1 | input/ 2 | out/ 3 | train/ 4 | test/ 5 | mod/ -------------------------------------------------------------------------------- /synthrain/shaders/basic.frag: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | uniform sampler2D tex; 3 | 4 | in vec2 UV; 5 | out vec4 color; 6 | 7 | void main() 8 | { 9 | color = texture2D(tex, UV); 10 | } -------------------------------------------------------------------------------- /synthrain/shaders/basic.vert: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(location = 0) in vec2 vtx_pos; 4 | 5 | out float depth; 6 | out vec2 UV; 7 | 8 | void main() 9 | { 10 | gl_Position.xy = (vtx_pos*2)+vec2(-1,-1); 11 | gl_Position.z = 1; 12 | gl_Position.w = 1.0; 13 | UV = vtx_pos; 14 | } -------------------------------------------------------------------------------- /synthrain/shaders/basic_alpha.frag: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | uniform sampler2D tex; 3 | uniform float alpha = 0.1; 4 | 5 | in vec2 UV; 6 | out vec4 color; 7 | 8 | void main() 9 | { 10 | color = vec4(texture2D(tex, UV).rgb, alpha); 11 | } -------------------------------------------------------------------------------- /synthrain/shaders/blur.frag: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | layout(binding = 0) uniform sampler2D tex; 3 | uniform vec2 resolution = vec2(960,960); 4 | uniform vec2 direction = vec2(1,0); 5 | 6 | in vec2 UV; 7 | out vec4 color; 8 | 9 | vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) { 10 | vec4 color = vec4(0.0); 11 | vec2 off1 = vec2(1.3846153846) * direction; 12 | vec2 off2 = vec2(3.2307692308) * direction; 13 | color += texture2D(image, uv) * 0.2270270270; 14 | color += texture2D(image, uv + (off1 / resolution)) * 0.3162162162; 15 | color += texture2D(image, uv - (off1 / resolution)) * 0.3162162162; 16 | color += texture2D(image, uv + (off2 / resolution)) * 0.0702702703; 17 | color += texture2D(image, uv - (off2 / resolution)) * 0.0702702703; 18 | return color; 19 | } 20 | 21 | void main() 22 | { 23 | color = blur9(tex, UV, resolution, 9*direction); 24 | } -------------------------------------------------------------------------------- /synthrain/shaders/bokeh-billboard.frag: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | uniform sampler2D tex; 3 | uniform sampler2D billboard_tex; 4 | 5 | uniform float u_alpha_min = 0.002f; 6 | uniform float u_alpha_max = 0.3f; 7 | 8 | in vec2 UV; 9 | in vec2 UV2; 10 | out vec4 color; 11 | out vec4 ground_truth; 12 | 13 | void main() 14 | { 15 | vec4 bokeh = texture2D(billboard_tex, UV2); 16 | 17 | vec4 c = texture2D(tex, UV); 18 | float lum = bokeh.r * dot(c.rgb, vec3(0.299, 0.587, 0.114));// smoothstep( 0.9f, 1.0f, ) ); 19 | float alpha = bokeh.a *c.a* (u_alpha_min + ((u_alpha_max-u_alpha_min)*lum)); 20 | 21 | ground_truth = vec4(alpha*0.25,alpha*0.25,alpha*0.25,1); 22 | color = vec4(c.rgb, alpha); 23 | } -------------------------------------------------------------------------------- /synthrain/shaders/bokeh-billboard.geom: -------------------------------------------------------------------------------- 1 | #version 430 core 2 | 3 | layout (points) in; 4 | layout (triangle_strip, max_vertices = 4) out; 5 | uniform float u_size = 0.02; 6 | uniform float uv_spread = 0.001; 7 | uniform float u_aspect = 1; 8 | out vec2 UV; 9 | out vec2 UV2; 10 | 11 | const uint num_offests = 4; 12 | 13 | const vec4 offsets[num_offests]=vec4[num_offests]( 14 | vec4(-0.5, -0.5, 0.0, 0.0), 15 | vec4( 0.5, -0.5, 0.0, 0.0), 16 | vec4(-0.5, 0.5, 0.0, 0.0), 17 | vec4( 0.5, 0.5, 0.0, 0.0) 18 | ); 19 | 20 | 21 | void build_hex(vec4 position) 22 | { 23 | 24 | vec2 UV_center = (position.xy/2) + vec2(0.5,0.5); 25 | 26 | for(uint i = 0; i < num_offests; ++i) 27 | { 28 | gl_Position = position + u_size*offsets[i]*vec4(1,u_aspect,0,0); 29 | UV = UV_center + uv_spread*offsets[i].xy; 30 | UV2 = (0.5+offsets[i].xy); 31 | EmitVertex(); 32 | } 33 | 34 | EndPrimitive(); 35 | } 36 | 37 | void main() 38 | { 39 | build_hex(vec4(gl_in[0].gl_Position.xy,0,1)); 40 | } 41 | 42 | 43 | /* 44 | gl_Position = position + u_size*vec4( -1.0, 0.0, 0.0, 0.0); 45 | UV = UV_center + uv_spread*vec2( -1.0, 0.0); 46 | EmitVertex(); 47 | 48 | gl_Position = position + u_size*vec4(-0.5, y, 0.0, 0.0); 49 | EmitVertex(); 50 | 51 | gl_Position = position + u_size*vec4(-0.5, -y, 0.0, 0.0); 52 | EmitVertex(); 53 | 54 | gl_Position = position + u_size*vec4( 0.5, y, 0.0, 0.0); 55 | EmitVertex(); 56 | 57 | gl_Position = position + u_size*vec4( 0.5, -y, 0.0, 0.0); 58 | EmitVertex(); 59 | 60 | gl_Position = position + u_size* vec4( 1.0, 0.0, 0.0, 0.0); 61 | EmitVertex(); 62 | */ 63 | -------------------------------------------------------------------------------- /synthrain/shaders/bokeh-circle.geom: -------------------------------------------------------------------------------- 1 | #version 430 core 2 | 3 | layout (points) in; 4 | layout (triangle_strip, max_vertices = 32) out; 5 | uniform float u_size = 0.02; 6 | uniform float uv_spread = 0.001; 7 | uniform float u_aspect = 1; 8 | out vec2 UV; 9 | 10 | const uint num_offests = 32; 11 | 12 | 13 | void build_hex(vec4 position) 14 | { 15 | float y = 0.5 * sqrt(3)*u_aspect; 16 | 17 | vec2 UV_center = (position.xy/2) + vec2(0.5,0.5); 18 | 19 | for(uint i = 0; i < num_offests; ++i) 20 | { 21 | gl_Position = position + vec2(sin(i), cos(i)); 22 | UV = UV_center + uv_spread*offsets[i].xy; 23 | EmitVertex(); 24 | } 25 | 26 | EndPrimitive(); 27 | } 28 | 29 | void main() 30 | { 31 | build_hex(vec4(gl_in[0].gl_Position.xy,0,1)); 32 | } 33 | 34 | 35 | /* 36 | gl_Position = position + u_size*vec4( -1.0, 0.0, 0.0, 0.0); 37 | UV = UV_center + uv_spread*vec2( -1.0, 0.0); 38 | EmitVertex(); 39 | 40 | gl_Position = position + u_size*vec4(-0.5, y, 0.0, 0.0); 41 | EmitVertex(); 42 | 43 | gl_Position = position + u_size*vec4(-0.5, -y, 0.0, 0.0); 44 | EmitVertex(); 45 | 46 | gl_Position = position + u_size*vec4( 0.5, y, 0.0, 0.0); 47 | EmitVertex(); 48 | 49 | gl_Position = position + u_size*vec4( 0.5, -y, 0.0, 0.0); 50 | EmitVertex(); 51 | 52 | gl_Position = position + u_size* vec4( 1.0, 0.0, 0.0, 0.0); 53 | EmitVertex(); 54 | */ 55 | -------------------------------------------------------------------------------- /synthrain/shaders/bokeh-hex.geom: -------------------------------------------------------------------------------- 1 | #version 430 core 2 | 3 | layout (points) in; 4 | layout (triangle_strip, max_vertices = 6) out; 5 | uniform float u_size = 0.043; 6 | uniform float uv_spread = 0.001; 7 | uniform float u_aspect = 1; 8 | out vec2 UV; 9 | 10 | const uint num_offests = 6; 11 | 12 | 13 | void build_hex(vec4 position) 14 | { 15 | float y = 0.5 * sqrt(3)*u_aspect; 16 | vec4 offsets[num_offests]=vec4[num_offests]( 17 | vec4( -1.0, 0.0, 0.0, 0.0), 18 | vec4(-0.5, y, 0.0, 0.0), 19 | vec4(-0.5, -y, 0.0, 0.0), 20 | vec4( 0.5, y, 0.0, 0.0), 21 | vec4( 0.5, -y, 0.0, 0.0), 22 | vec4( 1.0, 0.0, 0.0, 0.0) 23 | ); 24 | 25 | vec2 UV_center = (position.xy/2) + vec2(0.5,0.5); 26 | 27 | for(uint i = 0; i < num_offests; ++i) 28 | { 29 | gl_Position = position + u_size*offsets[i]; 30 | UV = UV_center + uv_spread*offsets[i].xy; 31 | EmitVertex(); 32 | } 33 | 34 | EndPrimitive(); 35 | } 36 | 37 | void main() 38 | { 39 | build_hex(vec4(gl_in[0].gl_Position.xy,0,1)); 40 | } 41 | 42 | 43 | /* 44 | gl_Position = position + u_size*vec4( -1.0, 0.0, 0.0, 0.0); 45 | UV = UV_center + uv_spread*vec2( -1.0, 0.0); 46 | EmitVertex(); 47 | 48 | gl_Position = position + u_size*vec4(-0.5, y, 0.0, 0.0); 49 | EmitVertex(); 50 | 51 | gl_Position = position + u_size*vec4(-0.5, -y, 0.0, 0.0); 52 | EmitVertex(); 53 | 54 | gl_Position = position + u_size*vec4( 0.5, y, 0.0, 0.0); 55 | EmitVertex(); 56 | 57 | gl_Position = position + u_size*vec4( 0.5, -y, 0.0, 0.0); 58 | EmitVertex(); 59 | 60 | gl_Position = position + u_size* vec4( 1.0, 0.0, 0.0, 0.0); 61 | EmitVertex(); 62 | */ 63 | -------------------------------------------------------------------------------- /synthrain/shaders/bokeh-hex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSVL/OpenSynthrain/59416b57beb5832ad82f67e4edd62ac1de19ea6e/synthrain/shaders/bokeh-hex.png -------------------------------------------------------------------------------- /synthrain/shaders/bokeh-round2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSVL/OpenSynthrain/59416b57beb5832ad82f67e4edd62ac1de19ea6e/synthrain/shaders/bokeh-round2.png -------------------------------------------------------------------------------- /synthrain/shaders/bokeh.frag: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | uniform sampler2D tex; 3 | 4 | uniform float u_min_alpha = 0.002f; 5 | uniform float u_max_alpha = 0.3f; 6 | 7 | in vec2 UV; 8 | out vec4 color; 9 | 10 | void main() 11 | { 12 | vec4 c = texture2D(tex, UV); 13 | float lum = dot(c.rgb, vec3(0.299, 0.587, 0.114)); //luminosity 14 | color = vec4(c.rgb, u_min_alpha + ((u_max_alpha-u_min_alpha)*lum*lum*c.a)); 15 | } -------------------------------------------------------------------------------- /synthrain/shaders/drop.frag: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | uniform sampler2D drop_tex; 3 | 4 | in vec2 UV; 5 | in float depth; 6 | out vec4 color; 7 | 8 | void main() 9 | { 10 | color = texture2D(drop_tex, UV); 11 | color.rgb *= color.a; 12 | } -------------------------------------------------------------------------------- /synthrain/shaders/drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSVL/OpenSynthrain/59416b57beb5832ad82f67e4edd62ac1de19ea6e/synthrain/shaders/drop.png -------------------------------------------------------------------------------- /synthrain/shaders/drop.vert: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(location = 0) in vec2 vtx_pos; 4 | layout(location = 1) in vec4 params; 5 | 6 | out float depth; 7 | out vec2 UV; 8 | 9 | uniform vec2 inv_half_screen_size; 10 | 11 | void main() 12 | { 13 | gl_Position.xy = ( ((vtx_pos*params.zw)+params.xy) *inv_half_screen_size ) - vec2(1,1) ; 14 | gl_Position.z = 1; 15 | gl_Position.w = 1.0; 16 | UV = vtx_pos + vec2(0.5f,0.5f); 17 | depth = params.w; 18 | } -------------------------------------------------------------------------------- /synthrain/shaders/flow_average.comp: -------------------------------------------------------------------------------- 1 | #version 440 core 2 | 3 | layout(local_size_x = 1, local_size_y = 1) in; 4 | 5 | layout(binding = 0) uniform sampler2D imageInput; 6 | layout(rg32f, binding = 1) writeonly restrict uniform image2D imageOutput; 7 | 8 | void main() { 9 | ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); 10 | 11 | const int windowSize = 33; 12 | 13 | vec4 colorSum = vec4(0.0); 14 | float weightSum = 0.0; 15 | 16 | for (int x = pixelCoord.x - windowSize / 2; x <= pixelCoord.x + windowSize / 2; x++) { 17 | for (int y = pixelCoord.y - windowSize / 2; y <= pixelCoord.y + windowSize / 2; y++) { 18 | colorSum += texelFetch(imageInput, ivec2(x, y)); 19 | weightSum += 1.0; 20 | } 21 | } 22 | 23 | imageStore(imageOutput, pixelCoord, colorSum / weightSum); 24 | } -------------------------------------------------------------------------------- /synthrain/shaders/fog.frag: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | layout(binding = 0) uniform sampler2D tex; 3 | layout(binding = 1) uniform sampler2D depth; 4 | layout(binding = 2) uniform sampler2D blur; 5 | 6 | uniform float density = 0.4; 7 | uniform float far_fog_plane = 0.000f; 8 | uniform float near_fog_plane = 0.063f; 9 | uniform vec3 fog_color = {0.89,0.89,0.89}; 10 | uniform float alpha = 0.23; 11 | uniform float distance_pow = 1; 12 | uniform float fog_max_density = 0.91f; 13 | 14 | 15 | in vec2 UV; 16 | out vec4 color; 17 | 18 | 19 | void main() 20 | { 21 | vec4 blur_color = vec4(texture2D(blur, UV).rgb, alpha); 22 | vec4 source_color = vec4(texture2D(tex, UV).rgb, alpha); 23 | 24 | /*float z = clamp(texture2D(depth, UV).r,far_fog_plane,near_fog_plane); 25 | float z_scaled = (z-far_fog_plane)/(near_fog_plane-far_fog_plane); 26 | float distance = distance_pow/(z_scaled); 27 | float fog = (1/exp((distance*density)));*/ 28 | 29 | 30 | float distance = clamp(texture2D(depth, UV).r,far_fog_plane,near_fog_plane); 31 | float distance_scaled = log(1/((distance-far_fog_plane)/(near_fog_plane-far_fog_plane))); 32 | float fog = clamp(1-(1/exp((distance_scaled*density))),0.f,fog_max_density); 33 | 34 | color = vec4( mix(mix(blur_color.rgb,source_color.rgb,alpha), fog_color, fog), 1); 35 | //color = vec4(fog,0,0,1); 36 | } -------------------------------------------------------------------------------- /synthrain/shaders/noise.frag: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | // 4 | // Description : Array and textureless GLSL 2D simplex noise function. 5 | // Author : Ian McEwan, Ashima Arts. 6 | // Maintainer : stegu 7 | // Lastmod : 20110822 (ijm) 8 | // License : Copyright (C) 2011 Ashima Arts. All rights reserved. 9 | // Distributed under the MIT License. See LICENSE file. 10 | // https://github.com/ashima/webgl-noise 11 | // https://github.com/stegu/webgl-noise 12 | // 13 | 14 | vec3 mod289(vec3 x) { 15 | return x - floor(x * (1.0 / 289.0)) * 289.0; 16 | } 17 | 18 | vec2 mod289(vec2 x) { 19 | return x - floor(x * (1.0 / 289.0)) * 289.0; 20 | } 21 | 22 | vec3 permute(vec3 x) { 23 | return mod289(((x*34.0)+1.0)*x); 24 | } 25 | 26 | float snoise(vec2 v) 27 | { 28 | const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 29 | 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) 30 | -0.577350269189626, // -1.0 + 2.0 * C.x 31 | 0.024390243902439); // 1.0 / 41.0 32 | // First corner 33 | vec2 i = floor(v + dot(v, C.yy) ); 34 | vec2 x0 = v - i + dot(i, C.xx); 35 | 36 | // Other corners 37 | vec2 i1; 38 | //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 39 | //i1.y = 1.0 - i1.x; 40 | i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); 41 | // x0 = x0 - 0.0 + 0.0 * C.xx ; 42 | // x1 = x0 - i1 + 1.0 * C.xx ; 43 | // x2 = x0 - 1.0 + 2.0 * C.xx ; 44 | vec4 x12 = x0.xyxy + C.xxzz; 45 | x12.xy -= i1; 46 | 47 | // Permutations 48 | i = mod289(i); // Avoid truncation effects in permutation 49 | vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) 50 | + i.x + vec3(0.0, i1.x, 1.0 )); 51 | 52 | vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); 53 | m = m*m ; 54 | m = m*m ; 55 | 56 | // Gradients: 41 points uniformly over a line, mapped onto a diamond. 57 | // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) 58 | 59 | vec3 x = 2.0 * fract(p * C.www) - 1.0; 60 | vec3 h = abs(x) - 0.5; 61 | vec3 ox = floor(x + 0.5); 62 | vec3 a0 = x - ox; 63 | 64 | // Normalise gradients implicitly by scaling m 65 | // Approximation of: m *= inversesqrt( a0*a0 + h*h ); 66 | m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); 67 | 68 | // Compute final noise value at P 69 | vec3 g; 70 | g.x = a0.x * x0.x + h.x * x0.y; 71 | g.yz = a0.yz * x12.xz + h.yz * x12.yw; 72 | return 130.0 * dot(m, g); 73 | } 74 | 75 | // End simplex code 76 | 77 | uniform vec2 image_size; 78 | uniform float noise_scale = 10; 79 | uniform float cutoff_low = 0; 80 | uniform float cutoff_high = 1; 81 | out vec4 color; 82 | 83 | void main() { 84 | vec2 norm_pos = gl_FragCoord.xy/image_size.xy; 85 | float aspect = image_size.x/image_size.y; 86 | norm_pos.x *= aspect; 87 | norm_pos *= noise_scale; 88 | 89 | float out_val = snoise(norm_pos)*0.5+0.5; 90 | 91 | out_val = smoothstep(cutoff_low, cutoff_high, out_val); 92 | 93 | color = vec4(out_val,out_val,out_val,1.0); 94 | } -------------------------------------------------------------------------------- /synthrain/shaders/refract.frag: -------------------------------------------------------------------------------- 1 | #version 430 core 2 | uniform sampler2D bg_tex; 3 | uniform sampler2D drop_tex; 4 | 5 | uniform vec2 u_texel = {1/1440.0f,1/1080.0f}; 6 | 7 | uniform float u_alphaMultiply = 10; 8 | uniform float u_alphaSubtract = 1; 9 | uniform float u_minRefraction = 2; 10 | uniform float u_refractionDelta = 1.f; 11 | 12 | in vec2 UV; 13 | in float depth; 14 | out vec4 color; 15 | 16 | layout(binding = 1, offset = 0) uniform atomic_uint bokeh_count; 17 | 18 | layout(std430, binding = 1) buffer bokeh_points 19 | { 20 | vec4 bokeh[]; 21 | }; 22 | 23 | 24 | vec4 blend(vec4 bg,vec4 fg){ 25 | vec3 bgm=bg.rgb*bg.a; 26 | vec3 fgm=fg.rgb*fg.a; 27 | float ia=1.0-fg.a; 28 | float a=(fg.a + bg.a * ia); 29 | vec3 rgb; 30 | if(a!=0.0){ 31 | rgb=(fgm + bgm * ia) / a; 32 | }else{ 33 | rgb=vec3(0.0,0.0,0.0); 34 | } 35 | return vec4(rgb,a); 36 | } 37 | 38 | vec3 filterNormal(sampler2D bilinearSampler, vec2 uv) 39 | { 40 | vec3 h; 41 | vec3 v; 42 | h[0] = texture2D(bilinearSampler, uv + u_texel*vec2(-1, 0)).a; 43 | h[1] = texture2D(bilinearSampler, uv).a; 44 | h[2] = texture2D(bilinearSampler, uv + u_texel*vec2( 1, 0)).a; 45 | v[0] = texture2D(bilinearSampler, uv + u_texel*vec2( 0,-1)).a; 46 | v[1] = h[1]; 47 | v[2] = texture2D(bilinearSampler, uv + u_texel*vec2( 0, 1)).a; 48 | vec3 n; 49 | n.z =((v[0] - v[1]) + (v[1] - v[2])) /2.0f; 50 | n.x = ((h[0] - h[1]) + (h[1] - h[2])) /2.0f; 51 | n.y = 2; 52 | 53 | return normalize(n); 54 | } 55 | 56 | 57 | void main() 58 | { 59 | vec4 dropmap = texture2D(drop_tex, UV); 60 | dropmap.rgb /= dropmap.a; 61 | float thickness = 0; 62 | vec2 refraction = (vec2(dropmap.g-0.5f, dropmap.r-0.5f)); 63 | vec2 refractionPos = UV + ((u_minRefraction+(thickness*u_refractionDelta))-sin(dropmap.a*(3.14159265359f/2)))*refraction;//*refraction*refraction; 64 | float alpha = clamp(dropmap.a*u_alphaMultiply-u_alphaSubtract, 0.0, 1.0); 65 | 66 | vec4 drops = vec4(texture2D(bg_tex, refractionPos).rgb, alpha); 67 | vec4 bg = texture2D(bg_tex, UV); 68 | 69 | color = vec4(drops.rgb, drops.a); 70 | float luma = dot(color.rgb, vec3(0.299, 0.587, 0.114)); 71 | if( alpha > 0) 72 | { 73 | uint index = atomicCounterIncrement(bokeh_count); 74 | index %= 256000; 75 | bokeh[index] = vec4(UV.xy, luma,dropmap.a); 76 | } 77 | 78 | 79 | } -------------------------------------------------------------------------------- /synthrain/shaders/scatter.frag: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | layout(binding = 0) uniform sampler2D tex; 3 | layout(binding = 1) uniform sampler2D depth; 4 | uniform vec2 resolution = vec2(960,960); 5 | uniform vec2 direction = vec2(1,0); 6 | 7 | uniform float far_fog_plane = 0.007f; 8 | uniform float near_fog_plane = 0.024f; 9 | uniform float density = 1; 10 | uniform float distance_pow = 1; 11 | 12 | in vec2 UV; 13 | out vec4 color; 14 | 15 | vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) { 16 | vec4 color = vec4(0.0); 17 | vec2 off1 = vec2(1.3846153846) * direction; 18 | vec2 off2 = vec2(3.2307692308) * direction; 19 | color += texture2D(image, uv) * 0.2270270270; 20 | color += texture2D(image, uv + (off1 / resolution)) * 0.3162162162; 21 | color += texture2D(image, uv - (off1 / resolution)) * 0.3162162162; 22 | color += texture2D(image, uv + (off2 / resolution)) * 0.0702702703; 23 | color += texture2D(image, uv - (off2 / resolution)) * 0.0702702703; 24 | return color; 25 | } 26 | 27 | void main() 28 | { 29 | float distance = clamp(texture2D(depth, UV).r,far_fog_plane,near_fog_plane); 30 | float distance_scaled = log(1/((distance-far_fog_plane)/(near_fog_plane-far_fog_plane))); 31 | float fog = 1-(1/exp((distance_scaled*distance_scaled*density))); 32 | 33 | color = blur9(tex, UV, resolution, direction*fog); 34 | // color = vec4(direction*fog,0,1) ; 35 | 36 | // fog *= fog_color_scale; 37 | // color = vec4((1-fog)*color.rgb + fog*fog_brightness*vec3(1,1,1),1); 38 | } -------------------------------------------------------------------------------- /synthrain/sort_bokeh.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern "C" void sort_pixels(size_t num_pixels); 8 | extern "C" void register_buffer(GLuint buffer); 9 | 10 | static GLuint bufferObj; 11 | static cudaGraphicsResource *resource; 12 | 13 | struct sort_functor 14 | { 15 | __host__ __device__ 16 | bool operator()(float4 left, float4 right) const 17 | { 18 | return (left.z < right.z); 19 | } 20 | }; 21 | 22 | extern "C" 23 | void sort_pixels(size_t num_pixels) { 24 | cudaGraphicsMapResources(1, &resource, NULL); 25 | float4* devPtr; 26 | size_t size; 27 | 28 | cudaGraphicsResourceGetMappedPointer((void**)&devPtr, &size, resource); 29 | thrust::device_ptr tptr = thrust::device_pointer_cast(devPtr); 30 | thrust::sort(tptr, tptr + (num_pixels), sort_functor()); 31 | cudaGraphicsUnmapResources(1, &resource, NULL); 32 | } 33 | 34 | extern "C" 35 | void register_buffer(GLuint buffer) 36 | { 37 | bufferObj = buffer; 38 | cudaGraphicsGLRegisterBuffer(&resource, bufferObj, cudaGraphicsMapFlagsNone); 39 | } 40 | -------------------------------------------------------------------------------- /synthrain/synthrain.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 | {04702296-C413-4849-B508-7ADC7827242D} 24 | eyes4windows 25 | 10.0.16299.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Level4 77 | Disabled 78 | true 79 | true 80 | stdcpp17 81 | NO_CUDA;_UNICODE;UNICODE;%(PreprocessorDefinitions) 82 | 83 | 84 | Windows 85 | $(VcpkgRoot)lib\manual-link\sdl2main.lib;opengl32.lib;%(AdditionalDependencies) 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | true 93 | true 94 | stdcpp17 95 | 96 | 97 | Windows 98 | cudart_static.lib;$(VcpkgRoot)lib\manual-link\sdl2main.lib;opengl32.lib;%(AdditionalDependencies) 99 | 100 | 101 | 102 | 103 | Level3 104 | MaxSpeed 105 | true 106 | true 107 | true 108 | true 109 | stdcpp17 110 | 111 | 112 | true 113 | true 114 | $(VcpkgRoot)lib\manual-link\sdl2main.lib;opengl32.lib;%(AdditionalDependencies) 115 | Windows 116 | 117 | 118 | 119 | 120 | Level3 121 | MaxSpeed 122 | true 123 | true 124 | true 125 | true 126 | stdcpp17 127 | NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) 128 | 129 | 130 | true 131 | true 132 | Windows 133 | cudart_static.lib;$(VcpkgRoot)lib\manual-link\sdl2main.lib;opengl32.lib;%(AdditionalDependencies) 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 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 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /synthrain/synthrain.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;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 | {c92087b0-c439-41b2-8df2-aa1e326dc3eb} 18 | 19 | 20 | {d0af575d-18f5-4082-aca1-2211e253a001} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | imgui 29 | 30 | 31 | imgui 32 | 33 | 34 | imgui 35 | 36 | 37 | imgui 38 | 39 | 40 | imgui 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 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 | Source Files 77 | 78 | 79 | Source Files 80 | 81 | 82 | Source Files 83 | 84 | 85 | Source Files 86 | 87 | 88 | Source Files 89 | 90 | 91 | 92 | 93 | imgui 94 | 95 | 96 | imgui 97 | 98 | 99 | imgui 100 | 101 | 102 | imgui 103 | 104 | 105 | imgui 106 | 107 | 108 | imgui 109 | 110 | 111 | imgui 112 | 113 | 114 | imgui 115 | 116 | 117 | Header Files 118 | 119 | 120 | Header Files 121 | 122 | 123 | Header Files 124 | 125 | 126 | Header Files 127 | 128 | 129 | Header Files 130 | 131 | 132 | Header Files 133 | 134 | 135 | Header Files 136 | 137 | 138 | Header Files 139 | 140 | 141 | Header Files 142 | 143 | 144 | Header Files 145 | 146 | 147 | Source Files 148 | 149 | 150 | Header Files 151 | 152 | 153 | Header Files 154 | 155 | 156 | Header Files 157 | 158 | 159 | Header Files 160 | 161 | 162 | Header Files 163 | 164 | 165 | Header Files 166 | 167 | 168 | Header Files 169 | 170 | 171 | Header Files 172 | 173 | 174 | 175 | 176 | 177 | shaders 178 | 179 | 180 | shaders 181 | 182 | 183 | shaders 184 | 185 | 186 | shaders 187 | 188 | 189 | shaders 190 | 191 | 192 | shaders 193 | 194 | 195 | shaders 196 | 197 | 198 | shaders 199 | 200 | 201 | shaders 202 | 203 | 204 | shaders 205 | 206 | 207 | shaders 208 | 209 | 210 | shaders 211 | 212 | 213 | shaders 214 | 215 | 216 | shaders 217 | 218 | 219 | shaders 220 | 221 | 222 | shaders 223 | 224 | 225 | 226 | 227 | 228 | --------------------------------------------------------------------------------