Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedOutputSurface.java @ 63b6561a

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
import android.opengl.Matrix;
24
import java.util.ArrayList;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27

    
28
abstract class DistortedOutputSurface extends DistortedSurface implements DistortedAttacheable
29
{
30
  private ArrayList<DistortedNode> mChildren;
31
  private int mNumChildren;   // ==mChildren.length(), but we only create mChildren if the first one gets added
32

    
33
  private float mX, mY, mFOV;
34
  int mWidth,mHeight,mDepth;
35
  float mDistance;
36
  float[] mProjectionMatrix;
37

    
38
  boolean mDepthEnabled;
39
  int[] mDepthH = new int[1];
40
  int[] mFBOH   = new int[1];
41

    
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

    
44
  DistortedOutputSurface(int width, int height, int color, int fbo, boolean system, boolean depth)
45
    {
46
    super(width,height,color,system);
47

    
48
    mProjectionMatrix = new float[16];
49

    
50
    mWidth = width;
51
    mHeight= height;
52

    
53
    mFOV = 60.0f;
54
    mX   =  0.0f;
55
    mY   =  0.0f;
56

    
57
    mDepthEnabled= depth;
58
    mFBOH[0]     = fbo;
59
    mDepthH[0]   = color;
60

    
61
    createProjection();
62
    }
63

    
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

    
66
  void createProjection()
67
    {
68
    if( mWidth>0 && mHeight>1 )
69
      {
70
      if( mFOV>0.0f )  // perspective projection
71
        {
72
        float left   = (-mX-mWidth /2.0f)/mHeight;
73
        float right  = (-mX+mWidth /2.0f)/mHeight;
74
        float bottom = (-mY-mHeight/2.0f)/mHeight;
75
        float top    = (-mY+mHeight/2.0f)/mHeight;
76
        float near   = (top-bottom) / (2.0f*(float)Math.tan(mFOV*Math.PI/360));
77
        mDistance    = mHeight*near/(top-bottom);
78
        float far    = 2*mDistance-near;
79
        mDepth       = (int)((far-near)/2);
80

    
81
        Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
82
        }
83
      else             // parallel projection
84
        {
85
        float left   = -mX-mWidth /2.0f;
86
        float right  = -mX+mWidth /2.0f;
87
        float bottom = -mY-mHeight/2.0f;
88
        float top    = -mY+mHeight/2.0f;
89
        float near   = (mWidth+mHeight)/2;
90
        mDistance    = 2*near;
91
        float far    = 3*near;
92
        mDepth       = (int)near;
93

    
94
        Matrix.orthoM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
95
        }
96
      }
97
    }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100
// PUBLIC API
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102
/**
103
 * Draws all the attached children to this OutputSurface.
104
 * <p>
105
 * Must be called from a thread holding OpenGL Context.
106
 *
107
 * @param time Current time, in milliseconds. This will be passed to all the Effects stored in the children Nodes.
108
 */
109
  public void render(long time)
110
    {
111
    // change tree topology (attach and detach children)
112
    // create and delete all underlying OpenGL resources
113
    // Watch out: FIRST change topology, only then deal
114
    // with OpenGL resources. That's because changing Tree
115
    // can result in additional Framebuffers that would need
116
    // to be created immediately, before the calls to drawRecursive()
117

    
118
    boolean changed = DistortedAttachDaemon.toDo();
119

    
120
    if( changed )
121
      {
122
      for(int i=0; i<mNumChildren; i++)
123
        {
124
        mChildren.get(i).treeIsomorphism();
125
        mChildren.get(i).debug(0);
126
        }
127

    
128
      //DistortedNode.debugMap();
129
      }
130

    
131
    toDo();
132

    
133
    if( changed )
134
      {
135
      DistortedSurface.debugLists();
136
      }
137

    
138
    for(int i=0; i<mNumChildren; i++)
139
      {
140
      mChildren.get(i).drawRecursive(time,this);
141
      }
142
    }
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145
/**
146
 * Bind this Surface as a Framebuffer we can render to.
147
 */
148
  public void setAsOutput()
149
    {
150
    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[0]);
151

    
152
    if( mDepthEnabled && mDepthH[0]!=NOT_CREATED_YET )
153
      {
154
      GLES30.glEnable(GLES30.GL_DEPTH_TEST);
155
      GLES30.glDepthMask(true);
156
      }
157
    else
158
      {
159
      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
160
      GLES30.glDepthMask(false);
161
      }
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165
/**
166
 * Create new Projection matrix.
167
 *
168
 * @param fov Vertical 'field of view' of the Projection frustrum (in degrees).
169
 * @param x X-coordinate of the point at which our camera looks at. 0 is the center.
170
 * @param y Y-coordinate of the point at which our camera looks at. 0 is the center.
171
 */
172
  public void setProjection(float fov, float x, float y)
173
    {
174
    mFOV = fov;
175
    mX = x;
176
    mY = y;
177

    
178
    createProjection();
179
    }
180

    
181
///////////////////////////////////////////////////////////////////////////////////////////////////
182
/**
183
 * Resize the underlying Framebuffer.
184
 *
185
 * @param width The new width.
186
 * @param height The new height.
187
 */
188
  public void resize(int width, int height)
189
    {
190
    if( mWidth!=width || mHeight!=height )
191
      {
192
      mWidth = width;
193
      mHeight= height;
194
      mSizeX = width;
195
      mSizeY = height;
196

    
197
      createProjection();
198

    
199
      if( mColorH[0]>0 )
200
        {
201
        moveToToDo();
202
        recreate();
203
        }
204
      }
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208
/**
209
 * Create a new DEPTH buffer and attach it or (param=false) detach an existing DEPTH attachment and recreate it.
210
 *
211
 * @param enable <bold>true</bold> if we want to attach a new DEPTH buffer to the FBO.<br>
212
 *               <bold>false</bold> if we want to detach the DEPTH attachment.
213
 */
214
  public void enableDepth(boolean enable)
215
    {
216
    if( mDepthEnabled!=enable )
217
      {
218
      mDepthEnabled = enable;
219
      moveToToDo();
220
      }
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224
/**
225
 * Return true if the Surface contains a DEPTH attachment.
226
 *
227
 * @return <bold>true</bold> if the FBO contains a DEPTH attachment.
228
 */
229
  public boolean hasDepth()
230
    {
231
    return mDepthEnabled;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235
/**
236
 * Adds a new child to the last position in the list of our Surface's children.
237
 * <p>
238
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
239
 * DistortedAttachDeamon (by calling attachNow())
240
 *
241
 * @param node The new Node to add.
242
 */
243
  public void attach(DistortedNode node)
244
    {
245
    DistortedAttachDaemon.attach(this,node);
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
/**
250
 * Adds a new child to the last position in the list of our Surface's children.
251
 * <p>
252
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
253
 * DistortedAttachDeamon (by calling attachNow())
254
 *
255
 * @param surface InputSurface to initialize our child Node with.
256
 * @param effects DistortedEffects to initialize our child Node with.
257
 * @param mesh MeshObject to initialize our child Node with.
258
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
259
 */
260
  public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
261
    {
262
    DistortedNode node = new DistortedNode(surface,effects,mesh);
263
    DistortedAttachDaemon.attach(this,node);
264
    return node;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268
/**
269
 * This is not really part of the public API. Has to be public only because it is a part of the
270
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
271
 * Java has no multiple inheritance.
272
 *
273
 * @param node new Node to add.
274
 */
275
  public void attachNow(DistortedNode node)
276
    {
277
    if( mChildren==null ) mChildren = new ArrayList<>(2);
278
    mChildren.add(node);
279
    mNumChildren++;
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283
/**
284
 * Removes the first occurrence of a specified child from the list of children of our Surface.
285
 * <p>
286
 * A bit questionable method as there can be many different Nodes attached as children, some
287
 * of them having the same Effects but - for instance - different Mesh. Use with care.
288
 * <p>
289
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
290
 * DistortedAttachDeamon (by calling detachNow())
291
 *
292
 * @param effects DistortedEffects to remove.
293
 */
294
  public void detach(DistortedEffects effects)
295
    {
296
    long id = effects.getID();
297
    DistortedNode node;
298

    
299
    for(int i=0; i<mNumChildren; i++)
300
      {
301
      node = mChildren.get(i);
302

    
303
      if( node.getEffects().getID()==id )
304
        {
305
        DistortedAttachDaemon.detach(this,node);
306
        break;
307
        }
308
      }
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312
/**
313
 * Removes the first occurrence of a specified child from the list of children of our Surface.
314
 * <p>
315
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
316
 * DistortedAttachDeamon (by calling detachNow())
317
 *
318
 * @param node The Node to remove.
319
 */
320
  public void detach(DistortedNode node)
321
    {
322
    DistortedAttachDaemon.detach(this,node);
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326
/**
327
 * This is not really part of the public API. Has to be public only because it is a part of the
328
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
329
 * Java has no multiple inheritance.
330
 *
331
 * @param node The Node to remove.
332
 */
333
  public void detachNow(DistortedNode node)
334
    {
335
    if( mNumChildren>0 && mChildren.remove(node) )
336
      {
337
      mNumChildren--;
338
      }
339
    }
340

    
341
///////////////////////////////////////////////////////////////////////////////////////////////////
342
/**
343
 * Removes all children Nodes.
344
 * <p>
345
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
346
 * DistortedAttachDeamon (by calling detachAllNow())
347
 */
348
  public void detachAll()
349
    {
350
    DistortedAttachDaemon.detachAll(this);
351
    }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354
/**
355
 * This is not really part of the public API. Has to be public only because it is a part of the
356
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
357
 * Java has no multiple inheritance.
358
 */
359
  public void detachAllNow()
360
    {
361
    if( mNumChildren>0 )
362
      {
363
      mNumChildren = 0;
364
      mChildren.clear();
365
      }
366
    }
367
}
(8-8/22)