Project

General

Profile

Download (12.9 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / DistortedFramebuffer.java @ c5369f1b

1 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.library;
21
22 194ab46f Leszek Koltunski
import android.opengl.GLES30;
23 f6fb3c6d Leszek Koltunski
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25 dedacd82 Leszek Koltunski
/**
26
 * Class which represents a OpenGL Framebuffer object.
27 71c3fecc Leszek Koltunski
 * <p>
28 c5369f1b leszek
 * User is able to create offscreen FBOs and both a) render to them b) use their COLOR0 attachment as
29
 * an input texture.
30 dedacd82 Leszek Koltunski
 */
31 c5369f1b leszek
public class DistortedFramebuffer extends DistortedRenderable implements DistortedInputSurface, DistortedOutputSurface
32 f6fb3c6d Leszek Koltunski
  {
33 133cbb2b Leszek Koltunski
  private int[] mDepthH = new int[1];
34
  private int[] mFBOH   = new int[1];
35 cdd5e827 Leszek Koltunski
  private boolean mDepthEnabled;
36 c5369f1b leszek
  private DistortedProjection mProjection;
37 bd3da5b2 Leszek Koltunski
38 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
39 6537ba91 Leszek Koltunski
// Must be called from a thread holding OpenGL Context
40 227ac49a Leszek Koltunski
// Watch out - this has the side-effect of binding a Texture and a Framebuffer!
41 f6fb3c6d Leszek Koltunski
42 c5369f1b leszek
  public void create()
43 f6fb3c6d Leszek Koltunski
    {
44 133cbb2b Leszek Koltunski
    if( mColorH[0]==NOT_CREATED_YET )
45 7cf783cb Leszek Koltunski
      {
46 133cbb2b Leszek Koltunski
      GLES30.glGenTextures(1, mColorH, 0);
47
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
48 194ab46f Leszek Koltunski
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
49
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
50
      GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
51
      GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
52 133cbb2b Leszek Koltunski
      GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mSizeX, mSizeY, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
53 194ab46f Leszek Koltunski
54 133cbb2b Leszek Koltunski
      GLES30.glGenFramebuffers(1, mFBOH, 0);
55
      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
56
      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[0], 0);
57 dedacd82 Leszek Koltunski
58 8337fa41 Leszek Koltunski
      checkStatus("color");
59 7cf783cb Leszek Koltunski
      }
60 133cbb2b Leszek Koltunski
    if( mDepthEnabled && mDepthH[0]==NOT_CREATED_YET ) // we need to create a new DEPTH attachment
61 8c327653 Leszek Koltunski
      {
62 133cbb2b Leszek Koltunski
      GLES30.glGenTextures(1, mDepthH, 0);
63
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mDepthH[0]);
64 194ab46f Leszek Koltunski
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
65
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
66
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
67
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST);
68 133cbb2b Leszek Koltunski
      GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH_COMPONENT, mSizeX, mSizeY, 0, GLES30.GL_DEPTH_COMPONENT, GLES30.GL_UNSIGNED_SHORT, null);
69 8c327653 Leszek Koltunski
70 133cbb2b Leszek Koltunski
      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
71
      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, mDepthH[0], 0);
72 8c327653 Leszek Koltunski
73 8337fa41 Leszek Koltunski
      checkStatus("depth");
74 8c327653 Leszek Koltunski
      }
75 133cbb2b Leszek Koltunski
    if( !mDepthEnabled && mDepthH[0]!=NOT_CREATED_YET ) // we need to detach and destroy the DEPTH attachment.
76 8c327653 Leszek Koltunski
      {
77 133cbb2b Leszek Koltunski
      GLES30.glDeleteTextures(1, mDepthH, 0);
78
      mDepthH[0]=NOT_CREATED_YET;
79 8c327653 Leszek Koltunski
      }
80 8337fa41 Leszek Koltunski
    }
81
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
84
  private boolean checkStatus(String message)
85
    {
86 194ab46f Leszek Koltunski
    int status = GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER);
87 8337fa41 Leszek Koltunski
88 194ab46f Leszek Koltunski
    if(status != GLES30.GL_FRAMEBUFFER_COMPLETE)
