Project

General

Profile

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

library / src / main / java / org / distorted / library / effectqueue / EffectQueue.java @ 644c21f2

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.effectqueue;
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.main.DistortedLibrary;
26
import org.distorted.library.main.InternalMaster;
27

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

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

    
41
  private static final int CREATE = 0;
42
  private static final int ATTACH = 1;
43
  private static final int DETACH = 2;
44
  private static final int DETALL = 3;
45

    
46
  int mNumEffects;              // 'ToBe' will be more than mNumEffects if doWork() hasn't
47
  private int mNumEffectsToBe;  // added them yet (or less if it hasn't removed some yet)
48
  float[] mUniforms;
49
  long[] mCurrentDuration;
50
  Effect[] mEffects;
51
  int[] mName;
52
  long mTime=0;
53

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

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

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

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

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

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

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

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

    
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110

    
111
  public static void compute(EffectQueue[] queues, long currTime)
112
    {
113
    ((EffectQueueMatrix     )queues[0]).compute(currTime);
114
    ((EffectQueueVertex     )queues[1]).compute(currTime);
115
    ((EffectQueueFragment   )queues[2]).compute(currTime);
116
    ((EffectQueuePostprocess)queues[3]).compute(currTime);
117
    }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
  public static void send( EffectQueue[] queues, int width, int height, float distance, float mipmap,
122
                           float[] projection, float inflate, float halfW, float halfH, float halfZ, int variant )
