JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
ShaderCode.java
Go to the documentation of this file.
1/**
2 * Copyright 2010 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.util.glsl;
30
31import java.io.BufferedInputStream;
32import java.io.BufferedReader;
33import java.io.FileNotFoundException;
34import java.io.IOException;
35import java.io.InputStreamReader;
36import java.io.PrintStream;
37import java.io.StringReader;
38import java.net.URISyntaxException;
39import java.net.URLConnection;
40import java.nio.Buffer;
41import java.nio.ByteBuffer;
42import java.nio.IntBuffer;
43import java.util.Arrays;
44import java.util.Iterator;
45import java.util.Set;
46
47import com.jogamp.opengl.GL;
48import com.jogamp.opengl.GL2ES2;
49import com.jogamp.opengl.GL3;
50import com.jogamp.opengl.GL3ES3;
51import com.jogamp.opengl.GL4;
52import com.jogamp.opengl.GLES2;
53import com.jogamp.opengl.GLContext;
54import com.jogamp.opengl.GLException;
55
56import jogamp.opengl.Debug;
57
58import com.jogamp.common.net.Uri;
59import com.jogamp.common.nio.Buffers;
60import com.jogamp.common.util.IOUtil;
61import com.jogamp.common.util.VersionNumber;
62
63/**
64 * Convenient shader code class to use and instantiate vertex or fragment programs.
65 * <p>
66 * A documented example of how to use this code is available
67 * {@link #create(GL2ES2, int, Class, String, String, String, boolean) here} and
68 * {@link #create(GL2ES2, int, int, Class, String, String[], String, String) here}.
69 * </p>
70 * <p>
71 * Support for {@link GL4#GL_TESS_CONTROL_SHADER} and {@link GL4#GL_TESS_EVALUATION_SHADER}
72 * was added since 2.2.1.
73 * </p>
74 */
75public final class ShaderCode {
76 public static final boolean DEBUG_CODE = Debug.isPropertyDefined("jogl.debug.GLSLCode", true);
77
78 /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in source code: <code>{@value}</code> */
79 public static final String SUFFIX_VERTEX_SOURCE = "vp" ;
80
81 /** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in binary: <code>{@value}</code> */
82 public static final String SUFFIX_VERTEX_BINARY = "bvp" ;
83
84 /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in source code: <code>{@value}</code> */
85 public static final String SUFFIX_GEOMETRY_SOURCE = "gp" ;
86
87 /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in binary: <code>{@value}</code> */
88 public static final String SUFFIX_GEOMETRY_BINARY = "bgp" ;
89
90 /**
91 * Unique resource suffix for {@link GL3ES3#GL_COMPUTE_SHADER} in source code: <code>{@value}</code>
92 * @since 2.3.2
93 */
94 public static final String SUFFIX_COMPUTE_SOURCE = "cp" ;
95
96 /**
97 * Unique resource suffix for {@link GL3ES3#GL_COMPUTE_SHADER} in binary: <code>{@value}</code>
98 * @since 2.3.2
99 */
100 public static final String SUFFIX_COMPUTE_BINARY = "bcp" ;
101
102 /**
103 * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in source code: <code>{@value}</code>
104 * @since 2.2.1
105 */
106 public static final String SUFFIX_TESS_CONTROL_SOURCE = "tcp" ;
107
108 /**
109 * Unique resource suffix for {@link GL4#GL_TESS_CONTROL_SHADER} in binary: <code>{@value}</code>
110 * @since 2.2.1
111 */
112 public static final String SUFFIX_TESS_CONTROL_BINARY = "btcp" ;
113
114 /**
115 * Unique resource suffix for {@link GL4#GL_TESS_EVALUATION_SHADER} in source code: <code>{@value}</code>
116 * @since 2.2.1
117 */
118 public static final String SUFFIX_TESS_EVALUATION_SOURCE = "tep" ;
119
120 /**
121 * Unique resource suffix for {@link GL4#GL_TESS_EVALUATION_SHADER} in binary: <code>{@value}</code>
122 * @since 2.2.1
123 */
124 public static final String SUFFIX_TESS_EVALUATION_BINARY = "btep" ;
125
126 /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in source code: <code>{@value}</code> */
127 public static final String SUFFIX_FRAGMENT_SOURCE = "fp" ;
128
129 /** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in binary: <code>{@value}</code> */
130 public static final String SUFFIX_FRAGMENT_BINARY = "bfp" ;
131
132 /** Unique relative path for binary shader resources for {@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: <code>{@value}</code> */
133 public static final String SUB_PATH_NVIDIA = "nvidia" ;
134
135 /**
136 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
137 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
138 * @param count number of shaders
139 * @param source CharSequence array containing the shader sources, organized as <code>source[count][strings-per-shader]</code>.
140 * May be either an immutable <code>String</code> - or mutable <code>StringBuilder</code> array.
141 *
142 * @throws IllegalArgumentException if <code>count</code> and <code>source.length</code> do not match
143 */
144 public ShaderCode(final int type, final int count, final CharSequence[][] source) {
145 if(source.length != count) {
146 throw new IllegalArgumentException("shader number ("+count+") and sourceFiles array ("+source.length+") of different lenght.");
147 }
148 switch (type) {
155 break;
156 default:
157 throw new GLException("Unknown shader type: "+type);
158 }
159 shaderSource = source;
160 shaderBinaryFormat = -1;
161 shaderBinary = null;
162 shaderType = type;
163 shader = Buffers.newDirectIntBuffer(count);
164 id = getNextID();
165
166 if(DEBUG_CODE) {
167 System.out.println("Created: "+toString());
168 // dumpShaderSource(System.out); // already done in readShaderSource
169 }
170 }
171
172 /**
173 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
174 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
175 * @param count number of shaders
176 * @param binary binary buffer containing the shader binaries,
177 */
178 public ShaderCode(final int type, final int count, final int binFormat, final Buffer binary) {
179 switch (type) {
186 break;
187 default:
188 throw new GLException("Unknown shader type: "+type);
189 }
190 shaderSource = null;
191 shaderBinaryFormat = binFormat;
192 shaderBinary = binary;
193 shaderType = type;
194 shader = Buffers.newDirectIntBuffer(count);
195 id = getNextID();
196 }
197
198 /**
199 * Creates a complete {@link ShaderCode} object while reading all shader source of <code>sourceFiles</code>,
200 * which location is resolved using the <code>context</code> class, see {@link #readShaderSource(Class, String)}.
201 *
202 * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed.
203 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
204 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
205 * @param count number of shaders
206 * @param context class used to help resolving the source location
207 * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code>
208 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
209 * which can be edited later on at the costs of a String conversion when passing to
210 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
211 * If <code>false</code> method returns an immutable <code>String</code> instance,
212 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
213 * at no additional costs.
214 *
215 * @throws IllegalArgumentException if <code>count</code> and <code>sourceFiles.length</code> do not match
216 * @see #readShaderSource(Class, String)
217 */
218 public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context,
219 final String[] sourceFiles, final boolean mutableStringBuilder) {
220 if(null != gl && !ShaderUtil.isShaderCompilerAvailable(gl)) {
221 return null;
222 }
223
224 CharSequence[][] shaderSources = null;
225 if(null!=sourceFiles) {
226 // sourceFiles.length and count is validated in ctor
227 shaderSources = new CharSequence[sourceFiles.length][1];
228 for(int i=0; i<sourceFiles.length; i++) {
229 try {
230 shaderSources[i][0] = readShaderSource(context, sourceFiles[i], mutableStringBuilder);
231 } catch (final IOException ioe) {
232 throw new RuntimeException("readShaderSource("+sourceFiles[i]+") error: ", ioe);
233 }
234 if(null == shaderSources[i][0]) {
235 shaderSources = null;
236 }
237 }
238 }
239 if(null==shaderSources) {
240 return null;
241 }
242 return new ShaderCode(type, count, shaderSources);
243 }
244
245 /**
246 * Creates a complete {@link ShaderCode} object while reading all shader sources from {@link Uri} <code>sourceLocations</code>
247 * via {@link #readShaderSource(Uri, boolean)}.
248 *
249 * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed.
250 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
251 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
252 * @param count number of shaders
253 * @param sourceLocations array of {@link Uri} source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code>
254 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
255 * which can be edited later on at the costs of a String conversion when passing to
256 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
257 * If <code>false</code> method returns an immutable <code>String</code> instance,
258 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
259 * at no additional costs.
260 *
261 * @throws IllegalArgumentException if <code>count</code> and <code>sourceFiles.length</code> do not match
262 * @see #readShaderSource(Uri, boolean)
263 * @since 2.3.2
264 */
265 public static ShaderCode create(final GL2ES2 gl, final int type, final int count,
266 final Uri[] sourceLocations, final boolean mutableStringBuilder) {
267 if(null != gl && !ShaderUtil.isShaderCompilerAvailable(gl)) {
268 return null;
269 }
270
271 CharSequence[][] shaderSources = null;
272 if(null!=sourceLocations) {
273 // sourceFiles.length and count is validated in ctor
274 shaderSources = new CharSequence[sourceLocations.length][1];
275 for(int i=0; i<sourceLocations.length; i++) {
276 try {
277 shaderSources[i][0] = readShaderSource(sourceLocations[i], mutableStringBuilder);
278 } catch (final IOException ioe) {
279 throw new RuntimeException("readShaderSource("+sourceLocations[i]+") error: ", ioe);
280 }
281 if(null == shaderSources[i][0]) {
282 shaderSources = null;
283 }
284 }
285 }
286 if(null==shaderSources) {
287 return null;
288 }
289 return new ShaderCode(type, count, shaderSources);
290 }
291
292 /**
293 * Creates a complete {@link ShaderCode} object while reading the shader binary of <code>binaryFile</code>,
294 * which location is resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
295 *
296 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
297 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
298 * @param count number of shaders
299 * @param context class used to help resolving the source location
300 * @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}.
301 * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code>
302 *
303 * @see #readShaderBinary(Class, String)
304 * @see ShaderUtil#getShaderBinaryFormats(GL)
305 */
306 public static ShaderCode create(final int type, final int count, final Class<?> context, int binFormat, final String binaryFile) {
307 ByteBuffer shaderBinary = null;
308 if(null!=binaryFile && 0<=binFormat) {
309 try {
310 shaderBinary = readShaderBinary(context, binaryFile);
311 } catch (final IOException ioe) {
312 throw new RuntimeException("readShaderBinary("+binaryFile+") error: ", ioe);
313 }
314 if(null == shaderBinary) {
315 binFormat = -1;
316 }
317 }
318 if(null==shaderBinary) {
319 return null;
320 }
321 return new ShaderCode(type, count, binFormat, shaderBinary);
322 }
323
324 /**
325 * Creates a complete {@link ShaderCode} object while reading the shader binary from {@link Uri} <code>binLocations</code>
326 * via {@link #readShaderBinary(Uri)}.
327 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
328 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
329 * @param count number of shaders
330 * @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}.
331 * @param binLocations {@link Uri} binary location
332 *
333 * @see #readShaderBinary(Uri)
334 * @see ShaderUtil#getShaderBinaryFormats(GL)
335 * @since 2.3.2
336 */
337 public static ShaderCode create(final int type, final int count, int binFormat, final Uri binLocation) {
338 ByteBuffer shaderBinary = null;
339 if(null!=binLocation && 0<=binFormat) {
340 try {
341 shaderBinary = readShaderBinary(binLocation);
342 } catch (final IOException ioe) {
343 throw new RuntimeException("readShaderBinary("+binLocation+") error: ", ioe);
344 }
345 if(null == shaderBinary) {
346 binFormat = -1;
347 }
348 }
349 if(null==shaderBinary) {
350 return null;
351 }
352 return new ShaderCode(type, count, binFormat, shaderBinary);
353 }
354
355 /**
356 * Returns a unique suffix for shader resources as follows:
357 * <ul>
358 * <li>Source<ul>
359 * <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_SOURCE}</li>
360 * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_SOURCE}</li>
361 * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_SOURCE}</li>
362 * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_SOURCE}</li>
363 * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_SOURCE}</li>
364 * <li>{@link GL3ES3#GL_COMPUTE_SHADER}: {@link #SUFFIX_COMPUTE_SOURCE}</li>
365 * </ul></li>
366 * <li>Binary<ul>
367 * <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_BINARY}</li>
368 * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_BINARY}</li>
369 * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_BINARY}</li>
370 * <li>{@link GL4#GL_TESS_CONTROL_SHADER tess-ctrl}: {@link #SUFFIX_TESS_CONTROL_BINARY}</li>
371 * <li>{@link GL4#GL_TESS_EVALUATION_SHADER tess-eval}: {@link #SUFFIX_TESS_EVALUATION_BINARY}</li>
372 * <li>{@link GL3ES3#GL_COMPUTE_SHADER}: {@link #SUFFIX_COMPUTE_BINARY}</li>
373 * </ul></li>
374 * </ul>
375 * @param binary true for a binary resource, false for a source resource
376 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
377 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
378 *
379 * @throws GLException if <code>type</code> is not supported
380 *
381 * @see #create(GL2ES2, int, Class, String, String, String, boolean)
382 */
383 public static String getFileSuffix(final boolean binary, final int type) {
384 switch (type) {
397 default:
398 throw new GLException("illegal shader type: "+type);
399 }
400 }
401
402 /**
403 * Returns a unique relative path for binary shader resources as follows:
404 * <ul>
405 * <li>{@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: {@link #SUB_PATH_NVIDIA}</li>
406 * </ul>
407 *
408 * @throws GLException if <code>binFormat</code> is not supported
409 *
410 * @see #create(GL2ES2, int, Class, String, String, String, boolean)
411 */
412 public static String getBinarySubPath(final int binFormat) {
413 switch (binFormat) {
415 return SUB_PATH_NVIDIA;
416 default:
417 throw new GLException("unsupported binary format: "+binFormat);
418 }
419 }
420
421 /**
422 * Convenient creation method for instantiating a complete {@link ShaderCode} object
423 * either from source code using {@link #create(GL2ES2, int, int, Class, String[])},
424 * or from a binary code using {@link #create(int, int, Class, int, String)},
425 * whatever is available first.
426 * <p>
427 * The source and binary location names are expected w/o suffixes which are
428 * resolved and appended using the given {@code srcSuffixOpt} and {@code binSuffixOpt}
429 * if not {@code null}, otherwise {@link #getFileSuffix(boolean, int)} determines the suffixes.
430 * </p>
431 * <p>
432 * Additionally, the binary resource is expected within a subfolder of <code>binRoot</code>
433 * which reflects the vendor specific binary format, see {@link #getBinarySubPath(int)}.
434 * All {@link ShaderUtil#getShaderBinaryFormats(GL)} are being iterated
435 * using the binary subfolder, the first existing resource is being used.
436 * </p>
437 *
438 * Example:
439 * <pre>
440 * Your std JVM layout (plain or within a JAR):
441 *
442 * org/test/glsl/MyShaderTest.class
443 * org/test/glsl/shader/vertex.vp
444 * org/test/glsl/shader/fragment.fp
445 * org/test/glsl/shader/bin/nvidia/vertex.bvp
446 * org/test/glsl/shader/bin/nvidia/fragment.bfp
447 *
448 * Your Android APK layout:
449 *
450 * classes.dex
451 * assets/org/test/glsl/shader/vertex.vp
452 * assets/org/test/glsl/shader/fragment.fp
453 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
454 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
455 * ...
456 *
457 * Your invocation in org/test/glsl/MyShaderTest.java:
458 *
459 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(),
460 * "shader", new String[] { "vertex" }, null,
461 * "shader/bin", "vertex", null, true);
462 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(),
463 * "shader", new String[] { "vertex" }, null,
464 * "shader/bin", "fragment", null, true);
465 * ShaderProgram sp0 = new ShaderProgram();
466 * sp0.add(gl, vp0, System.err);
467 * sp0.add(gl, fp0, System.err);
468 * st.attachShaderProgram(gl, sp0, true);
469 * </pre>
470 * A simplified entry point is {@link #create(GL2ES2, int, Class, String, String, String, boolean)}.
471 *
472 * <p>
473 * The location is finally being resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
474 * </p>
475 *
476 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
477 * or to determine the shader binary format (if <code>binary</code> is used).
478 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
479 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
480 * @param count number of shaders
481 * @param context class used to help resolving the source and binary location
482 * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional
483 * @param srcBasenames basenames w/o path or suffix relative to <code>srcRoot</code> for the shader's source code
484 * @param srcSuffixOpt optional custom suffix for shader's source file,
485 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
486 * @param binRoot relative <i>root</i> path for <code>binBasenames</code>
487 * @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code
488 * @param binSuffixOpt optional custom suffix for shader's binary file,
489 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
490 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
491 * which can be edited later on at the costs of a String conversion when passing to
492 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
493 * If <code>false</code> method returns an immutable <code>String</code> instance,
494 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
495 * at no additional costs.
496 *
497 * @throws IllegalArgumentException if <code>count</code> and <code>srcBasenames.length</code> do not match
498 *
499 * @see #create(GL2ES2, int, int, Class, String[])
500 * @see #create(int, int, Class, int, String)
501 * @see #readShaderSource(Class, String)
502 * @see #getFileSuffix(boolean, int)
503 * @see ShaderUtil#getShaderBinaryFormats(GL)
504 * @see #getBinarySubPath(int)
505 *
506 * @since 2.3.2
507 */
508 public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context,
509 final String srcRoot, final String[] srcBasenames, final String srcSuffixOpt,
510 final String binRoot, final String binBasename, final String binSuffixOpt,
511 final boolean mutableStringBuilder) {
512 ShaderCode res = null;
513 final String srcPath[];
514 String srcPathString = null;
515 String binFileName = null;
516
517 if( null!=srcBasenames && ShaderUtil.isShaderCompilerAvailable(gl) ) {
518 srcPath = new String[srcBasenames.length];
519 final String srcSuffix = null != srcSuffixOpt ? srcSuffixOpt : getFileSuffix(false, type);
520 if( null != srcRoot && srcRoot.length() > 0 ) {
521 for(int i=0; i<srcPath.length; i++) {
522 srcPath[i] = srcRoot + '/' + srcBasenames[i] + "." + srcSuffix;
523 }
524 } else {
525 for(int i=0; i<srcPath.length; i++) {
526 srcPath[i] = srcBasenames[i] + "." + srcSuffix;
527 }
528 }
529 res = create(gl, type, count, context, srcPath, mutableStringBuilder);
530 if(null!=res) {
531 return res;
532 }
533 srcPathString = Arrays.toString(srcPath);
534 } else {
535 srcPath = null;
536 }
537 if( null!=binBasename ) {
538 final Set<Integer> binFmts = ShaderUtil.getShaderBinaryFormats(gl);
539 final String binSuffix = null != binSuffixOpt ? binSuffixOpt : getFileSuffix(true, type);
540 for(final Iterator<Integer> iter=binFmts.iterator(); iter.hasNext(); ) {
541 final int bFmt = iter.next().intValue();
542 final String bFmtPath = getBinarySubPath(bFmt);
543 if(null==bFmtPath) continue;
544 binFileName = binRoot + '/' + bFmtPath + '/' + binBasename + "." + binSuffix;
545 res = create(type, count, context, bFmt, binFileName);
546 if(null!=res) {
547 return res;
548 }
549 }
550 }
551 throw new GLException("No shader code found (source nor binary) for src: "+srcPathString+
552 ", bin: "+binFileName);
553 }
554
555 /**
556 * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)}.
557 * <p>
558 * Convenient creation method for instantiating a complete {@link ShaderCode} object
559 * either from source code using {@link #create(GL2ES2, int, int, Class, String[])},
560 * or from a binary code using {@link #create(int, int, Class, int, String)},
561 * whatever is available first.
562 * </p>
563 * <p>
564 * The source and binary location names are expected w/o suffixes which are
565 * resolved and appended using {@link #getFileSuffix(boolean, int)}.
566 * </p>
567 * <p>
568 * Additionally, the binary resource is expected within a subfolder of <code>binRoot</code>
569 * which reflects the vendor specific binary format, see {@link #getBinarySubPath(int)}.
570 * All {@link ShaderUtil#getShaderBinaryFormats(GL)} are being iterated
571 * using the binary subfolder, the first existing resource is being used.
572 * </p>
573 *
574 * Example:
575 * <pre>
576 * Your std JVM layout (plain or within a JAR):
577 *
578 * org/test/glsl/MyShaderTest.class
579 * org/test/glsl/shader/vertex.vp
580 * org/test/glsl/shader/fragment.fp
581 * org/test/glsl/shader/bin/nvidia/vertex.bvp
582 * org/test/glsl/shader/bin/nvidia/fragment.bfp
583 *
584 * Your Android APK layout:
585 *
586 * classes.dex
587 * assets/org/test/glsl/shader/vertex.vp
588 * assets/org/test/glsl/shader/fragment.fp
589 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
590 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
591 * ...
592 *
593 * Your invocation in org/test/glsl/MyShaderTest.java:
594 *
595 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(),
596 * "shader", new String[] { "vertex" }, "shader/bin", "vertex", true);
597 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(),
598 * "shader", new String[] { "vertex" }, "shader/bin", "fragment", true);
599 * ShaderProgram sp0 = new ShaderProgram();
600 * sp0.add(gl, vp0, System.err);
601 * sp0.add(gl, fp0, System.err);
602 * st.attachShaderProgram(gl, sp0, true);
603 * </pre>
604 * A simplified entry point is {@link #create(GL2ES2, int, Class, String, String, String, boolean)}.
605 *
606 * <p>
607 * The location is finally being resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
608 * </p>
609 *
610 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
611 * or to determine the shader binary format (if <code>binary</code> is used).
612 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
613 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
614 * @param count number of shaders
615 * @param context class used to help resolving the source and binary location
616 * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional
617 * @param srcBasenames basenames w/o path or suffix relative to <code>srcRoot</code> for the shader's source code
618 * @param binRoot relative <i>root</i> path for <code>binBasenames</code>
619 * @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code
620 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
621 * which can be edited later on at the costs of a String conversion when passing to
622 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
623 * If <code>false</code> method returns an immutable <code>String</code> instance,
624 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
625 * at no additional costs.
626 *
627 * @throws IllegalArgumentException if <code>count</code> and <code>srcBasenames.length</code> do not match
628 *
629 * @see #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)
630 * @see #readShaderSource(Class, String)
631 * @see #getFileSuffix(boolean, int)
632 * @see ShaderUtil#getShaderBinaryFormats(GL)
633 * @see #getBinarySubPath(int)
634 */
635 public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context,
636 final String srcRoot, final String[] srcBasenames,
637 final String binRoot, final String binBasename,
638 final boolean mutableStringBuilder) {
639 return create(gl, type, count, context, srcRoot, srcBasenames, null,
640 binRoot, binBasename, null, mutableStringBuilder);
641 }
642
643 /**
644 * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)}.
645 * <p>
646 * Example:
647 * <pre>
648 * Your std JVM layout (plain or within a JAR):
649 *
650 * org/test/glsl/MyShaderTest.class
651 * org/test/glsl/shader/vertex.vp
652 * org/test/glsl/shader/fragment.fp
653 * org/test/glsl/shader/bin/nvidia/vertex.bvp
654 * org/test/glsl/shader/bin/nvidia/fragment.bfp
655 *
656 * Your Android APK layout:
657 *
658 * classes.dex
659 * assets/org/test/glsl/shader/vertex.vp
660 * assets/org/test/glsl/shader/fragment.fp
661 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
662 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
663 * ...
664 *
665 * Your invocation in org/test/glsl/MyShaderTest.java:
666 *
667 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
668 * "shader", "shader/bin", "vertex", null, null, true);
669 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
670 * "shader", "shader/bin", "fragment", null, null, true);
671 * ShaderProgram sp0 = new ShaderProgram();
672 * sp0.add(gl, vp0, System.err);
673 * sp0.add(gl, fp0, System.err);
674 * st.attachShaderProgram(gl, sp0, true);
675 * </pre>
676 * </p>
677 *
678 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
679 * or to determine the shader binary format (if <code>binary</code> is used).
680 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
681 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
682 * @param context class used to help resolving the source and binary location
683 * @param srcRoot relative <i>root</i> path for <code>basename</code> optional
684 * @param binRoot relative <i>root</i> path for <code>basename</code>
685 * @param basename basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code>
686 * for the shader's source and binary code.
687 * @param srcSuffixOpt optional custom suffix for shader's source file,
688 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
689 * @param binSuffixOpt optional custom suffix for shader's binary file,
690 * if {@code null} {@link #getFileSuffix(boolean, int)} is being used.
691 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
692 * which can be edited later on at the costs of a String conversion when passing to
693 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
694 * If <code>false</code> method returns an immutable <code>String</code> instance,
695 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
696 * at no additional costs.
697 * @throws IllegalArgumentException if <code>count</code> is not 1
698 *
699 * @see #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)
700 * @since 2.3.2
701 */
702 public static ShaderCode create(final GL2ES2 gl, final int type, final Class<?> context,
703 final String srcRoot, final String binRoot,
704 final String basename, final String srcSuffixOpt, final String binSuffixOpt,
705 final boolean mutableStringBuilder) {
706 return create(gl, type, 1, context, srcRoot, new String[] { basename }, srcSuffixOpt,
707 binRoot, basename, binSuffixOpt, mutableStringBuilder );
708 }
709
710 /**
711 * Simplified variation of {@link #create(GL2ES2, int, Class, String, String, String, String, String, boolean)}.
712 * <p>
713 * Example:
714 * <pre>
715 * Your std JVM layout (plain or within a JAR):
716 *
717 * org/test/glsl/MyShaderTest.class
718 * org/test/glsl/shader/vertex.vp
719 * org/test/glsl/shader/fragment.fp
720 * org/test/glsl/shader/bin/nvidia/vertex.bvp
721 * org/test/glsl/shader/bin/nvidia/fragment.bfp
722 *
723 * Your Android APK layout:
724 *
725 * classes.dex
726 * assets/org/test/glsl/shader/vertex.vp
727 * assets/org/test/glsl/shader/fragment.fp
728 * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
729 * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
730 * ...
731 *
732 * Your invocation in org/test/glsl/MyShaderTest.java:
733 *
734 * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
735 * "shader", "shader/bin", "vertex", true);
736 * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
737 * "shader", "shader/bin", "fragment", true);
738 * ShaderProgram sp0 = new ShaderProgram();
739 * sp0.add(gl, vp0, System.err);
740 * sp0.add(gl, fp0, System.err);
741 * st.attachShaderProgram(gl, sp0, true);
742 * </pre>
743 * </p>
744 *
745 * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
746 * or to determine the shader binary format (if <code>binary</code> is used).
747 * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER},
748 * {@link GL4#GL_TESS_CONTROL_SHADER}, {@link GL4#GL_TESS_EVALUATION_SHADER} or {@link GL3ES3#GL_COMPUTE_SHADER}.
749 * @param context class used to help resolving the source and binary location
750 * @param srcRoot relative <i>root</i> path for <code>basename</code> optional
751 * @param binRoot relative <i>root</i> path for <code>basename</code>
752 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
753 * which can be edited later on at the costs of a String conversion when passing to
754 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
755 * If <code>false</code> method returns an immutable <code>String</code> instance,
756 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
757 * at no additional costs.
758 * @param basenames basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code>
759 * for the shader's source and binary code.
760 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
761 * which can be edited later on at the costs of a String conversion when passing to
762 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
763 * If <code>false</code> method returns an immutable <code>String</code> instance,
764 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
765 * at no additional costs.
766 * @throws IllegalArgumentException if <code>count</code> is not 1
767 */
768 public static ShaderCode create(final GL2ES2 gl, final int type, final Class<?> context,
769 final String srcRoot, final String binRoot, final String basename,
770 final boolean mutableStringBuilder) {
771 return ShaderCode.create(gl, type, context, srcRoot, binRoot, basename, null, null, mutableStringBuilder);
772 }
773
774 /**
775 * returns the uniq shader id as an integer
776 */
777 public int id() { return id; }
778
779 public int shaderType() { return shaderType; }
780 public String shaderTypeStr() { return shaderTypeStr(shaderType); }
781
782 public static String shaderTypeStr(final int type) {
783 switch (type) {
785 return "VERTEX_SHADER";
787 return "FRAGMENT_SHADER";
789 return "GEOMETRY_SHADER";
791 return "TESS_CONTROL_SHADER";
793 return "TESS_EVALUATION_SHADER";
795 return "COMPUTE_SHADER";
796 }
797 return "UNKNOWN_SHADER";
798 }
799
800 public int shaderBinaryFormat() { return shaderBinaryFormat; }
801 public Buffer shaderBinary() { return shaderBinary; }
802 public CharSequence[][] shaderSource() { return shaderSource; }
803
804 public boolean isValid() { return valid; }
805
806 public IntBuffer shader() { return shader; }
807
808 public boolean compile(final GL2ES2 gl) {
809 return compile(gl, null);
810 }
811 public boolean compile(final GL2ES2 gl, final PrintStream verboseOut) {
812 if(isValid()) return true;
813
814 // Create & Compile the vertex/fragment shader objects
815 if(null!=shaderSource) {
816 if(DEBUG_CODE) {
817 System.err.println("ShaderCode.compile:");
818 dumpSource(System.err);
819 }
820 valid=ShaderUtil.createAndCompileShader(gl, shader, shaderType,
821 shaderSource, verboseOut);
822 } else if(null!=shaderBinary) {
823 valid=ShaderUtil.createAndLoadShader(gl, shader, shaderType,
824 shaderBinaryFormat, shaderBinary, verboseOut);
825 } else {
826 throw new GLException("no code (source or binary)");
827 }
828 return valid;
829 }
830
831 public void destroy(final GL2ES2 gl) {
832 if(isValid()) {
833 if(null!=gl) {
834 ShaderUtil.deleteShader(gl, shader());
835 }
836 valid=false;
837 }
838 if(null!=shaderBinary) {
839 shaderBinary.clear();
840 shaderBinary=null;
841 }
842 shaderSource=null;
843 shaderBinaryFormat=-1;
844 shaderType=-1;
845 id=-1;
846 }
847
848 @Override
849 public boolean equals(final Object obj) {
850 if(this==obj) { return true; }
851 if(obj instanceof ShaderCode) {
852 return id()==((ShaderCode)obj).id();
853 }
854 return false;
855 }
856 @Override
857 public int hashCode() {
858 return id;
859 }
860 @Override
861 public String toString() {
862 final StringBuilder buf = new StringBuilder("ShaderCode[id="+id()+", type="+shaderTypeStr()+", valid="+valid+", "+shader.remaining()+"/"+shader.capacity()+" shader: ");
863 for(int i=0; i<shader.remaining(); i++) {
864 buf.append(" "+shader.get(i));
865 }
866 if(null!=shaderSource) {
867 buf.append(", source]");
868 } else if(null!=shaderBinary) {
869 buf.append(", binary "+shaderBinary+"]");
870 }
871 return buf.toString();
872 }
873
874 public void dumpSource(final PrintStream out) {
875 if(null==shaderSource) {
876 out.println("<no shader source>");
877 return;
878 }
879 final int sourceCount = shaderSource.length;
880 final int shaderCount = shader.capacity();
881 out.println();
882 out.print("ShaderCode[id="+id()+", type="+shaderTypeStr()+", valid="+valid+", "+shader.remaining()+"/"+shaderCount+" shader: ");
883 if( 0 == shaderCount ) {
884 out.println("none]");
885 }
886 for(int i=0; i<shaderCount; i++) {
887 out.println();
888 out.println("Shader #"+i+"/"+shaderCount+" name "+shader.get(i));
889 out.println("--------------------------------------------------------------");
890 if(i>=sourceCount) {
891 out.println("<no shader source>");
892 } else {
893 final CharSequence[] src = shaderSource[i];
894 int lineno=0;
895
896 for(int j=0; j<src.length; j++) {
897 out.printf("%4d: // Segment %d/%d: \n", lineno, j, src.length);
898 final BufferedReader reader = new BufferedReader(new StringReader(src[j].toString()));
899 String line = null;
900 try {
901 while ((line = reader.readLine()) != null) {
902 lineno++;
903 out.printf("%4d: %s\n", lineno, line);
904 }
905 } catch (final IOException e) { /* impossible .. StringReader */ }
906 }
907 }
908 out.println("--------------------------------------------------------------");
909 }
910 out.println("]");
911 }
912
913 /**
914 * Adds <code>data</code> after the line containing <code>tag</code>.
915 * <p>
916 * Note: The shader source to be edit must be created using a mutable StringBuilder.
917 * </p>
918 *
919 * @param shaderIdx the shader index to be used.
920 * @param tag search string
921 * @param fromIndex start search <code>tag</code> begininig with this index
922 * @param data the text to be inserted. Shall end with an EOL '\n' character.
923 * @return index after the inserted <code>data</code>
924 *
925 * @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
926 */
927 public int insertShaderSource(final int shaderIdx, final String tag, final int fromIndex, final CharSequence data) {
928 if(null==shaderSource) {
929 throw new IllegalStateException("no shader source");
930 }
931 final int shaderCount = shader.capacity();
932 if(0>shaderIdx || shaderIdx>=shaderCount) {
933 throw new IndexOutOfBoundsException("shaderIdx not within shader bounds [0.."+(shaderCount-1)+"]: "+shaderIdx);
934 }
935 final int sourceCount = shaderSource.length;
936 if(shaderIdx>=sourceCount) {
937 throw new IndexOutOfBoundsException("shaderIdx not within source bounds [0.."+(sourceCount-1)+"]: "+shaderIdx);
938 }
939 final CharSequence[] src = shaderSource[shaderIdx];
940 int curEndIndex = 0;
941 for(int j=0; j<src.length; j++) {
942 if( !(src[j] instanceof StringBuilder) ) {
943 throw new IllegalStateException("shader source not a mutable StringBuilder, but CharSequence of type: "+src[j].getClass().getName());
944 }
945 final StringBuilder sb = (StringBuilder)src[j];
946 curEndIndex += sb.length();
947 if(fromIndex < curEndIndex) {
948 int insertIdx = sb.indexOf(tag, fromIndex);
949 if(0<=insertIdx) {
950 insertIdx += tag.length();
951 int eol = sb.indexOf("\n", insertIdx); // eol: covers \n and \r\n
952 if(0>eol) {
953 eol = sb.indexOf("\r", insertIdx); // eol: covers \r 'only'
954 }
955 if(0<eol) {
956 insertIdx = eol+1; // eol found
957 } else {
958 sb.insert(insertIdx, "\n"); // add eol
959 insertIdx++;
960 }
961 sb.insert(insertIdx, data);
962 return insertIdx+data.length();
963 }
964 }
965 }
966 return -1;
967 }
968
969 /**
970 * Replaces <code>oldName</code> with <code>newName</code> in all shader sources.
971 * <p>
972 * In case <code>oldName</code> and <code>newName</code> are equal, no action is performed.
973 * </p>
974 * <p>
975 * Note: The shader source to be edit must be created using a mutable StringBuilder.
976 * </p>
977 *
978 * @param oldName the to be replace string
979 * @param newName the replacement string
980 * @return the number of replacements
981 *
982 * @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
983 */
984 public int replaceInShaderSource(final String oldName, final String newName) {
985 if(null==shaderSource) {
986 throw new IllegalStateException("no shader source");
987 }
988 if(oldName == newName || oldName.equals(newName)) {
989 return 0;
990 }
991 final int oldNameLen = oldName.length();
992 final int newNameLen = newName.length();
993 int num = 0;
994 final int sourceCount = shaderSource.length;
995 for(int shaderIdx = 0; shaderIdx<sourceCount; shaderIdx++) {
996 final CharSequence[] src = shaderSource[shaderIdx];
997 for(int j=0; j<src.length; j++) {
998 if( !(src[j] instanceof StringBuilder) ) {
999 throw new IllegalStateException("shader source not a mutable StringBuilder, but CharSequence of type: "+src[j].getClass().getName());
1000 }
1001 final StringBuilder sb = (StringBuilder)src[j];
1002 int curPos = 0;
1003 while(curPos<sb.length()-oldNameLen+1) {
1004 final int startIdx = sb.indexOf(oldName, curPos);
1005 if(0<=startIdx) {
1006 final int endIdx = startIdx + oldNameLen;
1007 sb.replace(startIdx, endIdx, newName);
1008 curPos = startIdx + newNameLen;
1009 num++;
1010 } else {
1011 curPos = sb.length();
1012 }
1013 }
1014 }
1015 }
1016 return num;
1017 }
1018
1019 /**
1020 * Adds <code>data</code> at <code>position</code> in shader source for shader <code>shaderIdx</code>.
1021 * <p>
1022 * Note: The shader source to be edit must be created using a mutable StringBuilder.
1023 * </p>
1024 *
1025 * @param shaderIdx the shader index to be used.
1026 * @param position in shader source segments of shader <code>shaderIdx</code>, -1 will append data
1027 * @param data the text to be inserted. Shall end with an EOL '\n' character
1028 * @return index after the inserted <code>data</code>
1029 *
1030 * @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
1031 */
1032 public int insertShaderSource(final int shaderIdx, int position, final CharSequence data) {
1033 if(null==shaderSource) {
1034 throw new IllegalStateException("no shader source");
1035 }
1036 final int shaderCount = shader.capacity();
1037 if(0>shaderIdx || shaderIdx>=shaderCount) {
1038 throw new IndexOutOfBoundsException("shaderIdx not within shader bounds [0.."+(shaderCount-1)+"]: "+shaderIdx);
1039 }
1040 final int sourceCount = shaderSource.length;
1041 if(shaderIdx>=sourceCount) {
1042 throw new IndexOutOfBoundsException("shaderIdx not within source bounds [0.."+(sourceCount-1)+"]: "+shaderIdx);
1043 }
1044 final CharSequence[] src = shaderSource[shaderIdx];
1045 int curEndIndex = 0;
1046 for(int j=0; j<src.length; j++) {
1047 if( !(src[j] instanceof StringBuilder) ) {
1048 throw new IllegalStateException("shader source not a mutable StringBuilder, but CharSequence of type: "+src[j].getClass().getName());
1049 }
1050 final StringBuilder sb = (StringBuilder)src[j];
1051 curEndIndex += sb.length();
1052 if( 0 > position && j == src.length - 1 ) {
1053 position = curEndIndex;
1054 }
1055 if(0 <= position && position <= curEndIndex ) {
1056 sb.insert(position, data);
1057 return position+data.length();
1058 }
1059 }
1060 return position;
1061 }
1062
1063 /**
1064 * Adds shader source located in <code>path</code>,
1065 * either relative to the <code>context</code> class or absolute <i>as-is</i>
1066 * at <code>position</code> in shader source for shader <code>shaderIdx</code>.
1067 * <p>
1068 * Final location lookup is performed via {@link ClassLoader#getResource(String)} and {@link ClassLoader#getSystemResource(String)},
1069 * see {@link IOUtil#getResource(Class, String)}.
1070 * </p>
1071 * <p>
1072 * Note: The shader source to be edit must be created using a mutable StringBuilder.
1073 * </p>
1074 *
1075 * @param shaderIdx the shader index to be used.
1076 * @param position in shader source segments of shader <code>shaderIdx</code>, -1 will append data
1077 * @param context class used to help resolve the source location
1078 * @param path location of shader source
1079 * @return index after the inserted code.
1080 * @throws IOException
1081 * @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
1082 * @see IOUtil#getResource(Class, String)
1083 */
1084 public int insertShaderSource(final int shaderIdx, final int position, final Class<?> context, final String path) throws IOException {
1085 final CharSequence data = readShaderSource(context, path, true);
1086 if( null != data ) {
1087 return insertShaderSource(shaderIdx, position, data);
1088 } else {
1089 return position;
1090 }
1091 }
1092
1093 private static int readShaderSource(final Class<?> context, final URLConnection conn, final StringBuilder result, int lineno) throws IOException {
1094 if(DEBUG_CODE) {
1095 if(0 == lineno) {
1096 result.append("// "+conn.getURL().toExternalForm()+"\n");
1097 } else {
1098 result.append("// included @ line "+lineno+": "+conn.getURL().toExternalForm()+"\n");
1099 }
1100 }
1101 final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
1102 try {
1103 String line = null;
1104 while ((line = reader.readLine()) != null) {
1105 lineno++;
1106 if (line.startsWith("#include ")) {
1107 final String includeFile;
1108 {
1109 String s = line.substring(9).trim();
1110 // Bug 1283: Remove shader include filename quotes if exists at start and end only
1111 if( s.startsWith("\"") && s.endsWith("\"")) {
1112 s = s.substring(1, s.length()-1);
1113 }
1114 includeFile = s;
1115 }
1116 URLConnection nextConn = null;
1117
1118 // Try relative of current shader location
1119 final Uri relUri = Uri.valueOf( conn.getURL() ).getRelativeOf(new Uri.Encoded( includeFile, Uri.PATH_LEGAL ));
1120 nextConn = IOUtil.openURL(relUri.toURL(), "ShaderCode.relativeOf ");
1121 if (nextConn == null) {
1122 // Try relative of class and absolute
1123 nextConn = IOUtil.getResource(includeFile, context.getClassLoader(), context);
1124 }
1125 if (nextConn == null) {
1126 // Fail
1127 throw new FileNotFoundException("Can't find include file " + includeFile);
1128 }
1129 lineno = readShaderSource(context, nextConn, result, lineno);
1130 } else {
1131 result.append(line + "\n");
1132 }
1133 }
1134 } catch (final URISyntaxException e) {
1135 throw new IOException(e);
1136 } finally {
1137 IOUtil.close(reader, false);
1138 }
1139 return lineno;
1140 }
1141
1142 /**
1143 * Reads shader source located in <code>conn</code>.
1144 *
1145 * @param context class used to help resolve the source location, may be {@code null}
1146 * @param conn the {@link URLConnection} of the shader source
1147 * @param result {@link StringBuilder} sink for the resulting shader source code
1148 * @throws IOException
1149 */
1150 public static void readShaderSource(final Class<?> context, final URLConnection conn, final StringBuilder result) throws IOException {
1151 readShaderSource(context, conn, result, 0);
1152 }
1153
1154 /**
1155 * Reads shader source located in <code>path</code>,
1156 * either relative to the <code>context</code> class or absolute <i>as-is</i>.
1157 * <p>
1158 * Final location lookup is performed via {@link ClassLoader#getResource(String)} and {@link ClassLoader#getSystemResource(String)},
1159 * see {@link IOUtil#getResource(Class, String)}.
1160 * </p>
1161 *
1162 * @param context class used to help resolve the source location
1163 * @param path location of shader source
1164 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
1165 * which can be edited later on at the costs of a String conversion when passing to
1166 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
1167 * If <code>false</code> method returns an immutable <code>String</code> instance,
1168 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
1169 * at no additional costs.
1170 * @throws IOException
1171 *
1172 * @see IOUtil#getResource(Class, String)
1173 */
1174 public static CharSequence readShaderSource(final Class<?> context, final String path, final boolean mutableStringBuilder) throws IOException {
1175 final URLConnection conn = IOUtil.getResource(path, context.getClassLoader(), context);
1176 if (conn == null) {
1177 return null;
1178 }
1179 final StringBuilder result = new StringBuilder();
1180 readShaderSource(context, conn, result);
1181 return mutableStringBuilder ? result : result.toString();
1182 }
1183
1184 /**
1185 * Reads shader source located from {@link Uri#absolute} {@link Uri} <code>sourceLocation</code>.
1186 * @param sourceLocation {@link Uri} location of shader source
1187 * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
1188 * which can be edited later on at the costs of a String conversion when passing to
1189 * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
1190 * If <code>false</code> method returns an immutable <code>String</code> instance,
1191 * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
1192 * at no additional costs.
1193 * @throws IOException
1194 * @since 2.3.2
1195 */
1196 public static CharSequence readShaderSource(final Uri sourceLocation, final boolean mutableStringBuilder) throws IOException {
1197 final URLConnection conn = IOUtil.openURL(sourceLocation.toURL(), "ShaderCode ");
1198 if (conn == null) {
1199 return null;
1200 }
1201 final StringBuilder result = new StringBuilder();
1202 readShaderSource(null, conn, result);
1203 return mutableStringBuilder ? result : result.toString();
1204 }
1205
1206 /**
1207 * Reads shader binary located in <code>path</code>,
1208 * either relative to the <code>context</code> class or absolute <i>as-is</i>.
1209 * <p>
1210 * Final location lookup is perfomed via {@link ClassLoader#getResource(String)} and {@link ClassLoader#getSystemResource(String)},
1211 * see {@link IOUtil#getResource(Class, String)}.
1212 * </p>
1213 *
1214 * @param context class used to help resolve the source location
1215 * @param path location of shader binary
1216 * @throws IOException
1217 *
1218 * @see IOUtil#getResource(Class, String)
1219 */
1220 public static ByteBuffer readShaderBinary(final Class<?> context, final String path) throws IOException {
1221 final URLConnection conn = IOUtil.getResource(path, context.getClassLoader(), context);
1222 if (conn == null) {
1223 return null;
1224 }
1225 final BufferedInputStream bis = new BufferedInputStream( conn.getInputStream() );
1226 try {
1227 return IOUtil.copyStream2ByteBuffer( bis );
1228 } finally {
1229 IOUtil.close(bis, false);
1230 }
1231 }
1232
1233 /**
1234 * Reads shader binary located from {@link Uri#absolute} {@link Uri} <code>binLocation</code>.
1235 * @param binLocation {@link Uri} location of shader binary
1236 * @throws IOException
1237 * @since 2.3.2
1238 */
1239 public static ByteBuffer readShaderBinary(final Uri binLocation) throws IOException {
1240 final URLConnection conn = IOUtil.openURL(binLocation.toURL(), "ShaderCode ");
1241 if (conn == null) {
1242 return null;
1243 }
1244 final BufferedInputStream bis = new BufferedInputStream( conn.getInputStream() );
1245 try {
1246 return IOUtil.copyStream2ByteBuffer( bis );
1247 } finally {
1248 IOUtil.close(bis, false);
1249 }
1250 }
1251
1252 // Shall we use: #ifdef GL_FRAGMENT_PRECISION_HIGH .. #endif for using highp in fragment shader if avail ?
1253 /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es2_default_precision_vp} */
1254 public static final String es2_default_precision_vp = "\nprecision highp float;\nprecision highp int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n";
1255 /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es2_default_precision_fp} */
1256 public static final String es2_default_precision_fp = "\nprecision mediump float;\nprecision mediump int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n";
1257
1258 /** Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es3_default_precision_vp} */
1260 /**
1261 * Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es3_default_precision_fp},
1262 * same as for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}, i.e {@link #es3_default_precision_vp},
1263 * due to ES 3.x requirements of using same precision for uniforms!
1264 */
1266
1267 /** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader} or {@link GL3#GL_GEOMETRY_SHADER geometry-shader}: {@value #gl3_default_precision_vp_gp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
1268 public static final String gl3_default_precision_vp_gp = "\nprecision highp float;\nprecision highp int;\n";
1269 /** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #gl3_default_precision_fp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
1270 public static final String gl3_default_precision_fp = "\nprecision highp float;\nprecision mediump int;\n/*precision mediump sampler2D;*/\n";
1271
1272 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1273 public static final String REQUIRE = "require";
1274 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1275 public static final String ENABLE = "enable";
1276 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1277 public static final String DISABLE = "disable";
1278 /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
1279 public static final String WARN = "warn";
1280
1281 /**
1282 * Creates a GLSL extension directive.
1283 * <p>
1284 * Prefer {@link #ENABLE} over {@link #REQUIRE}, since the latter will force a failure if not supported.
1285 * </p>
1286 *
1287 * @param extensionName
1288 * @param behavior shall be either {@link #REQUIRE}, {@link #ENABLE}, {@link #DISABLE} or {@link #WARN}
1289 * @return the complete extension directive
1290 */
1291 public static String createExtensionDirective(final String extensionName, final String behavior) {
1292 return "#extension " + extensionName + " : " + behavior + "\n";
1293 }
1294
1295 /**
1296 * Add GLSL version at the head of this shader source code.
1297 * <p>
1298 * Note: The shader source to be edit must be created using a mutable StringBuilder.
1299 * </p>
1300 * @param gl a GL context, which must have been made current once
1301 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1302 */
1303 public final int addGLSLVersion(final GL2ES2 gl) {
1305 }
1306
1307 /**
1308 * Adds default precision to source code at given position if required, i.e.
1309 * {@link #es2_default_precision_vp}, {@link #es2_default_precision_fp},
1310 * {@link #gl3_default_precision_vp_gp}, {@link #gl3_default_precision_fp} or none,
1311 * depending on the {@link GLContext#getGLSLVersionNumber() GLSL version} being used.
1312 * <p>
1313 * Note: The shader source to be edit must be created using a mutable StringBuilder.
1314 * </p>
1315 * @param gl a GL context, which must have been made current once
1316 * @param pos position within this mutable shader source.
1317 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1318 */
1319 public final int addDefaultShaderPrecision(final GL2ES2 gl, int pos) {
1320 final String defaultPrecision;
1321 if( gl.isGLES3() ) {
1322 switch ( shaderType ) {
1324 defaultPrecision = es3_default_precision_vp; break;
1326 defaultPrecision = es3_default_precision_fp; break;
1328 defaultPrecision = es3_default_precision_fp; break;
1329 default:
1330 defaultPrecision = null;
1331 break;
1332 }
1333 } else if( gl.isGLES2() ) {
1334 switch ( shaderType ) {
1336 defaultPrecision = es2_default_precision_vp; break;
1338 defaultPrecision = es2_default_precision_fp; break;
1339 default:
1340 defaultPrecision = null;
1341 break;
1342 }
1343 } else if( requiresGL3DefaultPrecision(gl) ) {
1344 // GLSL [ 1.30 .. 1.50 [ needs at least fragement float default precision!
1345 switch ( shaderType ) {
1350 defaultPrecision = gl3_default_precision_vp_gp; break;
1352 defaultPrecision = gl3_default_precision_fp; break;
1354 defaultPrecision = gl3_default_precision_fp; break;
1355 default:
1356 defaultPrecision = null;
1357 break;
1358 }
1359 } else {
1360 defaultPrecision = null;
1361 }
1362 if( null != defaultPrecision ) {
1363 pos = insertShaderSource(0, pos, defaultPrecision);
1364 }
1365 return pos;
1366 }
1367
1368 /** Returns true, if GLSL version requires default precision, i.e. ES2 or GLSL [1.30 .. 1.50[. */
1369 public static final boolean requiresDefaultPrecision(final GL2ES2 gl) {
1370 if( gl.isGLES() ) {
1371 return true;
1372 }
1373 return requiresGL3DefaultPrecision(gl);
1374 }
1375
1376 /** Returns true, if GL3 GLSL version requires default precision, i.e. GLSL [1.30 .. 1.50[. */
1377 public static final boolean requiresGL3DefaultPrecision(final GL2ES2 gl) {
1378 if( gl.isGL3() ) {
1379 final VersionNumber glslVersion = gl.getContext().getGLSLVersionNumber();
1380 return glslVersion.compareTo(GLContext.Version1_30) >= 0 && glslVersion.compareTo(GLContext.Version1_50) < 0 ;
1381 } else {
1382 return false;
1383 }
1384 }
1385
1386 /**
1387 * Default customization of this shader source code.
1388 * <p>
1389 * Note: The shader source to be edit must be created using a mutable StringBuilder.
1390 * </p>
1391 * @param gl a GL context, which must have been made current once
1392 * @param preludeVersion if true {@link GLContext#getGLSLVersionString()} is preluded, otherwise not.
1393 * @param addDefaultPrecision if <code>true</code> default precision source code line(s) are added, i.e.
1394 * {@link #es2_default_precision_vp}, {@link #es2_default_precision_fp},
1395 * {@link #gl3_default_precision_vp_gp}, {@link #gl3_default_precision_fp} or none,
1396 * depending on the {@link GLContext#getGLSLVersionNumber() GLSL version} being used.
1397 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1398 * @see #addGLSLVersion(GL2ES2)
1399 * @see #addDefaultShaderPrecision(GL2ES2, int)
1400 */
1401 public final int defaultShaderCustomization(final GL2ES2 gl, final boolean preludeVersion, final boolean addDefaultPrecision) {
1402 int pos;
1403 if( preludeVersion ) {
1404 pos = addGLSLVersion(gl);
1405 } else {
1406 pos = 0;
1407 }
1408 if( addDefaultPrecision ) {
1409 pos = addDefaultShaderPrecision(gl, pos);
1410 }
1411 return pos;
1412 }
1413
1414 /**
1415 * Default customization of this shader source code.
1416 * <p>
1417 * Note: The shader source to be edit must be created using a mutable StringBuilder.
1418 * </p>
1419 * @param gl a GL context, which must have been made current once
1420 * @param preludeVersion if true {@link GLContext#getGLSLVersionString()} is preluded, otherwise not.
1421 * @param esDefaultPrecision optional default precision source code line(s) preluded if not null and if {@link GL#isGLES()}.
1422 * You may use {@link #es2_default_precision_fp} for fragment shader and {@link #es2_default_precision_vp} for vertex shader.
1423 * @return the index after the inserted data, maybe 0 if nothing has be inserted.
1424 * @see #addGLSLVersion(GL2ES2)
1425 * @see #addDefaultShaderPrecision(GL2ES2, int)
1426 */
1427 public final int defaultShaderCustomization(final GL2ES2 gl, final boolean preludeVersion, final String esDefaultPrecision) {
1428 int pos;
1429 if( preludeVersion ) {
1430 pos = addGLSLVersion(gl);
1431 } else {
1432 pos = 0;
1433 }
1434 if( gl.isGLES() && null != esDefaultPrecision ) {
1435 pos = insertShaderSource(0, pos, esDefaultPrecision);
1436 } else {
1437 pos = addDefaultShaderPrecision(gl, pos);
1438 }
1439 return pos;
1440 }
1441
1442 //----------------------------------------------------------------------
1443 // Internals only below this point
1444 //
1445
1446 private CharSequence[][] shaderSource;
1447 private Buffer shaderBinary;
1448 private int shaderBinaryFormat = -1;
1449 private final IntBuffer shader;
1450 private int shaderType = -1;
1451 private int id = -1;
1452
1453 private boolean valid=false;
1454
1455 private static synchronized int getNextID() {
1456 return nextID++;
1457 }
1458 private static int nextID = 1;
1459}
1460
Abstraction for an OpenGL rendering context.
Definition: GLContext.java:74
final String getGLSLVersionString()
Returns the matching GLSL version number, queried by this context GL via GL2ES2#GL_SHADING_LANGUAGE_V...
Definition: GLContext.java:848
static final VersionNumber Version1_30
Version 1.30, i.e.
Definition: GLContext.java:125
static final VersionNumber Version1_50
Version 1.50, i.e.
Definition: GLContext.java:129
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Convenient shader code class to use and instantiate vertex or fragment programs.
Definition: ShaderCode.java:75
static final String SUFFIX_COMPUTE_SOURCE
Unique resource suffix for GL3ES3#GL_COMPUTE_SHADER in source code: {@value}
Definition: ShaderCode.java:94
static ByteBuffer readShaderBinary(final Uri binLocation)
Reads shader binary located from Uri#absolute Uri binLocation.
void dumpSource(final PrintStream out)
static String getFileSuffix(final boolean binary, final int type)
Returns a unique suffix for shader resources as follows:
static final String SUFFIX_COMPUTE_BINARY
Unique resource suffix for GL3ES3#GL_COMPUTE_SHADER in binary: {@value}
static final String SUB_PATH_NVIDIA
Unique relative path for binary shader resources for NVIDIA: {@value}
static ByteBuffer readShaderBinary(final Class<?> context, final String path)
Reads shader binary located in path, either relative to the context class or absolute as-is.
int insertShaderSource(final int shaderIdx, int position, final CharSequence data)
Adds data at position in shader source for shader shaderIdx.
static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, final String srcRoot, final String[] srcBasenames, final String srcSuffixOpt, final String binRoot, final String binBasename, final String binSuffixOpt, final boolean mutableStringBuilder)
Convenient creation method for instantiating a complete ShaderCode object either from source code usi...
static final String gl3_default_precision_vp_gp
Default precision of GLSL ≥ 1.30 as required until < 1.50 for vertex-shader or geometry-shader: {@val...
static final String es3_default_precision_fp
Default precision of ES3 for fragment-shader: {@value es3_default_precision_fp}, same as for vertex-s...
static ShaderCode create(final GL2ES2 gl, final int type, final Class<?> context, final String srcRoot, final String binRoot, final String basename, final String srcSuffixOpt, final String binSuffixOpt, final boolean mutableStringBuilder)
Simplified variation of create(GL2ES2, int, int, Class, String, String[], String, String,...
boolean compile(final GL2ES2 gl)
final int defaultShaderCustomization(final GL2ES2 gl, final boolean preludeVersion, final boolean addDefaultPrecision)
Default customization of this shader source code.
final int defaultShaderCustomization(final GL2ES2 gl, final boolean preludeVersion, final String esDefaultPrecision)
Default customization of this shader source code.
final int addGLSLVersion(final GL2ES2 gl)
Add GLSL version at the head of this shader source code.
static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, final String[] sourceFiles, final boolean mutableStringBuilder)
Creates a complete ShaderCode object while reading all shader source of sourceFiles,...
static final String gl3_default_precision_fp
Default precision of GLSL ≥ 1.30 as required until < 1.50 for fragment-shader: {@value gl3_default_pr...
int insertShaderSource(final int shaderIdx, final int position, final Class<?> context, final String path)
Adds shader source located in path, either relative to the context class or absolute as-is at positio...
static final String SUFFIX_VERTEX_SOURCE
Unique resource suffix for GL2ES2#GL_VERTEX_SHADER in source code: {@value}
Definition: ShaderCode.java:79
static final String SUFFIX_FRAGMENT_SOURCE
Unique resource suffix for GL2ES2#GL_FRAGMENT_SHADER in source code: {@value}
static ShaderCode create(final int type, final int count, int binFormat, final Uri binLocation)
Creates a complete ShaderCode object while reading the shader binary from Uri binLocations via readSh...
static final boolean requiresGL3DefaultPrecision(final GL2ES2 gl)
Returns true, if GL3 GLSL version requires default precision, i.e.
static String shaderTypeStr(final int type)
ShaderCode(final int type, final int count, final CharSequence[][] source)
static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Uri[] sourceLocations, final boolean mutableStringBuilder)
Creates a complete ShaderCode object while reading all shader sources from Uri sourceLocations via re...
static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, final String srcRoot, final String[] srcBasenames, final String binRoot, final String binBasename, final boolean mutableStringBuilder)
Simplified variation of create(GL2ES2, int, int, Class, String, String[], String, String,...
static String getBinarySubPath(final int binFormat)
Returns a unique relative path for binary shader resources as follows:
static final boolean requiresDefaultPrecision(final GL2ES2 gl)
Returns true, if GLSL version requires default precision, i.e.
boolean compile(final GL2ES2 gl, final PrintStream verboseOut)
static ShaderCode create(final int type, final int count, final Class<?> context, int binFormat, final String binaryFile)
Creates a complete ShaderCode object while reading the shader binary of binaryFile,...
static final String SUFFIX_GEOMETRY_BINARY
Unique resource suffix for GL3#GL_GEOMETRY_SHADER in binary: {@value}
Definition: ShaderCode.java:88
int id()
returns the uniq shader id as an integer
static final String SUFFIX_VERTEX_BINARY
Unique resource suffix for GL2ES2#GL_VERTEX_SHADER in binary: {@value}
Definition: ShaderCode.java:82
static void readShaderSource(final Class<?> context, final URLConnection conn, final StringBuilder result)
Reads shader source located in conn.
static final String WARN
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static final String SUFFIX_TESS_CONTROL_SOURCE
Unique resource suffix for GL4#GL_TESS_CONTROL_SHADER in source code: {@value}
static final String SUFFIX_TESS_CONTROL_BINARY
Unique resource suffix for GL4#GL_TESS_CONTROL_SHADER in binary: {@value}
int replaceInShaderSource(final String oldName, final String newName)
Replaces oldName with newName in all shader sources.
boolean equals(final Object obj)
static final String ENABLE
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static String createExtensionDirective(final String extensionName, final String behavior)
Creates a GLSL extension directive.
static ShaderCode create(final GL2ES2 gl, final int type, final Class<?> context, final String srcRoot, final String binRoot, final String basename, final boolean mutableStringBuilder)
Simplified variation of create(GL2ES2, int, Class, String, String, String, String,...
static final String REQUIRE
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static final String SUFFIX_TESS_EVALUATION_SOURCE
Unique resource suffix for GL4#GL_TESS_EVALUATION_SHADER in source code: {@value}
static final String es2_default_precision_fp
Default precision of ES2 for fragment-shader: {@value es2_default_precision_fp}.
static CharSequence readShaderSource(final Uri sourceLocation, final boolean mutableStringBuilder)
Reads shader source located from Uri#absolute Uri sourceLocation.
static final String DISABLE
Behavior for GLSL extension directive, see createExtensionDirective(String, String),...
static final String es3_default_precision_vp
Default precision of ES3 for vertex-shader: {@value es3_default_precision_vp}.
ShaderCode(final int type, final int count, final int binFormat, final Buffer binary)
static final String es2_default_precision_vp
Default precision of ES2 for vertex-shader: {@value es2_default_precision_vp}.
static final String SUFFIX_GEOMETRY_SOURCE
Unique resource suffix for GL3#GL_GEOMETRY_SHADER in source code: {@value}
Definition: ShaderCode.java:85
final int addDefaultShaderPrecision(final GL2ES2 gl, int pos)
Adds default precision to source code at given position if required, i.e.
static final String SUFFIX_TESS_EVALUATION_BINARY
Unique resource suffix for GL4#GL_TESS_EVALUATION_SHADER in binary: {@value}
static CharSequence readShaderSource(final Class<?> context, final String path, final boolean mutableStringBuilder)
Reads shader source located in path, either relative to the context class or absolute as-is.
int insertShaderSource(final int shaderIdx, final String tag, final int fromIndex, final CharSequence data)
Adds data after the line containing tag.
static final String SUFFIX_FRAGMENT_BINARY
Unique resource suffix for GL2ES2#GL_FRAGMENT_SHADER in binary: {@value}
static boolean createAndLoadShader(final GL _gl, final IntBuffer shader, final int shaderType, final int binFormat, final java.nio.Buffer bin, final PrintStream verboseOut)
static void deleteShader(final GL _gl, final IntBuffer shaders)
static boolean isShaderCompilerAvailable(final GL _gl)
Returns true if a hader compiler is available, otherwise false.
static Set< Integer > getShaderBinaryFormats(final GL _gl)
If supported, queries the natively supported shader binary formats using GL2ES2#GL_NUM_SHADER_BINARY_...
static boolean createAndCompileShader(final GL _gl, final IntBuffer shader, final int shaderType, final CharSequence[][] sources, final PrintStream verboseOut)
static final int GL_VERTEX_SHADER
GL_ES_VERSION_2_0, GL_VERSION_2_0, GL_EXT_vertex_shader, GL_ARB_vertex_shader Alias for: GL_VERTEX_SH...
Definition: GL2ES2.java:39
static final int GL_FRAGMENT_SHADER
GL_ES_VERSION_2_0, GL_VERSION_2_0, GL_ATI_fragment_shader, GL_ARB_fragment_shader Alias for: GL_FRAGM...
Definition: GL2ES2.java:541
static final int GL_TESS_EVALUATION_SHADER
GL_ARB_tessellation_shader, GL_ES_VERSION_3_2, GL_VERSION_4_0, GL_EXT_tessellation_shader,...
Definition: GL3ES3.java:575
static final int GL_COMPUTE_SHADER
GL_ARB_compute_shader, GL_ES_VERSION_3_1, GL_VERSION_4_3 Define "GL_COMPUTE_SHADER" with expression '...
Definition: GL3ES3.java:327
static final int GL_TESS_CONTROL_SHADER
GL_ARB_tessellation_shader, GL_ES_VERSION_3_2, GL_VERSION_4_0, GL_EXT_tessellation_shader,...
Definition: GL3ES3.java:316
static final int GL_GEOMETRY_SHADER
GL_ES_VERSION_3_2, GL_VERSION_3_2, GL_OES_geometry_shader, GL_EXT_geometry_shader4,...
Definition: GL3ES3.java:402
boolean isGLES()
Indicates whether this GL object conforms to one of the OpenGL ES profiles, see isGLES1(),...
boolean isGL3()
Indicates whether this GL object conforms to the OpenGL ≥ 3.1 core profile.
GLContext getContext()
Returns the GLContext associated which this GL object.
boolean isGLES3()
Indicates whether this GL object conforms to the OpenGL ES ≥ 3.0 profile.
boolean isGLES2()
Indicates whether this GL object conforms to the OpenGL ES ≥ 2.0 profile.
static final int GL_NVIDIA_PLATFORM_BINARY_NV
Definition: GLES2.java:1759