Project

General

Profile

« Previous | Next » 

Revision 432442f9

Added by Leszek Koltunski over 7 years ago

New DistortedProgram class.

View differences:

src/main/java/org/distorted/library/Distorted.java
19 19

  
20 20
package org.distorted.library;
21 21

  
22
import java.io.BufferedReader;
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.io.InputStreamReader;
26

  
27 22
import android.content.Context;
28 23
import android.opengl.GLES20;
29
import android.os.Build;
24
import org.distorted.library.program.*;
30 25

  
31
import org.distorted.library.exception.*;
26
import java.io.InputStream;
32 27

  
33 28
///////////////////////////////////////////////////////////////////////////////////////////////////
34 29
/**
......
77 72

  
78 73
  private static boolean mInitialized = false;
79 74

  
80
  static int mPositionH;       // model position information
81
  static int mNormalH;         // model normal information.
82
  static int mTextureCoordH;   // model texture coordinate information.
75
  static int[] mAttributes;
83 76

  
84 77
///////////////////////////////////////////////////////////////////////////////////////////////////
85 78

  
......
88 81
    
89 82
    }
90 83

  
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92
  
93
  private static void sanitizeMaxValues() throws VertexUniformsException,FragmentUniformsException
94
    {
95
    int maxV,maxF;  
96
    int[] param = new int[1];
97
    
98
    GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
99
    maxV = param[0];
100
    GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
101
    maxF = param[0];
102
    
103
    //Log.d("Distorted", "Max vectors in vertex shader: "+maxV);
104
    //Log.d("Distorted", "Max vectors in fragment shader: "+maxF);
105
    
106
    if( !Build.FINGERPRINT.contains("generic") )
107
      {
108
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
109
      int realMaxF = (maxF- 2)/4;   //
110
    
111
      if( getMaxVertex()   > realMaxV )
112
        {
113
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
114
        }
115
      if( getMaxFragment() > realMaxF )
116
        {
117
        throw new FragmentUniformsException("Too many effects in the fragment shader, max is "+realMaxF, realMaxF);
118
        }
119
      }
120
    }
121
  
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

  
124
  private static int compileShader(final int shaderType, final String shaderSource) throws FragmentCompilationException,VertexCompilationException
125
    {
126
    int shaderHandle = GLES20.glCreateShader(shaderType);
127

  
128
    if (shaderHandle != 0) 
129
      {
130
      GLES20.glShaderSource(shaderHandle, "#version 100 \n"+ generateShaderHeader(shaderType) + shaderSource);
131
      GLES20.glCompileShader(shaderHandle);
132
      final int[] compileStatus = new int[1];
133
      GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
134

  
135
      if (compileStatus[0] != GLES20.GL_TRUE ) 
136
        {
137
        GLES20.glDeleteShader(shaderHandle);
138
        shaderHandle = 0;
139
        }
140
      }
141

  
142
    if (shaderHandle == 0)
143
      {     
144
      String error = GLES20.glGetShaderInfoLog(shaderHandle);
145
     
146
      switch(shaderType)
147
        {
148
        case GLES20.GL_VERTEX_SHADER  : throw new VertexCompilationException(error); 
149
        case GLES20.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
150
        default                       : throw new RuntimeException(error);
151
        }
152
      }
153

  
154
    return shaderHandle;
155
    }
156

  
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

  
159
  private static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) throws LinkingException
160
    {
161
    int programHandle = GLES20.glCreateProgram();
162

  
163
    if (programHandle != 0) 
164
      {
165
      GLES20.glAttachShader(programHandle, vertexShaderHandle);         
166
      GLES20.glAttachShader(programHandle, fragmentShaderHandle);
167

  
168
      if (attributes != null)
169
        {
170
        final int size = attributes.length;
171

  
172
        for (int i = 0; i < size; i++)
173
          {
174
          GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
175
          }                
176
        }
177

  
178
      GLES20.glLinkProgram(programHandle);
179

  
180
      final int[] linkStatus = new int[1];
181
      GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
182

  
183
      if (linkStatus[0] != GLES20.GL_TRUE ) 
184
        {         
185
        String error = GLES20.glGetProgramInfoLog(programHandle);
186
        GLES20.glDeleteProgram(programHandle);
187
        throw new LinkingException(error);
188
        }
189
      
190
      final int[] numberOfUniforms = new int[1];
191
      GLES20.glGetProgramiv(programHandle, GLES20.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
192

  
193
      //android.util.Log.d("Distorted", "number of active uniforms="+numberOfUniforms[0]);
194
      }
195
 
196
    return programHandle;
197
    }
198
 
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200
  
201
  private static String generateShaderHeader(final int type)
202
    {
203
    String header="";
204
   
205
    switch(type)
206
      {
207
      case GLES20.GL_VERTEX_SHADER  : header += ("#define NUM_VERTEX "  + getMaxVertex()+"\n");
208
     
209
                                      for(EffectNames name: EffectNames.values() )
210
                                        {
211
                                        if( name.getType()==EffectTypes.VERTEX)
212
                                        header += ("#define "+name.name()+" "+name.ordinal()+"\n");  
213
                                        }
214
                                      break;
215
      case GLES20.GL_FRAGMENT_SHADER: header += ("#define NUM_FRAGMENT "+ getMaxFragment()+"\n");
216
     
217
                                      for(EffectNames name: EffectNames.values() )
218
                                        {
219
                                        if( name.getType()==EffectTypes.FRAGMENT)
220
                                        header += ("#define "+name.name()+" "+name.ordinal()+"\n");  
221
                                        }
222
                                      break;
223
     }
224
   
225
    //Log.d(TAG,""+header);
226
    
227
    return header;
228
    }
229
  
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231
  
232
  private static String readTextFileFromRawResource(final Context c, final int resourceId)
233
    {
234
    final InputStream inputStream = c.getResources().openRawResource(resourceId);
235
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
236
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
237
 
238
    String nextLine;
239
    final StringBuilder body = new StringBuilder();
240
 
241
    try
242
      {
243
      while ((nextLine = bufferedReader.readLine()) != null)
244
        {
245
        body.append(nextLine);
246
        body.append('\n');
247
        }
248
      }
249
    catch (IOException e)
250
      {
251
      return null;
252
      }
253
 
254
    return body.toString();
255
    }
256
 
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258
 
259
  private static String getVertexShader(final Context c)
260
    {
261
    return readTextFileFromRawResource( c, R.raw.main_vertex_shader);
262
    }
263
 
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265
 
266
  private static String getFragmentShader(final Context c)
267
    {
268
    return readTextFileFromRawResource( c, R.raw.main_fragment_shader);
269
    }
270

  
271 84
///////////////////////////////////////////////////////////////////////////////////////////////////
272 85

  
273 86
  static boolean isInitialized()
......
278 91
///////////////////////////////////////////////////////////////////////////////////////////////////
279 92
/**
280 93
 * When OpenGL context gets created, you need to call this method so that the library can initialise its internal data structures.
281
 * I.e. best called from GLSurfaceView.onSurfaceCreated().
94
 * I.e. best called from GLSurfaceView.onCreate().
282 95
 * <p>
283
 * Compiles the vertex and fragment shaders, establishes the addresses of all uniforms.
96
 * Needs to be called from a thread holding the OpenGL context.
284 97
 *   
285 98
 * @param context Context of the App using the library - used to open up Resources and read Shader code.
286 99
 * @throws FragmentCompilationException
......
289 102
 * @throws FragmentUniformsException
290 103
 * @throws LinkingException
291 104
 */
