Project

General

Profile

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

library / src / main / java / org / distorted / library / effectqueue / EffectQueue.java @ 8c57d77b

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// This library is free software; you can redistribute it and/or                                 //
7
// modify it under the terms of the GNU Lesser General Public                                    //
8
// License as published by the Free Software Foundation; either                                  //
9
// version 2.1 of the License, or (at your option) any later version.                            //
10
//                                                                                               //
11
// This library 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 GNU                             //
14
// Lesser General Public License for more details.                                               //
15
//                                                                                               //
16
// You should have received a copy of the GNU Lesser General Public                              //
17
// License along with this library; if not, write to the Free Software                           //
18
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
19
///////////////////////////////////////////////////////////////////////////////////////////////////
20

    
21
package org.distorted.library.effectqueue;
22

    
23
import org.distorted.library.effect.Effect;
24
import org.distorted.library.effect.EffectName;
25
import org.distorted.library.effect.EffectType;
26
import org.distorted.library.main.DistortedLibrary;
27
import org.distorted.library.main.InternalMaster;
28
import org.distorted.library.main.InternalStackFrameList;
29
import org.distorted.library.uniformblock.UniformBlockFloatUniforms;
30
import org.distorted.library.uniformblock.UniformBlockIntUniforms;
31

    
32
import java.util.ArrayList;
33
import java.util.HashMap;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
/**
37
 * Not part of public API, do not document
38
 *
39
 * @y.exclude
40
 */
