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 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 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 */ 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 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 228 protected int createProgram () { 229 GL20 gl = Gdx.gl20; 230 int program = gl.glCreateProgram(); 231 return program != 0 ? program : -1; 232 } 233 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. */ 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. */ 278 public boolean isCompiled () { 279 return isCompiled; 280 } 281 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 294 private int fetchUniformLocation (String name) { 295 return fetchUniformLocation(name, pedantic); 296 } 297 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 */ 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 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 */ 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 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 */ 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 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 */ 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 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 */ 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 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 */ 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 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 */ 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 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 */ 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 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 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 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 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 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 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 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 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 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 */ 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 */ 524 public void setUniformMatrix (String name, Matrix4 matrix, boolean transpose) { 525 setUniformMatrix(fetchUniformLocation(name), matrix, transpose); 526 } 527 528 public void setUniformMatrix (int location, Matrix4 matrix) { 529 setUniformMatrix(location, matrix, false); 530 } 531 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 */ 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 */ 551 public void setUniformMatrix (String name, Matrix3 matrix, boolean transpose) { 552 setUniformMatrix(fetchUniformLocation(name), matrix, transpose); 553 } 554 555 public void setUniformMatrix (int location, Matrix3 matrix) { 556 setUniformMatrix(location, matrix, false); 557 } 558 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 */ 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 */ 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 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 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 */ 605 public void setUniformf (String name, Vector2 values) { 606 setUniformf(name, values.x, values.y); 607 } 608 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 */ 617 public void setUniformf (String name, Vector3 values) { 618 setUniformf(name, values.x, values.y, values.z); 619 } 620 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 */ 629 public void setUniformf (String name, Color values) { 630 setUniformf(name, values.r, values.g, values.b, values.a); 631 } 632 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. */ 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 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. */ 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 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()}. */ 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. */ 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. */ 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 */ 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 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 */ 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 736 public void enableVertexAttribute (int location) { 737 GL20 gl = Gdx.gl20; 738 checkManaged(); 739 gl.glEnableVertexAttribArray(location); 740 } 741 742 private void checkManaged () { 743 if (invalidated) { 744 compileShaders(vertexShaderSource, fragmentShaderSource); 745 invalidated = false; 746 } 747 } 748 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 */ 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 770 public static void clearAllShaderPrograms (Application app) { 771 shaders.remove(app); 772 } 773 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 */ 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 */ 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 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 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 */ 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. */ 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. */ 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. */ 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 */ 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. */ 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. */ 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. */ 891 public int getUniformSize (String name) { 892 return uniformSizes.get(name, 0); 893 } 894 895 /** @return the attributes */ 896 public String[] getAttributes () { 897 return attributeNames; 898 } 899 900 /** @return the uniforms */ 901 public String[] getUniforms () { 902 return uniformNames; 903 } 904 905 /** @return the source of the vertex shader */ 906 public String getVertexShaderSource () { 907 return vertexShaderSource; 908 } 909 910 /** @return the source of the fragment shader */ 911 public String getFragmentShaderSource () { 912 return fragmentShaderSource; 913 } 914 } 915