1 module prova.graphics.rendertarget;
2
3 import prova.graphics,
4 prova.math,
5 std.typecons;
6
7 ///
8 class RenderTarget
9 {
10 static ShaderProgram flatShaderProgram;
11 private static uint currentFrameBuffer = -1;
12
13 ///
14 SpriteBatch spriteBatch;
15 ///
16 protected Matrix projection;
17
18 private uint renderBufferId;
19 private uint _frameBufferId;
20 private Texture _texture;
21 private int _width;
22 private int _height;
23 private bool begun;
24
25 ///
26 this(int width, int height)
27 {
28 if(!flatShaderProgram)
29 flatShaderProgram = new FlatShaderProgram();
30
31 spriteBatch = new SpriteBatch();
32 _texture = new Texture(width, height);
33 _width = width;
34 _height = height;
35
36 createFrameBuffer();
37 createRenderBuffer();
38 }
39
40 private void createFrameBuffer()
41 {
42 glGenFramebuffers(1, &_frameBufferId);
43 bindFrameBuffer();
44
45 // attach texture to the frame buffer
46 glFramebufferTexture2D(
47 GL_FRAMEBUFFER,
48 GL_COLOR_ATTACHMENT0,
49 GL_TEXTURE_2D,
50 _texture.id,
51 0
52 );
53
54 glDepthFunc(GL_LEQUAL);
55 glEnable(GL_BLEND);
56 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
57 glViewport(0, 0, width, height);
58 }
59
60 private void createRenderBuffer()
61 {
62 glGenRenderbuffers(1, &renderBufferId);
63 glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
64 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
65
66 bindFrameBuffer();
67
68 glFramebufferRenderbuffer(
69 GL_FRAMEBUFFER,
70 GL_DEPTH_ATTACHMENT,
71 GL_RENDERBUFFER,
72 renderBufferId
73 );
74 }
75
76 ///
77 void resize(int width, int height)
78 {
79 _width = width;
80 _height = height;
81
82 texture.recreate(null, width, height);
83
84 glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
85 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
86
87 // update settings
88 glViewport(0, 0, width, height);
89 }
90
91 ///
92 @property int width()
93 {
94 return _width;
95 }
96
97 ///
98 @property int height()
99 {
100 return _height;
101 }
102
103 ///
104 @property Texture texture()
105 {
106 return _texture;
107 }
108
109 ///
110 @property uint frameBufferId()
111 {
112 return _frameBufferId;
113 }
114
115 package(prova) void bindFrameBuffer()
116 {
117 bindFrameBuffer(_frameBufferId);
118 }
119
120 /// Updates projection and prepares batches
121 void begin(Matrix projection)
122 {
123 if(begun)
124 throw new Exception("RenderTarget already started");
125
126 spriteBatch.begin(this, projection);
127
128 this.projection = projection;
129 begun = true;
130 }
131
132 /// Finishes the batch
133 void end()
134 {
135 if(!begun)
136 throw new Exception("RenderTarget not ready, call begin(Matrix projection)");
137
138 spriteBatch.end();
139 begun = false;
140 }
141
142 /// Draws mesh using a flat shader
143 void drawMesh(Mesh mesh, Matrix transform, DrawMode mode, Color color)
144 {
145 if(!begun)
146 throw new Exception("RenderTarget not ready, call begin(Matrix projection)");
147
148 flatShaderProgram.setMatrix("transform", projection * transform);
149 flatShaderProgram.setVector4("color", color);
150 flatShaderProgram.drawMesh(mesh, this, mode);
151 }
152
153 ///
154 void drawSprite(Sprite sprite, Matrix transform)
155 {
156 spriteBatch.batchSprite(sprite, transform);
157 }
158
159 ///
160 void drawSprite(AnimatedSprite sprite, Matrix transform)
161 {
162 spriteBatch.batchSprite(sprite, transform);
163 }
164
165 ///
166 void clear()
167 {
168 bindFrameBuffer();
169
170 glClearDepth(1);
171 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
172 }
173
174 package(prova) static void bindFrameBuffer(uint id)
175 {
176 if(id == currentFrameBuffer)
177 return;
178
179 glBindFramebuffer(GL_FRAMEBUFFER, id);
180 currentFrameBuffer = id;
181 }
182
183 ~this()
184 {
185 glDeleteFramebuffers(1, &_frameBufferId);
186 glDeleteRenderbuffers(1, &renderBufferId);
187 }
188 }