1 /+
2 The MIT License (MIT)
3 
4     Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)>
5 
6     Permission is hereby granted, free of charge, to any person obtaining a copy
7     of this software and associated documentation files (the "Software"), to deal
8     in the Software without restriction, including without limitation the rights
9     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10     copies of the Software, and to permit persons to whom the Software is
11     furnished to do so, subject to the following conditions:
12 
13     The above copyright notice and this permission notice shall be included in
14     all copies or substantial portions of the Software.
15 
16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22     THE SOFTWARE.
23 +/
24 
25 module des.gl.base.render;
26 
27 import des.math.linear;
28 import des.gl.base;
29 import des.il;
30 
31 private template staticChoise(bool s,A,B)
32 {
33     static if(s)
34         alias A staticChoise;
35     else
36         alias B staticChoise;
37 }
38 
39 private template createNew(bool buffer)
40 {
41     auto fnc()
42     {
43         static if(buffer)
44             return new GLRenderBuffer;
45         else
46         {
47             auto tex = new GLTexture( GLTexture.Target.T2D );
48 
49             tex.setParameter( GLTexture.Parameter.WRAP_S, GLTexture.Wrap.CLAMP_TO_EDGE );
50             tex.setParameter( GLTexture.Parameter.WRAP_T, GLTexture.Wrap.CLAMP_TO_EDGE );
51             tex.setParameter( GLTexture.Parameter.MIN_FILTER, GLTexture.Filter.NEAREST );
52             tex.setParameter( GLTexture.Parameter.MAG_FILTER, GLTexture.Filter.NEAREST );
53 
54             return tex;
55         }
56     }
57 
58     alias createNew=fnc;
59 }
60 
61 /// Render to FBO
62 class GLRender(bool CB, bool DB) : DesObject
63 {
64     mixin DES;
65     mixin ClassLogger;
66 protected:
67 
68     GLFrameBuffer fbo;
69 
70 public:
71 
72     ///
73     alias staticChoise!(CB,GLRenderBuffer,GLTexture) ColorObject;
74     ///
75     alias staticChoise!(DB,GLRenderBuffer,GLTexture) DepthObject;
76 
77     ///
78     DepthObject depth;
79     ///
80     ColorObject color;
81 
82     ///
83     this()
84     {
85         depth = registerChildEMM( createDepth() );
86         color = registerChildEMM( createColor() );
87 
88         resize( uivec2(1,1) );
89 
90         fbo = newEMM!GLFrameBuffer;
91         fbo.setAttachment( depth, fbo.Attachment.DEPTH );
92         fbo.setAttachment( color, fbo.Attachment.COLOR0 );
93         fbo.unbind();
94 
95         debug logger.Debug( "FBO [%d], color [%s][%d], depth [%s][%d]",
96                 fbo.id, CB?"RB":"Tex", color.id, DB?"RB":"Tex", depth.id );
97     }
98 
99     /// render
100     void opCall( uivec2 sz, void delegate() draw_func )
101     in
102     {
103         assert( sz.x > 0 );
104         assert( sz.y > 0 );
105         assert( draw_func !is null );
106     }
107     body
108     {
109         int[4] vpbuf;
110 
111         resize( sz );
112         fbo.bind();
113         glGetIntegerv( GL_VIEWPORT, vpbuf.ptr );
114         glViewport( 0, 0, sz.x, sz.y );
115 
116         draw_func();
117 
118         fbo.unbind();
119         glViewport( vpbuf[0], vpbuf[1], vpbuf[2], vpbuf[3] );
120 
121         debug logger.trace( "FBO [%d], size [%d,%d]", fbo.id, sz[0], sz[1] );
122     }
123 
124 protected:
125 
126     DepthObject createDepth()
127     {
128         auto tmp = createNew!DB();
129         static if(DB) tmp.storage( ivec2(1,1), tmp.Format.DEPTH_COMPONENT32F );
130         else tmp.image( ivec2(1,1), tmp.InternalFormat.DEPTH_COMPONENT,
131                 tmp.Format.DEPTH, tmp.Type.FLOAT );
132         return tmp;
133     }
134 
135     ColorObject createColor()
136     {
137         auto tmp = createNew!CB();
138         static if(CB) tmp.storage( ivec2(1,1), tmp.Format.RGBA8 );
139         else tmp.image( ivec2(1,1), tmp.InternalFormat.RGBA,
140                 tmp.Format.RGBA, tmp.Type.FLOAT );
141         return tmp;
142     }
143 
144     void resize( uivec2 sz )
145     {
146         depth.resize( sz );
147         color.resize( sz );
148     }
149 
150     override void selfDestroy()
151     {
152         fbo.unbind();
153         static if(!DB) depth.unbind();
154         static if(!CB) color.unbind();
155     }
156 }
157 
158 ///
159 alias GLRender!(false,false) GLRenderToTex;
160 ///
161 alias GLRender!(true,true) GLRenderToRB;
162 ///
163 alias GLRender!(false,true) GLRenderColorToTexDepthToRB;
164 ///
165 alias GLRender!(true,false) GLRenderColorToRBDepthToTex;