1 module graphics.adapters.adapter; 2 import core.gameobject, core.properties; 3 import components; 4 import graphics.shaders; 5 import utility.config, utility.output; 6 7 import gl3n.linalg; 8 import derelict.opengl3.gl3; 9 10 version( Windows ) 11 { 12 import win32.windef; 13 14 alias HGLRC GLRenderContext; 15 alias HDC GLDeviceContext; 16 } 17 else version( OSX ) 18 { 19 import derelict.opengl3.gl3, derelict.opengl3.cgl; 20 21 alias CGLContextObj GLRenderContext; 22 alias uint GLDeviceContext; 23 } 24 else 25 { 26 import derelict.opengl3.glx, derelict.opengl3.glxext; 27 28 //alias OpenGLRenderContext GLRenderContext; 29 alias GLXContext GLRenderContext; 30 alias uint GLDeviceContext; 31 } 32 33 abstract class Adapter 34 { 35 public: 36 // Graphics contexts 37 mixin Property!( "GLDeviceContext", "deviceContext", "protected" ); 38 mixin Property!( "GLRenderContext", "renderContext", "protected" ); 39 40 mixin Property!( "uint", "width", "protected" ); 41 mixin Property!( "uint", "screenWidth", "protected" ); 42 mixin Property!( "uint", "height", "protected" ); 43 mixin Property!( "uint", "screenHeight", "protected" ); 44 mixin Property!( "bool", "fullscreen", "protected" ); 45 mixin Property!( "bool", "backfaceCulling", "protected" ); 46 mixin Property!( "bool", "vsync", "protected" ); 47 mixin Property!( "float", "fov", "protected" ); 48 mixin Property!( "float", "near", "protected" ); 49 mixin Property!( "float", "far", "protected" ); 50 mixin Property!( "uint", "deferredFrameBuffer", "protected" ); 51 mixin Property!( "uint", "diffuseRenderTexture", "protected" ); //Alpha channel stores Specular color 52 mixin Property!( "uint", "normalRenderTexture", "protected" ); //Alpha channel stores Specular power 53 mixin Property!( "uint", "depthRenderTexture", "protected" ); 54 55 enum : string 56 { 57 GeometryShader = "geometry", 58 LightingShader = "lighting", 59 WindowMesh = "WindowMesh" 60 } 61 62 abstract void initialize(); 63 abstract void shutdown(); 64 abstract void resize(); 65 abstract void reload(); 66 abstract void swapBuffers(); 67 68 abstract void openWindow(); 69 abstract void closeWindow(); 70 71 abstract void messageLoop(); 72 73 final void initializeDeferredRendering() 74 { 75 //http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ 76 77 //Create the frame buffer, which will contain the textures to render to 78 deferredFrameBuffer = 0; 79 glGenFramebuffers( 1, &_deferredFrameBuffer ); 80 glBindFramebuffer( GL_FRAMEBUFFER, deferredFrameBuffer ); 81 82 //Generate our 3 textures 83 glGenTextures( 1, &_diffuseRenderTexture ); 84 glGenTextures( 1, &_normalRenderTexture ); 85 glGenTextures( 1, &_depthRenderTexture ); 86 87 //For each texture, we bind it to our active texture, and set the format and filtering 88 glBindTexture( GL_TEXTURE_2D, diffuseRenderTexture ); 89 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null ); 90 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); 91 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); 92 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); 93 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); 94 95 glBindTexture( GL_TEXTURE_2D, normalRenderTexture ); 96 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, null ); 97 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); 98 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); 99 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); 100 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); 101 102 glBindTexture( GL_TEXTURE_2D, depthRenderTexture ); 103 glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, null ); 104 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); 105 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); 106 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); 107 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); 108 109 //And finally set all of these to our frameBuffer 110 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, diffuseRenderTexture, 0 ); 111 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normalRenderTexture, 0 ); 112 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthRenderTexture, 0 ); 113 114 GLenum[ 2 ] DrawBuffers = [ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 ]; 115 glDrawBuffers( 2, DrawBuffers.ptr ); 116 glViewport(0, 0, width, height); 117 updateProjection(); 118 119 if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ) 120 { 121 log( OutputType.Error, "Deffered rendering Frame Buffer was not initialized correctly."); 122 assert(false); 123 } 124 } 125 126 /** 127 * sets up the rendering pipeline for the geometry pass 128 */ 129 final void beginDraw() 130 { 131 glBindFramebuffer( GL_FRAMEBUFFER, deferredFrameBuffer ); 132 133 // must be called before glClear to clear the depth buffer, otherwise 134 // depth buffer won't be cleared 135 glDepthMask( GL_TRUE ); 136 137 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 138 139 glEnable( GL_DEPTH_TEST ); 140 glDisable( GL_BLEND ); 141 142 glUseProgram( Shaders[GeometryShader].programID ); 143 } 144 145 /** 146 * draws an object for the geometry pass 147 * beginDraw must be called before any calls of this function 148 * Params: 149 * object = the object to be drawn 150 */ 151 final void drawObject( GameObject object ) 152 { 153 // set the shader 154 auto shader = Shaders[GeometryShader]; 155 glBindVertexArray( object.mesh.glVertexArray ); 156 157 shader.bindUniformMatrix4fv( ShaderUniform.World , object.transform.matrix ); 158 shader.bindUniformMatrix4fv( ShaderUniform.WorldViewProjection , projection * 159 ( ( activeCamera !is null ) ? activeCamera.viewMatrix : mat4.identity ) * 160 object.transform.matrix ); 161 162 shader.bindMaterial( object.material ); 163 164 glDrawElements( GL_TRIANGLES, object.mesh.numVertices, GL_UNSIGNED_INT, null ); 165 166 glBindVertexArray(0); 167 } 168 169 /** 170 * called after all desired objects are drawn 171 * handles lighting and post processing 172 */ 173 final void endDraw() 174 { 175 // settings for light pass 176 glDepthMask( GL_FALSE ); 177 glDisable( GL_DEPTH_TEST ); 178 glEnable( GL_BLEND ); 179 // glBlendEquation( GL_FUNC_ADD ); 180 // glBlendFunc(GL_ONE, GL_ONE ); 181 182 //This line switches back to the default framebuffer 183 glBindFramebuffer( GL_FRAMEBUFFER, 0 ); 184 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 185 186 auto shader = Shaders[LightingShader]; 187 glUseProgram( shader.programID ); 188 189 // bind geometry pass textures 190 GLint textureLocation = shader.getUniformLocation( ShaderUniform.DiffuseTexture ); 191 glUniform1i( textureLocation, 0 ); 192 glActiveTexture( GL_TEXTURE0 ); 193 glBindTexture( GL_TEXTURE_2D, diffuseRenderTexture ); 194 195 textureLocation = shader.getUniformLocation( ShaderUniform.NormalTexture ); 196 glUniform1i( textureLocation, 1 ); 197 glActiveTexture( GL_TEXTURE1 ); 198 glBindTexture( GL_TEXTURE_2D, normalRenderTexture ); 199 200 textureLocation = shader.getUniformLocation( ShaderUniform.DepthTexture ); 201 glUniform1i( textureLocation, 2 ); 202 glActiveTexture( GL_TEXTURE2 ); 203 glBindTexture( GL_TEXTURE_2D, depthRenderTexture ); 204 205 // bind the directional and ambient lights 206 if( directionalLight is null ) 207 { 208 directionalLight = new DirectionalLight( vec3(), vec3() ); 209 } 210 if( ambientLight is null ) 211 { 212 ambientLight = new AmbientLight( vec3() ); 213 } 214 shader.bindDirectionalLight( directionalLight ); 215 shader.bindAmbientLight( ambientLight ); 216 217 // bind the window mesh for directional lights 218 glBindVertexArray( Assets.get!Mesh( WindowMesh ).glVertexArray ); 219 glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, null ); 220 221 glBindVertexArray(0); 222 glUseProgram(0); 223 224 swapBuffers(); 225 226 lights = []; 227 ambientLight = null; 228 directionalLight = null; 229 } 230 231 final void addLight( Light light ) 232 { 233 if( typeid( light ) == typeid( AmbientLight ) ) 234 { 235 if( ambientLight is null ) 236 { 237 ambientLight = cast(AmbientLight)light; 238 } 239 else 240 log( OutputType.Info, "Attemtping to add multiple ambient lights to the scene. Ignoring additional ambient lights." ); 241 } 242 else if( typeid( light ) == typeid( DirectionalLight ) ) 243 { 244 if( directionalLight is null ) 245 { 246 directionalLight = cast(DirectionalLight)light; 247 } 248 else 249 log( OutputType.Info, "Attemtping to add multiple directional lights to the scene. Ignoring additional directional lights." ); 250 } 251 else 252 { 253 lights ~= light; 254 } 255 } 256 257 final void setCamera( Camera camera ) 258 { 259 activeCamera = camera; 260 } 261 262 protected: 263 final void loadProperties() 264 { 265 fullscreen = Config.get!bool( "Display.Fullscreen" ); 266 if( fullscreen ) 267 { 268 width = screenWidth; 269 height = screenHeight; 270 } 271 else 272 { 273 width = Config.get!uint( "Display.Width" ); 274 height = Config.get!uint( "Display.Height" ); 275 } 276 277 backfaceCulling = Config.get!bool( "Graphics.BackfaceCulling" ); 278 vsync = Config.get!bool( "Graphics.VSync" ); 279 fov = Config.get!float( "Display.FieldOfView" ); 280 near = Config.get!float( "Display.NearPlane" ); 281 far = Config.get!float( "Display.FarPlane" ); 282 } 283 284 final void updateProjection() 285 { 286 projection = mat4.perspective( cast(float)width, cast(float)height, fov, near, far ); 287 } 288 289 private: 290 Camera activeCamera; 291 mat4 projection; 292 //To be cleared after a draw call: 293 AmbientLight ambientLight; 294 DirectionalLight directionalLight; 295 Light[] lights; 296 }