Project

General

Profile

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

library / src / main / java / org / distorted / library / Distorted.java @ b6a5d557

1 d333eb6b 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 6a06a912 Leszek Koltunski
package org.distorted.library;
21
22
import java.io.BufferedReader;
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.io.InputStreamReader;
26
27 7845dc66 Leszek Koltunski
import android.content.Context;
28 6a06a912 Leszek Koltunski
import android.opengl.GLES20;
29
import android.os.Build;
30
31
import org.distorted.library.exception.*;
32
33
///////////////////////////////////////////////////////////////////////////////////////////////////
34
/**
35
 * A singleton class used to control various global settings.
36
 */
37
public class Distorted 
38 39cbf9dc Leszek Koltunski
  {
39 6a06a912 Leszek Koltunski
  /**
40 e8c81a8e Leszek Koltunski
   * When creating an instance of a DistortedObject from another instance, do not clone anything.
41 6a06a912 Leszek Koltunski
   * Used in the copy constructor.
42
   */
43
  public static final int CLONE_NOTHING = 0x0;
44
  /**
45
   * When creating an instance of a DistortedObject from another instance, clone the Bitmap that's
46
   * backing up our DistortedObject. 
47
   * <p>
48
   * This way we can have two DistortedObjects, both backed up by the same Bitmap, to which we can 
49
   * apply different effects. Used in the copy constructor.
50
   */
51
  public static final int CLONE_BITMAP  = 0x1;
52
  /**
53 015642fb Leszek Koltunski
   * When creating an instance of a DistortedObject from another instance, clone the Matrix Effects.
54 6a06a912 Leszek Koltunski
   * <p>
55
   * This way we can have two different DistortedObjects with different Bitmaps behind them, both 
56
   * always displayed in exactly the same place on the screen. Applying any matrix-based effect to 
57
   * one of them automatically applies the effect to the other. Used in the copy constructor.
58
   */
59 015642fb Leszek Koltunski
  public static final int CLONE_MATRIX = 0x2;
60 6a06a912 Leszek Koltunski
  /**
61
   * When creating an instance of a DistortedObject from another instance, clone the Vertex Effects.
62
   * <p>
63
   * This way we can have two different DistortedObjects with different Bitmaps behind them, both 
64
   * always with the same Vertex effects. Applying any vertex-based effect to one of them automatically 
65
   * applies the effect to the other. Used in the copy constructor.
66
   */
67
  public static final int CLONE_VERTEX  = 0x4;
68
  /**
69
   * When creating an instance of a DistortedObject from another instance, clone the Fragment Effects.
70
   * <p>
71
   * This way we can have two different DistortedObjects with different Bitmaps behind them, both 
72
   * always with the same Fragment effects. Applying any fragment-based effect to one of them automatically 
73
   * applies the effect to the other. Used in the copy constructor.
74
   */
75
  public static final int CLONE_FRAGMENT= 0x8;
76
  /**
77 b455eb48 Leszek Koltunski
   * When creating an instance of a DistortedObjectTree from another instance, clone the children Nodes.
78 6a06a912 Leszek Koltunski
   * <p>
79
   * This is mainly useful for creating many similar sub-trees of Bitmaps and rendering then at different places
80
   * on the screen, with (optionally) different effects of the top-level root Bitmap.   
81
   */
82
  public static final int CLONE_CHILDREN= 0x10;
83 b3618cb5 Leszek Koltunski
84 6a06a912 Leszek Koltunski
  private static boolean mInitialized = false;
85 57578636 Leszek Koltunski
86 3f3bf7dc Leszek Koltunski
  static int mPositionH;       // model position information
87
  static int mNormalH;         // model normal information.
88
  static int mTextureCoordH;   // model texture coordinate information.
89 6a06a912 Leszek Koltunski
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91
92
  private Distorted()
93
    {
94
    
95
    }
96
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98
  
99
  private static void sanitizeMaxValues() throws VertexUniformsException,FragmentUniformsException
100
    {
101
    int maxV,maxF;  
102
    int[] param = new int[1];
103
    
104
    GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
105
    maxV = param[0];
106
    GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
107
    maxF = param[0];
108
    
109 b6a5d557 Leszek Koltunski
    //Log.d("Distorted", "Max vectors in vertex shader: "+maxV);
110
    //Log.d("Distorted", "Max vectors in fragment shader: "+maxF);
111 6a06a912 Leszek Koltunski
    
112 8e34674e Leszek Koltunski
    if( !Build.FINGERPRINT.contains("generic") )
113 6a06a912 Leszek Koltunski
      {
114
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
115
      int realMaxF = (maxF- 2)/4;   //
116
    
117 71887484 Leszek Koltunski
      if( getMaxVertex()   > realMaxV )
118 6a06a912 Leszek Koltunski
        {
119
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
120
        }
121 71887484 Leszek Koltunski
      if( getMaxFragment() > realMaxF )
122 6a06a912 Leszek Koltunski
        {
123
        throw new FragmentUniformsException("Too many effects in the fragment shader, max is "+realMaxF, realMaxF);
124
        }
125
      }
126
    }
127
  
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
130
  private static int compileShader(final int shaderType, final String shaderSource) throws FragmentCompilationException,VertexCompilationException
131
    {
132
    int shaderHandle = GLES20.glCreateShader(shaderType);
133
134
    if (shaderHandle != 0) 
135
      {
136
      GLES20.glShaderSource(shaderHandle, "#version 100 \n"+ generateShaderHeader(shaderType) + shaderSource);
137
      GLES20.glCompileShader(shaderHandle);
138
      final int[] compileStatus = new int[1];
139
      GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
140
141
      if (compileStatus[0] != GLES20.GL_TRUE ) 
142
        {
143
        GLES20.glDeleteShader(shaderHandle);
144
        shaderHandle = 0;
145
        }
146
      }
147
148
    if (shaderHandle == 0)
149
      {     
150
      String error = GLES20.glGetShaderInfoLog(shaderHandle);
151
     
152
      switch(shaderType)
153
        {
154
        case GLES20.GL_VERTEX_SHADER  : throw new VertexCompilationException(error); 
155
        case GLES20.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
156
        default                       : throw new RuntimeException(error);
157
        }
158
      }
159
160
    return shaderHandle;
161
    }
162
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164
165
  private static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) throws LinkingException
