Project

General

Profile

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

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

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