Project

General

Profile

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

library / src / main / java / org / distorted / library / effect / PostprocessEffect.java @ cc62b34a

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