Project

General

Profile

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

library / src / main / java / org / distorted / library / program / DistortedProgram.java @ 81a0b906

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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.program;
21

    
22
import android.opengl.GLES30;
23
import android.os.Build;
24

    
25
import org.distorted.library.DistortedEffects;
26

    
27
import java.io.BufferedReader;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.InputStreamReader;
31

    
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33
/**
34
 * An object which encapsulates a vertex/fragment shader combo, aka Shader Program.
35
 */
36
public class DistortedProgram
37
  {
38
  private int mProgramHandle;
39

    
40
  private int mNumAttributes;
41
  private String[] mAttributeName;
42

    
43
  public final int[] mAttribute;
44

    
45
///////////////////////////////////////////////////////////////////////////////////////////////////
46

    
47
  private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes)
48
  throws LinkingException
49
    {
50
    int programHandle = GLES30.glCreateProgram();
51

    
52
    if (programHandle != 0)
53
      {
54
      GLES30.glAttachShader(programHandle, vertexShaderHandle);
55
      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
56

    
57
      if (attributes != null)
58
        {
59
        final int size = attributes.length;
60

    
61
        for (int i = 0; i < size; i++)
62
          {
63
          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
64
          }
65
        }
66

    
67
      GLES30.glLinkProgram(programHandle);
68

    
69
      final int[] linkStatus = new int[1];
70
      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
71

    
72
      if (linkStatus[0] != GLES30.GL_TRUE )
73
        {
74
        String error = GLES30.glGetProgramInfoLog(programHandle);
75
        GLES30.glDeleteProgram(programHandle);
76
        throw new LinkingException(error);
77
        }
78

    
79
      final int[] numberOfUniforms = new int[1];
80
      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
81

    
82
      //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
83
      }
84

    
85
    return programHandle;
86
    }
87

    
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89

    
90
  private String parseOutAttribute(final String line)
