1 /** 2 * Copyright: Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved 3 * Authors: $(Gabriel Gheorghe) 4 * License: $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007) 5 * Source: $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/graphics/postprocessing.d, _postprocessing.d) 6 * Documentation: 7 * Coverage: 8 */ 9 module liberty.graphics.postprocessing; 10 version (nonde) : 11 version (__OpenGL__) : 12 import liberty.graphics.opengl; 13 /// Value less = priority bigger 14 enum PostProcessFxFlag : long { 15 /// 16 Default = 0x00, 17 /// 18 Sepia = 0x01, 19 /// 20 Aqua = 0x02, // TODO. 21 /// 22 BlackAndWhite = 0x04 23 } 24 /// 25 class Postprocessing { 26 private immutable defaultVER = " 27 #version 450 core 28 "; 29 private immutable defaultVS = " 30 #if VERTEX_SHADER 31 in vec3 position; 32 in vec2 coordinates; 33 out vec2 fragmentUV; 34 void main() 35 { 36 gl_Position = vec4(position, 1.0); 37 fragmentUV = coordinates; 38 } 39 #endif 40 "; 41 private immutable defaultFS_begin = " 42 #if FRAGMENT_SHADER 43 in vec2 fragmentUV; 44 uniform sampler2D fbTexture; 45 out vec4 color; 46 void main() { 47 vec3 base = texture(fbTexture, fragmentUV).rgb; 48 "; 49 private immutable defaultFS_end = " 50 color = vec4(base, 1.0); 51 } 52 #endif 53 "; 54 private immutable bwFS = " 55 float luminance = base.r * 0.299 + base.g * 0.578 + base.b * 0.114; 56 base = vec3(luminance); 57 "; 58 private immutable sepiaFS = " 59 vec3 sepia = vec3( 60 clamp(base.r * 0.393 + base.g * 0.769 + base.b * 0.189, 0.0, 1.0), 61 clamp(base.r * 0.349 + base.g * 0.686 + base.b * 0.168, 0.0, 1.0), 62 clamp(base.r * 0.272 + base.g * 0.534 + base.b * 0.131, 0.0, 1.0) 63 ); 64 base = mix(base, sepia, clamp(1.0, 0.0, 1.0)); 65 "; 66 /// 67 this(GLBackend gl, int screenWidth, int screenHeight, PostProcessFxFlag flag) { 68 _screenBuf = new GLTexture2D(); 69 _screenBuf.minFilter = GL_LINEAR_MIPMAP_LINEAR; 70 _screenBuf.magFilter = GL_LINEAR; 71 _screenBuf.wrapS = GL_CLAMP_TO_EDGE; 72 _screenBuf.wrapT = GL_CLAMP_TO_EDGE; 73 _screenBuf.setImage(0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); 74 _screenBuf.generateMipmap(); 75 _fbo = new GLFrameBufferObject(); 76 _fbo.use(); 77 _fbo.color(0).attach(_screenBuf); 78 _fbo.unuse(); 79 80 // create a shader program made of a single fragment shader 81 string postprocProgramSource = defaultVER ~ defaultVS ~ defaultFS_begin; 82 if (flag & PostProcessFxFlag.Sepia) { 83 postprocProgramSource ~= sepiaFS; 84 } 85 if (flag & PostProcessFxFlag.BlackAndWhite) { 86 postprocProgramSource ~= bwFS; 87 } 88 postprocProgramSource ~= defaultFS_end; 89 90 _program = new GLProgram(postprocProgramSource); 91 } 92 93 ~this() 94 { 95 _program.destroy(); 96 _fbo.destroy(); 97 _screenBuf.destroy(); 98 } 99 100 void bindFBO() 101 { 102 _fbo.use(); 103 } 104 105 // Post-processing pass 106 void pass(void delegate() drawGeometry) { 107 _fbo.unuse(); 108 _screenBuf.generateMipmap(); 109 110 int texUnit = 1; 111 _screenBuf.use(texUnit); 112 113 _program.uniform("fbTexture").set(texUnit); 114 _program.uniform("sharpen").set(true); 115 _program.use(); 116 117 drawGeometry(); 118 } 119 private: 120 GLFrameBufferObject _fbo; 121 GLTexture2D _screenBuf; 122 GLProgram _program; 123 }