1 module des.gl.render;
2 
3 import des.gl;
4 import des.il;
5 
6 /// Render to FBO
7 class GLRender : DesObject
8 {
9     mixin DES;
10     mixin ClassLogger;
11 protected:
12 
13     ///
14     GLFrameBuffer fbo;
15 
16     ///
17     GLTexture2D depth_buf;
18 
19     ///
20     GLTexture2D[uint] color_bufs;
21 
22     uivec2 buf_size;
23     int[4] last_vp;
24 
25 public:
26 
27     ///
28     this() { fbo = newEMM!GLFrameBuffer; }
29 
30     ///
31     GLTexture2D defaultDepth( uint unit )
32     {
33         auto tex = createDefaultTexture( unit );
34         tex.setImage( uivec3(1), GLTexture.InternalFormat.DEPTH32F,
35             GLTexture.Format.DEPTH, GLTexture.Type.FLOAT );
36         return tex;
37     }
38 
39     ///
40     GLTexture2D defaultColor( uint unit )
41     {
42         auto tex = createDefaultTexture( unit );
43         tex.setImage( uivec3(1), GLTexture.InternalFormat.RGBA,
44             GLTexture.Format.RGBA, GLTexture.Type.FLOAT );
45         return tex;
46     }
47 
48     ///
49     GLTexture2D getDepth() { return depth_buf; }
50 
51     ///
52     void setDepth( GLTexture2D buf )
53     in{ assert( buf !is null ); } body
54     {
55         if( depth_buf is buf )
56         {
57             // TODO: warning
58             return;
59         }
60 
61         removeIfChild( depth_buf );
62         registerChildEMM( buf, true );
63         depth_buf = buf;
64         fbo.setDepth( buf );
65         fbo.check();
66     }
67 
68     /// get buffer setted to color attachment N
69     GLTexture2D getColor( uint N )
70     { return color_bufs.get( N, null ); }
71 
72     ///
73     GLTexture2D[uint] getColors() { return color_bufs.dup; }
74 
75     /// set buf to color attachment N
76     void setColor( GLTexture2D buf, uint N )
77     in{ assert( buf !is null ); } body
78     {
79         if( auto tmp = color_bufs.get( N, null ) )
80         {
81             if( tmp is buf )
82             {
83                 // TODO: warning
84                 return;
85             }
86             removeIfChild( tmp );
87         }
88 
89         registerChildEMM( buf, true );
90         color_bufs[N] = buf;
91         fbo.setColor( buf, N );
92         fbo.check();
93     }
94 
95     ///
96     void resize( uivec2 sz )
97     {
98         if( sz == buf_size ) return;
99         if( depth_buf ) depth_buf.size = uivec3( sz, 1 );
100         foreach( col; color_bufs ) col.size = uivec3( sz, 1 );
101         buf_size = sz;
102         logger.Debug( "[%d,%d]", sz.x, sz.y );
103     }
104 
105     /// `GLFrameBuffer.drawBuffers`
106     void drawBuffers( in int[] bufs... ) { fbo.drawBuffers( bufs ); }
107 
108     ///
109     void resize( uint w, uint h ) { resize( uivec2( w, h ) ); }
110 
111     ///
112     void bind()
113     {
114         fbo.bind();
115         checkGLCall!glGetIntegerv( GL_VIEWPORT, last_vp.ptr );
116         checkGLCall!glViewport( 0, 0, buf_size.x, buf_size.y );
117     }
118 
119     ///
120     void unbind()
121     {
122         fbo.unbind();
123         checkGLCall!glViewport( last_vp[0], last_vp[1], last_vp[2], last_vp[3] );
124     }
125 
126 protected:
127 
128     auto createDefaultTexture( uint unit )
129     {
130         auto tex = new GLTexture2D( unit );
131         tex.setWrapS( GLTexture.Wrap.CLAMP_TO_EDGE );
132         tex.setWrapT( GLTexture.Wrap.CLAMP_TO_EDGE );
133         tex.setMinFilter( GLTexture.Filter.NEAREST );
134         tex.setMagFilter( GLTexture.Filter.NEAREST );
135         return tex;
136     }
137 
138     void removeIfChild( GLTexture2D t )
139     {
140         if( depth_buf && findInChildsEMM( depth_buf ) )
141         {
142             depth_buf.destroy();
143             detachChildsEMM( depth_buf );
144         }
145     }
146 
147     override void selfDestroy() { fbo.unbind(); }
148 }