Project

General

Profile

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

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

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

    
27
import java.util.ArrayList;
28

    
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

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

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

    
49
  private EffectQueuePostprocess mP;
50

    
51
  private boolean postprocessCloned;
52

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

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

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

    
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

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

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84

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

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91

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

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

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

    
103
    mP = null;
104
    }
105

    
106
///////////////////////////////////////////////////////////////////////////////////////////////////
107

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

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114

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

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

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

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

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

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

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

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

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

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

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

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

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

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

    
270
    if( type==Effect.POSTPROCESS ) return mP.removeByID(id>>Effect.LENGTH);
271

    
272
    return 0;
273
    }
274

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

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

    
306
    return false;
307
    }
308

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

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

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

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

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