Project

General

Profile

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

library / src / main / java / org / distorted / library / EffectQueuePostprocess.java @ a225e5aa

1 4c1dd6e9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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;
21
22 c90b9e01 Leszek Koltunski
import android.content.res.Resources;
23 194ab46f Leszek Koltunski
import android.opengl.GLES30;
24 1c67457f Leszek Koltunski
import android.opengl.Matrix;
25 4c1dd6e9 Leszek Koltunski
26
import org.distorted.library.message.EffectMessage;
27 8fa96e69 Leszek Koltunski
import org.distorted.library.program.DistortedProgram;
28 c90b9e01 Leszek Koltunski
import org.distorted.library.program.FragmentCompilationException;
29
import org.distorted.library.program.FragmentUniformsException;
30
import org.distorted.library.program.LinkingException;
31
import org.distorted.library.program.VertexCompilationException;
32
import org.distorted.library.program.VertexUniformsException;
33 4c1dd6e9 Leszek Koltunski
import org.distorted.library.type.Data1D;
34
import org.distorted.library.type.Dynamic1D;
35
import org.distorted.library.type.Static1D;
36
37 c90b9e01 Leszek Koltunski
import java.io.InputStream;
38 8fa96e69 Leszek Koltunski
import java.nio.ByteBuffer;
39
import java.nio.ByteOrder;
40
import java.nio.FloatBuffer;
41
42 4c1dd6e9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
43
44
class EffectQueuePostprocess extends EffectQueue
45
  {
46 a225e5aa Leszek Koltunski
  private static final float GAUSSIAN[] =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
47
    {                                       // where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2). The last 0 terminates.
48 99218642 Leszek Koltunski
    0.398948f, 0.398769f, 0.398231f, 0.397336f, 0.396086f, 0.394485f, 0.392537f, 0.390247f, 0.387622f, 0.384668f,
49
    0.381393f, 0.377806f, 0.373916f, 0.369733f, 0.365268f, 0.360532f, 0.355538f, 0.350297f, 0.344823f, 0.339129f,
50
    0.333229f, 0.327138f, 0.320868f, 0.314436f, 0.307856f, 0.301142f, 0.294309f, 0.287373f, 0.280348f, 0.273248f,
51
    0.266089f, 0.258884f, 0.251648f, 0.244394f, 0.237135f, 0.229886f, 0.222657f, 0.215461f, 0.208311f, 0.201217f,
52
    0.194189f, 0.187238f, 0.180374f, 0.173605f, 0.166940f, 0.160386f, 0.153951f, 0.147641f, 0.141462f, 0.135420f,
53
    0.129520f, 0.123765f, 0.118159f, 0.112706f, 0.107408f, 0.102266f, 0.097284f, 0.092461f, 0.087797f, 0.083294f,
54
    0.078951f, 0.074767f, 0.070741f, 0.066872f, 0.063158f, 0.059596f, 0.056184f, 0.052920f, 0.049801f, 0.046823f,
55
    0.043984f, 0.041280f, 0.038707f, 0.036262f, 0.033941f, 0.031740f, 0.029655f, 0.027682f, 0.025817f, 0.024056f,
56
    0.022395f, 0.020830f, 0.019357f, 0.017971f, 0.016670f, 0.015450f, 0.014305f, 0.013234f, 0.012232f, 0.011295f,
57
    0.010421f, 0.009606f, 0.008847f, 0.008140f, 0.007483f, 0.006873f, 0.006307f, 0.005782f, 0.005296f, 0.004847f,
58 a225e5aa Leszek Koltunski
    0.004432f, 0.000000f
59 99218642 Leszek Koltunski
    };
60 a225e5aa Leszek Koltunski
  private static final int NUM_GAUSSIAN = GAUSSIAN.length-2;
61 99218642 Leszek Koltunski
62 0d81d0fb Leszek Koltunski
  private static final int MAX_BLUR = 50;
63
64 9d5bb851 Leszek Koltunski
  private static final int POS_DATA_SIZE= 2; // Post Program: size of the position data in elements
65
  private static final int TEX_DATA_SIZE= 2; // Post Program: size of the texture coordinate data in elements.
66 8fa96e69 Leszek Koltunski
67 667a1ad9 Leszek Koltunski
  private static final int NUM_UNIFORMS = 4;
68 4c1dd6e9 Leszek Koltunski
  private static final int NUM_CACHE    = 0;
69
  private static final int INDEX = EffectTypes.POSTPROCESS.ordinal();
70
71 1c67457f Leszek Koltunski
  private static final FloatBuffer mQuadPositions, mQuadTextureNor, mQuadTextureInv;
72 8fa96e69 Leszek Koltunski
73
  static
74
    {
75 667a1ad9 Leszek Koltunski
    int dataLength      = 4;
76
    int bytes_per_float = 4;
77 8fa96e69 Leszek Koltunski
78 1c67457f Leszek Koltunski
    float[] position  = { -0.5f, -0.5f,  -0.5f, 0.5f,  0.5f,-0.5f,  0.5f, 0.5f };
79
    float[] textureNor= {  0.0f,  0.0f,   0.0f, 1.0f,  1.0f, 0.0f,  1.0f, 1.0f };
80
    float[] textureInv= {  0.0f,  0.0f,   1.0f, 0.0f,  0.0f, 1.0f,  1.0f, 1.0f };
81 8fa96e69 Leszek Koltunski
82 9d5bb851 Leszek Koltunski
    mQuadPositions = ByteBuffer.allocateDirect(POS_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
83 1c67457f Leszek Koltunski
    mQuadPositions.put(position).position(0);
84 9d5bb851 Leszek Koltunski
    mQuadTextureNor= ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
85 1c67457f Leszek Koltunski
    mQuadTextureNor.put(textureNor).position(0);
86 9d5bb851 Leszek Koltunski
    mQuadTextureInv= ByteBuffer.allocateDirect(TEX_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
87 1c67457f Leszek Koltunski
    mQuadTextureInv.put(textureInv).position(0);
88 8fa96e69 Leszek Koltunski
    }
89 4c1dd6e9 Leszek Koltunski
90 0d81d0fb Leszek Koltunski
  private static DistortedFramebuffer mBufferFBO = new DistortedFramebuffer(1,1);
91 1c67457f Leszek Koltunski
  private static float[] mMVPMatrix = new float[16];
92
  private static float[] mTmpMatrix = new float[16];
93 0d81d0fb Leszek Koltunski
94
  // BLUR effect
95
  private static DistortedProgram mBlurProgram;
96 5ccafcca Leszek Koltunski
  private static int mRadiusH,mOffsetsH,mWeightsH,mObjDH,mMVPMatrixH;
97 0d81d0fb Leszek Koltunski
  private float[] mWeights = new float[MAX_BLUR];
98 5ccafcca Leszek Koltunski
  private float[] mOffsets = new float[MAX_BLUR];
99 0d81d0fb Leszek Koltunski
  // another effect ....
100
101 4c1dd6e9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
102
103
  EffectQueuePostprocess(long id)
104
    { 
105
    super(id,NUM_UNIFORMS,NUM_CACHE,INDEX );
106
    }
107
108 c90b9e01 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
109
110
  static void createProgram(Resources resources)
111
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
112
    {
113 f1d5ea12 Leszek Koltunski
    final InputStream postVertexStream   = resources.openRawResource(R.raw.blur_vertex_shader);
114
    final InputStream postFragmentStream = resources.openRawResource(R.raw.blur_fragment_shader);
115 c90b9e01 Leszek Koltunski
116 0d81d0fb Leszek Koltunski
    mBlurProgram = new DistortedProgram(postVertexStream,postFragmentStream,
117
                                        "#version 100\n",
118
                                        "#version 100\n#define MAX_BLUR "+MAX_BLUR);
119 c90b9e01 Leszek Koltunski
120 f1d5ea12 Leszek Koltunski
    int blurProgramH = mBlurProgram.getProgramHandle();
121
    mRadiusH    = GLES30.glGetUniformLocation( blurProgramH, "u_Radius");
122 5ccafcca Leszek Koltunski
    mOffsetsH   = GLES30.glGetUniformLocation( blurProgramH, "u_Offsets");
123 0d81d0fb Leszek Koltunski
    mWeightsH   = GLES30.glGetUniformLocation( blurProgramH, "u_Weights");
124 f1d5ea12 Leszek Koltunski
    mObjDH      = GLES30.glGetUniformLocation( blurProgramH, "u_objD");
125
    mMVPMatrixH = GLES30.glGetUniformLocation( blurProgramH, "u_MVPMatrix");
126 4c1dd6e9 Leszek Koltunski
    }
127
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
  
130
  synchronized void compute(long currTime) 
131
    {
132
    if( currTime==mTime ) return;
133
    if( mTime==0 ) mTime = currTime;
134
    long step = (currTime-mTime);
135
   
136
    for(int i=0; i<mNumEffects; i++)
137
      {
138
      if( mInter[0][i]!=null && mInter[0][i].interpolateMain(mUniforms ,NUM_UNIFORMS*i, mCurrentDuration[i], step) )
139
        {
140
        for(int j=0; j<mNumListeners; j++)
141
          EffectMessageSender.newMessage( mListeners.elementAt(j),
142
                                          EffectMessage.EFFECT_FINISHED,
143
                                         (mID[i]<<EffectTypes.LENGTH)+EffectTypes.POSTPROCESS.type,
144
                                          mName[i],
145
                                          mObjectID);
146
147
        if( EffectNames.isUnity(mName[i], mUniforms, NUM_UNIFORMS*i) )
148
          {
149
          remove(i);
150
          i--;
151
          continue;
152
          }
153
        else mInter[0][i] = null;
154
        }
155
156
      mCurrentDuration[i] += step;
157
      }
158
     
159
    mTime = currTime;  
160
    }  
161
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163
164
  protected void moveEffect(int index)
165
    {
166
    mUniforms[NUM_UNIFORMS*index  ] = mUniforms[NUM_UNIFORMS*(index+1)  ];
167
    mUniforms[NUM_UNIFORMS*index+1] = mUniforms[NUM_UNIFORMS*(index+1)+1];
168
    mUniforms[NUM_UNIFORMS*index+2] = mUniforms[NUM_UNIFORMS*(index+1)+2];
169 667a1ad9 Leszek Koltunski
    mUniforms[NUM_UNIFORMS*index+3] = mUniforms[NUM_UNIFORMS*(index+1)+3];
170 4c1dd6e9 Leszek Koltunski
    }
171
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173
174 9d5bb851 Leszek Koltunski
  private int computeKernel(int radius, float height)
175 4c1dd6e9 Leszek Koltunski
    {
176 0d81d0fb Leszek Koltunski
    if( radius>=MAX_BLUR ) radius = MAX_BLUR-1;
177
178 a225e5aa Leszek Koltunski
    // Box Blur size 'radius'
179
/*
180 0d81d0fb Leszek Koltunski
    for(int i=0; i<=radius; i++)
181
      {
182
      mWeights[i] = 1.0f / (2.0f*radius+1.0f);
183 9d5bb851 Leszek Koltunski
      mOffsets[i] = i*height;
184 a225e5aa Leszek Koltunski
      }
185
*/
186
    // Gaussian Blur size 'radius'
187
188
    float P = (float)NUM_GAUSSIAN / (radius>3 ? radius:3);
189
    float x = 0.0f;
190
    mWeights[0] = GAUSSIAN[0];
191
    mOffsets[0] = 0.0f;
192
    float sum = GAUSSIAN[0];
193
    int j;
194
    float z;
195
196
    for(int i=1; i<=radius; i++)
197
      {
198
      x += P;
199
      j = (int)x;
200
      z = x-j;
201 9d5bb851 Leszek Koltunski
202 a225e5aa Leszek Koltunski
      mWeights[i] = (1-z)*GAUSSIAN[j] + z*GAUSSIAN[j+1];
203
      sum += 2*mWeights[i];
204
      mOffsets[i] = i*height;
205
      }
206 9d5bb851 Leszek Koltunski
207 a225e5aa Leszek Koltunski
    for(int i=0; i<=radius; i++)
208
      {
209
      mWeights[i] /= sum;
210
      }
211 9d5bb851 Leszek Koltunski
212 a225e5aa Leszek Koltunski
    // squash the weights and offsets for linear sampling
213
    int numloops = radius/2;
214
215
    for(int i=0; i<numloops; i++)
216
      {
217
      mOffsets[i+1] = mWeights[2*i+1]*mOffsets[2*i+1] + mWeights[2*i+2]*mOffsets[2*i+2];
218
      mWeights[i+1] = mWeights[2*i+1] + mWeights[2*i+2];
219
      mOffsets[i+1] /= mWeights[i+1];
220
      }
221
222
    if( radius%2 == 1 )
223
      {
224
      int index = radius/2 +1;
225
      mOffsets[index]=mOffsets[radius];
226
      mWeights[index]=mWeights[radius];
227
      radius = numloops+1;
228
      }
229
    else
230
      {
231
      radius = numloops;
232 0d81d0fb Leszek Koltunski
      }
233
234 9d5bb851 Leszek Koltunski
    return radius;
235
    }
236
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238
// w,h - width and height of the input texture. MVP - Model-View-Projection matrix to apply to the
239
// texture; df - output FBO.
240
241
  synchronized void render(float w, float h, float[] mvp, DistortedFramebuffer df)
242
    {
243
    mBlurProgram.useProgram();
244
245
    int radius = computeKernel( (int)mUniforms[0], 1/h );
246
247 0d81d0fb Leszek Koltunski
    GLES30.glUniform1fv( mWeightsH, radius+1, mWeights,0);
248
    GLES30.glUniform1i( mRadiusH, radius);
249 194ab46f Leszek Koltunski
    GLES30.glUniform2f( mObjDH , w, h );
250 4c1dd6e9 Leszek Koltunski
251 1c67457f Leszek Koltunski
    mBufferFBO.resizeFast( (int)w, (int)h);
252 0d81d0fb Leszek Koltunski
    mBufferFBO.setAsOutput();
253 1c67457f Leszek Koltunski
    GLES30.glViewport(0, 0, (int)w, (int)h);
254
255
    Matrix.setIdentityM(mTmpMatrix, 0);
256
    Matrix.translateM(mTmpMatrix, 0, 0, 0, -mBufferFBO.mDistance);
257
    Matrix.multiplyMM(mMVPMatrix, 0, mBufferFBO.mProjectionMatrix, 0, mTmpMatrix, 0);
258 0d81d0fb Leszek Koltunski
259
    // horizontal blur
260 9d5bb851 Leszek Koltunski
    GLES30.glUniform1fv( mOffsetsH ,radius+1, mOffsets,0);
261 1c67457f Leszek Koltunski
    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix , 0);
262 9d5bb851 Leszek Koltunski
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
263
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTextureInv);
264 0d81d0fb Leszek Koltunski
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
265
266
    mBufferFBO.setAsInput();
267
    df.setAsOutput();
268 1c67457f Leszek Koltunski
    GLES30.glViewport(0, 0, df.mWidth, df.mHeight);
269 0d81d0fb Leszek Koltunski
270 5ccafcca Leszek Koltunski
    float adjust = h/w;
271
    for(int i=0; i<=radius; i++) mOffsets[i] *= adjust;
272
273 0d81d0fb Leszek Koltunski
    // vertical blur
274 5ccafcca Leszek Koltunski
    GLES30.glUniform1fv( mOffsetsH ,radius+1, mOffsets,0);
275 1c67457f Leszek Koltunski
    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
276 9d5bb851 Leszek Koltunski
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
277
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTextureInv);
278 194ab46f Leszek Koltunski
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
279 d6e94c84 Leszek Koltunski
    }
280
281 4c1dd6e9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
282
// blur
283
284 85cbbc5e Leszek Koltunski
  synchronized long add(EffectNames eln, Data1D degree)
285 4c1dd6e9 Leszek Koltunski
    {
286
    if( mMax[INDEX]>mNumEffects )
287
      {
288
      if( degree instanceof Dynamic1D)
289
        {
290
        mInter[0][mNumEffects] = (Dynamic1D)degree;
291
        }
292
      else if( degree instanceof Static1D)
293
        {
294
        mInter[0][mNumEffects] = null;
295
        mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)degree).getX();
296
        }
297
      else return -1;
298
299 85cbbc5e Leszek Koltunski
      mInter[1][mNumEffects] = null;
300
      mInter[2][mNumEffects] = null;
301 4c1dd6e9 Leszek Koltunski
302
      return addBase(eln);
303
      }
304
      
305
    return -1;
306
    }
307
  }