Project

General

Profile

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

library / src / main / java / org / distorted / library / EffectQueuePostprocess.java @ 93dca704

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 93dca704 Leszek Koltunski
  private int computeGaussianKernel(int radius)
175 4c1dd6e9 Leszek Koltunski
    {
176 0d81d0fb Leszek Koltunski
    if( radius>=MAX_BLUR ) radius = MAX_BLUR-1;
177
178 a225e5aa Leszek Koltunski
    float P = (float)NUM_GAUSSIAN / (radius>3 ? radius:3);
179
    float x = 0.0f;
180
    mWeights[0] = GAUSSIAN[0];
181
    mOffsets[0] = 0.0f;
182
    float sum = GAUSSIAN[0];
183
    int j;
184
    float z;
185
186
    for(int i=1; i<=radius; i++)
187
      {
188
      x += P;
189
      j = (int)x;
190
      z = x-j;
191 9d5bb851 Leszek Koltunski
192 a225e5aa Leszek Koltunski
      mWeights[i] = (1-z)*GAUSSIAN[j] + z*GAUSSIAN[j+1];
193
      sum += 2*mWeights[i];
194
      }
195 9d5bb851 Leszek Koltunski
196 a225e5aa Leszek Koltunski
    for(int i=0; i<=radius; i++)
197
      {
198
      mWeights[i] /= sum;
199
      }
200 9d5bb851 Leszek Koltunski
201 a225e5aa Leszek Koltunski
    // squash the weights and offsets for linear sampling
202
    int numloops = radius/2;
203
204
    for(int i=0; i<numloops; i++)
205
      {
206 93dca704 Leszek Koltunski
      mOffsets[i+1] = mWeights[2*i+1]*(2*i+1) + mWeights[2*i+2]*(2*i+2);
207 a225e5aa Leszek Koltunski
      mWeights[i+1] = mWeights[2*i+1] + mWeights[2*i+2];
208
      mOffsets[i+1] /= mWeights[i+1];
209
      }
210
211
    if( radius%2 == 1 )
212
      {
213
      int index = radius/2 +1;
214
      mOffsets[index]=mOffsets[radius];
215
      mWeights[index]=mWeights[radius];
216
      radius = numloops+1;
217
      }
218
    else
219
      {
220
      radius = numloops;
221 0d81d0fb Leszek Koltunski
      }
222
223 9d5bb851 Leszek Koltunski
    return radius;
224
    }
225
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227
// w,h - width and height of the input texture. MVP - Model-View-Projection matrix to apply to the
228
// texture; df - output FBO.
229
230
  synchronized void render(float w, float h, float[] mvp, DistortedFramebuffer df)
231
    {
232
    mBlurProgram.useProgram();
233
234 93dca704 Leszek Koltunski
    int radius = computeGaussianKernel( (int)mUniforms[0] );
235
236
    float adjust = 1/h;
237
    for(int i=0; i<=radius; i++) mOffsets[i] *= adjust;
238 9d5bb851 Leszek Koltunski
239 0d81d0fb Leszek Koltunski
    GLES30.glUniform1fv( mWeightsH, radius+1, mWeights,0);
240
    GLES30.glUniform1i( mRadiusH, radius);
241 194ab46f Leszek Koltunski
    GLES30.glUniform2f( mObjDH , w, h );
242 4c1dd6e9 Leszek Koltunski
243 1c67457f Leszek Koltunski
    mBufferFBO.resizeFast( (int)w, (int)h);
244 0d81d0fb Leszek Koltunski
    mBufferFBO.setAsOutput();
245 1c67457f Leszek Koltunski
    GLES30.glViewport(0, 0, (int)w, (int)h);
246
247
    Matrix.setIdentityM(mTmpMatrix, 0);
248
    Matrix.translateM(mTmpMatrix, 0, 0, 0, -mBufferFBO.mDistance);
249
    Matrix.multiplyMM(mMVPMatrix, 0, mBufferFBO.mProjectionMatrix, 0, mTmpMatrix, 0);
250 0d81d0fb Leszek Koltunski
251
    // horizontal blur
252 9d5bb851 Leszek Koltunski
    GLES30.glUniform1fv( mOffsetsH ,radius+1, mOffsets,0);
253 1c67457f Leszek Koltunski
    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix , 0);
254 9d5bb851 Leszek Koltunski
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
255
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTextureInv);
256 0d81d0fb Leszek Koltunski
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
257
258
    mBufferFBO.setAsInput();
259
    df.setAsOutput();
260 1c67457f Leszek Koltunski
    GLES30.glViewport(0, 0, df.mWidth, df.mHeight);
261 0d81d0fb Leszek Koltunski
262 93dca704 Leszek Koltunski
    adjust = h/w;
263 5ccafcca Leszek Koltunski
    for(int i=0; i<=radius; i++) mOffsets[i] *= adjust;
264
265 0d81d0fb Leszek Koltunski
    // vertical blur
266 5ccafcca Leszek Koltunski
    GLES30.glUniform1fv( mOffsetsH ,radius+1, mOffsets,0);
267 1c67457f Leszek Koltunski
    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
268 9d5bb851 Leszek Koltunski
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
269
    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTextureInv);
270 194ab46f Leszek Koltunski
    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
271 d6e94c84 Leszek Koltunski
    }
272
273 4c1dd6e9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
274
// blur
275
276 85cbbc5e Leszek Koltunski
  synchronized long add(EffectNames eln, Data1D degree)
277 4c1dd6e9 Leszek Koltunski
    {
278
    if( mMax[INDEX]>mNumEffects )
279
      {
280
      if( degree instanceof Dynamic1D)
281
        {
282
        mInter[0][mNumEffects] = (Dynamic1D)degree;
283
        }
284
      else if( degree instanceof Static1D)
285
        {
286
        mInter[0][mNumEffects] = null;
287
        mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)degree).getX();
288
        }
289
      else return -1;
290
291 85cbbc5e Leszek Koltunski
      mInter[1][mNumEffects] = null;
292
      mInter[2][mNumEffects] = null;
293 4c1dd6e9 Leszek Koltunski
294
      return addBase(eln);
295
      }
296
      
297
    return -1;
298
    }
299
  }