123
    {
124
    ((EffectQueueMatrix  )queues[0]).send(width, height, distance, mipmap, projection, halfW, halfH, halfZ, variant);
125
    ((EffectQueueVertex  )queues[1]).send(inflate, variant);
126
    ((EffectQueueFragment)queues[2]).send(variant);
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  public static float[] getMVP(EffectQueue[] queues)
132
    {
133
    return ((EffectQueueMatrix)queues[0]).getMVP();
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  public static void getUniforms(int programH, int variant)
139
    {
140
    EffectQueueFragment.uniforms(programH,variant);
141
    EffectQueueVertex  .uniforms(programH,variant);
142
    EffectQueueMatrix  .uniforms(programH,variant);
143
    }
144

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

    
150
  private void regenerateID()
151
    {
152
    if( mNumEffects>0 )
153
      {
154
      ArrayList<Long> list = new ArrayList<>();
155
      for (int i = 0; i < mNumEffects; i++) list.add(mEffects[i].getID());
156
      Long id = mMapID.get(list);
157

    
158
      if( id!=null )
159
        {
160
        mID = id;
161
        }
162
      else
163
        {
164
        mMapID.put(list,mNextID);
165
        mID = mNextID++;
166
        }
167
      }
168
    else
169
      {
170
      mID = 0;
171
      }
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

    
176
  public long getID()
177
    {
178
    return mID;
179
    }
180

    
181
///////////////////////////////////////////////////////////////////////////////////////////////////
182

    
183
  public static boolean setMax(int index, int m)
184
    {
185
    if( !DistortedLibrary.isInitialized() || m<=mMax[index] )
186
      {
187
      mMax[index] = m<0 ? 0:m;
188
      return true;
189
      }
190

    
191
    return false;
192
    }
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

    
196
  public static int getMax(int index)
197
    {
198
    return mMax[index];
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202

    
203
  public static void onDestroy()
204
    {
205
    mNextID = 1;
206
    mMapID.clear();
207
    EffectType.reset(mMax);
208
    }
209

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211
// this assumes 0<=effect<mNumEffects
212

    
213
  protected void remove(int effect)
214
    {
215
    mNumEffects--;
216

    
217
    for(int j=effect; j<mNumEffects; j++ )
218
      {
219
      mEffects[j]         = mEffects[j+1];
220
      mCurrentDuration[j] = mCurrentDuration[j+1];
221
      mName[j]            = mName[j+1];
222
      }
223

    
224
    mEffects[mNumEffects] = null;
225
    }
226

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

    
229
  public synchronized int removeByName(EffectName name)
230
    {
231
    int ret = 0;
232

    
233
    for(int i=0; i<mNumEffects; i++)
234
      {
235
      if( mEffects[i].getName() == name )
236
        {
237
        mJobs.add(new Job(DETACH,0,true,mEffects[i]));
238
        ret++;
239
        }
240
      }
241

    
242
    if( ret>0 )
243
      {
244
      InternalMaster.newSlave(this);
245
      mNumEffectsToBe-=ret;
246
      }
247

    
248
    return ret;
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

    
253
  public synchronized int removeById(long id)
254
    {
255
    for(int i=0; i<mNumEffects; i++)
256
      {
257
      if( mEffects[i].getID() == id )
258
        {
259
        mJobs.add(new Job(DETACH,0,true,mEffects[i]));
260
        InternalMaster.newSlave(this);
261
        mNumEffectsToBe--;
262
        return 1;
263
        }
264
      }
265

    
266
    return 0;
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

    
271
  public synchronized int removeEffect(Effect effect)
272
    {
273
    for(int i=0; i<mNumEffects; i++)
274
      {
275
      if( mEffects[i]==effect )
276
        {
277
        mJobs.add(new Job(DETACH,0,true,mEffects[i]));
278
        InternalMaster.newSlave(this);
279
        mNumEffectsToBe--;
280
        return 1;
281
        }
282
      }
283
   
284
    return 0;
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288
// we do want to notify Listeners if they called 'abortAll' themselves but don't want to notify
289
// them if it is the library itself which is releasing resources.
290

    
291
  public synchronized int abortAll(boolean notify)
292
    {
293
    mJobs.add(new Job(DETALL,0,notify,null));
294
    InternalMaster.newSlave(this);
295
    mNumEffectsToBe = 0;
296
    return mNumEffects;
297
    }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300
  
301
  public boolean add(Effect effect)
302
    {
303
    if( mMax[mIndex]>mNumEffectsToBe || !mCreated )
304
      {
305
      mJobs.add(new Job(ATTACH,-1,false,effect));
306
      InternalMaster.newSlave(this);
307
      mNumEffectsToBe++;
308
      return true;
309
      }
310

    
311
    return false;
312
    }
313

    
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315

    
316
  public boolean add(Effect effect, int position)
317
    {
318
    if( mMax[mIndex]>mNumEffectsToBe || !mCreated )
319
      {
320
      mJobs.add(new Job(ATTACH,position,false,effect));
321
      InternalMaster.newSlave(this);
322
      mNumEffectsToBe++;
323
      return true;
324
      }
325

    
326
    return false;
327
    }
328

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

    
331
  public int getNumEffects()
332
    {
333
    return mNumEffects;
334
    }
335

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

    
338
  public Effect getEffect(int position)
339
    {
340
    if( position>=0 && position< mNumEffects )
341
      {
342
      return mEffects[position];
343
      }
344
    else
345
      {
346
      android.util.Log.e("queue", "getEffect: out of range "+position);
347
      return null;
348
      }
349
    }
350

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

    
353
  public void doWork()
354
    {
355
    boolean changed = false;
356
    int num = mJobs.size();
357
    Job job;
358

    
359
    for(int i=0; i<num; i++)
360
      {
361
      job = mJobs.remove(0);
362

    
363
      switch(job.type)
364
        {
365
        case CREATE: int max = mMax[mIndex];
366
                     if( max>0 )
367
                       {
368
                       mUniforms        = new float[max*job.num];
369
                       mCurrentDuration = new long[max];
370
                       mEffects         = new Effect[max];
371
                       mName            = new int[max];
372
                       }
373
                     mCreated = true;
374

    
375
                     break;
376
        case ATTACH: if( mMax[mIndex]>mNumEffects ) // it is possible that we have first
377
                       {                            // added effects and then lowered mMax
378
                       int position = job.num;
379

    
380
                       if( position==-1 )
381
                         {
382
                         mCurrentDuration[mNumEffects] = 0;
383
                         mEffects[mNumEffects] = job.effect;
384
                         mName[mNumEffects] = job.effect.getName().ordinal();
385

    
386
                         mNumEffects++;
387
                         changed = true;
388
                         }
389
                       else if( position>=0 && position<=mNumEffects )
390
                         {
391
                         for(int j=mNumEffects; j>position; j--)
392
                           {
393
                           mCurrentDuration[j] = mCurrentDuration[j-1];
394
                           mEffects[j]         = mEffects[j-1];
395
                           mName[j]            = mName[j-1];
396
                           }
397

    
398
                         mCurrentDuration[position] = 0;
399
                         mEffects[position] = job.effect;
400
                         mName[position] = job.effect.getName().ordinal();
401

    
402
                         mNumEffects++;
403
                         changed = true;
404
                         }
405
                       }
406
                     else
407
                       {
408
                       android.util.Log.e("queue", "failed to add effect "+job.effect.getName());
409
                       }
410
                     break;
411
        case DETACH: for(int j=0; j<mNumEffects; j++)
412
                       {
413
                       if (mEffects[j] == job.effect)
414
                         {
415
                         remove(j);
416
                         changed = true;
417
                         break;
418
                         }
419
                       }
420
                     break;
421
        case DETALL: for(int j=0; j<mNumEffects; j++ )
422
                       {
423
                       changed = true;
424
                       mEffects[j] = null;
425
                       }
426

    
427
                     mNumEffects= 0;
428
                     break;
429
        }
430
      }
431

    
432
    if( changed && mIndex==EffectType.POSTPROCESS.ordinal() ) regenerateID();
433
    }
434
  }
(1-1/5)