Project

General

Profile

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

library / src / main / java / org / distorted / library / effect / PostprocessEffect.java @ 8c57d77b

1 8eccf334 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2 cc62b34a Leszek Koltunski
// Copyright 2017 Leszek Koltunski  leszek@koltunski.pl                                          //
3 8eccf334 Leszek Koltunski
//                                                                                               //
4 46b572b5 Leszek Koltunski
// This file is part of Distorted.                                                               //
5 8eccf334 Leszek Koltunski
//                                                                                               //
6 cc62b34a Leszek Koltunski
// This library is free software; you can redistribute it and/or                                 //
7
// modify it under the terms of the GNU Lesser General Public                                    //
8
// License as published by the Free Software Foundation; either                                  //
9
// version 2.1 of the License, or (at your option) any later version.                            //
10 8eccf334 Leszek Koltunski
//                                                                                               //
11 cc62b34a Leszek Koltunski
// This library is distributed in the hope that it will be useful,                               //
12 8eccf334 Leszek Koltunski
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13 cc62b34a Leszek Koltunski
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                             //
14
// Lesser General Public License for more details.                                               //
15 8eccf334 Leszek Koltunski
//                                                                                               //
16 cc62b34a Leszek Koltunski
// You should have received a copy of the GNU Lesser General Public                              //
17
// License along with this library; if not, write to the Free Software                           //
18
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
19 8eccf334 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
20
21
package org.distorted.library.effect;
22
23 43814a57 Leszek Koltunski
import org.distorted.library.effectqueue.EffectQueue;
24 9e771d06 Leszek Koltunski
import org.distorted.library.main.DistortedFramebuffer;
25 8c57d77b Leszek Koltunski
import org.distorted.library.main.DistortedLibrary;
26 7602a827 Leszek Koltunski
import org.distorted.library.main.InternalMaster;
27 aa2f0486 Leszek Koltunski
import org.distorted.library.program.DistortedProgram;
28 1dfc9074 leszek
29 2f1f7570 Leszek Koltunski
import java.lang.reflect.Method;
30 1dfc9074 leszek
import java.nio.ByteBuffer;
31
import java.nio.ByteOrder;
32
import java.nio.FloatBuffer;
33 aa2f0486 Leszek Koltunski
import java.util.ArrayList;
34 1dfc9074 leszek
35 8eccf334 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
36 faa3ff56 Leszek Koltunski
/**
37 a20f274f Leszek Koltunski
 * Abstract class that represents an Effect that works by running a certain Shader Program(s) on a Framebuffer.
38 faa3ff56 Leszek Koltunski
 */