166
    {
167
    int programHandle = GLES20.glCreateProgram();
168
169
    if (programHandle != 0) 
170
      {
171
      GLES20.glAttachShader(programHandle, vertexShaderHandle);         
172
      GLES20.glAttachShader(programHandle, fragmentShaderHandle);
173
174
      if (attributes != null)
175
        {
176
        final int size = attributes.length;
177
178
        for (int i = 0; i < size; i++)
179
          {
180
          GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
181
          }                
182
        }
183
184
      GLES20.glLinkProgram(programHandle);
185
186
      final int[] linkStatus = new int[1];
187
      GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
188
189
      if (linkStatus[0] != GLES20.GL_TRUE ) 
190
        {         
191
        String error = GLES20.glGetProgramInfoLog(programHandle);
192
        GLES20.glDeleteProgram(programHandle);
193
        throw new LinkingException(error);
194
        }
195
      
196
      final int[] numberOfUniforms = new int[1];
197
      GLES20.glGetProgramiv(programHandle, GLES20.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
198
199 b6a5d557 Leszek Koltunski
      //android.util.Log.d("Distorted", "number of active uniforms="+numberOfUniforms[0]);
200 6a06a912 Leszek Koltunski
      }
201
 
202
    return programHandle;
203
    }
204
 
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206
  
207
  private static String generateShaderHeader(final int type)
208
    {
209
    String header="";
210
   
211
    switch(type)
212
      {
213 71887484 Leszek Koltunski
      case GLES20.GL_VERTEX_SHADER  : header += ("#define NUM_VERTEX "  + getMaxVertex()+"\n");
214 6a06a912 Leszek Koltunski
     
215
                                      for(EffectNames name: EffectNames.values() )
216
                                        {
217 1e438fc7 Leszek Koltunski
                                        if( name.getType()==EffectTypes.VERTEX)
218 6a06a912 Leszek Koltunski
                                        header += ("#define "+name.name()+" "+name.ordinal()+"\n");  
219
                                        }
220
                                      break;
221 71887484 Leszek Koltunski
      case GLES20.GL_FRAGMENT_SHADER: header += ("#define NUM_FRAGMENT "+ getMaxFragment()+"\n");
222 6a06a912 Leszek Koltunski
     
223
                                      for(EffectNames name: EffectNames.values() )
224
                                        {
225 1e438fc7 Leszek Koltunski
                                        if( name.getType()==EffectTypes.FRAGMENT)
226 6a06a912 Leszek Koltunski
                                        header += ("#define "+name.name()+" "+name.ordinal()+"\n");  
227
                                        }
228
                                      break;
229
     }
230
   
231
    //Log.d(TAG,""+header);
232
    
233
    return header;
234
    }
235
  
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237
  
238 7845dc66 Leszek Koltunski
  private static String readTextFileFromRawResource(final Context c, final int resourceId)
239 6a06a912 Leszek Koltunski
    {
240 7845dc66 Leszek Koltunski
    final InputStream inputStream = c.getResources().openRawResource(resourceId);
241 6a06a912 Leszek Koltunski
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
242
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
243
 
244
    String nextLine;
245
    final StringBuilder body = new StringBuilder();
246
 
247
    try
248
      {
249
      while ((nextLine = bufferedReader.readLine()) != null)
250
        {
251
        body.append(nextLine);
252
        body.append('\n');
253
        }
254
      }
255
    catch (IOException e)
256
      {
257
      return null;
258
      }
259
 
260
    return body.toString();
261
    }
262
 
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264
 
265 7845dc66 Leszek Koltunski
  private static String getVertexShader(final Context c)
266 6a06a912 Leszek Koltunski
    {
267 7845dc66 Leszek Koltunski
    return readTextFileFromRawResource( c, R.raw.main_vertex_shader);
268 6a06a912 Leszek Koltunski
    }
269
 
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
 
272 7845dc66 Leszek Koltunski
  private static String getFragmentShader(final Context c)
273 6a06a912 Leszek Koltunski
    {
274 7845dc66 Leszek Koltunski
    return readTextFileFromRawResource( c, R.raw.main_fragment_shader);
275 6a06a912 Leszek Koltunski
    }
276
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278
/**
279
 * When OpenGL context gets created, you need to call this method so that the library can initialise its internal data structures.
280
 * I.e. best called from GLSurfaceView.onSurfaceCreated().
281
 * <p>
282
 * Compiles the vertex and fragment shaders, establishes the addresses of all uniforms, and initialises all Bitmaps that have already
283
 * been created.
284
 *   
285 015642fb Leszek Koltunski
 * @param context Context of the App using the library - used to open up Resources and read Shader code.
286 6a06a912 Leszek Koltunski
 * @throws FragmentCompilationException
287
 * @throws VertexCompilationException
288
 * @throws VertexUniformsException
289
 * @throws FragmentUniformsException
290
 * @throws LinkingException
291
 */
292 7845dc66 Leszek Koltunski
  public static void onSurfaceCreated(final Context context) throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
293 6a06a912 Leszek Koltunski
    { 
294
    mInitialized = true;  
295 f6fb3c6d Leszek Koltunski
296 7845dc66 Leszek Koltunski
    final String vertexShader   = Distorted.getVertexShader(context);
297
    final String fragmentShader = Distorted.getFragmentShader(context);
298 f6fb3c6d Leszek Koltunski
299 6a06a912 Leszek Koltunski
    sanitizeMaxValues();
300
    
301
    final int vertexShaderHandle   = compileShader(GLES20.GL_VERTEX_SHADER  , vertexShader  );     
302
    final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);     
303
      
304 3f3bf7dc Leszek Koltunski
    int programH = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, new String[] {"a_Position",  "a_Color", "a_Normal", "a_TexCoordinate"});
