├── .gitattributes ├── .gitignore ├── Clouds.sln ├── Clouds.vcxproj ├── Clouds.vcxproj.filters ├── res └── shaders │ ├── blur.frag │ ├── blur.vert │ ├── post.frag │ ├── post.vert │ ├── resolve.vert │ ├── resolve_noise.frag │ ├── resolve_tile.frag │ ├── sky.frag │ ├── sky.vert │ ├── terrain.frag │ └── terrain.vert └── src ├── camera.cpp ├── camera.h ├── cloud_preprocess.cpp ├── cloud_preprocess.h ├── cloud_tiling.cpp ├── cloud_tiling.h ├── framebuffer.cpp ├── framebuffer.h ├── fullscreen_quad.cpp ├── fullscreen_quad.h ├── log.cpp ├── log.h ├── main.cpp ├── model.cpp ├── model.h ├── quad.cpp ├── quad.h ├── shader.cpp ├── shader.h ├── texture.cpp └── texture.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /Clouds.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Clouds", "Clouds.vcxproj", "{F4A9BBD7-2B15-44A7-BFEE-CC408D2D0DF8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F4A9BBD7-2B15-44A7-BFEE-CC408D2D0DF8}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {F4A9BBD7-2B15-44A7-BFEE-CC408D2D0DF8}.Debug|Win32.Build.0 = Debug|Win32 16 | {F4A9BBD7-2B15-44A7-BFEE-CC408D2D0DF8}.Release|Win32.ActiveCfg = Release|Win32 17 | {F4A9BBD7-2B15-44A7-BFEE-CC408D2D0DF8}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Clouds.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {F4A9BBD7-2B15-44A7-BFEE-CC408D2D0DF8} 15 | Clouds 16 | 17 | 18 | 19 | Application 20 | true 21 | v120 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v120 28 | true 29 | MultiByte 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | .\src;$(SourcePath) 43 | $(Configuration)\ 44 | 45 | 46 | .\src;$(SourcePath) 47 | $(Configuration)\ 48 | 49 | 50 | 51 | EnableAllWarnings 52 | Disabled 53 | true 54 | .\lib\glm;.\lib\SDL2-2.0.4\include;.\lib\glew-1.13.0\include;%(AdditionalIncludeDirectories) 55 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 56 | 57 | 58 | true 59 | .\lib\glew-1.13.0\lib\Release\Win32;.\lib\SDL2-2.0.4\lib\x86;%(AdditionalLibraryDirectories) 60 | glew32.lib;SDL2.lib;SDL2main.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) 61 | Console 62 | 63 | 64 | 65 | 66 | Level3 67 | MaxSpeed 68 | true 69 | true 70 | true 71 | .\lib\glm;.\lib\SDL2-2.0.4\include;.\lib\glew-1.13.0\include;%(AdditionalIncludeDirectories) 72 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 73 | 74 | 75 | true 76 | true 77 | true 78 | .\lib\glew-1.13.0\lib\Release\Win32;.\lib\SDL2-2.0.4\lib\x86;%(AdditionalLibraryDirectories) 79 | glew32.lib;SDL2.lib;SDL2main.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies) 80 | Console 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /Clouds.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {af1ec427-23f4-4281-85b0-ff4ffcfde3b5} 18 | 19 | 20 | {a9078203-df9d-4ab6-ba4a-fc93490c2bdf} 21 | 22 | 23 | 24 | 25 | Resource Files\models 26 | 27 | 28 | Resource Files\models 29 | 30 | 31 | Resource Files\shaders 32 | 33 | 34 | Resource Files\shaders 35 | 36 | 37 | Resource Files\shaders 38 | 39 | 40 | Resource Files\shaders 41 | 42 | 43 | Resource Files\shaders 44 | 45 | 46 | Resource Files\shaders 47 | 48 | 49 | Resource Files\shaders 50 | 51 | 52 | Resource Files\shaders 53 | 54 | 55 | Resource Files\shaders 56 | 57 | 58 | Resource Files\shaders 59 | 60 | 61 | Resource Files\shaders 62 | 63 | 64 | 65 | 66 | Resource Files 67 | 68 | 69 | 70 | 71 | Source Files 72 | 73 | 74 | Source Files 75 | 76 | 77 | Source Files 78 | 79 | 80 | Source Files 81 | 82 | 83 | Source Files 84 | 85 | 86 | Source Files 87 | 88 | 89 | Source Files 90 | 91 | 92 | Source Files 93 | 94 | 95 | Source Files 96 | 97 | 98 | Source Files 99 | 100 | 101 | Source Files 102 | 103 | 104 | 105 | 106 | Header Files 107 | 108 | 109 | Header Files 110 | 111 | 112 | Header Files 113 | 114 | 115 | Header Files 116 | 117 | 118 | Header Files 119 | 120 | 121 | Header Files 122 | 123 | 124 | Header Files 125 | 126 | 127 | Header Files 128 | 129 | 130 | Header Files 131 | 132 | 133 | Header Files 134 | 135 | 136 | -------------------------------------------------------------------------------- /res/shaders/blur.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | out vec4 fcolor; 4 | 5 | in vec2 TexCoords; 6 | 7 | uniform sampler2D image; 8 | uniform bool horizontal; 9 | 10 | uniform float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); 11 | 12 | void main() { 13 | 14 | vec2 tex_offset = 1.0 / textureSize(image, 0); 15 | vec3 result = texture(image, TexCoords).rgb * weight[0]; 16 | 17 | if(horizontal) { 18 | for(int i = 1; i < 5; ++i) { 19 | result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i]; 20 | result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i]; 21 | } 22 | } else { 23 | for(int i = 1; i < 5; ++i) { 24 | result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgb * weight[i]; 25 | result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgb * weight[i]; 26 | } 27 | } 28 | 29 | fcolor = vec4(result * 1, 1.0); 30 | } -------------------------------------------------------------------------------- /res/shaders/blur.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 position; 4 | layout (location = 1) in vec2 texCoords; 5 | 6 | out vec2 TexCoords; 7 | 8 | void main() 9 | { 10 | gl_Position = vec4(position, 1.0f); 11 | TexCoords = texCoords; 12 | } -------------------------------------------------------------------------------- /res/shaders/post.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) out vec4 frag_color; 4 | 5 | uniform sampler2D HDR_buffer; 6 | uniform sampler2D bloom_blur; 7 | 8 | 9 | void main() { 10 | const float gamma = 2.2; 11 | const float exposure = 0.1; 12 | 13 | vec3 hdrColor = texelFetch(HDR_buffer, ivec2(gl_FragCoord.xy), 0).rgb; 14 | vec3 bloomColor = texelFetch(bloom_blur, ivec2(gl_FragCoord.xy), 0).rgb; 15 | hdrColor += bloomColor; 16 | 17 | // Reinhard tone mapping 18 | vec3 mapped = hdrColor / (hdrColor + vec3(1.0)); 19 | // Exposure tone mapping 20 | //vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure); 21 | // Gamma correction 22 | //mapped = pow(mapped, vec3(1.0 / gamma)); 23 | 24 | frag_color = vec4(mapped, 1.0); 25 | } -------------------------------------------------------------------------------- /res/shaders/post.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 vert; 4 | 5 | void main() { 6 | gl_Position = vec4(vert, 1.0f); 7 | } -------------------------------------------------------------------------------- /res/shaders/resolve.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 vert; 4 | 5 | layout(location = 0) out vec3 vertex_pos; 6 | 7 | void main() { 8 | vertex_pos = vert; 9 | gl_Position = vec4(vert, 1.0); 10 | } -------------------------------------------------------------------------------- /res/shaders/resolve_noise.frag: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rikardolajos/clouds/855cd20a7ab389136a38e8dfe9571531cd034959/res/shaders/resolve_noise.frag -------------------------------------------------------------------------------- /res/shaders/resolve_tile.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 vertex_pos; 4 | 5 | out vec4 frag_color; 6 | 7 | uniform sampler1D mie_texture; 8 | uniform sampler3D cloud_structure; 9 | uniform sampler3D cloud_tile00; 10 | 11 | uniform sampler2D diffuse_buffer; 12 | uniform sampler2D depth_buffer; 13 | 14 | uniform vec2 view_port; 15 | uniform vec3 camera_pos; 16 | uniform vec3 sun_pos; 17 | 18 | uniform mat4 view; 19 | uniform mat4 proj; 20 | 21 | float PI = 3.1415962; 22 | float PI_r = 0.3183098; 23 | 24 | float HG(float costheta) { 25 | float g = 0.99; 26 | return 0.25 * PI_r * (1 - pow(g, 2.0)) / pow((1 + pow(g, 2.0) - 2 * g * costheta), 1.5); 27 | } 28 | 29 | float Mie(float costheta) { 30 | float angle = acos(costheta); 31 | return texture(mie_texture, (PI - angle) * PI_r).r; 32 | } 33 | 34 | float phase(vec3 v1, vec3 v2) { 35 | float costheta = dot(v1, v2) / length(v1) / length(v2); 36 | return HG(-costheta); 37 | //return Mie(costheta); 38 | } 39 | 40 | float cloud_sampling_structure(vec3 v, float delta) { 41 | /* Reposition the cloud first */ 42 | v = (v + vec3(500, -50, 500)) * 0.001; 43 | 44 | vec4 texture = texture(cloud_structure, v); 45 | return texture.r; 46 | } 47 | 48 | float cloud_sampling_tile(float tile, vec3 v, float delta) { 49 | /* Reposition the tile first */ 50 | v = (v + vec3(500, -50, 500)) * 0.256; 51 | v = fract(v); 52 | 53 | if (tile * 255 == 1) { 54 | return texture(cloud_tile00, v).r * delta; 55 | } 56 | 57 | if (tile * 255 == 255) { 58 | /* This is the safety tile that surrounds all non-zero tiles */ 59 | return 0.008 * delta; 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | float cast_scatter_ray(vec3 origin, vec3 dir) { 66 | float delta = 5.0; 67 | float end = 50.0; 68 | 69 | vec3 sample_point = vec3(0.0); 70 | float inside = 0.0; 71 | 72 | float phase = phase(dir, vec3(camera_pos - origin)); 73 | 74 | for (float t = 0.0; t < end; t += delta) { 75 | sample_point = origin + dir * t; 76 | //inside += cloud_sampling(sample_point, delta); 77 | } 78 | 79 | float beer = exp(-0.2 * inside); 80 | 81 | float value = phase + beer; 82 | return value; 83 | } 84 | 85 | // http://www.iquilezles.org/www/articles/terrainmarching/terrainmarching.htm 86 | vec4 cast_ray(vec3 origin, vec3 dir) { 87 | float delta_large = 10.0; 88 | float delta_small = 0.1; 89 | float start = gl_DepthRange.near; 90 | float end = 500.0; 91 | 92 | vec4 value = vec4(0.0); 93 | vec3 cloud_color = vec3(0.93, 0.93, 0.95); 94 | vec3 cloud_shade = vec3(0.859, 0.847, 0.757) - 0.1; 95 | vec3 cloud_bright = vec3(0.99, 0.96, 0.95); 96 | vec3 cloud_dark = vec3(0.671, 0.725, 0.753); 97 | value.rgb = cloud_dark; 98 | 99 | bool inside = false; 100 | bool looking_for_new_tile = true; 101 | int points_inside = 0; 102 | vec3 sample_point = origin; 103 | 104 | float tile; 105 | float delta = delta_large; 106 | for (float t = start; t < end; t += delta) { 107 | sample_point = origin + dir * t; 108 | 109 | /* Stop rays that are going below ground */ 110 | if (sample_point.y < 0.0) { 111 | break; 112 | } 113 | 114 | /* Stop rays that already reach full opacity */ 115 | if (value.a > 1.0) { 116 | break; 117 | } 118 | 119 | float alpha; 120 | if (!inside) { 121 | tile = cloud_sampling_structure(sample_point, delta); 122 | if (tile > 0.0) { 123 | inside = true; 124 | } else { 125 | looking_for_new_tile = true; 126 | } 127 | } 128 | 129 | if (inside) { 130 | /* Start of a new tile? */ 131 | if (looking_for_new_tile) { 132 | /* Move the starting point a large delta backwards */ 133 | t -= delta_large; 134 | if (t < gl_DepthRange.near) { 135 | t = gl_DepthRange.near; 136 | } 137 | sample_point = origin + dir * t; 138 | delta = delta_small; 139 | 140 | looking_for_new_tile = false; 141 | points_inside = 0; 142 | } 143 | delta = delta_small; 144 | alpha = cloud_sampling_tile(tile, sample_point, delta); 145 | value.a += alpha; 146 | points_inside += 1; 147 | } 148 | 149 | /* Check next structure block if we are still inside */ 150 | if (inside && points_inside * delta_small > delta_large) { 151 | tile = cloud_sampling_structure(sample_point, delta); 152 | if (tile == 0.0) { 153 | inside = false; 154 | looking_for_new_tile = true; 155 | 156 | delta = delta_large; 157 | } else { 158 | points_inside = 0; 159 | } 160 | } 161 | 162 | /* Calculate the scattering */ 163 | float energy = cast_scatter_ray(sample_point, normalize(sun_pos - sample_point)); 164 | //value.rgb = mix(cloud_dark, cloud_bright, energy); 165 | } 166 | 167 | return clamp(value, 0.0, 1.0); 168 | } 169 | 170 | void main() { 171 | /* Calculate the ray */ 172 | // http://antongerdelan.net/opengl/raycasting.html 173 | float x = 2.0 * gl_FragCoord.x / view_port.x - 1.0; 174 | float y = 2.0 * gl_FragCoord.y / view_port.y - 1.0; 175 | vec2 ray_nds = vec2(x, y); 176 | vec4 ray_clip = vec4(ray_nds, -1.0, 1.0); 177 | vec4 ray_view = inverse(proj) * ray_clip; 178 | ray_view = vec4(ray_view.xy, -1.0, 0.0); 179 | vec3 ray_world = (inverse(view) * ray_view).xyz; 180 | ray_world = normalize(ray_world); 181 | 182 | vec4 cloud_color = cast_ray(camera_pos, ray_world); 183 | 184 | vec4 diffuse_color = texelFetch(diffuse_buffer, ivec2(gl_FragCoord.xy), 0); 185 | float depth = pow(texelFetch(depth_buffer, ivec2(gl_FragCoord.xy), 0).x, 128.0); 186 | 187 | frag_color.a = 1.0; 188 | frag_color.rgb = mix(diffuse_color.rgb, cloud_color.rgb, cloud_color.a); 189 | 190 | //frag_color.rgb = texture(cloud_structure, vec3(gl_FragCoord.xy / view_port.xy, 0.5)).rrr; 191 | } -------------------------------------------------------------------------------- /res/shaders/sky.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) smooth in vec3 N; 4 | layout(location = 1) in vec3 S; 5 | 6 | layout(location = 0) out vec4 fcolor; 7 | 8 | void main () { 9 | 10 | float sun = dot(normalize(-S), normalize(N)); 11 | float sun_pos = smoothstep(0.9995, 0.99995, sun); 12 | vec3 sun_color = vec3(1, 0.55, 0.15) * 1000; 13 | 14 | vec3 deep_blue = vec3(0.3421052632, 0.9029850746, 2.311688312); 15 | vec3 light_blue = deep_blue + 1; 16 | 17 | /* Lighter around the horizon */ 18 | vec3 sky_color = mix(deep_blue, light_blue, smoothstep(-1.0, 0.7, dot(normalize(N), vec3(0.0, 1.0, 0.0)))); 19 | /* Lighter around the sun */ 20 | sky_color += 0.15 * mix(vec3(0.0), vec3(1.0), smoothstep(0.85, 1.0, sun)); 21 | sky_color += 0.2 * mix(vec3(0.0), vec3(1.0), smoothstep(0.75, 1.0, sun)); 22 | 23 | vec3 color = sky_color + sun_pos * sun_color; 24 | fcolor = vec4(color, 1.0); 25 | } -------------------------------------------------------------------------------- /res/shaders/sky.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 vert; 4 | layout(location = 1) in vec3 norm; 5 | 6 | layout(location = 0) smooth out vec3 N; 7 | layout(location = 1) out vec3 S; 8 | 9 | uniform mat4 model; 10 | uniform mat4 view; 11 | uniform mat4 proj; 12 | 13 | uniform vec3 camera_pos; 14 | uniform vec3 sun_pos; 15 | 16 | void main() { 17 | N = norm; 18 | S = sun_pos - camera_pos; 19 | gl_Position = proj * view * model * vec4(vert, 1.0); 20 | } -------------------------------------------------------------------------------- /res/shaders/terrain.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in float height; 4 | layout(location = 1) in float dist; 5 | layout(location = 2) in vec2 pos; 6 | layout(location = 3) in vec2 uv; 7 | 8 | layout(location = 0) out vec4 fcolor; 9 | 10 | uniform sampler2D terrain_texture; 11 | 12 | 13 | void main() { 14 | 15 | vec3 fog_color = vec3(0.3, 0.3, 0.7); 16 | vec3 terrain_color_base = vec3(0.30, 0.34, 0.05); 17 | vec3 terrain_color_top = vec3(0.5, 0.4, 0.1); 18 | 19 | vec3 fog = fog_color * smoothstep(300, 500, dist) * 1; 20 | vec3 terrain = terrain_color_base + clamp(height, -0.8, 1.0) * terrain_color_top * texture(terrain_texture, uv * 100).rgb; 21 | vec3 color = terrain + fog; 22 | 23 | fcolor = vec4(color, smoothstep(580, 330, dist)); 24 | fcolor.rgb *= 1.5; 25 | 26 | /* Grid */ 27 | if (mod(pos.x, 4) < 0.2 || mod(pos.y, 4) < 0.2) { 28 | //fcolor = vec4(1.0, 1.0, 0.4, 1.0); 29 | } 30 | } -------------------------------------------------------------------------------- /res/shaders/terrain.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 vert; 4 | layout(location = 1) in vec3 norm; 5 | layout(location = 2) in vec2 text; 6 | 7 | layout(location = 0) out float height; 8 | layout(location = 1) out float dist; 9 | layout(location = 2) out vec2 pos; 10 | layout(location = 3) out vec2 uv; 11 | 12 | uniform sampler2D terrain_texture; 13 | 14 | uniform mat4 model; 15 | uniform mat4 view; 16 | uniform mat4 proj; 17 | 18 | uniform vec3 camera_pos; 19 | 20 | void main() { 21 | dist = length(vert - camera_pos); 22 | height = texture(terrain_texture, vert.xz * 5).g * 0.4; 23 | pos = vec2(vert.x, vert.z); 24 | uv = text; 25 | gl_Position = proj * view * model * vec4(vert.x, vert.y + height * 3 - 3, vert.z, 1.0); 26 | } -------------------------------------------------------------------------------- /src/camera.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rikardolajos/clouds/855cd20a7ab389136a38e8dfe9571531cd034959/src/camera.cpp -------------------------------------------------------------------------------- /src/camera.h: -------------------------------------------------------------------------------- 1 | #ifndef CAMERA_H 2 | #define CAMERA_H 3 | 4 | #include "glm/glm.hpp" 5 | #include "SDL.h" 6 | 7 | #define CAMERA_NEAR 0.1f 8 | #define CAMERA_FAR 2000.0f 9 | #define CAMERA_FOV 60.0f 10 | 11 | typedef struct Camera Camera; 12 | struct Camera { 13 | int width; 14 | int height; 15 | 16 | float fov; 17 | float z_near; 18 | float z_far; 19 | 20 | glm::vec3 position; 21 | glm::vec3 front; 22 | glm::vec3 up; 23 | 24 | float pitch; 25 | float yaw; 26 | float sensitivity; 27 | SDL_bool enabled; 28 | }; 29 | 30 | /* Initialize a camera at (0, 2, 0) with (0, 1, 0) as up vector, looking down negative z-axis */ 31 | void camera_init(Camera* c, int width, int height, float fov, float z_near, float z_far); 32 | glm::mat4 camera_view_matrix(Camera* c); 33 | glm::mat4 camera_projection_matrix(Camera* c); 34 | void camera_translate(Camera* c, const char* direction, float delta_time); 35 | void camera_movement(Camera* c, float delta_time); 36 | void camera_toggle_mouse(Camera* c, SDL_Window* w); 37 | void camera_track1(Camera* c, Uint32 time, Uint32 duration); 38 | void camera_track2(Camera* c, Uint32 time, Uint32 duration); 39 | void camera_track3(Camera* c, Uint32 time, Uint32 duration); 40 | void camera_track4(Camera* c, Uint32 time, Uint32 duration); 41 | 42 | #endif -------------------------------------------------------------------------------- /src/cloud_preprocess.cpp: -------------------------------------------------------------------------------- 1 | #include "cloud_preprocess.h" 2 | 3 | #include "glm/glm.hpp" 4 | 5 | #include "texture.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | /* 1 = inside cloud, else 0 */ 12 | GLubyte structure(GLubyte pixel) 13 | { 14 | if (pixel / 255.0 > 0.35) { 15 | return 1; 16 | } 17 | return 0; 18 | } 19 | 20 | int cloud_preprocess(Texture* cloud_structure, Texture source) 21 | { 22 | /* Read the source texture */ 23 | GLubyte* cloud_pixels = (GLubyte*)malloc(source.width * source.height * source.depth * 4 * sizeof(GLubyte)); 24 | glBindTexture(GL_TEXTURE_3D, source.object); 25 | glGetTexImage(GL_TEXTURE_3D, 0, GL_RGBA, GL_UNSIGNED_BYTE, cloud_pixels); 26 | 27 | /* Set size of structure texture */ 28 | cloud_structure->width = 32; /* Creates 4x4x4 cubes of original 128x128x128 texture */ 29 | cloud_structure->height = 32; 30 | cloud_structure->depth = 32; 31 | 32 | /* Pick the red channel and procces it */ 33 | GLubyte* temp = (GLubyte*)malloc(source.width * source.height * source.depth * sizeof(GLubyte)); 34 | for (int i = 0; i < source.width * source.height * source.depth; i++) { 35 | temp[i] = structure(cloud_pixels[i * 4]); 36 | } 37 | 38 | GLubyte* new_structure = (GLubyte*)malloc(cloud_structure->width * cloud_structure->height * cloud_structure->depth * sizeof(GLubyte)); 39 | 40 | /* Analyze every 4x4x4 block of the original texture */ 41 | int inside = 0; 42 | for (int i = 0; i < cloud_structure->width; i++) { 43 | for (int j = 0; j < cloud_structure->height; j++) { 44 | for (int k = 0; k < cloud_structure->depth; k++) { 45 | 46 | inside = 0; 47 | 48 | for (int u = 0; u < 4; u++) { 49 | for (int v = 0; v < 4; v++) { 50 | for (int w = 0; w < 4; w++) { 51 | 52 | int x = i * 4 + u; 53 | int y = j * 4 + v; 54 | int z = k * 4 + w; 55 | 56 | inside += temp[x + y * source.height + z * source.height * source.depth]; 57 | 58 | } 59 | } 60 | } 61 | 62 | if (inside < 8) { 63 | new_structure[i + j * cloud_structure->height + k * cloud_structure->height * cloud_structure->depth] = 0; 64 | } else { 65 | new_structure[i + j * cloud_structure->height + k * cloud_structure->height * cloud_structure->depth] = 255; 66 | } 67 | 68 | } 69 | } 70 | } 71 | 72 | /* Post process -- expanding the structure to reduce artifacts */ 73 | GLubyte* post_pixels = (GLubyte*)calloc(cloud_structure->width * cloud_structure->height * cloud_structure->depth, sizeof(GLubyte)); 74 | 75 | for (int i = 0; i < cloud_structure->width; i++) { 76 | for (int j = 0; j < cloud_structure->height; j++) { 77 | for (int k = 0; k < cloud_structure->depth; k++) { 78 | 79 | if (new_structure[k + j * cloud_structure->height + i * cloud_structure->height * cloud_structure->depth] == 0) { 80 | continue; 81 | } 82 | 83 | for (int ii = -1; ii < 2; ii++) { 84 | if (i + ii < 0 || i + ii >= cloud_structure->width) continue; 85 | for (int jj = -1; jj < 2; jj++) { 86 | if (j + jj < 0 || j + jj >= cloud_structure->height) continue; 87 | for (int kk = -1; kk < 2; kk++) { 88 | if (k + kk < 0 || k + kk >= cloud_structure->depth) continue; 89 | 90 | post_pixels[(k + kk) + (j + jj) * cloud_structure->height + (i + ii) * cloud_structure->height * cloud_structure->depth] = 255; 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | /* Bind the new texture */ 99 | glGenTextures(1, &cloud_structure->object); 100 | glBindTexture(GL_TEXTURE_3D, cloud_structure->object); 101 | 102 | /* Give it an index */ 103 | texture_activate(cloud_structure); 104 | 105 | glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, cloud_structure->width, cloud_structure->height, cloud_structure->depth, 0, GL_RED, GL_UNSIGNED_BYTE, post_pixels); 106 | glGenerateMipmap(GL_TEXTURE_3D); 107 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 108 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 109 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); 110 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 111 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); 112 | 113 | free(cloud_pixels); 114 | free(temp); 115 | free(new_structure); 116 | free(post_pixels); 117 | 118 | return 0; 119 | } -------------------------------------------------------------------------------- /src/cloud_preprocess.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOUD_PREPROCESS_H 2 | #define CLOUD_PREPROCESS_H 3 | 4 | #include "texture.h" 5 | 6 | int cloud_preprocess(Texture* cloud_structure, Texture source); 7 | 8 | #endif -------------------------------------------------------------------------------- /src/cloud_tiling.cpp: -------------------------------------------------------------------------------- 1 | #include "cloud_tiling.h" 2 | 3 | #include "glm/glm.hpp" 4 | 5 | #include "texture.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int cloud_tiling_structure(Texture* cloud_structure) 12 | { 13 | /* Set up cloud structure */ 14 | cloud_structure->width = 256; 15 | cloud_structure->height = 256; 16 | cloud_structure->depth = 256; 17 | 18 | GLubyte* pixels = (GLubyte*)malloc(cloud_structure->width * cloud_structure->height * cloud_structure->depth * sizeof(GLubyte)); 19 | 20 | /* Process the pixels */ 21 | for (int i = 0; i < cloud_structure->width; i++) { 22 | for (int j = 0; j < cloud_structure->height; j++) { 23 | for (int k = 0; k < cloud_structure->depth; k++) { 24 | if (j == 1 && i == 127 && k == 127) { 25 | pixels[k + j * cloud_structure->height + i * cloud_structure->height * cloud_structure->depth] = 1; 26 | } else { 27 | pixels[k + j * cloud_structure->height + i * cloud_structure->height * cloud_structure->depth] = 0; 28 | } 29 | } 30 | } 31 | } 32 | 33 | /* Post process -- expanding the structure to reduce artifacts */ 34 | GLubyte* post_pixels = (GLubyte*)calloc(cloud_structure->width * cloud_structure->height * cloud_structure->depth, sizeof(GLubyte)); 35 | 36 | for (int i = 0; i < cloud_structure->width; i++) { 37 | for (int j = 0; j < cloud_structure->height; j++) { 38 | for (int k = 0; k < cloud_structure->depth; k++) { 39 | 40 | if (pixels[k + j * cloud_structure->height + i * cloud_structure->height * cloud_structure->depth] == 0) { 41 | continue; 42 | } 43 | 44 | for (int ii = -10; ii < 11; ii++) { 45 | if (i + ii < 0 || i + ii >= cloud_structure->width) continue; 46 | for (int jj = -10; jj < 11; jj++) { 47 | if (j + jj < 0 || j + jj >= cloud_structure->height) continue; 48 | for (int kk = -10; kk < 11; kk++) { 49 | if (k + kk < 0 || k + kk >= cloud_structure->depth) continue; 50 | 51 | GLubyte p = pixels[(k + kk) + (j + jj) * cloud_structure->height + (i + ii) * cloud_structure->height * cloud_structure->depth]; 52 | if (p == 0) { 53 | post_pixels[(k + kk) + (j + jj) * cloud_structure->height + (i + ii) * cloud_structure->height * cloud_structure->depth] = 255; 54 | } else { 55 | post_pixels[(k + kk) + (j + jj) * cloud_structure->height + (i + ii) * cloud_structure->height * cloud_structure->depth] = p; 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | /* Bind the new texture */ 65 | glGenTextures(1, &cloud_structure->object); 66 | glBindTexture(GL_TEXTURE_3D, cloud_structure->object); 67 | 68 | /* Give it an index */ 69 | texture_activate(cloud_structure); 70 | 71 | glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, cloud_structure->width, cloud_structure->height, cloud_structure->depth, 0, GL_RED, GL_UNSIGNED_BYTE, post_pixels); 72 | glGenerateMipmap(GL_TEXTURE_3D); 73 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 74 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 75 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); 76 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 77 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); 78 | 79 | free(pixels); 80 | free(post_pixels); 81 | 82 | return 0; 83 | } 84 | 85 | int cloud_tiling_init(Texture cloud_tiles[], Texture* cloud_structure) 86 | { 87 | /* Set size of structure texture */ 88 | cloud_tiles[0].width = 64; 89 | cloud_tiles[0].height = 64; 90 | cloud_tiles[0].depth = 64; 91 | 92 | GLubyte* pixels = (GLubyte*)malloc(cloud_tiles[0].width * cloud_tiles[0].height * cloud_tiles[0].depth * sizeof(GLubyte)); 93 | 94 | /* Process the pixels */ 95 | for (int i = 0; i < cloud_tiles[0].width; i++) { 96 | for (int j = 0; j < cloud_tiles[0].height; j++) { 97 | for (int k = 0; k < cloud_tiles[0].depth; k++) { 98 | if (i > 32 && j > 32) { 99 | pixels[k + j * cloud_tiles[0].height + i * cloud_tiles[0].height * cloud_tiles[0].depth] = 255; 100 | } else { 101 | pixels[k + j * cloud_tiles[0].height + i * cloud_tiles[0].height * cloud_tiles[0].depth] = 0; 102 | } 103 | } 104 | } 105 | } 106 | 107 | /* Bind the new texture */ 108 | glGenTextures(1, &cloud_tiles[0].object); 109 | glBindTexture(GL_TEXTURE_3D, cloud_tiles[0].object); 110 | 111 | /* Give it an index */ 112 | texture_activate(&cloud_tiles[0]); 113 | 114 | glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, cloud_tiles[0].width, cloud_tiles[0].height, cloud_tiles[0].depth, 0, GL_RED, GL_UNSIGNED_BYTE, pixels); 115 | glGenerateMipmap(GL_TEXTURE_3D); 116 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 117 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 118 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); 119 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 120 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); 121 | 122 | free(pixels); 123 | 124 | cloud_tiling_structure(cloud_structure); 125 | 126 | return 0; 127 | } -------------------------------------------------------------------------------- /src/cloud_tiling.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOUD_TILING_H 2 | #define CLOUD_TILING_H 3 | 4 | #include "texture.h" 5 | 6 | int cloud_tiling_init(Texture cloud_tiles[], Texture* cloud_structure); 7 | 8 | #endif -------------------------------------------------------------------------------- /src/framebuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "framebuffer.h" 2 | 3 | #include "log.h" 4 | 5 | #include "GL/glew.h" 6 | 7 | #include 8 | 9 | void framebuffer_scene_init(Framebuffer* f, int screen_width, int screen_height) 10 | { 11 | glGenFramebuffers(1, &f->fbo); 12 | glBindFramebuffer(GL_FRAMEBUFFER, f->fbo); 13 | 14 | glGenTextures(1, &f->color_buffer[0]); 15 | 16 | glBindTexture(GL_TEXTURE_2D, f->color_buffer[0]); 17 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, screen_width, screen_height, 0, GL_RGB, GL_FLOAT, NULL); 18 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 19 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 20 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 21 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 22 | 23 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, f->color_buffer[0], 0); 24 | 25 | GLuint depth_rbo; 26 | glGenRenderbuffers(1, &depth_rbo); 27 | glBindRenderbuffer(GL_RENDERBUFFER, depth_rbo); 28 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screen_width, screen_height); 29 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rbo); 30 | 31 | GLuint scene_attachments[1] = { GL_COLOR_ATTACHMENT0 }; 32 | glDrawBuffers(1, scene_attachments); 33 | 34 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 35 | log("Error: Framebuffer not created!\n"); 36 | } 37 | } 38 | 39 | void framebuffer_cloud_init(Framebuffer* f, int screen_width, int screen_height) 40 | { 41 | glGenFramebuffers(1, &f->fbo); 42 | glBindFramebuffer(GL_FRAMEBUFFER, f->fbo); 43 | 44 | glGenTextures(2, f->color_buffer); 45 | for (GLuint i = 0; i < 2; i++) { 46 | glBindTexture(GL_TEXTURE_2D, f->color_buffer[i]); 47 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, screen_width, screen_height, 0, GL_RGB, GL_FLOAT, NULL); 48 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 49 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 50 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 51 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 52 | 53 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, f->color_buffer[i], 0); 54 | } 55 | 56 | GLuint cloud_attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; 57 | glDrawBuffers(2, cloud_attachments); 58 | 59 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 60 | log("Error: Framebuffer not created!\n"); 61 | } 62 | } 63 | 64 | void framebuffer_pingpong_init(Framebuffer f[2], int screen_width, int screen_height) 65 | { 66 | glGenFramebuffers(1, &f[0].fbo); 67 | glGenTextures(1, f[0].color_buffer); 68 | 69 | glGenFramebuffers(1, &f[1].fbo); 70 | glGenTextures(1, f[1].color_buffer); 71 | 72 | for (GLuint i = 0; i < 2; i++) { 73 | glBindFramebuffer(GL_FRAMEBUFFER, f[i].fbo); 74 | glBindTexture(GL_TEXTURE_2D, f[i].color_buffer[0]); 75 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, screen_width, screen_height, 0, GL_RGB, GL_FLOAT, NULL); 76 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 77 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 78 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 79 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 80 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, f[i].color_buffer[0], 0); 81 | 82 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 83 | log("Framebuffer not complete!"); 84 | } 85 | 86 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 87 | } -------------------------------------------------------------------------------- /src/framebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef FRAMEBUFFER_H 2 | #define FRAMEBUFFER_H 3 | 4 | #include "GL/glew.h" 5 | 6 | typedef struct Framebuffer Framebuffer; 7 | struct Framebuffer { 8 | GLuint fbo; 9 | GLuint color_buffer[2]; 10 | }; 11 | 12 | void framebuffer_scene_init(Framebuffer* f, int screen_width, int screen_height); 13 | void framebuffer_cloud_init(Framebuffer* f, int screen_width, int screen_height); 14 | void framebuffer_pingpong_init(Framebuffer* f, int screen_width, int screen_height); 15 | 16 | #endif -------------------------------------------------------------------------------- /src/fullscreen_quad.cpp: -------------------------------------------------------------------------------- 1 | #include "fullscreen_quad.h" 2 | 3 | #include "GL/glew.h" 4 | #include "log.h" 5 | #include "texture.h" 6 | 7 | #include 8 | 9 | /* http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ */ 10 | /* http://learnopengl.com/#!Advanced-Lighting/HDR */ 11 | /* http://learnopengl.com/#!Advanced-Lighting/Bloom */ 12 | 13 | void fs_quad_init(FS_Quad* q, int screen_width, int screen_height, Shader s) 14 | { 15 | q->screen_width = screen_width; 16 | q->screen_height = screen_height; 17 | q->shader = s; 18 | 19 | /* Reserve two texture indices */ 20 | texture_activate(&q->texture); 21 | texture_activate(&q->texture); 22 | q->texture.index--; 23 | 24 | /* Create framebuffer */ 25 | glGenFramebuffers(1, &q->framebuffer_object); 26 | glBindFramebuffer(GL_FRAMEBUFFER, q->framebuffer_object); 27 | 28 | /* Create textures to render to */ 29 | glGenTextures(2, q->color_buffers); 30 | q->texture.object = q->color_buffers[0]; 31 | 32 | for (GLuint i = 0; i < 2; i++) { 33 | /* Send an empty texture to OpenGL and set some filtering */ 34 | glBindTexture(GL_TEXTURE_2D, q->color_buffers[i]); 35 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, q->screen_width, q->screen_height, 0, GL_RGBA, GL_FLOAT, 0); 36 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 37 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 38 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 39 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 40 | 41 | /* Set color attachment */ 42 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, q->color_buffers[i], 0); 43 | } 44 | 45 | /* Depth buffer */ 46 | glGenRenderbuffers(1, &q->depth_render_buffer); 47 | glBindRenderbuffer(GL_RENDERBUFFER, q->depth_render_buffer); 48 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, q->screen_width, q->screen_height); 49 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, q->depth_render_buffer); 50 | 51 | /* Set the list of draw buffers */ 52 | GLenum draw_buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; 53 | glDrawBuffers(2, draw_buffers); 54 | 55 | /* Check for errors */ 56 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 57 | log("Error: Framebuffer not created!\n"); 58 | } 59 | 60 | /* Create fullscreen quad */ 61 | float quad[] = { 62 | -1.0f, -1.0f, 0.0f, 63 | 1.0f, -1.0f, 0.0f, 64 | 1.0f, 1.0f, 0.0f, 65 | -1.0f, -1.0f, 0.0f, 66 | 1.0f, 1.0f, 0.0f, 67 | -1.0f, 1.0f, 0.0f 68 | }; 69 | 70 | GLuint vbo; 71 | glGenBuffers(1, &vbo); 72 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 73 | glBufferData(GL_ARRAY_BUFFER, sizeof quad, quad, GL_STATIC_DRAW); 74 | 75 | glGenVertexArrays(1, &q->vertex_array_object); 76 | glBindVertexArray(q->vertex_array_object); 77 | 78 | glEnableVertexAttribArray(0); 79 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 80 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); 81 | } 82 | 83 | void fs_quad_pingpong_init(FS_Quad pingpong[2], int screen_width, int screen_height, Shader s) 84 | { 85 | pingpong[0].screen_width = screen_width; 86 | pingpong[0].screen_height = screen_height; 87 | pingpong[0].shader = s; 88 | 89 | pingpong[1].screen_width = screen_width; 90 | pingpong[1].screen_height = screen_height; 91 | pingpong[1].shader = s; 92 | 93 | texture_activate(&pingpong[0].texture); 94 | texture_activate(&pingpong[1].texture); 95 | 96 | glGenFramebuffers(1, &pingpong[0].framebuffer_object); 97 | glGenTextures(1, &pingpong[0].texture.object); 98 | 99 | glGenFramebuffers(1, &pingpong[1].framebuffer_object); 100 | glGenTextures(1, &pingpong[1].texture.object); 101 | 102 | for (GLuint i = 0; i < 2; i++) { 103 | glBindFramebuffer(GL_FRAMEBUFFER, pingpong[i].framebuffer_object); 104 | glBindTexture(GL_TEXTURE_2D, pingpong[i].texture.object); 105 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, pingpong[i].screen_width, pingpong[i].screen_height, 0, GL_RGB, GL_FLOAT, NULL); 106 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 107 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 108 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 109 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 110 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pingpong[i].texture.object, 0); 111 | } 112 | 113 | /* Create fullscreen quad */ 114 | float quad[] = { 115 | -1.0f, -1.0f, 0.0f, 116 | 1.0f, -1.0f, 0.0f, 117 | 1.0f, 1.0f, 0.0f, 118 | -1.0f, -1.0f, 0.0f, 119 | 1.0f, 1.0f, 0.0f, 120 | -1.0f, 1.0f, 0.0f 121 | }; 122 | 123 | GLuint vbo; 124 | glGenBuffers(1, &vbo); 125 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 126 | glBufferData(GL_ARRAY_BUFFER, sizeof quad, quad, GL_STATIC_DRAW); 127 | 128 | glGenVertexArrays(1, &pingpong[0].vertex_array_object); 129 | glBindVertexArray(pingpong[0].vertex_array_object); 130 | 131 | glEnableVertexAttribArray(0); 132 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 133 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); 134 | } 135 | 136 | /* http://learnopengl.com/#!Advanced-Lighting/Bloom */ 137 | void fs_quad_pingpong_render(FS_Quad pingpong[2], FS_Quad q) 138 | { 139 | GLboolean horizontal = true; 140 | GLboolean first_iteration = true; 141 | GLuint amount = 10; 142 | 143 | glUseProgram(pingpong[0].shader.shader_program); 144 | 145 | for (GLuint i = 0; i < amount; i++) { 146 | glBindFramebuffer(GL_FRAMEBUFFER, pingpong[horizontal].framebuffer_object); 147 | 148 | glUniform1i(glGetUniformLocation(pingpong[0].shader.shader_program, "horizontal"), horizontal); 149 | 150 | glActiveTexture(GL_TEXTURE0); 151 | glBindTexture(GL_TEXTURE_2D, first_iteration ? q.color_buffers[1] : pingpong[!horizontal].texture.object); 152 | GLuint image = glGetUniformLocation(pingpong[0].shader.shader_program, "image"); 153 | glUniform1i(image, 0); 154 | 155 | glBindVertexArray(pingpong[0].vertex_array_object); 156 | glDrawArrays(GL_TRIANGLES, 0, 6); 157 | glBindVertexArray(0); 158 | 159 | horizontal = !horizontal; 160 | if (first_iteration) 161 | first_iteration = false; 162 | } 163 | } 164 | 165 | void fs_quad_set_as_render_target(FS_Quad q) 166 | { 167 | glBindFramebuffer(GL_FRAMEBUFFER, q.framebuffer_object); 168 | glViewport(0, 0, q.screen_width, q.screen_height); 169 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 170 | } 171 | 172 | void fs_quad_render_to_post(FS_Quad q, FS_Quad post) 173 | { 174 | glBindFramebuffer(GL_FRAMEBUFFER, post.framebuffer_object); 175 | glViewport(0, 0, post.screen_width, post.screen_height); 176 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 177 | 178 | glUseProgram(q.shader.shader_program); 179 | 180 | glActiveTexture(GL_TEXTURE0 + q.texture.index); 181 | glBindTexture(GL_TEXTURE_2D, q.texture.object); 182 | GLuint buffer = glGetUniformLocation(q.shader.shader_program, "diffuse_buffer"); 183 | glUniform1i(buffer, q.texture.index); 184 | 185 | glBindVertexArray(q.vertex_array_object); 186 | glDrawArrays(GL_TRIANGLES, 0, 6); 187 | } 188 | 189 | void fs_quad_render_to_screen(FS_Quad q, FS_Quad pingpong[2]) 190 | { 191 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 192 | glViewport(0, 0, q.screen_width, q.screen_height); 193 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 194 | 195 | glUseProgram(q.shader.shader_program); 196 | 197 | glActiveTexture(GL_TEXTURE0); 198 | glBindTexture(GL_TEXTURE_2D, q.texture.object); 199 | GLuint buffer = glGetUniformLocation(q.shader.shader_program, "HDR_buffer"); 200 | glUniform1i(buffer, 0); 201 | 202 | glActiveTexture(GL_TEXTURE1); 203 | glBindTexture(GL_TEXTURE_2D, pingpong[1].texture.object); 204 | GLuint bloom = glGetUniformLocation(q.shader.shader_program, "bloom_blur"); 205 | glUniform1i(bloom, 1); 206 | 207 | glBindVertexArray(q.vertex_array_object); 208 | glDrawArrays(GL_TRIANGLES, 0, 6); 209 | } -------------------------------------------------------------------------------- /src/fullscreen_quad.h: -------------------------------------------------------------------------------- 1 | #ifndef FULLSCREEN_QUAD_H 2 | #define FULLSCREEN_QUAD_H 3 | 4 | #include "shader.h" 5 | 6 | typedef struct FS_Quad FS_Quad; 7 | struct FS_Quad { 8 | GLuint framebuffer_object; 9 | GLuint vertex_array_object; 10 | GLuint depth_render_buffer; 11 | 12 | GLuint color_buffers[2]; 13 | 14 | int screen_width; 15 | int screen_height; 16 | 17 | Shader shader; 18 | Texture texture; 19 | }; 20 | 21 | void fs_quad_init(FS_Quad* q, int screen_width, int screen_height, Shader s); 22 | void fs_quad_pingpong_init(FS_Quad pingpong[2], int screen_width, int screen_height, Shader s); 23 | void fs_quad_pingpong_render(FS_Quad pingpong[2], FS_Quad q); 24 | void fs_quad_set_as_render_target(FS_Quad q); 25 | void fs_quad_render_to_post(FS_Quad q, FS_Quad post); 26 | void fs_quad_render_to_screen(FS_Quad q, FS_Quad pingpong[2]); 27 | 28 | 29 | #endif -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | 3 | #include "GL/glew.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void log_init() 10 | { 11 | if (ERROR_LOG == 1) { 12 | FILE* file = fopen("../log.txt", "a"); 13 | if (!file) fprintf(stdout, "Could not open log.txt for appending!"); 14 | CString t = CTime::GetCurrentTime().Format("%Y-%m-%d %H:%M"); 15 | fprintf(file, "\n\n[%s]\n", t); 16 | fclose(file); 17 | } 18 | } 19 | 20 | void log(const char* message, ...) 21 | { 22 | va_list args; 23 | 24 | va_start(args, message); 25 | 26 | if (ERROR_LOG == 1) { 27 | FILE* file = fopen("../log.txt", "a"); 28 | if (!file) fprintf(stdout, "Could not open log.txt for appending!"); 29 | vfprintf(file, message, args); 30 | fclose(file); 31 | } 32 | else { 33 | vfprintf(stderr, message, args); 34 | } 35 | 36 | va_end(args); 37 | } 38 | 39 | void log_opengl_error() 40 | { 41 | int e = glGetError(); 42 | if (e != 0) { 43 | printf("OpenGL Error: 0x%x\n\n", e); 44 | } 45 | } 46 | 47 | void log_opengl_clear_errors() 48 | { 49 | while (glGetError() != 0); 50 | } -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOH_H 3 | 4 | #define ERROR_LOG 0 /* 0 = print errors to stdout 5 | 1 = print errors to log.txt */ 6 | 7 | void log_init(); 8 | void log(const char* message, ...); 9 | void log_opengl_error(); 10 | void log_opengl_clear_errors(); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "GL/glew.h" 2 | #include "SDL.h" 3 | #include "SDL_opengl.h" 4 | 5 | #include "glm/glm.hpp" 6 | #include "glm/gtc/matrix_transform.hpp" 7 | #include "glm/gtc/type_ptr.hpp" 8 | 9 | #include "camera.h" 10 | #include "cloud_tiling.h" 11 | #include "cloud_preprocess.h" 12 | #include "framebuffer.h" 13 | #include "fullscreen_quad.h" 14 | #include "log.h" 15 | #include "model.h" 16 | #include "quad.h" 17 | #include "shader.h" 18 | #include "texture.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #define OPENGL_MAJOR_VERSION 4 27 | #define OPENGL_MINOR_VERSION 5 28 | 29 | #define FULLSCREEN 0 30 | #define VERTICAL_SYNC 0 31 | 32 | #define CLOUD_TILE 0 33 | 34 | #if FULLSCREEN 35 | #define SCREEN_WIDTH 1920 36 | #define SCREEN_HEIGHT 1600 37 | #else 38 | #define SCREEN_WIDTH 1280 39 | #define SCREEN_HEIGHT 720 40 | #endif 41 | 42 | /* Main function */ 43 | int main(int argc, char** argv) 44 | { 45 | /* Initialize Log file */ 46 | log_init(); 47 | 48 | /* Initialize SDL */ 49 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) { 50 | log("Error: %s\n", SDL_GetError()); 51 | return 1; 52 | } 53 | 54 | /*Set OpenGL attributes */ 55 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, OPENGL_MAJOR_VERSION); 56 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, OPENGL_MINOR_VERSION); 57 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 58 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 59 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 60 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); 61 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 62 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 63 | SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); 64 | SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); // Anti-aliasing: 0 = Off, 4 = On 65 | 66 | /* Create SDL window */ 67 | #if FULLSCREEN 68 | SDL_Window* window = SDL_CreateWindow("Clouds", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 69 | SCREEN_WIDTH, SCREEN_HEIGHT, 70 | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN); 71 | #else 72 | SDL_Window* window = SDL_CreateWindow("Clouds", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 73 | SCREEN_WIDTH, SCREEN_HEIGHT, 74 | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); 75 | #endif 76 | 77 | if (window == NULL) { 78 | log("Error: %s\n", SDL_GetError()); 79 | return -1; 80 | } 81 | 82 | /* Create a window icon */ 83 | SDL_Surface *icon = SDL_LoadBMP("./res/window_icon.bmp"); 84 | SDL_SetWindowIcon(window, icon); 85 | SDL_FreeSurface(icon); 86 | 87 | /* Create OpenGL context */ 88 | SDL_GLContext context = SDL_GL_CreateContext(window); 89 | if (context == NULL) { 90 | log("Error: %s\n", SDL_GetError()); 91 | return -1; 92 | } 93 | 94 | /* Use vertical sync */ 95 | if (SDL_GL_SetSwapInterval(VERTICAL_SYNC) != 0) { 96 | log("Error: %s\n", SDL_GetError()); 97 | } 98 | 99 | /* Start GLEW */ 100 | glewExperimental = GL_TRUE; 101 | if (glewInit() != GLEW_OK) { 102 | log("Error: GLEW failed to initialize.\n"); 103 | } 104 | 105 | /* OpenGL settings */ 106 | log_opengl_clear_errors(); 107 | glEnable(GL_DEPTH_TEST); 108 | glDepthFunc(GL_LESS); 109 | glClearColor(0.0, 0.0, 0.0, 1.0); 110 | glFrontFace(GL_CCW); 111 | glEnable(GL_CULL_FACE); 112 | glCullFace(GL_BACK); 113 | glEnable(GL_BLEND); 114 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 115 | glDepthRange(CAMERA_NEAR, CAMERA_FAR); 116 | //glEnable(GL_TEXTURE_3D); 117 | log_opengl_error(); 118 | 119 | /* Initialize camera */ 120 | Camera camera; 121 | camera_init(&camera, SCREEN_WIDTH, SCREEN_HEIGHT, CAMERA_FOV, CAMERA_NEAR, CAMERA_FAR); 122 | 123 | /* Initialize shaders */ 124 | log("Loading sky shader...\n"); 125 | Shader sky_shader; 126 | if (shader_init(&sky_shader, "./res/shaders/sky.vert", "./res/shaders/sky.frag") != 0) { 127 | log("Error: Failed to initialize shader in %s at line %d.\n\n", __FILE__, __LINE__); 128 | } 129 | 130 | log("Loading terrain shader...\n"); 131 | Shader terrain_shader; 132 | if (shader_init(&terrain_shader, "./res/shaders/terrain.vert", "./res/shaders/terrain.frag") != 0) { 133 | log("Error: Failed to initialize shader in %s at line %d.\n\n", __FILE__, __LINE__); 134 | } 135 | 136 | #if CLOUD_TILE 137 | log("Loading resolve shader (tile based)...\n"); 138 | Shader resolve_shader; 139 | if (shader_init(&resolve_shader, "./res/shaders/resolve.vert", "./res/shaders/resolve_tile.frag") != 0) { 140 | log("Error: Failed to initialize shader in %s at line %d.\n\n", __FILE__, __LINE__); 141 | } 142 | #else 143 | log("Loading resolve shader (noise based)...\n"); 144 | Shader resolve_shader; 145 | if (shader_init(&resolve_shader, "./res/shaders/resolve.vert", "./res/shaders/resolve_noise.frag") != 0) { 146 | log("Error: Failed to initialize shader in %s at line %d.\n\n", __FILE__, __LINE__); 147 | } 148 | #endif 149 | 150 | log("Loading blur shader...\n"); 151 | Shader blur_shader; 152 | if (shader_init(&blur_shader, "./res/shaders/blur.vert", "./res/shaders/blur.frag") != 0) { 153 | log("Error: Failed to initialize shader in %s at line %d.\n\n", __FILE__, __LINE__); 154 | } 155 | 156 | log("Loading post shader...\n"); 157 | Shader post_shader; 158 | if (shader_init(&post_shader, "./res/shaders/post.vert", "./res/shaders/post.frag") != 0) { 159 | log("Error: Failed to initialize shader in %s at line %d.\n\n", __FILE__, __LINE__); 160 | } 161 | 162 | /* Set up framebuffers */ 163 | log("Setting up framebuffers...\n"); 164 | Framebuffer scene_framebuffer; 165 | framebuffer_scene_init(&scene_framebuffer, SCREEN_WIDTH, SCREEN_HEIGHT); 166 | 167 | Framebuffer cloud_framebuffer; 168 | framebuffer_cloud_init(&cloud_framebuffer, SCREEN_WIDTH, SCREEN_HEIGHT); 169 | 170 | Framebuffer pingpong_framebuffer[2]; 171 | framebuffer_pingpong_init(pingpong_framebuffer, SCREEN_WIDTH, SCREEN_HEIGHT); 172 | 173 | /* Load models */ 174 | log("\nLoading sky dome...\n"); 175 | Model sky_model; 176 | if (model_load_obj(&sky_model, "./res/models/sky_uv.obj") != 0) { 177 | log("Error: Failed to load model in %s at line %d.\n\n", __FILE__, __LINE__); 178 | } 179 | sky_model.shader = sky_shader; 180 | sky_model.scale = glm::vec3(1000.0f, 1000.0f, 1000.0f); 181 | Model sun; 182 | 183 | log("Loading terrain plane...\n"); 184 | Model terrain_model; 185 | if (model_load_obj(&terrain_model, "./res/models/terrain_uv.obj") != 0) { 186 | log("Error: Failed to load model in %s at line %d.\n\n", __FILE__, __LINE__); 187 | } 188 | terrain_model.shader = terrain_shader; 189 | 190 | /* Create textures */ 191 | log("\nLoading terrain texture...\n"); 192 | Texture terrain_texture; 193 | if (texture2D_from_ex5(&terrain_texture, "./res/textures/terrain.ex5") != 0) { 194 | log("Error: Failed to load texture in %s at line %d.\n\n", __FILE__, __LINE__); 195 | } 196 | 197 | log("Loading 3D cloud texture...\n"); 198 | Texture cloud_texture; 199 | if (texture3D_from_ex5(&cloud_texture, "./res/textures/noise5.ex5") != 0) { 200 | log("Error: Failed to load texture in %s at line %d.\n\n", __FILE__, __LINE__); 201 | } 202 | 203 | log("Loading Mie phase texture...\n"); 204 | Texture mie_texture; 205 | if (texture1D_phase(&mie_texture, "./res/textures/phase.txt") != 0) { 206 | log("Error: Failed to load texture in %s at line %d.\n\n", __FILE__, __LINE__); 207 | } 208 | 209 | #if CLOUD_TILE 210 | /* Preprocess for the tile based clouds */ 211 | log("\nPreprocessing cloud structure (tile based)...\n"); 212 | Texture cloud_structure; 213 | Texture cloud_tiles[5]; 214 | cloud_tiling_init(cloud_tiles, &cloud_structure); 215 | 216 | /* Send textures to shaders */ 217 | shader_send_texture3D(resolve_shader, cloud_structure, "cloud_structure"); 218 | shader_send_texture3D(resolve_shader, cloud_tiles[0], "cloud_tile00"); 219 | #else 220 | /* Preprocess the structure of the noise based clouds */ 221 | log("\nPreprocessing cloud structure (noise based)...\n"); 222 | Texture cloud_structure_texture; 223 | cloud_preprocess(&cloud_structure_texture, cloud_texture); 224 | 225 | /* Send textures to shaders */ 226 | shader_send_texture3D(resolve_shader, cloud_texture, "cloud_texture"); 227 | shader_send_texture3D(resolve_shader, cloud_structure_texture, "cloud_structure"); 228 | #endif 229 | 230 | /* Send textures to shaders */ 231 | shader_send_texture2D(terrain_shader, terrain_texture, "terrain_texture"); 232 | shader_send_texture1D(resolve_shader, mie_texture, "mie_texture"); 233 | 234 | /* Main loop */ 235 | log("\nStarting main loop.\n"); 236 | bool exit = false; 237 | float delta_time = 0.0f; 238 | auto last_frame = std::chrono::high_resolution_clock::now(); 239 | float avrage_timer = 0.0f; 240 | bool camera_test = false; 241 | int camera_track = 1; 242 | Uint64 camera_time = 0; 243 | Uint64 camera_start = 0; 244 | Uint64 camera_end = 0; 245 | Uint64 camera_era = 0; 246 | Uint64 camera_duration = 20 * SDL_GetPerformanceFrequency(); 247 | Uint64 frame_counter = 0; 248 | FILE* perf; 249 | Uint64 prev_count = 0; 250 | 251 | while (!exit) { 252 | /* Frame time calculation */ 253 | auto current_time = std::chrono::high_resolution_clock::now(); 254 | delta_time = std::chrono::duration_cast(current_time - last_frame).count() / 1000.0; 255 | last_frame = current_time; 256 | avrage_timer += delta_time; 257 | 258 | if (avrage_timer > 1000) { 259 | char title[128]; 260 | sprintf(title, "Clouds -- Frame time: %.2f ms, FPS: %.0f", delta_time, 1000.0 / delta_time); 261 | SDL_SetWindowTitle(window, title); 262 | avrage_timer = 0; 263 | } 264 | 265 | /* Event handling */ 266 | SDL_Event e; 267 | while (SDL_PollEvent(&e)) { 268 | if (e.type == SDL_QUIT) { 269 | exit = true; 270 | } 271 | 272 | if (e.type == SDL_KEYDOWN) { 273 | if (e.key.keysym.sym == SDLK_ESCAPE) { 274 | exit = true;; 275 | } 276 | if (e.key.keysym.sym == SDLK_r) { 277 | log("Recompiling active shaders...\n\n"); 278 | shader_recompile(); 279 | 280 | /* Send textures to shaders */ 281 | #if CLOUD_TILE 282 | 283 | shader_send_texture3D(resolve_shader, cloud_structure, "cloud_structure"); 284 | shader_send_texture3D(resolve_shader, cloud_tiles[0], "cloud_tile00"); 285 | #else 286 | shader_send_texture3D(resolve_shader, cloud_texture, "cloud_texture"); 287 | shader_send_texture3D(resolve_shader, cloud_structure_texture, "cloud_structure"); 288 | #endif 289 | shader_send_texture2D(terrain_shader, terrain_texture, "terrain_texture"); 290 | shader_send_texture1D(resolve_shader, mie_texture, "mie_texture"); 291 | } 292 | if (e.key.keysym.sym == SDLK_F1) { 293 | if (!camera_test) { 294 | log("Running performance test..."); 295 | perf = fopen("./performance_data_inv_cpu.txt", "w"); 296 | frame_counter = 0; 297 | prev_count = SDL_GetPerformanceCounter(); 298 | camera_track = 1; 299 | camera_start = SDL_GetPerformanceCounter(); 300 | camera_end = camera_start + camera_duration; 301 | camera_era = camera_start; 302 | camera_test = true; 303 | } 304 | } 305 | } 306 | 307 | if (e.type == SDL_MOUSEBUTTONDOWN) { 308 | if (e.button.button == SDL_BUTTON_LEFT) { 309 | camera_toggle_mouse(&camera, window); 310 | } 311 | } 312 | 313 | if (e.type == SDL_MOUSEMOTION) { 314 | if (camera.enabled == SDL_TRUE) { 315 | camera.pitch -= camera.sensitivity * e.motion.yrel; 316 | camera.yaw += camera.sensitivity * e.motion.xrel; 317 | } 318 | 319 | } 320 | } 321 | 322 | ///////////////////////////////////////////////////// http://advances.realtimerendering.com/s2015/The%20Real-time%20Volumetric%20Cloudscapes%20of%20Horizon%20-%20Zero%20Dawn%20-%20ARTR.pdf 323 | ///////////////////////////////////////////////////// http://freespace.virgin.net/hugo.elias/models/m_clouds.htm 324 | ///////////////////////////////////////////////////// http://www.neilblevins.com/cg_education/procedural_noise/procedural_noise.html 325 | ///////////////////////////////////////////////////// http://wiki.nuaj.net/index.php?title=Clouds 326 | ///////////////////////////////////////////////////// http://www-evasion.imag.fr/Publications/2006/BNL06/ 327 | ///////////////////////////////////////////////////// http://learnopengl.com/#!Advanced-Lighting/HDR 328 | 329 | /* Camera movement */ 330 | if (camera_test) { 331 | 332 | camera_time = SDL_GetPerformanceCounter() - camera_start; 333 | 334 | 335 | double frame_time = (double)((SDL_GetPerformanceCounter() - prev_count) * 1000) / SDL_GetPerformanceFrequency(); 336 | double total_time = (double)((SDL_GetPerformanceCounter() - camera_era) * 1000) / SDL_GetPerformanceFrequency(); 337 | 338 | fprintf(perf, "%f %f\n", total_time, frame_time); 339 | prev_count = SDL_GetPerformanceCounter(); 340 | 341 | switch (camera_track) { 342 | case 1: 343 | camera_track1(&camera, camera_time, camera_duration); 344 | break; 345 | case 2: 346 | camera_track2(&camera, camera_time, camera_duration); 347 | break; 348 | case 3: 349 | camera_track3(&camera, camera_time, camera_duration); 350 | break; 351 | case 4: 352 | camera_track4(&camera, camera_time, camera_duration); 353 | break; 354 | } 355 | 356 | if (camera_time > camera_duration) { 357 | camera_track++; 358 | camera_time = 0; 359 | camera_start = SDL_GetPerformanceCounter(); 360 | camera_end = camera_start + camera_duration; 361 | double elapsed_time = (double)((camera_start - camera_era) * 1000) / SDL_GetPerformanceFrequency(); 362 | if (camera_track > 4) { 363 | log("Done\n"); 364 | log("Time passed: %f ms\n", elapsed_time); 365 | log("Total frames rendered: %" SDL_PRIu64 "\n", frame_counter); 366 | log("Average frame time: %f ms\n", elapsed_time / frame_counter); 367 | log("Average frequency: %f f/s\n\n", (double)frame_counter / (elapsed_time / 1000)); 368 | fprintf(perf, "\n"); 369 | fclose(perf); 370 | camera_test = false; 371 | } 372 | } 373 | } else { 374 | camera_movement(&camera, delta_time); 375 | } 376 | sky_model.position = camera.position; 377 | sun.position = camera.position + glm::vec3(1000.0f, 1000.0f, 1000.0f); 378 | 379 | /* Calculate view and projection matrices and send them to shaders */ 380 | shader_uniform_mat4(terrain_shader, model_model_matrix(terrain_model), "model"); 381 | shader_uniform_mat4(terrain_shader, camera_view_matrix(&camera), "view"); 382 | shader_uniform_mat4(terrain_shader, camera_projection_matrix(&camera), "proj"); 383 | 384 | shader_uniform_mat4(sky_shader, model_model_matrix(sky_model), "model"); 385 | shader_uniform_mat4(sky_shader, camera_view_matrix(&camera), "view"); 386 | shader_uniform_mat4(sky_shader, camera_projection_matrix(&camera), "proj"); 387 | 388 | shader_uniform_mat4(resolve_shader, camera_view_matrix(&camera), "view"); 389 | shader_uniform_mat4(resolve_shader, camera_projection_matrix(&camera), "proj"); 390 | 391 | shader_uniform_mat4(resolve_shader, glm::inverse(camera_view_matrix(&camera)), "inv_view"); 392 | shader_uniform_mat4(resolve_shader, glm::inverse(camera_projection_matrix(&camera)), "inv_proj"); 393 | 394 | /* Send miscellaneous uniforms to shaders */ 395 | shader_uniform_vec3(terrain_shader, camera.position, "camera_pos"); 396 | 397 | shader_uniform_vec3(sky_shader, camera.position, "camera_pos"); 398 | shader_uniform_vec3(sky_shader, sun.position, "sun_pos"); 399 | 400 | shader_uniform_vec2(resolve_shader, glm::vec2(SCREEN_WIDTH, SCREEN_HEIGHT), "view_port"); 401 | shader_uniform_vec3(resolve_shader, camera.position, "camera_pos"); 402 | shader_uniform_vec3(resolve_shader, sun.position, "sun_pos"); 403 | 404 | /*** OpenGL rendering ***/ 405 | 406 | /* Render terrain and sky */ 407 | glBindFramebuffer(GL_FRAMEBUFFER, scene_framebuffer.fbo); 408 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 409 | model_render(sky_model); 410 | model_render(terrain_model); 411 | 412 | /* Render clouds via resolve shader */ 413 | glBindFramebuffer(GL_FRAMEBUFFER, cloud_framebuffer.fbo); 414 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 415 | 416 | shader_use(resolve_shader); 417 | 418 | glActiveTexture(GL_TEXTURE10); 419 | glBindTexture(GL_TEXTURE_2D, scene_framebuffer.color_buffer[0]); 420 | GLuint diffuse_buffer = glGetUniformLocation(resolve_shader.shader_program, "diffuse_buffer"); 421 | glUniform1i(diffuse_buffer, 10); 422 | 423 | render_quad(); 424 | 425 | /* Pinpong buffers for bloom */ 426 | GLboolean horizontal = true, first_iteration = true; 427 | GLuint amount = 10; 428 | shader_use(blur_shader); 429 | for (GLuint i = 0; i < amount; i++) { 430 | glBindFramebuffer(GL_FRAMEBUFFER, pingpong_framebuffer[horizontal].fbo); 431 | glUniform1i(glGetUniformLocation(blur_shader.shader_program, "horizontal"), horizontal); 432 | glActiveTexture(GL_TEXTURE5); 433 | glBindTexture(GL_TEXTURE_2D, first_iteration ? cloud_framebuffer.color_buffer[1] : pingpong_framebuffer[!horizontal].color_buffer[0]); 434 | GLuint image = glGetUniformLocation(blur_shader.shader_program, "image"); 435 | glUniform1i(image, 5); 436 | 437 | render_quad(); 438 | horizontal = !horizontal; 439 | if (first_iteration) 440 | first_iteration = false; 441 | } 442 | 443 | /* Render to screen via post shader */ 444 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 445 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 446 | shader_use(post_shader); 447 | 448 | glActiveTexture(GL_TEXTURE11); 449 | glBindTexture(GL_TEXTURE_2D, cloud_framebuffer.color_buffer[0]); 450 | GLuint hdr_buffer = glGetUniformLocation(post_shader.shader_program, "HDR_buffer"); 451 | glUniform1i(hdr_buffer, 11); 452 | 453 | glActiveTexture(GL_TEXTURE12); 454 | glBindTexture(GL_TEXTURE_2D, pingpong_framebuffer[!horizontal].color_buffer[0]); 455 | GLuint bloom = glGetUniformLocation(post_shader.shader_program, "bloom_blur"); 456 | glUniform1i(bloom, 12); 457 | 458 | render_quad(); 459 | 460 | SDL_GL_SwapWindow(window); 461 | 462 | frame_counter++; 463 | } 464 | 465 | /* Shutdown functions */ 466 | SDL_Quit(); 467 | 468 | return 0; 469 | } -------------------------------------------------------------------------------- /src/model.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rikardolajos/clouds/855cd20a7ab389136a38e8dfe9571531cd034959/src/model.cpp -------------------------------------------------------------------------------- /src/model.h: -------------------------------------------------------------------------------- 1 | #ifndef MODEL_H 2 | #define MODEL_H 3 | 4 | #include "GL/glew.h" 5 | #include "shader.h" 6 | #include "glm/glm.hpp" 7 | 8 | typedef struct Model Model; 9 | struct Model { 10 | Shader shader; 11 | GLuint vertex_array_object; 12 | int triangles; 13 | 14 | glm::vec3 position; 15 | glm::vec3 rotation; 16 | glm::vec3 scale; 17 | }; 18 | 19 | int model_load_obj(Model* m, const char* file_path); 20 | void model_render(Model m); 21 | glm::mat4 model_model_matrix(Model m); 22 | 23 | #endif -------------------------------------------------------------------------------- /src/quad.cpp: -------------------------------------------------------------------------------- 1 | #include "quad.h" 2 | 3 | #include "GL/glew.h" 4 | 5 | static GLuint quad_vao = 0; 6 | static GLuint quad_vbo = 0; 7 | 8 | void render_quad() 9 | { 10 | if (quad_vao == 0) { 11 | GLfloat quadVertices[] = { 12 | // Positions // Texture Coords 13 | -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 14 | -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 15 | 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 16 | 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 17 | }; 18 | glGenVertexArrays(1, &quad_vao); 19 | glGenBuffers(1, &quad_vbo); 20 | glBindVertexArray(quad_vao); 21 | glBindBuffer(GL_ARRAY_BUFFER, quad_vbo); 22 | glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); 23 | glEnableVertexAttribArray(0); 24 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); 25 | glEnableVertexAttribArray(1); 26 | glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 27 | } 28 | glBindVertexArray(quad_vao); 29 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 30 | glBindVertexArray(0); 31 | } -------------------------------------------------------------------------------- /src/quad.h: -------------------------------------------------------------------------------- 1 | #ifndef QUAD_H 2 | #define QUAD_H 3 | 4 | void render_quad(); 5 | 6 | #endif -------------------------------------------------------------------------------- /src/shader.cpp: -------------------------------------------------------------------------------- 1 | #include "shader.h" 2 | 3 | #include "GL/glew.h" 4 | #include "glm/gtc/type_ptr.hpp" 5 | 6 | #include "log.h" 7 | #include "texture.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static Shader* active_shaders[24] = { 0 }; 15 | static int active_index = 0; 16 | 17 | #define ERROR_LOG 0 /* 0 = print errors to stderr 18 | 1 = print errors to shader_error_log.txt */ 19 | 20 | static void shader_info_log(GLuint s) 21 | { 22 | int max_length = 2048; 23 | int len = 0; 24 | char info_log[2048] = { 0 }; 25 | glGetShaderInfoLog(s, max_length, &len, info_log); 26 | log("--> %s\n", info_log); 27 | } 28 | 29 | static void program_info_log(GLuint s) 30 | { 31 | int max_length = 2048; 32 | int len = 0; 33 | char info_log[2048] = { 0 }; 34 | glGetProgramInfoLog(s, max_length, &len, info_log); 35 | log("--> %s\n", info_log); 36 | } 37 | 38 | /* Read from file and store in a string */ 39 | static char* read_file(const char* file_path) 40 | { 41 | char* file_contents; 42 | long input_file_size; 43 | 44 | FILE* input_file = fopen(file_path, "rb"); 45 | if (input_file == NULL) { 46 | log("Error: Unable to open file: %s\n", file_path); 47 | return NULL; 48 | } 49 | fseek(input_file, 0, SEEK_END); 50 | input_file_size = ftell(input_file); 51 | rewind(input_file); 52 | file_contents = (char*)malloc((input_file_size + 1) * (sizeof(char))); 53 | fread(file_contents, sizeof(char), input_file_size, input_file); 54 | fclose(input_file); 55 | file_contents[input_file_size] = 0; 56 | 57 | return file_contents; 58 | } 59 | 60 | int shader_init(Shader* shader, const char* vertex_shader_path, const char* fragment_shader_path, int recompile) 61 | { 62 | char* vertex_source = read_file(vertex_shader_path); 63 | char* fragment_source = read_file(fragment_shader_path); 64 | 65 | if (vertex_source == NULL || fragment_source == NULL) { 66 | return -1; 67 | } 68 | 69 | strcpy(shader->path_vertex, vertex_shader_path); 70 | strcpy(shader->path_fragment, fragment_shader_path); 71 | 72 | if (recompile == 0) { 73 | active_shaders[active_index++] = shader; 74 | } 75 | 76 | /* Compile vertex shader */ 77 | log("Compiling: %s\n", vertex_shader_path); 78 | if (recompile == 0) { 79 | shader->vertex_shader = glCreateShader(GL_VERTEX_SHADER); 80 | } 81 | glShaderSource(shader->vertex_shader, 1, &vertex_source, NULL); 82 | glCompileShader(shader->vertex_shader); 83 | 84 | int params = -1; 85 | glGetShaderiv(shader->vertex_shader, GL_COMPILE_STATUS, ¶ms); 86 | if (GL_TRUE != params) { 87 | log("Error: Shader %s did not compile.\n", vertex_shader_path); 88 | shader_info_log(shader->vertex_shader); 89 | return -1; 90 | } 91 | 92 | /* Compile fragment shader */ 93 | log("Compiling: %s\n", fragment_shader_path); 94 | if (recompile == 0) { 95 | shader->fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 96 | } 97 | glShaderSource(shader->fragment_shader, 1, &fragment_source, NULL); 98 | glCompileShader(shader->fragment_shader); 99 | 100 | glGetShaderiv(shader->fragment_shader, GL_COMPILE_STATUS, ¶ms); 101 | if (GL_TRUE != params) { 102 | log("Error: Shader %s did not compile.\n", fragment_shader_path); 103 | shader_info_log(shader->fragment_shader); 104 | return -1; 105 | } 106 | 107 | /* Link vertex shader and fragment shader */ 108 | log("Linking: %s and %s\n", vertex_shader_path, fragment_shader_path); 109 | if (recompile == 0) { 110 | shader->shader_program = glCreateProgram(); 111 | } 112 | glAttachShader(shader->shader_program, shader->vertex_shader); 113 | glAttachShader(shader->shader_program, shader->fragment_shader); 114 | glLinkProgram(shader->shader_program); 115 | 116 | glGetProgramiv(shader->shader_program, GL_LINK_STATUS, ¶ms); 117 | if (GL_TRUE != params) { 118 | log("Error: Could not link shader program %s and %s.\n", vertex_shader_path, fragment_shader_path); 119 | program_info_log(shader->shader_program); 120 | return -1; 121 | } 122 | log("Shader program compiled and linked successfully.\n\n"); 123 | 124 | free(vertex_source); 125 | free(fragment_source); 126 | 127 | return 0; 128 | } 129 | 130 | void shader_recompile() 131 | { 132 | for (int i = 0; i < active_index; i++) { 133 | shader_init(active_shaders[i], active_shaders[i]->path_vertex, active_shaders[i]->path_fragment, 1); 134 | } 135 | } 136 | 137 | void shader_use(Shader shader) 138 | { 139 | glUseProgram(shader.shader_program); 140 | } 141 | 142 | void shader_uniform_mat4(Shader shader, glm::mat4 matrix, const char* name) 143 | { 144 | glUseProgram(shader.shader_program); 145 | GLint uni = glGetUniformLocation(shader.shader_program, name); 146 | glUniformMatrix4fv(uni, 1, GL_FALSE, glm::value_ptr(matrix)); 147 | } 148 | 149 | void shader_uniform_vec2(Shader shader, glm::vec2 vector, const char* name) 150 | { 151 | glUseProgram(shader.shader_program); 152 | GLint uni = glGetUniformLocation(shader.shader_program, name); 153 | glUniform2fv(uni, 1, glm::value_ptr(vector)); 154 | } 155 | 156 | void shader_uniform_vec3(Shader shader, glm::vec3 vector, const char* name) 157 | { 158 | glUseProgram(shader.shader_program); 159 | GLint uni = glGetUniformLocation(shader.shader_program, name); 160 | glUniform3fv(uni, 1, glm::value_ptr(vector)); 161 | } 162 | 163 | void shader_uniform_1f(Shader shader, float f, const char* name) 164 | { 165 | glUseProgram(shader.shader_program); 166 | GLint uni = glGetUniformLocation(shader.shader_program, name); 167 | glUniform1f(uni, f); 168 | } 169 | 170 | void shader_send_texture1D(Shader shader, Texture t, const char* name) 171 | { 172 | glUseProgram(shader.shader_program); 173 | GLint uni = glGetUniformLocation(shader.shader_program, name); 174 | glUniform1i(uni, t.index); 175 | glActiveTexture(GL_TEXTURE0 + t.index); 176 | glBindTexture(GL_TEXTURE_1D, t.object); 177 | } 178 | 179 | void shader_send_texture2D(Shader shader, Texture t, const char* name) 180 | { 181 | glUseProgram(shader.shader_program); 182 | GLint uni = glGetUniformLocation(shader.shader_program, name); 183 | glUniform1i(uni, t.index); 184 | glActiveTexture(GL_TEXTURE0 + t.index); 185 | glBindTexture(GL_TEXTURE_2D, t.object); 186 | } 187 | 188 | void shader_send_texture3D(Shader shader, Texture t, const char* name) 189 | { 190 | glUseProgram(shader.shader_program); 191 | GLint uni = glGetUniformLocation(shader.shader_program, name); 192 | glUniform1i(uni, t.index); 193 | glActiveTexture(GL_TEXTURE0 + t.index); 194 | glBindTexture(GL_TEXTURE_3D, t.object); 195 | } -------------------------------------------------------------------------------- /src/shader.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADER_H 2 | #define SHADER_H 3 | 4 | #include "GL/glew.h" 5 | #include "glm/glm.hpp" 6 | 7 | #include "texture.h" 8 | 9 | typedef struct Shader Shader; 10 | struct Shader { 11 | GLuint vertex_shader; 12 | GLuint fragment_shader; 13 | GLuint shader_program; 14 | char path_vertex[256]; 15 | char path_fragment[256]; 16 | }; 17 | 18 | 19 | int shader_init(Shader* shader, const char* vertex_shader_path, const char* fragment_shader_path, int recompile = 0); 20 | void shader_recompile(); 21 | void shader_use(Shader shader); 22 | void shader_uniform_mat4(Shader shader, glm::mat4 matrix, const char* name); 23 | void shader_uniform_vec2(Shader shader, glm::vec2 vector, const char* name); 24 | void shader_uniform_vec3(Shader shader, glm::vec3 vector, const char* name); 25 | void shader_uniform_1f(Shader shader, float f, const char* name); 26 | void shader_send_texture1D(Shader shader, Texture t, const char* name); 27 | void shader_send_texture2D(Shader shader, Texture t, const char* name); 28 | void shader_send_texture3D(Shader shader, Texture t, const char* name); 29 | 30 | #endif -------------------------------------------------------------------------------- /src/texture.cpp: -------------------------------------------------------------------------------- 1 | #include "texture.h" 2 | 3 | #include "GL/glew.h" 4 | 5 | #include "log.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static int active_textures = 0; 13 | 14 | void texture_activate(Texture* t) 15 | { 16 | t->index = active_textures++; 17 | } 18 | 19 | int texture1D_phase(Texture* t, const char* file_path) 20 | { 21 | FILE* fp = fopen(file_path, "r"); 22 | 23 | if (fp == NULL) { 24 | return -1; 25 | } 26 | 27 | texture_activate(t); 28 | 29 | /* Create image */ 30 | uint8_t* data = (uint8_t*)calloc(1801, sizeof *data); 31 | 32 | /* Read image*/ 33 | int i = 0; 34 | char value[128]; 35 | while (fgets(value, 128, fp)) { 36 | value[strlen(value) - 1] = '\0'; 37 | data[i++] = (uint8_t)(255 * atof(value)); 38 | } 39 | 40 | glGenTextures(1, &t->object); 41 | glBindTexture(GL_TEXTURE_1D, t->object); 42 | 43 | glTexImage1D(GL_TEXTURE_1D, 0, GL_RED, 1800, 0, GL_RED, GL_UNSIGNED_BYTE, data); 44 | glGenerateMipmap(GL_TEXTURE_1D); 45 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 46 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 47 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); 48 | 49 | free(data); 50 | 51 | return 0; 52 | } 53 | 54 | int texture2D_from_ex5(Texture* t, const char* file_path) 55 | { 56 | FILE* fp = fopen(file_path, "r"); 57 | 58 | if (fp == NULL) { 59 | return -1; 60 | } 61 | 62 | texture_activate(t); 63 | 64 | /* Read header */ 65 | fscanf(fp, "%d", &t->width); 66 | fscanf(fp, "%d", &t->height); 67 | 68 | /* Create image */ 69 | uint8_t* data = (uint8_t*)calloc(t->width * t->height * 4, sizeof *data); 70 | 71 | /* Read image*/ 72 | int i = 0; 73 | uint32_t pixel; 74 | while (fscanf(fp, "%d", &pixel) == 1) { 75 | data[i++] = pixel >> 24; 76 | data[i++] = pixel >> 16; 77 | data[i++] = pixel >> 8; 78 | data[i++] = pixel >> 0; 79 | } 80 | 81 | glGenTextures(1, &t->object); 82 | glBindTexture(GL_TEXTURE_2D, t->object); 83 | 84 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t->width, t->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 85 | glGenerateMipmap(GL_TEXTURE_2D); 86 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 89 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 90 | 91 | free(data); 92 | 93 | return 0; 94 | } 95 | 96 | int texture3D_from_ex5(Texture* t, const char* file_path) 97 | { 98 | FILE* fp = fopen(file_path, "r"); 99 | 100 | if (fp == NULL) { 101 | return -1; 102 | } 103 | 104 | texture_activate(t); 105 | 106 | /* Read header */ 107 | fscanf(fp, "%d", &t->width); 108 | fscanf(fp, "%d", &t->height); 109 | fscanf(fp, "%d", &t->depth); 110 | 111 | /* Create image */ 112 | uint8_t* data = (uint8_t*)calloc(t->width * t->height * t->depth * 4, sizeof *data); 113 | 114 | /* Read image*/ 115 | int i = 0; 116 | uint32_t pixel; 117 | while (fscanf(fp, "%d", &pixel) == 1) { 118 | data[i++] = pixel >> 24; 119 | data[i++] = pixel >> 16; 120 | data[i++] = pixel >> 8; 121 | data[i++] = pixel >> 0; 122 | } 123 | 124 | glGenTextures(1, &t->object); 125 | glBindTexture(GL_TEXTURE_3D, t->object); 126 | 127 | glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, t->width, t->height, t->depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 128 | glGenerateMipmap(GL_TEXTURE_3D); 129 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 130 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 131 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); 132 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT); 133 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); 134 | 135 | free(data); 136 | 137 | return 0; 138 | } -------------------------------------------------------------------------------- /src/texture.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXTURE_H 2 | #define TEXTURE_H 3 | 4 | #include "GL/glew.h" 5 | 6 | typedef struct Texture Texture; 7 | struct Texture { 8 | GLuint object; 9 | GLuint index; 10 | int width, height, depth; 11 | }; 12 | 13 | void texture_activate(Texture* t); 14 | int texture1D_phase(Texture* t, const char* file_path); 15 | int texture2D_from_ex5(Texture* t, const char* file_path); 16 | int texture3D_from_ex5(Texture* t, const char* file_path); 17 | 18 | #endif --------------------------------------------------------------------------------