Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
import android.opengl.GLES30;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25
/**
26
 * Class which represents a OpenGL Framebuffer object.
27
 * <p>
28
 * User is able to create offscreen FBOs and both a) render to them b) use their COLOR0 attachment as
29
 * an input texture.
30
 */
31
public class DistortedFramebuffer extends DistortedOutputSurface implements DistortedInputSurface
32
  {
33
  private int[] mDepthH = new int[1];
34
  private int[] mFBOH   = new int[1];
35
  private boolean mDepthEnabled;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38
// Must be called from a thread holding OpenGL Context
39
// Watch out - this has the side-effect of binding a Texture and a Framebuffer!
40

    
41
  public void create()
42
    {
43
    if( mColorH[0]==NOT_CREATED_YET )
44
      {
45
      GLES30.glGenTextures(1, mColorH, 0);
46
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
47
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
48
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
49
      GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
50
      GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
51
      GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mSizeX, mSizeY, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
52

    
53
      GLES30.glGenFramebuffers(1, mFBOH, 0);
54
      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
55
      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[0], 0);
56

    
57
      checkStatus("color");
58
      }
59
    if( mDepthEnabled && mDepthH[0]==NOT_CREATED_YET ) // we need to create a new DEPTH attachment
60
      {
61
      GLES30.glGenTextures(1, mDepthH, 0);
62
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mDepthH[0]);
63
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
64
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
65
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
66
      GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST);
67
      GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH_COMPONENT, mSizeX, mSizeY, 0, GLES30.GL_DEPTH_COMPONENT, GLES30.GL_UNSIGNED_SHORT, null);
68

    
69
      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
70
      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, mDepthH[0], 0);
71

    
72
      checkStatus("depth");
73
      }
74
    if( !mDepthEnabled && mDepthH[0]!=NOT_CREATED_YET ) // we need to detach and destroy the DEPTH attachment.
75
      {
76
      GLES30.glDeleteTextures(1, mDepthH, 0);
77
      mDepthH[0]=NOT_CREATED_YET;
78
      }
79
    }
80

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

    
83
  private boolean checkStatus(String message)
84
    {
85
    int status = GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER);
86

    
87
    if(status != GLES30.GL_FRAMEBUFFER_COMPLETE)
88
      {
89
      android.util.Log.e("DistortedFramebuffer", "FRAMEBUFFER INCOMPLETE, "+message+" error="+status);
90

    
91
      GLES30.glDeleteTextures(1, mColorH, 0);
92
      GLES30.glDeleteTextures(1, mDepthH, 0);
93
      GLES30.glDeleteFramebuffers(1, mFBOH, 0);
94
      mFBOH[0]   = 0;
95
      mColorH[0] = FAILED_TO_CREATE;
96
      mDepthH[0] = FAILED_TO_CREATE;
97

    
98
      return false;
99
      }
100

    
101
    return true;
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105
// Must be called from a thread holding OpenGL Context
106

    
107
  void delete()
