Project

General

Profile

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

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

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 cacc63de Leszek Koltunski
   * When creating an instance of a DistortedTexture (or Tree) 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 cacc63de Leszek Koltunski
   * When creating an instance of a DistortedTexture from another instance, clone the Bitmap that's
46
   * backing up our DistortedTexture.
47 6a06a912 Leszek Koltunski
   * <p>
48 cacc63de Leszek Koltunski
   * This way we can have two DistortedTextures, both backed up by the same Bitmap, to which we can
49 6a06a912 Leszek Koltunski
   * apply different effects. Used in the copy constructor.
50
   */
51
  public static final int CLONE_BITMAP  = 0x1;
52
  /**
53 cacc63de Leszek Koltunski
   * When creating an instance of a DistortedEffects from another instance, clone the Matrix Effects.
54 6a06a912 Leszek Koltunski
   * <p>
55 cacc63de Leszek Koltunski
   * This way we can have two different DistortedEffects sharing the MATRIX queue.
56 6a06a912 Leszek Koltunski
   */
57 015642fb Leszek Koltunski
  public static final int CLONE_MATRIX = 0x2;
58 6a06a912 Leszek Koltunski
  /**
59 cacc63de Leszek Koltunski
   * When creating an instance of a DistortedEffects from another instance, clone the Vertex Effects.
60 6a06a912 Leszek Koltunski
   * <p>
61 cacc63de Leszek Koltunski
   * This way we can have two different DistortedEffects sharing the VERTEX queue.
62 6a06a912 Leszek Koltunski
   */
63
  public static final int CLONE_VERTEX  = 0x4;
64
  /**
65 cacc63de Leszek Koltunski
   * When creating an instance of a DistortedEffects from another instance, clone the Fragment Effects.
66 6a06a912 Leszek Koltunski
   * <p>
67 cacc63de Leszek Koltunski
   * This way we can have two different DistortedEffects sharing the FRAGMENT queue.
68 6a06a912 Leszek Koltunski
   */
69
  public static final int CLONE_FRAGMENT= 0x8;
70
  /**
71 421c2728 Leszek Koltunski
   * When creating an instance of a DistortedTree from another instance, clone the children Nodes.
72 6a06a912 Leszek Koltunski
   * <p>
73 cacc63de Leszek Koltunski
   * This is mainly useful for creating many similar sub-trees and rendering then at different places
74
   * on the screen with (optionally) different Effects.
75 6a06a912 Leszek Koltunski
   */
76
  public static final int CLONE_CHILDREN= 0x10;
77 b3618cb5 Leszek Koltunski
78 6a06a912 Leszek Koltunski
  private static boolean mInitialized = false;
79 57578636 Leszek Koltunski
80 3f3bf7dc Leszek Koltunski
  static int mPositionH;       // model position information
81
  static int mNormalH;         // model normal information.
82
  static int mTextureCoordH;   // model texture coordinate information.
83 6a06a912 Leszek Koltunski
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85
86
  private Distorted()
87
    {
88
    
89
    }
90
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 b6a5d557 Leszek Koltunski
    //Log.d("Distorted", "Max vectors in vertex shader: "+maxV);
104
    //Log.d("Distorted", "Max vectors in fragment shader: "+maxF);
105 6a06a912 Leszek Koltunski
    
106 8e34674e Leszek Koltunski
    if( !Build.FINGERPRINT.contains("generic") )
