Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ b7074bc6

1 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4 46b572b5 Leszek Koltunski
// This file is part of Distorted.                                                               //
5 432442f9 Leszek Koltunski
//                                                                                               //
6 46b572b5 Leszek Koltunski
// Distorted is free software: you can redistribute it and/or modify                             //
7 432442f9 Leszek Koltunski
// 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 46b572b5 Leszek Koltunski
// Distorted is distributed in the hope that it will be useful,                                  //
12 432442f9 Leszek Koltunski
// 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 46b572b5 Leszek Koltunski
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.library.program;
21
22 b7074bc6 Leszek Koltunski
import android.opengl.GLES30;
23 432442f9 Leszek Koltunski
24
import java.io.BufferedReader;
25
import java.io.IOException;
26
import java.io.InputStream;
27
import java.io.InputStreamReader;
28
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30
/**
31
 * An object which encapsulates a vertex/fragment shader combo, aka Shader Program.
32
 */
33
public class DistortedProgram
34
  {
35 041b6dee Leszek Koltunski
  private String mAttributeStr, mUniformStr, mUniList;
36
  private int mAttributeLen, mUniformLen;
37 94f6d472 Leszek Koltunski
  private int mProgramHandle;
38 432442f9 Leszek Koltunski
  private int mNumAttributes;
39 041b6dee Leszek Koltunski
  private int mNumUniforms;
40 432442f9 Leszek Koltunski
  private String[] mAttributeName;
41 041b6dee Leszek Koltunski
  private String[] mUniformName;
42 432442f9 Leszek Koltunski
43 faa3ff56 Leszek Koltunski
/**
44 f81ebc3f Leszek Koltunski
 * List of Attributes (OpenGL ES 3.0: 'in' variables), in the same order as declared in the shader source.
45 faa3ff56 Leszek Koltunski
 */
46 02de77c9 Leszek Koltunski
  public final int[] mAttribute;
47 faa3ff56 Leszek Koltunski
/**
48 f81ebc3f Leszek Koltunski
 * List of Uniforms, in the same order as declared in the shader source.
49 faa3ff56 Leszek Koltunski
 */
50 041b6dee Leszek Koltunski
  public final int[] mUniform;
51 02de77c9 Leszek Koltunski
52 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
53
54 4782b4e6 Leszek Koltunski
  private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes, final String[] feedbackVaryings)
55 432442f9 Leszek Koltunski
  throws LinkingException
56
    {
57 b7074bc6 Leszek Koltunski
    int programHandle = GLES30.glCreateProgram();
58 432442f9 Leszek Koltunski
59
    if (programHandle != 0)
60
      {
61 b7074bc6 Leszek Koltunski
      GLES30.glAttachShader(programHandle, vertexShaderHandle);
62
      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
63 432442f9 Leszek Koltunski
64 4782b4e6 Leszek Koltunski
      if( feedbackVaryings!=null )
65
        {
66 b7074bc6 Leszek Koltunski
        GLES30.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES30.GL_INTERLEAVED_ATTRIBS);
67 4782b4e6 Leszek Koltunski
        }
68
69 432442f9 Leszek Koltunski
      if (attributes != null)
70
        {
71
        final int size = attributes.length;
72
73
        for (int i = 0; i < size; i++)
74
          {
75 b7074bc6 Leszek Koltunski
          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
76 432442f9 Leszek Koltunski
          }
77
        }
78
79 b7074bc6 Leszek Koltunski
      GLES30.glLinkProgram(programHandle);
80 432442f9 Leszek Koltunski
81
      final int[] linkStatus = new int[1];
82 b7074bc6 Leszek Koltunski
      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
83 432442f9 Leszek Koltunski
84 b7074bc6 Leszek Koltunski
      if (linkStatus[0] != GLES30.GL_TRUE )
85 432442f9 Leszek Koltunski
        {
86 b7074bc6 Leszek Koltunski
        String error = GLES30.glGetProgramInfoLog(programHandle);
87
        GLES30.glDeleteProgram(programHandle);
88 432442f9 Leszek Koltunski
        throw new LinkingException(error);
89
        }
90
91
      final int[] numberOfUniforms = new int[1];
92 b7074bc6 Leszek Koltunski
      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
93 432442f9 Leszek Koltunski
94
      //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
95
      }
