• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.graphics.glutils;
18 
19 import java.nio.Buffer;
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
22 import java.nio.FloatBuffer;
23 import java.nio.IntBuffer;
24 
25 import com.badlogic.gdx.Application;
26 import com.badlogic.gdx.Gdx;
27 import com.badlogic.gdx.files.FileHandle;
28 import com.badlogic.gdx.graphics.Color;
29 import com.badlogic.gdx.graphics.GL20;
30 import com.badlogic.gdx.graphics.Mesh;
31 import com.badlogic.gdx.math.Matrix3;
32 import com.badlogic.gdx.math.Matrix4;
33 import com.badlogic.gdx.math.Vector2;
34 import com.badlogic.gdx.math.Vector3;
35 import com.badlogic.gdx.utils.Array;
36 import com.badlogic.gdx.utils.BufferUtils;
37 import com.badlogic.gdx.utils.Disposable;
38 import com.badlogic.gdx.utils.ObjectIntMap;
39 import com.badlogic.gdx.utils.ObjectMap;
40 
41 /** <p>
42  * A shader program encapsulates a vertex and fragment shader pair linked to form a shader program useable with OpenGL ES 2.0.
43  * </p>
44  *
45  * <p>
46  * After construction a ShaderProgram can be used to draw {@link Mesh}. To make the GPU use a specific ShaderProgram the programs
47  * {@link ShaderProgram#begin()} method must be used which effectively binds the program.
48  * </p>
49  *
50  * <p>
51  * When a ShaderProgram is bound one can set uniforms, vertex attributes and attributes as needed via the respective methods.
52  * </p>
53  *
54  * <p>
55  * A ShaderProgram can be unbound with a call to {@link ShaderProgram#end()}
56  * </p>
57  *
58  * <p>
59  * A ShaderProgram must be disposed via a call to {@link ShaderProgram#dispose()} when it is no longer needed
60  * </p>
61  *
62  * <p>
63  * ShaderPrograms are managed. In case the OpenGL context is lost all shaders get invalidated and have to be reloaded. This
64  * happens on Android when a user switches to another application or receives an incoming call. Managed ShaderPrograms are
65  * automatically reloaded when the OpenGL context is recreated so you don't have to do this manually.
66  * </p>
67  *
68  * @author mzechner */
69 public class ShaderProgram implements Disposable {
70 	/** default name for position attributes **/
71 	public static final String POSITION_ATTRIBUTE = "a_position";
72 	/** default name for normal attributes **/
73 	public static final String NORMAL_ATTRIBUTE = "a_normal";
74 	/** default name for color attributes **/
75 	public static final String COLOR_ATTRIBUTE = "a_color";
76 	/** default name for texcoords attributes, append texture unit number **/
77 	public static final String TEXCOORD_ATTRIBUTE = "a_texCoord";
78 	/** default name for tangent attribute **/
79 	public static final String TANGENT_ATTRIBUTE = "a_tangent";
80 	/** default name for binormal attribute **/
81 	public static final String BINORMAL_ATTRIBUTE = "a_binormal";
82 
83 	/** flag indicating whether attributes & uniforms must be present at all times **/
84 	public static boolean pedantic = true;
85 
86 	/** code that is always added to the vertex shader code, typically used to inject a #version line. Note that this is added
87 	 * as-is, you should include a newline (`\n`) if needed. */
88 	public static String prependVertexCode = "";
89 
90 	/** code that is always added to every fragment shader code, typically used to inject a #version line. Note that this is added
91 	 * as-is, you should include a newline (`\n`) if needed. */
92 	public static String prependFragmentCode = "";
93 
94 	/** the list of currently available shaders **/
95 	private final static ObjectMap<Application, Array<ShaderProgram>> shaders = new ObjectMap<Application, Array<ShaderProgram>>();
96 
97 	/** the log **/
98 	private String log = "";
99 
100 	/** whether this program compiled successfully **/
101 	private boolean isCompiled;
102 
103 	/** uniform lookup **/
104 	private final ObjectIntMap<String> uniforms = new ObjectIntMap<String>();
105 
106 	/** uniform types **/
107 	private final ObjectIntMap<String> uniformTypes = new ObjectIntMap<String>();
108 
109 	/** uniform sizes **/
110 	private final ObjectIntMap<String> uniformSizes = new ObjectIntMap<String>();
111 
112 	/** uniform names **/
113 	private String[] uniformNames;
114 
115 	/** attribute lookup **/
116 	private final ObjectIntMap<String> attributes = new ObjectIntMap<String>();
117 
118 	/** attribute types **/
119 	private final ObjectIntMap<String> attributeTypes = new ObjectIntMap<String>();
120 
121 	/** attribute sizes **/
122 	private final ObjectIntMap<String> attributeSizes = new ObjectIntMap<String>();
123 
124 	/** attribute names **/
125 	private String[] attributeNames;
126 
127 	/** program handle **/
128 	private int program;
129 
130 	/** vertex shader handle **/
131 	private int vertexShaderHandle;
132 
133 	/** fragment shader handle **/
134 	private int fragmentShaderHandle;
135 
136 	/** matrix float buffer **/
137 	private final FloatBuffer matrix;
138 
139 	/** vertex shader source **/
140 	private final String vertexShaderSource;
141 
142 	/** fragment shader source **/
143 	private final String fragmentShaderSource;
144 
145 	/** whether this shader was invalidated **/
146 	private boolean invalidated;
147 
148 	/** reference count **/
149 	private int refCount = 0;
150 
151 	/** Constructs a new ShaderProgram and immediately compiles it.
152 	 *
153 	 * @param vertexShader the vertex shader
154 	 * @param fragmentShader the fragment shader */
155 
ShaderProgram(String vertexShader, String fragmentShader)156 	public ShaderProgram (String vertexShader, String fragmentShader) {
157 		if (vertexShader == null) throw new IllegalArgumentException("vertex shader must not be null");
158 		if (fragmentShader == null) throw new IllegalArgumentException("fragment shader must not be null");
159 
160 		if (prependVertexCode != null && prependVertexCode.length() > 0)
161 			vertexShader = prependVertexCode + vertexShader;
162 		if (prependFragmentCode != null && prependFragmentCode.length() > 0)
163 			fragmentShader = prependFragmentCode + fragmentShader;
164 
165 		this.vertexShaderSource = vertexShader;
166 		this.fragmentShaderSource = fragmentShader;
167 		this.matrix = BufferUtils.newFloatBuffer(16);
168 
169 		compileShaders(vertexShader, fragmentShader);
170 		if (isCompiled()) {
171 			fetchAttributes();
172 			fetchUniforms();
173 			addManagedShader(Gdx.app, this);
174 		}
175 	}
176 
ShaderProgram(FileHandle vertexShader, FileHandle fragmentShader)177 	public ShaderProgram (FileHandle vertexShader, FileHandle fragmentShader) {
178 		this(vertexShader.readString(), fragmentShader.readString());
179 	}
180 
181 	/** Loads and compiles the shaders, creates a new program and links the shaders.
182 	 *
183 	 * @param vertexShader
184 	 * @param fragmentShader */
compileShaders(String vertexShader, String fragmentShader)185 	private void compileShaders (String vertexShader, String fragmentShader) {
186 		vertexShaderHandle = loadShader(GL20.GL_VERTEX_SHADER, vertexShader);
187 		fragmentShaderHandle = loadShader(GL20.GL_FRAGMENT_SHADER, fragmentShader);
188 
189 		if (vertexShaderHandle == -1 || fragmentShaderHandle == -1) {
190 			isCompiled = false;
191 			return;
192 		}
193 
194 		program = linkProgram(createProgram());
195 		if (program == -1) {
196 			isCompiled = false;
197 			return;
198 		}
199 
200 		isCompiled = true;
201 	}
202 
loadShader(int type, String source)203 	private int loadShader (int type, String source) {
204 		GL20 gl = Gdx.gl20;
205 		IntBuffer intbuf = BufferUtils.newIntBuffer(1);
206 
207 		int shader = gl.glCreateShader(type);
208 		if (shader == 0) return -1;
209 
210 		gl.glShaderSource(shader, source);
211 		gl.glCompileShader(shader);
212 		gl.glGetShaderiv(shader, GL20.GL_COMPILE_STATUS, intbuf);
213 
214 		int compiled = intbuf.get(0);
215 		if (compiled == 0) {
216 // gl.glGetShaderiv(shader, GL20.GL_INFO_LOG_LENGTH, intbuf);
217 // int infoLogLength = intbuf.get(0);
218 // if (infoLogLength > 1) {
219 			String infoLog = gl.glGetShaderInfoLog(shader);
220 			log += infoLog;
221 // }
222 			return -1;
223 		}
224 
225 		return shader;
226 	}
227 
createProgram()228 	protected int createProgram () {
229 		GL20 gl = Gdx.gl20;
230 		int program = gl.glCreateProgram();
231 		return program != 0 ? program : -1;
232 	}
233 
linkProgram(int program)234 	private int linkProgram (int program) {
235 		GL20 gl = Gdx.gl20;
236 		if (program == -1) return -1;
237 
238 		gl.glAttachShader(program, vertexShaderHandle);
239 		gl.glAttachShader(program, fragmentShaderHandle);
240 		gl.glLinkProgram(program);
241 
242 		ByteBuffer tmp = ByteBuffer.allocateDirect(4);
243 		tmp.order(ByteOrder.nativeOrder());
244 		IntBuffer intbuf = tmp.asIntBuffer();
245 
246 		gl.glGetProgramiv(program, GL20.GL_LINK_STATUS, intbuf);
247 		int linked = intbuf.get(0);
248 		if (linked == 0) {
249 // Gdx.gl20.glGetProgramiv(program, GL20.GL_INFO_LOG_LENGTH, intbuf);
250 // int infoLogLength = intbuf.get(0);
251 // if (infoLogLength > 1) {
252 			log = Gdx.gl20.glGetProgramInfoLog(program);
253 // }
254 			return -1;
255 		}
256 
257 		return program;
258 	}
259 
260 	final static IntBuffer intbuf = BufferUtils.newIntBuffer(1);
261 
262 	/** @return the log info for the shader compilation and program linking stage. The shader needs to be bound for this method to
263 	 *         have an effect. */
getLog()264 	public String getLog () {
265 		if (isCompiled) {
266 // Gdx.gl20.glGetProgramiv(program, GL20.GL_INFO_LOG_LENGTH, intbuf);
267 // int infoLogLength = intbuf.get(0);
268 // if (infoLogLength > 1) {
269 			log = Gdx.gl20.glGetProgramInfoLog(program);
270 // }
271 			return log;
272 		} else {
273 			return log;
274 		}
275 	}
276 
277 	/** @return whether this ShaderProgram compiled successfully. */
isCompiled()278 	public boolean isCompiled () {
279 		return isCompiled;
280 	}
281 
fetchAttributeLocation(String name)282 	private int fetchAttributeLocation (String name) {
283 		GL20 gl = Gdx.gl20;
284 		// -2 == not yet cached
285 		// -1 == cached but not found
286 		int location;
287 		if ((location = attributes.get(name, -2)) == -2) {
288 			location = gl.glGetAttribLocation(program, name);
289 			attributes.put(name, location);
290 		}
291 		return location;
292 	}
293 
fetchUniformLocation(String name)294 	private int fetchUniformLocation (String name) {
295 		return fetchUniformLocation(name, pedantic);
296 	}
297 
fetchUniformLocation(String name, boolean pedantic)298 	public int fetchUniformLocation (String name, boolean pedantic) {
299 		GL20 gl = Gdx.gl20;
300 		// -2 == not yet cached
301 		// -1 == cached but not found
302 		int location;
303 		if ((location = uniforms.get(name, -2)) == -2) {
304 			location = gl.glGetUniformLocation(program, name);
305 			if (location == -1 && pedantic) throw new IllegalArgumentException("no uniform with name '" + name + "' in shader");
306 			uniforms.put(name, location);
307 		}
308 		return location;
309 	}
310 
311 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
312 	 *
313 	 * @param name the name of the uniform
314 	 * @param value the value */
setUniformi(String name, int value)315 	public void setUniformi (String name, int value) {
316 		GL20 gl = Gdx.gl20;
317 		checkManaged();
318 		int location = fetchUniformLocation(name);
319 		gl.glUniform1i(location, value);
320 	}
321 
setUniformi(int location, int value)322 	public void setUniformi (int location, int value) {
323 		GL20 gl = Gdx.gl20;
324 		checkManaged();
325 		gl.glUniform1i(location, value);
326 	}
327 
328 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
329 	 *
330 	 * @param name the name of the uniform
331 	 * @param value1 the first value
332 	 * @param value2 the second value */
setUniformi(String name, int value1, int value2)333 	public void setUniformi (String name, int value1, int value2) {
334 		GL20 gl = Gdx.gl20;
335 		checkManaged();
336 		int location = fetchUniformLocation(name);
337 		gl.glUniform2i(location, value1, value2);
338 	}
339 
setUniformi(int location, int value1, int value2)340 	public void setUniformi (int location, int value1, int value2) {
341 		GL20 gl = Gdx.gl20;
342 		checkManaged();
343 		gl.glUniform2i(location, value1, value2);
344 	}
345 
346 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
347 	 *
348 	 * @param name the name of the uniform
349 	 * @param value1 the first value
350 	 * @param value2 the second value
351 	 * @param value3 the third value */
setUniformi(String name, int value1, int value2, int value3)352 	public void setUniformi (String name, int value1, int value2, int value3) {
353 		GL20 gl = Gdx.gl20;
354 		checkManaged();
355 		int location = fetchUniformLocation(name);
356 		gl.glUniform3i(location, value1, value2, value3);
357 	}
358 
setUniformi(int location, int value1, int value2, int value3)359 	public void setUniformi (int location, int value1, int value2, int value3) {
360 		GL20 gl = Gdx.gl20;
361 		checkManaged();
362 		gl.glUniform3i(location, value1, value2, value3);
363 	}
364 
365 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
366 	 *
367 	 * @param name the name of the uniform
368 	 * @param value1 the first value
369 	 * @param value2 the second value
370 	 * @param value3 the third value
371 	 * @param value4 the fourth value */
setUniformi(String name, int value1, int value2, int value3, int value4)372 	public void setUniformi (String name, int value1, int value2, int value3, int value4) {
373 		GL20 gl = Gdx.gl20;
374 		checkManaged();
375 		int location = fetchUniformLocation(name);
376 		gl.glUniform4i(location, value1, value2, value3, value4);
377 	}
378 
setUniformi(int location, int value1, int value2, int value3, int value4)379 	public void setUniformi (int location, int value1, int value2, int value3, int value4) {
380 		GL20 gl = Gdx.gl20;
381 		checkManaged();
382 		gl.glUniform4i(location, value1, value2, value3, value4);
383 	}
384 
385 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
386 	 *
387 	 * @param name the name of the uniform
388 	 * @param value the value */
setUniformf(String name, float value)389 	public void setUniformf (String name, float value) {
390 		GL20 gl = Gdx.gl20;
391 		checkManaged();
392 		int location = fetchUniformLocation(name);
393 		gl.glUniform1f(location, value);
394 	}
395 
setUniformf(int location, float value)396 	public void setUniformf (int location, float value) {
397 		GL20 gl = Gdx.gl20;
398 		checkManaged();
399 		gl.glUniform1f(location, value);
400 	}
401 
402 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
403 	 *
404 	 * @param name the name of the uniform
405 	 * @param value1 the first value
406 	 * @param value2 the second value */
setUniformf(String name, float value1, float value2)407 	public void setUniformf (String name, float value1, float value2) {
408 		GL20 gl = Gdx.gl20;
409 		checkManaged();
410 		int location = fetchUniformLocation(name);
411 		gl.glUniform2f(location, value1, value2);
412 	}
413 
setUniformf(int location, float value1, float value2)414 	public void setUniformf (int location, float value1, float value2) {
415 		GL20 gl = Gdx.gl20;
416 		checkManaged();
417 		gl.glUniform2f(location, value1, value2);
418 	}
419 
420 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
421 	 *
422 	 * @param name the name of the uniform
423 	 * @param value1 the first value
424 	 * @param value2 the second value
425 	 * @param value3 the third value */
setUniformf(String name, float value1, float value2, float value3)426 	public void setUniformf (String name, float value1, float value2, float value3) {
427 		GL20 gl = Gdx.gl20;
428 		checkManaged();
429 		int location = fetchUniformLocation(name);
430 		gl.glUniform3f(location, value1, value2, value3);
431 	}
432 
setUniformf(int location, float value1, float value2, float value3)433 	public void setUniformf (int location, float value1, float value2, float value3) {
434 		GL20 gl = Gdx.gl20;
435 		checkManaged();
436 		gl.glUniform3f(location, value1, value2, value3);
437 	}
438 
439 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
440 	 *
441 	 * @param name the name of the uniform
442 	 * @param value1 the first value
443 	 * @param value2 the second value
444 	 * @param value3 the third value
445 	 * @param value4 the fourth value */
setUniformf(String name, float value1, float value2, float value3, float value4)446 	public void setUniformf (String name, float value1, float value2, float value3, float value4) {
447 		GL20 gl = Gdx.gl20;
448 		checkManaged();
449 		int location = fetchUniformLocation(name);
450 		gl.glUniform4f(location, value1, value2, value3, value4);
451 	}
452 
setUniformf(int location, float value1, float value2, float value3, float value4)453 	public void setUniformf (int location, float value1, float value2, float value3, float value4) {
454 		GL20 gl = Gdx.gl20;
455 		checkManaged();
456 		gl.glUniform4f(location, value1, value2, value3, value4);
457 	}
458 
setUniform1fv(String name, float[] values, int offset, int length)459 	public void setUniform1fv (String name, float[] values, int offset, int length) {
460 		GL20 gl = Gdx.gl20;
461 		checkManaged();
462 		int location = fetchUniformLocation(name);
463 		gl.glUniform1fv(location, length, values, offset);
464 	}
465 
setUniform1fv(int location, float[] values, int offset, int length)466 	public void setUniform1fv (int location, float[] values, int offset, int length) {
467 		GL20 gl = Gdx.gl20;
468 		checkManaged();
469 		gl.glUniform1fv(location, length, values, offset);
470 	}
471 
setUniform2fv(String name, float[] values, int offset, int length)472 	public void setUniform2fv (String name, float[] values, int offset, int length) {
473 		GL20 gl = Gdx.gl20;
474 		checkManaged();
475 		int location = fetchUniformLocation(name);
476 		gl.glUniform2fv(location, length / 2, values, offset);
477 	}
478 
setUniform2fv(int location, float[] values, int offset, int length)479 	public void setUniform2fv (int location, float[] values, int offset, int length) {
480 		GL20 gl = Gdx.gl20;
481 		checkManaged();
482 		gl.glUniform2fv(location, length / 2, values, offset);
483 	}
484 
setUniform3fv(String name, float[] values, int offset, int length)485 	public void setUniform3fv (String name, float[] values, int offset, int length) {
486 		GL20 gl = Gdx.gl20;
487 		checkManaged();
488 		int location = fetchUniformLocation(name);
489 		gl.glUniform3fv(location, length / 3, values, offset);
490 	}
491 
setUniform3fv(int location, float[] values, int offset, int length)492 	public void setUniform3fv (int location, float[] values, int offset, int length) {
493 		GL20 gl = Gdx.gl20;
494 		checkManaged();
495 		gl.glUniform3fv(location, length / 3, values, offset);
496 	}
497 
setUniform4fv(String name, float[] values, int offset, int length)498 	public void setUniform4fv (String name, float[] values, int offset, int length) {
499 		GL20 gl = Gdx.gl20;
500 		checkManaged();
501 		int location = fetchUniformLocation(name);
502 		gl.glUniform4fv(location, length / 4, values, offset);
503 	}
504 
setUniform4fv(int location, float[] values, int offset, int length)505 	public void setUniform4fv (int location, float[] values, int offset, int length) {
506 		GL20 gl = Gdx.gl20;
507 		checkManaged();
508 		gl.glUniform4fv(location, length / 4, values, offset);
509 	}
510 
511 	/** Sets the uniform matrix with the given name. The {@link ShaderProgram} must be bound for this to work.
512 	 *
513 	 * @param name the name of the uniform
514 	 * @param matrix the matrix */
setUniformMatrix(String name, Matrix4 matrix)515 	public void setUniformMatrix (String name, Matrix4 matrix) {
516 		setUniformMatrix(name, matrix, false);
517 	}
518 
519 	/** Sets the uniform matrix with the given name. The {@link ShaderProgram} must be bound for this to work.
520 	 *
521 	 * @param name the name of the uniform
522 	 * @param matrix the matrix
523 	 * @param transpose whether the matrix should be transposed */
setUniformMatrix(String name, Matrix4 matrix, boolean transpose)524 	public void setUniformMatrix (String name, Matrix4 matrix, boolean transpose) {
525 		setUniformMatrix(fetchUniformLocation(name), matrix, transpose);
526 	}
527 
setUniformMatrix(int location, Matrix4 matrix)528 	public void setUniformMatrix (int location, Matrix4 matrix) {
529 		setUniformMatrix(location, matrix, false);
530 	}
531 
setUniformMatrix(int location, Matrix4 matrix, boolean transpose)532 	public void setUniformMatrix (int location, Matrix4 matrix, boolean transpose) {
533 		GL20 gl = Gdx.gl20;
534 		checkManaged();
535 		gl.glUniformMatrix4fv(location, 1, transpose, matrix.val, 0);
536 	}
537 
538 	/** Sets the uniform matrix with the given name. The {@link ShaderProgram} must be bound for this to work.
539 	 *
540 	 * @param name the name of the uniform
541 	 * @param matrix the matrix */
setUniformMatrix(String name, Matrix3 matrix)542 	public void setUniformMatrix (String name, Matrix3 matrix) {
543 		setUniformMatrix(name, matrix, false);
544 	}
545 
546 	/** Sets the uniform matrix with the given name. The {@link ShaderProgram} must be bound for this to work.
547 	 *
548 	 * @param name the name of the uniform
549 	 * @param matrix the matrix
550 	 * @param transpose whether the uniform matrix should be transposed */
setUniformMatrix(String name, Matrix3 matrix, boolean transpose)551 	public void setUniformMatrix (String name, Matrix3 matrix, boolean transpose) {
552 		setUniformMatrix(fetchUniformLocation(name), matrix, transpose);
553 	}
554 
setUniformMatrix(int location, Matrix3 matrix)555 	public void setUniformMatrix (int location, Matrix3 matrix) {
556 		setUniformMatrix(location, matrix, false);
557 	}
558 
setUniformMatrix(int location, Matrix3 matrix, boolean transpose)559 	public void setUniformMatrix (int location, Matrix3 matrix, boolean transpose) {
560 		GL20 gl = Gdx.gl20;
561 		checkManaged();
562 		gl.glUniformMatrix3fv(location, 1, transpose, matrix.val, 0);
563 	}
564 
565 	/** Sets an array of uniform matrices with the given name. The {@link ShaderProgram} must be bound for this to work.
566 	 *
567 	 * @param name the name of the uniform
568 	 * @param buffer buffer containing the matrix data
569 	 * @param transpose whether the uniform matrix should be transposed */
setUniformMatrix3fv(String name, FloatBuffer buffer, int count, boolean transpose)570 	public void setUniformMatrix3fv (String name, FloatBuffer buffer, int count, boolean transpose) {
571 		GL20 gl = Gdx.gl20;
572 		checkManaged();
573 		buffer.position(0);
574 		int location = fetchUniformLocation(name);
575 		gl.glUniformMatrix3fv(location, count, transpose, buffer);
576 	}
577 
578 	/** Sets an array of uniform matrices with the given name. The {@link ShaderProgram} must be bound for this to work.
579 	 *
580 	 * @param name the name of the uniform
581 	 * @param buffer buffer containing the matrix data
582 	 * @param transpose whether the uniform matrix should be transposed */
setUniformMatrix4fv(String name, FloatBuffer buffer, int count, boolean transpose)583 	public void setUniformMatrix4fv (String name, FloatBuffer buffer, int count, boolean transpose) {
584 		GL20 gl = Gdx.gl20;
585 		checkManaged();
586 		buffer.position(0);
587 		int location = fetchUniformLocation(name);
588 		gl.glUniformMatrix4fv(location, count, transpose, buffer);
589 	}
590 
setUniformMatrix4fv(int location, float[] values, int offset, int length)591 	public void setUniformMatrix4fv (int location, float[] values, int offset, int length) {
592 		GL20 gl = Gdx.gl20;
593 		checkManaged();
594 		gl.glUniformMatrix4fv(location, length / 16, false, values, offset);
595 	}
596 
setUniformMatrix4fv(String name, float[] values, int offset, int length)597 	public void setUniformMatrix4fv (String name, float[] values, int offset, int length) {
598 		setUniformMatrix4fv(fetchUniformLocation(name), values, offset, length);
599 	}
600 
601 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
602 	 *
603 	 * @param name the name of the uniform
604 	 * @param values x and y as the first and second values respectively */
setUniformf(String name, Vector2 values)605 	public void setUniformf (String name, Vector2 values) {
606 		setUniformf(name, values.x, values.y);
607 	}
608 
setUniformf(int location, Vector2 values)609 	public void setUniformf (int location, Vector2 values) {
610 		setUniformf(location, values.x, values.y);
611 	}
612 
613 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
614 	 *
615 	 * @param name the name of the uniform
616 	 * @param values x, y and z as the first, second and third values respectively */
setUniformf(String name, Vector3 values)617 	public void setUniformf (String name, Vector3 values) {
618 		setUniformf(name, values.x, values.y, values.z);
619 	}
620 
setUniformf(int location, Vector3 values)621 	public void setUniformf (int location, Vector3 values) {
622 		setUniformf(location, values.x, values.y, values.z);
623 	}
624 
625 	/** Sets the uniform with the given name. The {@link ShaderProgram} must be bound for this to work.
626 	 *
627 	 * @param name the name of the uniform
628 	 * @param values r, g, b and a as the first through fourth values respectively */
setUniformf(String name, Color values)629 	public void setUniformf (String name, Color values) {
630 		setUniformf(name, values.r, values.g, values.b, values.a);
631 	}
632 
setUniformf(int location, Color values)633 	public void setUniformf (int location, Color values) {
634 		setUniformf(location, values.r, values.g, values.b, values.a);
635 	}
636 
637 	/** Sets the vertex attribute with the given name. The {@link ShaderProgram} must be bound for this to work.
638 	 *
639 	 * @param name the attribute name
640 	 * @param size the number of components, must be >= 1 and <= 4
641 	 * @param type the type, must be one of GL20.GL_BYTE, GL20.GL_UNSIGNED_BYTE, GL20.GL_SHORT,
642 	 *           GL20.GL_UNSIGNED_SHORT,GL20.GL_FIXED, or GL20.GL_FLOAT. GL_FIXED will not work on the desktop
643 	 * @param normalize whether fixed point data should be normalized. Will not work on the desktop
644 	 * @param stride the stride in bytes between successive attributes
645 	 * @param buffer the buffer containing the vertex attributes. */
setVertexAttribute(String name, int size, int type, boolean normalize, int stride, Buffer buffer)646 	public void setVertexAttribute (String name, int size, int type, boolean normalize, int stride, Buffer buffer) {
647 		GL20 gl = Gdx.gl20;
648 		checkManaged();
649 		int location = fetchAttributeLocation(name);
650 		if (location == -1) return;
651 		gl.glVertexAttribPointer(location, size, type, normalize, stride, buffer);
652 	}
653 
setVertexAttribute(int location, int size, int type, boolean normalize, int stride, Buffer buffer)654 	public void setVertexAttribute (int location, int size, int type, boolean normalize, int stride, Buffer buffer) {
655 		GL20 gl = Gdx.gl20;
656 		checkManaged();
657 		gl.glVertexAttribPointer(location, size, type, normalize, stride, buffer);
658 	}
659 
660 	/** Sets the vertex attribute with the given name. The {@link ShaderProgram} must be bound for this to work.
661 	 *
662 	 * @param name the attribute name
663 	 * @param size the number of components, must be >= 1 and <= 4
664 	 * @param type the type, must be one of GL20.GL_BYTE, GL20.GL_UNSIGNED_BYTE, GL20.GL_SHORT,
665 	 *           GL20.GL_UNSIGNED_SHORT,GL20.GL_FIXED, or GL20.GL_FLOAT. GL_FIXED will not work on the desktop
666 	 * @param normalize whether fixed point data should be normalized. Will not work on the desktop
667 	 * @param stride the stride in bytes between successive attributes
668 	 * @param offset byte offset into the vertex buffer object bound to GL20.GL_ARRAY_BUFFER. */
setVertexAttribute(String name, int size, int type, boolean normalize, int stride, int offset)669 	public void setVertexAttribute (String name, int size, int type, boolean normalize, int stride, int offset) {
670 		GL20 gl = Gdx.gl20;
671 		checkManaged();
672 		int location = fetchAttributeLocation(name);
673 		if (location == -1) return;
674 		gl.glVertexAttribPointer(location, size, type, normalize, stride, offset);
675 	}
676 
setVertexAttribute(int location, int size, int type, boolean normalize, int stride, int offset)677 	public void setVertexAttribute (int location, int size, int type, boolean normalize, int stride, int offset) {
678 		GL20 gl = Gdx.gl20;
679 		checkManaged();
680 		gl.glVertexAttribPointer(location, size, type, normalize, stride, offset);
681 	}
682 
683 	/** Makes OpenGL ES 2.0 use this vertex and fragment shader pair. When you are done with this shader you have to call
684 	 * {@link ShaderProgram#end()}. */
begin()685 	public void begin () {
686 		GL20 gl = Gdx.gl20;
687 		checkManaged();
688 		gl.glUseProgram(program);
689 	}
690 
691 	/** Disables this shader. Must be called when one is done with the shader. Don't mix it with dispose, that will release the
692 	 * shader resources. */
end()693 	public void end () {
694 		GL20 gl = Gdx.gl20;
695 		gl.glUseProgram(0);
696 	}
697 
698 	/** Disposes all resources associated with this shader. Must be called when the shader is no longer used. */
dispose()699 	public void dispose () {
700 		GL20 gl = Gdx.gl20;
701 		gl.glUseProgram(0);
702 		gl.glDeleteShader(vertexShaderHandle);
703 		gl.glDeleteShader(fragmentShaderHandle);
704 		gl.glDeleteProgram(program);
705 		if (shaders.get(Gdx.app) != null) shaders.get(Gdx.app).removeValue(this, true);
706 	}
707 
708 	/** Disables the vertex attribute with the given name
709 	 *
710 	 * @param name the vertex attribute name */
disableVertexAttribute(String name)711 	public void disableVertexAttribute (String name) {
712 		GL20 gl = Gdx.gl20;
713 		checkManaged();
714 		int location = fetchAttributeLocation(name);
715 		if (location == -1) return;
716 		gl.glDisableVertexAttribArray(location);
717 	}
718 
disableVertexAttribute(int location)719 	public void disableVertexAttribute (int location) {
720 		GL20 gl = Gdx.gl20;
721 		checkManaged();
722 		gl.glDisableVertexAttribArray(location);
723 	}
724 
725 	/** Enables the vertex attribute with the given name
726 	 *
727 	 * @param name the vertex attribute name */
enableVertexAttribute(String name)728 	public void enableVertexAttribute (String name) {
729 		GL20 gl = Gdx.gl20;
730 		checkManaged();
731 		int location = fetchAttributeLocation(name);
732 		if (location == -1) return;
733 		gl.glEnableVertexAttribArray(location);
734 	}
735 
enableVertexAttribute(int location)736 	public void enableVertexAttribute (int location) {
737 		GL20 gl = Gdx.gl20;
738 		checkManaged();
739 		gl.glEnableVertexAttribArray(location);
740 	}
741 
checkManaged()742 	private void checkManaged () {
743 		if (invalidated) {
744 			compileShaders(vertexShaderSource, fragmentShaderSource);
745 			invalidated = false;
746 		}
747 	}
748 
addManagedShader(Application app, ShaderProgram shaderProgram)749 	private void addManagedShader (Application app, ShaderProgram shaderProgram) {
750 		Array<ShaderProgram> managedResources = shaders.get(app);
751 		if (managedResources == null) managedResources = new Array<ShaderProgram>();
752 		managedResources.add(shaderProgram);
753 		shaders.put(app, managedResources);
754 	}
755 
756 	/** Invalidates all shaders so the next time they are used new handles are generated
757 	 * @param app */
invalidateAllShaderPrograms(Application app)758 	public static void invalidateAllShaderPrograms (Application app) {
759 		if (Gdx.gl20 == null) return;
760 
761 		Array<ShaderProgram> shaderArray = shaders.get(app);
762 		if (shaderArray == null) return;
763 
764 		for (int i = 0; i < shaderArray.size; i++) {
765 			shaderArray.get(i).invalidated = true;
766 			shaderArray.get(i).checkManaged();
767 		}
768 	}
769 
clearAllShaderPrograms(Application app)770 	public static void clearAllShaderPrograms (Application app) {
771 		shaders.remove(app);
772 	}
773 
getManagedStatus()774 	public static String getManagedStatus () {
775 		StringBuilder builder = new StringBuilder();
776 		int i = 0;
777 		builder.append("Managed shaders/app: { ");
778 		for (Application app : shaders.keys()) {
779 			builder.append(shaders.get(app).size);
780 			builder.append(" ");
781 		}
782 		builder.append("}");
783 		return builder.toString();
784 	}
785 
786 	/** @return the number of managed shader programs currently loaded */
getNumManagedShaderPrograms()787 	public static int getNumManagedShaderPrograms () {
788 		return shaders.get(Gdx.app).size;
789 	}
790 
791 	/** Sets the given attribute
792 	 *
793 	 * @param name the name of the attribute
794 	 * @param value1 the first value
795 	 * @param value2 the second value
796 	 * @param value3 the third value
797 	 * @param value4 the fourth value */
setAttributef(String name, float value1, float value2, float value3, float value4)798 	public void setAttributef (String name, float value1, float value2, float value3, float value4) {
799 		GL20 gl = Gdx.gl20;
800 		int location = fetchAttributeLocation(name);
801 		gl.glVertexAttrib4f(location, value1, value2, value3, value4);
802 	}
803 
804 	IntBuffer params = BufferUtils.newIntBuffer(1);
805 	IntBuffer type = BufferUtils.newIntBuffer(1);
806 
fetchUniforms()807 	private void fetchUniforms () {
808 		params.clear();
809 		Gdx.gl20.glGetProgramiv(program, GL20.GL_ACTIVE_UNIFORMS, params);
810 		int numUniforms = params.get(0);
811 
812 		uniformNames = new String[numUniforms];
813 
814 		for (int i = 0; i < numUniforms; i++) {
815 			params.clear();
816 			params.put(0, 1);
817 			type.clear();
818 			String name = Gdx.gl20.glGetActiveUniform(program, i, params, type);
819 			int location = Gdx.gl20.glGetUniformLocation(program, name);
820 			uniforms.put(name, location);
821 			uniformTypes.put(name, type.get(0));
822 			uniformSizes.put(name, params.get(0));
823 			uniformNames[i] = name;
824 		}
825 	}
826 
fetchAttributes()827 	private void fetchAttributes () {
828 		params.clear();
829 		Gdx.gl20.glGetProgramiv(program, GL20.GL_ACTIVE_ATTRIBUTES, params);
830 		int numAttributes = params.get(0);
831 
832 		attributeNames = new String[numAttributes];
833 
834 		for (int i = 0; i < numAttributes; i++) {
835 			params.clear();
836 			params.put(0, 1);
837 			type.clear();
838 			String name = Gdx.gl20.glGetActiveAttrib(program, i, params, type);
839 			int location = Gdx.gl20.glGetAttribLocation(program, name);
840 			attributes.put(name, location);
841 			attributeTypes.put(name, type.get(0));
842 			attributeSizes.put(name, params.get(0));
843 			attributeNames[i] = name;
844 		}
845 	}
846 
847 	/** @param name the name of the attribute
848 	 * @return whether the attribute is available in the shader */
hasAttribute(String name)849 	public boolean hasAttribute (String name) {
850 		return attributes.containsKey(name);
851 	}
852 
853 	/** @param name the name of the attribute
854 	 * @return the type of the attribute, one of {@link GL20#GL_FLOAT}, {@link GL20#GL_FLOAT_VEC2} etc. */
getAttributeType(String name)855 	public int getAttributeType (String name) {
856 		return attributeTypes.get(name, 0);
857 	}
858 
859 	/** @param name the name of the attribute
860 	 * @return the location of the attribute or -1. */
getAttributeLocation(String name)861 	public int getAttributeLocation (String name) {
862 		return attributes.get(name, -1);
863 	}
864 
865 	/** @param name the name of the attribute
866 	 * @return the size of the attribute or 0. */
getAttributeSize(String name)867 	public int getAttributeSize (String name) {
868 		return attributeSizes.get(name, 0);
869 	}
870 
871 	/** @param name the name of the uniform
872 	 * @return whether the uniform is available in the shader */
hasUniform(String name)873 	public boolean hasUniform (String name) {
874 		return uniforms.containsKey(name);
875 	}
876 
877 	/** @param name the name of the uniform
878 	 * @return the type of the uniform, one of {@link GL20#GL_FLOAT}, {@link GL20#GL_FLOAT_VEC2} etc. */
getUniformType(String name)879 	public int getUniformType (String name) {
880 		return uniformTypes.get(name, 0);
881 	}
882 
883 	/** @param name the name of the uniform
884 	 * @return the location of the uniform or -1. */
getUniformLocation(String name)885 	public int getUniformLocation (String name) {
886 		return uniforms.get(name, -1);
887 	}
888 
889 	/** @param name the name of the uniform
890 	 * @return the size of the uniform or 0. */
getUniformSize(String name)891 	public int getUniformSize (String name) {
892 		return uniformSizes.get(name, 0);
893 	}
894 
895 	/** @return the attributes */
getAttributes()896 	public String[] getAttributes () {
897 		return attributeNames;
898 	}
899 
900 	/** @return the uniforms */
getUniforms()901 	public String[] getUniforms () {
902 		return uniformNames;
903 	}
904 
905 	/** @return the source of the vertex shader */
getVertexShaderSource()906 	public String getVertexShaderSource () {
907 		return vertexShaderSource;
908 	}
909 
910 	/** @return the source of the fragment shader */
getFragmentShaderSource()911 	public String getFragmentShaderSource () {
912 		return fragmentShaderSource;
913 	}
914 }
915