305 57578636 Leszek Koltunski
306 3f3bf7dc Leszek Koltunski
    GLES20.glUseProgram(programH);
307 57578636 Leszek Koltunski
308 3f3bf7dc Leszek Koltunski
    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 57578636 Leszek Koltunski
313 6a06a912 Leszek Koltunski
    GLES20.glEnable (GLES20.GL_DEPTH_TEST);
314
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
315
    GLES20.glEnable(GLES20.GL_BLEND);
316
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
317 0ce6fcef Leszek Koltunski
    GLES20.glEnable(GLES20.GL_CULL_FACE);
318
    GLES20.glCullFace(GLES20.GL_BACK);
319 5bf698ee Leszek Koltunski
    GLES20.glFrontFace(GLES20.GL_CW);
320 57578636 Leszek Koltunski
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
321 3f3bf7dc Leszek Koltunski
    GLES20.glUniform1i(textureUniformH, 0);
322 8c893ffc Leszek Koltunski
323 3f3bf7dc Leszek Koltunski
    EffectQueueFragment.getUniforms(programH);
324
    EffectQueueVertex.getUniforms(programH);
325
    EffectQueueMatrix.getUniforms(programH);
326 6a06a912 Leszek Koltunski
    
327
    GLES20.glEnableVertexAttribArray(mPositionH);        