292
  public static void onSurfaceCreated(final Context context) throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
105
  public static void onCreate(final Context context)
106
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
293 107
    { 
294 108
    mInitialized = true;  
295 109

  
296
    final String vertexShader   = Distorted.getVertexShader(context);
297
    final String fragmentShader = Distorted.getFragmentShader(context);
298

  
299
    sanitizeMaxValues();
300
    
301
    final int vertexShaderHandle   = compileShader(GLES20.GL_VERTEX_SHADER  , vertexShader  );     
302
    final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);     
303
      
304
    int programH = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, new String[] {"a_Position",  "a_Color", "a_Normal", "a_TexCoordinate"});
110
    final InputStream vertexStream   = context.getResources().openRawResource(R.raw.main_vertex_shader);
111
    final InputStream fragmentStream = context.getResources().openRawResource(R.raw.main_fragment_shader);
305 112

  
113
    DistortedProgram mainProgram = new DistortedProgram(vertexStream,fragmentStream);
114
    int programH = mainProgram.getProgramHandle();
306 115
    GLES20.glUseProgram(programH);
116
    mainProgram.bindAndEnableAttributes();
117
    mAttributes = mainProgram.getAttributes();
307 118

  
308 119
    int textureUniformH = GLES20.glGetUniformLocation(programH, "u_Texture");
309
    mPositionH          = GLES20.glGetAttribLocation( programH, "a_Position");
310
    mNormalH            = GLES20.glGetAttribLocation( programH, "a_Normal");
311
    mTextureCoordH      = GLES20.glGetAttribLocation( programH, "a_TexCoordinate");
312 120

  
313 121
    GLES20.glEnable (GLES20.GL_DEPTH_TEST);
