Project

General

Profile

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

library / src / main / java / org / distorted / library / main / DistortedNode.java @ 8bfefd68

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.main;
21

    
22
import android.opengl.GLES31;
23

    
24
import org.distorted.library.mesh.MeshBase;
25

    
26
import java.util.ArrayList;
27
import java.util.Collections;
28

    
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30
/**
31
 * Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets.
32
 * <p>
33
 * Having organized such sets into a Tree, we can then render any Node to any OutputSurface.
34
 * That recursively renders the set held in the Node and all its children.
35
 * <p>
36
 * The class takes special care to only render identical sub-trees once. Each Node holds a reference
37
 * to sub-class 'NodeData'. Two identical sub-trees attached at different points of the main tree
38
 * will point to the same NodeData; only the first of this is rendered (mData.numRender!).
39
 */
40
public class DistortedNode implements DistortedMaster.Slave
41
  {
42
  private static final int ATTACH = 0;
43
  private static final int DETACH = 1;
44
  private static final int DETALL = 2;
45
  private static final int SORT   = 3;
46

    
47
  private class Job
48
    {
49
    int type;
50
    DistortedNode node;
51

    
52
    Job(int t, DistortedNode n)
53
      {
54
      type = t;
55
      node = n;
56
      }
57
    }
58

    
59
  private ArrayList<Job> mJobs = new ArrayList<>();
60

    
61
  private ArrayList<DistortedNode> mChildren;
62
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
63

    
64
  private boolean mRenderWayOIT;
65
  private DistortedNode mParent;
66
  private DistortedOutputSurface mSurfaceParent;
67
  private MeshBase mMesh;
68
  private DistortedEffects mEffects;
69
  private DistortedSurface mSurface;
70
  private DistortedRenderState mState;
71
  private DistortedNodeData mData;
72
  private int mFboW, mFboH, mFboDepthStencil;
73

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

    
76
  public void markForDeletion()
77
    {
78
    if( mData.removeData() )
79
      {
80
      mData.mFBO.markForDeletion();
81
      mData.mFBO = null;
82
      }
83

    
84
    mEffects.removeNode(this);
85
    }
86

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
  private ArrayList<Long> generateIDList()
90
    {
91
    ArrayList<Long> ret = new ArrayList<>();
92

    
93
    if( mNumChildren[0]==0 )
94
      {
95
      // add a negative number so this leaf never gets confused with a internal node
96
      // with a single child that happens to have ID identical to some leaf's Effects ID.
97
      ret.add(-mEffects.getID());
98
      }
99
    else
100
      {
101
      DistortedNode node;
102
   
103
      for(int i=0; i<mNumChildren[0]; i++)
104
        {
105
        node = mChildren.get(i);
106
        ret.add(node.mData.ID);
107
        }
108

    
109
      // A bit questionable decision here - we are sorting the children IDs, which means
110
      // that order in which we draw the children is going to be undefined (well, this is not
111
      // strictly speaking true - when rendering, if no postprocessing and isomorphism are
112
      // involved, we *DO* render the children in order they were added; if however there
113
      // are two internal nodes with the same list of identical children, just added in a
114
      // different order each time, then we consider them isomorphic, i.e. identical and only
115
      // render the first one. If then two children of such 'pseudo-isomorphic' nodes are at
116
      // exactly the same Z-height this might result in some unexpected sights).
117
      //
118
      // Reason: with the children being sorted by postprocessing buckets, the order is
119
      // undefined anyway (although only when postprocessing is applied).
120
      //
121
      // See the consequences in the 'Olympic' app - remove a few leaves and add them back in
122
      // different order. You will see the number of renders go back to the original 15.
123
      Collections.sort(ret);
124
      }
125

    
126
    ret.add( 0, mSurface.getID() );
127

    
128
    return ret;
129
    }
130

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132
// tree isomorphism algorithm
133

    
134
  private void adjustIsomorphism()
135
    {
136
    DistortedNodeData newData = DistortedNodeData.returnData(generateIDList());
137
    boolean deleteOldFBO = mData.removeData();
138
    boolean createNewFBO = (mNumChildren[0]>0 && newData.mFBO==null);
139

    
140
    if( deleteOldFBO && createNewFBO )
141
      {
142
      newData.mFBO = mData.mFBO;
143
      }
144
    else if( deleteOldFBO )
145
      {
146
      mData.mFBO.markForDeletion();
147
      mData.mFBO = null;
148
      }
149
    else if( createNewFBO )
150
      {
151
      int width  = mFboW <= 0 ? mSurface.getWidth()  : mFboW;
152
      int height = mFboH <= 0 ? mSurface.getHeight() : mFboH;
153
      newData.mFBO = new DistortedFramebuffer(1,mFboDepthStencil, DistortedSurface.TYPE_TREE, width, height);
154
      }
155

    
156
    mData = newData;
157

    
158
    if( mParent!=null ) mParent.adjustIsomorphism();
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162
// return the total number of render calls issued
163

    
164
  int drawNoBlend(long currTime, DistortedOutputSurface surface)
165
    {
166
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
167

    
168
    if( input.setAsInput() )
169
      {
170
      mState.apply();
171
      GLES31.glDisable(GLES31.GL_BLEND);
172
      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
173
      GLES31.glEnable(GLES31.GL_BLEND);
174
      return 1;
175
      }
176

    
177
    return 0;
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181
// Use the Order Independent Transparency method to draw a non-postprocessed child.
182

    
183
  int drawOIT(long currTime, DistortedOutputSurface surface)
184
    {
185
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
186

    
187
    if( input.setAsInput() )
188
      {
189
      mState.apply();
190
      mEffects.drawPrivOIT(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
191
      return 1;
192
      }
193

    
194
    return 0;
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198
// return the total number of render calls issued
199

    
200
  int draw(long currTime, DistortedOutputSurface surface)
201
    {
202
    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
203

    
204
    if( input.setAsInput() )
205
      {
206
      mState.apply();
207
      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
208
      return 1;
209
      }
210

    
211
    return 0;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215
// return the total number of render calls issued
216

    
217
  int renderRecursive(long currTime)
218
    {
219
    int numRenders = 0;
220

    
221
    if( mNumChildren[0]>0 && mData.notRenderedYetAtThisTime(currTime) )
222
      {
223
      for (int i=0; i<mNumChildren[0]; i++)
224
        {
225
        numRenders += mChildren.get(i).renderRecursive(currTime);
226
        }
227

    
228
      if( mData.mFBO==null )
229
        {
230
        int width  = mFboW <= 0 ? mSurface.getWidth()  : mFboW;
231
        int height = mFboH <= 0 ? mSurface.getHeight() : mFboH;
232
        mData.mFBO = new DistortedFramebuffer(1,mFboDepthStencil, DistortedSurface.TYPE_TREE, width, height);
233
        }
234

    
235
      mData.mFBO.setAsOutput(currTime);
236

    
237
      if( mSurface.setAsInput() )
238
        {
239
        numRenders++;
240
        DistortedEffects.blitPriv(mData.mFBO);
241
        }
242

    
243
      numRenders += mData.mFBO.renderChildren(currTime,mNumChildren[0],mChildren,0, mRenderWayOIT);
244
      }
245

    
246
    return numRenders;
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

    
251
  void setSurfaceParent(DistortedOutputSurface dep)
252
    {
253
    mSurfaceParent = dep;
254
    mParent = null;
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  void sort()
260
    {
261
    if( mParent!=null )
262
      {
263
      mParent.mChildren.remove(this);
264
      DistortedMaster.addSortingByBuckets(mParent.mChildren,this);
265
      }
266
    else if( mSurfaceParent!=null )
267
      {
268
      ArrayList<DistortedNode> children = mSurfaceParent.getChildren();
269
      children.remove(this);
270
      DistortedMaster.addSortingByBuckets(children,this);
271
      }
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  EffectQueuePostprocess getPostprocessQueue()
277
    {
278
    return mEffects.getPostprocess();
279
    }
280

    
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282
// PUBLIC API
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284
/**
285
 * Constructs new Node.
286
 *     
287
 * @param surface InputSurface to put into the new Node.
288
 * @param effects DistortedEffects to put into the new Node.
289
 * @param mesh MeshBase to put into the new Node.
290
 */
291
  public DistortedNode(DistortedSurface surface, DistortedEffects effects, MeshBase mesh)
292
    {
293
    mSurface       = surface;
294
    mEffects       = effects;
295
    mMesh          = mesh;
296
    mState         = new DistortedRenderState();
297
    mChildren      = null;
298
    mNumChildren   = new int[1];
299
    mParent        = null;
300
    mSurfaceParent = null;
301
    mRenderWayOIT  = false;
302

    
303
    mFboW            = 0;  // i.e. take this from
304
    mFboH            = 0;  // mSurface's dimensions
305
    mFboDepthStencil = DistortedFramebuffer.DEPTH_NO_STENCIL;
306

    
307
    mData = DistortedNodeData.returnData(generateIDList());
308
    mEffects.newNode(this);
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////  
312
/**
313
 * Copy-constructs new Node from another Node.
314
 *     
315
 * @param node The DistortedNode to copy data from.
316
 * @param flags bit field composed of a subset of the following:
317
 *        {@link Distorted#CLONE_SURFACE},  {@link Distorted#CLONE_MATRIX}, {@link Distorted#CLONE_VERTEX},
318
 *        {@link Distorted#CLONE_FRAGMENT} and {@link Distorted#CLONE_CHILDREN}.
319
 *        For example flags = CLONE_SURFACE | CLONE_CHILDREN.
320
 */
321
  public DistortedNode(DistortedNode node, int flags)
322
    {
323
    mEffects      = new DistortedEffects(node.mEffects,flags);
324
    mMesh         = node.mMesh;
325
    mState        = new DistortedRenderState();
326
    mParent       = null;
327
    mSurfaceParent= null;
328
    mRenderWayOIT = false;
329

    
330
    mFboW            = node.mFboW;
331
    mFboH            = node.mFboH;
332
    mFboDepthStencil = node.mFboDepthStencil;
333

    
334
    if( (flags & Distorted.CLONE_SURFACE) != 0 )
335
      {
336
      mSurface = node.mSurface;
337
      }
338
    else
339
      {
340
      int w = node.mSurface.getWidth();
341
      int h = node.mSurface.getHeight();
342

    
343
      if( node.mSurface instanceof DistortedTexture )
344
        {
345
        mSurface = new DistortedTexture(w,h, DistortedSurface.TYPE_TREE);
346
        }
347
      else if( node.mSurface instanceof DistortedFramebuffer )
348
        {
349
        int depthStencil = DistortedFramebuffer.NO_DEPTH_NO_STENCIL;
350

    
351
        if( ((DistortedFramebuffer) node.mSurface).hasDepth() )
352
          {
353
          boolean hasStencil = ((DistortedFramebuffer) node.mSurface).hasStencil();
354
          depthStencil = (hasStencil ? DistortedFramebuffer.BOTH_DEPTH_STENCIL:DistortedFramebuffer.DEPTH_NO_STENCIL);
355
          }
356

    
357
        mSurface = new DistortedFramebuffer(1,depthStencil,DistortedSurface.TYPE_TREE,w,h);
358
        }
359
      }
360
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
361
      {
362
      if( node.mChildren==null )     // do NOT copy over the NULL!
363
        {
364
        node.mChildren = new ArrayList<>(2);
365
        }
366

    
367
      mChildren = node.mChildren;
368
      mNumChildren = node.mNumChildren;
369
      }
370
    else
371
      {
372
      mChildren = null;
373
      mNumChildren = new int[1];
374
      }
375

    
376
    mData = DistortedNodeData.returnData(generateIDList());
377
    mEffects.newNode(this);
378
    }
379

    
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381
  /**
382
   * When rendering this Node, should we use the Order Independent Transparency render more?
383
   * <p>
384
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
385
   * fragments in different ways depending on which fragments get rendered first, or the slower
386
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
387
   *
388
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
389
   */
390
  public void setOrderIndependentTransparency(boolean oit)
391
    {
392
    mRenderWayOIT = oit;
393
    }
394

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396
  /**
397
   * When rendering this Node, should we use the Order Independent Transparency render more?
398
   * <p>
399
   * There are two modes of rendering: the fast 'normal' way, which however renders transparent
400
   * fragments in different ways depending on which fragments get rendered first, or the slower
401
   * 'oit' way, which renders transparent fragments correctly regardless of their order.
402
   *
403
   * @param oit True if we want to render more slowly, but in a way which accounts for transparency.
404
   * @param initialSize Initial number of transparent fragments we expect, in screenfulls.
405
   *                    I.e '1.0' means 'the scene we are going to render contains about 1 screen
406
   *                    worth of transparent fragments'. Valid values: 0.0 &lt; initialSize &lt; 10.0
407
   *                    Even if you get this wrong, the library will detect that there are more
408
   *                    transparent fragments than it has space for and readjust its internal buffers,
409
   *                    but only after a few frames during which one will probably see missing objects.
410
   */
411
  public void setOrderIndependentTransparency(boolean oit, float initialSize)
412
    {
413
    mRenderWayOIT = oit;
414

    
415
    if( initialSize>0.0f && initialSize<10.0f )
416
      DistortedEffects.setSSBOSize(initialSize);
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420
/**
421
 * Adds a new child to the last position in the list of our Node's children.
422
 * <p>
423
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
424
 * DistortedMaster (by calling doWork())
425
 *
426
 * @param node The new Node to add.
427
 */
428
  public void attach(DistortedNode node)
429
    {
430
    mJobs.add(new Job(ATTACH,node));
431
    DistortedMaster.newSlave(this);
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435
/**
436
 * Adds a new child to the last position in the list of our Node's children.
437
 * <p>
438
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
439
 * DistortedMaster (by calling doWork())
440
 *
441
 * @param surface InputSurface to initialize our child Node with.
442
 * @param effects DistortedEffects to initialize our child Node with.
443
 * @param mesh MeshBase to initialize our child Node with.
444
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
445
 */
446
  public DistortedNode attach(DistortedSurface surface, DistortedEffects effects, MeshBase mesh)
447
    {
448
    DistortedNode node = new DistortedNode(surface,effects,mesh);
449
    mJobs.add(new Job(ATTACH,node));
450
    DistortedMaster.newSlave(this);
451
    return node;
452
    }
453

    
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455
/**
456
 * Removes the first occurrence of a specified child from the list of children of our Node.
457
 * <p>
458
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
459
 * DistortedMaster (by calling doWork())
460
 *
461
 * @param node The Node to remove.
462
 */
463
  public void detach(DistortedNode node)
464
    {
465
    mJobs.add(new Job(DETACH,node));
466
    DistortedMaster.newSlave(this);
467
    }
468

    
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470
/**
471
 * Removes the first occurrence of a specified child from the list of children of our Node.
472
 * <p>
473
 * A bit questionable method as there can be many different Nodes attached as children, some
474
 * of them having the same Effects but - for instance - different Mesh. Use with care.
475
 * <p>
476
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
477
 * DistortedMaster (by calling doWork())
478
 *
479
 * @param effects DistortedEffects to remove.
480
 */
481
  public void detach(DistortedEffects effects)
482
    {
483
    long id = effects.getID();
484
    DistortedNode node;
485
    boolean detached = false;
486

    
487
    for(int i=0; i<mNumChildren[0]; i++)
488
      {
489
      node = mChildren.get(i);
490

    
491
      if( node.getEffects().getID()==id )
492
        {
493
        detached = true;
494
        mJobs.add(new Job(DETACH,node));
495
        DistortedMaster.newSlave(this);
496
        break;
497
        }
498
      }
499

    
500
    if( !detached )
501
      {
502
      // if we failed to detach any, it still might be the case that
503
      // there's an ATTACH job that we need to cancel.
504
      int num = mJobs.size();
505
      Job job;
506

    
507
      for(int i=0; i<num; i++)
508
        {
509
        job = mJobs.get(i);
510

    
511
        if( job.type==ATTACH && job.node.getEffects()==effects )
512
          {
513
          mJobs.remove(i);
514
          break;
515
          }
516
        }
517
      }
518
    }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521
/**
522
 * Removes all children Nodes.
523
 * <p>
524
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
525
 * DistortedMaster (by calling doWork())
526
 */
527
  public void detachAll()
528
    {
529
    mJobs.add(new Job(DETALL,null));
530
    DistortedMaster.newSlave(this);
531
    }
532

    
533
///////////////////////////////////////////////////////////////////////////////////////////////////
534
/**
535
 * This is not really part of the public API. Has to be public only because it is a part of the
536
 * DistortedSlave interface, which should really be a class that we extend here instead but
537
 * Java has no multiple inheritance.
538
 *
539
 * @y.exclude
540
 */
541
  public void doWork()
542
    {
543
    int num = mJobs.size();
544

    
545
    if( num>0 )
546
      {
547
      Job job;
548
      int numChanges=0;
549

    
550
      for(int i=0; i<num; i++)
551
        {
552
        job = mJobs.remove(0);
553

    
554
        switch(job.type)
555
          {
556
          case ATTACH: numChanges++;
557
                       if( mChildren==null ) mChildren = new ArrayList<>(2);
558
                       job.node.mParent = this;
559
                       job.node.mSurfaceParent = null;
560
                       DistortedMaster.addSortingByBuckets(mChildren,job.node);
561
                       mNumChildren[0]++;
562
                       break;
563
          case DETACH: numChanges++;
564
                       if( mNumChildren[0]>0 && mChildren.remove(job.node) )
565
                         {
566
                         job.node.mParent = null;
567
                         job.node.mSurfaceParent = null;
568
                         mNumChildren[0]--;
569
                         }
570
                       break;
571
          case DETALL: numChanges++;
572
                       if( mNumChildren[0]>0 )
573
                         {
574
                         DistortedNode tmp;
575

    
576
                         for(int j=mNumChildren[0]-1; j>=0; j--)
577
                           {
578
                           tmp = mChildren.remove(j);
579
                           tmp.mParent = null;
580
                           tmp.mSurfaceParent = null;
581
                           }
582

    
583
                         mNumChildren[0] = 0;
584
                         }
585
                       break;
586
          case SORT  : mChildren.remove(job.node);
587
                       DistortedMaster.addSortingByBuckets(mChildren,job.node);
588
                       break;
589
          }
590
        }
591
      if( numChanges>0 ) adjustIsomorphism();
592
      }
593
    }
594

    
595
///////////////////////////////////////////////////////////////////////////////////////////////////
596
/**
597
 * Returns the DistortedEffects object that's in the Node.
598
 * 
599
 * @return The DistortedEffects contained in the Node.
600
 */
601
  public DistortedEffects getEffects()
602
    {
603
    return mEffects;
604
    }
605

    
606
///////////////////////////////////////////////////////////////////////////////////////////////////
607
/**
608
 * Returns the DistortedSurface object that's in the Node.
609
 *
610
 * @return The DistortedSurface contained in the Node.
611
 */
612
  public DistortedSurface getSurface()
613
    {
614
    return mSurface;
615
    }
616

    
617
///////////////////////////////////////////////////////////////////////////////////////////////////
618
  /**
619
   * Returns the DistortedSurface object that's in the Node.
620
   *
621
   * @return The DistortedSurface contained in the Node (if a leaf), or the FBO (if an internal Node)
622
   */
623
  public DistortedSurface getInternalSurface()
624
    {
625
    return mNumChildren[0]==0 ? mSurface : mData.mFBO;
626
    }
627

    
628
///////////////////////////////////////////////////////////////////////////////////////////////////
629
/**
630
 * Returns the Mesh object that's in the Node.
631
 *
632
 * @return Mesh contained in the Node.
633
 */
634
  public MeshBase getMesh()
635
    {
636
    return mMesh;
637
    }
638

    
639
///////////////////////////////////////////////////////////////////////////////////////////////////
640
/**
641
 * Resizes the DistortedFramebuffer object that we render this Node to.
642
 */
643
  public void resize(int width, int height)
644
    {
645
    mFboW = width;
646
    mFboH = height;
647

    
648
    if ( mData.mFBO !=null )
649
      {
650
      // TODO: potentially allocate a new NodeData if we have to
651
      mData.mFBO.resize(width,height);
652
      }
653
    }
654

    
655
///////////////////////////////////////////////////////////////////////////////////////////////////
656
/**
657
 * Enables/disables DEPTH and STENCIL buffers in the Framebuffer object that we render this Node to.
658
 */
659
  public void enableDepthStencil(int depthStencil)
660
    {
661
    mFboDepthStencil = depthStencil;
662

    
663
    if ( mData.mFBO !=null )
664
      {
665
      // TODO: potentially allocate a new NodeData if we have to
666
      mData.mFBO.enableDepthStencil(depthStencil);
667
      }
668
    }
669

    
670
///////////////////////////////////////////////////////////////////////////////////////////////////
671
// APIs that control how to set the OpenGL state just before rendering this Node.
672
///////////////////////////////////////////////////////////////////////////////////////////////////
673
/**
674
 * When rendering this Node, use ColorMask (r,g,b,a).
675
 *
676
 * @param r Write to the RED color channel when rendering this Node?
677
 * @param g Write to the GREEN color channel when rendering this Node?
678
 * @param b Write to the BLUE color channel when rendering this Node?
679
 * @param a Write to the ALPHA channel when rendering this Node?
680
 */
681
  @SuppressWarnings("unused")
682
  public void glColorMask(boolean r, boolean g, boolean b, boolean a)
683
    {
684
    mState.glColorMask(r,g,b,a);
685
    }
686

    
687
///////////////////////////////////////////////////////////////////////////////////////////////////
688
/**
689
 * When rendering this Node, switch on writing to Depth buffer?
690
 *
691
 * @param mask Write to the Depth buffer when rendering this Node?
692
 */
693
  @SuppressWarnings("unused")
694
  public void glDepthMask(boolean mask)
695
    {
696
    mState.glDepthMask(mask);
697
    }
698

    
699
///////////////////////////////////////////////////////////////////////////////////////////////////
700
/**
701
 * When rendering this Node, which bits of the Stencil buffer to write to?
702
 *
703
 * @param mask Marks the bits of the Stencil buffer we will write to when rendering this Node.
704
 */
705
  @SuppressWarnings("unused")
706
  public void glStencilMask(int mask)
707
    {
708
    mState.glStencilMask(mask);
709
    }
710

    
711
///////////////////////////////////////////////////////////////////////////////////////////////////
712
/**
713
 * When rendering this Node, which Tests to enable?
714
 *
715
 * @param test Valid values: GL_DEPTH_TEST, GL_STENCIL_TEST, GL_BLEND
716
 */
717
  @SuppressWarnings("unused")
718
  public void glEnable(int test)
719
    {
720
    mState.glEnable(test);
721
    }
722

    
723
///////////////////////////////////////////////////////////////////////////////////////////////////
724
/**
725
 * When rendering this Node, which Tests to enable?
726
 *
727
 * @param test Valid values: GL_DEPTH_TEST, GL_STENCIL_TEST, GL_BLEND
728
 */
729
  @SuppressWarnings("unused")
730
  public void glDisable(int test)
731
    {
732
    mState.glDisable(test);
733
    }
734

    
735
///////////////////////////////////////////////////////////////////////////////////////////////////
736
/**
737
 * When rendering this Node, use the following StencilFunc.
738
 *
739
 * @param func Valid values: GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL
740
 * @param ref  Reference valut to compare our stencil with.
741
 * @param mask Mask used when comparing.
742
 */
743
  @SuppressWarnings("unused")
744
  public void glStencilFunc(int func, int ref, int mask)
745
    {
746
    mState.glStencilFunc(func,ref,mask);
747
    }
748

    
749
///////////////////////////////////////////////////////////////////////////////////////////////////
750
/**
751
 * When rendering this Node, use the following StencilOp.
752
 * <p>
753
 * Valid values of all 3 parameters: GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR, GL_INVERT, GL_INCR_WRAP, GL_DECR_WRAP
754
 *
755
 * @param sfail  What to do when Stencil Test fails.
756
 * @param dpfail What to do when Depth Test fails.
757
 * @param dppass What to do when Depth Test passes.
758
 */
759
  @SuppressWarnings("unused")
760
  public void glStencilOp(int sfail, int dpfail, int dppass)
761
    {
762
    mState.glStencilOp(sfail,dpfail,dppass);
763
    }
764

    
765
///////////////////////////////////////////////////////////////////////////////////////////////////
766
/**
767
 * When rendering this Node, use the following DepthFunc.
768
 *
769
 * @param func Valid values: GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL
770
 */
771
  @SuppressWarnings("unused")
772
  public void glDepthFunc(int func)
773
    {
774
    mState.glDepthFunc(func);
775
    }
776

    
777
///////////////////////////////////////////////////////////////////////////////////////////////////
778
/**
779
 * When rendering this Node, use the following Blending mode.
780
 * <p>
781
 * Valid values: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
782
 *               GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
783
 *               GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_SRC_ALPHA_SATURATE
784
 *
785
 * @param src Source Blend function
786
 * @param dst Destination Blend function
787
 */
788
  @SuppressWarnings("unused")
789
  public void glBlendFunc(int src, int dst)
790
    {
791
    mState.glBlendFunc(src,dst);
792
    }
793

    
794
///////////////////////////////////////////////////////////////////////////////////////////////////
795
/**
796
 * Before rendering this Node, clear the following buffers.
797
 * <p>
798
 * Valid values: 0, or bitwise OR of one or more values from the set GL_COLOR_BUFFER_BIT,
799
 *               GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT.
800
 * Default: 0
801
 *
802
 * @param mask bitwise OR of BUFFER_BITs to clear.
803
 */
804
  @SuppressWarnings("unused")
805
  public void glClear(int mask)
806
    {
807
    mState.glClear(mask);
808
    }
809
  }
(6-6/18)