Project

General

Profile

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

library / src / main / java / org / distorted / library / main / EffectQueue.java @ a0397f32

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 org.distorted.library.effect.Effect;
23
import org.distorted.library.effect.EffectName;
24
import org.distorted.library.effect.EffectType;
25
import org.distorted.library.message.EffectListener;
26
import org.distorted.library.message.EffectMessage;
27
import org.distorted.library.message.EffectMessageSender;
28

    
29
import java.util.ArrayList;
30
import java.util.HashMap;
31

    
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33

    
34
abstract class EffectQueue implements DistortedMaster.Slave
35
  {
36
  private static final int CREATE = 0;
37
  private static final int ATTACH = 1;
38
  private static final int DETACH = 2;
39
  private static final int DETALL = 3;
40

    
41
  int mNumEffects;              // 'ToBe' will be more than mNumEffects if doWork() hasn't
42
  private int mNumEffectsToBe;  // added them yet (or less if it hasn't removed some yet)
43
  float[] mUniforms;
44
  long[] mCurrentDuration;
45
  Effect[] mEffects;
46
  int[] mName;
47
  long mTime=0;
48
  ArrayList<EffectListener> mListeners =null;
49
  int mNumListeners=0;  // ==mListeners.length(), but we only create mListeners if the first one gets added
50
  long mDistortedEffectsID;
51

    
52
  private static int[] mMax = new int[EffectType.LENGTH];
53
  private static long mNextID;
54
  private static HashMap<ArrayList<Long>,Long> mMapID = new HashMap<>(); // maps lists of Effect IDs (longs) to a
55
                                                                         // single long - the queue ID.
56
  private ArrayList<DistortedNode> mNodes = null;
57
  private long mID;
58
  private int mIndex;
59
  private boolean mCreated;
60

    
61
  private class Job
62
    {
63
    int type;
64
    int num;
65
    boolean notify;
66
    Effect effect;
67

    
68
    Job(int t, int m, boolean n, Effect e)
69
      {
70
      type  = t;
71
      num   = m;
72
      notify= n;
73
      effect= e;
74
      }
75
    }
76

    
77
  private ArrayList<Job> mJobs = new ArrayList<>();
78

    
79
  static
80
    {
81
    onDestroy();
82
    }
83
  
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85
   
86
  EffectQueue(long id, int numUniforms, int index)
87
    {
88
    mCreated            = false;
89
    mID                 = 0;
90
    mNumEffects         = 0;
91
    mNumEffectsToBe     = 0;
92
    mDistortedEffectsID = id;
93
    mIndex              = index;
94

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

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100
// queues - guaranteed to be an array of EffectType.LENGTH length.
101
// Change this when creating a new ty[e of effect!
102

    
103
  static void allocateQueues(EffectQueue[] queues, EffectQueue[] from, int flags, long id)
104
    {
105
    queues[0] = (flags & Distorted.CLONE_MATRIX     ) != 0 ? from[0] : new EffectQueueMatrix(id);
106
    queues[1] = (flags & Distorted.CLONE_VERTEX     ) != 0 ? from[1] : new EffectQueueVertex(id);
107
    queues[2] = (flags & Distorted.CLONE_FRAGMENT   ) != 0 ? from[2] : new EffectQueueFragment(id);
108
    queues[3] = (flags & Distorted.CLONE_POSTPROCESS) != 0 ? from[3] : new EffectQueuePostprocess(id);
109
    }
110

    
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112
// queues - guaranteed to be an array of EffectType.LENGTH length.
113
// Change this when creating a new ty[e of effect!
114

    
115
  static void compute(EffectQueue[] queues, long currTime, float halfW, float halfH, float halfZ )
116
    {
117
    ((EffectQueueMatrix     )queues[0]).compute(currTime);
118
    ((EffectQueueVertex     )queues[1]).compute(currTime,halfW,halfH,halfZ);
119
    ((EffectQueueFragment   )queues[2]).compute(currTime,halfW,halfH,halfZ);
120
    ((EffectQueuePostprocess)queues[3]).compute(currTime);
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// queues - guaranteed to be an array of EffectType.LENGTH length.
125
// Change this when creating a new ty[e of effect!
126

    
127
  static void send(EffectQueue[] queues, DistortedOutputSurface surface, float inflate, float halfW, float halfH, float halfZ, int variant )
128
    {
129
    ((EffectQueueMatrix  )queues[0]).send(surface,halfW,halfH,halfZ, variant);
130
    ((EffectQueueVertex  )queues[1]).send(inflate, variant);
131
    ((EffectQueueFragment)queues[2]).send(variant);
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135
// queues - guaranteed to be an array of EffectType.LENGTH length.
136
// Change this when creating a new ty[e of effect!
137

    
138
  static float[] getMVP(EffectQueue[] queues)
139
    {
140
    return ((EffectQueueMatrix  )queues[0]).getMVP();
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
// queues - guaranteed to be an array of EffectType.LENGTH length.
145
// Change this when creating a new ty[e of effect!
146

    
147
  static void newNode(EffectQueue[] queues, DistortedNode node)
148
    {
149
    queues[3].newNode(node);
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153
// queues - guaranteed to be an array of EffectType.LENGTH length.
154
// Change this when creating a new ty[e of effect!
155

    
156
  static void removeNode(EffectQueue[] queues, DistortedNode node)
157
    {
158
    queues[3].removeNode(node);
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162
// queues - guaranteed to be an array of EffectType.LENGTH length.
163
// Change this when creating a new ty[e of effect!
164

    
165
  static void getUniforms(int programH, int variant)
166
    {
167
    EffectQueueFragment.getUniforms(programH,variant);
168
    EffectQueueVertex  .getUniforms(programH,variant);
169
    EffectQueueMatrix  .getUniforms(programH,variant);
170
    }
171

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

    
177
  private void regenerateIDandSort()
178
    {
179
    if( mNumEffects>0 )
180
      {
181
      ArrayList<Long> list = new ArrayList<>();
182
      for (int i = 0; i < mNumEffects; i++) list.add(mEffects[i].getID());
183
      Long id = mMapID.get(list);
184

    
185
      if( id!=null )
186
        {
187
        mID = id;
188
        }
189
      else
190
        {
191
        mMapID.put(list,mNextID);
192
        mID = mNextID++;
193
        }
194
      }
195
    else
196
      {
197
      mID = 0;
198
      }
199

    
200
    int numNodes = (mNodes==null ? 0: mNodes.size());
201
    for(int i=0; i<numNodes; i++) mNodes.get(i).sort();
202
    }
203

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

    
206
  private void newNode(DistortedNode node)
207
    {
208
    if( mNodes==null ) mNodes = new ArrayList<>();
209

    
210
    mNodes.add(node);
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  private void removeNode(DistortedNode node)
216
    {
217
    mNodes.remove(node);
218
    }
219

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

    
222
  @SuppressWarnings("unused")
223
  int getNumEffects()
224
    {
225
    return mNumEffects;  
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229

    
230
  long getID()
231
    {
232
    return mID;
233
    }
234

    
235
///////////////////////////////////////////////////////////////////////////////////////////////////
236

    
237
  static boolean setMax(int index, int m)
238
    {
239
    if( !Distorted.isInitialized() || m<=mMax[index] )
240
      {
241
      mMax[index] = m<0 ? 0:m;
242
      return true;
243
      }
244

    
245
    return false;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  static int getMax(int index)
251
    {
252
    return mMax[index];
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  void registerForMessages(EffectListener el)
258
    {
259
    if( mListeners==null ) mListeners = new ArrayList<>();
260

    
261
    if( !mListeners.contains(el) )
262
      {
263
      mListeners.add(el);
264
      mNumListeners++;
265
      }
266
    }
267
 
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  void deregisterForMessages(EffectListener el)
271
    {
272
    if( mListeners.remove(el) )
273
      {
274
      mNumListeners--;
275
      }
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  static void onDestroy()
281
    {
282
    mNextID = 1;
283
    mMapID.clear();
284
    EffectType.reset(mMax);
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288
// this assumes 0<=effect<mNumEffects
289

    
290
  protected void remove(int effect)
291
    {
292
    mNumEffects--;
293

    
294
    long removedID = mEffects[effect].getID();
295

    
296
    for(int j=effect; j<mNumEffects; j++ )
297
      {
298
      mEffects[j]         = mEffects[j+1];
299
      mCurrentDuration[j] = mCurrentDuration[j+1];
300
      mName[j]            = mName[j+1];
301
      }
302

    
303
    mEffects[mNumEffects] = null;
304

    
305
    for(int i=0; i<mNumListeners; i++)
306
      EffectMessageSender.newMessage( mListeners.get(i), EffectMessage.EFFECT_REMOVED, removedID, mDistortedEffectsID);
307
    }
308

    
309
///////////////////////////////////////////////////////////////////////////////////////////////////
310

    
311
  synchronized int removeByName(EffectName name)
312
    {
313
    int ret = 0;
314

    
315
    for(int i=0; i<mNumEffects; i++)
316
      {
317
      if( mEffects[i].getName() == name )
318
        {
319
        mJobs.add(new Job(DETACH,0,true,mEffects[i]));
320
        ret++;
321
        }
322
      }
323

    
324
    if( ret>0 )
325
      {
326
      DistortedMaster.newSlave(this);
327
      mNumEffectsToBe-=ret;
328
      }
329

    
330
    return ret;
331
    }
332

    
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334

    
335
  synchronized int removeById(long id)
336
    {
337
    for(int i=0; i<mNumEffects; i++)
338
      {
339
      if( mEffects[i].getID() == id )
340
        {
341
        mJobs.add(new Job(DETACH,0,true,mEffects[i]));
342
        DistortedMaster.newSlave(this);
343
        mNumEffectsToBe--;
344
        return 1;
345
        }
346
      }
347

    
348
    return 0;
349
    }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352

    
353
  synchronized int removeEffect(Effect effect)
354
    {
355
    for(int i=0; i<mNumEffects; i++)
356
      {
357
      if( mEffects[i]==effect )
358
        {
359
        mJobs.add(new Job(DETACH,0,true,mEffects[i]));
360
        DistortedMaster.newSlave(this);
361
        mNumEffectsToBe--;
362
        return 1;
363
        }
364
      }
365
   
366
    return 0;
367
    }
368

    
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370
// we do want to notify Listeners if they called 'abortAll' themselves but don't want to notify
371
// them if it is the library itself which is releasing resources.
372

    
373
  synchronized int abortAll(boolean notify)
374
    {
375
    mJobs.add(new Job(DETALL,0,notify,null));
376
    DistortedMaster.newSlave(this);
377
    mNumEffectsToBe = 0;
378
    return mNumEffects;
379
    }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382
  
383
  boolean add(Effect effect)
384
    {
385
    if( mMax[mIndex]>mNumEffectsToBe || !mCreated )
386
      {
387
      mJobs.add(new Job(ATTACH,0,false,effect));
388
      DistortedMaster.newSlave(this);
389
      mNumEffectsToBe++;
390
      return true;
391
      }
392

    
393
    return false;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397
/**
398
 * This is not really part of the public API. Has to be public only because it is a part of the
399
 * DistortedSlave interface, which should really be a class that we extend here instead but
400
 * Java has no multiple inheritance.
401
 *
402
 * @y.exclude
403
 */
404
  public void doWork()
405
    {
406
    boolean changed = false;
407
    int num = mJobs.size();
408
    Job job;
409

    
410
    for(int i=0; i<num; i++)
411
      {
412
      job = mJobs.remove(0);
413

    
414
      switch(job.type)
415
        {
416
        case CREATE: int max = mMax[mIndex];
417
                     if( max>0 )
418
                       {
419
                       mUniforms        = new float[max*job.num];
420
                       mCurrentDuration = new long[max];
421
                       mEffects         = new Effect[max];
422
                       mName            = new int[max];
423
                       }
424
                     mCreated = true;
425

    
426
                     break;
427
        case ATTACH: if( mMax[mIndex]>mNumEffects ) // it is possible that we have first
428
                       {                            // added effects and then lowered mMax
429
                       mCurrentDuration[mNumEffects] = 0;
430
                       mEffects[mNumEffects] = job.effect;
431
                       mName[mNumEffects] = job.effect.getName().ordinal();
432
                       mNumEffects++;
433
                       changed = true;
434
                       }
435
                     else
436
                       {
437
                       android.util.Log.e("queue", "failed to add effect "+job.effect.getName());
438
                       }
439
                     break;
440
        case DETACH: for(int j=0; j<mNumEffects; j++)
441
                       {
442
                       if (mEffects[j] == job.effect)
443
                         {
444
                         remove(j);
445
                         changed = true;
446
                         break;
447
                         }
448
                       }
449
                     break;
450
        case DETALL: for(int j=0; j<mNumEffects; j++ )
451
                       {
452
                       changed = true;
453

    
454
                       if( job.notify )
455
                         {
456
                         for(int k=0; k<mNumListeners; k++)
457
                           EffectMessageSender.newMessage( mListeners.get(k), EffectMessage.EFFECT_REMOVED, mEffects[j].getID(), mDistortedEffectsID);
458
                         }
459

    
460
                       mEffects[j] = null;
461
                       }
462

    
463
                     mNumEffects= 0;
464
                     break;
465
        }
466
      }
467

    
468
    if( changed && mIndex==EffectType.POSTPROCESS.ordinal() ) regenerateIDandSort();
469
    }
470
  }
(15-15/19)