108
    {
109
    if( mColorH[0]>=0 )
110
      {
111
      if( mDepthH[0]>=0 )
112
        {
113
        GLES30.glDeleteTextures(1, mDepthH, 0);
114
        mDepthH[0]=NOT_CREATED_YET;
115
        }
116

    
117
      GLES30.glDeleteTextures(1, mColorH, 0);
118
      mColorH[0] = NOT_CREATED_YET;
119

    
120
      GLES30.glDeleteFramebuffers(1, mFBOH, 0);
121
      mFBOH[0] = 0;
122
      }
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126
// called from onDestroy(); mark OpenGL assets as 'not created'
127

    
128
  void destroy()
129
    {
130
    if( mColorH[0]!=DONT_CREATE ) mColorH[0] = NOT_CREATED_YET;
131
    if( mDepthEnabled           ) mDepthH[0] = NOT_CREATED_YET;
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135
// if new size fits into the size of the underlying Texture, just change the projection without
136
// reallocating the Texture. Otherwise, we need to reallocate.
137
//
138
// Must be called from a thread holding the OpenGL context.
139

    
140
  void resizeFast(int width, int height)
141
    {
142
    if( mWidth!=width || mHeight!=height )
143
      {
144
      mWidth = width;
145
      mHeight= height;
146
      createProjection();
147

    
148
      if( width> mSizeX || height> mSizeY)
149
        {
150
        mSizeX = width;
151
        mSizeY = height;
152
        delete();
153
        }
154
      }
155

    
156
    create();
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160
// PUBLIC API
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162
/**
163
 * Create a new offscreen Framebuffer.
164
 *
165
 * @param width Width of the COLOR attachment.
166
 * @param height Height of the COLOR attachment.
167
 * @param depthEnabled Add DEPTH attachment?
168
 */
169
  @SuppressWarnings("unused")
170
  public DistortedFramebuffer(int width, int height, boolean depthEnabled)
171
    {
172
    super(width,height,NOT_CREATED_YET);
173
    mDepthEnabled= depthEnabled;
174
    mFBOH[0]     = NOT_CREATED_YET;
175
    mDepthH[0]   = NOT_CREATED_YET;
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
/**
181
 * Create a new offscreen Framebuffer.
182
 *
183
 * @param width Width of the COLOR attachment.
184
 * @param height Height of the COLOR attachment.
185
 */
186
  @SuppressWarnings("unused")
187
  public DistortedFramebuffer(int width, int height)
188
    {
189
    super(width,height,NOT_CREATED_YET);
190
    mDepthEnabled= false;
191
    mFBOH[0]     = NOT_CREATED_YET;
192
    mDepthH[0]   = NOT_CREATED_YET;
193
    }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196
/**
197
 * Bind the underlying rectangle of pixels as a OpenGL Texture.
198
 *
199
 * @returns <code>true</code> if successful.
200
 */
201
  public boolean setAsInput()
202
    {
203
    if( mColorH[0]>0 )
204
      {
205
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
206
      return true;
207
      }
208

    
209
    return false;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213
/**
214
 * Bind this Surface as a Framebuffer we can render to.
215
 */
216
  public void setAsOutput()
217
    {
218
    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
219

    
220
    if( mDepthH[0]!=NOT_CREATED_YET )
221
      {
222
      GLES30.glEnable(GLES30.GL_DEPTH_TEST);
223
      GLES30.glDepthMask(true);
224
      }
225
    else
226
      {
227
      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
228
      GLES30.glDepthMask(false);
229
      }
230
    }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233
/**
234
 * Create a new DEPTH buffer and attach it or (param=false) detach an existing DEPTh attachment and destroy it.
235
 *
236
 * @param enable <bold>true</bold> if we want to attach a new DEPTH buffer to the FBO.<br>
237
 *               <bold>false</bold> if we want to detach the DEPTH attachment.
238
 */
239
  public void enableDepthAttachment(boolean enable)
240
    {
241
    mDepthEnabled = enable;
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
/**
246
 * Return the ID of the Texture (COLOR attachment 0) that's backing this FBO.
247
 * <p>
248
 * Catch: this will only work if the library has had time to actually create the texture. Remember
249
 * that the texture gets created only on first render, thus creating a Texture object and immediately
250
 * calling this method will return an invalid (negative) result.
251
 *
252
 * @return If there was not a single render between creation of the Object and calling this method on
253
 *         it, return a negative value. Otherwise, return ID of COLOR attachment 0.
254
 */
255
  public int getTextureID()
256
    {
257
    return mColorH[0];
258
    }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261
/**
262
 * Return true if the FBO contains a DEPTH attachment.
263
 *
264
 * @return <bold>true</bold> if the FBO contains a DEPTH attachment.
265
 */
266
  public boolean hasDepth()
267
    {
268
    return mDepthEnabled;
269
    }
270
  }
(3-3/20)