41
public abstract class EffectQueue implements InternalMaster.Slave
42
  {
43
  public static final int MAIN_VARIANTS = 4; // Number of Main program variants (ATM 4: MAIN, MAIN OIT, PREPROCESS, FULL)
44

    
45
  static final int VERT_INT_UBO_BINDING = 5;
46
  static final int VERT_FLO_UBO_BINDING = 6;
47

    
48
  private static final int CREATE = 0;
49
  private static final int ATTACH = 1;
50
  private static final int DETACH = 2;
51
  private static final int DETALL = 3;
52

    
53
  int mNumEffects;              // 'ToBe' will be more than mNumEffects if doWork() hasn't
54
  private int mNumEffectsToBe;  // added them yet (or less if it hasn't removed some yet)
55
  Effect[] mEffects;
56

    
57
  UniformBlockFloatUniforms mUBF;
58
  UniformBlockIntUniforms mUBI;
59

    
60
  private long mID;
61
  private final int mIndex;
62
  private boolean mCreated;
63

    
64
  private static class Job
65
    {
66
    int type;
67
    int num1, num2;
68
    boolean bool;
69
    Effect effect;
70

    
71
    Job(int t, int m1, int m2, boolean n, Effect e)
72
      {
73
      type  = t;
74
      num1  = m1;
75
      num2  = m2;
76
      bool  = n;
77
      effect= e;
78
      }
79
    }
80

    
81
  private final ArrayList<Job> mJobs;
82

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
   
85
  EffectQueue(int numFloatUniforms, int numIntUniforms, boolean useUBO, int index)
86
    {
87
    mCreated        = false;
88
    mID             = 0;
89
    mNumEffects     = 0;
90
    mNumEffectsToBe = 0;
91
    mIndex          = index;
92

    
93
    mJobs = new ArrayList<>();
94

    
95
    mJobs.add(new Job(CREATE,numFloatUniforms,numIntUniforms,useUBO,null)); // create the stuff that depends on max number
96
    InternalMaster.newSlave(this);                                          // of uniforms later, on first render.
97
    }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100
// this is not thread safe! The 'source' might change while we're copying it.
101

    
102
  EffectQueue(EffectQueue source)
103
    {
104
    if( !source.mCreated )
105
      {
106
      mCreated        = false;
107
      mID             = 0;
108
      mNumEffects     = 0;
109
      mNumEffectsToBe = 0;
110
      mIndex          = source.mIndex;
111

    
112
      mJobs = new ArrayList<>();
113

    
114
      int numJobs = source.mJobs.size();
115

    
116
      for(int i=0; i<numJobs; i++)
117
        {
118
        Job job = source.mJobs.get(i);
119
        mJobs.add(job);
120
        }
121

    
122
      InternalMaster.newSlave(this);
123
      }
124
    else
125
      {
126
      mCreated        = true;
127
      mID             = source.mID;
128
      mNumEffects     = source.mNumEffects;
129
      mNumEffectsToBe = source.mNumEffectsToBe;
130
      mIndex          = source.mIndex;
131

    
132
      mJobs = new ArrayList<>();
133

    
134
      int max = InternalStackFrameList.getMax(mIndex);
135

    
136
      if( max>0 )
137
        {
138
        mEffects= new Effect[max];
139
        mUBI  = new UniformBlockIntUniforms(source.mUBI);
140
        mUBF  = new UniformBlockFloatUniforms(source.mUBF);
141

    
142
        if( mNumEffects>=0 )
143
          {
144
          System.arraycopy(source.mEffects, 0, mEffects, 0, mNumEffects);
145
          }
146
        }
147
      }
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  public static void allocateQueues(EffectQueue[] queues, EffectQueue[] from, int flags)
153
    {
154
    queues[0] = (flags & DistortedLibrary.CLONE_MATRIX     ) != 0 ? from[0] : new EffectQueueMatrix();
155
    queues[1] = (flags & DistortedLibrary.CLONE_VERTEX     ) != 0 ? from[1] : new EffectQueueVertex();
156
    queues[2] = (flags & DistortedLibrary.CLONE_FRAGMENT   ) != 0 ? from[2] : new EffectQueueFragment();
157
    queues[3] = (flags & DistortedLibrary.CLONE_POSTPROCESS) != 0 ? from[3] : new EffectQueuePostprocess();
158
    }
159

    
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161

    
162
  public static void compute(EffectQueue[] queues, long currTime, long step)
163
    {
164
    ((EffectQueueMatrix     )queues[0]).compute(currTime,step);
165
    ((EffectQueueVertex     )queues[1]).compute(currTime,step);
166
    ((EffectQueueFragment   )queues[2]).compute(currTime,step);
167
    ((EffectQueuePostprocess)queues[3]).compute(currTime,step);
168
    }
169

    
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

    
172
  public static void send(EffectQueue[] queues, int programH, float distance, float mipmap,
173
                          float[] projection, float inflate, int variant )
174
    {
175
    ((EffectQueueMatrix  )queues[0]).send(distance, mipmap, projection, variant);
176
    ((EffectQueueVertex  )queues[1]).send(inflate, programH, variant);
177
    ((EffectQueueFragment)queues[2]).send(programH, variant);
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181
// variant: 0 --> MAIN  1 --> OIT  2 --> prePOST  3 --> FULL
182

    
183
  public static void getUniforms(int programH, int variant)
184
    {
185
    EffectQueueFragment.uniforms(programH,variant);
186
    EffectQueueVertex  .uniforms(programH,variant);
187
    EffectQueueMatrix  .uniforms(programH,variant);
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191
// Every effect queue has an ID, which should be the same iff two queues hold the same effects.
192
// (this is a speedup: then both queues can be applied once, which seriously speeds up stuff -
193
// especially important in case of postprocessing)
194

    
195
  private void regenerateID()
196
    {
197
    if( mNumEffects>0 )
198
      {
199
      HashMap<ArrayList<Long>,Long> map = InternalStackFrameList.getMap();
200
      ArrayList<Long> list = new ArrayList<>();
201
      for (int i=0; i<mNumEffects; i++) list.add(mEffects[i].getID());
202
      Long id = map.get(list);
203

    
204
      if( id!=null )
205
        {
206
        mID = id;
207
        }
208
      else
209
        {
210
        mID = InternalStackFrameList.getNextQueueID();
211
        map.put(list,mID);
212
        }
213
      }
214
    else
215
      {
216
      mID = 0;
217
      }
218
    }
219

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221

    
222
  public long getID()
223
    {
224
    return mID;
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

    
229
  public static boolean setMax(int index, int m)
230
    {
231
    return InternalStackFrameList.setMax(index, Math.max(m,0));
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  public static int getMax(int index)
237
    {
238
    return InternalStackFrameList.getMax(index);
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242
// this assumes 0<=effect
243

    
244
  private void removeNow(int pos)
245
    {
246
    if( mNumEffects>pos )
247
      {
248
      mNumEffects--;
249
      mEffects[pos].remQueue(this);
250
      System.arraycopy(mEffects, pos+1, mEffects, pos, mNumEffects-pos);
251
      mUBI.remove(pos, mNumEffects);
252
      mEffects[mNumEffects] = null;
253
      }
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

    
258
  private void addNow(int pos, Effect effect)
259
    {
260
    mEffects[pos] = effect;
261
    mUBI.addOrdinal(pos, effect.getName().ordinal() );
262
    effect.addQueue(this);
263

    
264
    if( mIndex==EffectType.VERTEX.ordinal() )
265
      {
266
      mUBI.addAssociations(pos,effect);
267
      }
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
  public synchronized int removeByName(EffectName name)
273
    {
274
    int ret = 0;
275

    
276
    for(int i=0; i<mNumEffects; i++)
277
      {
278
      if( mEffects[i].getName() == name )
279
        {
280
        mJobs.add(new Job(DETACH,0,0,true,mEffects[i]));
281
        ret++;
282
        }
283
      }
284

    
285
    if( ret>0 )
286
      {
287
      InternalMaster.newSlave(this);
288
      mNumEffectsToBe-=ret;
289
      }
290

    
291
    return ret;
292
    }
293

    
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295

    
296
  public synchronized int removeById(long id)
297
    {
298
    for(int i=0; i<mNumEffects; i++)
299
      {
300
      if( mEffects[i].getID() == id )
301
        {
302
        mJobs.add(new Job(DETACH,0,0,true,mEffects[i]));
303
        InternalMaster.newSlave(this);
304
        mNumEffectsToBe--;
305
        return 1;
306
        }
307
      }
308

    
309
    return 0;
310
    }
311

    
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313

    
314
  public synchronized int removeEffect(Effect effect)
315
    {
316
    for(int i=0; i<mNumEffects; i++)
317
      {
318
      if( mEffects[i]==effect )
319
        {
320
        mJobs.add(new Job(DETACH,0,0,true,mEffects[i]));
321
        InternalMaster.newSlave(this);
322
        mNumEffectsToBe--;
323
        return 1;
324
        }
325
      }
326
   
327
    return 0;
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331
// we do want to notify Listeners if they called 'abortAll' themselves but don't want to notify
332
// them if it is the library itself which is releasing resources.
333

    
334
  public synchronized int removeAll(boolean notify)
335
    {
336
    mJobs.add(new Job(DETALL,0,0,notify,null));
337
    InternalMaster.newSlave(this);
338
    mNumEffectsToBe = 0;
339
    return mNumEffects;
340
    }
341

    
342
///////////////////////////////////////////////////////////////////////////////////////////////////
343
  
344
  public boolean add(Effect effect)
345
    {
346
    if( InternalStackFrameList.getMax(mIndex)>mNumEffectsToBe || !mCreated )
347
      {
348
      mJobs.add(new Job(ATTACH,-1,0,false,effect));
349
      InternalMaster.newSlave(this);
350
      mNumEffectsToBe++;
351
      return true;
352
      }
353

    
354
    return false;
355
    }
356

    
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358

    
359
  public boolean add(Effect effect, int position)
360
    {
361
    if( InternalStackFrameList.getMax(mIndex)>mNumEffectsToBe || !mCreated )
362
      {
363
      mJobs.add(new Job(ATTACH,position,0,false,effect));
364
      InternalMaster.newSlave(this);
365
      mNumEffectsToBe++;
366
      return true;
367
      }
368

    
369
    return false;
370
    }
371

    
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373

    
374
  public boolean exists(long id)
375
    {
376
    for(int i=0; i<mNumEffects; i++)
377
      {
378
      if( mEffects[i].getID() == id ) return true;
379
      }
380

    
381
    return false;
382
    }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385

    
386
  public int getNumEffects()
387
    {
388
    return mNumEffects;
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
  public int getNumEffectsToBe()
394
    {
395
    return mNumEffectsToBe;
396
    }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399

    
400
  public Effect getEffect(int position)
401
    {
402
    if( position>=0 && position< mNumEffects )
403
      {
404
      return mEffects[position];
405
      }
406
    else
407
      {
408
      DistortedLibrary.logMessage("EffectQueue: getEffect: out of range "+position);
409
      return null;
410
      }
411
    }
412

    
413
///////////////////////////////////////////////////////////////////////////////////////////////////
414

    
415
  public void setAssociation(long effectID)
416
    {
417
    for(int j=0; j<mNumEffects; j++)
418
      {
419
      if (mEffects[j].getID() == effectID)
420
        {
421
        mUBI.addAssociations(j,mEffects[j]);
422
        }
423
      }
424
    }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

    
428
  public void markForDeletion()
429
    {
430
    mUBI.markForDeletion();
431
    mUBF.markForDeletion();
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

    
436
  public String retEffects()
437
    {
438
    String dbg="";
439

    
440
    for(int i=0; i<mNumEffects; i++)
441
      {
442
      dbg += (i+": "+mEffects[i].getString()+" ");
443
      }
444

    
445
    return dbg;
446
    }
447

    
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449

    
450
  public void doWork()
451
    {
452
    boolean changed = false;
453
    int num = mJobs.size();
454
    Job job;
455

    
456
    for(int i=0; i<num; i++)
457
      {
458
      job = mJobs.remove(0);
459

    
460
      switch(job.type)
461
        {
462
        case CREATE: int max = InternalStackFrameList.getMax(mIndex);
463
                     if( max>0 )
464
                       {
465
                       mEffects= new Effect[max];
466
                       mUBF    = new UniformBlockFloatUniforms(job.num1, max, job.bool);
467
                       mUBI    = new UniformBlockIntUniforms  (job.num2, max, job.bool);
468
                       }
469
                     mCreated = true;
470

    
471
                     break;
472
        case ATTACH: if( InternalStackFrameList.getMax(mIndex)>mNumEffects ) // it is possible that we have first
473
                       {                                                     // added effects and then lowered mMax
474
                       int position = job.num1;
475

    
476
                       if( position<0 )
477
                         {
478
                         addNow(mNumEffects,job.effect);
479
                         mNumEffects++;
480
                         changed = true;
481
                         }
482
                       else if( position<=mNumEffects )
483
                         {
484
                         System.arraycopy(mEffects, position, mEffects, position+1, mNumEffects-position);
485
                         mUBI.makeHole(position, mNumEffects);
486
                         addNow(position,job.effect);
487
                         mNumEffects++;
488
                         changed = true;
489
                         }
490
                       }
491
                     else
492
                       {
493
                       DistortedLibrary.logMessage("EffectQueue: failed to add effect "+job.effect.getName());
494
                       }
495
                     break;
496
        case DETACH: for(int j=0; j<mNumEffects; j++)
497
                       {
498
                       if (mEffects[j] == job.effect)
499
                         {
500
                         removeNow(j);
501
                         changed = true;
502
                         break;
503
                         }
504
                       }
505
                     break;
506
        case DETALL: for(int j=0; j<mNumEffects; j++ )
507
                       {
508
                       changed = true;
509
                       mEffects[j] = null;
510
                       }
511

    
512
                     // TODO: notify listeners?
513
                     /* if( job.bool )
514
                          {
515
                          // ...
516
                          }
517
                      */
518

    
519
                     mNumEffects= 0;
520
                     break;
521
        }
522
      }
523

    
524
    if( changed && mIndex==EffectType.POSTPROCESS.ordinal() ) regenerateID();
525
    }
526
  }
(1-1/5)