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