├── .gitignore ├── .gitmodules ├── INSTALL.txt ├── LICENSE ├── README.md ├── TODO.md ├── bin ├── config.json └── ui_config.json ├── premake5.lua ├── screenshots ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png └── 6.png └── src ├── Game ├── sun.cpp └── sun.h ├── Systems ├── atmosphere.cpp ├── atmosphere.h ├── planet.cpp ├── planet.h ├── water.cpp └── water.h ├── definitions.h ├── radar.cpp ├── radar_unix.cpp ├── radar_win32.cpp ├── sound.cpp ├── sound.h ├── tests.cpp └── tests.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.make 2 | *.exe 3 | *.dll 4 | *.ilk 5 | *.pdb 6 | *.exp 7 | *.obj 8 | *.so 9 | *.o 10 | *.a 11 | *.lib 12 | bin/.vs 13 | bin/radar.exe 14 | bin/radar 15 | radar/ 16 | tags 17 | obj/ 18 | *.sln 19 | *.vcxproj 20 | *.user 21 | *.filters 22 | *.log 23 | .vs/ 24 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/openal-soft"] 2 | path = ext/openal-soft 3 | url = https://github.com/kcat/openal-soft 4 | ignore = dirty 5 | [submodule "ext/rf"] 6 | path = ext/rf 7 | url = https://github.com/Adrien-radr/rf 8 | [submodule "bin/data"] 9 | path = bin/data 10 | url = https://github.com/Adrien-radr/radar-data 11 | -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | In order : 2 | 3 | git submodule update --init --recursive 4 | cd ext/openal-soft/build 5 | cmake .. 6 | [compile openal depending on platform] 7 | copy Release/OpenAL32.lib and x64/Release/OpenAL32.dll to ./ (ext/openal-soft/build) 8 | cd radar/ 9 | premake5 [platform] 10 | [compile radar] 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Adrien-radr 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Radar Engine 2 | A Physically based renderer in OpenGL/GLSL 4. 3 | 4 | **Warning** : This repo is in development and might not work out of the box depending on when you clone it. 5 | 6 | ![Screenshot 1](https://github.com/Adrien-radr/radar/blob/master/screenshots/1.png "Dev Screenshot 1") 7 | ![Screenshot 2](https://github.com/Adrien-radr/radar/blob/master/screenshots/2.png "Dev Screenshot 2") 8 | ![Screenshot 3](https://github.com/Adrien-radr/radar/blob/master/screenshots/3.png "Dev Screenshot 3") 9 | ![Screenshot 4](https://github.com/Adrien-radr/radar/blob/master/screenshots/4.png "Dev Screenshot 4") 10 | ![Screenshot 5](https://github.com/Adrien-radr/radar/blob/master/screenshots/5.png "Dev Screenshot 5") 11 | ![Screenshot 6](https://github.com/Adrien-radr/radar/blob/master/screenshots/6.png "Dev Screenshot 6") 12 | 13 | ## Features 14 | - OpenGL 4.x / GLSL(400) rendering engine 15 | - Physically based rendering (GGX and Lambertian diffuse) with albedo/specular-roughness/normal maps 16 | - Ocean rendering 17 | - Atmospheric scattering with time of day (Sun + Moon) 18 | - Immediate mode GUI inspired by dear-imgui 19 | - GLTF Model suport 20 | - Basic OpenAL support 21 | 22 | ## TODO 23 | - Unifying ocean and atmosphere rendering for smooth water to sky transition 24 | 25 | ## Sources 26 | This repository contains an implementation of those papers, amongst other things : 27 | - [Simulating Ocean Water](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.161.9102&rep=rep1&type=pdf) - Jerry Tessendorf (1999) 28 | - [Precomputed Atmospheric Scattering](https://hal.inria.fr/inria-00288758/document) - Eric Bruneton, Fabrice Neyret (2008) 29 | 30 | ## Used libraries 31 | - [GLEW](https://github.com/nigels-com/glew) 32 | - [GLFW 3](http://www.glfw.org/) 33 | - [CJSON](https://github.com/DaveGamble/cJSON) 34 | - [OpenAL](https://github.com/kcat/openal-soft) 35 | - [STB Image & Truetype](https://github.com/nothings/stb) 36 | - [Tiny GLTF](https://github.com/syoyo/tinygltf) 37 | - [SFMT](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/) 38 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ### General 2 | + ~~Refactor Water code somewhere~~ 3 | + ~~Think about compiling .cpp's separately --> No~~ 4 | + ~~Fix OpenAL using Jack by default when building it on Debian, wtf is this shit. Turns out it's 5 | just trying to connect to jack before the other drivers and jack is verbose...~~ 6 | + ~~Remove all {m,c}alloc from the code except the Pools creation~~ 7 | + Fast, Deterministic Random Variable system --> SFMT, WIP 8 | + ~~Add an UI watch for all pools, describing how full they are each frame~~ 9 | + ~~Resource manager (Fonts, Images, ...)~~ 10 | + 3D axis object to show the coordinate system in the scene 11 | - ~~RF Memory revamp (Pool, Arena, dynamic buffers, hash maps, remove STL data structures dependencies)~~ 12 | 13 | ### Rendering 14 | + Fix the .HDR Envmap loading. There seem to be a mixup at the poles between the south and north. 15 | + ~~PBR using irradiance map~~ 16 | + ~~Specular IBL~~ 17 | 18 | ### UI 19 | + ~~2D Panel creation with custom shader~~ 20 | + ~~1 VS / 1 FS : pos, tex, color~~ 21 | + ~~1 VBO per panel~~ 22 | + ~~Z depth layering~~ 23 | + ~~Transparency~~ 24 | - When word wrapping with a maxWidth for display texts : wrap at spaces, not inside words 25 | + Display textures in panel (e.g. gbuffers display) 26 | + ~~Color theme for panels, borders, text color, ...~~ 27 | - JSON UI descriptor 28 | 29 | ### Water 30 | - Underwater render 31 | - Underwater background screen quad at infinity when nothing intersected 32 | - Godrays 33 | - Caustics on ocean floor 34 | - Screenspace solution 35 | - Screen-space partitionned in horiz. slabs to allow different LODs (no transparency & other 36 | demanding effects for far away water) 37 | - Screen-space quad projected onto y=0 and FFT/sim done by compute shaders ? 38 | - ~~Water Beaufort Scale States~~ 39 | - ~~4/5 States, with precomputed HTidle0 (and other init data)~~ 40 | - ~~Interpolation between states at runtime~~ 41 | - ~~Fix Scaling bug.~~ 42 | - Water / Boat / Objects collision and interactions (Gamasutra & Black Flag articles) 43 | -------------------------------------------------------------------------------- /bin/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "iWindowX": 200, 3 | "iWindowY": 200, 4 | "iWindowWidth": 1280, 5 | "iWindowHeight": 720, 6 | "iMSAA": 0, 7 | "bFullScreen": 0, 8 | "bVSync": 0, 9 | "fFOV": 75.0, 10 | "fNearPlane": 0.001, 11 | "fFarPlane": 10000.0, 12 | "iAnisotropicFiltering": 16, 13 | 14 | "fCameraSpeedBase": 40.0, 15 | "vCameraSpeedMult": [ 0.05, 1.0, 20.0, 20000.0 ], 16 | "fCameraSpeedAngular": 0.3, 17 | 18 | "vCameraPosition": [ 0, 6360100, 0 ], 19 | 20 | "fTimeScale": 30.0 21 | } 22 | -------------------------------------------------------------------------------- /bin/ui_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Red" : [ 1, 0, 0, 1 ], 3 | "Green" : [ 0, 1, 0, 1 ], 4 | "Blue" : [ 0, 0, 1, 1 ], 5 | "Black" : [ 0, 0, 0, 1 ], 6 | "White" : [ 1, 1, 1, 1 ], 7 | 8 | "ConsoleBG" : [ 0, 0, 0, 0.7 ], 9 | "PanelBG" : [ 0, 0, 0, 0.5 ], 10 | "PanelFG" : [ 0.8, 0.8, 0.8, 1 ], 11 | "TitlebarBG" : [ 1, 1, 1, 0.1 ], 12 | "BorderBG" : [ 1, 1, 1, 0.20 ], 13 | "ConsoleFG" : [ 1, 1, 1, 0.9 ], 14 | "SliderBG" : [ 1, 1, 1, 0.2 ], 15 | "SliderFG" : [ 0, 0, 0, 0.6 ], 16 | "ProgressbarBG" : [ 0, 0, 0, 0.2 ], 17 | "ProgressbarFG" : [ 1, 1, 1, 0.1 ], 18 | 19 | "ButtonBG" : [ 1, 1, 1, 0.1 ], 20 | "ButtonPressedBG" : [ 1, 1, 1, 0.05 ], 21 | 22 | "DebugFG" : [ 1, 1, 1, 1 ], 23 | 24 | "ConsoleFont" : [ "data/Roboto-Regular.ttf", 13 ], 25 | "DefaultFont" : [ "data/Roboto-Regular.ttf", 13 ], 26 | "AwesomeFont" : [ "data/fontawesome.ttf", 32 ] 27 | } 28 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | -- Copy ext/rf/premake5.lua script as rf.lua to be able to include it 2 | os.copyfile("ext/rf/premake5.lua", "ext/rf/rf.lua") 3 | 4 | require "ext/rf" 5 | 6 | workspace "Radar" 7 | language "C++" 8 | cppdialect "C++11" 9 | architecture "x86_64" 10 | 11 | platforms { "Windows", "Unix" } 12 | configurations { "Debug", "Release", "ReleaseDbg" } 13 | 14 | filter "configurations:Debug" 15 | defines { "DEBUG" } 16 | symbols "On" 17 | 18 | filter "configurations:Release" 19 | optimize "On" 20 | 21 | filter "configurations:ReleaseDbg" 22 | optimize "Debug" 23 | buildoptions { "-fno-omit-frame-pointer" } 24 | 25 | filter "platforms:Windows" 26 | buildoptions { "-W4" } 27 | 28 | filter "platforms:Unix" 29 | buildoptions { "-Wall" } 30 | 31 | filter {} 32 | 33 | externalproject "glfw3" 34 | kind "StaticLib" 35 | location "ext/rf" 36 | targetdir "ext/rf/lib" 37 | 38 | externalproject "rf" 39 | kind "StaticLib" 40 | location "ext/rf" 41 | targetdir "ext/rf/lib" 42 | includedirs { "ext/rf/ext/glfw/include" } 43 | 44 | project "radar" 45 | kind "ConsoleApp" 46 | targetdir "bin/" 47 | debugdir "bin/" 48 | defines { "GLEW_STATIC" } 49 | defines { "HAVE_SSE2=1" } 50 | 51 | files { "src/**.cpp", "src/**.h" } 52 | removefiles { "src/radar_unix.cpp", "src/radar_win32.cpp" } 53 | includedirs { "src", "ext/rf/include", "ext/rf/ext/cjson", "ext/openal-soft/include", 54 | "ext/rf/ext/glew/include", "ext/rf/ext/glfw/include" } 55 | 56 | libdirs { "ext/rf/lib", "ext/openal-soft/build" } 57 | 58 | filter "configurations:Debug" 59 | links { "rf_d", "glfw3_d" } 60 | 61 | filter "configurations:ReleaseDbg" 62 | links { "rf_p", "glfw3_p" } 63 | 64 | filter { "configurations:Release" } 65 | links { "rf", "glfw3" } 66 | 67 | filter "platforms:Windows" 68 | libdirs{ "ext/openal-soft/build/Release" } 69 | links { "openal32", "opengl32", "PowrProf" } 70 | 71 | filter "platforms:Unix" 72 | links { "openal", "GL", "X11", "dl", "pthread" } 73 | 74 | filter {} -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrien-radr/radar/69d03f8362ee8d5743d0707b786a75911cec8aaa/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrien-radr/radar/69d03f8362ee8d5743d0707b786a75911cec8aaa/screenshots/2.png -------------------------------------------------------------------------------- /screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrien-radr/radar/69d03f8362ee8d5743d0707b786a75911cec8aaa/screenshots/3.png -------------------------------------------------------------------------------- /screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrien-radr/radar/69d03f8362ee8d5743d0707b786a75911cec8aaa/screenshots/4.png -------------------------------------------------------------------------------- /screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrien-radr/radar/69d03f8362ee8d5743d0707b786a75911cec8aaa/screenshots/5.png -------------------------------------------------------------------------------- /screenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrien-radr/radar/69d03f8362ee8d5743d0707b786a75911cec8aaa/screenshots/6.png -------------------------------------------------------------------------------- /src/Game/sun.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sun.h" 3 | #include "rf/context.h" 4 | 5 | static vec3f CameraDefaultPos(0, 0, 0); 6 | 7 | namespace game { 8 | // In meters 9 | const real32 EarthRadius = 6.3710088e6f; 10 | const real32 SunDistance = 1.496e11f; 11 | 12 | void InitCamera(camera *Camera, config *Config) 13 | { 14 | Camera->Position = Config->CameraPosition; 15 | CameraDefaultPos = Config->CameraPosition; 16 | Camera->PositionDecimal = vec3f(0, 0, 0); 17 | Camera->Forward = Config->CameraForward; 18 | Camera->Up = vec3f(0, 1, 0); 19 | Camera->Right = Normalize(Cross(Camera->Forward, Camera->Up)); 20 | Camera->Up = Normalize(Cross(Camera->Right, Camera->Forward)); 21 | //Camera->Target = Camera->Position + Camera->Forward; 22 | Camera->LinearSpeed = Config->CameraSpeedBase; 23 | Camera->AngularSpeed = Config->CameraSpeedAngular; 24 | for (int i = 0; i < 4; ++i) 25 | { 26 | Camera->SpeedMult[i] = Config->CameraSpeedMult[i]; 27 | } 28 | Camera->SpeedMode = 0; 29 | Camera->FreeflyMode = false; 30 | 31 | vec2f Spherical = CartesianToSpherical(Camera->Forward); 32 | Camera->Theta = Spherical.x; 33 | Camera->Phi = Spherical.y; 34 | #if 0 35 | vec2f Azimuth = Normalize(vec2f(Camera->Forward[0], Camera->Forward[2])); 36 | Camera->Phi = atan2f(Azimuth.y, Azimuth.x); 37 | Camera->Theta = atan2f(Camera->Forward.y, sqrtf(Dot(Azimuth, Azimuth))); 38 | #endif 39 | } 40 | 41 | bool Init(state *State, config *Config) 42 | { 43 | State->TextLineCount = 0; 44 | State->EngineTime = 0.0; 45 | State->Counter = 0.1; // init those past their reset time to not have to wait the reset time at game start 46 | State->CounterTenth = 0.1; 47 | State->DisableMouse.Switch(); // Set On 48 | 49 | InitCamera(&State->Camera, Config); 50 | 51 | State->Latitude = 5.345317f * DEG2RAD; 52 | State->EarthTilt = 23.43f * DEG2RAD; 53 | State->SunSpeed = Config->TimeScale * (M_PI / 86400.f); 54 | State->SunDirection = SphericalToCartesian(0.46f * M_PI, M_TWO_PI * 0.37f); 55 | State->LightColor = vec4f(1.0f, 0.6f, 0.5f, 1.0f); 56 | State->WaterCounter = 0.0; 57 | State->WaterStateInterp = 0.f; 58 | State->WaterState = 1; 59 | State->WaterDirection = 0.f; 60 | 61 | return true; 62 | } 63 | 64 | static void UpdateUI(state *State, rf::input *Input, rf::context *Context) 65 | { 66 | //int32 TextlineCount = 4; 67 | State->TextLineCount = 5; // 0 : Camera Pos, 1, Camera movement, 2 : FPS/Mouse, 3 : Water, 4 : Atmosphere 68 | 69 | if (State->CounterTenth >= 0.1) 70 | { 71 | const camera &Camera = State->Camera; 72 | State->Textline[0].Position = vec2i(4, 4); 73 | State->Textline[0].Color = rf::ui::COLOR_DEBUGFG; 74 | 75 | snprintf(State->Textline[0].String, UI_STRINGLEN, "Camera : <%.0f, %.0f, %.0f> <%.4f, %.4f, %.4f> <%.2f, %.2f>", 76 | Camera.Position.x, Camera.Position.y, Camera.Position.z, 77 | Camera.PositionDecimal.x, Camera.PositionDecimal.y, Camera.PositionDecimal.z, 78 | Camera.Theta, Camera.Phi); 79 | 80 | State->Textline[1].Position = vec2i(4, 18); 81 | State->Textline[1].Color = rf::ui::COLOR_DEBUGFG; 82 | 83 | State->Textline[2].Position = vec2i(4, 32); 84 | State->Textline[2].Color = rf::ui::COLOR_DEBUGFG; 85 | 86 | snprintf(State->Textline[2].String, UI_STRINGLEN, "%2.4g, Mouse: %d,%d", 1.0 / Input->dTime, Input->MousePosX, Input->MousePosY); 87 | 88 | State->CounterTenth = 0.0; 89 | } 90 | 91 | if (State->Counter >= 0.75) 92 | { 93 | State->Textline[3].Position = vec2i(4, 46); 94 | State->Textline[3].Color = rf::ui::COLOR_DEBUGFG; 95 | 96 | snprintf(State->Textline[3].String, UI_STRINGLEN, "Water State : %d Water Interpolant : %g", State->WaterState, State->WaterStateInterp); 97 | 98 | State->Textline[4].Color = rf::ui::COLOR_DEBUGFG; 99 | State->Textline[4].Position = vec2i(4, 60); 100 | 101 | int CharWritten = snprintf(State->Textline[4].String, UI_STRINGLEN, "Sun Speed : %.3f", State->SunSpeed); 102 | 103 | if (State->IsNight) 104 | snprintf(State->Textline[4].String + CharWritten, UI_STRINGLEN - CharWritten, " Day"); 105 | else 106 | snprintf(State->Textline[4].String + CharWritten, UI_STRINGLEN - CharWritten, " Night"); 107 | 108 | State->Counter = 0.0; 109 | } 110 | 111 | 112 | int32 LineGap = rf::ui::GetFontLineGap(rf::ui::FONT_DEFAULT); 113 | 114 | int UIStackHeight = LineGap * State->TextLineCount; 115 | static uint32 UIStackPanel = 0; 116 | static vec3i UIStackPanelPos(0, 0, 0); 117 | static vec2i UIStackPanelSize(400, UIStackHeight + 20); 118 | rf::ui::BeginPanel(&UIStackPanel, "", &UIStackPanelPos, &UIStackPanelSize, rf::ui::COLOR_PANELBG, rf::ui::DECORATION_NONE); 119 | for (int32 i = 0; i < State->TextLineCount; ++i) 120 | { 121 | rf::ui::text_line *Line = &State->Textline[i]; 122 | rf::ui::MakeText((void*)Line, Line->String, rf::ui::FONT_DEFAULT, Line->Position, Line->Color, 1.f, Context->WindowWidth); 123 | } 124 | rf::ui::EndPanel(); 125 | } 126 | 127 | void MovePlayer(state *State, rf::input *Input, rf::context *Context) 128 | { 129 | camera &Camera = State->Camera; 130 | vec2i MousePos = vec2i(Input->MousePosX, Input->MousePosY); 131 | 132 | // Camera reset pos 133 | if (KEY_RELEASED(Input->Keys[KEY_Z]) && KEY_PRESSED(Input->Keys[KEY_LEFT_CONTROL])) 134 | { 135 | Camera.Position = CameraDefaultPos; 136 | Camera.PositionDecimal = vec3f(0); 137 | } 138 | 139 | vec3f CameraMove(0, 0, 0); 140 | if (KEY_PRESSED(Input->Keys[KEY_W])) CameraMove += Camera.Forward; 141 | if (KEY_PRESSED(Input->Keys[KEY_S])) CameraMove -= Camera.Forward; 142 | if (KEY_PRESSED(Input->Keys[KEY_A])) CameraMove -= Camera.Right; 143 | if (KEY_PRESSED(Input->Keys[KEY_D])) CameraMove += Camera.Right; 144 | if (KEY_PRESSED(Input->Keys[KEY_R])) CameraMove += Camera.Up; 145 | if (KEY_PRESSED(Input->Keys[KEY_F])) CameraMove -= Camera.Up; 146 | 147 | if (KEY_PRESSED(Input->Keys[KEY_LEFT_SHIFT])) 148 | { 149 | if (KEY_PRESSED(Input->Keys[KEY_LEFT_CONTROL])) 150 | { // Super Speed 151 | Camera.SpeedMode = 3; 152 | } 153 | else 154 | { 155 | Camera.SpeedMode = 2; 156 | } 157 | } 158 | else if (KEY_PRESSED(Input->Keys[KEY_LEFT_CONTROL])) 159 | { 160 | Camera.SpeedMode = 0; 161 | } 162 | else 163 | { 164 | Camera.SpeedMode = 1; 165 | } 166 | 167 | Normalize(CameraMove); 168 | real32 SpeedMult = Camera.SpeedMult[Camera.SpeedMode]; 169 | CameraMove *= (real32)(Input->dTime * Camera.LinearSpeed * SpeedMult); 170 | 171 | // Move the camera decimal point, add the floored integer part to the full Camera Position 172 | Camera.PositionDecimal += CameraMove; 173 | vec3i IntegerPos((int)floor(Camera.PositionDecimal.x), (int)floor(Camera.PositionDecimal.y), (int)floor(Camera.PositionDecimal.z)); 174 | Camera.PositionDecimal -= IntegerPos; 175 | Camera.Position += IntegerPos; 176 | 177 | // UI for camera movement 178 | snprintf(State->Textline[1].String, UI_STRINGLEN, "Move : <%.4f, %.4f, %.4f>", CameraMove.x, CameraMove.y, CameraMove.z); 179 | 180 | //Camera.Position.y = Max(0.5f, Camera.Position.y); // Min at .5 meters 181 | 182 | if (MOUSE_HIT(Input->MouseRight)) 183 | { 184 | Camera.FreeflyMode = true; 185 | State->DisableMouse.Switch(); 186 | Camera.LastMousePos = MousePos; 187 | } 188 | if (MOUSE_RELEASED(Input->MouseRight)) 189 | { 190 | Camera.FreeflyMode = false; 191 | State->DisableMouse.Switch(); 192 | } 193 | 194 | if (Camera.FreeflyMode) 195 | { 196 | vec2i MouseOffset = MousePos - Camera.LastMousePos; 197 | Camera.LastMousePos = MousePos; 198 | 199 | if (MouseOffset.x != 0 || MouseOffset.y != 0) 200 | { 201 | Camera.Phi += real32(MouseOffset.x * Input->dTime * Camera.AngularSpeed); 202 | Camera.Theta += real32(MouseOffset.y * Input->dTime * Camera.AngularSpeed); 203 | 204 | if (Camera.Phi > M_TWO_PI) Camera.Phi -= M_TWO_PI; 205 | if (Camera.Phi < 0.0f) Camera.Phi += M_TWO_PI; 206 | 207 | Camera.Theta = std::max(1e-5f, std::min(real32(M_PI) - 1e-5f, Camera.Theta)); 208 | Camera.Forward = SphericalToCartesian(Camera.Theta, Camera.Phi); 209 | 210 | Camera.Right = Normalize(Cross(Camera.Forward, vec3f(0, 1, 0))); 211 | Camera.Up = Normalize(Cross(Camera.Right, Camera.Forward)); 212 | } 213 | } 214 | 215 | //Camera.Target = Camera.Position + Camera.Forward; 216 | vec3f CameraFullPosition = Camera.Position + Camera.PositionDecimal; 217 | Camera.ViewMatrix = mat4f::LookAtPrecise(CameraFullPosition, Camera.Forward, Camera.Right, Camera.Up); 218 | 219 | // Mouse cursor disabling when in Freefly 220 | if (State->DisableMouse.Switched()) 221 | { 222 | if (State->DisableMouse) 223 | { 224 | rf::ctx::ShowCursor(Context, false); 225 | } 226 | else 227 | { 228 | rf::ctx::ShowCursor(Context, true); 229 | } 230 | 231 | State->DisableMouse.Update(); 232 | } 233 | } 234 | 235 | void UpdateSky(game::state *State, rf::input *Input) 236 | { 237 | State->DayPhase = fmod(State->DayPhase + State->SunSpeed * M_PI * (real32)Input->dTime, 2.f * M_PI); 238 | 239 | 240 | real32 CosET = cosf(State->EarthTilt); 241 | 242 | vec3f SunPos(SunDistance * CosET * cosf(State->DayPhase) - EarthRadius * cosf(State->Latitude), 243 | SunDistance * sinf(State->EarthTilt) - EarthRadius * sinf(State->Latitude), 244 | SunDistance * CosET * sinf(State->DayPhase)); 245 | mat4f Rot; 246 | Rot = Rot.RotateZ(M_PI_OVER_TWO - State->Latitude); 247 | SunPos = Rot * SunPos; 248 | 249 | //snprintf(Msg, CONSOLE_STRINGLEN, "%e %e %e", Rot[1][1], SunPos.y, SunPos.z); 250 | //LogString(System->ConsoleLog, Msg); 251 | 252 | if (State->IsNight && SunPos.y > 0.f) { 253 | State->IsNight = false; 254 | } 255 | if (!State->IsNight && SunPos.y < 0.f) { 256 | State->IsNight = true; 257 | } 258 | 259 | State->SunDirection = Normalize(SunPos); 260 | //State->LightColor = vec4f(0.9f, 0.7, 0.8, 1.0f); 261 | State->LightColor = vec4f(2.7f, 2.1f, 2.4f, 1.0f); 262 | } 263 | 264 | void Update(state *State, rf::input *Input, rf::context *Context) 265 | { 266 | State->Counter += Input->dTime; 267 | State->CounterTenth += Input->dTime; 268 | 269 | UpdateUI(State, Input, Context); 270 | 271 | MovePlayer(State, Input, Context); 272 | 273 | // Water state 274 | #if 0 275 | if (KEY_DOWN(Input->Keys[KEY_KP_ADD])) 276 | { 277 | State->WaterStateInterp = State->WaterStateInterp + 0.01; 278 | 279 | if (State->WaterState < (water_system::BeaufortStateCount - 2)) 280 | { 281 | if (State->WaterStateInterp >= 1.f) 282 | { 283 | State->WaterStateInterp -= 1.f; 284 | ++State->WaterState; 285 | } 286 | } 287 | else 288 | { 289 | State->WaterStateInterp = std::min(1.f, State->WaterStateInterp); 290 | } 291 | } 292 | 293 | if (KEY_DOWN(Input->Keys[KEY_KP_SUBTRACT])) 294 | { 295 | State->WaterStateInterp = State->WaterStateInterp - 0.01; 296 | 297 | if (State->WaterState > 0) 298 | { 299 | if (State->WaterStateInterp < 0.f) 300 | { 301 | State->WaterStateInterp += 1.f; 302 | --State->WaterState; 303 | } 304 | } 305 | else 306 | { 307 | State->WaterStateInterp = std::max(0.f, State->WaterStateInterp); 308 | } 309 | } 310 | #endif 311 | 312 | // Sun state 313 | if (Input->MouseDZ > 0) 314 | { 315 | // State->WaterDirection += Input->dTime * 0.05; 316 | State->SunSpeed += Input->MouseDZ * 0.0005f; 317 | } 318 | 319 | if (Input->MouseDZ < 0) 320 | { 321 | //State->WaterDirection -= Input->dTime * 0.05; 322 | State->SunSpeed += Input->MouseDZ * 0.0005f; 323 | } 324 | 325 | if (KEY_HIT(Input->Keys[KEY_P])) 326 | State->SunSpeed = 0.f; 327 | 328 | UpdateSky(State, Input); 329 | } 330 | 331 | void Destroy(state *State) 332 | { 333 | (void)State; 334 | } 335 | 336 | } 337 | 338 | #if 0 339 | 340 | void FillAudioBuffer(tmp_sound_data *SoundData) 341 | { 342 | uint32 ToneHz = 440; 343 | uint32 ALen = 40 * ToneHz; 344 | 345 | SoundData->SoundBufferSize = ALen; 346 | uint32 Size = SoundData->SoundBufferSize; 347 | 348 | for (uint32 i = 0; i < ALen; ++i) 349 | { 350 | real32 Angle = 2.f * M_PI * i / (real32)ToneHz; 351 | uint16 Value = (uint16)(10000 * sinf(Angle)); 352 | // NOTE = Temp : no sound 353 | Value = 0; 354 | SoundData->SoundBuffer[i] = Value; 355 | } 356 | } 357 | 358 | void GameInitialization(game_memory *Memory) 359 | { 360 | FillAudioBuffer(System->SoundData); 361 | System->SoundData->ReloadSoundBuffer = true; 362 | } 363 | 364 | 365 | 366 | DLLEXPORT GAMEUPDATE(GameUpdate) 367 | { 368 | 369 | #if 0 370 | if (Input->KeyReleased) 371 | { 372 | tmp_sound_data *SoundData = System->SoundData; 373 | FillAudioBuffer(SoundData); 374 | SoundData->ReloadSoundBuffer = true; 375 | } 376 | #endif 377 | 378 | 379 | UpdateSky(Local, State, System, Input); 380 | } 381 | #endif 382 | -------------------------------------------------------------------------------- /src/Game/sun.h: -------------------------------------------------------------------------------- 1 | #ifndef SUN_H 2 | #define SUN_H 3 | 4 | #include "rf/ui.h" 5 | #include "definitions.h" 6 | 7 | namespace game { 8 | // Keeps a binary state with its previous state value 9 | struct binary_switch 10 | { 11 | binary_switch() : Current(false), Last(false) {} 12 | 13 | void Switch() { Current = !Current; } 14 | bool Switched() { return Current != Last; } 15 | void Update() { Last = Current; } 16 | operator bool() const { return Current; } 17 | 18 | private: 19 | bool Current; 20 | bool Last; 21 | }; 22 | 23 | // TODO - divide this with scene, etc 24 | struct state 25 | { 26 | real64 EngineTime; 27 | real64 dTime; 28 | camera Camera; 29 | binary_switch DisableMouse; 30 | vec4f LightColor; 31 | 32 | real64 WaterCounter; 33 | real32 WaterStateInterp; 34 | real32 WaterDirection; 35 | int WaterState; 36 | 37 | vec3f SunDirection; 38 | real32 SunSpeed; 39 | 40 | real64 Counter; 41 | real64 CounterTenth; 42 | bool IsNight; 43 | // DayPhase: 0 = noon, pi = midnight 44 | real32 DayPhase; 45 | // Varies with season 46 | real32 EarthTilt; 47 | // Latitude: -pi/2 = South pole, +pi/2 = North pole 48 | real32 Latitude; 49 | 50 | static int32 const TextlineCapacity = 16; 51 | int32 TextLineCount; 52 | rf::ui::text_line Textline[TextlineCapacity]; 53 | }; 54 | 55 | bool Init(state *State, config *Config); 56 | void Destroy(state *State); 57 | void Update(state *State, rf::input *Input, rf::context *Context); 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/Systems/atmosphere.cpp: -------------------------------------------------------------------------------- 1 | #include "atmosphere.h" 2 | #include "rf/context.h" 3 | #include "rf/utils.h" 4 | #include "Game/sun.h" 5 | #include "rf/color.h" 6 | 7 | #include 8 | 9 | #define USE_MOON 0 10 | #define PRECOMPUTE_STUFF 11 | 12 | namespace atmosphere 13 | { 14 | // Values from "Reference Solar Spectral Irradiance: ASTM G-173", ETR column 15 | // (see http://rredc.nrel.gov/solar/spectra/am1.5/ASTMG173/ASTMG173.html), 16 | // Values are in W.m-2.nm-1 17 | static const real32 kSolarIrradiance[48] = { 18 | 1.11776f, 1.14259f, 1.01249f, 1.14716f, 1.72765f, 1.73054f, 1.6887f, 1.61253f, 19 | 1.91198f, 2.03474f, 2.02042f, 2.02212f, 1.93377f, 1.95809f, 1.91686f, 1.8298f, 20 | 1.8685f, 1.8931f, 1.85149f, 1.8504f, 1.8341f, 1.8345f, 1.8147f, 1.78158f, 1.7533f, 21 | 1.6965f, 1.68194f, 1.64654f, 1.6048f, 1.52143f, 1.55622f, 1.5113f, 1.474f, 1.4482f, 22 | 1.41018f, 1.36775f, 1.34188f, 1.31429f, 1.28303f, 1.26758f, 1.2367f, 1.2082f, 23 | 1.18737f, 1.14683f, 1.12362f, 1.1058f, 1.07124f, 1.04992f 24 | }; 25 | 26 | // Values from "Precise Measurement of Lunar Spectral Irradiance at Visible Wavelengths" 27 | // (see https://www.researchgate.net/publication/272672351_Precise_Measurement_of_Lunar_Spectral_Irradiance_at_Visible_Wavelengths) 28 | // Values are in microW.m-2.nm-1 29 | static const real32 kLunarIrradiance[48] = { 30 | 0.1916f, 0.4312f, 0.6708f, 0.9104f, 1.15f, 1.3896f, 1.6292f, 1.8688f, 31 | 2.1084f, 2.348f, 2.3574f, 2.3668f, 2.3762f, 2.3856f, 2.395f, 2.4426f, 32 | 2.4902f, 2.5378f, 2.5854f, 2.633f, 2.6402f, 2.6474f, 2.6546f, 2.6618f, 2.669f, 33 | 2.6548f, 2.6406f, 2.6264f, 2.6122f, 2.598f, 2.5732f, 2.5484f, 2.5236f, 34 | 2.4988f, 2.474f, 2.442f, 2.41f, 2.378f, 2.346f, 2.314f, 2.2696f, 35 | 2.2252f, 2.1808f, 2.1364f, 2.092f, 2.0476f, 2.0032f // 0, 0, 1.870 36 | }; 37 | 38 | static const real32 kOzoneCrossSection[48] = { 39 | 1.18e-27f, 2.182e-28f, 2.818e-28f, 6.636e-28f, 1.527e-27f, 2.763e-27f, 5.52e-27f, 40 | 8.451e-27f, 1.582e-26f, 2.316e-26f, 3.669e-26f, 4.924e-26f, 7.752e-26f, 9.016e-26f, 41 | 1.48e-25f, 1.602e-25f, 2.139e-25f, 2.755e-25f, 3.091e-25f, 3.5e-25f, 4.266e-25f, 42 | 4.672e-25f, 4.398e-25f, 4.701e-25f, 5.019e-25f, 4.305e-25f, 3.74e-25f, 3.215e-25f, 43 | 2.662e-25f, 2.238e-25f, 1.852e-25f, 1.473e-25f, 1.209e-25f, 9.423e-26f, 7.455e-26f, 44 | 6.566e-26f, 5.105e-26f, 4.15e-26f, 4.228e-26f, 3.237e-26f, 2.451e-26f, 2.801e-26f, 45 | 2.534e-26f, 1.624e-26f, 1.465e-26f, 2.078e-26f, 1.383e-26f, 7.105e-27f 46 | }; 47 | 48 | 49 | 50 | /// Defined as "ExpTerm * exp(ExpScale * H) + LinearTerm * H + ConstantTerm" 51 | /// Clamped in [0,1] 52 | struct density_profile_layer 53 | { 54 | real32 Width; 55 | real32 ExpTerm; 56 | real32 ExpScale; 57 | real32 LinearTerm; 58 | real32 ConstantTerm; 59 | }; 60 | 61 | /// Atmosphere is made of several layers from bottom to top 62 | /// The height of the topmost layer is inconsequential as it extends always to the top of the atmosphere 63 | struct density_profile 64 | { 65 | density_profile_layer Layers[2]; 66 | }; 67 | 68 | struct atmosphere_parameters 69 | { 70 | real32 TopRadius; // distance between planet's center and top of atmosphere 71 | real32 BottomRadius; // distance between planet's center and bottom of atmosphere 72 | vec3f RayleighScattering; // scattering coefficient of air molecules at max density (function of wavelength) 73 | density_profile Rayleigh; // density profile of air molecules 74 | vec3f MieScattering; // scattering coefficient of aerosols at max density (function of wavelength) 75 | vec3f MieExtinction; // extinction coefficient of aerosols at max density (function of wavelength) 76 | density_profile Mie; // density profile of aerosols 77 | //vec3f AbsorptionScattering;// scattering coefficient of air molecules that absorb light at max density (function of wavelength) 78 | vec3f AbsorptionExtinction;// extinction coefficient of air molecules that absorb light at max density (function of wavelength); 79 | density_profile Absorption; // density profile of air molecules that absorb light (e.g. ozone) 80 | vec3f GroundAlbedo; // average albedo of the ground 81 | vec3f SolarIrradiance; // defined at the top of the atmosphere 82 | real32 SunAngularRadius; // < 0.1 radians 83 | real32 MiePhaseG; // asymmetry coefficient for the Mie phase function 84 | real32 MinMuS; // Cosine of the maximum sun zenith (102deg for earth, so that MinMuS = -0.208) 85 | 86 | }; 87 | 88 | radiance_mode RadianceMode = RGB; 89 | int NumPrecomputedWavelengths = RadianceMode == FULL ? 15 : 3; 90 | real32 DefaultWavelengths[] = { LAMBDA_R, LAMBDA_G, LAMBDA_B }; 91 | 92 | atmosphere_parameters AtmosphereParameters; 93 | rf::mesh ScreenQuad = {}; 94 | uint32 AtmosphereProgram = 0; 95 | uint32 TransmittanceTexture = 0; 96 | uint32 IrradianceTexture = 0; 97 | uint32 ScatteringTexture = 0; 98 | uint32 MoonAlbedoTexture = 0; 99 | 100 | vec3f WhitePoint(1.0f); 101 | 102 | static const vec2i kTransmittanceTextureSize = vec2i(256, 64); 103 | static const vec2i kIrradianceTextureSize = vec2i(64, 16); 104 | static const vec4i kScatteringTextureRMuMuSNuSize = vec4i(64, 128, 32, 8); 105 | static const vec3i kScatteringTextureSize = vec3i(kScatteringTextureRMuMuSNuSize.w * kScatteringTextureRMuMuSNuSize.z, kScatteringTextureRMuMuSNuSize.y, kScatteringTextureRMuMuSNuSize.x); 106 | 107 | static const real32 kLengthUnitInMeters = 1000.f; 108 | static const real32 kRayleighScaleHeight = 8000.f; 109 | static const real32 kRayleigh = 1.24062e-6f; 110 | static const real32 kMieScaleHeight = 1200.f; 111 | static const real32 kMieAngstromAlpha = 0.f; 112 | static const real32 kMieAngstromBeta = 5.328e-3f; // orig 5.328e-3 113 | static const real32 kMieSingleScatteringAlbedo = 0.9f; 114 | static const real32 kDobsonUnit = 2.687e20f; // From wiki, in molecules.m^-2 115 | static const real32 kMaxOzoneNumberDensity = 300.f * kDobsonUnit / 15000.f; // Max nb density of ozone molecules in m^-3, 300 DU integrated over the ozone density profile (15km) 116 | static const real32 kGroundAlbedo = 0.1f; // orig 0.1 117 | static const real32 kSunAngularRadius = 0.004675f; 118 | static const real32 kMoonAngularRadius = 0.018f;//0.004509f; 119 | static const real32 kSunSolidAngle = M_PI * kSunAngularRadius * kSunAngularRadius; 120 | static const real32 kMiePhaseG = USE_MOON ? 0.93f : 0.90f; 121 | static const real32 kMaxSunZenithAngle = DEG2RAD * 120.f; 122 | 123 | static void SendShaderUniforms(uint32 Program) 124 | { 125 | glUseProgram(Program); 126 | // TODO - Write the constants directly in the header (construct it from here), instead of this disgusting mess 127 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.BottomRadius"), AtmosphereParameters.BottomRadius / kLengthUnitInMeters); 128 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.TopRadius"), AtmosphereParameters.TopRadius / kLengthUnitInMeters); 129 | rf::SendVec3(glGetUniformLocation(Program, "Atmosphere.RayleighScattering"), AtmosphereParameters.RayleighScattering); 130 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[0].Width"), AtmosphereParameters.Rayleigh.Layers[0].Width / kLengthUnitInMeters); 131 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[0].ExpTerm"), AtmosphereParameters.Rayleigh.Layers[0].ExpTerm); 132 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[0].ExpScale"), AtmosphereParameters.Rayleigh.Layers[0].ExpScale * kLengthUnitInMeters); 133 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[0].LinearTerm"), AtmosphereParameters.Rayleigh.Layers[0].LinearTerm * kLengthUnitInMeters); 134 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[0].ConstantTerm"), AtmosphereParameters.Rayleigh.Layers[0].ConstantTerm); 135 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[1].Width"), AtmosphereParameters.Rayleigh.Layers[1].Width / kLengthUnitInMeters); 136 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[1].ExpTerm"), AtmosphereParameters.Rayleigh.Layers[1].ExpTerm); 137 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[1].ExpScale"), AtmosphereParameters.Rayleigh.Layers[1].ExpScale * kLengthUnitInMeters); 138 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[1].LinearTerm"), AtmosphereParameters.Rayleigh.Layers[1].LinearTerm * kLengthUnitInMeters); 139 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.RayleighDensity.Layers[1].ConstantTerm"), AtmosphereParameters.Rayleigh.Layers[1].ConstantTerm); 140 | rf::SendVec3(glGetUniformLocation(Program, "Atmosphere.MieExtinction"), AtmosphereParameters.MieExtinction); 141 | rf::SendVec3(glGetUniformLocation(Program, "Atmosphere.MieScattering"), AtmosphereParameters.MieScattering); 142 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[0].Width"), AtmosphereParameters.Mie.Layers[0].Width / kLengthUnitInMeters); 143 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[0].ExpTerm"), AtmosphereParameters.Mie.Layers[0].ExpTerm); 144 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[0].ExpScale"), AtmosphereParameters.Mie.Layers[0].ExpScale * kLengthUnitInMeters); 145 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[0].LinearTerm"), AtmosphereParameters.Mie.Layers[0].LinearTerm * kLengthUnitInMeters); 146 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[0].ConstantTerm"), AtmosphereParameters.Mie.Layers[0].ConstantTerm); 147 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[1].Width"), AtmosphereParameters.Mie.Layers[1].Width / kLengthUnitInMeters); 148 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[1].ExpTerm"), AtmosphereParameters.Mie.Layers[1].ExpTerm); 149 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[1].ExpScale"), AtmosphereParameters.Mie.Layers[1].ExpScale * kLengthUnitInMeters); 150 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[1].LinearTerm"), AtmosphereParameters.Mie.Layers[1].LinearTerm * kLengthUnitInMeters); 151 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MieDensity.Layers[1].ConstantTerm"), AtmosphereParameters.Mie.Layers[1].ConstantTerm); 152 | rf::SendVec3(glGetUniformLocation(Program, "Atmosphere.AbsorptionExtinction"), AtmosphereParameters.AbsorptionExtinction); 153 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[0].Width"), AtmosphereParameters.Absorption.Layers[0].Width / kLengthUnitInMeters); 154 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[0].ExpTerm"), AtmosphereParameters.Absorption.Layers[0].ExpTerm); 155 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[0].ExpScale"), AtmosphereParameters.Absorption.Layers[0].ExpScale * kLengthUnitInMeters); 156 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[0].LinearTerm"), AtmosphereParameters.Absorption.Layers[0].LinearTerm * kLengthUnitInMeters); 157 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[0].ConstantTerm"), AtmosphereParameters.Absorption.Layers[0].ConstantTerm); 158 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[1].Width"), AtmosphereParameters.Absorption.Layers[1].Width / kLengthUnitInMeters); 159 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[1].ExpTerm"), AtmosphereParameters.Absorption.Layers[1].ExpTerm); 160 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[1].ExpScale"), AtmosphereParameters.Absorption.Layers[1].ExpScale * kLengthUnitInMeters); 161 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[1].LinearTerm"), AtmosphereParameters.Absorption.Layers[1].LinearTerm * kLengthUnitInMeters); 162 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.AbsorptionDensity.Layers[1].ConstantTerm"), AtmosphereParameters.Absorption.Layers[1].ConstantTerm); 163 | rf::SendVec3(glGetUniformLocation(Program, "Atmosphere.GroundAlbedo"), AtmosphereParameters.GroundAlbedo); 164 | rf::SendVec3(glGetUniformLocation(Program, "Atmosphere.SolarIrradiance"), AtmosphereParameters.SolarIrradiance); 165 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.SunAngularRadius"), AtmosphereParameters.SunAngularRadius); 166 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MiePhaseG"), AtmosphereParameters.MiePhaseG); 167 | rf::SendFloat(glGetUniformLocation(Program, "Atmosphere.MinMuS"), AtmosphereParameters.MinMuS); 168 | rf::CheckGLError("Atmosphere Uniform Shader"); 169 | } 170 | 171 | void InitializeModel(rf::context *Context) 172 | { 173 | path VSPath, FSPath, GSPath; 174 | 175 | rf::ConcatStrings(VSPath, rf::ctx::GetExePath(Context), "data/shaders/atmosphere_precompute_vert.glsl"); 176 | rf::ConcatStrings(FSPath, rf::ctx::GetExePath(Context), "data/shaders/atmosphere_precompute_frag.glsl"); 177 | uint32 AtmospherePrecomputeProgram = rf::BuildShader(Context, VSPath, FSPath); 178 | rf::ConcatStrings(GSPath, rf::ctx::GetExePath(Context), "data/shaders/atmosphere_precompute_geom.glsl"); 179 | uint32 ScatteringProgram = rf::BuildShader(Context, VSPath, FSPath, GSPath); 180 | 181 | 182 | // Precompute atmosphere textures 183 | rf::frame_buffer RenderBuffer = {}; 184 | 185 | glUseProgram(AtmospherePrecomputeProgram); 186 | rf::CheckGLError("Atmosphere Precompute Shader"); 187 | 188 | SendShaderUniforms(AtmospherePrecomputeProgram); 189 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "Tex0"), 0); 190 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "Tex1"), 1); 191 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "Tex2"), 2); 192 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "Tex3"), 3); 193 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "Tex4"), 4); 194 | 195 | // Transmittance texture 196 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "ProgramUnit"), 0); 197 | rf::DestroyFramebuffer(&RenderBuffer); 198 | RenderBuffer = rf::MakeFramebuffer(1, kTransmittanceTextureSize); 199 | glDeleteTextures(1, &TransmittanceTexture); 200 | TransmittanceTexture = rf::Make2DTexture(NULL, kTransmittanceTextureSize.x, kTransmittanceTextureSize.y, 4, true, false, 1, 201 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 202 | //FramebufferAttachBuffer(&RenderBuffer, 0, 4, true, false, false); // RGBA32F 203 | glBindFramebuffer(GL_FRAMEBUFFER, RenderBuffer.FBO); 204 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TransmittanceTexture, 0); 205 | glViewport(0, 0, kTransmittanceTextureSize.x, kTransmittanceTextureSize.y); 206 | glClearColor(0, 0, 0, 0); 207 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 208 | glBindVertexArray(ScreenQuad.VAO); 209 | rf::RenderMesh(&ScreenQuad); 210 | 211 | // Ground Irradiance texture 212 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "ProgramUnit"), 1); 213 | rf::DestroyFramebuffer(&RenderBuffer); 214 | RenderBuffer = rf::MakeFramebuffer(2, kIrradianceTextureSize); 215 | glDeleteTextures(1, &IrradianceTexture); 216 | IrradianceTexture = rf::Make2DTexture(NULL, kIrradianceTextureSize.x, kIrradianceTextureSize.y, 4, true, false, 1, 217 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 218 | uint32 DeltaIrradianceTexture = rf::Make2DTexture(NULL, kIrradianceTextureSize.x, kIrradianceTextureSize.y, 4, true, false, 1, 219 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 220 | glBindFramebuffer(GL_FRAMEBUFFER, RenderBuffer.FBO); 221 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, DeltaIrradianceTexture, 0); 222 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, IrradianceTexture, 0); 223 | glViewport(0, 0, kIrradianceTextureSize.x, kIrradianceTextureSize.y); 224 | glClearColor(0, 0, 0, 0); 225 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 226 | glActiveTexture(GL_TEXTURE0); 227 | glBindTexture(GL_TEXTURE_2D, TransmittanceTexture); 228 | glBindVertexArray(ScreenQuad.VAO); 229 | rf::RenderMesh(&ScreenQuad); 230 | 231 | // Single Scattering 232 | glUseProgram(ScatteringProgram); 233 | SendShaderUniforms(ScatteringProgram); 234 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "ProgramUnit"), 2); 235 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "Tex0"), 0); 236 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "Tex1"), 1); 237 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "Tex2"), 2); 238 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "Tex3"), 3); 239 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "Tex4"), 4); 240 | rf::CheckGLError("Scattering Precompute Shader"); 241 | 242 | rf::DestroyFramebuffer(&RenderBuffer); 243 | RenderBuffer = rf::MakeFramebuffer(3, vec2i(kScatteringTextureSize.x, kScatteringTextureSize.y), false); 244 | glBindFramebuffer(GL_FRAMEBUFFER, RenderBuffer.FBO); 245 | glDeleteTextures(1, &ScatteringTexture); 246 | ScatteringTexture = rf::Make3DTexture(kScatteringTextureSize.x, kScatteringTextureSize.y, kScatteringTextureSize.z, 4, true, false, 247 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 248 | uint32 DeltaRayleighTexture = rf::Make3DTexture(kScatteringTextureSize.x, kScatteringTextureSize.y, kScatteringTextureSize.z, 4, true, false, 249 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 250 | uint32 DeltaMieTexture = rf::Make3DTexture(kScatteringTextureSize.x, kScatteringTextureSize.y, kScatteringTextureSize.z, 4, true, false, 251 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 252 | rf::FramebufferAttachBuffer(&RenderBuffer, 0, DeltaRayleighTexture); 253 | rf::FramebufferAttachBuffer(&RenderBuffer, 1, DeltaMieTexture); 254 | rf::FramebufferAttachBuffer(&RenderBuffer, 2, ScatteringTexture); 255 | D_ONLY(if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 256 | { 257 | LogError("Incomplete Scattering Framebuffer"); 258 | }) 259 | glViewport(0, 0, kScatteringTextureSize.x, kScatteringTextureSize.y); 260 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 261 | glActiveTexture(GL_TEXTURE0); 262 | glBindTexture(GL_TEXTURE_2D, TransmittanceTexture); 263 | glBindVertexArray(ScreenQuad.VAO); 264 | uint32 LayerLoc = glGetUniformLocation(ScatteringProgram, "ScatteringLayer"); 265 | for (int layer = 0; layer < kScatteringTextureSize.z; ++layer) 266 | { 267 | rf::SendInt(LayerLoc, layer); 268 | rf::RenderMesh(&ScreenQuad); 269 | } 270 | 271 | rf::CheckGLError("Scattering Precomputation"); 272 | 273 | // Multiple Scattering 274 | uint32 DeltaScatteringDensityTexture = rf::Make3DTexture(kScatteringTextureSize.x, kScatteringTextureSize.y, kScatteringTextureSize.z, 4, true, false, 275 | GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 276 | 277 | glDisablei(GL_BLEND, 0); 278 | glDisablei(GL_BLEND, 1); 279 | glBlendEquation(GL_FUNC_ADD); 280 | glBlendFunc(GL_ONE, GL_ONE); 281 | 282 | uint32 NumScatteringBounces = 4; 283 | for (uint32 bounce = 2; bounce <= NumScatteringBounces; ++bounce) 284 | { 285 | // 1. Compute Scattering density into DeltaScatteringDensityTexture 286 | glUseProgram(ScatteringProgram); 287 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "ProgramUnit"), 3); 288 | rf::FramebufferSetAttachmentCount(&RenderBuffer, 1); 289 | rf::FramebufferAttachBuffer(&RenderBuffer, 0, DeltaScatteringDensityTexture); 290 | rf::FramebufferAttachBuffer(&RenderBuffer, 1, 0); 291 | rf::FramebufferAttachBuffer(&RenderBuffer, 2, 0); 292 | rf::FramebufferAttachBuffer(&RenderBuffer, 3, 0); 293 | rf::CheckFramebufferError("Scattering Density Framebuffer"); 294 | glActiveTexture(GL_TEXTURE0); 295 | glBindTexture(GL_TEXTURE_2D, TransmittanceTexture); 296 | glActiveTexture(GL_TEXTURE1); 297 | glBindTexture(GL_TEXTURE_3D, DeltaRayleighTexture); 298 | glActiveTexture(GL_TEXTURE2); 299 | glBindTexture(GL_TEXTURE_3D, DeltaMieTexture); 300 | glActiveTexture(GL_TEXTURE3); 301 | glBindTexture(GL_TEXTURE_3D, DeltaRayleighTexture); 302 | glActiveTexture(GL_TEXTURE4); 303 | glBindTexture(GL_TEXTURE_2D, DeltaIrradianceTexture); 304 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "ScatteringBounce"), bounce); 305 | for (int32 layer = 0; layer < kScatteringTextureSize.z; ++layer) 306 | { 307 | rf::SendInt(LayerLoc, layer); 308 | rf::RenderMesh(&ScreenQuad); 309 | } 310 | 311 | // 2. Compute Indirect irradiance into DeltaIrradianceTexture, accumulate it into IrradianceTexture 312 | glUseProgram(AtmospherePrecomputeProgram); 313 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "ProgramUnit"), 4); 314 | rf::FramebufferSetAttachmentCount(&RenderBuffer, 2); 315 | rf::FramebufferAttachBuffer(&RenderBuffer, 0, DeltaIrradianceTexture); 316 | rf::FramebufferAttachBuffer(&RenderBuffer, 1, IrradianceTexture); 317 | rf::CheckFramebufferError("Indirect Irradiance Framebuffer"); 318 | rf::BindTexture3D(DeltaRayleighTexture, 1); 319 | rf::BindTexture3D(DeltaMieTexture, 2); 320 | rf::BindTexture3D(DeltaRayleighTexture, 3); 321 | rf::SendInt(glGetUniformLocation(AtmospherePrecomputeProgram, "ScatteringBounce"), bounce - 1); 322 | // Accumulate Irradiance in Attachment 1 323 | glEnablei(GL_BLEND, 1); 324 | rf::RenderMesh(&ScreenQuad); 325 | glDisablei(GL_BLEND, 1); 326 | 327 | // 3. Compute Multiple scattering into RayleighTexture 328 | glUseProgram(ScatteringProgram); 329 | rf::SendInt(glGetUniformLocation(ScatteringProgram, "ProgramUnit"), 5); 330 | rf::FramebufferSetAttachmentCount(&RenderBuffer, 2); 331 | rf::FramebufferAttachBuffer(&RenderBuffer, 0, DeltaRayleighTexture); 332 | rf::FramebufferAttachBuffer(&RenderBuffer, 1, ScatteringTexture); 333 | rf::CheckFramebufferError("MS Framebuffer"); 334 | rf::BindTexture2D(TransmittanceTexture, 0); 335 | rf::BindTexture3D(DeltaScatteringDensityTexture, 1); 336 | glEnablei(GL_BLEND, 1); 337 | for (int32 layer = 0; layer < kScatteringTextureSize.z; ++layer) 338 | { 339 | rf::SendInt(LayerLoc, layer); 340 | rf::RenderMesh(&ScreenQuad); 341 | } 342 | glDisablei(GL_BLEND, 1); 343 | } 344 | 345 | 346 | glBindVertexArray(0); 347 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 348 | glUseProgram(0); 349 | glViewport(0, 0, Context->WindowWidth, Context->WindowHeight); 350 | 351 | glDeleteTextures(1, &DeltaIrradianceTexture); 352 | glDeleteTextures(1, &DeltaRayleighTexture); 353 | glDeleteTextures(1, &DeltaMieTexture); 354 | glDeleteTextures(1, &DeltaScatteringDensityTexture); 355 | glDeleteProgram(ScatteringProgram); 356 | glDeleteProgram(AtmospherePrecomputeProgram); 357 | rf::DestroyFramebuffer(&RenderBuffer); 358 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 359 | glEnablei(GL_BLEND, 0); 360 | glEnablei(GL_BLEND, 1); 361 | 362 | //MoonAlbedoTexture = *rf::ResourceLoad2DTexture(Context, "data/moon/albedo.png", false, false, 4, 363 | //GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_CLAMP_TO_EDGE); 364 | } 365 | 366 | void Init(game::state *State, rf::context *Context) 367 | { 368 | (void) State; 369 | ScreenQuad = rf::Make2DQuad(Context, vec2i(-1,1), vec2i(1, -1)); 370 | 371 | AtmosphereParameters.TopRadius = 6420000.f; 372 | AtmosphereParameters.BottomRadius = 6360000.f; 373 | 374 | density_profile_layer DefaultLayer = { 0.f, 0.f, 0.f, 0.f, 0.f }; 375 | density_profile_layer RayleighLayer = { 0.f, 1.f, -1.f / kRayleighScaleHeight, 0.f, 0.f }; 376 | density_profile_layer MieLayer = { 0.f, 1.f, -1.f / kMieScaleHeight, 0.f, 0.f }; 377 | density_profile_layer Ozone0Layer = { 25000.f, 0.f, 0.f, 1.f / 15000.f, -2.f / 3.f }; 378 | density_profile_layer Ozone1Layer = { 0.f, 0.f, 0.f, -1.f / 15000.f, 8.f / 3.f }; 379 | 380 | // Compute absorption and scattering SRGB colors from wavelength 381 | int const nWavelengths = (LAMBDA_MAX-LAMBDA_MIN) / 10; 382 | real32 *Wavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 383 | real32 *SolarIrradianceWavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 384 | real32 *GroundAlbedoWavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 385 | real32 *RayleighScatteringWavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 386 | real32 *MieScatteringWavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 387 | real32 *MieExtinctionWavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 388 | real32 *AbsorptionExtinctionWavelengths = rf::PoolAlloc(Context->ScratchPool, nWavelengths); 389 | 390 | for(int l = LAMBDA_MIN; l <= LAMBDA_MAX; l += 10) 391 | { 392 | int Idx = (l-LAMBDA_MIN)/10; 393 | real32 Lambda = (real32)l * 1e-3f; // micrometers 394 | real32 Mie = kMieAngstromBeta / kMieScaleHeight * std::pow(Lambda, -kMieAngstromAlpha); 395 | Wavelengths[Idx] = (real32)l; 396 | RayleighScatteringWavelengths[Idx] = kRayleigh * std::pow(Lambda, -4); 397 | MieScatteringWavelengths[Idx] = Mie * kMieSingleScatteringAlbedo; 398 | MieExtinctionWavelengths[Idx] = Mie; 399 | AbsorptionExtinctionWavelengths[Idx] = kMaxOzoneNumberDensity * kOzoneCrossSection[Idx]; 400 | SolarIrradianceWavelengths[Idx] = USE_MOON ? kLunarIrradiance[Idx] * 1e-3f : kSolarIrradiance[Idx]; 401 | GroundAlbedoWavelengths[Idx] = kGroundAlbedo; 402 | } 403 | 404 | // Extract from above data depending on radiance rendering mode 405 | //int nW = 3; 406 | 407 | AtmosphereParameters.RayleighScattering = ConvertSpectrumToSRGB(Wavelengths, RayleighScatteringWavelengths, nWavelengths, kLengthUnitInMeters); 408 | AtmosphereParameters.Rayleigh.Layers[0] = DefaultLayer; 409 | AtmosphereParameters.Rayleigh.Layers[1] = RayleighLayer; 410 | AtmosphereParameters.MieExtinction = ConvertSpectrumToSRGB(Wavelengths, MieExtinctionWavelengths, nWavelengths, kLengthUnitInMeters); 411 | AtmosphereParameters.MieScattering = ConvertSpectrumToSRGB(Wavelengths, MieScatteringWavelengths, nWavelengths, kLengthUnitInMeters); 412 | AtmosphereParameters.Mie.Layers[0] = DefaultLayer; 413 | AtmosphereParameters.Mie.Layers[1] = MieLayer; 414 | AtmosphereParameters.AbsorptionExtinction = ConvertSpectrumToSRGB(Wavelengths, AbsorptionExtinctionWavelengths, nWavelengths, kLengthUnitInMeters); 415 | AtmosphereParameters.Absorption.Layers[0] = Ozone0Layer; 416 | AtmosphereParameters.Absorption.Layers[1] = Ozone1Layer; 417 | AtmosphereParameters.GroundAlbedo = ConvertSpectrumToSRGB(Wavelengths, GroundAlbedoWavelengths, nWavelengths, 1.0); 418 | AtmosphereParameters.SolarIrradiance = ConvertSpectrumToSRGB(Wavelengths, SolarIrradianceWavelengths, nWavelengths, 1.0); 419 | AtmosphereParameters.SunAngularRadius = USE_MOON ? kMoonAngularRadius : kSunAngularRadius; 420 | AtmosphereParameters.MiePhaseG = kMiePhaseG; 421 | AtmosphereParameters.MinMuS = cosf(kMaxSunZenithAngle); 422 | 423 | #ifdef PRECOMPUTE_STUFF 424 | InitializeModel(Context); 425 | #endif 426 | } 427 | 428 | void Update() 429 | { 430 | } 431 | 432 | void Render(game::state *State, rf::context *Context) 433 | { 434 | mat4f ViewMatrix = State->Camera.ViewMatrix; 435 | mat4f InvViewMatrix = ViewMatrix.Inverse(); 436 | 437 | real32 AspectRatio = Context->WindowWidth / (real32)Context->WindowHeight; 438 | real32 FovRadians = HFOVtoVFOV(AspectRatio, Context->FOV) * DEG2RAD; 439 | real32 TanFovY = tanf(FovRadians * 0.5f); 440 | mat4f ProjMatrix 441 | ( 442 | 1.f/(TanFovY * AspectRatio), 0.f, 0.f, 0.f, 443 | 0.f, 1.f/TanFovY, 0.f, 0.f, 444 | 0.f, 0.f, 1.f, 1.f, 445 | 0.f, 0.f, -1.f, 0.f 446 | ); 447 | 448 | glDepthFunc(GL_LEQUAL); 449 | 450 | real32 CameraScale = 1.0f / (kLengthUnitInMeters); 451 | 452 | glUseProgram(AtmosphereProgram); 453 | rf::SendMat4(glGetUniformLocation(AtmosphereProgram, "ViewMatrix"), ViewMatrix); 454 | rf::SendMat4(glGetUniformLocation(AtmosphereProgram, "InvViewMatrix"), InvViewMatrix); 455 | rf::SendMat4(glGetUniformLocation(AtmosphereProgram, "ProjMatrix"), ProjMatrix); 456 | rf::SendFloat(glGetUniformLocation(AtmosphereProgram, "CameraScale"), CameraScale); 457 | rf::SendVec3(glGetUniformLocation(AtmosphereProgram, "SunDirection"), State->SunDirection); 458 | rf::SendFloat(glGetUniformLocation(AtmosphereProgram, "Time"), (real32)State->EngineTime); 459 | rf::SendVec2(glGetUniformLocation(AtmosphereProgram, "Resolution"), vec2f((real32)Context->WindowWidth, (real32)Context->WindowHeight)); 460 | rf::CheckGLError("Atmo0"); 461 | #ifdef PRECOMPUTE_STUFF 462 | rf::BindTexture2D(TransmittanceTexture, 0); 463 | rf::BindTexture2D(IrradianceTexture, 1); 464 | rf::BindTexture3D(ScatteringTexture, 2); 465 | #else 466 | rf::BindTexture2D(*Context->RenderResources.DefaultDiffuseTexture, 0); 467 | rf::BindTexture2D(*Context->RenderResources.DefaultDiffuseTexture, 1); 468 | //BindTexture3D(*Context->RenderResources.DefaultDiffuseTexture, 2); 469 | #endif 470 | rf::CheckGLError("Atmo1"); 471 | rf::BindTexture2D(USE_MOON ? MoonAlbedoTexture : *Context->RenderResources.DefaultDiffuseTexture, 3); 472 | glBindVertexArray(ScreenQuad.VAO); 473 | rf::RenderMesh(&ScreenQuad); 474 | glUseProgram(0); 475 | 476 | 477 | glDepthFunc(GL_LESS); 478 | rf::CheckGLError("Atmo"); 479 | 480 | // TMP - print center view ray info 481 | #if 0 482 | str dbgStr; 483 | 484 | vec4f CenterPoint(0.f, 0.f, 0.f, 1.f); 485 | vec4f ViewCenterPoint = Context->ProjectionMatrix3D.Inverse() * CenterPoint; 486 | ViewCenterPoint.w = 0.0f; 487 | vec4f WorldCenterPoint = InvViewMatrix * ViewCenterPoint; 488 | vec3f E = -Normalize(vec3f(WorldCenterPoint)); 489 | vec3f P = State->Camera.Position + State->Camera.PositionDecimal; 490 | vec3f p = P; 491 | 492 | real32 PdotV = Dot(p, E); 493 | real32 PdotP = Dot(p, p); 494 | real32 EarthCenterRayDistance = PdotP - PdotV * PdotV; 495 | real32 insqrt = AtmosphereParameters.BottomRadius * AtmosphereParameters.BottomRadius - EarthCenterRayDistance; 496 | real32 sqrtval = sqrtf(insqrt); 497 | real32 n1 = PdotV / PdotV; 498 | real32 n2 = sqrtval / PdotV; 499 | real32 nd = -n1 - n2; 500 | real32 depth = nd * PdotV; 501 | real32 ViewInfoDepth = -PdotV - sqrtf(AtmosphereParameters.BottomRadius * AtmosphereParmeters.BottomRadius - EarthCenterRayDistance); 502 | snprintf(dbgStr, MAX_STRLEN, "Center Ray : n1 %f n2 %f nd %f d %f", n1, n2, nd, depth); 503 | 504 | int TextID = 0; 505 | rf::ui::MakeText(&TextID, ss.str().c_str(), rf::ui::FONT_DEFAULT, vec2i(4, Context->WindowHeight - 20), col4f(1)); 506 | #endif 507 | } 508 | 509 | void ReloadShaders(rf::context *Context) 510 | { 511 | path VSPath, FSPath; 512 | 513 | // Rendering shader 514 | rf::ConcatStrings(VSPath, rf::ctx::GetExePath(Context), "data/shaders/atmosphere_vert.glsl"); 515 | rf::ConcatStrings(FSPath, rf::ctx::GetExePath(Context), "data/shaders/atmosphere_frag.glsl"); 516 | AtmosphereProgram = rf::BuildShader(Context, VSPath, FSPath); 517 | glUseProgram(AtmosphereProgram); 518 | rf::CheckGLError("Atmosphere Shader"); 519 | 520 | // Init constants 521 | SendShaderUniforms(AtmosphereProgram); 522 | rf::SendInt(glGetUniformLocation(AtmosphereProgram, "TransmittanceTexture"), 0); 523 | rf::SendInt(glGetUniformLocation(AtmosphereProgram, "IrradianceTexture"), 1); 524 | rf::SendInt(glGetUniformLocation(AtmosphereProgram, "ScatteringTexture"), 2); 525 | rf::SendInt(glGetUniformLocation(AtmosphereProgram, "MoonAlbedo"), 3); 526 | 527 | glUseProgram(0); 528 | } 529 | } 530 | 531 | -------------------------------------------------------------------------------- /src/Systems/atmosphere.h: -------------------------------------------------------------------------------- 1 | #ifndef ATMOSPHERE_H 2 | #define ATMOSPHERE_H 3 | 4 | #include "definitions.h" 5 | 6 | 7 | namespace game { 8 | struct state; 9 | } 10 | 11 | namespace atmosphere { 12 | 13 | enum radiance_mode 14 | { 15 | RGB, 16 | SRGB, 17 | FULL 18 | }; 19 | 20 | /// NOTE - Atmospheric scattering engine, inspired by Eric Bruneton's Precomputed Atmospheric Scattering 21 | /// https://ebruneton.github.io/precomputed_atmospheric_scattering/ 22 | extern uint32 TransmittanceTexture; 23 | extern uint32 IrradianceTexture; 24 | extern uint32 ScatteringTexture; 25 | 26 | void Init(game::state *State, rf::context *Context); 27 | void Update(); 28 | void Render(game::state *State, rf::context *Context); 29 | void ReloadShaders(rf::context *Context); 30 | 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/Systems/planet.cpp: -------------------------------------------------------------------------------- 1 | #include "planet.h" 2 | #include "rf/context.h" 3 | #include "rf/utils.h" 4 | #include "Game/sun.h" 5 | 6 | namespace planet 7 | { 8 | struct planet_params 9 | { 10 | mat4f ModelMatrix; 11 | mat4f ViewMatrix; 12 | vec3f CameraPosition; 13 | float OuterTessFactor; 14 | vec3f TileSize; 15 | float InnerTessFactor; 16 | vec3f Origin; 17 | float Time; 18 | int GridW; 19 | int GridH; 20 | int GridD; 21 | }; 22 | 23 | planet_params PlanetParams; 24 | uint32 TessTestShader; 25 | uint32 PlanetUBO; 26 | rf::mesh PlanetMesh; 27 | 28 | void Init(game::state * /*State*/, rf::context * /*Context*/) 29 | { 30 | // 1 vertex VBO 31 | float vtxData[] = { 0.0f, 0.0f, 0.0f }; 32 | uint32 idxData = 0; 33 | PlanetMesh.IndexCount = 1; 34 | PlanetMesh.IndexType = GL_UNSIGNED_INT; 35 | PlanetMesh.VAO = rf::MakeVertexArrayObject(); 36 | PlanetMesh.VBO[0] = rf::AddIBO(GL_STATIC_DRAW, sizeof(uint32), &idxData); 37 | PlanetMesh.VBO[1] = rf::AddEmptyVBO(sizeof(vtxData), GL_STATIC_DRAW); 38 | rf::FillVBO(0, 3, GL_FLOAT, 0, sizeof(vtxData), vtxData); 39 | glBindVertexArray(0); 40 | rf::CheckGLError("Init"); 41 | PlanetUBO = rf::MakeUBO(sizeof(planet_params), GL_STREAM_DRAW); 42 | rf::CheckGLError("InitUBO"); 43 | } 44 | 45 | void Destroy() 46 | { 47 | rf::DestroyUBO(PlanetUBO); 48 | } 49 | 50 | void Update() 51 | { 52 | } 53 | 54 | void SetParameters(game::state * State) 55 | { 56 | float sc = 10.0; 57 | PlanetParams.ModelMatrix.FromTRS(vec3f(0, 0, 0), vec3f(0, 0, 0), vec3f(sc)); 58 | PlanetParams.ViewMatrix = State->Camera.ViewMatrix; 59 | PlanetParams.CameraPosition = State->Camera.Position; 60 | 61 | PlanetParams.GridW = PlanetParams.GridH = 32; 62 | PlanetParams.GridD = 6; 63 | PlanetParams.TileSize = vec3f(0.5f, 1.0f, 0.5f); 64 | PlanetParams.Origin = vec3f(-PlanetParams.TileSize.x*PlanetParams.GridW*0.5f, 65 | -PlanetParams.TileSize.x*PlanetParams.GridW*0.5f, 66 | -PlanetParams.TileSize.z*PlanetParams.GridH*0.5f); 67 | 68 | PlanetParams.OuterTessFactor = 32.0f; 69 | PlanetParams.InnerTessFactor = 32.0f; 70 | 71 | 72 | static float st = 0.0f; 73 | st += (float)State->dTime; 74 | PlanetParams.Time = st; 75 | } 76 | 77 | void Render(game::state * State, rf::context * Context) 78 | { 79 | rf::ctx::SetCullMode(Context); 80 | //rf::ctx::SetWireframeMode(Context); 81 | glEnable(GL_BLEND); 82 | //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 83 | glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); 84 | glUseProgram(TessTestShader); 85 | 86 | rf::CheckGLError("PlanetUBOStart"); 87 | SetParameters(State); 88 | 89 | rf::BindUBO(PlanetUBO, 1); 90 | rf::FillUBO(0, sizeof(planet_params), &PlanetParams); 91 | 92 | rf::CheckGLError("PlanetUBO"); 93 | glPatchParameteri(GL_PATCH_VERTICES, 1); 94 | glBindVertexArray(PlanetMesh.VAO); 95 | int instances = PlanetParams.GridW * PlanetParams.GridH * PlanetParams.GridD; 96 | glDrawElementsInstanced(GL_PATCHES, PlanetMesh.IndexCount, PlanetMesh.IndexType, 0, instances); 97 | 98 | 99 | rf::CheckGLError("PlanetDraw"); 100 | glBlendEquation(GL_FUNC_ADD); 101 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 102 | //rf::ctx::SetWireframeMode(Context); 103 | rf::ctx::SetCullMode(Context); 104 | } 105 | 106 | void ReloadShaders(rf::context * Context) 107 | { 108 | path const &ExePath = rf::ctx::GetExePath(Context); 109 | path VSPath, FSPath, GSPath, TESCPath, TESEPath; 110 | rf::ConcatStrings(VSPath, ExePath, "data/shaders/planet_vert.glsl"); 111 | rf::ConcatStrings(FSPath, ExePath, "data/shaders/planet_frag.glsl"); 112 | rf::ConcatStrings(TESCPath, ExePath, "data/shaders/planet_tesc.glsl"); 113 | rf::ConcatStrings(TESEPath, ExePath, "data/shaders/planet_tese.glsl"); 114 | rf::ConcatStrings(GSPath, ExePath, "data/shaders/planet_geom.glsl"); 115 | TessTestShader = rf::BuildShader(Context, VSPath, FSPath, NULL, TESCPath, TESEPath); 116 | glUseProgram(TessTestShader); 117 | rf::ctx::RegisterShader3D(Context, TessTestShader); 118 | rf::CheckGLError("PlanetShader"); 119 | } 120 | } -------------------------------------------------------------------------------- /src/Systems/planet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "definitions.h" 4 | 5 | namespace game 6 | { 7 | struct state; 8 | } 9 | 10 | namespace planet 11 | { 12 | void Init(game::state *State, rf::context *Context); 13 | void Update(); 14 | void Render(game::state *State, rf::context *Context); 15 | void ReloadShaders(rf::context *Context); 16 | } -------------------------------------------------------------------------------- /src/Systems/water.cpp: -------------------------------------------------------------------------------- 1 | #include "water.h" 2 | #include "rf/context.h" 3 | #include "rf/utils.h" 4 | #include "Game/sun.h" 5 | 6 | // NOTE - Tmp storage here 7 | // Beaufort Level : WidthScale, WaveScale, Choppiness 8 | // Beaufort 1 : 3, 0.05, 0.005 9 | // Beaufort 3 : 3, 0.1, 0.1 10 | // Beaufort 7 : 3, 0.5, 0.5 11 | // Beaufort 12 : 3, 1.0, 1.0 12 | real32 BeaufortParams[][3] = { 13 | { 3.f, 0.05f, 0.005f }, 14 | { 3.f, 0.1f, 0.1f }, 15 | { 3.f, 0.5f, 0.5f }, 16 | { 3.f, 1.0f, 1.0f } 17 | }; 18 | 19 | struct wave_vector 20 | { 21 | complex H; // Wave Height 22 | vec2f D; // Wave XZ Displacement 23 | vec3f N; // Wave Normal 24 | }; 25 | 26 | // TODO - Should return a vec2f, with complex having vec2f cast 27 | // TODO - Use precomputed and better random variables, not rand() 28 | complex GaussianRandomVariable() 29 | { 30 | float U, V, W; 31 | do { 32 | U = 2.f * rand()/(real32)RAND_MAX - 1.f; 33 | V = 2.f * rand()/(real32)RAND_MAX - 1.f; 34 | W = Square(U) + Square(V); 35 | } while(W >= 1.f); 36 | W = sqrtf((-2.f * logf(W)) / W); 37 | return complex(U * W, V * W); 38 | } 39 | 40 | real32 Phillips(water::beaufort_state *State, int n_prime, int m_prime) 41 | { 42 | vec2f K(M_PI * (2.f * n_prime - water::system::WaterN) / State->Width, 43 | M_PI * (2.f * m_prime - water::system::WaterN) / State->Width); 44 | real32 KLen = Length(K); 45 | if(KLen < 1e-6f) return 0.f; 46 | 47 | real32 KLen2 = Square(KLen); 48 | real32 KLen4 = Square(KLen2); 49 | 50 | vec2f UnitK = Normalize(K); 51 | vec2f UnitW = Normalize(State->Direction); 52 | real32 KDotW = Dot(UnitK, UnitW); 53 | real32 KDotW2 = Square(Square(KDotW)); 54 | 55 | real32 WLen = Length(State->Direction); 56 | real32 L = Square(WLen) / g_G; 57 | real32 L2 = Square(L); 58 | 59 | real32 Damping = 1e-3f; 60 | real32 DampL2 = L2 * Square(Damping); 61 | 62 | return State->Amplitude * (expf(-1.f / (KLen2 * L2)) / KLen4) * KDotW2 * expf(-KLen2 * DampL2); 63 | } 64 | 65 | real32 ComputeDispersion(real32 Width, int n_prime, int m_prime) 66 | { 67 | real32 W0 = 2.f * M_PI / 200.f; 68 | real32 Kx = M_PI * (2 * n_prime - water::system::WaterN) / Width; 69 | real32 Kz = M_PI * (2 * m_prime - water::system::WaterN) / Width; 70 | return floorf(sqrtf(g_G * sqrtf(Square(Kx) + Square(Kz))) / W0) * W0; 71 | } 72 | 73 | complex ComputeHTilde0(water::beaufort_state *State, int n_prime, int m_prime) 74 | { 75 | complex R = GaussianRandomVariable(); 76 | return R * sqrtf(Phillips(State, n_prime, m_prime) / 2.0f); 77 | } 78 | 79 | complex ComputeHTilde(water::beaufort_state *StateA, water::beaufort_state *StateB, real32 WaterInterp, 80 | real32 T, int n_prime, int m_prime) 81 | { 82 | int NPlus1 = water::system::WaterN+1; 83 | int Idx = m_prime * NPlus1 + n_prime; 84 | 85 | vec3f *HTilde0A = (vec3f*)StateA->HTilde0; 86 | vec3f *HTilde0B = (vec3f*)StateB->HTilde0; 87 | vec3f *HTilde0mkA = (vec3f*)StateA->HTilde0mk; 88 | vec3f *HTilde0mkB = (vec3f*)StateB->HTilde0mk; 89 | 90 | vec3f dHT0 = Lerp(HTilde0A[Idx], HTilde0B[Idx], WaterInterp); 91 | vec3f dHT0mk = Lerp(HTilde0mkA[Idx], HTilde0mkB[Idx], WaterInterp); 92 | real32 dWidth = Lerp((real32)StateA->Width, (real32)StateB->Width, WaterInterp); 93 | 94 | complex H0(dHT0.x, dHT0.y); 95 | complex H0mk(dHT0mk.x, dHT0mk.y); 96 | 97 | real32 OmegaT = ComputeDispersion(dWidth, n_prime, m_prime) * T; 98 | real32 CosOT = cosf(OmegaT); 99 | real32 SinOT = sinf(OmegaT); 100 | 101 | complex C0(CosOT, SinOT); 102 | complex C1(CosOT, -SinOT); 103 | 104 | return H0 * C0 + H0mk * C1; 105 | } 106 | 107 | uint32 FFTReverse(uint32 i, int Log2N) 108 | { 109 | uint32 Res = 0; 110 | for(int j = 0; j < Log2N; ++j) 111 | { 112 | Res = (Res << 1) + (i & 1); 113 | i >>= 1; 114 | } 115 | return Res; 116 | } 117 | 118 | complex FFTW(uint32 X, uint32 N) 119 | { 120 | float V = M_TWO_PI * X / N; 121 | return complex(cosf(V), sinf(V)); 122 | } 123 | 124 | void FFTEvaluate(water::system *WS, complex *Input, complex *Output, int Stride, int Offset, int N) 125 | { 126 | for(int i = 0; i < N; ++i) 127 | WS->FFTC[WS->Switch][i] = Input[WS->Reversed[i] * Stride + Offset]; 128 | 129 | int Loops = N >> 1; 130 | int Size = 2; 131 | int SizeOver2 = 1; 132 | int W_ = 0; 133 | for(int j = 1; j <= WS->Log2N; ++j) 134 | { 135 | WS->Switch ^= 1; 136 | for(int i = 0; i < Loops; ++i) 137 | { 138 | complex *FFTCDst = WS->FFTC[WS->Switch]; 139 | complex *FFTCSrc = WS->FFTC[WS->Switch^1]; 140 | for(int k = 0; k < SizeOver2; ++k) 141 | { 142 | FFTCDst[Size * i + k] = FFTCSrc[Size * i + k] + 143 | FFTCSrc[Size * i + SizeOver2 + k] * WS->FFTW[W_][k]; 144 | } 145 | for(int k = SizeOver2; k < Size; ++k) 146 | { 147 | FFTCDst[Size * i + k] = FFTCSrc[Size * i - SizeOver2 + k] - 148 | FFTCSrc[Size * i + k] * WS->FFTW[W_][k - SizeOver2]; 149 | } 150 | } 151 | Loops >>= 1; 152 | Size <<= 1; 153 | SizeOver2 <<= 1; 154 | W_++; 155 | } 156 | 157 | for(int i = 0; i < N; ++i) 158 | Output[i * Stride + Offset] = WS->FFTC[WS->Switch][i]; 159 | } 160 | 161 | void UpdateWaterMesh(water::system *WaterSystem) 162 | { 163 | glBindVertexArray(WaterSystem->VAO); 164 | size_t VertSize = WaterSystem->VertexCount * sizeof(real32); 165 | rf::UpdateVBO(WaterSystem->VBO[1], 0, VertSize, WaterSystem->VertexData); 166 | rf::UpdateVBO(WaterSystem->VBO[1], VertSize, VertSize, WaterSystem->VertexData + WaterSystem->VertexCount); 167 | 168 | glBindVertexArray(0); 169 | } 170 | 171 | void WaterBeaufortStateInitialize(water::system *WaterSystem, uint32 State) 172 | { 173 | water::beaufort_state *WaterState = &WaterSystem->States[State]; 174 | int N = water::system::WaterN; 175 | int NPlus1 = N+1; 176 | 177 | WaterState->Width = (int)BeaufortParams[State][0] * water::system::WaterN; 178 | WaterState->Direction = vec2f(BeaufortParams[State][1] * water::system::WaterN, 0.0f); 179 | WaterState->Amplitude = 0.00000025f * BeaufortParams[State][2] * water::system::WaterN; 180 | 181 | size_t BaseOffset = 2 * WaterSystem->VertexCount; 182 | WaterState->OrigPositions = WaterSystem->VertexData + BaseOffset + (State * 3 + 0) * WaterSystem->VertexCount; 183 | WaterState->HTilde0 = WaterSystem->VertexData + BaseOffset + (State * 3 + 1) * WaterSystem->VertexCount; 184 | WaterState->HTilde0mk = WaterSystem->VertexData + BaseOffset + (State * 3 + 2) * WaterSystem->VertexCount; 185 | 186 | vec3f *OrigPositions = (vec3f*)WaterState->OrigPositions; 187 | vec3f *HTilde0 = (vec3f*)WaterState->HTilde0; 188 | vec3f *HTilde0mk = (vec3f*)WaterState->HTilde0mk; 189 | 190 | for(int m_prime = 0; m_prime < NPlus1; m_prime++) 191 | { 192 | for(int n_prime = 0; n_prime < NPlus1; n_prime++) 193 | { 194 | int Idx = m_prime * NPlus1 + n_prime; 195 | complex H0 = ComputeHTilde0(WaterState, n_prime, m_prime); 196 | complex H0mk = Conjugate(ComputeHTilde0(WaterState, -n_prime, -m_prime)); 197 | 198 | OrigPositions[Idx].x = (n_prime - N / 2.0f) * WaterState->Width / N; 199 | OrigPositions[Idx].y = 0.f; 200 | OrigPositions[Idx].z = (m_prime - N / 2.0f) * WaterState->Width / N; 201 | 202 | HTilde0[Idx].x = H0.r; 203 | HTilde0[Idx].y = H0.i; 204 | HTilde0mk[Idx].x = H0mk.r; 205 | HTilde0mk[Idx].y = H0mk.i; 206 | } 207 | } 208 | } 209 | 210 | namespace water { 211 | water::system *WaterSystem = NULL; 212 | rf::mesh ScreenQuad = {}; 213 | 214 | void Init(game::state * /*State*/, rf::context *Context, uint32 /*BeaufortState*/) 215 | { 216 | ScreenQuad = rf::Make2DQuad(Context, vec2i(-1,1), vec2i(1, -1), 5); 217 | WaterSystem = rf::PoolAlloc(Context->SessionPool, 1); 218 | #if 0 219 | int N = water::system::WaterN; 220 | int NPlus1 = N+1; 221 | 222 | 223 | size_t WaterStateAttribs = 3 * sizeof(vec3f); // hTilde0, hTilde0mk, OrigPos 224 | size_t WaterAttribs = 2 * sizeof(vec3f); // Pos, Norm 225 | size_t WaterVertexDataSize = Square(NPlus1) * (WaterAttribs + water::system::BeaufortStateCount * WaterStateAttribs); 226 | size_t WaterVertexCount = 3 * Square(NPlus1); // 3 floats per attrib 227 | real32 *WaterVertexData = (real32*)PushArenaData(Context->SessionArena, WaterVertexDataSize); 228 | 229 | size_t WaterIndexDataSize = Square(N) * 6 * sizeof(uint32); 230 | uint32 *WaterIndexData = (uint32*)PushArenaData(Context->SessionArena, WaterIndexDataSize); 231 | 232 | 233 | WaterSystem->VertexDataSize = WaterVertexDataSize; 234 | WaterSystem->VertexCount = WaterVertexCount; 235 | WaterSystem->VertexData = WaterVertexData; 236 | WaterSystem->IndexDataSize = WaterIndexDataSize; 237 | WaterSystem->IndexData = WaterIndexData; 238 | WaterSystem->Positions = WaterSystem->VertexData; 239 | WaterSystem->Normals = WaterSystem->VertexData + WaterVertexCount; 240 | 241 | WaterSystem->hTilde = (complex*)PushArenaData(Context->SessionArena, N * N * sizeof(complex)); 242 | WaterSystem->hTildeSlopeX = (complex*)PushArenaData(Context->SessionArena, N * N * sizeof(complex)); 243 | WaterSystem->hTildeSlopeZ = (complex*)PushArenaData(Context->SessionArena, N * N * sizeof(complex)); 244 | WaterSystem->hTildeDX = (complex*)PushArenaData(Context->SessionArena, N * N * sizeof(complex)); 245 | WaterSystem->hTildeDZ = (complex*)PushArenaData(Context->SessionArena, N * N * sizeof(complex)); 246 | 247 | WaterSystem->Switch = 0; 248 | WaterSystem->Log2N = log(N) / log(2); 249 | WaterSystem->FFTC[0] = (complex*)PushArenaData(Context->SessionArena, N * sizeof(complex)); 250 | WaterSystem->FFTC[1] = (complex*)PushArenaData(Context->SessionArena, N * sizeof(complex)); 251 | WaterSystem->Reversed = (uint32*)PushArenaData(Context->SessionArena, N * sizeof(uint32)); 252 | for(int i = 0; i < N; ++i) 253 | { 254 | WaterSystem->Reversed[i] = FFTReverse(i, WaterSystem->Log2N); 255 | } 256 | WaterSystem->FFTW = (complex**)PushArenaData(Context->SessionArena, WaterSystem->Log2N * sizeof(complex*)); 257 | int Pow2 = 1; 258 | for(int j = 0; j < WaterSystem->Log2N; ++j) 259 | { 260 | WaterSystem->FFTW[j] = (complex*)PushArenaData(Context->SessionArena, Pow2 * sizeof(complex)); 261 | for(int i = 0; i < Pow2; ++i) 262 | WaterSystem->FFTW[j][i] = FFTW(i, 2 * Pow2); 263 | Pow2 *=2; 264 | } 265 | 266 | for(uint32 i = 0; i < water::system::BeaufortStateCount; ++i) 267 | { 268 | WaterBeaufortStateInitialize(WaterSystem, i); 269 | } 270 | 271 | vec3f *Positions = (vec3f*)WaterSystem->Positions; 272 | vec3f *Normals = (vec3f*)WaterSystem->Normals; 273 | uint32 *Indices = (uint32*)WaterSystem->IndexData; 274 | 275 | vec3f *OrigPositions = (vec3f*)WaterSystem->States[BeaufortState].OrigPositions; 276 | for(int m_prime = 0; m_prime < NPlus1; m_prime++) 277 | { 278 | for(int n_prime = 0; n_prime < NPlus1; n_prime++) 279 | { 280 | int Idx = m_prime * NPlus1 + n_prime; 281 | Positions[Idx].x = OrigPositions[Idx].x; 282 | Positions[Idx].y = OrigPositions[Idx].y; 283 | Positions[Idx].z = OrigPositions[Idx].z; 284 | 285 | Normals[Idx] = vec3f(0, 1, 0); 286 | } 287 | } 288 | 289 | uint32 IndexCount = 0; 290 | for(int m_prime = 0; m_prime < N; m_prime++) 291 | { 292 | for(int n_prime = 0; n_prime < N; n_prime++) 293 | { 294 | int Idx = m_prime * NPlus1 + n_prime; 295 | 296 | Indices[IndexCount++] = Idx; 297 | Indices[IndexCount++] = Idx + NPlus1; 298 | Indices[IndexCount++] = Idx + NPlus1 + 1; 299 | Indices[IndexCount++] = Idx; 300 | Indices[IndexCount++] = Idx + NPlus1 + 1; 301 | Indices[IndexCount++] = Idx + 1; 302 | } 303 | } 304 | WaterSystem->IndexCount = IndexCount; 305 | WaterSystem->VAO = rf::MakeVertexArrayObject(); 306 | WaterSystem->VBO[0] = rf::AddIBO(GL_STATIC_DRAW, WaterSystem->IndexCount * sizeof(uint32), WaterSystem->IndexData); 307 | WaterSystem->VBO[1] = rf::AddEmptyVBO(WaterSystem->VertexDataSize, GL_STATIC_DRAW); 308 | size_t VertSize = WaterSystem->VertexCount * sizeof(real32); 309 | rf::FillVBO(0, 3, GL_FLOAT, 0, VertSize, WaterSystem->VertexData); 310 | rf::FillVBO(1, 3, GL_FLOAT, VertSize, VertSize, WaterSystem->VertexData + WaterSystem->VertexCount); 311 | rf::FillVBO(2, 3, GL_FLOAT, 2*VertSize, VertSize, WaterSystem->VertexData + 2 * WaterSystem->VertexCount); 312 | glBindVertexArray(0); 313 | #endif 314 | } 315 | 316 | void Update(game::state * /*State*/, rf::input * /*Input*/) 317 | { 318 | #if 0 319 | beaufort_state *WStateA = &WaterSystem->States[State->WaterState]; 320 | beaufort_state *WStateB = &WaterSystem->States[State->WaterState + 1]; 321 | 322 | State->WaterCounter += Input->dTime; 323 | 324 | vec3f *WaterPositions = (vec3f*)WaterSystem->Positions; 325 | vec3f *WaterNormals = (vec3f*)WaterSystem->Normals; 326 | 327 | vec3f *WaterOrigPositionsA = (vec3f*)WStateA->OrigPositions; 328 | vec3f *WaterOrigPositionsB = (vec3f*)WStateB->OrigPositions; 329 | 330 | real32 dT = (real32)State->WaterCounter; 331 | 332 | int N = water::system::WaterN; 333 | int NPlus1 = N+1; 334 | 335 | float Lambda = -1.0f; 336 | 337 | complex *hT = (complex*)WaterSystem->hTilde; 338 | complex *hTSX = (complex*)WaterSystem->hTildeSlopeX; 339 | complex *hTSZ = (complex*)WaterSystem->hTildeSlopeZ; 340 | complex *hTDX = (complex*)WaterSystem->hTildeDX; 341 | complex *hTDZ = (complex*)WaterSystem->hTildeDZ; 342 | 343 | real32 dWidth = Mix((real32)WStateA->Width, (real32)WStateB->Width, State->WaterStateInterp); 344 | 345 | // Prepare 346 | for(int m_prime = 0; m_prime < N; ++m_prime) 347 | { 348 | real32 Kz = M_PI * (2.f * m_prime - N) / dWidth; 349 | for(int n_prime = 0; n_prime < N; ++n_prime) 350 | { 351 | real32 Kx = M_PI * (2.f * n_prime - N) / dWidth; 352 | real32 Len = sqrtf(Square(Kx) + Square(Kz)); 353 | int Idx = m_prime * N + n_prime; 354 | 355 | hT[Idx] = ComputeHTilde(WStateA, WStateB, State->WaterStateInterp, dT, n_prime, m_prime); 356 | hTSX[Idx] = hT[Idx] * complex(0, Kx); 357 | hTSZ[Idx] = hT[Idx] * complex(0, Kz); 358 | if(Len < 1e-6f) 359 | { 360 | hTDX[Idx] = complex(0, 0); 361 | hTDZ[Idx] = complex(0, 0); 362 | } else { 363 | hTDX[Idx] = hT[Idx] * complex(0, -Kx/Len); 364 | hTDZ[Idx] = hT[Idx] * complex(0, -Kz/Len); 365 | } 366 | } 367 | } 368 | 369 | // Evaluate 370 | for(int m_prime = 0; m_prime < N; ++m_prime) 371 | { 372 | FFTEvaluate(WaterSystem, hT, hT, 1, m_prime * N, N); 373 | FFTEvaluate(WaterSystem, hTSX, hTSX, 1, m_prime * N, N); 374 | FFTEvaluate(WaterSystem, hTSZ, hTSZ, 1, m_prime * N, N); 375 | FFTEvaluate(WaterSystem, hTDX, hTDX, 1, m_prime * N, N); 376 | FFTEvaluate(WaterSystem, hTDZ, hTDZ, 1, m_prime * N, N); 377 | } 378 | 379 | for(int n_prime = 0; n_prime < N; ++n_prime) 380 | { 381 | FFTEvaluate(WaterSystem, hT, hT, N, n_prime, N); 382 | FFTEvaluate(WaterSystem, hTSX, hTSX, N, n_prime, N); 383 | FFTEvaluate(WaterSystem, hTSZ, hTSZ, N, n_prime, N); 384 | FFTEvaluate(WaterSystem, hTDX, hTDX, N, n_prime, N); 385 | FFTEvaluate(WaterSystem, hTDZ, hTDZ, N, n_prime, N); 386 | } 387 | 388 | // Fill results 389 | float Signs[] = { 1.f, -1.f }; 390 | for(int m_prime = 0; m_prime < N; ++m_prime) 391 | { 392 | for(int n_prime = 0; n_prime < N; ++n_prime) 393 | { 394 | int Idx = m_prime * N + n_prime; // for htilde 395 | int Idx1 = m_prime * NPlus1 + n_prime; // for vertices 396 | 397 | int Sign = Signs[(n_prime + m_prime) & 1]; 398 | 399 | hT[Idx] = hT[Idx] * Sign; 400 | WaterPositions[Idx1].y = hT[Idx].r; 401 | 402 | hTDX[Idx] = hTDX[Idx] * Sign; 403 | hTDZ[Idx] = hTDZ[Idx] * Sign; 404 | { 405 | vec3f OP = Mix(WaterOrigPositionsA[Idx1], WaterOrigPositionsB[Idx1], State->WaterStateInterp); 406 | WaterPositions[Idx1].x = OP.x + Lambda * hTDX[Idx].r; 407 | WaterPositions[Idx1].z = OP.z + Lambda * hTDZ[Idx].r; 408 | } 409 | 410 | hTSX[Idx] = hTSX[Idx] * Sign; 411 | hTSZ[Idx] = hTSZ[Idx] * Sign; 412 | vec3f Normal = Normalize(vec3f(-hTSX[Idx].r, 1, -hTSZ[Idx].r)); 413 | 414 | WaterNormals[Idx1] = Normal; 415 | 416 | if(n_prime == 0 && m_prime == 0) 417 | { 418 | vec3f OP = Mix(WaterOrigPositionsA[Idx1 + N + NPlus1 * N], WaterOrigPositionsB[Idx1 + N + NPlus1 * N], State->WaterStateInterp); 419 | WaterPositions[Idx1 + N + NPlus1 * N].x = OP.x + Lambda * hTDX[Idx].r; 420 | WaterPositions[Idx1 + N + NPlus1 * N].y = hT[Idx].r; 421 | WaterPositions[Idx1 + N + NPlus1 * N].z = OP.z + Lambda * hTDZ[Idx].r; 422 | 423 | WaterNormals[Idx1 + N + NPlus1 * N] = Normal; 424 | } 425 | if(n_prime == 0) 426 | { 427 | vec3f OP = Mix(WaterOrigPositionsA[Idx1 + N], WaterOrigPositionsB[Idx1 + N], State->WaterStateInterp); 428 | WaterPositions[Idx1 + N].x = OP.x + Lambda * hTDX[Idx].r; 429 | WaterPositions[Idx1 + N].y = hT[Idx].r; 430 | WaterPositions[Idx1 + N].z = OP.z + Lambda * hTDZ[Idx].r; 431 | 432 | WaterNormals[Idx1 + N] = Normal; 433 | } 434 | if(m_prime == 0) 435 | { 436 | vec3f OP = Mix(WaterOrigPositionsA[Idx1 + NPlus1 * N], WaterOrigPositionsB[Idx1 + NPlus1 * N], State->WaterStateInterp); 437 | WaterPositions[Idx1 + NPlus1 * N].x = OP.x + Lambda * hTDX[Idx].r; 438 | WaterPositions[Idx1 + NPlus1 * N].y = hT[Idx].r; 439 | WaterPositions[Idx1 + NPlus1 * N].z = OP.z + Lambda * hTDZ[Idx].r; 440 | 441 | WaterNormals[Idx1 + NPlus1 * N] = Normal; 442 | } 443 | } 444 | } 445 | UpdateWaterMesh(WaterSystem); 446 | #endif 447 | } 448 | 449 | real32 IntersectPlane(vec3f const &N, vec3f const &P0, vec3f const &RayOrg, vec3f const &RayDir) 450 | { 451 | real32 Denom = Dot(N, RayDir); 452 | if(std::fabs(Denom) > 1e-5) 453 | { 454 | vec3f P0Org = P0 - RayOrg; 455 | real32 T = Dot(P0Org, N) / Denom; 456 | if(T >= 0.f) 457 | return T; 458 | return -1.f; 459 | } 460 | return -1.f; 461 | } 462 | 463 | static const float S_Upper = 5.f; // TODO - this is the upper level of displacement, should be parameterized 464 | static const float M2_FixedLength = 10.f; // Fixed length along the Fwd vector for method 2 projector direction 465 | 466 | void GetProjectorPositionAndDirection(const camera &Camera, 467 | vec3f &ProjectorPosition, vec3f &ProjectorTarget) 468 | { 469 | ProjectorPosition = Camera.Position + Camera.PositionDecimal; 470 | //ProjectorPosition.y = Max(ProjectorPosition.y, S_Upper); // limit Projector height above upper displacement 471 | 472 | // Get projector orientation 473 | vec3f D = Camera.Forward; 474 | vec3f N = vec3f(0,1,0); // plane normal 475 | real32 NdotD = Dot(D, N); 476 | if(NdotD > 0.f) 477 | { // Mirror direction if not towards plane 478 | D.y = -D.y; 479 | NdotD = -NdotD; 480 | } 481 | 482 | // method 1 : to the intersection of the camera direction and the sea plane 483 | real32 T = IntersectPlane(N, vec3f(0,0,0), ProjectorPosition, D); 484 | Assert(T >= 0.f); 485 | vec3f M1 = ProjectorPosition + D * T; 486 | 487 | // method 2 : to the 2d plane projection of a fixed length direction along the fwd vector 488 | vec3f M2 = ProjectorPosition + Camera.Forward * M2_FixedLength; 489 | M2.y = 0.f; 490 | 491 | // The result is a linear mix between the two methods depending on the angle of the cam 492 | // view direction and the sea normal 493 | ProjectorTarget = Lerp(M2, M1, NdotD); 494 | } 495 | 496 | void Render(game::state *State, uint32 /*Envmap*/, uint32 /*GGXLUT*/) 497 | { 498 | glDisable(GL_CULL_FACE); 499 | glUseProgram(WaterSystem->ProgramWater); 500 | { 501 | uint32 Loc = glGetUniformLocation(WaterSystem->ProgramWater, "ViewMatrix"); 502 | rf::SendMat4(Loc, State->Camera.ViewMatrix); 503 | rf::CheckGLError("ViewMatrix"); 504 | } 505 | 506 | #if 0 507 | camera WPC = State->Camera; 508 | WPC.Theta = Min(WPC.Theta, (real32(M_PI) * 0.5) - 1e-5f); 509 | WPC.Theta = WPC.Theta - sin(WPC.Theta); 510 | WPC.Forward = SphericalToCartesian(WPC.Theta, WPC.Phi); 511 | WPC.Right = Normalize(Cross(WPC.Forward, vec3f(0, 1, 0))); 512 | WPC.Up = Normalize(Cross(WPC.Right, WPC.Forward)); 513 | WPC.Target = WPC.Position + WPC.Forward; 514 | WPC.ViewMatrix = mat4f::LookAt(WPC.Position, WPC.Target, WPC.Up); 515 | vec3f Pos = State->Camera.Position; 516 | vec3f Target = Pos + vec3f(0,-1,0); 517 | vec3f Fwd = Normalize(Target - Fwd); 518 | vec3f Right = Normalize(Cross(Fwd, vec3f(0, 1, 0))); 519 | vec3f Up = Normalize(Cross(Right, Fwd)); 520 | #endif 521 | 522 | vec3f ProjPos, ProjTarget; 523 | GetProjectorPositionAndDirection(State->Camera, ProjPos, ProjTarget); 524 | vec3f ProjFwd = Normalize(ProjTarget - ProjPos); 525 | vec3f ProjRight = Normalize(Cross(ProjFwd, vec3f(0,1,0))); 526 | vec3f ProjUp = Normalize(Cross(ProjRight, ProjFwd)); 527 | mat4f ProjectorMatrix = mat4f::LookAt(ProjPos, ProjTarget, ProjUp); 528 | 529 | rf::SendFloat(glGetUniformLocation(WaterSystem->ProgramWater, "Time"), (real32)State->EngineTime); 530 | rf::SendVec3(glGetUniformLocation(WaterSystem->ProgramWater, "ProjectorPosition"), ProjPos); 531 | rf::SendMat4(glGetUniformLocation(WaterSystem->ProgramWater, "WaterProjMatrix"), ProjectorMatrix); 532 | glBindVertexArray(ScreenQuad.VAO); 533 | RenderMesh(&ScreenQuad); 534 | glEnable(GL_CULL_FACE); 535 | #if 0 536 | glUseProgram(WaterSystem->ProgramWater); 537 | glDisable(GL_CULL_FACE); 538 | { 539 | uint32 Loc = glGetUniformLocation(WaterSystem->ProgramWater, "ViewMatrix"); 540 | rf::SendMat4(Loc, State->Camera.ViewMatrix); 541 | rf::CheckGLError("ViewMatrix"); 542 | } 543 | uint32 Loc = glGetUniformLocation(WaterSystem->ProgramWater, "LightColor"); 544 | rf::SendVec4(Loc, State->LightColor); 545 | Loc = glGetUniformLocation(WaterSystem->ProgramWater, "CameraPos"); 546 | rf::SendVec3(Loc, State->Camera.Position); 547 | Loc = glGetUniformLocation(WaterSystem->ProgramWater, "SunDirection"); 548 | rf::SendVec3(Loc, State->SunDirection); 549 | Loc = glGetUniformLocation(WaterSystem->ProgramWater, "Time"); 550 | rf::SendFloat(Loc, State->EngineTime); 551 | 552 | 553 | Loc = glGetUniformLocation(WaterSystem->ProgramWater, "ModelMatrix"); 554 | mat4f ModelMatrix; 555 | glBindVertexArray(WaterSystem->VAO); 556 | 557 | beaufort_state *WaterStateA = &WaterSystem->States[State->WaterState]; 558 | beaufort_state *WaterStateB = &WaterSystem->States[State->WaterState + 1]; 559 | real32 dWidth = Mix((real32)WaterStateA->Width, (real32)WaterStateB->Width, State->WaterStateInterp); 560 | //dWidth *= (State->WaterState+1) * 1.5; 561 | 562 | real32 Interp = (State->WaterState+1) + State->WaterStateInterp; 563 | 564 | glActiveTexture(GL_TEXTURE0); 565 | glBindTexture(GL_TEXTURE_2D, GGXLUT); 566 | glActiveTexture(GL_TEXTURE1); 567 | glBindTexture(GL_TEXTURE_CUBE_MAP, Envmap); 568 | 569 | 570 | int Repeat = 1; 571 | int Middle = (Repeat-1)/2; 572 | for(int j = 0; j < Repeat; ++j) 573 | { 574 | for(int i = 0; i < Repeat; ++i) 575 | { 576 | // MIDDLE 577 | real32 PositionScale = dWidth * (Interp); 578 | vec3f Position(PositionScale * (Middle-i), 0.f, PositionScale * (Middle-j)); 579 | vec3f Scale(Interp, Interp, Interp); 580 | vec3f Rotation(0, State->WaterDirection, 0); 581 | mat4f RotationMatrix; 582 | RotationMatrix.FromAxisAngle(Rotation); 583 | ModelMatrix.FromTRS(Position, vec3f(0), Scale); 584 | ModelMatrix = RotationMatrix * ModelMatrix; 585 | 586 | rf::SendMat4(Loc, ModelMatrix); 587 | glDrawElements(GL_TRIANGLES, WaterSystem->IndexCount, GL_UNSIGNED_INT, 0); 588 | } 589 | } 590 | glEnable(GL_CULL_FACE); 591 | #endif 592 | } 593 | 594 | void ReloadShaders(rf::context *Context) 595 | { 596 | path VSPath, FSPath; 597 | 598 | rf::ConcatStrings(VSPath, rf::ctx::GetExePath(Context), "data/shaders/water_vert.glsl"); 599 | rf::ConcatStrings(FSPath, rf::ctx::GetExePath(Context), "data/shaders/water_frag.glsl"); 600 | WaterSystem->ProgramWater = rf::BuildShader(Context, VSPath, FSPath); 601 | glUseProgram(WaterSystem->ProgramWater); 602 | //rf::SendInt(glGetUniformLocation(WaterSystem->ProgramWater, "GGXLUT"), 0); 603 | //rf::SendInt(glGetUniformLocation(WaterSystem->ProgramWater, "Skybox"), 1); 604 | rf::CheckGLError("Water Shader"); 605 | 606 | rf::ctx::RegisterShader3D(Context, WaterSystem->ProgramWater); 607 | 608 | /* 609 | MakeRelativePath(RH, VSPath, "data/shaders/waterproj_vert.glsl"); 610 | MakeRelativePath(RH, VSPath, "data/shaders/waterproj_frag.glsl"); 611 | ProjWaterProgram = BuildShader(Memory, VSPath, FSPath); 612 | glUseProgram(ProjWaterProgram); 613 | CheckGLError("Proj Water Shader"); 614 | 615 | context::RegisterShader3D(Context, ProjWaterProgram); 616 | */ 617 | } 618 | 619 | } 620 | -------------------------------------------------------------------------------- /src/Systems/water.h: -------------------------------------------------------------------------------- 1 | #ifndef WATER_H 2 | #define WATER_H 3 | 4 | #include "definitions.h" 5 | 6 | namespace game { 7 | struct state; 8 | } 9 | 10 | namespace water { 11 | struct beaufort_state 12 | { 13 | int Width; 14 | vec2f Direction; 15 | real32 Amplitude; 16 | 17 | void *OrigPositions; 18 | void *HTilde0; 19 | void *HTilde0mk; 20 | }; 21 | 22 | struct system 23 | { 24 | int static const BeaufortStateCount = 4; 25 | int static const WaterN = 64; 26 | 27 | size_t VertexDataSize; 28 | size_t VertexCount; 29 | real32 *VertexData; 30 | size_t IndexDataSize; 31 | uint32 IndexCount; 32 | uint32 *IndexData; 33 | 34 | beaufort_state States[BeaufortStateCount]; 35 | 36 | // NOTE - Accessor Pointers, index VertexData 37 | void *Positions; 38 | void *Normals; 39 | 40 | complex *hTilde; 41 | complex *hTildeSlopeX; 42 | complex *hTildeSlopeZ; 43 | complex *hTildeDX; 44 | complex *hTildeDZ; 45 | 46 | // NOTE - FFT system 47 | int Switch; 48 | int Log2N; 49 | complex *FFTC[2]; 50 | complex **FFTW; 51 | uint32 *Reversed; 52 | 53 | uint32 VAO; 54 | uint32 VBO[2]; // 0 : idata, 1 : vdata 55 | uint32 ProgramWater; 56 | }; 57 | 58 | void Init(game::state *State, rf::context *Context, uint32 BeaufortState); 59 | void Update(game::state *State, rf::input *Input); 60 | void ReloadShaders(rf::context *Context); 61 | void Render(game::state *State, uint32 Envmap, uint32 GGXLUT); 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /src/definitions.h: -------------------------------------------------------------------------------- 1 | #ifndef RADAR_DEFINITIONS_H 2 | #define RADAR_DEFINITIONS_H 3 | 4 | #include "rf/rf_defs.h" 5 | 6 | #define RADAR_MAJOR 0 7 | #define RADAR_MINOR 0 8 | #define RADAR_PATCH 1 9 | 10 | // TODO - This is temporarily here, this constant should be part of a physics system 11 | real32 static const g_G = 9.807f; 12 | 13 | // NOTE - Systems fwd declarations 14 | struct water_system; //water.h 15 | struct tmp_sound_data; //sound.h 16 | 17 | struct config 18 | { 19 | int32 WindowX; 20 | int32 WindowY; 21 | int32 WindowWidth; 22 | int32 WindowHeight; 23 | int32 MSAA; 24 | bool FullScreen; 25 | bool VSync; 26 | real32 FOV; 27 | real32 NearPlane; 28 | real32 FarPlane; 29 | int32 AnisotropicFiltering; 30 | 31 | real32 CameraSpeedBase; 32 | vec4f CameraSpeedMult; 33 | real32 CameraSpeedAngular; 34 | vec3f CameraPosition; 35 | vec3f CameraForward; 36 | 37 | real32 TimeScale; // Ratio for the length of a day. 1.0 is real time. 38 | // 30.0 is 1 day = 48 minutes 39 | }; 40 | 41 | // NOTE - This memory is allocated at startup 42 | // Each pool is then mapped according to the needed layout 43 | struct memory 44 | { 45 | // NOTE - For Game State. 46 | // This is used for a player's game state and should contain everything 47 | // that is supposed to be saved/load from disk when exiting/entering a 48 | // savegame. 49 | // Use cases : hit points, present entities, game timers, etc... 50 | rf::mem_pool *PermanentMemPool; 51 | 52 | // NOTE - For Session Memory 53 | // Contains everything that is constructed for a whole game session, but, 54 | // contrary to the PermanentMemPool, is destructed forever when exiting 55 | // the game (leaving the game, loading another savegame, etc). 56 | // Use cases : game systems like the ocean, GL resources, Audio buffers, etc) 57 | rf::mem_pool *SessionMemPool; 58 | 59 | // NOTE - For Ephemeral data 60 | // This can be scratched at any frame, using it for something that will 61 | // last more than 1 frame is not a good idea. 62 | // Use cases : temp buffers for quick operations, vertex data before storing 63 | // in managed GL VBOs or AL audio buffers. 64 | rf::mem_pool *ScratchMemPool; 65 | 66 | bool IsValid; 67 | 68 | memory() : PermanentMemPool(nullptr), ScratchMemPool(nullptr), IsValid(false) {} 69 | }; 70 | 71 | struct camera 72 | { 73 | vec3f Position; 74 | vec3f PositionDecimal; 75 | //vec3f Target; 76 | vec3f Up; 77 | vec3f Forward; 78 | vec3f Right; 79 | 80 | real32 Phi, Theta; 81 | 82 | real32 LinearSpeed; 83 | real32 AngularSpeed; 84 | real32 SpeedMult[4]; 85 | 86 | int SpeedMode; // -1 : slower, 0 : normal, 1 : faster, 2 : faster 87 | bool FreeflyMode; 88 | vec2i LastMousePos; 89 | 90 | mat4f ViewMatrix; 91 | }; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/radar.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rf/utils.h" 6 | #include "rf/context.h" 7 | #include "rf/ui.h" 8 | 9 | #include "definitions.h" 10 | 11 | #include "Systems/water.h" 12 | #include "Systems/atmosphere.h" 13 | #include "Systems/planet.h" 14 | #include "Game/sun.h" 15 | #include "tests.h" 16 | 17 | // PLATFORM 18 | int RadarMain(int argc, char **argv); 19 | #if RF_WIN32 20 | #include "radar_win32.cpp" 21 | #elif RF_UNIX 22 | #include "radar_unix.cpp" 23 | #endif 24 | 25 | #define DO_ATMOSPHERE 1 26 | #define DO_WATER 0 27 | #define DO_PLANET 0 28 | 29 | memory *InitMemory() 30 | { 31 | memory *Memory = (memory*)calloc(1, sizeof(memory)); 32 | 33 | Memory->PermanentMemPool = rf::PoolCreate(32 * MB); 34 | Memory->SessionMemPool = rf::PoolCreate(512 * MB); 35 | Memory->ScratchMemPool = rf::PoolCreate(64 * MB); 36 | 37 | Memory->IsValid = Memory->PermanentMemPool && Memory->SessionMemPool && Memory->ScratchMemPool; 38 | 39 | return Memory; 40 | } 41 | void DestroyMemory(memory *Memory) 42 | { 43 | if(Memory->IsValid) 44 | { 45 | rf::PoolFree(&Memory->PermanentMemPool); 46 | rf::PoolFree(&Memory->SessionMemPool); 47 | rf::PoolFree(&Memory->ScratchMemPool); 48 | Memory->IsValid = false; 49 | } 50 | } 51 | 52 | bool ParseConfig(config *ConfigOut, char const *Filename) 53 | { 54 | path ExePath; 55 | rf::GetExecutablePath(ExePath); 56 | 57 | path ConfigPath; 58 | rf::ConcatStrings(ConfigPath, ExePath, Filename); 59 | 60 | void *Content = rf::ReadFileContentsNoContext(ConfigPath, 0); 61 | 62 | cJSON *root = nullptr; 63 | if (Content) 64 | { 65 | root = cJSON_Parse((char*)Content); 66 | } 67 | else 68 | { 69 | printf("Error parsing config file.\n"); 70 | } 71 | 72 | ConfigOut->WindowX = rf::JSON_Get(root, "iWindowX", 200); 73 | ConfigOut->WindowY = rf::JSON_Get(root, "iWindowY", 200); 74 | ConfigOut->WindowWidth = rf::JSON_Get(root, "iWindowWidth", 960); 75 | ConfigOut->WindowHeight = rf::JSON_Get(root, "iWindowHeight", 540); 76 | ConfigOut->MSAA = rf::JSON_Get(root, "iMSAA", 0); 77 | ConfigOut->FullScreen = rf::JSON_Get(root, "bFullScreen", 0) != 0; 78 | ConfigOut->VSync = rf::JSON_Get(root, "bVSync", 0) != 0; 79 | ConfigOut->FOV = (real32)rf::JSON_Get(root, "fFOV", 75.0); 80 | ConfigOut->NearPlane = (real32)rf::JSON_Get(root, "fNearPlane", 0.1); 81 | ConfigOut->FarPlane = (real32)rf::JSON_Get(root, "fFarPlane", 10000.0); 82 | ConfigOut->AnisotropicFiltering = rf::JSON_Get(root, "iAnisotropicFiltering", 1); 83 | 84 | ConfigOut->CameraSpeedBase = (real32)rf::JSON_Get(root, "fCameraSpeedBase", 20.0); 85 | ConfigOut->CameraSpeedMult = rf::JSON_Get(root, "vCameraSpeedMult", vec4f(1)); 86 | ConfigOut->CameraSpeedAngular = (real32)rf::JSON_Get(root, "fCameraSpeedAngular", 0.3); 87 | 88 | ConfigOut->CameraPosition = rf::JSON_Get(root, "vCameraPosition", vec3f(0, 6360001, 0)); 89 | ConfigOut->CameraForward = rf::JSON_Get(root, "vCameraForward", vec3f(1, 0, 0)); 90 | 91 | ConfigOut->TimeScale = (real32)rf::JSON_Get(root, "fTimescale", 30.0); 92 | 93 | if (Content) free(Content); 94 | 95 | return true; 96 | } 97 | 98 | void ReloadShaders(rf::context *Context) 99 | { 100 | rf::ctx::RegisteredShaderClear(Context); 101 | path const &ExePath = rf::ctx::GetExePath(Context); 102 | 103 | path VSPath, FSPath; 104 | 105 | // TODO - TODO - PostProcessprogram shouldnt live in Context, this is application dependent 106 | rf::ConcatStrings(VSPath, ExePath, "data/shaders/screenquad_vert.glsl"); 107 | rf::ConcatStrings(FSPath, ExePath, "data/shaders/hdr_frag.glsl"); 108 | Context->ProgramPostProcess = BuildShader(Context, VSPath, FSPath); 109 | glUseProgram(Context->ProgramPostProcess); 110 | rf::SendInt(glGetUniformLocation(Context->ProgramPostProcess, "HDRFB"), 0); 111 | rf::CheckGLError("HDR Shader"); 112 | 113 | Tests::ReloadShaders(Context); 114 | rf::ui::ReloadShaders(Context); 115 | 116 | #if DO_WATER 117 | water::ReloadShaders(Context); 118 | #endif 119 | #if DO_ATMOSPHERE 120 | atmosphere::ReloadShaders(Context); 121 | #endif 122 | #if DO_PLANET 123 | planet::ReloadShaders(Context); 124 | #endif 125 | rf::ctx::UpdateShaderProjection(Context); 126 | 127 | glUseProgram(0); 128 | } 129 | 130 | void MakeUI(memory *Memory, rf::context *Context, rf::input * /*Input*/) 131 | { 132 | //game_system *System = (game_system*)Memory->PermanentMemPool; 133 | 134 | #if 0 135 | console_log *Log = System->ConsoleLog; 136 | font *FontInfo = ui::GetFont(ui::FONT_DEFAULT); 137 | int32 LineGap = FontInfo->LineGap; 138 | int32 LogHeight = Context->WindowHeight/3; 139 | int32 LogCapacity = Log->StringCount - std::ceil((LogHeight) / (real32)LineGap); 140 | 141 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 142 | // NOTE - Drop Down Console 143 | static bool ConsoleShow = false; 144 | static uint32 ConsolePanel = 0; 145 | static vec3i ConsolePanelPos(0,0,0); 146 | static vec2i ConsolePanelSize(Context->WindowWidth, LogHeight); 147 | static real32 ConsoleSlider = 0.f; 148 | uint32 ConsoleDecorationFlags = ui::DECORATION_BORDER; 149 | 150 | if(KEY_HIT(Input->KeyTilde)) 151 | { 152 | ConsoleShow = !ConsoleShow; 153 | ConsoleDecorationFlags |= ui::DECORATION_FOCUS; // force focus when opening the console 154 | } 155 | 156 | if(ConsoleShow) 157 | { 158 | ConsolePanelSize = vec2i(Context->WindowWidth, LogHeight); 159 | ui::BeginPanel(&ConsolePanel, "", &ConsolePanelPos, &ConsolePanelSize, ui::COLOR_CONSOLEBG, ConsoleDecorationFlags); 160 | ui::MakeSlider(&ConsoleSlider, 0.f, (real32)LogCapacity); 161 | for(uint32 i = 0; i < Log->StringCount; ++i) 162 | { 163 | uint32 RIdx = (Log->ReadIdx + i) % CONSOLE_CAPACITY; 164 | real32 YOffset = (real32)i + ConsoleSlider - (real32)Log->StringCount; 165 | real32 YPos = LogHeight + YOffset * LineGap; 166 | if(YPos < 0) 167 | continue; 168 | if(YPos >= LogHeight) 169 | break; 170 | vec2i Position(0, YPos); 171 | ui::MakeText((void*)Log->MsgStack[RIdx], Log->MsgStack[RIdx], ui::FONT_CONSOLE, Position, 172 | ui::COLOR_CONSOLEFG, 1.f, Context->WindowWidth); 173 | } 174 | ui::EndPanel(); 175 | } 176 | #endif 177 | 178 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 179 | // NOTE - System Panel 180 | static bool SystemShow = false; 181 | 182 | vec2i UIStackPanelSize(360, 0); 183 | 184 | static uint32 SystemButtonPanel = 0; 185 | static char SystemButtonStr[16]; 186 | static vec2i SystemButtonSize(25); 187 | vec3i SystemButtonPos(Context->WindowWidth-SystemButtonSize.x, 0, 0); 188 | static uint32 SystemButtonID = 0; 189 | snprintf(SystemButtonStr, 16, "%s", ICON_FA_COG); 190 | rf::ui::BeginPanel(&SystemButtonPanel, "", &SystemButtonPos, &SystemButtonSize, rf::ui::COLOR_PANELBG, rf::ui::DECORATION_INVISIBLE); 191 | if(rf::ui::MakeButton(&SystemButtonID, SystemButtonStr, rf::ui::FONT_AWESOME, vec2i(0), SystemButtonSize, 0.4f, rf::ui::DECORATION_BORDER)) 192 | { 193 | SystemShow = !SystemShow; 194 | } 195 | rf::ui::EndPanel(); 196 | 197 | static uint32 SystemPanelID = 0; 198 | static vec2i SystemPanelSize(210, 500); 199 | static vec3i SystemPanelPos(Context->WindowWidth - 50 - SystemPanelSize.x, 100, 0); 200 | 201 | if(SystemShow) 202 | { 203 | rf::ui::BeginPanel(&SystemPanelID, "System Info", &SystemPanelPos, &SystemPanelSize, rf::ui::COLOR_PANELBG); 204 | // Session Pool occupancy 205 | int CurrHeight = 0; 206 | real32 ToMiB = 1.f / (real32)MB; 207 | char OccupancyStr[64]; 208 | 209 | static real32 PermanentOccupancy = 0.0f; 210 | PermanentOccupancy = rf::PoolOccupancy(Memory->PermanentMemPool); 211 | uint64 permanentUsedSpace = (uint64)(PermanentOccupancy * Memory->PermanentMemPool->Capacity); 212 | snprintf(OccupancyStr, 64, "permanent stack %.3f / %.2f MiB", permanentUsedSpace*ToMiB, Memory->PermanentMemPool->Capacity*ToMiB); 213 | rf::ui::MakeText(NULL, OccupancyStr, rf::ui::FONT_DEFAULT, vec2i(0, CurrHeight), rf::ui::COLOR_PANELFG); 214 | CurrHeight += 16; 215 | rf::ui::MakeProgressbar(&PermanentOccupancy, 1.f, vec2i(0, CurrHeight), vec2i(300, 10)); 216 | CurrHeight += 16; 217 | 218 | static real32 SessionOccupancy = 0.0f; 219 | SessionOccupancy = rf::PoolOccupancy(Memory->SessionMemPool); 220 | uint64 sessionUsedSpace = (uint64)(SessionOccupancy * Memory->SessionMemPool->Capacity); 221 | snprintf(OccupancyStr, 64, "session stack %.3f / %.2f MiB", sessionUsedSpace*ToMiB, Memory->SessionMemPool->Capacity*ToMiB); 222 | rf::ui::MakeText(NULL, OccupancyStr, rf::ui::FONT_DEFAULT, vec2i(0, CurrHeight), rf::ui::COLOR_PANELFG); 223 | CurrHeight += 16; 224 | rf::ui::MakeProgressbar(&SessionOccupancy, 1.f, vec2i(0, CurrHeight), vec2i(300, 10)); 225 | CurrHeight += 16; 226 | 227 | static real32 ScratchOccupancy = 0.0f; 228 | ScratchOccupancy = rf::PoolOccupancy(Memory->ScratchMemPool); 229 | uint64 scratchUsedSpace = (uint64)(ScratchOccupancy * Memory->ScratchMemPool->Capacity); 230 | snprintf(OccupancyStr, 64, "scratch stack %.3f / %.2f MiB", scratchUsedSpace*ToMiB, Memory->ScratchMemPool->Capacity*ToMiB); 231 | rf::ui::MakeText(NULL, OccupancyStr, rf::ui::FONT_DEFAULT, vec2i(0, CurrHeight), rf::ui::COLOR_PANELFG); 232 | CurrHeight += 16; 233 | rf::ui::MakeProgressbar(&ScratchOccupancy, 1.f, vec2i(0, CurrHeight), vec2i(300, 10)); 234 | CurrHeight += 16; 235 | 236 | static uint32 TmpBut = 0; 237 | rf::ui::MakeButton(&TmpBut, "a", rf::ui::FONT_DEFAULT, vec2i(0, CurrHeight), vec2i(20)); 238 | CurrHeight += 26; 239 | 240 | static uint32 TmpBut2 = 0; 241 | rf::ui::MakeButton(&TmpBut2, "Hello", rf::ui::FONT_DEFAULT, vec2i(0, CurrHeight), vec2i(60,20)); 242 | CurrHeight += 26; 243 | 244 | char Str[16]; 245 | snprintf(Str, 16, "%s%s%s", ICON_FA_SEARCH, ICON_FA_GLASS, ICON_FA_SHARE); 246 | rf::ui::MakeText(NULL, Str, rf::ui::FONT_AWESOME, vec2i(0, 180), rf::ui::COLOR_BORDERBG); 247 | rf::ui::EndPanel(); 248 | } 249 | } 250 | 251 | rf::context_descriptor MakeContextDescriptor(memory *Memory, config *Config, path const ExecutableName) 252 | { 253 | rf::context_descriptor CtxDesc; 254 | CtxDesc.SessionPool = Memory->SessionMemPool; 255 | CtxDesc.ScratchPool = Memory->ScratchMemPool; 256 | // cpy WinX, WinY, WinW, WinH, VSync, FOV, NearPlane, FarPlane from Config to the Descriptor 257 | CtxDesc.WindowX = (real32)Config->WindowX; 258 | CtxDesc.WindowY = (real32)Config->WindowY; 259 | CtxDesc.WindowWidth = Config->WindowWidth; 260 | CtxDesc.WindowHeight = Config->WindowHeight; 261 | CtxDesc.VSync = Config->VSync; 262 | CtxDesc.FOV = Config->FOV; 263 | CtxDesc.NearPlane = Config->NearPlane; 264 | CtxDesc.FarPlane = Config->FarPlane; 265 | memcpy(CtxDesc.ExecutableName, ExecutableName, sizeof(path)); 266 | 267 | return CtxDesc; 268 | } 269 | 270 | int RadarMain(int /*argc*/, char ** /*argv*/) 271 | { 272 | // Init Engine memory 273 | memory *Memory = InitMemory(); 274 | 275 | // Parse Engine config file (or get the default config if inexistent) 276 | config Config; 277 | if(!ParseConfig(&Config, "config.json")) 278 | return 1; 279 | 280 | // Create the RF context 281 | path ExecutableName; 282 | snprintf(ExecutableName, MAX_PATH, "Radar Engine %d.%d.%d", RADAR_MAJOR, RADAR_MINOR, RADAR_PATCH); 283 | rf::context_descriptor CtxDesc = MakeContextDescriptor(Memory, &Config, ExecutableName); 284 | rf::context *Context = rf::ctx::Init(&CtxDesc); 285 | LogInfo(""); 286 | LogInfo("%s", ExecutableName); 287 | 288 | if(!Context->IsValid || !Memory->IsValid) 289 | return 1; 290 | 291 | real64 CurrentTime, LastTime = glfwGetTime(); 292 | real64 TimeCounter = 0.0; 293 | int const GameRefreshHz = 60; 294 | real64 const TargetSecondsPerFrame = 1.0 / (real64)GameRefreshHz; 295 | 296 | rf::BindTexture2D(0, 0); 297 | rf::CheckGLError("Engine Start"); 298 | 299 | if(!Tests::Init(Context, &Config)) 300 | return 1; 301 | 302 | int LastMouseX = 0, LastMouseY = 0; 303 | 304 | rf::mesh ScreenQuad = rf::Make2DQuad(Context, vec2i(-1,1), vec2i(1, -1)); 305 | rf::frame_buffer FPBackbuffer = {}; 306 | 307 | // TMP TextureViewer UI 308 | static uint32 TW_ID = 0; 309 | static real32 TW_ImgScale = 1.0f; 310 | static vec2f TW_ImgOffset(0.f, 0.f); 311 | static vec2i TW_Size(310, 330); 312 | static vec3i TW_Position(Context->WindowWidth - 10 - TW_Size.x, Context->WindowHeight - 10 - TW_Size.y, 0); 313 | 314 | // Game State initialization 315 | game::state *State = rf::PoolAlloc(Memory->PermanentMemPool, 1); 316 | if(!game::Init(State, &Config)) 317 | { 318 | LogError("Error initializing Game State."); 319 | return 1; 320 | } 321 | 322 | // Subsystems initialization 323 | #if DO_ATMOSPHERE 324 | atmosphere::Init(State, Context); 325 | #endif 326 | #if DO_WATER 327 | water::Init(State, Context, State->WaterState); 328 | #endif 329 | #if DO_PLANET 330 | planet::Init(State, Context); 331 | #endif 332 | 333 | // First time shader loading at the end of the initialization phase 334 | ReloadShaders(Context); 335 | 336 | while(Context->IsRunning) 337 | { 338 | rf::input Input = {}; 339 | 340 | CurrentTime = glfwGetTime(); 341 | Input.dTime = CurrentTime - LastTime; 342 | 343 | LastTime = CurrentTime; 344 | State->EngineTime += Input.dTime; 345 | State->dTime = Input.dTime; 346 | TimeCounter += Input.dTime; 347 | 348 | // NOTE - Each frame, clear the Scratch Arena Data 349 | // TODO - Is this too often ? Maybe let it stay several frames 350 | rf::PoolClear(Memory->ScratchMemPool); 351 | 352 | rf::ctx::GetFrameInput(Context, &Input); 353 | 354 | if(Context->HasResized) 355 | { 356 | // Resize FBO 357 | DestroyFramebuffer(&FPBackbuffer); 358 | FPBackbuffer = rf::MakeFramebuffer(1, vec2i(Context->WindowWidth, Context->WindowHeight)); 359 | rf::FramebufferAttachBuffer(&FPBackbuffer, 0, 4, true, true, true); // RGBA16F attachment 360 | rf::CheckGLError("FramebufferAttach"); 361 | } 362 | 363 | Input.MouseDX = Input.MousePosX - LastMouseX; 364 | Input.MouseDY = Input.MousePosY - LastMouseY; 365 | LastMouseX = Input.MousePosX; 366 | LastMouseY = Input.MousePosY; 367 | 368 | glClearColor(Context->ClearColor.x, Context->ClearColor.y, Context->ClearColor.z, Context->ClearColor.w); 369 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 370 | 371 | rf::ui::BeginFrame(&Input); 372 | 373 | game::Update(State, &Input, Context); 374 | 375 | // Local timed stuff 376 | if(TimeCounter > 0.1) 377 | { 378 | TimeCounter = 0.0; 379 | } 380 | 381 | // Additional termination test with escape key 382 | if (KEY_PRESSED(Input.Keys[KEY_ESCAPE])) 383 | { 384 | Context->IsRunning = false; 385 | } 386 | 387 | // Shader hot reload key (Shift-F11) 388 | if(KEY_PRESSED(Input.Keys[KEY_LEFT_SHIFT]) && KEY_RELEASED(Input.Keys[KEY_F11])) 389 | { 390 | ReloadShaders(Context); 391 | } 392 | 393 | // Wireframe toggle key (Shift-F10) 394 | if(KEY_PRESSED(Input.Keys[KEY_LEFT_SHIFT]) && KEY_RELEASED(Input.Keys[KEY_F10])) 395 | { 396 | rf::ctx::SetWireframeMode(Context); 397 | } 398 | 399 | 400 | glBindFramebuffer(GL_FRAMEBUFFER, FPBackbuffer.FBO); 401 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 402 | 403 | Tests::Render(State, &Input, Context); 404 | 405 | #if DO_ATMOSPHERE 406 | atmosphere::Render(State, Context); 407 | #endif 408 | #if DO_WATER 409 | water::Update(State, &Input); 410 | water::Render(State, 0, 0); 411 | #endif 412 | #if DO_PLANET 413 | planet::Render(State, Context); 414 | #endif 415 | 416 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 417 | 418 | // Toggle wireframe off to draw the UI and the PostProcess pass 419 | GLenum CurrWireframemode = rf::ctx::SetWireframeMode(Context, GL_FILL); 420 | 421 | glUseProgram(Context->ProgramPostProcess); 422 | uint32 MipmapLogLoc = glGetUniformLocation(Context->ProgramPostProcess, "MipmapQueryLevel"); 423 | uint32 ResolutionLoc = glGetUniformLocation(Context->ProgramPostProcess, "Resolution"); 424 | rf::SendFloat(MipmapLogLoc, Context->WindowSizeLogLevel); 425 | rf::SendVec2(ResolutionLoc, vec2f((real32)Context->WindowWidth, (real32)Context->WindowHeight)); 426 | rf::SendVec3(glGetUniformLocation(Context->ProgramPostProcess, "CameraPosition"), vec3f(State->Camera.Position + State->Camera.PositionDecimal)); 427 | rf::BindTexture2D(FPBackbuffer.BufferIDs[0], 0); 428 | glGenerateMipmap(GL_TEXTURE_2D); // generate mipmap for the color buffer 429 | rf::CheckGLError("TexBind"); 430 | 431 | glBindVertexArray(ScreenQuad.VAO); 432 | rf::RenderMesh(&ScreenQuad); 433 | 434 | MakeUI(Memory, Context, &Input); 435 | 436 | #if 0 437 | rf::font *FontInfo = rf::ui::GetFont(rf::ui::FONT_AWESOME); 438 | rf::ui::BeginPanel(&TW_ID, "Texture Viewer", &TW_Position, &TW_Size, rf::ui::COLOR_PANELBG, rf::ui::DECORATION_TITLEBAR | rf::ui::DECORATION_BORDER); 439 | rf::ui::MakeImage(&TW_ImgScale, atmosphere::TransmittanceTexture/*FPBackbuffer.BufferIDs[0]*/, &TW_ImgOffset, vec2i(300, 300), false); 440 | rf::ui::EndPanel(); 441 | #endif 442 | 443 | rf::ui::Draw(); 444 | 445 | rf::ctx::SetWireframeMode(Context, CurrWireframemode); 446 | 447 | glfwSwapBuffers(Context->Window); 448 | } 449 | 450 | rf::DestroyFramebuffer(&FPBackbuffer); 451 | Tests::Destroy(); 452 | 453 | game::Destroy(State); 454 | rf::ctx::Destroy(Context); 455 | DestroyMemory(Memory); 456 | return 0; 457 | } 458 | -------------------------------------------------------------------------------- /src/radar_unix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #if 0 10 | 11 | static path DllName = "sun.so"; 12 | static path DllDynamicCopyName = "sun_temp.so"; 13 | struct game_code 14 | { 15 | void *GameDLL; 16 | time_t GameDLLLastWriteTime; 17 | bool IsValid; 18 | 19 | // DLL Dynamic Entry Points 20 | game_update_function *GameUpdate; 21 | }; 22 | 23 | time_t FindLastWriteTime(path Path) 24 | { 25 | struct stat Info; 26 | stat(Path, &Info); 27 | return Info.st_mtime; 28 | } 29 | 30 | game_code LoadGameCode(path DllSrcPath, path DllDstPath) 31 | { 32 | game_code Result = {}; 33 | 34 | CopyFile(DllSrcPath, DllDstPath); 35 | 36 | Result.GameUpdate = GameUpdateStub; 37 | Result.GameDLL = dlopen(DllDstPath, RTLD_NOW); 38 | 39 | if(Result.GameDLL) 40 | { 41 | Result.GameDLLLastWriteTime = FindLastWriteTime(DllSrcPath); 42 | Result.GameUpdate = (game_update_function*)dlsym(Result.GameDLL, "GameUpdate"); 43 | Result.IsValid = (Result.GameUpdate != NULL); 44 | } 45 | 46 | return Result; 47 | 48 | } 49 | 50 | void UnloadGameCode(game_code *Code, path DuplicateDLL) 51 | { 52 | if(Code->GameDLL) 53 | { 54 | dlclose(Code->GameDLL); 55 | Code->GameDLL = 0; 56 | 57 | if(DuplicateDLL) 58 | { 59 | unlink(DuplicateDLL); 60 | } 61 | } 62 | 63 | Code->IsValid = false; 64 | Code->GameUpdate = GameUpdateStub; 65 | } 66 | 67 | bool CheckNewDllVersion(game_code *Game, path DllPath) 68 | { 69 | time_t WriteTime = FindLastWriteTime(DllPath); 70 | if(WriteTime != Game->GameDLLLastWriteTime) 71 | { 72 | Game->GameDLLLastWriteTime = WriteTime; 73 | return true; 74 | } 75 | 76 | return false; 77 | } 78 | #endif 79 | 80 | int main(int argc, char **argv) 81 | { 82 | return RadarMain(argc, argv); 83 | } 84 | -------------------------------------------------------------------------------- /src/radar_win32.cpp: -------------------------------------------------------------------------------- 1 | #if 0 2 | static path DllName = "sun.dll"; 3 | static path DllDynamicCopyName = "sun_temp.dll"; 4 | struct game_code 5 | { 6 | HMODULE GameDLL; 7 | FILETIME GameDLLLastWriteTime; 8 | bool IsValid; 9 | 10 | // DLL Dynamic Entry Points 11 | game_update_function *GameUpdate; 12 | }; 13 | 14 | FILETIME FindLastWriteTime(path Path) 15 | { 16 | FILETIME LastWriteTime = {}; 17 | 18 | WIN32_FIND_DATA FindData; 19 | HANDLE H = FindFirstFileA(Path, &FindData); 20 | if(H != INVALID_HANDLE_VALUE) 21 | { 22 | LastWriteTime = FindData.ftLastWriteTime; 23 | FindClose(H); 24 | } 25 | 26 | return LastWriteTime; 27 | } 28 | 29 | game_code LoadGameCode(path DllSrcPath, path DllDstPath) 30 | { 31 | game_code Result = {}; 32 | 33 | CopyFileA(DllSrcPath, DllDstPath, FALSE); 34 | 35 | Result.GameUpdate = GameUpdateStub; 36 | Result.GameDLL = LoadLibraryA(DllDstPath); 37 | 38 | if(Result.GameDLL) 39 | { 40 | Result.GameDLLLastWriteTime = FindLastWriteTime(DllSrcPath); 41 | 42 | Result.GameUpdate = (game_update_function*)GetProcAddress(Result.GameDLL, "GameUpdate"); 43 | Result.IsValid = (Result.GameUpdate != NULL); 44 | } 45 | 46 | return Result; 47 | } 48 | 49 | void UnloadGameCode(game_code *Code, path DuplicateDLL) 50 | { 51 | if(Code->GameDLL) 52 | { 53 | FreeLibrary(Code->GameDLL); 54 | 55 | if(DuplicateDLL) 56 | { 57 | DeleteFileA(DuplicateDLL); 58 | } 59 | } 60 | 61 | Code->IsValid = false; 62 | Code->GameUpdate = GameUpdateStub; 63 | } 64 | 65 | bool CheckNewDllVersion(game_code *Game, path DllPath) 66 | { 67 | FILETIME WriteTime = FindLastWriteTime(DllPath); 68 | if(CompareFileTime(&Game->GameDLLLastWriteTime, &WriteTime) != 0) { 69 | Game->GameDLLLastWriteTime = WriteTime; 70 | return true; 71 | } 72 | 73 | return false; 74 | } 75 | #endif 76 | 77 | // NOTE - We just call the platform-agnostic main function here 78 | int main() 79 | { 80 | return RadarMain(__argc, __argv); 81 | } 82 | -------------------------------------------------------------------------------- /src/sound.cpp: -------------------------------------------------------------------------------- 1 | #include "sound.h" 2 | 3 | #include "AL/al.h" 4 | #include "AL/alc.h" 5 | 6 | namespace sound { 7 | bool Init() 8 | { 9 | ALCdevice *ALDevice = alcOpenDevice(NULL); 10 | 11 | bool ALValid = (NULL != ALDevice); 12 | if(ALValid) 13 | { 14 | ALCcontext *ALContext = alcCreateContext(ALDevice, NULL); 15 | alcMakeContextCurrent(ALContext); 16 | alGetError(); // Clear Error Stack 17 | } 18 | else 19 | { 20 | printf("Couldn't init OpenAL.\n"); 21 | } 22 | 23 | return ALValid; 24 | } 25 | 26 | void Destroy() 27 | { 28 | ALCcontext *ALContext = alcGetCurrentContext(); 29 | if(ALContext) 30 | { 31 | ALCdevice *ALDevice = alcGetContextsDevice(ALContext); 32 | alcMakeContextCurrent(NULL); 33 | alcDestroyContext(ALContext); 34 | alcCloseDevice(ALDevice); 35 | } 36 | } 37 | 38 | bool CheckALError() 39 | { 40 | ALenum Error = alGetError(); 41 | if(Error != AL_NO_ERROR) 42 | { 43 | char ErrorMsg[128]; 44 | switch(Error) 45 | { 46 | case AL_INVALID_NAME: 47 | { 48 | snprintf(ErrorMsg, 128, "Bad Name ID passed to AL."); 49 | }break; 50 | case AL_INVALID_ENUM: 51 | { 52 | snprintf(ErrorMsg, 128, "Invalid Enum passed to AL."); 53 | }break; 54 | case AL_INVALID_VALUE: 55 | { 56 | snprintf(ErrorMsg, 128, "Invalid Value passed to AL."); 57 | }break; 58 | case AL_INVALID_OPERATION: 59 | { 60 | snprintf(ErrorMsg, 128, "Invalid Operation requested to AL."); 61 | }break; 62 | case AL_OUT_OF_MEMORY: 63 | { 64 | snprintf(ErrorMsg, 128, "Out of Memory."); 65 | }break; 66 | } 67 | 68 | printf("OpenAL Error : %s\n", ErrorMsg); 69 | return false; 70 | } 71 | return true; 72 | } 73 | 74 | bool TempPrepareSound(ALuint *Buffer, ALuint *Source) 75 | { 76 | // Generate Buffers 77 | alGenBuffers(1, Buffer); 78 | if(!CheckALError()) return false; 79 | 80 | // Generate Sources 81 | alGenSources(1, Source); 82 | if(!CheckALError()) return false; 83 | 84 | // Attach Buffer to Source 85 | alSourcei(*Source, AL_LOOPING, AL_TRUE); 86 | if(!CheckALError()) return false; 87 | 88 | return true; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/sound.h: -------------------------------------------------------------------------------- 1 | #ifndef SOUND_H 2 | #define SOUND_H 3 | 4 | #include "rf/rf_common.h" 5 | 6 | namespace sound { 7 | bool Init(); 8 | void Destroy(); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/tests.cpp: -------------------------------------------------------------------------------- 1 | #include "tests.h" 2 | 3 | #include "rf/utils.h" 4 | #include "rf/context.h" 5 | 6 | namespace Tests 7 | { 8 | // PBR Materials tests 9 | uint32 Program3D = 0; 10 | uint32 GGXLUT = 0; 11 | uint32 HDRCubemapEnvmap, HDRIrradianceEnvmap, HDRGlossyEnvmap; 12 | rf::mesh Sphere = {}; 13 | rf::mesh Cube = {}; 14 | 15 | // PBR GLTF Models tests 16 | uint32 const PBRModelsCount = 1; 17 | uint32 const PBRModelsCapacity = 2; 18 | rf::model PBRModels[PBRModelsCapacity]; 19 | float rotation[PBRModelsCapacity] = { 0.f }; 20 | vec3f translation[PBRModelsCapacity] = { vec3f(-5.f, 0.f, 0.f) , vec3f(0,-1.98f,0) }; 21 | int translationDir[PBRModelsCapacity] = { 1 }; 22 | vec3f renderOrigin(0.f, 6360100.f, 0.f); 23 | 24 | // PBR MATERIALS 25 | uint32 *Texture1; 26 | uint32 const MaterialCount = 6; 27 | uint32 *PBR_Albedo[MaterialCount]; 28 | uint32 *PBR_MetalRoughness[MaterialCount]; 29 | uint32 *PBR_Normal[MaterialCount]; 30 | 31 | // SOUND 32 | //#include "AL/al.h" 33 | //ALuint AudioBuffer; 34 | //ALuint AudioSource; 35 | 36 | // SKYBOX 37 | rf::mesh SkyboxCube = {}; 38 | uint32 ProgramSkybox = 0; 39 | 40 | void Destroy() 41 | { 42 | #if TEST_MODELS 43 | for (uint32 model = 0; model < PBRModelsCount; ++model) 44 | { 45 | ModelFree(&PBRModels[model]); 46 | } 47 | #endif 48 | glDeleteTextures(1, &GGXLUT); 49 | glDeleteTextures(1, &HDRCubemapEnvmap); 50 | glDeleteTextures(1, &HDRGlossyEnvmap); 51 | glDeleteTextures(1, &HDRIrradianceEnvmap); 52 | rf::DestroyMesh(&Sphere); 53 | rf::DestroyMesh(&Cube); 54 | rf::DestroyMesh(&SkyboxCube); 55 | glDeleteProgram(ProgramSkybox); 56 | glDeleteProgram(Program3D); 57 | } 58 | 59 | void ReloadShaders(rf::context *Context) 60 | { 61 | path const &ExePath = rf::ctx::GetExePath(Context); 62 | path VSPath, FSPath; 63 | 64 | rf::ConcatStrings(VSPath, ExePath, "data/shaders/vert.glsl"); 65 | rf::ConcatStrings(FSPath, ExePath, "data/shaders/frag.glsl"); 66 | Program3D = rf::BuildShader(Context, VSPath, FSPath); 67 | glUseProgram(Program3D); 68 | rf::SendInt(glGetUniformLocation(Program3D, "Albedo"), 0); 69 | rf::SendInt(glGetUniformLocation(Program3D, "NormalMap"), 1); 70 | rf::SendInt(glGetUniformLocation(Program3D, "MetallicRoughness"), 2); 71 | rf::SendInt(glGetUniformLocation(Program3D, "Emissive"), 3); 72 | rf::SendInt(glGetUniformLocation(Program3D, "GGXLUT"), 4); 73 | rf::SendInt(glGetUniformLocation(Program3D, "Skybox"), 5); 74 | rf::CheckGLError("Mesh Shader"); 75 | 76 | rf::ctx::RegisterShader3D(Context, Program3D); 77 | 78 | rf::ConcatStrings(VSPath, ExePath, "data/shaders/skybox_vert.glsl"); 79 | rf::ConcatStrings(FSPath, ExePath, "data/shaders/skybox_frag.glsl"); 80 | ProgramSkybox = rf::BuildShader(Context, VSPath, FSPath); 81 | glUseProgram(ProgramSkybox); 82 | rf::SendInt(glGetUniformLocation(ProgramSkybox, "Skybox"), 0); 83 | rf::CheckGLError("Skybox Shader"); 84 | 85 | rf::ctx::RegisterShader3D(Context, ProgramSkybox); 86 | } 87 | 88 | bool Init(rf::context *Context, config const * Config) 89 | { 90 | GGXLUT = rf::PrecomputeGGXLUT(Context, 512); 91 | rf::ComputeIrradianceCubemap(Context, "data/envmap_monument.hdr", 92 | &HDRCubemapEnvmap, &HDRGlossyEnvmap, &HDRIrradianceEnvmap); 93 | 94 | Sphere = rf::MakeUnitSphere(true, 3); 95 | Cube = rf::MakeUnitCube(); 96 | SkyboxCube = rf::MakeUnitCube(false); 97 | 98 | #if TEST_MODELS 99 | if(!rf::ModelLoadGLTF(Context, &PBRModels[0], "data/gltftest/suzanne/Suzanne.gltf", Config->AnisotropicFiltering)) 100 | return false; 101 | //if(!rf::ModelLoadGLTF(Context, &PBRModels[1], "data/gltftest/lantern/Lantern.gltf", Config->AnisotropicFiltering)) 102 | //return 1; 103 | #endif 104 | 105 | #if TEST_PBRMATERIALS 106 | // PBR Texture Tes 107 | Texture1 = rf::ResourceLoad2DTexture(Context, "data/crate1_diffuse.png", 108 | false, false, Config->AnisotropicFiltering); 109 | 110 | PBR_Albedo[0] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/StreakedMetal/albedo.png", 111 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 112 | PBR_MetalRoughness[0] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/StreakedMetal/metalroughness.png", 113 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 114 | PBR_Normal[0] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/StreakedMetal/normal.png", 115 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 116 | 117 | PBR_Albedo[1] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/ScuffedGold/albedo.png", 118 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 119 | PBR_MetalRoughness[1] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/ScuffedGold/metalroughness.png", 120 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 121 | PBR_Normal[1] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/ScuffedGold/normal.png", 122 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 123 | 124 | PBR_Albedo[2] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/RustedIron/albedo.png", 125 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 126 | PBR_MetalRoughness[2] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/RustedIron/metalroughness.png", 127 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 128 | PBR_Normal[2] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/RustedIron/normal.png", 129 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 130 | 131 | PBR_Albedo[3] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/ScuffedPlastic/albedo_blue.png", 132 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 133 | PBR_MetalRoughness[3] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/ScuffedPlastic/metalroughness.png", 134 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 135 | PBR_Normal[3] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/ScuffedPlastic/normal.png", 136 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 137 | 138 | PBR_Albedo[4] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/SynthRubber/albedo.png", 139 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 140 | PBR_MetalRoughness[4] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/SynthRubber/metalroughness.png", 141 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 142 | PBR_Normal[4] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/SynthRubber/normal.png", 143 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 144 | 145 | PBR_Albedo[5] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/PlasticPattern/albedo.png", 146 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 147 | PBR_MetalRoughness[5] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/PlasticPattern/metalroughness.png", 148 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 149 | PBR_Normal[5] = rf::ResourceLoad2DTexture(Context, "data/PBRTextures/PlasticPattern/normal.png", 150 | false, false, Config->AnisotropicFiltering, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_REPEAT, GL_REPEAT); 151 | #endif 152 | 153 | #if TEST_SOUND 154 | if(TempPrepareSound(&AudioBuffer, &AudioSource)) 155 | { 156 | alSourcePlay(AudioSource); 157 | } 158 | #endif 159 | return true; 160 | } 161 | 162 | void Render(game::state *State, rf::input * Input, rf::context * /*Context*/) 163 | { 164 | mat4f const &ViewMatrix = State->Camera.ViewMatrix; 165 | 166 | #if TEST_MODELS // NOTE - Model rendering test 167 | { 168 | glCullFace(GL_BACK); 169 | glUseProgram(Program3D); 170 | { 171 | uint32 Loc = glGetUniformLocation(Program3D, "ViewMatrix"); 172 | rf::SendMat4(Loc, ViewMatrix); 173 | rf::CheckGLError("ViewMatrix"); 174 | } 175 | 176 | uint32 Loc = glGetUniformLocation(Program3D, "LightColor"); 177 | rf::SendVec4(Loc, State->LightColor); 178 | Loc = glGetUniformLocation(Program3D, "SunDirection"); 179 | rf::SendVec3(Loc, State->SunDirection); 180 | Loc = glGetUniformLocation(Program3D, "CameraPos"); 181 | rf::SendVec3(Loc, State->Camera.Position); 182 | uint32 AlbedoLoc = glGetUniformLocation(Program3D, "AlbedoMult"); 183 | uint32 EmissiveLoc = glGetUniformLocation(Program3D, "EmissiveMult"); 184 | uint32 MetallicLoc = glGetUniformLocation(Program3D, "MetallicMult"); 185 | uint32 RoughnessLoc = glGetUniformLocation(Program3D, "RoughnessMult"); 186 | for(uint32 m = 0; m < PBRModelsCount; ++m) 187 | { 188 | rf::model *Model = &PBRModels[m]; 189 | for(uint32 i = 0; i < BufSize(Model->Meshes); ++i) 190 | { 191 | rf::material const &Mat = Model->Materials[Model->MaterialIdx[i]]; 192 | rf::mesh &Mesh = Model->Meshes[i]; 193 | 194 | rf::SendVec3(AlbedoLoc, Mat.AlbedoMult); 195 | rf::SendVec3(EmissiveLoc, Mat.EmissiveMult); 196 | rf::SendFloat(MetallicLoc, Mat.MetallicMult); 197 | rf::SendFloat(RoughnessLoc, Mat.RoughnessMult); 198 | rf::BindTexture2D(Mat.AlbedoTexture, 0); 199 | rf::BindTexture2D(Mat.NormalTexture, 1); 200 | rf::BindTexture2D(Mat.RoughnessMetallicTexture, 2); 201 | rf::BindTexture2D(Mat.EmissiveTexture, 3); 202 | rf::BindTexture2D(GGXLUT, 4); 203 | rf::BindCubemap(HDRGlossyEnvmap, 5); 204 | mat4f ModelMatrix; 205 | Loc = glGetUniformLocation(Program3D, "ModelMatrix"); 206 | ModelMatrix.FromTRS(translation[m] + renderOrigin, vec3f(0,rotation[m],0), vec3f(1)); 207 | ModelMatrix = ModelMatrix * Mesh.ModelMatrix; 208 | rf::SendMat4(Loc, ModelMatrix); 209 | glBindVertexArray(Mesh.VAO); 210 | rf::RenderMesh(&Mesh); 211 | } 212 | } 213 | rotation[0] += M_PI * (real32)Input->dTimeFixed * 0.02f; 214 | if(translation[0].y > 1.f) translationDir[0] = -1; 215 | if(translation[0].y < -1.f) translationDir[0] = 1; 216 | translation[0].y += (real32)Input->dTimeFixed * translationDir[0] * 0.05f; 217 | } 218 | #endif 219 | 220 | int PBRCount = 3; 221 | #if TEST_SPHEREARRAY // NOTE - Sphere Array Test for PBR 222 | { 223 | glUseProgram(Program3D); 224 | { 225 | uint32 Loc = glGetUniformLocation(Program3D, "ViewMatrix"); 226 | rf::SendMat4(Loc, ViewMatrix); 227 | rf::CheckGLError("ViewMatrix"); 228 | } 229 | uint32 Loc = glGetUniformLocation(Program3D, "LightColor"); 230 | rf::SendVec4(Loc, State->LightColor); 231 | Loc = glGetUniformLocation(Program3D, "SunDirection"); 232 | rf::SendVec3(Loc, State->SunDirection); 233 | Loc = glGetUniformLocation(Program3D, "CameraPos"); 234 | rf::SendVec3(Loc, State->Camera.Position); 235 | 236 | glBindVertexArray(Sphere.VAO); 237 | mat4f ModelMatrix; 238 | Loc = glGetUniformLocation(Program3D, "ModelMatrix"); 239 | 240 | rf::BindTexture2D(*Context->RenderResources.DefaultDiffuseTexture, 0); 241 | rf::BindTexture2D(*Context->RenderResources.DefaultNormalTexture, 1); 242 | rf::BindTexture2D(*Context->RenderResources.DefaultDiffuseTexture, 2); 243 | rf::BindTexture2D(*Context->RenderResources.DefaultEmissiveTexture, 3); 244 | rf::BindTexture2D(GGXLUT, 4); 245 | rf::BindCubemap(HDRGlossyEnvmap, 5); 246 | 247 | uint32 AlbedoLoc = glGetUniformLocation(Program3D, "AlbedoMult"); 248 | uint32 EmissiveLoc = glGetUniformLocation(Program3D, "EmissiveMult"); 249 | uint32 MetallicLoc = glGetUniformLocation(Program3D, "MetallicMult"); 250 | uint32 RoughnessLoc = glGetUniformLocation(Program3D, "RoughnessMult"); 251 | rf::SendVec3(AlbedoLoc, vec3f(0.7f, 0.7f, 0.7f)); 252 | rf::SendVec3(EmissiveLoc, vec3f(1)); 253 | for(int j = 0; j < PBRCount; ++j) 254 | { 255 | rf::SendFloat(MetallicLoc, (j)/(real32)PBRCount); 256 | for(int i = 0; i < 9; ++i) 257 | { 258 | rf::SendFloat(RoughnessLoc, Clamp((i)/9.0f, 0.05f, 1.f)); 259 | ModelMatrix.FromTRS(vec3f(-3.0f*(j), 3.0f, 3.0f*(i+1)), vec3f(0.f), vec3f(1.f)); 260 | rf::SendMat4(Loc, ModelMatrix); 261 | rf::RenderMesh(&Sphere); 262 | } 263 | } 264 | glActiveTexture(GL_TEXTURE0); 265 | } 266 | #endif 267 | 268 | #if TEST_PBRMATERIALS // NOTE - PBR materials rendering tests 269 | { 270 | glUseProgram(Program3D); 271 | { 272 | uint32 Loc = glGetUniformLocation(Program3D, "ViewMatrix"); 273 | rf::SendMat4(Loc, ViewMatrix); 274 | } 275 | uint32 Loc = glGetUniformLocation(Program3D, "LightColor"); 276 | rf::SendVec4(Loc, State->LightColor); 277 | Loc = glGetUniformLocation(Program3D, "SunDirection"); 278 | rf::SendVec3(Loc, State->SunDirection); 279 | Loc = glGetUniformLocation(Program3D, "CameraPos"); 280 | rf::SendVec3(Loc, State->Camera.Position); 281 | 282 | glBindVertexArray(Sphere.VAO); 283 | mat4f ModelMatrix; 284 | Loc = glGetUniformLocation(Program3D, "ModelMatrix"); 285 | 286 | uint32 AlbedoLoc = glGetUniformLocation(Program3D, "AlbedoMult"); 287 | uint32 EmissiveLoc = glGetUniformLocation(Program3D, "EmissiveMult"); 288 | uint32 MetallicLoc = glGetUniformLocation(Program3D, "MetallicMult"); 289 | uint32 RoughnessLoc = glGetUniformLocation(Program3D, "RoughnessMult"); 290 | 291 | rf::BindTexture2D(GGXLUT, 4); 292 | rf::BindCubemap(HDRGlossyEnvmap, 5); 293 | rf::SendVec3(AlbedoLoc, vec3f(1)); 294 | rf::SendVec3(EmissiveLoc, vec3f(1)); 295 | rf::SendFloat(MetallicLoc, 1.0); 296 | 297 | auto DrawSpheres = [&](int idx, uint32 albedo, uint32 mr, uint32 nrm) 298 | { 299 | rf::BindTexture2D(albedo, 0); 300 | rf::BindTexture2D(nrm, 1); 301 | rf::BindTexture2D(mr, 2); 302 | rf::BindTexture2D(*Context->RenderResources.DefaultEmissiveTexture, 3); 303 | for(int i = 0; i < 9; ++ i) 304 | { 305 | rf::SendFloat(RoughnessLoc, 1.0f + 0.5f * i); 306 | ModelMatrix.FromTRS(vec3f(-(PBRCount+idx) * 3.0f, 3.0f, 3.0f*(i+1)), vec3f(0.f), vec3f(1.f)); 307 | rf::SendMat4(Loc, ModelMatrix); 308 | rf::RenderMesh(&Sphere); 309 | } 310 | }; 311 | for(uint32 i = 0; i < MaterialCount; ++i) 312 | { 313 | DrawSpheres(i, *PBR_Albedo[i], *PBR_MetalRoughness[i], *PBR_Normal[i]); 314 | } 315 | 316 | glBindVertexArray(0); 317 | rf::CheckGLError("PBR draw"); 318 | 319 | glActiveTexture(GL_TEXTURE0); 320 | } 321 | #endif 322 | 323 | #if TEST_PLANE // NOTE - CUBE DRAWING Test Put somewhere else 324 | { 325 | glUseProgram(Program3D); 326 | { 327 | 328 | uint32 Loc = glGetUniformLocation(Program3D, "ViewMatrix"); 329 | rf::SendMat4(Loc, ViewMatrix); 330 | CheckGLError("ViewMatrix"); 331 | } 332 | 333 | uint32 Loc = glGetUniformLocation(Program3D, "LightColor"); 334 | rf::SendVec4(Loc, State->LightColor); 335 | Loc = glGetUniformLocation(Program3D, "SunDirection"); 336 | rf::SendVec3(Loc, State->SunDirection); 337 | Loc = glGetUniformLocation(Program3D, "CameraPos"); 338 | rf::SendVec3(Loc, State->Camera.Position); 339 | glBindVertexArray(Cube.VAO); 340 | mat4f ModelMatrix;// = mat4f::Translation(State->PlayerPosition); 341 | Loc = glGetUniformLocation(Program3D, "ModelMatrix"); 342 | uint32 AlbedoLoc = glGetUniformLocation(Program3D, "AlbedoMult"); 343 | uint32 EmissiveLoc = glGetUniformLocation(Program3D, "EmissiveMult"); 344 | uint32 MetallicLoc = glGetUniformLocation(Program3D, "MetallicMult"); 345 | uint32 RoughnessLoc = glGetUniformLocation(Program3D, "RoughnessMult"); 346 | 347 | rf::SendVec3(AlbedoLoc, vec3f(1)); 348 | rf::SendVec3(EmissiveLoc, vec3f(1)); 349 | rf::SendFloat(MetallicLoc, 0.1f); 350 | rf::SendFloat(RoughnessLoc, 0.9f); 351 | glBindVertexArray(Cube.VAO); 352 | rf::BindTexture2D(*Context->RenderResources.DefaultDiffuseTexture, 0); 353 | rf::BindTexture2D(*Context->RenderResources.DefaultNormalTexture, 1); 354 | rf::BindTexture2D(*Context->RenderResources.DefaultDiffuseTexture, 2); 355 | rf::BindTexture2D(*Context->RenderResources.DefaultEmissiveTexture, 3); 356 | rf::BindTexture2D(GGXLUT, 0); 357 | rf::BindCubemap(HDRGlossyEnvmap, 0); 358 | 359 | float planesize = 20; 360 | ModelMatrix.FromTRS(vec3f(-planesize/2.f-2,1,planesize/2.f+2), vec3f(0), vec3f(planesize,0.2f,planesize)); 361 | rf::SendMat4(Loc, ModelMatrix); 362 | rf::CheckGLError("ModelMatrix"); 363 | rf::RenderMesh(&Cube); 364 | } 365 | #endif 366 | #if TEST_SOUND // NOTE - Sound play 367 | tmp_sound_data *SoundData = System->SoundData; 368 | if(SoundData->ReloadSoundBuffer) 369 | { 370 | SoundData->ReloadSoundBuffer = false; 371 | alSourceStop(AudioSource); 372 | alSourcei(AudioSource, AL_BUFFER, 0); 373 | alBufferData(AudioBuffer, AL_FORMAT_MONO16, SoundData->SoundBuffer, SoundData->SoundBufferSize, 48000); 374 | alSourcei(AudioSource, AL_BUFFER, AudioBuffer); 375 | alSourcePlay(AudioSource); 376 | CheckALError(); 377 | } 378 | #endif 379 | 380 | #if TEST_SKYBOX // NOTE - Skybox Rendering Test, put somewhere else 381 | { 382 | glDisable(GL_CULL_FACE); 383 | glDepthFunc(GL_LEQUAL); 384 | rf::CheckGLError("Skybox"); 385 | 386 | glUseProgram(ProgramSkybox); 387 | { 388 | // NOTE - remove translation component from the ViewMatrix for the skybox 389 | mat4f SkyViewMatrix = ViewMatrix; 390 | SkyViewMatrix.SetTranslation(vec3f(0.f)); 391 | uint32 Loc = glGetUniformLocation(ProgramSkybox, "ViewMatrix"); 392 | rf::SendMat4(Loc, SkyViewMatrix); 393 | rf::CheckGLError("ViewMatrix Skybox"); 394 | } 395 | glActiveTexture(GL_TEXTURE0); 396 | glBindTexture(GL_TEXTURE_CUBE_MAP, HDRGlossyEnvmap); 397 | glBindVertexArray(SkyboxCube.VAO); 398 | glDrawElements(GL_TRIANGLES, SkyboxCube.IndexCount, SkyboxCube.IndexType, 0); 399 | 400 | glDepthFunc(GL_LESS); 401 | glEnable(GL_CULL_FACE); 402 | } 403 | #endif 404 | 405 | 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /src/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTS_H 2 | #define TESTS_H 3 | 4 | #include "definitions.h" 5 | #include "Game/sun.h" 6 | 7 | #define TEST_MODELS 0 8 | #define TEST_SPHEREARRAY 0 9 | #define TEST_PBRMATERIALS 0 10 | #define TEST_SKYBOX 0 11 | #define TEST_PLANE 0 12 | #define TEST_SOUND 0 13 | 14 | namespace Tests { 15 | void Destroy(); 16 | void ReloadShaders(rf::context *Context); 17 | bool Init(rf::context *Context, config const *Config); 18 | void Render(game::state *State, rf::input *Input, rf::context *Context); 19 | } 20 | #endif 21 | --------------------------------------------------------------------------------