96
97
    return programHandle;
98
    }
99
100 041b6dee Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
101
102
  private void init(int glslVersion)
103
    {
104
    mAttributeStr  = (glslVersion == 100 ? "attribute " : "in ");
105
    mAttributeLen  = mAttributeStr.length();
106
    mNumAttributes = 0;
107
    mUniformStr    = "uniform ";
108
    mUniformLen    = mUniformStr.length();
109
    mNumUniforms   = 0;
110
    mUniList       = "";
111
    }
112
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114
115
  private String parseOutUniform(final String line)
116
    {
117
    int len = line.length();
118
    int whiteSpace, semicolon, nameBegin;
119
    char currChar;
120
121
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
122
      {
123
      currChar = line.charAt(whiteSpace);
124
      if( currChar!=' ' && currChar!='\t') break;
125
      }
126
127
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
128
      {
129
      currChar = line.charAt(semicolon);
130
      if( currChar==';') break;
131
      }
132
133
    if( semicolon<len && semicolon-whiteSpace>=mUniformLen+1 )
134
      {
135
      String subline = line.substring(whiteSpace,semicolon);
136
      int subLen = semicolon-whiteSpace;
137
138
      if( subline.startsWith(mUniformStr))
139
        {
140
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
141
142
        for(nameBegin=subLen-1; nameBegin>mUniformLen-2; nameBegin--)
143
          {
144
          currChar=subline.charAt(nameBegin);
145
146
          if( currChar==' ' || currChar=='\t' )
147
            {
148
            mNumUniforms++;
149
            String uniform = subline.substring(nameBegin+1,subLen);
150
            int brace = uniform.indexOf("[");
151
152
            return brace>=0 ? uniform.substring(0,brace) : uniform;
153
            }
154
          }
155
        }
156
      }
157
158
    return null;
159
    }
160
161 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
162
163 3d804c91 Leszek Koltunski
  private String parseOutAttribute(final String line)
164 432442f9 Leszek Koltunski
    {
165
    int len = line.length();
166
    int whiteSpace, semicolon, nameBegin;
167
    char currChar;
168
169
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
170
      {
171
      currChar = line.charAt(whiteSpace);
172
      if( currChar!=' ' && currChar!='\t') break;
173
      }
174
175
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
176
      {
177
      currChar = line.charAt(semicolon);
178
      if( currChar==';') break;
179
      }
180
181 94f6d472 Leszek Koltunski
    if( semicolon<len && semicolon-whiteSpace>=mAttributeLen+1 )
182 432442f9 Leszek Koltunski
      {
183
      String subline = line.substring(whiteSpace,semicolon);
184
      int subLen = semicolon-whiteSpace;
185
186 94f6d472 Leszek Koltunski
      if( subline.startsWith(mAttributeStr))
187 432442f9 Leszek Koltunski
        {
188
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
189
190 94f6d472 Leszek Koltunski
        for(nameBegin=subLen-1; nameBegin>mAttributeLen-2; nameBegin--)
191 432442f9 Leszek Koltunski
          {
192
          currChar=subline.charAt(nameBegin);
193
194
          if( currChar==' ' || currChar=='\t' )
195
            {
196
            mNumAttributes++;
197 3d804c91 Leszek Koltunski
            return subline.substring(nameBegin+1,subLen);
198 432442f9 Leszek Koltunski
            }
199
          }
200
        }
201
      }
202 3d804c91 Leszek Koltunski
203
    return null;
204 432442f9 Leszek Koltunski
    }