39 7602a827 Leszek Koltunski
public abstract class PostprocessEffect extends Effect implements InternalMaster.Slave
40 8eccf334 Leszek Koltunski
  {
41 86d322b5 Leszek Koltunski
  private static final int MIPMAP = 0;
42 96e3b88a Leszek Koltunski
  /**
43
   * 5 per-effect interpolated values.
44
   */
45
  public static final int NUM_FLOAT_UNIFORMS = 6;
46
  /**
47
   * 1: the name of the effect
48
   */
49
  public static final int NUM_INT_UNIFORMS = 1;
50 125cee3d Leszek Koltunski
51 faa3ff56 Leszek Koltunski
  static final int POS_DATA_SIZE= 2;
52
  static final int TEX_DATA_SIZE= 2;
53 1dfc9074 leszek
54
  static final FloatBuffer mQuadPositions, mQuadTexture, mQuadTextureInv;
55
56
  static
57
    {
58
    int dataLength      = 4;
59
    int bytes_per_float = 4;
60
61
    float[] position  = { -0.5f, -0.5f,  -0.5f, 0.5f,  0.5f,-0.5f,  0.5f, 0.5f };
62
    float[] textureNor= {  0.0f,  0.0f,   0.0f, 1.0f,  1.0f, 0.0f,  1.0f, 1.0f };
63
    float[] textureInv= {  0.0f,  0.0f,   1.0f, 0.0f,  0.0f, 1.0f,  1.0f, 1.0f };
64
65
    mQuadPositions = ByteBuffer.allocateDirect(POS_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
66
    mQuadPositions.put(position).position(0);
67 031fbe7a Leszek Koltunski
    mQuadTexture   = ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
68 1dfc9074 leszek
    mQuadTexture.put(textureNor).position(0);
69
    mQuadTextureInv= ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
70
    mQuadTextureInv.put(textureInv).position(0);
71
    }
72
73 aa2f0486 Leszek Koltunski
  private static class Source
74
    {
75 d58407a8 Leszek Koltunski
    private final String mName, mVertexShader, mFragmentShader;
76 aa2f0486 Leszek Koltunski
77 86d322b5 Leszek Koltunski
    Source(String name, String vertex, String fragment)
78 aa2f0486 Leszek Koltunski
      {
79
      mName           = name;
80
      mVertexShader   = vertex;
81
      mFragmentShader = fragment;
82
      }
83
    }
84
85
  static ArrayList<DistortedProgram> mPrograms = new ArrayList<>();
86 d58407a8 Leszek Koltunski
  private final static ArrayList<Source> mSources = new ArrayList<>();
87 aa2f0486 Leszek Koltunski
  private static int mNumSources = 0;
88
89 b7074bc6 Leszek Koltunski
  private static class Job
90 86d322b5 Leszek Koltunski
    {
91
    int type;
92
    int level;
93
94
    Job(int t, int l)
95
      {
96
      type = t;
97
      level= l;
98
      }
99
    }
100
101 d58407a8 Leszek Koltunski
  private final ArrayList<Job> mJobs = new ArrayList<>();
102 b7074bc6 Leszek Koltunski
  private int mQualityLevel;
103 5c84d9c2 Leszek Koltunski
  private boolean mUseHaloDepth;
104 86d322b5 Leszek Koltunski
105
  float mQualityScale;
106
107 aa2f0486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
108
109
  static int register(final String name, final String vertexShader, final String fragmentShader)
110
    {
111
    mSources.add(new Source(name,vertexShader,fragmentShader));
112
113
    return mNumSources++;
114
    }
115
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117 faa3ff56 Leszek Koltunski
/**
118
 * Only for use by the library itself.
119
 *
120
 * @y.exclude
121
 */
122 b7074bc6 Leszek Koltunski
  public static void createPrograms(int GLSL)
123 aa2f0486 Leszek Koltunski
    {
124
    Source source;
125
    int len = mSources.size();
126
127 b7074bc6 Leszek Koltunski
    String version = "#version "+GLSL+" es\n";
128
129 aa2f0486 Leszek Koltunski
    for(int i=0; i<len; i++)
130
      {
131
      source = mSources.remove(0);
132
133
      try
134
        {
135 b7074bc6 Leszek Koltunski
        mPrograms.add (new DistortedProgram(version+source.mVertexShader,version+source.mFragmentShader));
136 aa2f0486 Leszek Koltunski
        }
137
      catch(Exception e)
138
        {
139 8c57d77b Leszek Koltunski
        DistortedLibrary.logMessage("PostproocessEffect: exception trying to compile "+source.mName+" program: "+e.getMessage());
140 aa2f0486 Leszek Koltunski
        throw new RuntimeException(e.getMessage());
141
        }
142
      }
143
    }
144
145 1dfc9074 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
146 faa3ff56 Leszek Koltunski
/**
147 d58407a8 Leszek Koltunski
 * At this moment the 'buffer' contains a) preprocessed object b) real object rendered 'on top' of
148
 * the preprocessed one.
149
 * Postprocess buffer. What this means exactly depends on the effect -
150
 *
151 faa3ff56 Leszek Koltunski
 * Only for use by the library itself.
152
 *
153
 * @y.exclude
154
 */
155 d58407a8 Leszek Koltunski
  public abstract int postprocess(float[] uniforms, int index, DistortedFramebuffer buffer);
156 86d322b5 Leszek Koltunski
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158 9e771d06 Leszek Koltunski
  /**
159 f90fe926 Leszek Koltunski
   * Do we render the object directly to the final surface, and only postprocess and then blit its
160
   * 'halo', or do we render the object along with its halo to the intermediate framebuffer and
161
   * postprocess it as well?
162
   *
163 9e771d06 Leszek Koltunski
   * Only for use by the library itself.
164
   *
165
   * @y.exclude
166
   */
167 d58407a8 Leszek Koltunski
  public abstract boolean getRenderDirectly();
168 7266d8ef Leszek Koltunski
169 247d8225 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
170
  /**
171
   * Only for use by the library itself.
172
   *
173
   * @y.exclude
174
   */
175 9e771d06 Leszek Koltunski
  public int getQuality()
176 247d8225 Leszek Koltunski
    {
177 9e771d06 Leszek Koltunski
    return mQualityLevel;
178 247d8225 Leszek Koltunski
    }
179
180 5c84d9c2 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
181
  /**
182
   * Only for use by the library itself.
183
   *
184
   * @y.exclude
185
   */
186
  public boolean getHaloDepth()
187
    {
188
    return mUseHaloDepth;
189
    }
190
191 43814a57 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
192
/**
193
 * Only for use by the library itself.
194
 *
195
 * @y.exclude
196
 */
197
  public void addQueue(EffectQueue queue)
198
    {
199
    // NO OP
200
    }
201
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203
/**
204
 * Only for use by the library itself.
205
 *
206
 * @y.exclude
207
 */
208
  public void remQueue(EffectQueue queue)
209
    {
210
    // NO OP
211
    }
212
213 86d322b5 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
214
/**
215
 * This is not really part of the public API. Has to be public only because it is a part of the
216
 * DistortedSlave interface, which should really be a class that we extend here instead but
217
 * Java has no multiple inheritance.
218
 *
219
 * @y.exclude
220
 */
221
  public void doWork()
222
    {
223
    int num = mJobs.size();
224
    Job job;
225
226
    for(int i=0; i<num; i++)
227
      {
228
      job = mJobs.remove(0);
229
230
      switch(job.type)
231
        {
232
        case MIPMAP: int level = job.level;
233
                     mQualityLevel = level;
234
                     mQualityScale = 1.0f;
235
                     for(int j=0; j<level; j++) mQualityScale*= EffectQuality.MULTIPLIER;
236
                     break;
237
        }
238
      }
239
    }
240 1dfc9074 leszek
241 2f1f7570 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
242
243
  static void destroyStatics()
244
    {
245
    mPrograms.clear();
246
    mSources.clear();
247
    mNumSources = 0;
248
249 7a1fcbeb Leszek Koltunski
    Method method;
250 2f1f7570 Leszek Koltunski
251
    for(EffectName name: EffectName.values())
252
      {
253
      if( name.getType() == EffectType.POSTPROCESS )
254
        {
255
        Class<? extends Effect> cls = name.getEffectClass();
256
257
        try
258
          {
259 7a1fcbeb Leszek Koltunski
          method = cls.getDeclaredMethod("destroyStatics");  // destroyStatics not public, thus getDeclaredMethod
260 2f1f7570 Leszek Koltunski
          }
261
        catch(NoSuchMethodException ex)
262
          {
263 8c57d77b Leszek Koltunski
          DistortedLibrary.logMessage("PostprocessEffect: "+cls.getSimpleName()+": exception getting method: "+ex.getMessage());
264 7a1fcbeb Leszek Koltunski
          method = null;
265 2f1f7570 Leszek Koltunski
          }
266
267
        try
268
          {
269 7a1fcbeb Leszek Koltunski
          if( method!=null ) method.invoke(null);
270 2f1f7570 Leszek Koltunski
          }
271
        catch(Exception ex)
272
          {
273 8c57d77b Leszek Koltunski
          DistortedLibrary.logMessage("PostprocessEffect: exception invoking method: "+ex.getMessage());
274 2f1f7570 Leszek Koltunski
          }
275
        }
276
      }
277
    }
278
279 b547aaba leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
280
281 a0d5e302 Leszek Koltunski
  PostprocessEffect(EffectName name)
282 b547aaba leszek
    {
283 9d0d8530 leszek
    super(name);
284 86d322b5 Leszek Koltunski
285
    mQualityLevel = 0;
286
    mQualityScale = 1.0f;
287 cc2367fe Leszek Koltunski
    mUseHaloDepth = true;
288 86d322b5 Leszek Koltunski
    }
289
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291
// PUBLIC API
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293
/**
294
 * The higher the quality, the better the effect will look like and the slower it will be.
295
 * <p>
296
 * This works by rendering into smaller and smaller intermediate buffers. Each step renders into a
297
 * buffer that's half the size of the previous one.
298
 * <p>
299
 * We cannot this during mid-render - thus, give it to the Master to assign us back this job on the
300
 * next render.
301
 */
302
  public void setQuality(EffectQuality quality)
303
    {
304
    mJobs.add(new Job(MIPMAP,quality.getLevel()));
305 7602a827 Leszek Koltunski
    InternalMaster.newSlave(this);
306 b547aaba leszek
    }
307 5c84d9c2 Leszek Koltunski
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309
/**
310
 * When preprocessing - so drawning the 'halo' - do we also want to write the depth buffer?
311
 * If yes, the halo would cover the whole object; if no, it would be just around it (and possibly
312
 * could be covered by other similarly postprocessed objects nearby)
313
 *
314
 * @param depth should the halo around the object cover it or not?
315
 */
316
  public void setHaloDepth(boolean depth)
317
    {
318
    mUseHaloDepth = depth;
319
    }
320 8eccf334 Leszek Koltunski
  }