Project

General

Profile

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

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

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.effect.EffectType;
24
import org.distorted.library.message.EffectListener;
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
/**
232
 * Aborts all Effects.
233
 * @return Number of effects aborted.
234
 */
235
  public int abortAllEffects()
236
    {
237
    return mP.abortAll(true);
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241
/**
242
 * Aborts all Effects of a given type, for example all POSTPROCESS Effects.
243
 *
244
 * @param type one of the constants defined in {@link EffectType}
245
 * @return Number of effects aborted.
246
 */
247
  public int abortByType(EffectType 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 effect the Effect we want to abort.
261
 * @return number of Effects aborted. Always either 0 or 1.
262
 */
263
  public int abortEffect(Effect effect)
264
    {
265
    switch(effect.getType())
266
      {
267
      case POSTPROCESS: return mP.removeEffect(effect);
268
      default         : return 0;
269
      }
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273
/**
274
 * Returns the maximum number of Postprocess effects.
275
 *
276
 * @return The maximum number of Postprocess effects
277
 */
278
  @SuppressWarnings("unused")
279
  public static int getMaxPostprocess()
280
    {
281
    return EffectQueue.getMax(EffectType.POSTPROCESS.ordinal());
282
    }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285
/**
286
 * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
287
 * This can fail if:
288
 * <ul>
289
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
290
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
291
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link Distorted#onCreate}. After this
292
 *     time only decreasing the value of 'max' is permitted.
293
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
294
 * </ul>
295
 *
296
 * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
297
 *            than Byte.MAX_VALUE
298
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
299
 */
300
  @SuppressWarnings("unused")
301
  public static boolean setMaxPostprocess(int max)
302
    {
303
    return EffectQueue.setMax(EffectType.POSTPROCESS.ordinal(),max);
304
    }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
/**
308
 * The higher the quality, the better the effect will look like and the slower it will be.
309
 * <p>
310
 * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
311
 * buffer that's half the size of the previous one.
312
 * <p>
313
 * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
314
 * next render.
315
 */
316
  public void setQuality(EffectQuality quality)
317
    {
318
    mJobs.add(new Job(MIPMAP,quality.level));
319
    DistortedMaster.newSlave(this);
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323
/**
324
 * Add a new Effect to our queue.
325
 *
326
 * @param effect The Effect to add.
327
 */
328
  public void apply(Effect effect)
329
    {
330
    switch(effect.getType())
331
      {
332
      case POSTPROCESS : mP.add(effect); break;
333
      }
334
    }
335
  }
(3-3/24)