328
    GLES20.glEnableVertexAttribArray(mNormalH);
329
    GLES20.glEnableVertexAttribArray(mTextureCoordH);
330
   
331 b455eb48 Leszek Koltunski
    DistortedObjectTree.reset();
332 6a06a912 Leszek Koltunski
    EffectMessageSender.startSending();
333
    }
334
335
///////////////////////////////////////////////////////////////////////////////////////////////////
336
/**
337
 * Call this so that the Library can release its internal data structures.
338
 * Must be called from Activity.onDestroy(). 
339
 */
340
  public static void onDestroy()
341
    {
342 7b8086eb Leszek Koltunski
    DistortedTexture.onDestroy();
343
    DistortedFramebuffer.onDestroy();
344
    DistortedObjectTree.onDestroy();
345
    EffectQueue.onDestroy();
346
    DistortedEffectQueues.onDestroy();
347 6a06a912 Leszek Koltunski
    EffectMessageSender.stopSending();
348
   
349
    mInitialized = false;
350
    }
351
  
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353
/**
354
 * Returns the true if onSurfaceCreated has been called already, and thus if the Library's is ready
355
 * to accept effect requests.
356
 * 
357
 * @return <code>true</code> if the Library is ready for action, <code>false</code> otherwise.
358
 */
359
  public static boolean isInitialized()
360
    {
361
    return mInitialized;  
362
    }
363
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
/**
366 1e438fc7 Leszek Koltunski
 * Returns the maximum number of Matrix effects.
367 6a06a912 Leszek Koltunski
 *    
368 1e438fc7 Leszek Koltunski
 * @return The maximum number of Matrix effects
369 6a06a912 Leszek Koltunski
 */
370 1e438fc7 Leszek Koltunski
  public static int getMaxMatrix()
371 6a06a912 Leszek Koltunski
    {
372 71887484 Leszek Koltunski
    return EffectQueue.getMax(EffectTypes.MATRIX.ordinal());
373 6a06a912 Leszek Koltunski
    }
374
 
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376
/**
377
 * Returns the maximum number of Vertex effects.
378
 *    
379
 * @return The maximum number of Vertex effects
380
 */  