205
206 041b6dee Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
207
208
  private void doAttributes(final String shader, boolean doAttributes)
209
    {
210
    String attribute, attrList="", uniform;
211
    String[] lines = shader.split("\n");
212
    int length = lines.length;
213
214
    for(int i=0; i<length; i++)
215
      {
216
      if( doAttributes )
217
        {
218
        attribute = parseOutAttribute(lines[i]);
219
220
        if( attribute!=null )
221
          {
222
          //android.util.Log.d("program", "new attribute: "+attribute);
223
          if( attrList.length()>0 ) attrList+=" ";
224
          attrList += attribute;
225
          }
226
        }
227
228
      uniform = parseOutUniform(lines[i]);
229
230
      if( uniform!=null )
231
        {
232 aa2f0486 Leszek Koltunski
        //android.util.Log.d("program", "new uniform: "+uniform);
233 041b6dee Leszek Koltunski
        if( mUniList.length()>0 ) mUniList+=" ";
234
        mUniList += uniform;
235
        }
236
      }
237
238
    if( doAttributes ) mAttributeName = attrList.split(" ");
239
    }
240
241 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
242
243
  private String readTextFileFromRawResource(final InputStream inputStream, boolean doAttributes)
244
    {
245
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
246
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
247
248 3d804c91 Leszek Koltunski
    String nextLine, attribute, attrList="";
249 432442f9 Leszek Koltunski
    final StringBuilder body = new StringBuilder();
250
251
    try
252
      {
253
      while ((nextLine = bufferedReader.readLine()) != null)
254
        {
255
        body.append(nextLine);
256
        body.append('\n');
257
258 3d804c91 Leszek Koltunski
        if( doAttributes )
259
          {
260
          attribute = parseOutAttribute(nextLine);
261
262
          if( attribute!=null )
263
            {
264
            //android.util.Log.d("program", "new attribute: "+attribute);
265
            if( attrList.length()>0 ) attrList+=" ";
266
            attrList += attribute;
267
            }
268
          }
269 432442f9 Leszek Koltunski
        }
270
      }
271
    catch (IOException e)
272
      {
273
      return null;
274
      }
275
276 041b6dee Leszek Koltunski
    if( doAttributes ) mAttributeName = attrList.split(" ");
277 432442f9 Leszek Koltunski
278
    return body.toString();
279
    }
280
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282
283
  private static int compileShader(final int shaderType, final String shaderSource)
284
  throws FragmentCompilationException,VertexCompilationException
285
    {
286 b7074bc6 Leszek Koltunski
    int shaderHandle = GLES30.glCreateShader(shaderType);
287 432442f9 Leszek Koltunski
288
    if (shaderHandle != 0)
289
      {
290 b7074bc6 Leszek Koltunski
      GLES30.glShaderSource(shaderHandle, shaderSource);
291
      GLES30.glCompileShader(shaderHandle);
292 432442f9 Leszek Koltunski
      final int[] compileStatus = new int[1];
293 b7074bc6 Leszek Koltunski
      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
294 432442f9 Leszek Koltunski
295 b7074bc6 Leszek Koltunski
      if (compileStatus[0] != GLES30.GL_TRUE)
296 432442f9 Leszek Koltunski
        {
297 b7074bc6 Leszek Koltunski
        String error = GLES30.glGetShaderInfoLog(shaderHandle);
298 432442f9 Leszek Koltunski
299 b7074bc6 Leszek Koltunski
        GLES30.glDeleteShader(shaderHandle);
300 81a0b906 leszek
301 341151fc Leszek Koltunski
        switch (shaderType)
302
          {
303 b7074bc6 Leszek Koltunski
          case GLES30.GL_VERTEX_SHADER:   throw new VertexCompilationException(error);
304
          case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
305 341151fc Leszek Koltunski
          default:                        throw new RuntimeException(error);
306
          }
307 432442f9 Leszek Koltunski
        }
308
      }
309
310
    return shaderHandle;
311
    }