89 8337fa41 Leszek Koltunski
      {
90
      android.util.Log.e("DistortedFramebuffer", "FRAMEBUFFER INCOMPLETE, "+message+" error="+status);
91
92 133cbb2b Leszek Koltunski
      GLES30.glDeleteTextures(1, mColorH, 0);
93
      GLES30.glDeleteTextures(1, mDepthH, 0);
94
      GLES30.glDeleteFramebuffers(1, mFBOH, 0);
95
      mFBOH[0]   = 0;
96
      mColorH[0] = FAILED_TO_CREATE;
97
      mDepthH[0] = FAILED_TO_CREATE;
98 8337fa41 Leszek Koltunski
99
      return false;
100
      }
101 8c327653 Leszek Koltunski
102 f6fb3c6d Leszek Koltunski
    return true;
103
    }
104
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106 6537ba91 Leszek Koltunski
// Must be called from a thread holding OpenGL Context
107 f6fb3c6d Leszek Koltunski
108 227ac49a Leszek Koltunski
  void delete()
109 f6fb3c6d Leszek Koltunski
    {
110 133cbb2b Leszek Koltunski
    if( mColorH[0]>=0 )
111 e6cf7d50 Leszek Koltunski
      {
112 133cbb2b Leszek Koltunski
      if( mDepthH[0]>=0 )
113 8c327653 Leszek Koltunski
        {
114 133cbb2b Leszek Koltunski
        GLES30.glDeleteTextures(1, mDepthH, 0);
115
        mDepthH[0]=NOT_CREATED_YET;
116 8c327653 Leszek Koltunski
        }
117
118 133cbb2b Leszek Koltunski
      GLES30.glDeleteTextures(1, mColorH, 0);
119
      mColorH[0] = NOT_CREATED_YET;
120 bd3da5b2 Leszek Koltunski
121 133cbb2b Leszek Koltunski
      GLES30.glDeleteFramebuffers(1, mFBOH, 0);
122
      mFBOH[0] = 0;
123 e6cf7d50 Leszek Koltunski
      }
124 bd3da5b2 Leszek Koltunski
    }
125
126 4ebbb17a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
127
// called from onDestroy(); mark OpenGL assets as 'not created'
128
129
  void destroy()
130
    {
131
    if( mColorH[0]!=DONT_CREATE ) mColorH[0] = NOT_CREATED_YET;
132
    if( mDepthEnabled           ) mDepthH[0] = NOT_CREATED_YET;
133
    }
134
135 86eb00a9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
136
// if new size fits into the size of the underlying Texture, just change the projection without
137
// reallocating the Texture. Otherwise, we need to reallocate.
138
//
139
// Must be called form a thread holding the OpenGL context.
140
141
  void resizeFast(int width, int height)
142
    {
143 c5369f1b leszek
    if( mProjection.resize(width,height) )
144 86eb00a9 Leszek Koltunski
      {
145 c5369f1b leszek
      if( width> mSizeX || height> mSizeY)
146 86eb00a9 Leszek Koltunski
        {
147 c5369f1b leszek
        mSizeX = width;
148
        mSizeY = height;
149 133cbb2b Leszek Koltunski
        delete();
150 86eb00a9 Leszek Koltunski
        }
151
      }
152 cc0734e7 Leszek Koltunski
153 133cbb2b Leszek Koltunski
    create();
154 86eb00a9 Leszek Koltunski
    }
155
156 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
157
// PUBLIC API
158 dedacd82 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
159 cdd5e827 Leszek Koltunski
/**
160
 * Create a new offscreen Framebuffer.
161
 *
162
 * @param width Width of the COLOR attachment.
163
 * @param height Height of the COLOR attachment.
164
 * @param depthEnabled Add DEPTH attachment?
165
 */
166
  @SuppressWarnings("unused")
167
  public DistortedFramebuffer(int width, int height, boolean depthEnabled)
168
    {
169 2e49718d Leszek Koltunski
    super(width,height,NOT_CREATED_YET);
170
171 c5369f1b leszek
    mProjection  = new DistortedProjection(width,height);
172 cdd5e827 Leszek Koltunski
    mDepthEnabled= depthEnabled;
173 2e49718d Leszek Koltunski
    mFBOH[0]     = NOT_CREATED_YET;
174
    mDepthH[0]   = NOT_CREATED_YET;
175 cdd5e827 Leszek Koltunski
    }