381
  public static int getMaxVertex()
382
    {
383 71887484 Leszek Koltunski
    return EffectQueue.getMax(EffectTypes.VERTEX.ordinal());
384 6a06a912 Leszek Koltunski
    }
385
  
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387
/**
388
 * Returns the maximum number of Fragment effects.
389
 *    
390
 * @return The maximum number of Fragment effects
391
 */  
392
  public static int getMaxFragment()
393
    {
394 71887484 Leszek Koltunski
    return EffectQueue.getMax(EffectTypes.FRAGMENT.ordinal());
395 6a06a912 Leszek Koltunski
    }
396 71887484 Leszek Koltunski
397 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
398
/**
399 71887484 Leszek Koltunski
 * Sets the maximum number of Matrix effects that can be applied to a single DistortedObject at one time.
400 61ec8208 Leszek Koltunski
 * This can fail if:
401
 * <ul>
402
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
403
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
404
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
405
 *     time only decreasing the value of 'max' is permitted.
406
 * <li>Furthermore, this needs to be called before any DistortedObject gets created.
407
 * </ul>
408 6a06a912 Leszek Koltunski
 * 
409 1e438fc7 Leszek Koltunski
 * @param max new maximum number of simultaneous Matrix Effects. Has to be a non-negative number not greater
410 6a06a912 Leszek Koltunski
 *            than Byte.MAX_VALUE 
411
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
412
 */
413 1e438fc7 Leszek Koltunski
  public static boolean setMaxMatrix(int max)
414 6a06a912 Leszek Koltunski
    {
415 71887484 Leszek Koltunski
    return EffectQueue.setMax(EffectTypes.MATRIX.ordinal(),max);
416 6a06a912 Leszek Koltunski
    }
417
  
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419
/**
420 71887484 Leszek Koltunski
 * Sets the maximum number of Vertex effects that can be applied to a single DistortedObject at one time.
421 6a06a912 Leszek Koltunski
 * This can fail if:
422
 * <ul>
423 61ec8208 Leszek Koltunski
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
424 6a06a912 Leszek Koltunski
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called 
425
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
426 61ec8208 Leszek Koltunski
 *     time only decreasing the value of 'max' is permitted.
427
* <li>Furthermore, this needs to be called before any DistortedObject gets created.
428 6a06a912 Leszek Koltunski
 * </ul>
429
 * 
430
 * @param max new maximum number of simultaneous Vertex Effects. Has to be a non-negative number not greater
431
 *            than Byte.MAX_VALUE 
432
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
433
 */
434
  public static boolean setMaxVertex(int max)
435
    {
436 71887484 Leszek Koltunski
    return EffectQueue.setMax(EffectTypes.VERTEX.ordinal(),max);
437 6a06a912 Leszek Koltunski
    }
438
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440
/**
441 71887484 Leszek Koltunski
 * Sets the maximum number of Fragment effects that can be applied to a single DistortedObject at one time.
442 6a06a912 Leszek Koltunski
 * This can fail if:
443
 * <ul>
444 61ec8208 Leszek Koltunski
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
445 6a06a912 Leszek Koltunski
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called 
446
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
447 61ec8208 Leszek Koltunski
 *     time only decreasing the value of 'max' is permitted.
448
 * <li>Furthermore, this needs to be called before any DistortedObject gets created.
449 6a06a912 Leszek Koltunski
 * </ul>
450
 * 
451
 * @param max new maximum number of simultaneous Fragment Effects. Has to be a non-negative number not greater
452
 *            than Byte.MAX_VALUE 
453
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
454
 */
455
  public static boolean setMaxFragment(int max)
456
    {
457 71887484 Leszek Koltunski
    return EffectQueue.setMax(EffectTypes.FRAGMENT.ordinal(),max);
458 6a06a912 Leszek Koltunski
    }
459 39cbf9dc Leszek Koltunski
  }