107 6a06a912 Leszek Koltunski
      {
108
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
109
      int realMaxF = (maxF- 2)/4;   //
110
    
111 71887484 Leszek Koltunski
      if( getMaxVertex()   > realMaxV )
112 6a06a912 Leszek Koltunski
        {
113
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
114
        }
115 71887484 Leszek Koltunski
      if( getMaxFragment() > realMaxF )
116 6a06a912 Leszek Koltunski
        {
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 b6a5d557 Leszek Koltunski
      //android.util.Log.d("Distorted", "number of active uniforms="+numberOfUniforms[0]);
194 6a06a912 Leszek Koltunski
      }
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 71887484 Leszek Koltunski
      case GLES20.GL_VERTEX_SHADER  : header += ("#define NUM_VERTEX "  + getMaxVertex()+"\n");
208 6a06a912 Leszek Koltunski
     
209
                                      for(EffectNames name: EffectNames.values() )
210
                                        {
211 1e438fc7 Leszek Koltunski
                                        if( name.getType()==EffectTypes.VERTEX)
212 6a06a912 Leszek Koltunski
                                        header += ("#define "+name.name()+" "+name.ordinal()+"\n");  
213
                                        }
214
                                      break;
215 71887484 Leszek Koltunski
      case GLES20.GL_FRAGMENT_SHADER: header += ("#define NUM_FRAGMENT "+ getMaxFragment()+"\n");
216 6a06a912 Leszek Koltunski
     
217
                                      for(EffectNames name: EffectNames.values() )
218
                                        {
219 1e438fc7 Leszek Koltunski
                                        if( name.getType()==EffectTypes.FRAGMENT)
220 6a06a912 Leszek Koltunski
                                        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 7845dc66 Leszek Koltunski
  private static String readTextFileFromRawResource(final Context c, final int resourceId)
233 6a06a912 Leszek Koltunski
    {
234 7845dc66 Leszek Koltunski
    final InputStream inputStream = c.getResources().openRawResource(resourceId);
235 6a06a912 Leszek Koltunski
    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 7845dc66 Leszek Koltunski
  private static String getVertexShader(final Context c)
260 6a06a912 Leszek Koltunski
    {
261 7845dc66 Leszek Koltunski
    return readTextFileFromRawResource( c, R.raw.main_vertex_shader);
262 6a06a912 Leszek Koltunski
    }
263
 
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265
 
266 7845dc66 Leszek Koltunski
  private static String getFragmentShader(final Context c)
267 6a06a912 Leszek Koltunski
    {
268 7845dc66 Leszek Koltunski
    return readTextFileFromRawResource( c, R.raw.main_fragment_shader);
269 6a06a912 Leszek Koltunski
    }
270
271 421c2728 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
272
273
  static boolean isInitialized()
274
    {
275
    return mInitialized;
276
    }
277
278 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
279
/**
280
 * 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().
282
 * <p>
283
 * Compiles the vertex and fragment shaders, establishes the addresses of all uniforms, and initialises all Bitmaps that have already
284
 * been created.
285
 *   
286 015642fb Leszek Koltunski
 * @param context Context of the App using the library - used to open up Resources and read Shader code.
287 6a06a912 Leszek Koltunski
 * @throws FragmentCompilationException
288
 * @throws VertexCompilationException
289
 * @throws VertexUniformsException
290
 * @throws FragmentUniformsException
291
 * @throws LinkingException
292
 */
293 7845dc66 Leszek Koltunski
  public static void onSurfaceCreated(final Context context) throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
294 6a06a912 Leszek Koltunski
    { 
295
    mInitialized = true;  
296 f6fb3c6d Leszek Koltunski
297 7845dc66 Leszek Koltunski
    final String vertexShader   = Distorted.getVertexShader(context);
298
    final String fragmentShader = Distorted.getFragmentShader(context);
299 f6fb3c6d Leszek Koltunski
300 6a06a912 Leszek Koltunski
    sanitizeMaxValues();
301
    
302
    final int vertexShaderHandle   = compileShader(GLES20.GL_VERTEX_SHADER  , vertexShader  );     
303
    final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);     
304
      
305 3f3bf7dc Leszek Koltunski
    int programH = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, new String[] {"a_Position",  "a_Color", "a_Normal", "a_TexCoordinate"});
306 57578636 Leszek Koltunski
307 3f3bf7dc Leszek Koltunski
    GLES20.glUseProgram(programH);
308 57578636 Leszek Koltunski
309 3f3bf7dc Leszek Koltunski
    int textureUniformH = GLES20.glGetUniformLocation(programH, "u_Texture");
310
    mPositionH          = GLES20.glGetAttribLocation( programH, "a_Position");
311
    mNormalH            = GLES20.glGetAttribLocation( programH, "a_Normal");
312
    mTextureCoordH      = GLES20.glGetAttribLocation( programH, "a_TexCoordinate");
313 57578636 Leszek Koltunski
314 6a06a912 Leszek Koltunski
    GLES20.glEnable (GLES20.GL_DEPTH_TEST);
315
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
316
    GLES20.glEnable(GLES20.GL_BLEND);
317
    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
318 0ce6fcef Leszek Koltunski
    GLES20.glEnable(GLES20.GL_CULL_FACE);
319
    GLES20.glCullFace(GLES20.GL_BACK);
320 5bf698ee Leszek Koltunski
    GLES20.glFrontFace(GLES20.GL_CW);
321 57578636 Leszek Koltunski
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
322 3f3bf7dc Leszek Koltunski
    GLES20.glUniform1i(textureUniformH, 0);
323 8c893ffc Leszek Koltunski
324 3f3bf7dc Leszek Koltunski
    EffectQueueFragment.getUniforms(programH);
325
    EffectQueueVertex.getUniforms(programH);
326
    EffectQueueMatrix.getUniforms(programH);
327 6a06a912 Leszek Koltunski
    
328
    GLES20.glEnableVertexAttribArray(mPositionH);        
329
    GLES20.glEnableVertexAttribArray(mNormalH);
330
    GLES20.glEnableVertexAttribArray(mTextureCoordH);
331
   
332 421c2728 Leszek Koltunski
    DistortedTree.reset();
333 6a06a912 Leszek Koltunski
    EffectMessageSender.startSending();
334
    }
335
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337
/**
338
 * Call this so that the Library can release its internal data structures.
339
 * Must be called from Activity.onDestroy(). 
340
 */
341
  public static void onDestroy()
342
    {
343 7b8086eb Leszek Koltunski
    DistortedTexture.onDestroy();
344
    DistortedFramebuffer.onDestroy();
345 421c2728 Leszek Koltunski
    DistortedTree.onDestroy();
346 7b8086eb Leszek Koltunski
    EffectQueue.onDestroy();
347 421c2728 Leszek Koltunski
    DistortedEffects.onDestroy();
348 6a06a912 Leszek Koltunski
    EffectMessageSender.stopSending();
349
   
350
    mInitialized = false;
351
    }
352
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354
/**
355 1e438fc7 Leszek Koltunski
 * Returns the maximum number of Matrix effects.
356 6a06a912 Leszek Koltunski
 *    
357 1e438fc7 Leszek Koltunski
 * @return The maximum number of Matrix effects
358 6a06a912 Leszek Koltunski
 */
359 1e438fc7 Leszek Koltunski
  public static int getMaxMatrix()
360 6a06a912 Leszek Koltunski
    {
361 71887484 Leszek Koltunski
    return EffectQueue.getMax(EffectTypes.MATRIX.ordinal());
362 6a06a912 Leszek Koltunski
    }
363
 
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
/**
366
 * Returns the maximum number of Vertex effects.
367
 *    
368
 * @return The maximum number of Vertex effects
369
 */  
370
  public static int getMaxVertex()
371
    {
372 71887484 Leszek Koltunski
    return EffectQueue.getMax(EffectTypes.VERTEX.ordinal());
373 6a06a912 Leszek Koltunski
    }
374
  
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376
/**
377
 * Returns the maximum number of Fragment effects.
378
 *    
379
 * @return The maximum number of Fragment effects
380
 */  
381
  public static int getMaxFragment()
382
    {
383 71887484 Leszek Koltunski
    return EffectQueue.getMax(EffectTypes.FRAGMENT.ordinal());
384 6a06a912 Leszek Koltunski
    }
385 71887484 Leszek Koltunski
386 6a06a912 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
387
/**
388 cacc63de Leszek Koltunski
 * Sets the maximum number of Matrix effects that can be stored in a single EffectQueue at one time.
389 61ec8208 Leszek Koltunski
 * This can fail if:
390
 * <ul>
391
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
392
 * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
393
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
394
 *     time only decreasing the value of 'max' is permitted.
395 cacc63de Leszek Koltunski
 * <li>Furthermore, this needs to be called before any DistortedEffects gets created.
396 61ec8208 Leszek Koltunski
 * </ul>
397 6a06a912 Leszek Koltunski
 * 
398 1e438fc7 Leszek Koltunski
 * @param max new maximum number of simultaneous Matrix Effects. Has to be a non-negative number not greater
399 6a06a912 Leszek Koltunski
 *            than Byte.MAX_VALUE 
400
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
401
 */
402 1e438fc7 Leszek Koltunski
  public static boolean setMaxMatrix(int max)
403 6a06a912 Leszek Koltunski
    {
404 71887484 Leszek Koltunski
    return EffectQueue.setMax(EffectTypes.MATRIX.ordinal(),max);
405 6a06a912 Leszek Koltunski
    }
406
  
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408
/**
409 cacc63de Leszek Koltunski
 * Sets the maximum number of Vertex effects that can be stored in a single EffectQueue at one time.
410 6a06a912 Leszek Koltunski
 * This can fail if:
411
 * <ul>
412 61ec8208 Leszek Koltunski
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
413 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 
414
 *     before the Vertex Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
415 61ec8208 Leszek Koltunski
 *     time only decreasing the value of 'max' is permitted.
416 cacc63de Leszek Koltunski
* <li>Furthermore, this needs to be called before any DistortedEffects get created.
417 6a06a912 Leszek Koltunski
 * </ul>
418
 * 
419
 * @param max new maximum number of simultaneous Vertex Effects. Has to be a non-negative number not greater
420
 *            than Byte.MAX_VALUE 
421
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
422
 */
423
  public static boolean setMaxVertex(int max)
424
    {
425 71887484 Leszek Koltunski
    return EffectQueue.setMax(EffectTypes.VERTEX.ordinal(),max);
426 6a06a912 Leszek Koltunski
    }
427
428
///////////////////////////////////////////////////////////////////////////////////////////////////
429
/**
430 cacc63de Leszek Koltunski
 * Sets the maximum number of Fragment effects that can be stored in a single EffectQueue at one time.
431 6a06a912 Leszek Koltunski
 * This can fail if:
432
 * <ul>
433 61ec8208 Leszek Koltunski
 * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
434 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 
435
 *     before the Fragment Shader gets compiled, i.e. before the call to {@link #onSurfaceCreated}. After this
436 61ec8208 Leszek Koltunski
 *     time only decreasing the value of 'max' is permitted.
437 cacc63de Leszek Koltunski
 * <li>Furthermore, this needs to be called before any DistortedEffects get created.
438 6a06a912 Leszek Koltunski
 * </ul>
439
 * 
440
 * @param max new maximum number of simultaneous Fragment Effects. Has to be a non-negative number not greater
441
 *            than Byte.MAX_VALUE 
442
 * @return <code>true</code> if operation was successful, <code>false</code> otherwise.
443
 */
444
  public static boolean setMaxFragment(int max)
445
    {
446 71887484 Leszek Koltunski
    return EffectQueue.setMax(EffectTypes.FRAGMENT.ordinal(),max);
447 6a06a912 Leszek Koltunski
    }
448 39cbf9dc Leszek Koltunski
  }