176
177 133cbb2b Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
178
179 dedacd82 Leszek Koltunski
/**
180 57578636 Leszek Koltunski
 * Create a new offscreen Framebuffer.
181 dedacd82 Leszek Koltunski
 *
182
 * @param width Width of the COLOR attachment.
183
 * @param height Height of the COLOR attachment.
184
 */
185 1942537e Leszek Koltunski
  @SuppressWarnings("unused")
186 ed13a5de Leszek Koltunski
  public DistortedFramebuffer(int width, int height)
187 f6fb3c6d Leszek Koltunski
    {
188 2e49718d Leszek Koltunski
    super(width,height,NOT_CREATED_YET);
189
190 c5369f1b leszek
    mProjection  = new DistortedProjection(width,height);
191 cdd5e827 Leszek Koltunski
    mDepthEnabled= false;
192 2e49718d Leszek Koltunski
    mFBOH[0]     = NOT_CREATED_YET;
193
    mDepthH[0]   = NOT_CREATED_YET;
194 f6fb3c6d Leszek Koltunski
    }
195
196 b448e6b9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
197 dedacd82 Leszek Koltunski
/**
198 c5369f1b leszek
 * Bind the underlying rectangle of pixels as a OpenGL Texture.
199 dedacd82 Leszek Koltunski
 */
200 c5369f1b leszek
  public boolean setAsInput()
201 b448e6b9 Leszek Koltunski
    {
202 c5369f1b leszek
    if( mColorH[0]>0 )
203
      {
204
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
205
      return true;
206
      }
207
208
    return false;
209
    }
210 2e49718d Leszek Koltunski
211 c5369f1b leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
212
/**
213
 * Bind this Surface as a Framebuffer we can render to.
214
 */
215
  public void setAsOutput()
216
    {
217
    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
218 b448e6b9 Leszek Koltunski
219 c5369f1b leszek
    if( mDepthH[0]!=NOT_CREATED_YET )
220
      {
221
      GLES30.glEnable(GLES30.GL_DEPTH_TEST);
222
      GLES30.glDepthMask(true);
223
      }
224
    else
225
      {
226
      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
227
      GLES30.glDepthMask(false);
228
      }
229 8c327653 Leszek Koltunski
    }
230
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232
/**
233
 * Create a new DEPTH buffer and attach it or (param=false) detach an existing DEPTh attachment and destroy it.
234
 *
235 cdd5e827 Leszek Koltunski
 * @param enable <bold>true</bold> if we want to attach a new DEPTH buffer to the FBO.<br>
236
 *               <bold>false</bold> if we want to detach the DEPTH attachment.
237 8c327653 Leszek Koltunski
 */
238 cdd5e827 Leszek Koltunski
  public void enableDepthAttachment(boolean enable)
239 8c327653 Leszek Koltunski
    {
240 cdd5e827 Leszek Koltunski
    mDepthEnabled = enable;
241 b448e6b9 Leszek Koltunski
    }
242
243 a0f644b7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
244 8c327653 Leszek Koltunski
245 a0f644b7 Leszek Koltunski
/**
246 05403bba Leszek Koltunski
 * Draw the (texture,mesh,effects) object to the Framebuffer.
247 a0f644b7 Leszek Koltunski
 * <p>
248 d254d550 Leszek Koltunski
 * Must be called from a thread holding OpenGL Context.
249 a0f644b7 Leszek Koltunski
 *
250 c5369f1b leszek
 * @param surface InputSurface to skin our Mesh with.
251 05403bba Leszek Koltunski
 * @param mesh Class descendant from MeshObject
252 a0f644b7 Leszek Koltunski
 * @param effects The DistortedEffects to use when rendering
253
 * @param time Current time, in milliseconds.
254
 */
255 c5369f1b leszek
  public void renderTo(DistortedInputSurface surface, MeshObject mesh, DistortedEffects effects, long time)
256 a0f644b7 Leszek Koltunski
    {
257 c5369f1b leszek
    surface.create();  // Watch out  - this needs to be before
258
    create();          // the 'setAsInput' because this has side-effects!
259 133cbb2b Leszek Koltunski
260 c5369f1b leszek
    if( surface.setAsInput() )
261 133cbb2b Leszek Koltunski
      {
262 2e49718d Leszek Koltunski
      DistortedRenderable.deleteAllMarked();
263 c5369f1b leszek
      effects.drawPriv(surface.getWidth()/2.0f, surface.getHeight()/2.0f, mesh, this, time);
264 52358355 Leszek Koltunski
      }
265
    }