314 122
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
......
323 131
    EffectQueueFragment.getUniforms(programH);
324 132
    EffectQueueVertex.getUniforms(programH);
325 133
    EffectQueueMatrix.getUniforms(programH);
326
    
327
    GLES20.glEnableVertexAttribArray(mPositionH);        
328
    GLES20.glEnableVertexAttribArray(mNormalH);
329
    GLES20.glEnableVertexAttribArray(mTextureCoordH);
330
   
134

  
331 135
    DistortedTree.reset();
332 136
    EffectMessageSender.startSending();
333 137
    }
......
348 152
   
349 153
    mInitialized = false;
350 154
    }
351

  
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353
/**
354
 * Returns the maximum number of Matrix effects.
355
 *    
356
 * @return The maximum number of Matrix effects
357
 */
358
  public static int getMaxMatrix()
359
    {
360
    return EffectQueue.getMax(EffectTypes.MATRIX.ordinal());
361
    }
362
 
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
/**
365
 * Returns the maximum number of Vertex effects.
366
 *    
367
 * @return The maximum number of Vertex effects
368
 */  
369
  public static int getMaxVertex()
370
    {
371
    return EffectQueue.getMax(EffectTypes.VERTEX.ordinal());
372
    }
373
  
374
///////////////////////////////////////////////////////////////////////////////////////////////////
375
/**
376
 * Returns the maximum number of Fragment effects.
377
 *    
378
 * @return The maximum number of Fragment effects
379
 */  
380
  public static int getMaxFragment()
381
    {
382
    return EffectQueue.getMax(EffectTypes.FRAGMENT.ordinal());
383
    }
384

  
385
///////////////////////////////////////////////////////////////////////////////////////////////////
386
/**
387
 * Returns the maximum number of Postprocess effects.
388
 *
389
 * @return The maximum number of Postprocess effects
390
 */
391
  public static int getMaxPostprocess()
392
    {
393
    return EffectQueue.getMax(EffectTypes.POSTPROCESS.ordinal());
394
    }
395

  
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397
/**
398
 * Sets the maximum number of Matrix effects that can be stored in a single EffectQueue at one time.
399
 * This can fail if:
400
 * <ul>
401
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
402
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
403
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
404
 *     time only decreasing the value of 'max' is permitted.
405
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
406
 * </ul>
407
 * 
408
 * @param max new maximum number of simultaneous Matrix Effects. Has to be a non-negative number not greater
409
 *            than Byte.MAX_VALUE 
410
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
411
 */
412
  public static boolean setMaxMatrix(int max)
413
    {
414
    return EffectQueue.setMax(EffectTypes.MATRIX.ordinal(),max);
415
    }
416
  
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418
/**
419
 * Sets the maximum number of Vertex effects that can be stored in a single EffectQueue at one time.
420
 * This can fail if:
421
 * <ul>
422
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
423
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called 
424
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
425
 *     time only decreasing the value of 'max' is permitted.
426
* <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
427
 * </ul>
428
 * 
429
 * @param max new maximum number of simultaneous Vertex Effects. Has to be a non-negative number not greater
430
 *            than Byte.MAX_VALUE 
431
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
432
 */
433
  public static boolean setMaxVertex(int max)
434
    {
435
    return EffectQueue.setMax(EffectTypes.VERTEX.ordinal(),max);
436
    }
437

  
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439
/**
440
 * Sets the maximum number of Fragment effects that can be stored in a single EffectQueue at one time.
441
 * This can fail if:
442
 * <ul>
443
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
444
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called 
445
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
446
 *     time only decreasing the value of 'max' is permitted.
447
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
448
 * </ul>
449
 * 
450
 * @param max new maximum number of simultaneous Fragment Effects. Has to be a non-negative number not greater
451
 *            than Byte.MAX_VALUE 
452
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
453
 */
454
  public static boolean setMaxFragment(int max)
455
    {
456
    return EffectQueue.setMax(EffectTypes.FRAGMENT.ordinal(),max);
457
    }
458

  
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460
/**
461
 * Sets the maximum number of Postprocess effects that can be stored in a single EffectQueue at one time.
462
 * This can fail if:
463
 * <ul>
464
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
465
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
466
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
467
 *     time only decreasing the value of 'max' is permitted.
468
 * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
469
 * </ul>
470
 *
471
 * @param max new maximum number of simultaneous Postprocess Effects. Has to be a non-negative number not greater
472
 *            than Byte.MAX_VALUE
473
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
474
 */
475
  public static boolean setMaxPostprocess(int max)
476
    {
477
    return EffectQueue.setMax(EffectTypes.POSTPROCESS.ordinal(),max);
478
    }
479 155
  }

Also available in: Unified diff