91
    {
92
    int len = line.length();
93
    int whiteSpace, semicolon, nameBegin;
94
    char currChar;
95

    
96
    for(whiteSpace=0; whiteSpace<len; whiteSpace++)
97
      {
98
      currChar = line.charAt(whiteSpace);
99
      if( currChar!=' ' && currChar!='\t') break;
100
      }
101

    
102
    for(semicolon=whiteSpace; semicolon<len; semicolon++)
103
      {
104
      currChar = line.charAt(semicolon);
105
      if( currChar==';') break;
106
      }
107

    
108
    if( semicolon<len && semicolon-whiteSpace>=11 )   // "attribute a;" --> 11
109
      {
110
      String subline = line.substring(whiteSpace,semicolon);
111
      int subLen = semicolon-whiteSpace;
112

    
113
      if( subline.startsWith("attribute"))
114
        {
115
        //android.util.Log.e("program", "GOOD LINE: " +subline+" subLen="+subLen);
116

    
117
        for(nameBegin=subLen-1; nameBegin>8; nameBegin--)
118
          {
119
          currChar=subline.charAt(nameBegin);
120

    
121
          if( currChar==' ' || currChar=='\t' )
122
            {
123
            mNumAttributes++;
124
            return subline.substring(nameBegin+1,subLen);
125
            }
126
          }
127
        }
128
      }
129

    
130
    return null;
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  private String readTextFileFromRawResource(final InputStream inputStream, boolean doAttributes)
136
    {
137
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
138
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
139

    
140
    String nextLine, attribute, attrList="";
141
    final StringBuilder body = new StringBuilder();
142

    
143
    try
144
      {
145
      while ((nextLine = bufferedReader.readLine()) != null)
146
        {
147
        body.append(nextLine);
148
        body.append('\n');
149

    
150
        if( doAttributes )
151
          {
152
          attribute = parseOutAttribute(nextLine);
153

    
154
          if( attribute!=null )
155
            {
156
            //android.util.Log.d("program", "new attribute: "+attribute);
157
            if( attrList.length()>0 ) attrList+=" ";
158
            attrList += attribute;
159
            }
160
          }
161
        }
162
      }
163
    catch (IOException e)
164
      {
165
      return null;
166
      }
167

    
168
    if( doAttributes )
169
      {
170
      mAttributeName = attrList.split(" ");
171
      }
172

    
173
    return body.toString();
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  private static void sanitizeMaxValues()
179
  throws VertexUniformsException,FragmentUniformsException
180
    {
181
    int maxV,maxF;
182
    int[] param = new int[1];
183

    
184
    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
185
    maxV = param[0];
186
    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
187
    maxF = param[0];
188

    
189
    //Log.d("program", "Max vectors in vertex shader: "+maxV);
190
    //Log.d("program", "Max vectors in fragment shader: "+maxF);
191

    
192
    if( !Build.FINGERPRINT.contains("generic") )
193
      {
194
      int realMaxV = (maxV-11)/4;   // adjust this in case of changes to the shaders...
195
      int realMaxF = (maxF- 2)/4;   //
196

    
197
      if( DistortedEffects.getMaxVertex()   > realMaxV )
198
        {
199
        throw new VertexUniformsException("Too many effects in the vertex shader, max is "+realMaxV, realMaxV);
200
        }
201
      if( DistortedEffects.getMaxFragment() > realMaxF )
202
        {
203
        throw new FragmentUniformsException("Too many effects in the fragment shader, max is "+realMaxF, realMaxF);
204
        }
205
      }
206
    }
207

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209

    
210
  private static int compileShader(final int shaderType, final String shaderSource)
211
  throws FragmentCompilationException,VertexCompilationException
212
    {
213
    int shaderHandle = GLES30.glCreateShader(shaderType);
214

    
215
    if (shaderHandle != 0)
216
      {
217
      GLES30.glShaderSource(shaderHandle, shaderSource);
218
      GLES30.glCompileShader(shaderHandle);
219
      final int[] compileStatus = new int[1];
220
      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
221

    
222
      if (compileStatus[0] != GLES30.GL_TRUE )
223
        {
224
        GLES30.glDeleteShader(shaderHandle);
225
        shaderHandle = 0;
226
        }
227
      }
228

    
229
    if (shaderHandle == 0)
230
      {
231
      String error = GLES30.glGetShaderInfoLog(shaderHandle);
232

    
233
      //android.util.Log.e("Program", "error compiling :"+error);
234

    
235
      switch(shaderType)
236
        {
237
        case GLES30.GL_VERTEX_SHADER  : throw new VertexCompilationException(error);
238
        case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
239
        default                       : throw new RuntimeException(error);
240
        }
241
      }
242

    
243
    return shaderHandle;
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247
// PUBLIC API
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
  /**
250
   * Create a new Shader Program from source stored in resource files.
251
   * <p>
252
   * Needs to be called from a thread holding the OpenGL context.
253
   *
254
   * @param vertex   InputStream containing the opened Resource file from where to read vertex shader code.
255
   * @param fragment InputStream containing the opened Resource file from where to read fragment shader code.
256
   * @throws FragmentCompilationException
257
   * @throws VertexCompilationException
258
   * @throws VertexUniformsException
259
   * @throws FragmentUniformsException
260
   * @throws LinkingException
261
   */
262

    
263
  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader)
264
  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
265
    {
266
    mNumAttributes = 0;
267

    
268
    final String vertexShader   = readTextFileFromRawResource(vertex  , true );
269
    final String fragmentShader = readTextFileFromRawResource(fragment, false);
270

    
271
    sanitizeMaxValues();
272

    
273
    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
274
    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
275

    
276
    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName);
277

    
278
    mAttribute = new int[mNumAttributes];
279

    
280
    for(int i=0; i<mNumAttributes; i++)
281
      {
282
      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
283
      }
284
    }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287
/**
288
 * Return the handle of the created program so that we can later, say, call glUseProgram.
289
 */
290
  public int getProgramHandle()
291
    {
292
    return mProgramHandle;
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296
/**
297
 * Use the program and enable all vertex attribute arrays.
298
 *
299
 * Needs to be called from a thread holding the OpenGL context.
300
 */
301
  public void useProgram()
302
    {
303
    GLES30.glUseProgram(mProgramHandle);
304

    
305
    for(int i=0; i<mNumAttributes; i++)
306
      GLES30.glEnableVertexAttribArray(mAttribute[i]);
307
    }
308
  }
309

    
310

    
(1-1/6)