1 module des.gl.fbo; 2 3 import std.exception; 4 import std.conv; 5 6 import des.gl.general; 7 import des.gl.texture; 8 import des.gl.rbo; 9 10 /// 11 class GLFBOException : DesGLException 12 { 13 /// 14 this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow 15 { super( msg, file, line ); } 16 } 17 18 /// 19 class GLFrameBuffer : GLObject!"Framebuffer" 20 { 21 mixin DES; 22 mixin ClassLogger; 23 24 protected: 25 static uint[] id_stack; 26 27 /// 28 enum Attachment 29 { 30 COLOR = GL_COLOR_ATTACHMENT0, /// `GL_COLOR_ATTACHMENT0` 31 DEPTH = GL_DEPTH_ATTACHMENT, /// `GL_DEPTH_ATTACHMENT` 32 STENCIL = GL_STENCIL_ATTACHMENT, /// `GL_STENCIL_ATTACHMENT` 33 DEPTH_STENCIL = GL_DEPTH_STENCIL_ATTACHMENT, /// `GL_DEPTH_STENCIL_ATTACHMENT` 34 } 35 36 public: 37 38 /// 39 this() 40 { 41 if( id_stack.length == 0 ) id_stack ~= 0; 42 super( GL_FRAMEBUFFER ); 43 logger.Debug( "pass" ); 44 } 45 46 final 47 { 48 /// `glBindFramebuffer` add id to stack 49 override void bind() 50 { 51 if( id_stack[$-1] == id ) return; 52 ntCheckGLCall!glBindFramebuffer( GL_FRAMEBUFFER, id ); 53 id_stack ~= id; 54 debug logger.trace( "pass" ); 55 } 56 57 /// pop from stack old frame buffer id and `glBindFramebuffer` with it 58 override void unbind() 59 { 60 if( id_stack.length < 2 && id_stack[$-1] != id ) return; 61 id_stack.length--; 62 ntCheckGLCall!glBindFramebuffer( GL_FRAMEBUFFER, id_stack[$-1] ); 63 debug logger.trace( "bind [%d]", id_stack[$-1] ); 64 } 65 } 66 67 /// 68 void drawBuffers( in int[] bufs... ) 69 { 70 int max_bufs; 71 checkGLCall!glGetIntegerv( GL_MAX_DRAW_BUFFERS, &max_bufs ); 72 enforce( bufs.length < max_bufs, 73 new GLFBOException( format( "count of draw buffers greater what max value (%d>%d)", bufs.length, max_bufs ) ) ); 74 bind(); scope(exit) unbind(); 75 GLenum[] res; 76 foreach( val; bufs ) 77 if( val < 0 ) res ~= GL_NONE; 78 else res ~= cast(GLenum)( Attachment.COLOR + val ); 79 checkGLCall!glDrawBuffers( cast(int)res.length, res.ptr ); 80 } 81 82 /// set render buffer as depth attachment 83 void setDepth( GLRenderBuffer rbo ) 84 in{ assert( rbo !is null ); } body 85 { 86 bind(); scope(exit) unbind(); 87 setRBO( rbo, Attachment.DEPTH ); 88 logger.Debug( "[%d]", rbo.id ); 89 } 90 91 /// set render buffer as color attachment 92 void setColor( GLRenderBuffer rbo, uint no ) 93 in{ assert( rbo !is null ); } body 94 { 95 bind(); scope(exit) unbind(); 96 setRBO( rbo, cast(GLenum)( Attachment.COLOR + no ) ); 97 logger.Debug( "[%d] as COLOR%d", rbo.id, no ); 98 } 99 100 /// set texture as depth attachment 101 void setDepth( GLTexture tex ) 102 { 103 bind(); scope(exit) unbind(); 104 setTex( tex, Attachment.DEPTH ); 105 logger.Debug( "[%d]", tex.id ); 106 } 107 108 /// set texture as color attachment 109 void setColor( GLTexture tex, uint no=0 ) 110 { 111 bind(); scope(exit) unbind(); 112 setTex( tex, cast(GLenum)( Attachment.COLOR + no ) ); 113 logger.Debug( "[%d] as COLOR%d", tex.id, no ); 114 } 115 116 /// `glCheckFramebufferStatus` 117 void check() 118 { 119 bind(); scope(exit) unbind(); 120 auto status = checkGLCall!glCheckFramebufferStatus( GL_FRAMEBUFFER ); 121 import std..string; 122 if( status != GL_FRAMEBUFFER_COMPLETE ) 123 throw new GLFBOException( format( "status isn't GL_FRAMEBUFFER_COMPLETE, it's %#x", status ) ); 124 logger.Debug( "pass" ); 125 } 126 127 protected: 128 129 /// warning: no bind 130 void setRBO( GLRenderBuffer rbo, GLenum attachment ) 131 in{ assert( rbo !is null ); } body 132 { 133 checkGLCall!glFramebufferRenderbuffer( GL_FRAMEBUFFER, 134 attachment, GL_RENDERBUFFER, rbo.id ); 135 } 136 137 /// warning: no bind 138 void texture1D( GLTexture tex, GLenum attachment, uint level=0 ) 139 in { assert( tex !is null ); } body 140 { 141 checkGLCall!glFramebufferTexture1D( GL_FRAMEBUFFER, attachment, 142 GL_TEXTURE_1D, tex.id, level ); 143 } 144 145 /// warning: no bind 146 void texture2D( GLTexture tex, GLenum attachment, uint level=0 ) 147 in { assert( tex !is null ); } body 148 { 149 checkGLCall!glFramebufferTexture2D( GL_FRAMEBUFFER, attachment, 150 tex.target, tex.id, level ); 151 } 152 153 /// warning: no bind 154 void texture3D( GLTexture tex, GLenum attachment, uint level=0, int layer=0 ) 155 in { assert( tex !is null ); } body 156 { 157 checkGLCall!glFramebufferTexture3D( GL_FRAMEBUFFER, attachment, 158 tex.target, tex.id, level, layer ); 159 } 160 161 /// warning: no bind 162 void texture( GLTexture tex, GLenum attachment, uint level=0 ) 163 { checkGLCall!glFramebufferTexture( GL_FRAMEBUFFER, attachment, tex.id, level ); } 164 165 /// warning: no bind 166 void textureLayer( GLTexture tex, GLenum attachment, uint layer, uint level=0 ) 167 { checkGLCall!glFramebufferTextureLayer( GL_FRAMEBUFFER, attachment, tex.id, level, layer ); } 168 169 170 /// warning: no bind 171 void setTex( GLTexture tex, GLenum attachment ) 172 { 173 if( tex.target == GL_TEXTURE_1D ) 174 texture1D( tex, attachment ); 175 else if( tex.target == GL_TEXTURE_3D || 176 tex.target == GL_TEXTURE_2D_ARRAY || 177 tex.target == GL_TEXTURE_CUBE_MAP_ARRAY ) 178 texture3D( tex, attachment ); 179 else 180 texture2D( tex, attachment, tex.target ); 181 } 182 }