312
313 7cd24173 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
314
315
  private static String insertEnabledEffects(String code, final String effects)
316
    {
317
    final String marker = "// ENABLED EFFECTS WILL BE INSERTED HERE";
318
    int length = marker.length();
319
320
    int place = code.indexOf(marker);
321
322
    if( place>=0 )
323
      {
324
      String begin = code.substring(0,place-1);
325
      String end   = code.substring(place+length);
326
/*
327
int len = begin.length();
328
329
android.util.Log.d("Program", begin.substring(len-40));
330
android.util.Log.d("Program", effects);
331
android.util.Log.d("Program", end.substring(0,40));
332
*/
333
      return begin + effects + end;
334
      }
335
    else
336
      {
337
      android.util.Log.e("Program", "Error: marker string not found in SHADER!");
338
      }
339
340
    return null;
341
    }
342
343 432442f9 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
344 faa3ff56 Leszek Koltunski
/**
345
 * Only for use by the library itself.
346
 *
347
 * @y.exclude
348
 */
349 a13dde77 Leszek Koltunski
  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
350
                          int glslVersion, final String[] feedback )
351
  throws FragmentCompilationException,VertexCompilationException,LinkingException
352 432442f9 Leszek Koltunski
    {
353 041b6dee Leszek Koltunski
    init(glslVersion);
354 432442f9 Leszek Koltunski
355 a13dde77 Leszek Koltunski
    final String vertShader = readTextFileFromRawResource(vert, true );
356
    final String fragShader = readTextFileFromRawResource(frag, false);
357 432442f9 Leszek Koltunski
358 b7074bc6 Leszek Koltunski
    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
359
    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
360 432442f9 Leszek Koltunski
361 a13dde77 Leszek Koltunski
    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
362 7cd24173 leszek
363
    mAttribute = new int[mNumAttributes];
364
365
    for(int i=0; i<mNumAttributes; i++)
366
      {
367 b7074bc6 Leszek Koltunski
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
368 7cd24173 leszek
      }
369 041b6dee Leszek Koltunski
370
    if( mNumUniforms>0 )
371
      {
372
      mUniform = new int[mNumUniforms];
373
      mUniformName = mUniList.split(" ");
374
375
      for(int i=0; i<mNumUniforms; i++)
376
        {
377 b7074bc6 Leszek Koltunski
        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
378 041b6dee Leszek Koltunski
        }
379
      }
380
    else mUniform = null;
381
    }
382
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384 faa3ff56 Leszek Koltunski
/**
385
 * Only for use by the library itself.
386
 *
387
 * @y.exclude
388
 */
389 a13dde77 Leszek Koltunski
  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
390
                          final String enabledVert, final String enabledFrag, int glslVersion, final String[] feedback )
391
  throws FragmentCompilationException,VertexCompilationException,LinkingException
392 041b6dee Leszek Koltunski
    {
393 faa3ff56 Leszek Koltunski
    init(glslVersion);
394 041b6dee Leszek Koltunski
395 a13dde77 Leszek Koltunski
    String vertShader = readTextFileFromRawResource( vert, true );
396
    String fragShader = readTextFileFromRawResource( frag, false);
397 041b6dee Leszek Koltunski
398 a13dde77 Leszek Koltunski
    if( enabledVert!=null ) vertShader = insertEnabledEffects(vertShader,enabledVert);
399
    if( enabledFrag!=null ) fragShader = insertEnabledEffects(fragShader,enabledFrag);
400 041b6dee Leszek Koltunski
401 b7074bc6 Leszek Koltunski
    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
402
    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
403 faa3ff56 Leszek Koltunski
404 a13dde77 Leszek Koltunski
    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
405 041b6dee Leszek Koltunski
406
    mAttribute = new int[mNumAttributes];
407
408
    for(int i=0; i<mNumAttributes; i++)
409
      {
410 b7074bc6 Leszek Koltunski
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
411 041b6dee Leszek Koltunski
      }
412
413
    if( mNumUniforms>0 )
414
      {
415
      mUniform = new int[mNumUniforms];
416
      mUniformName = mUniList.split(" ");
417
418
      for(int i=0; i<mNumUniforms; i++)
419
        {
420 b7074bc6 Leszek Koltunski
        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
421 041b6dee Leszek Koltunski
        }
422
      }
423
    else mUniform = null;
424 7cd24173 leszek
    }
