Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedEffectsPostprocess.java @ 7c6d11c8

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 org.distorted.library.message.EffectListener;
23
import org.distorted.library.type.Data1D;
24

    
25
import java.util.ArrayList;
26

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

    
29
/**
30
 * Class containing the queue of postprocessing effects.
31
 * <p>
32
 * This better be separate from the main DistortedEffects class, because we want to be able to apply
33
 * the same postprocessing effects (i.e. not only the same effects, but the very same instance of this
34
 * object) to several Children of a Node. Reason for that: if several children have the same Object,
35
 * it is easy to group them into 'Buckets' where each bucket has the same postprocessing effects and
36
 * is therefore rendered to the same buffer, which is then postprocessed in one go.
37
 * <p>
38
 * The queue holds actual effects to be applied to a given bucket of several (DistortedTexture,MeshObject) combos.
39
 */
40
public class DistortedEffectsPostprocess implements DistortedSlave
41
  {
42
  private static final int MIPMAP = 0;
43

    
44
  private static long mNextID =0;
45
  private long mID;
46

    
47
  private EffectQueuePostprocess mP;
48

    
49
  private boolean postprocessCloned;
50

    
51
  private class Job
52
    {
53
    int type;
54
    int level;
55

    
56
    Job(int t, int l)
57
      {
58
      type = t;
59
      level= l;
60
      }
61
    }
62

    
63
  private ArrayList<Job> mJobs = new ArrayList<>();
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  private void initializeEffectLists(DistortedEffectsPostprocess d, int flags)
68
    {
69
    if( (flags & Distorted.CLONE_POSTPROCESS) != 0 )
70
      {
71
      mP = d.mP;
72
      postprocessCloned = true;
73
      }
74
    else
75
      {
76
      mP = new EffectQueuePostprocess(mID);
77
      postprocessCloned = false;
78
      }
79
    }
80

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

    
83
  int postprocess(long time, DistortedOutputSurface surface)
84
    {
85
    return mP.postprocess(time,surface);
86
    }
87

    
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89

    
90
  long getBucket()
91
    {
92
    return mP.mNumEffects==0 ? 0: mID;
93
    }
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
  private void releasePriv()
98
    {
99
    if( !postprocessCloned) mP.abortAll(false);
100

    
101
    mP = null;
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

    
106
  int getQuality()
107
    {
108
    return mP.mQualityLevel;
109
    }
110

    
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112

    
113
  static void onDestroy()
114
    {
115
    mNextID = 0;
116
    }
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119
// PUBLIC API
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121
/**
122
 * Create empty effect queue.
123
 */
124
  public DistortedEffectsPostprocess()
125
    {
126
    mID = ++mNextID;
127
    initializeEffectLists(this,0);
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131
/**
132
 * Copy constructor.
133
 * <p>
134
 * Whatever we do not clone gets created just like in the default constructor.
135
 *
136
 * @param dc    Source object to create our object from
137
 * @param flags A bitmask of values specifying what to copy.
138
 *              Currently the only values possible are CLONE_NOTHING or CLONE_POSTPROCESS.
139
 */
140
  public DistortedEffectsPostprocess(DistortedEffectsPostprocess dc, int flags)
141
    {
142
    mID = ++mNextID;
143
    initializeEffectLists(dc,flags);
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147
/**
148
 * This is not really part of the public API. Has to be public only because it is a part of the
149
 * DistortedSlave interface, which should really be a class that we extend here instead but
150
 * Java has no multiple inheritance.
151
 *
152
 * @y.exclude
153
 */
154
  public void doWork()
155
    {
156
    int num = mJobs.size();
157
    Job job;
158

    
159
    for(int i=0; i<num; i++)
160
      {
161
      job = mJobs.remove(0);
162

    
163
      switch(job.type)
164
        {
165
        case MIPMAP: int level = job.level;
166
                     mP.mQualityLevel = level;
167
                     mP.mQualityScale = 1.0f;
168
                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
169
                     break;
170
        }
171
      }
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175
/**
176
 * Releases all resources. After this call, the queue should not be used anymore.
177
 */
178
  @SuppressWarnings("unused")
179
  public synchronized void delete()
180
    {
181
    releasePriv();
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
/**
186
 * Returns unique ID of this instance.
187
 *
188
 * @return ID of the object.
189
 */
190
  @SuppressWarnings("unused")
191
  public long getID()
192
      {
193
      return mID;
194
      }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
/**
198
 * Adds the calling class to the list of Listeners that get notified each time some event happens 
199
 * to one of the Effects in the queues. Nothing will happen if 'el' is already in the list.
200
 * 
201
 * @param el A class implementing the EffectListener interface that wants to get notifications.
202
 */
203
  @SuppressWarnings("unused")
204
  public void registerForMessages(EffectListener el)
205
    {
206
    mP.registerForMessages(el);
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210
/**
211
 * Removes the calling class from the list of Listeners.
212
 * 
213
 * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
214
 */
215
  @SuppressWarnings("unused")
216
  public void deregisterForMessages(EffectListener el)
217
    {
218
    mP.deregisterForMessages(el);
219
    }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222
/**
223
 * Aborts all Effects.
224
 * @return Number of effects aborted.
225
 */
226
  @SuppressWarnings("unused")
227
  public int abortAllEffects()
228
      {
229
      return mP.abortAll(true);
230
      }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233
/**
234
 * Aborts all Effects of a given type (currently only POSTPROCESSING Effects).
235
 * 
236
 * @param type one of the constants defined in {@link EffectTypes}
237
 * @return Number of effects aborted.
238
 */
239
  @SuppressWarnings("unused")
240
  public int abortEffects(EffectTypes type)
241
    {
242
    switch(type)
243
      {
244
      case POSTPROCESS: return mP.abortAll(true);
245
      default         : return 0;
246
      }
247
    }
248
    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250
/**
251
 * Aborts a single Effect.
252
 * 
253
 * @param id ID of the Effect we want to abort.
254
 * @return number of Effects aborted. Always either 0 or 1.
255
 */
256
  @SuppressWarnings("unused")
257
  public int abortEffect(long id)
258
    {
259
    int type = (int)(id&EffectTypes.MASK);
260

    
261
    if( type==EffectTypes.POSTPROCESS.type ) return mP.removeByID(id>>EffectTypes.LENGTH);
262

    
263
    return 0;
264
    }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267
/**
268
 * Abort all Effects of a given name, for example all blurs.
269
 * 
270
 * @param name one of the constants defined in {@link EffectNames}
271
 * @return number of Effects aborted.
272
 */
273
  @SuppressWarnings("unused")
274
  public int abortEffects(EffectNames name)
275
    {
276
    switch(name.getType())
277
      {
278
      case POSTPROCESS: return mP.removeByType(name);
279
      default         : return 0;
280
      }
281
    }
282
    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284
/**
285
 * Print some info about a given Effect to Android's standard out. Used for debugging only.
286
 * 
287
 * @param id Effect ID we want to print info about
288
 * @return <code>true</code> if a single Effect of type effectType has been found.
289
 */
290
  @SuppressWarnings("unused")
291
  public boolean printEffect(long id)
292
    {
293
    int type = (int)(id&EffectTypes.MASK);
294

    
295
    if( type==EffectTypes.POSTPROCESS.type )  return mP.printByID(id>>EffectTypes.LENGTH);
296

    
297
    return false;
298
    }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301
/**
302
 * Returns the maximum number of Postprocess effects.
303
 *
304
 * @return The maximum number of Postprocess effects
305
 */
306
  @SuppressWarnings("unused")
307
  public static int getMaxPostprocess()
308
    {
309
    return EffectQueue.getMax(EffectTypes.POSTPROCESS.ordinal());
310
    }
311

    
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313
/**
314
 * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
315
 * This can fail if:
316
 * <ul>
317
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
318
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
319
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
320
 *     time only decreasing the value of 'max' is permitted.
321
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
322
 * </ul>
323
 *
324
 * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
325
 *            than Byte.MAX_VALUE
326
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
327
 */
328
  @SuppressWarnings("unused")
329
  public static boolean setMaxPostprocess(int max)
330
    {
331
    return EffectQueue.setMax(EffectTypes.POSTPROCESS.ordinal(),max);
332
    }
333

    
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335
/**
336
 * The higher the quality, the better the effect will look like and the slower it will be.
337
 * <p>
338
 * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
339
 * buffer that's half the size of the previous one.
340
 * <p>
341
 * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
342
 * next render.
343
 */
344
  public void setQuality(EffectQuality quality)
345
    {
346
    mJobs.add(new Job(MIPMAP,quality.level));
347
    DistortedMaster.newSlave(this);
348
    }
349

    
350
///////////////////////////////////////////////////////////////////////////////////////////////////   
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352
// Individual effect functions.
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354
// Postprocess-based effects
355
///////////////////////////////////////////////////////////////////////////////////////////////////
356
/**
357
 * Blur the object.
358
 *
359
 * @param radius The 'strength' if the effect, in pixels. 0 = no blur, 10 = when blurring a given pixel,
360
 *               take into account 10 pixels in each direction.
361
 * @return ID of the effect added, or -1 if we failed to add one.
362
 */
363
  public long blur(Data1D radius)
364
    {
365
    return mP.add(EffectNames.BLUR, radius);
366
    }
367
  }
(3-3/25)