Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedEffectsPostprocess.java @ a31dbc5c

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
import org.distorted.library.type.Data4D;
25

    
26
import java.util.ArrayList;
27

    
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29

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

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

    
48
  private EffectQueuePostprocess mP;
49

    
50
  private boolean postprocessCloned;
51

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

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

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

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

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

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83

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

    
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

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

    
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97

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

    
102
    mP = null;
103
    }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

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

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
  int getHalo()
115
    {
116
    return mP.getHalo();
117
    }
118

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

    
121
  static void onDestroy()
122
    {
123
    mNextID = 0;
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127
// PUBLIC API
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
/**
130
 * Create empty effect queue.
131
 */
132
  public DistortedEffectsPostprocess()
133
    {
134
    mID = ++mNextID;
135
    initializeEffectLists(this,0);
136
    }
137

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

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155
/**
156
 * This is not really part of the public API. Has to be public only because it is a part of the
157
 * DistortedSlave interface, which should really be a class that we extend here instead but
158
 * Java has no multiple inheritance.
159
 *
160
 * @y.exclude
161
 */
162
  public void doWork()
163
    {
164
    int num = mJobs.size();
165
    Job job;
166

    
167
    for(int i=0; i<num; i++)
168
      {
169
      job = mJobs.remove(0);
170

    
171
      switch(job.type)
172
        {
173
        case MIPMAP: int level = job.level;
174
                     mP.mQualityLevel = level;
175
                     mP.mQualityScale = 1.0f;
176
                     for(int j=0; j<level; j++) mP.mQualityScale*=EffectQuality.MULTIPLIER;
177
                     break;
178
        }
179
      }
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183
/**
184
 * Releases all resources. After this call, the queue should not be used anymore.
185
 */
186
  @SuppressWarnings("unused")
187
  public synchronized void delete()
188
    {
189
    releasePriv();
190
    }
191

    
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
/**
194
 * Returns unique ID of this instance.
195
 *
196
 * @return ID of the object.
197
 */
198
  @SuppressWarnings("unused")
199
  public long getID()
200
      {
201
      return mID;
202
      }
203

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205
/**
206
 * Adds the calling class to the list of Listeners that get notified each time some event happens 
207
 * to one of the Effects in the queues. Nothing will happen if 'el' is already in the list.
208
 * 
209
 * @param el A class implementing the EffectListener interface that wants to get notifications.
210
 */
211
  @SuppressWarnings("unused")
212
  public void registerForMessages(EffectListener el)
213
    {
214
    mP.registerForMessages(el);
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218
/**
219
 * Removes the calling class from the list of Listeners.
220
 * 
221
 * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
222
 */
223
  @SuppressWarnings("unused")
224
  public void deregisterForMessages(EffectListener el)
225
    {
226
    mP.deregisterForMessages(el);
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230
/**
231
 * Aborts all Effects.
232
 * @return Number of effects aborted.
233
 */
234
  @SuppressWarnings("unused")
235
  public int abortAllEffects()
236
      {
237
      return mP.abortAll(true);
238
      }
239

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

    
269
    if( type==EffectTypes.POSTPROCESS.type ) return mP.removeByID(id>>EffectTypes.LENGTH);
270

    
271
    return 0;
272
    }
273

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

    
303
    if( type==EffectTypes.POSTPROCESS.type )  return mP.printByID(id>>EffectTypes.LENGTH);
304

    
305
    return false;
306
    }
307

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309
/**
310
 * Returns the maximum number of Postprocess effects.
311
 *
312
 * @return The maximum number of Postprocess effects
313
 */
314
  @SuppressWarnings("unused")
315
  public static int getMaxPostprocess()
316
    {
317
    return EffectQueue.getMax(EffectTypes.POSTPROCESS.ordinal());
318
    }
319

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

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

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////   
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
// Individual effect functions.
361
///////////////////////////////////////////////////////////////////////////////////////////////////
362
// Postprocess-based effects
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
/**
365
 * Blur the object.
366
 *
367
 * @param radius The 'strength' if the effect, in pixels. 0 = no blur, 10 = when blurring a given pixel,
368
 *               take into account 10 pixels in each direction.
369
 * @return ID of the effect added, or -1 if we failed to add one.
370
 */
371
  public long blur(Data1D radius)
372
    {
373
    return mP.add(EffectNames.BLUR, radius);
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377
/**
378
 * Make the object glow with a specific color and a halo of specific radius.
379
 *
380
 * @param radius The 'strength' if the effect, in pixels. 0 = no halo, 10 = halo of roughly 10 pixels
381
 *               around the whole object.
382
 * @param color  RGBA of the color with which to draw the glow.
383
 * @return ID of the effect added, or -1 if we failed to add one.
384
 */
385
  public long glow(Data1D radius, Data4D color)
386
    {
387
    return mP.add(EffectNames.GLOW, radius, color);
388
    }
389
  }
(3-3/26)