266
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268 a0f644b7 Leszek Koltunski
/**
269
 * Draws the Tree, and all its children, to the Framebuffer.
270
 * <p>
271 d254d550 Leszek Koltunski
 * Must be called from a thread holding OpenGL Context.
272 a0f644b7 Leszek Koltunski
 *
273
 * @param dt DistortedTree to render.
274
 * @param time Current time, in milliseconds. This will be passed to all the Effects stored in the Tree.
275
 */
276
  public void renderTo(DistortedTree dt, long time)
277
    {
278 2e49718d Leszek Koltunski
    DistortedRenderable.deleteAllMarked();
279 133cbb2b Leszek Koltunski
    create();
280 a0f644b7 Leszek Koltunski
    dt.drawRecursive(time,this);
281
    }
282
283 f6fb3c6d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
284 dedacd82 Leszek Koltunski
/**
285
 * Create new Projection matrix.
286
 *
287
 * @param fov Vertical 'field of view' of the Projection frustrum (in degrees).
288 46a52b78 Leszek Koltunski
 * @param x X-coordinate of the point at which our camera looks at. 0 is the center.
289
 * @param y Y-coordinate of the point at which our camera looks at. 0 is the center.
290 dedacd82 Leszek Koltunski
 */
291
  public void setProjection(float fov, float x, float y)
292 f6fb3c6d Leszek Koltunski
    {
293 c5369f1b leszek
    mProjection.set(fov,x,y);
294
    mProjection.createProjection();
295 f6fb3c6d Leszek Koltunski
    }
296
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298 dedacd82 Leszek Koltunski
/**
299
 * Resize the underlying Framebuffer.
300
 *
301
 * @param width The new width.
302
 * @param height The new height.
303
 */
304 f6fb3c6d Leszek Koltunski
  public void resize(int width, int height)
305
    {
306 c5369f1b leszek
    if( mProjection.resize(width,height) )
307 bd3da5b2 Leszek Koltunski
      {
308 133cbb2b Leszek Koltunski
      mSizeX = width;
309
      mSizeY = height;
310
      if( mColorH[0]>0 ) markForDeletion();
311 bd3da5b2 Leszek Koltunski
      }
312 f6fb3c6d Leszek Koltunski
    }
313 d1e740c5 Leszek Koltunski
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315
/**
316 09d4f4b1 Leszek Koltunski
 * Return the ID of the Texture (COLOR attachment 0) that's backing this FBO.
317
 * <p>
318
 * Catch: this will only work if the library has had time to actually create the texture. Remember
319
 * that the texture gets created only on first render, thus creating a Texture object and immediately
320
 * calling this method will return an invalid (negative) result.
321
 *
322 ab12f06b Leszek Koltunski
 * @return If there was not a single render between creation of the Object and calling this method on
323
 *         it, return a negative value. Otherwise, return ID of COLOR attachment 0.
324 d1e740c5 Leszek Koltunski
 */
325 09d4f4b1 Leszek Koltunski
  public int getTextureID()
326 d1e740c5 Leszek Koltunski
    {
327 133cbb2b Leszek Koltunski
    return mColorH[0];
328 8c327653 Leszek Koltunski
    }
329
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331
/**
332
 * Return true if the FBO contains a DEPTH attachment.
333
 *
334
 * @return <bold>true</bold> if the FBO contains a DEPTH attachment.
335
 */
336
  public boolean hasDepth()
337
    {
338 cdd5e827 Leszek Koltunski
    return mDepthEnabled;
339 d1e740c5 Leszek Koltunski
    }
340 c5369f1b leszek
341
//////////////////////////////////////////////////////////////////////////////////////////////////
342
/**
343
 * Return Projection stored in this Framebuffer.
344
 *
345
 * @return DistortedProjection object.
346
 */
347
  public DistortedProjection getProjection()
348
    {
349
    return mProjection;
350
    }
351 f6fb3c6d Leszek Koltunski
  }