425
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427 faa3ff56 Leszek Koltunski
/**
428
 * Only for use by the library itself.
429
 *
430
 * @y.exclude
431
 */
432
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion )
433 7cd24173 leszek
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
434
    {
435 faa3ff56 Leszek Koltunski
    this(vertex,fragment,vertexHeader,fragmentHeader,glslVersion,null);
436
    }
437 7cd24173 leszek
438 faa3ff56 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
439
// PUBLIC API
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441
/**
442
 * Create a new Shader Program from two source strings.
443
 * <p>
444
 * Needs to be called from a thread holding the OpenGL context.
445
 *
446
 * @param vertex   Vertex shader code.
447
 * @param fragment Fragment shader code.
448
 * @throws FragmentCompilationException
449
 * @throws VertexCompilationException
450
 * @throws VertexUniformsException
451
 * @throws FragmentUniformsException
452
 * @throws LinkingException
453
 */
454
  public DistortedProgram(final String vertex, final String fragment)
455
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
456
    {
457
    init(300);
458 7cd24173 leszek
459 faa3ff56 Leszek Koltunski
    doAttributes(vertex  , true );
460
    doAttributes(fragment, false);
461 7cd24173 leszek
462 b7074bc6 Leszek Koltunski
    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertex  );
463
    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragment);
464 7cd24173 leszek
465 faa3ff56 Leszek Koltunski
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, null );
466 432442f9 Leszek Koltunski
467 02de77c9 Leszek Koltunski
    mAttribute = new int[mNumAttributes];
468 432442f9 Leszek Koltunski
469 02de77c9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
470
      {
471 b7074bc6 Leszek Koltunski
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
472 02de77c9 Leszek Koltunski
      }
473 041b6dee Leszek Koltunski
474
    if( mNumUniforms>0 )
475
      {
476
      mUniform = new int[mNumUniforms];
477
      mUniformName = mUniList.split(" ");
478
479
      for(int i=0; i<mNumUniforms; i++)
480
        {
481 b7074bc6 Leszek Koltunski
        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
482 041b6dee Leszek Koltunski
        }
483
      }
484
    else mUniform = null;
485 432442f9 Leszek Koltunski
    }
486
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488 3d804c91 Leszek Koltunski
/**
489
 * Return the handle of the created program so that we can later, say, call glUseProgram.
490
 */
491 432442f9 Leszek Koltunski
  public int getProgramHandle()
492
    {
493
    return mProgramHandle;
494
    }
495
496
///////////////////////////////////////////////////////////////////////////////////////////////////
497 3d804c91 Leszek Koltunski
/**
498 02de77c9 Leszek Koltunski
 * Use the program and enable all vertex attribute arrays.
499
 *
500 3d804c91 Leszek Koltunski
 * Needs to be called from a thread holding the OpenGL context.
501
 */
502 02de77c9 Leszek Koltunski
  public void useProgram()
503 432442f9 Leszek Koltunski
    {
504 b7074bc6 Leszek Koltunski
    GLES30.glUseProgram(mProgramHandle);
505 02de77c9 Leszek Koltunski
506 432442f9 Leszek Koltunski
    for(int i=0; i<mNumAttributes; i++)
507 b7074bc6 Leszek Koltunski
      GLES30.glEnableVertexAttribArray(mAttribute[i]);
508 432442f9 Leszek Koltunski
    }
509
  }
510 02de77c9 Leszek Koltunski