Project

General

Profile

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

library / src / main / java / org / distorted / library / DistortedEffectsPostprocess.java @ 984dc935

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
  int getHalo()
114
    {
115
    return mP.getHalo();
116
    }
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

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

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

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

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

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

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

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

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

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

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

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

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

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

    
270
    return 0;
271
    }
272

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

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

    
304
    return false;
305
    }
306

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

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

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

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