1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.jme3.renderer.android; 33 34 import android.opengl.GLES10; 35 import android.opengl.GLES20; 36 import android.os.Build; 37 import com.jme3.asset.AndroidImageInfo; 38 import com.jme3.light.LightList; 39 import com.jme3.material.RenderState; 40 import com.jme3.math.*; 41 import com.jme3.renderer.*; 42 import com.jme3.scene.Mesh; 43 import com.jme3.scene.Mesh.Mode; 44 import com.jme3.scene.VertexBuffer; 45 import com.jme3.scene.VertexBuffer.Format; 46 import com.jme3.scene.VertexBuffer.Type; 47 import com.jme3.scene.VertexBuffer.Usage; 48 import com.jme3.shader.Attribute; 49 import com.jme3.shader.Shader; 50 import com.jme3.shader.Shader.ShaderSource; 51 import com.jme3.shader.Shader.ShaderType; 52 import com.jme3.shader.Uniform; 53 import com.jme3.texture.FrameBuffer; 54 import com.jme3.texture.FrameBuffer.RenderBuffer; 55 import com.jme3.texture.Image; 56 import com.jme3.texture.Texture; 57 import com.jme3.texture.Texture.WrapAxis; 58 import com.jme3.util.BufferUtils; 59 import com.jme3.util.ListMap; 60 import com.jme3.util.NativeObjectManager; 61 import java.nio.*; 62 import java.util.EnumSet; 63 import java.util.List; 64 import java.util.logging.Level; 65 import java.util.logging.Logger; 66 67 public class OGLESShaderRenderer implements Renderer { 68 69 private static final Logger logger = Logger.getLogger(OGLESShaderRenderer.class.getName()); 70 private static final boolean VALIDATE_SHADER = false; 71 private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); 72 private final StringBuilder stringBuf = new StringBuilder(250); 73 private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); 74 private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16); 75 private final RenderContext context = new RenderContext(); 76 private final NativeObjectManager objManager = new NativeObjectManager(); 77 private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class); 78 // current state 79 private Shader boundShader; 80 private int initialDrawBuf, initialReadBuf; 81 private int glslVer; 82 private int vertexTextureUnits; 83 private int fragTextureUnits; 84 private int vertexUniforms; 85 private int fragUniforms; 86 private int vertexAttribs; 87 private int maxFBOSamples; 88 private int maxFBOAttachs; 89 private int maxMRTFBOAttachs; 90 private int maxRBSize; 91 private int maxTexSize; 92 private int maxCubeTexSize; 93 private int maxVertCount; 94 private int maxTriCount; 95 private boolean tdc; 96 private FrameBuffer lastFb = null; 97 private final Statistics statistics = new Statistics(); 98 private int vpX, vpY, vpW, vpH; 99 private int clipX, clipY, clipW, clipH; 100 //private final GL10 gl; 101 private boolean powerVr = false; 102 private boolean powerOf2 = false; 103 private boolean verboseLogging = false; 104 private boolean useVBO = false; 105 private boolean checkErrors = true; 106 107 public OGLESShaderRenderer() { 108 } 109 110 public void setUseVA(boolean value) { 111 logger.log(Level.INFO, "use_VBO [{0}] -> [{1}]", new Object[]{useVBO, !value}); 112 useVBO = !value; 113 } 114 115 public void setVerboseLogging(boolean value) { 116 logger.log(Level.INFO, "verboseLogging [{0}] -> [{1}]", new Object[]{verboseLogging, value}); 117 verboseLogging = value; 118 } 119 120 protected void updateNameBuffer() { 121 int len = stringBuf.length(); 122 123 nameBuf.position(0); 124 nameBuf.limit(len); 125 for (int i = 0; i < len; i++) { 126 nameBuf.put((byte) stringBuf.charAt(i)); 127 } 128 129 nameBuf.rewind(); 130 } 131 132 private void checkGLError() { 133 if (!checkErrors) return; 134 int error; 135 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 136 throw new RendererException("OpenGL Error " + error); 137 } 138 } 139 140 private boolean log(String message) { 141 logger.info(message); 142 return true; 143 } 144 145 public Statistics getStatistics() { 146 return statistics; 147 } 148 149 public EnumSet<Caps> getCaps() { 150 return caps; 151 } 152 153 public void initialize() { 154 155 logger.log(Level.INFO, "Vendor: {0}", GLES20.glGetString(GLES20.GL_VENDOR)); 156 logger.log(Level.INFO, "Renderer: {0}", GLES20.glGetString(GLES20.GL_RENDERER)); 157 logger.log(Level.INFO, "Version: {0}", GLES20.glGetString(GLES20.GL_VERSION)); 158 159 powerVr = GLES20.glGetString(GLES20.GL_RENDERER).contains("PowerVR"); 160 161 String versionStr = GLES20.glGetString(GLES20.GL_SHADING_LANGUAGE_VERSION); 162 logger.log(Level.INFO, "GLES20.Shading Language Version: {0}", versionStr); 163 if (versionStr == null || versionStr.equals("")) { 164 glslVer = -1; 165 throw new UnsupportedOperationException("GLSL and OpenGL2 is " 166 + "required for the OpenGL ES " 167 + "renderer!"); 168 } 169 170 // Fix issue in TestRenderToMemory when GL_FRONT is the main 171 // buffer being used. 172 173 // initialDrawBuf = GLES20.glGetIntegeri(GLES20.GL_DRAW_BUFFER); 174 // initialReadBuf = GLES20.glGetIntegeri(GLES20.GL_READ_BUFFER); 175 176 String openGlEsStr = "OpenGL ES GLSL ES "; 177 int spaceIdx = versionStr.indexOf(" ", openGlEsStr.length()); 178 if (spaceIdx >= 1) { 179 versionStr = versionStr.substring(openGlEsStr.length(), spaceIdx).trim(); 180 }else{ 181 versionStr = versionStr.substring(openGlEsStr.length()).trim(); 182 } 183 184 float version = Float.parseFloat(versionStr); 185 glslVer = (int) (version * 100); 186 187 switch (glslVer) { 188 // TODO: When new versions of OpenGL ES shader language come out, 189 // update this. 190 default: 191 caps.add(Caps.GLSL100); 192 break; 193 } 194 195 if (!caps.contains(Caps.GLSL100)) { 196 logger.info("Force-adding GLSL100 support, since OpenGL2 is supported."); 197 caps.add(Caps.GLSL100); 198 } 199 200 GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, intBuf16); 201 vertexTextureUnits = intBuf16.get(0); 202 logger.log(Level.INFO, "VTF Units: {0}", vertexTextureUnits); 203 if (vertexTextureUnits > 0) { 204 caps.add(Caps.VertexTextureFetch); 205 } 206 207 GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, intBuf16); 208 fragTextureUnits = intBuf16.get(0); 209 logger.log(Level.INFO, "Texture Units: {0}", fragTextureUnits); 210 /* 211 GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); 212 vertexUniforms = intBuf16.get(0); 213 logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); 214 215 GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); 216 fragUniforms = intBuf16.get(0); 217 logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); 218 */ 219 220 GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_ATTRIBS, intBuf16); 221 vertexAttribs = intBuf16.get(0); 222 logger.log(Level.INFO, "Vertex Attributes: {0}", vertexAttribs); 223 224 /* 225 GLES20.glGetIntegerv(GLES20.GL_MAX_VARYING_FLOATS, intBuf16); 226 int varyingFloats = intBuf16.get(0); 227 logger.log(Level.FINER, "Varying Floats: {0}", varyingFloats); 228 */ 229 230 GLES20.glGetIntegerv(GLES20.GL_SUBPIXEL_BITS, intBuf16); 231 int subpixelBits = intBuf16.get(0); 232 logger.log(Level.INFO, "Subpixel Bits: {0}", subpixelBits); 233 /* 234 GLES20.glGetIntegerv(GLES20.GL_MAX_ELEMENTS_VERTICES, intBuf16); 235 maxVertCount = intBuf16.get(0); 236 logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); 237 238 GLES20.glGetIntegerv(GLES20.GL_MAX_ELEMENTS_INDICES, intBuf16); 239 maxTriCount = intBuf16.get(0); 240 logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); 241 */ 242 GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, intBuf16); 243 maxTexSize = intBuf16.get(0); 244 logger.log(Level.INFO, "Maximum Texture Resolution: {0}", maxTexSize); 245 246 GLES20.glGetIntegerv(GLES20.GL_MAX_CUBE_MAP_TEXTURE_SIZE, intBuf16); 247 maxCubeTexSize = intBuf16.get(0); 248 logger.log(Level.INFO, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); 249 250 251 /* 252 if (ctxCaps.GL_ARB_color_buffer_float){ 253 // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. 254 if (ctxCaps.GL_ARB_half_float_pixel){ 255 caps.add(Caps.FloatColorBuffer); 256 } 257 } 258 259 if (ctxCaps.GL_ARB_depth_buffer_float){ 260 caps.add(Caps.FloatDepthBuffer); 261 } 262 263 if (ctxCaps.GL_ARB_draw_instanced) 264 caps.add(Caps.MeshInstancing); 265 266 if (ctxCaps.GL_ARB_fragment_program) 267 caps.add(Caps.ARBprogram); 268 269 if (ctxCaps.GL_ARB_texture_buffer_object) 270 caps.add(Caps.TextureBuffer); 271 272 if (ctxCaps.GL_ARB_texture_float){ 273 if (ctxCaps.GL_ARB_half_float_pixel){ 274 caps.add(Caps.FloatTexture); 275 } 276 } 277 278 if (ctxCaps.GL_ARB_vertex_array_object) 279 caps.add(Caps.VertexBufferArray); 280 281 boolean latc = ctxCaps.GL_EXT_texture_compression_latc; 282 boolean atdc = ctxCaps.GL_ATI_texture_compression_3dc; 283 if (latc || atdc){ 284 caps.add(Caps.TextureCompressionLATC); 285 if (atdc && !latc){ 286 tdc = true; 287 } 288 } 289 290 if (ctxCaps.GL_EXT_packed_float){ 291 caps.add(Caps.PackedFloatColorBuffer); 292 if (ctxCaps.GL_ARB_half_float_pixel){ 293 // because textures are usually uploaded as RGB16F 294 // need half-float pixel 295 caps.add(Caps.PackedFloatTexture); 296 } 297 } 298 299 if (ctxCaps.GL_EXT_texture_array) 300 caps.add(Caps.TextureArray); 301 302 if (ctxCaps.GL_EXT_texture_shared_exponent) 303 caps.add(Caps.SharedExponentTexture); 304 305 if (ctxCaps.GL_EXT_framebuffer_object){ 306 caps.add(Caps.FrameBuffer); 307 308 glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT, intBuf16); 309 maxRBSize = intBuf16.get(0); 310 logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); 311 312 glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT, intBuf16); 313 maxFBOAttachs = intBuf16.get(0); 314 logger.log(Level.FINER, "FBO Max renderbuffers: {0}", maxFBOAttachs); 315 316 if (ctxCaps.GL_EXT_framebuffer_multisample){ 317 caps.add(Caps.FrameBufferMultisample); 318 319 glGetInteger(GL_MAX_SAMPLES_EXT, intBuf16); 320 maxFBOSamples = intBuf16.get(0); 321 logger.log(Level.FINER, "FBO Max Samples: {0}", maxFBOSamples); 322 } 323 324 if (ctxCaps.GL_ARB_draw_buffers){ 325 caps.add(Caps.FrameBufferMRT); 326 glGetInteger(ARBDrawBuffers.GL_MAX_DRAW_BUFFERS_ARB, intBuf16); 327 maxMRTFBOAttachs = intBuf16.get(0); 328 logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); 329 } 330 } 331 332 if (ctxCaps.GL_ARB_multisample){ 333 glGetInteger(ARBMultisample.GL_SAMPLE_BUFFERS_ARB, intBuf16); 334 boolean available = intBuf16.get(0) != 0; 335 glGetInteger(ARBMultisample.GL_SAMPLES_ARB, intBuf16); 336 int samples = intBuf16.get(0); 337 logger.log(Level.FINER, "Samples: {0}", samples); 338 boolean enabled = glIsEnabled(ARBMultisample.GL_MULTISAMPLE_ARB); 339 if (samples > 0 && available && !enabled){ 340 glEnable(ARBMultisample.GL_MULTISAMPLE_ARB); 341 } 342 } 343 */ 344 345 String extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS); 346 logger.log(Level.INFO, "GL_EXTENSIONS: {0}", extensions); 347 348 GLES20.glGetIntegerv(GLES20.GL_COMPRESSED_TEXTURE_FORMATS, intBuf16); 349 for (int i = 0; i < intBuf16.limit(); i++) { 350 logger.log(Level.INFO, "Compressed Texture Formats: {0}", intBuf16.get(i)); 351 } 352 353 if (extensions.contains("GL_OES_texture_npot")) { 354 powerOf2 = true; 355 } 356 357 applyRenderState(RenderState.DEFAULT); 358 GLES20.glDisable(GLES20.GL_DITHER); 359 360 checkGLError(); 361 362 useVBO = false; 363 364 // NOTE: SDK_INT is only available since 1.6, 365 // but for jME3 it doesn't matter since android versions 1.5 and below 366 // are not supported. 367 if (Build.VERSION.SDK_INT >= 9){ 368 useVBO = true; 369 } 370 371 logger.log(Level.INFO, "Caps: {0}", caps); 372 } 373 374 /** 375 * <code>resetGLObjects</code> should be called when die GLView gets recreated to reset all GPU objects 376 */ 377 public void resetGLObjects() { 378 objManager.resetObjects(); 379 statistics.clearMemory(); 380 boundShader = null; 381 lastFb = null; 382 context.reset(); 383 } 384 385 public void cleanup() { 386 objManager.deleteAllObjects(this); 387 statistics.clearMemory(); 388 } 389 390 private void checkCap(Caps cap) { 391 if (!caps.contains(cap)) { 392 throw new UnsupportedOperationException("Required capability missing: " + cap.name()); 393 } 394 } 395 396 /*********************************************************************\ 397 |* Render State *| 398 \*********************************************************************/ 399 public void setDepthRange(float start, float end) { 400 401 if (verboseLogging) { 402 logger.log(Level.INFO, "GLES20.glDepthRangef({0}, {1})", new Object[]{start, end}); 403 } 404 GLES20.glDepthRangef(start, end); 405 checkGLError(); 406 } 407 408 public void clearBuffers(boolean color, boolean depth, boolean stencil) { 409 int bits = 0; 410 if (color) { 411 bits = GLES20.GL_COLOR_BUFFER_BIT; 412 } 413 if (depth) { 414 bits |= GLES20.GL_DEPTH_BUFFER_BIT; 415 } 416 if (stencil) { 417 bits |= GLES20.GL_STENCIL_BUFFER_BIT; 418 } 419 if (bits != 0) { 420 if (verboseLogging) { 421 logger.log(Level.INFO, "GLES20.glClear(color={0}, depth={1}, stencil={2})", new Object[]{color, depth, stencil}); 422 } 423 GLES20.glClear(bits); 424 checkGLError(); 425 } 426 } 427 428 public void setBackgroundColor(ColorRGBA color) { 429 if (verboseLogging) { 430 logger.log(Level.INFO, "GLES20.glClearColor({0}, {1}, {2}, {3})", new Object[]{color.r, color.g, color.b, color.a}); 431 } 432 GLES20.glClearColor(color.r, color.g, color.b, color.a); 433 checkGLError(); 434 } 435 436 public void applyRenderState(RenderState state) { 437 /* 438 if (state.isWireframe() && !context.wireframe){ 439 GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_LINE); 440 context.wireframe = true; 441 }else if (!state.isWireframe() && context.wireframe){ 442 GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_FILL); 443 context.wireframe = false; 444 } 445 */ 446 if (state.isDepthTest() && !context.depthTestEnabled) { 447 if (verboseLogging) { 448 logger.info("GLES20.glEnable(GLES20.GL_DEPTH_TEST)"); 449 } 450 GLES20.glEnable(GLES20.GL_DEPTH_TEST); 451 checkGLError(); 452 if (verboseLogging) { 453 logger.info("GLES20.glDepthFunc(GLES20.GL_LEQUAL)"); 454 } 455 GLES20.glDepthFunc(GLES20.GL_LEQUAL); 456 checkGLError(); 457 context.depthTestEnabled = true; 458 } else if (!state.isDepthTest() && context.depthTestEnabled) { 459 if (verboseLogging) { 460 logger.info("GLES20.glDisable(GLES20.GL_DEPTH_TEST)"); 461 } 462 GLES20.glDisable(GLES20.GL_DEPTH_TEST); 463 checkGLError(); 464 context.depthTestEnabled = false; 465 } 466 if (state.isAlphaTest() && !context.alphaTestEnabled) { 467 // GLES20.glEnable(GLES20.GL_ALPHA_TEST); 468 // GLES20.glAlphaFunc(GLES20.GL_GREATER, state.getAlphaFallOff()); 469 context.alphaTestEnabled = true; 470 } else if (!state.isAlphaTest() && context.alphaTestEnabled) { 471 // GLES20.glDisable(GLES20.GL_ALPHA_TEST); 472 context.alphaTestEnabled = false; 473 } 474 if (state.isDepthWrite() && !context.depthWriteEnabled) { 475 if (verboseLogging) { 476 logger.info("GLES20.glDepthMask(true)"); 477 } 478 GLES20.glDepthMask(true); 479 checkGLError(); 480 context.depthWriteEnabled = true; 481 } else if (!state.isDepthWrite() && context.depthWriteEnabled) { 482 if (verboseLogging) { 483 logger.info("GLES20.glDepthMask(false)"); 484 } 485 GLES20.glDepthMask(false); 486 checkGLError(); 487 context.depthWriteEnabled = false; 488 } 489 if (state.isColorWrite() && !context.colorWriteEnabled) { 490 if (verboseLogging) { 491 logger.info("GLES20.glColorMask(true, true, true, true)"); 492 } 493 GLES20.glColorMask(true, true, true, true); 494 checkGLError(); 495 context.colorWriteEnabled = true; 496 } else if (!state.isColorWrite() && context.colorWriteEnabled) { 497 if (verboseLogging) { 498 logger.info("GLES20.glColorMask(false, false, false, false)"); 499 } 500 GLES20.glColorMask(false, false, false, false); 501 checkGLError(); 502 context.colorWriteEnabled = false; 503 } 504 if (state.isPointSprite() && !context.pointSprite) { 505 // GLES20.glEnable(GLES20.GL_POINT_SPRITE); 506 // GLES20.glTexEnvi(GLES20.GL_POINT_SPRITE, GLES20.GL_COORD_REPLACE, GLES20.GL_TRUE); 507 // GLES20.glEnable(GLES20.GL_VERTEX_PROGRAM_POINT_SIZE); 508 // GLES20.glPointParameterf(GLES20.GL_POINT_SIZE_MIN, 1.0f); 509 } else if (!state.isPointSprite() && context.pointSprite) { 510 // GLES20.glDisable(GLES20.GL_POINT_SPRITE); 511 } 512 513 if (state.isPolyOffset()) { 514 if (!context.polyOffsetEnabled) { 515 if (verboseLogging) { 516 logger.info("GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL)"); 517 } 518 GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL); 519 checkGLError(); 520 if (verboseLogging) { 521 logger.log(Level.INFO, "GLES20.glPolygonOffset({0}, {1})", new Object[]{state.getPolyOffsetFactor(), state.getPolyOffsetUnits()}); 522 } 523 GLES20.glPolygonOffset(state.getPolyOffsetFactor(), 524 state.getPolyOffsetUnits()); 525 checkGLError(); 526 context.polyOffsetEnabled = true; 527 context.polyOffsetFactor = state.getPolyOffsetFactor(); 528 context.polyOffsetUnits = state.getPolyOffsetUnits(); 529 } else { 530 if (state.getPolyOffsetFactor() != context.polyOffsetFactor 531 || state.getPolyOffsetUnits() != context.polyOffsetUnits) { 532 if (verboseLogging) { 533 logger.log(Level.INFO, "GLES20.glPolygonOffset({0}, {1})", new Object[]{state.getPolyOffsetFactor(), state.getPolyOffsetUnits()}); 534 } 535 GLES20.glPolygonOffset(state.getPolyOffsetFactor(), 536 state.getPolyOffsetUnits()); 537 checkGLError(); 538 context.polyOffsetFactor = state.getPolyOffsetFactor(); 539 context.polyOffsetUnits = state.getPolyOffsetUnits(); 540 } 541 } 542 } else { 543 if (context.polyOffsetEnabled) { 544 if (verboseLogging) { 545 logger.info("GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL)"); 546 } 547 GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL); 548 checkGLError(); 549 context.polyOffsetEnabled = false; 550 context.polyOffsetFactor = 0; 551 context.polyOffsetUnits = 0; 552 } 553 } 554 if (state.getFaceCullMode() != context.cullMode) { 555 if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) { 556 if (verboseLogging) { 557 logger.info("GLES20.glDisable(GLES20.GL_CULL_FACE)"); 558 } 559 GLES20.glDisable(GLES20.GL_CULL_FACE); 560 } else { 561 if (verboseLogging) { 562 logger.info("GLES20.glEnable(GLES20.GL_CULL_FACE)"); 563 } 564 GLES20.glEnable(GLES20.GL_CULL_FACE); 565 } 566 567 checkGLError(); 568 569 switch (state.getFaceCullMode()) { 570 case Off: 571 break; 572 case Back: 573 if (verboseLogging) { 574 logger.info("GLES20.glCullFace(GLES20.GL_BACK)"); 575 } 576 GLES20.glCullFace(GLES20.GL_BACK); 577 break; 578 case Front: 579 if (verboseLogging) { 580 logger.info("GLES20.glCullFace(GLES20.GL_FRONT)"); 581 } 582 GLES20.glCullFace(GLES20.GL_FRONT); 583 break; 584 case FrontAndBack: 585 if (verboseLogging) { 586 logger.info("GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK)"); 587 } 588 GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK); 589 break; 590 default: 591 throw new UnsupportedOperationException("Unrecognized face cull mode: " 592 + state.getFaceCullMode()); 593 } 594 595 checkGLError(); 596 597 context.cullMode = state.getFaceCullMode(); 598 } 599 600 if (state.getBlendMode() != context.blendMode) { 601 if (state.getBlendMode() == RenderState.BlendMode.Off) { 602 if (verboseLogging) { 603 logger.info("GLES20.glDisable(GLES20.GL_BLEND)"); 604 } 605 GLES20.glDisable(GLES20.GL_BLEND); 606 } else { 607 if (verboseLogging) { 608 logger.info("GLES20.glEnable(GLES20.GL_BLEND)"); 609 } 610 GLES20.glEnable(GLES20.GL_BLEND); 611 switch (state.getBlendMode()) { 612 case Off: 613 break; 614 case Additive: 615 if (verboseLogging) { 616 logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE)"); 617 } 618 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE); 619 break; 620 case AlphaAdditive: 621 if (verboseLogging) { 622 logger.info("GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE)"); 623 } 624 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE); 625 break; 626 case Color: 627 if (verboseLogging) { 628 logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR)"); 629 } 630 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR); 631 break; 632 case Alpha: 633 if (verboseLogging) { 634 logger.info("GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)"); 635 } 636 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); 637 break; 638 case PremultAlpha: 639 if (verboseLogging) { 640 logger.info("GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA)"); 641 } 642 GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); 643 break; 644 case Modulate: 645 if (verboseLogging) { 646 logger.info("GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_ZERO)"); 647 } 648 GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_ZERO); 649 break; 650 case ModulateX2: 651 if (verboseLogging) { 652 logger.info("GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_SRC_COLOR)"); 653 } 654 GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_SRC_COLOR); 655 break; 656 default: 657 throw new UnsupportedOperationException("Unrecognized blend mode: " 658 + state.getBlendMode()); 659 } 660 } 661 662 checkGLError(); 663 664 context.blendMode = state.getBlendMode(); 665 } 666 } 667 668 /*********************************************************************\ 669 |* Camera and World transforms *| 670 \*********************************************************************/ 671 public void setViewPort(int x, int y, int w, int h) { 672 if (x != vpX || vpY != y || vpW != w || vpH != h) { 673 if (verboseLogging) { 674 logger.log(Level.INFO, "GLES20.glViewport({0}, {1}, {2}, {3})", new Object[]{x, y, w, h}); 675 } 676 GLES20.glViewport(x, y, w, h); 677 checkGLError(); 678 vpX = x; 679 vpY = y; 680 vpW = w; 681 vpH = h; 682 } 683 } 684 685 public void setClipRect(int x, int y, int width, int height) { 686 if (!context.clipRectEnabled) { 687 if (verboseLogging) { 688 logger.info("GLES20.glEnable(GLES20.GL_SCISSOR_TEST)"); 689 } 690 GLES20.glEnable(GLES20.GL_SCISSOR_TEST); 691 checkGLError(); 692 context.clipRectEnabled = true; 693 } 694 if (clipX != x || clipY != y || clipW != width || clipH != height) { 695 if (verboseLogging) { 696 logger.log(Level.INFO, "GLES20.glScissor({0}, {1}, {2}, {3})", new Object[]{x, y, width, height}); 697 } 698 GLES20.glScissor(x, y, width, height); 699 clipX = x; 700 clipY = y; 701 clipW = width; 702 clipH = height; 703 checkGLError(); 704 } 705 } 706 707 public void clearClipRect() { 708 if (context.clipRectEnabled) { 709 if (verboseLogging) { 710 logger.info("GLES20.glDisable(GLES20.GL_SCISSOR_TEST)"); 711 } 712 GLES20.glDisable(GLES20.GL_SCISSOR_TEST); 713 checkGLError(); 714 context.clipRectEnabled = false; 715 716 clipX = 0; 717 clipY = 0; 718 clipW = 0; 719 clipH = 0; 720 } 721 } 722 723 public void onFrame() { 724 if (!checkErrors){ 725 int error = GLES20.glGetError(); 726 if (error != GLES20.GL_NO_ERROR){ 727 throw new RendererException("OpenGL Error " + error + ". Enable error checking for more info."); 728 } 729 } 730 objManager.deleteUnused(this); 731 // statistics.clearFrame(); 732 } 733 734 public void setWorldMatrix(Matrix4f worldMatrix) { 735 } 736 737 public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { 738 } 739 740 /*********************************************************************\ 741 |* Shaders *| 742 \*********************************************************************/ 743 protected void updateUniformLocation(Shader shader, Uniform uniform) { 744 stringBuf.setLength(0); 745 stringBuf.append(uniform.getName()).append('\0'); 746 updateNameBuffer(); 747 if (verboseLogging) { 748 logger.log(Level.INFO, "GLES20.glGetUniformLocation({0}, {1})", new Object[]{shader.getId(), uniform.getName()}); 749 } 750 int loc = GLES20.glGetUniformLocation(shader.getId(), uniform.getName()); 751 checkGLError(); 752 if (loc < 0) { 753 uniform.setLocation(-1); 754 // uniform is not declared in shader 755 if (verboseLogging) { 756 logger.log(Level.WARNING, "Uniform [{0}] is not declared in shader.", uniform.getName()); 757 } 758 } else { 759 uniform.setLocation(loc); 760 } 761 } 762 763 protected void updateUniform(Shader shader, Uniform uniform) { 764 int shaderId = shader.getId(); 765 766 assert uniform.getName() != null; 767 assert shader.getId() > 0; 768 769 if (context.boundShaderProgram != shaderId) { 770 if (verboseLogging) { 771 logger.log(Level.INFO, "GLES20.glUseProgram({0})", shaderId); 772 } 773 GLES20.glUseProgram(shaderId); 774 checkGLError(); 775 statistics.onShaderUse(shader, true); 776 boundShader = shader; 777 context.boundShaderProgram = shaderId; 778 } else { 779 statistics.onShaderUse(shader, false); 780 } 781 782 int loc = uniform.getLocation(); 783 if (loc == -1) { 784 if (verboseLogging) { 785 logger.log(Level.WARNING, "no location for uniform [{0}]", uniform.getName()); 786 } 787 return; 788 } 789 790 if (loc == -2) { 791 // get uniform location 792 updateUniformLocation(shader, uniform); 793 if (uniform.getLocation() == -1) { 794 // not declared, ignore 795 796 if (verboseLogging) { 797 logger.log(Level.WARNING, "not declared uniform: [{0}]", uniform.getName()); 798 } 799 800 uniform.clearUpdateNeeded(); 801 return; 802 } 803 loc = uniform.getLocation(); 804 } 805 806 if (uniform.getVarType() == null) { 807 logger.warning("value is not set yet."); 808 return; // value not set yet.. 809 } 810 811 statistics.onUniformSet(); 812 813 uniform.clearUpdateNeeded(); 814 FloatBuffer fb; 815 switch (uniform.getVarType()) { 816 case Float: 817 if (verboseLogging) { 818 logger.info("GLES20.glUniform1f set Float. " + uniform.getName()); 819 } 820 Float f = (Float) uniform.getValue(); 821 GLES20.glUniform1f(loc, f.floatValue()); 822 break; 823 case Vector2: 824 if (verboseLogging) { 825 logger.info("GLES20.glUniform2f set Vector2. " + uniform.getName()); 826 } 827 Vector2f v2 = (Vector2f) uniform.getValue(); 828 GLES20.glUniform2f(loc, v2.getX(), v2.getY()); 829 break; 830 case Vector3: 831 if (verboseLogging) { 832 logger.info("GLES20.glUniform3f set Vector3. " + uniform.getName()); 833 } 834 Vector3f v3 = (Vector3f) uniform.getValue(); 835 GLES20.glUniform3f(loc, v3.getX(), v3.getY(), v3.getZ()); 836 break; 837 case Vector4: 838 if (verboseLogging) { 839 logger.info("GLES20.glUniform4f set Vector4." + uniform.getName()); 840 } 841 Object val = uniform.getValue(); 842 if (val instanceof ColorRGBA) { 843 ColorRGBA c = (ColorRGBA) val; 844 GLES20.glUniform4f(loc, c.r, c.g, c.b, c.a); 845 } else { 846 Quaternion c = (Quaternion) uniform.getValue(); 847 GLES20.glUniform4f(loc, c.getX(), c.getY(), c.getZ(), c.getW()); 848 } 849 break; 850 case Boolean: 851 if (verboseLogging) { 852 logger.info("GLES20.glUniform1i set Boolean." + uniform.getName()); 853 } 854 Boolean b = (Boolean) uniform.getValue(); 855 GLES20.glUniform1i(loc, b.booleanValue() ? GLES20.GL_TRUE : GLES20.GL_FALSE); 856 break; 857 case Matrix3: 858 if (verboseLogging) { 859 logger.info("GLES20.glUniformMatrix3fv set Matrix3." + uniform.getName()); 860 } 861 fb = (FloatBuffer) uniform.getValue(); 862 assert fb.remaining() == 9; 863 GLES20.glUniformMatrix3fv(loc, 1, false, fb); 864 break; 865 case Matrix4: 866 if (verboseLogging) { 867 logger.info("GLES20.glUniformMatrix4fv set Matrix4." + uniform.getName()); 868 } 869 fb = (FloatBuffer) uniform.getValue(); 870 assert fb.remaining() == 16; 871 GLES20.glUniformMatrix4fv(loc, 1, false, fb); 872 break; 873 case FloatArray: 874 if (verboseLogging) { 875 logger.info("GLES20.glUniform1fv set FloatArray." + uniform.getName()); 876 } 877 fb = (FloatBuffer) uniform.getValue(); 878 GLES20.glUniform1fv(loc, fb.capacity(), fb); 879 break; 880 case Vector2Array: 881 if (verboseLogging) { 882 logger.info("GLES20.glUniform2fv set Vector2Array." + uniform.getName()); 883 } 884 fb = (FloatBuffer) uniform.getValue(); 885 GLES20.glUniform2fv(loc, fb.capacity() / 2, fb); 886 break; 887 case Vector3Array: 888 if (verboseLogging) { 889 logger.info("GLES20.glUniform3fv set Vector3Array." + uniform.getName()); 890 } 891 fb = (FloatBuffer) uniform.getValue(); 892 GLES20.glUniform3fv(loc, fb.capacity() / 3, fb); 893 break; 894 case Vector4Array: 895 if (verboseLogging) { 896 logger.info("GLES20.glUniform4fv set Vector4Array." + uniform.getName()); 897 } 898 fb = (FloatBuffer) uniform.getValue(); 899 GLES20.glUniform4fv(loc, fb.capacity() / 4, fb); 900 break; 901 case Matrix4Array: 902 if (verboseLogging) { 903 logger.info("GLES20.glUniform4fv set Matrix4Array." + uniform.getName()); 904 } 905 fb = (FloatBuffer) uniform.getValue(); 906 GLES20.glUniformMatrix4fv(loc, fb.capacity() / 16, false, fb); 907 break; 908 case Int: 909 if (verboseLogging) { 910 logger.info("GLES20.glUniform1i set Int." + uniform.getName()); 911 } 912 Integer i = (Integer) uniform.getValue(); 913 GLES20.glUniform1i(loc, i.intValue()); 914 break; 915 default: 916 throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType()); 917 } 918 checkGLError(); 919 } 920 921 protected void updateShaderUniforms(Shader shader) { 922 ListMap<String, Uniform> uniforms = shader.getUniformMap(); 923 // for (Uniform uniform : shader.getUniforms()){ 924 for (int i = 0; i < uniforms.size(); i++) { 925 Uniform uniform = uniforms.getValue(i); 926 if (uniform.isUpdateNeeded()) { 927 updateUniform(shader, uniform); 928 } 929 } 930 } 931 932 protected void resetUniformLocations(Shader shader) { 933 ListMap<String, Uniform> uniforms = shader.getUniformMap(); 934 // for (Uniform uniform : shader.getUniforms()){ 935 for (int i = 0; i < uniforms.size(); i++) { 936 Uniform uniform = uniforms.getValue(i); 937 uniform.reset(); // e.g check location again 938 } 939 } 940 941 /* 942 * (Non-javadoc) 943 * Only used for fixed-function. Ignored. 944 */ 945 public void setLighting(LightList list) { 946 } 947 948 public int convertShaderType(ShaderType type) { 949 switch (type) { 950 case Fragment: 951 return GLES20.GL_FRAGMENT_SHADER; 952 case Vertex: 953 return GLES20.GL_VERTEX_SHADER; 954 // case Geometry: 955 // return ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB; 956 default: 957 throw new RuntimeException("Unrecognized shader type."); 958 } 959 } 960 961 public void updateShaderSourceData(ShaderSource source, String language) { 962 int id = source.getId(); 963 if (id == -1) { 964 // create id 965 if (verboseLogging) { 966 logger.info("GLES20.glCreateShader(" + source.getType() + ")"); 967 } 968 id = GLES20.glCreateShader(convertShaderType(source.getType())); 969 checkGLError(); 970 if (id <= 0) { 971 throw new RendererException("Invalid ID received when trying to create shader."); 972 } 973 974 source.setId(id); 975 } 976 977 // upload shader source 978 // merge the defines and source code 979 byte[] versionData = new byte[]{};//"#version 140\n".getBytes(); 980 // versionData = "#define INSTANCING 1\n".getBytes(); 981 byte[] definesCodeData = source.getDefines().getBytes(); 982 byte[] sourceCodeData = source.getSource().getBytes(); 983 ByteBuffer codeBuf = BufferUtils.createByteBuffer(versionData.length 984 + definesCodeData.length 985 + sourceCodeData.length); 986 codeBuf.put(versionData); 987 codeBuf.put(definesCodeData); 988 codeBuf.put(sourceCodeData); 989 codeBuf.flip(); 990 991 if (verboseLogging) { 992 logger.info("GLES20.glShaderSource(" + id + ")"); 993 } 994 995 if (powerVr && source.getType() == ShaderType.Vertex) { 996 // XXX: This is to fix a bug in old PowerVR, remove 997 // when no longer applicable. 998 GLES20.glShaderSource( 999 id, source.getDefines() 1000 + source.getSource()); 1001 } else { 1002 GLES20.glShaderSource( 1003 id, 1004 "precision mediump float;\n" 1005 + source.getDefines() 1006 + source.getSource()); 1007 } 1008 1009 checkGLError(); 1010 1011 if (verboseLogging) { 1012 logger.info("GLES20.glCompileShader(" + id + ")"); 1013 } 1014 1015 GLES20.glCompileShader(id); 1016 1017 checkGLError(); 1018 1019 if (verboseLogging) { 1020 logger.info("GLES20.glGetShaderiv(" + id + ", GLES20.GL_COMPILE_STATUS)"); 1021 } 1022 1023 GLES20.glGetShaderiv(id, GLES20.GL_COMPILE_STATUS, intBuf1); 1024 1025 checkGLError(); 1026 1027 boolean compiledOK = intBuf1.get(0) == GLES20.GL_TRUE; 1028 String infoLog = null; 1029 1030 if (VALIDATE_SHADER || !compiledOK) { 1031 // even if compile succeeded, check 1032 // log for warnings 1033 if (verboseLogging) { 1034 logger.info("GLES20.glGetShaderiv()"); 1035 } 1036 GLES20.glGetShaderiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1); 1037 checkGLError(); 1038 if (verboseLogging) { 1039 logger.info("GLES20.glGetShaderInfoLog(" + id + ")"); 1040 } 1041 infoLog = GLES20.glGetShaderInfoLog(id); 1042 logger.severe("Errooooooooooot(" + id + ")"); 1043 } 1044 1045 if (compiledOK) { 1046 if (infoLog != null) { 1047 logger.log(Level.INFO, "compile success: " + source.getName() + ", " + infoLog); 1048 } else { 1049 logger.log(Level.FINE, "compile success: " + source.getName()); 1050 } 1051 } else { 1052 logger.log(Level.WARNING, "Bad compile of:\n{0}{1}", 1053 new Object[]{source.getDefines(), source.getSource()}); 1054 if (infoLog != null) { 1055 throw new RendererException("compile error in:" + source + " error:" + infoLog); 1056 } else { 1057 throw new RendererException("compile error in:" + source + " error: <not provided>"); 1058 } 1059 } 1060 1061 source.clearUpdateNeeded(); 1062 // only usable if compiled 1063 source.setUsable(compiledOK); 1064 if (!compiledOK) { 1065 // make sure to dispose id cause all program's 1066 // shaders will be cleared later. 1067 if (verboseLogging) { 1068 logger.info("GLES20.glDeleteShader(" + id + ")"); 1069 } 1070 GLES20.glDeleteShader(id); 1071 checkGLError(); 1072 } else { 1073 // register for cleanup since the ID is usable 1074 objManager.registerForCleanup(source); 1075 } 1076 } 1077 1078 public void updateShaderData(Shader shader) { 1079 int id = shader.getId(); 1080 boolean needRegister = false; 1081 if (id == -1) { 1082 // create program 1083 1084 if (verboseLogging) { 1085 logger.info("GLES20.glCreateProgram()"); 1086 } 1087 1088 id = GLES20.glCreateProgram(); 1089 1090 if (id <= 0) { 1091 throw new RendererException("Invalid ID received when trying to create shader program."); 1092 } 1093 1094 shader.setId(id); 1095 needRegister = true; 1096 } 1097 1098 for (ShaderSource source : shader.getSources()) { 1099 if (source.isUpdateNeeded()) { 1100 updateShaderSourceData(source, shader.getLanguage()); 1101 // shader has been compiled here 1102 } 1103 1104 if (!source.isUsable()) { 1105 // it's useless.. just forget about everything.. 1106 shader.setUsable(false); 1107 shader.clearUpdateNeeded(); 1108 return; 1109 } 1110 if (verboseLogging) { 1111 logger.info("GLES20.glAttachShader(" + id + ", " + source.getId() + ")"); 1112 } 1113 1114 GLES20.glAttachShader(id, source.getId()); 1115 } 1116 1117 // link shaders to program 1118 if (verboseLogging) { 1119 logger.info("GLES20.glLinkProgram(" + id + ")"); 1120 } 1121 1122 GLES20.glLinkProgram(id); 1123 1124 1125 if (verboseLogging) { 1126 logger.info("GLES20.glGetProgramiv(" + id + ")"); 1127 } 1128 1129 GLES20.glGetProgramiv(id, GLES20.GL_LINK_STATUS, intBuf1); 1130 1131 boolean linkOK = intBuf1.get(0) == GLES20.GL_TRUE; 1132 String infoLog = null; 1133 1134 if (VALIDATE_SHADER || !linkOK) { 1135 if (verboseLogging) { 1136 logger.info("GLES20.glGetProgramiv(" + id + ", GLES20.GL_INFO_LOG_LENGTH, buffer)"); 1137 } 1138 1139 GLES20.glGetProgramiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1); 1140 1141 int length = intBuf1.get(0); 1142 if (length > 3) { 1143 // get infos 1144 1145 if (verboseLogging) { 1146 logger.info("GLES20.glGetProgramInfoLog(" + id + ")"); 1147 } 1148 1149 infoLog = GLES20.glGetProgramInfoLog(id); 1150 } 1151 } 1152 1153 if (linkOK) { 1154 if (infoLog != null) { 1155 logger.log(Level.INFO, "shader link success. \n{0}", infoLog); 1156 } else { 1157 logger.fine("shader link success"); 1158 } 1159 } else { 1160 if (infoLog != null) { 1161 throw new RendererException("Shader link failure, shader:" + shader + " info:" + infoLog); 1162 } else { 1163 throw new RendererException("Shader link failure, shader:" + shader + " info: <not provided>"); 1164 } 1165 } 1166 1167 shader.clearUpdateNeeded(); 1168 if (!linkOK) { 1169 // failure.. forget about everything 1170 shader.resetSources(); 1171 shader.setUsable(false); 1172 deleteShader(shader); 1173 } else { 1174 shader.setUsable(true); 1175 if (needRegister) { 1176 objManager.registerForCleanup(shader); 1177 statistics.onNewShader(); 1178 } else { 1179 // OpenGL spec: uniform locations may change after re-link 1180 resetUniformLocations(shader); 1181 } 1182 } 1183 } 1184 1185 public void setShader(Shader shader) { 1186 if (verboseLogging) { 1187 logger.info("setShader(" + shader + ")"); 1188 } 1189 1190 if (shader == null) { 1191 if (context.boundShaderProgram > 0) { 1192 1193 if (verboseLogging) { 1194 logger.info("GLES20.glUseProgram(0)"); 1195 } 1196 1197 GLES20.glUseProgram(0); 1198 1199 statistics.onShaderUse(null, true); 1200 context.boundShaderProgram = 0; 1201 boundShader = null; 1202 } 1203 } else { 1204 if (shader.isUpdateNeeded()) { 1205 updateShaderData(shader); 1206 } 1207 1208 // NOTE: might want to check if any of the 1209 // sources need an update? 1210 1211 if (!shader.isUsable()) { 1212 logger.warning("shader is not usable."); 1213 return; 1214 } 1215 1216 assert shader.getId() > 0; 1217 1218 updateShaderUniforms(shader); 1219 if (context.boundShaderProgram != shader.getId()) { 1220 if (VALIDATE_SHADER) { 1221 // check if shader can be used 1222 // with current state 1223 if (verboseLogging) { 1224 logger.info("GLES20.glValidateProgram(" + shader.getId() + ")"); 1225 } 1226 1227 GLES20.glValidateProgram(shader.getId()); 1228 1229 if (verboseLogging) { 1230 logger.info("GLES20.glGetProgramiv(" + shader.getId() + ", GLES20.GL_VALIDATE_STATUS, buffer)"); 1231 } 1232 1233 GLES20.glGetProgramiv(shader.getId(), GLES20.GL_VALIDATE_STATUS, intBuf1); 1234 1235 boolean validateOK = intBuf1.get(0) == GLES20.GL_TRUE; 1236 1237 if (validateOK) { 1238 logger.fine("shader validate success"); 1239 } else { 1240 logger.warning("shader validate failure"); 1241 } 1242 } 1243 1244 if (verboseLogging) { 1245 logger.info("GLES20.glUseProgram(" + shader.getId() + ")"); 1246 } 1247 1248 GLES20.glUseProgram(shader.getId()); 1249 1250 statistics.onShaderUse(shader, true); 1251 context.boundShaderProgram = shader.getId(); 1252 boundShader = shader; 1253 } else { 1254 statistics.onShaderUse(shader, false); 1255 } 1256 } 1257 } 1258 1259 public void deleteShaderSource(ShaderSource source) { 1260 if (source.getId() < 0) { 1261 logger.warning("Shader source is not uploaded to GPU, cannot delete."); 1262 return; 1263 } 1264 source.setUsable(false); 1265 source.clearUpdateNeeded(); 1266 1267 if (verboseLogging) { 1268 logger.info("GLES20.glDeleteShader(" + source.getId() + ")"); 1269 } 1270 1271 GLES20.glDeleteShader(source.getId()); 1272 source.resetObject(); 1273 } 1274 1275 public void deleteShader(Shader shader) { 1276 if (shader.getId() == -1) { 1277 logger.warning("Shader is not uploaded to GPU, cannot delete."); 1278 return; 1279 } 1280 for (ShaderSource source : shader.getSources()) { 1281 if (source.getId() != -1) { 1282 1283 if (verboseLogging) { 1284 logger.info("GLES20.glDetachShader(" + shader.getId() + ", " + source.getId() + ")"); 1285 } 1286 1287 GLES20.glDetachShader(shader.getId(), source.getId()); 1288 // the next part is done by the GLObjectManager automatically 1289 // glDeleteShader(source.getId()); 1290 } 1291 } 1292 // kill all references so sources can be collected 1293 // if needed. 1294 shader.resetSources(); 1295 1296 if (verboseLogging) { 1297 logger.info("GLES20.glDeleteProgram(" + shader.getId() + ")"); 1298 } 1299 1300 GLES20.glDeleteProgram(shader.getId()); 1301 1302 statistics.onDeleteShader(); 1303 } 1304 1305 /*********************************************************************\ 1306 |* Framebuffers *| 1307 \*********************************************************************/ 1308 public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { 1309 logger.warning("copyFrameBuffer is not supported."); 1310 } 1311 1312 public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { 1313 logger.warning("copyFrameBuffer is not supported."); 1314 } 1315 /* 1316 public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst){ 1317 if (GLContext.getCapabilities().GL_EXT_framebuffer_blit){ 1318 int srcW = 0; 1319 int srcH = 0; 1320 int dstW = 0; 1321 int dstH = 0; 1322 int prevFBO = context.boundFBO; 1323 1324 if (src != null && src.isUpdateNeeded()) 1325 updateFrameBuffer(src); 1326 1327 if (dst != null && dst.isUpdateNeeded()) 1328 updateFrameBuffer(dst); 1329 1330 if (src == null){ 1331 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 1332 // srcW = viewWidth; 1333 // srcH = viewHeight; 1334 }else{ 1335 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, src.getId()); 1336 srcW = src.getWidth(); 1337 srcH = src.getHeight(); 1338 } 1339 if (dst == null){ 1340 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); 1341 // dstW = viewWidth; 1342 // dstH = viewHeight; 1343 }else{ 1344 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dst.getId()); 1345 dstW = dst.getWidth(); 1346 dstH = dst.getHeight(); 1347 } 1348 glBlitFramebufferEXT(0, 0, srcW, srcH, 1349 0, 0, dstW, dstH, 1350 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, 1351 GL_NEAREST); 1352 1353 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prevFBO); 1354 try { 1355 checkFrameBufferError(); 1356 } catch (IllegalStateException ex){ 1357 logger.log(Level.SEVERE, "Source FBO:\n{0}", src); 1358 logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst); 1359 throw ex; 1360 } 1361 }else{ 1362 throw new UnsupportedOperationException("EXT_framebuffer_blit required."); 1363 // TODO: support non-blit copies? 1364 } 1365 } 1366 */ 1367 1368 private void checkFrameBufferError() { 1369 logger.warning("checkFrameBufferError is not supported."); 1370 } 1371 /* 1372 private void checkFrameBufferError() { 1373 int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 1374 switch (status) { 1375 case GL_FRAMEBUFFER_COMPLETE_EXT: 1376 break; 1377 case GL_FRAMEBUFFER_UNSUPPORTED_EXT: 1378 //Choose different formats 1379 throw new IllegalStateException("Framebuffer object format is " + 1380 "unsupported by the video hardware."); 1381 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: 1382 throw new IllegalStateException("Framebuffer has erronous attachment."); 1383 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: 1384 throw new IllegalStateException("Framebuffer is missing required attachment."); 1385 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: 1386 throw new IllegalStateException("Framebuffer attachments must have same dimensions."); 1387 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: 1388 throw new IllegalStateException("Framebuffer attachments must have same formats."); 1389 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: 1390 throw new IllegalStateException("Incomplete draw buffer."); 1391 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: 1392 throw new IllegalStateException("Incomplete read buffer."); 1393 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: 1394 throw new IllegalStateException("Incomplete multisample buffer."); 1395 default: 1396 //Programming error; will fail on all hardware 1397 throw new IllegalStateException("Some video driver error " + 1398 "or programming error occured. " + 1399 "Framebuffer object status is invalid. "); 1400 } 1401 } 1402 */ 1403 1404 private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { 1405 logger.warning("updateRenderBuffer is not supported."); 1406 } 1407 /* 1408 private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb){ 1409 int id = rb.getId(); 1410 if (id == -1){ 1411 glGenRenderbuffersEXT(intBuf1); 1412 id = intBuf1.get(0); 1413 rb.setId(id); 1414 } 1415 1416 if (context.boundRB != id){ 1417 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id); 1418 context.boundRB = id; 1419 } 1420 1421 if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) 1422 throw new UnsupportedOperationException("Resolution "+fb.getWidth()+ 1423 ":"+fb.getHeight()+" is not supported."); 1424 1425 if (fb.getSamples() > 0 && GLContext.getCapabilities().GL_EXT_framebuffer_multisample){ 1426 int samples = fb.getSamples(); 1427 if (maxFBOSamples < samples){ 1428 samples = maxFBOSamples; 1429 } 1430 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, 1431 samples, 1432 TextureUtil.convertTextureFormat(rb.getFormat()), 1433 fb.getWidth(), 1434 fb.getHeight()); 1435 }else{ 1436 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, 1437 TextureUtil.convertTextureFormat(rb.getFormat()), 1438 fb.getWidth(), 1439 fb.getHeight()); 1440 } 1441 } 1442 */ 1443 1444 private int convertAttachmentSlot(int attachmentSlot) { 1445 logger.warning("convertAttachmentSlot is not supported."); 1446 return -1; 1447 } 1448 /* 1449 private int convertAttachmentSlot(int attachmentSlot){ 1450 // can also add support for stencil here 1451 if (attachmentSlot == -100){ 1452 return GL_DEPTH_ATTACHMENT_EXT; 1453 }else if (attachmentSlot < 0 || attachmentSlot >= 16){ 1454 throw new UnsupportedOperationException("Invalid FBO attachment slot: "+attachmentSlot); 1455 } 1456 1457 return GL_COLOR_ATTACHMENT0_EXT + attachmentSlot; 1458 } 1459 */ 1460 1461 public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { 1462 logger.warning("updateRenderTexture is not supported."); 1463 } 1464 /* 1465 public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb){ 1466 Texture tex = rb.getTexture(); 1467 Image image = tex.getImage(); 1468 if (image.isUpdateNeeded()) 1469 updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels()); 1470 1471 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, 1472 convertAttachmentSlot(rb.getSlot()), 1473 convertTextureType(tex.getType()), 1474 image.getId(), 1475 0); 1476 } 1477 */ 1478 1479 public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { 1480 logger.warning("updateFrameBufferAttachment is not supported."); 1481 } 1482 /* 1483 public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb){ 1484 boolean needAttach; 1485 if (rb.getTexture() == null){ 1486 // if it hasn't been created yet, then attach is required. 1487 needAttach = rb.getId() == -1; 1488 updateRenderBuffer(fb, rb); 1489 }else{ 1490 needAttach = false; 1491 updateRenderTexture(fb, rb); 1492 } 1493 if (needAttach){ 1494 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, 1495 convertAttachmentSlot(rb.getSlot()), 1496 GL_RENDERBUFFER_EXT, 1497 rb.getId()); 1498 } 1499 } 1500 */ 1501 1502 public void updateFrameBuffer(FrameBuffer fb) { 1503 logger.warning("updateFrameBuffer is not supported."); 1504 } 1505 /* 1506 public void updateFrameBuffer(FrameBuffer fb) { 1507 int id = fb.getId(); 1508 if (id == -1){ 1509 // create FBO 1510 glGenFramebuffersEXT(intBuf1); 1511 id = intBuf1.get(0); 1512 fb.setId(id); 1513 objManager.registerForCleanup(fb); 1514 1515 statistics.onNewFrameBuffer(); 1516 } 1517 1518 if (context.boundFBO != id){ 1519 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); 1520 // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 1521 context.boundDrawBuf = 0; 1522 context.boundFBO = id; 1523 } 1524 1525 FrameBuffer.RenderBuffer depthBuf = fb.getDepthBuffer(); 1526 if (depthBuf != null){ 1527 updateFrameBufferAttachment(fb, depthBuf); 1528 } 1529 1530 for (int i = 0; i < fb.getNumColorBuffers(); i++){ 1531 FrameBuffer.RenderBuffer colorBuf = fb.getColorBuffer(i); 1532 updateFrameBufferAttachment(fb, colorBuf); 1533 } 1534 1535 fb.clearUpdateNeeded(); 1536 } 1537 */ 1538 1539 public void setMainFrameBufferOverride(FrameBuffer fb){ 1540 } 1541 1542 public void setFrameBuffer(FrameBuffer fb) { 1543 if (verboseLogging) { 1544 logger.warning("setFrameBuffer is not supported."); 1545 } 1546 } 1547 /* 1548 public void setFrameBuffer(FrameBuffer fb) { 1549 if (lastFb == fb) 1550 return; 1551 1552 // generate mipmaps for last FB if needed 1553 if (lastFb != null){ 1554 for (int i = 0; i < lastFb.getNumColorBuffers(); i++){ 1555 RenderBuffer rb = lastFb.getColorBuffer(i); 1556 Texture tex = rb.getTexture(); 1557 if (tex != null 1558 && tex.getMinFilter().usesMipMapLevels()){ 1559 setTexture(0, rb.getTexture()); 1560 glGenerateMipmapEXT(convertTextureType(tex.getType())); 1561 } 1562 } 1563 } 1564 1565 1566 if (fb == null){ 1567 // unbind any fbos 1568 if (context.boundFBO != 0){ 1569 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 1570 statistics.onFrameBufferUse(null, true); 1571 1572 context.boundFBO = 0; 1573 } 1574 // select back buffer 1575 if (context.boundDrawBuf != -1){ 1576 glDrawBuffer(initialDrawBuf); 1577 context.boundDrawBuf = -1; 1578 } 1579 if (context.boundReadBuf != -1){ 1580 glReadBuffer(initialReadBuf); 1581 context.boundReadBuf = -1; 1582 } 1583 1584 lastFb = null; 1585 }else{ 1586 if (fb.isUpdateNeeded()) 1587 updateFrameBuffer(fb); 1588 1589 if (context.boundFBO != fb.getId()){ 1590 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb.getId()); 1591 statistics.onFrameBufferUse(fb, true); 1592 1593 // update viewport to reflect framebuffer's resolution 1594 setViewPort(0, 0, fb.getWidth(), fb.getHeight()); 1595 1596 context.boundFBO = fb.getId(); 1597 }else{ 1598 statistics.onFrameBufferUse(fb, false); 1599 } 1600 if (fb.getNumColorBuffers() == 0){ 1601 // make sure to select NONE as draw buf 1602 // no color buffer attached. select NONE 1603 if (context.boundDrawBuf != -2){ 1604 glDrawBuffer(GL_NONE); 1605 context.boundDrawBuf = -2; 1606 } 1607 if (context.boundReadBuf != -2){ 1608 glReadBuffer(GL_NONE); 1609 context.boundReadBuf = -2; 1610 } 1611 }else{ 1612 if (fb.isMultiTarget()){ 1613 if (fb.getNumColorBuffers() > maxMRTFBOAttachs) 1614 throw new UnsupportedOperationException("Framebuffer has more" 1615 + " targets than are supported" 1616 + " on the system!"); 1617 1618 if (context.boundDrawBuf != 100 + fb.getNumColorBuffers()){ 1619 intBuf16.clear(); 1620 for (int i = 0; i < fb.getNumColorBuffers(); i++) 1621 intBuf16.put( GL_COLOR_ATTACHMENT0_EXT + i ); 1622 1623 intBuf16.flip(); 1624 glDrawBuffers(intBuf16); 1625 context.boundDrawBuf = 100 + fb.getNumColorBuffers(); 1626 } 1627 }else{ 1628 RenderBuffer rb = fb.getColorBuffer(fb.getTargetIndex()); 1629 // select this draw buffer 1630 if (context.boundDrawBuf != rb.getSlot()){ 1631 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + rb.getSlot()); 1632 context.boundDrawBuf = rb.getSlot(); 1633 } 1634 } 1635 } 1636 1637 assert fb.getId() >= 0; 1638 assert context.boundFBO == fb.getId(); 1639 lastFb = fb; 1640 } 1641 1642 try { 1643 checkFrameBufferError(); 1644 } catch (IllegalStateException ex){ 1645 logger.log(Level.SEVERE, "Problem FBO:\n{0}", fb); 1646 throw ex; 1647 } 1648 } 1649 */ 1650 1651 public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { 1652 logger.warning("readFrameBuffer is not supported."); 1653 } 1654 /* 1655 public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf){ 1656 if (fb != null){ 1657 RenderBuffer rb = fb.getColorBuffer(); 1658 if (rb == null) 1659 throw new IllegalArgumentException("Specified framebuffer" + 1660 " does not have a colorbuffer"); 1661 1662 setFrameBuffer(fb); 1663 if (context.boundReadBuf != rb.getSlot()){ 1664 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + rb.getSlot()); 1665 context.boundReadBuf = rb.getSlot(); 1666 } 1667 }else{ 1668 setFrameBuffer(null); 1669 } 1670 1671 glReadPixels(vpX, vpY, vpW, vpH, GL_RGBA GL_BGRA, GL_UNSIGNED_BYTE, byteBuf); 1672 } 1673 */ 1674 1675 private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { 1676 logger.warning("deleteRenderBuffer is not supported."); 1677 } 1678 /* 1679 private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb){ 1680 intBuf1.put(0, rb.getId()); 1681 glDeleteRenderbuffersEXT(intBuf1); 1682 } 1683 */ 1684 1685 public void deleteFrameBuffer(FrameBuffer fb) { 1686 logger.warning("deleteFrameBuffer is not supported."); 1687 } 1688 /* 1689 public void deleteFrameBuffer(FrameBuffer fb) { 1690 if (fb.getId() != -1){ 1691 if (context.boundFBO == fb.getId()){ 1692 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 1693 context.boundFBO = 0; 1694 } 1695 1696 if (fb.getDepthBuffer() != null){ 1697 deleteRenderBuffer(fb, fb.getDepthBuffer()); 1698 } 1699 if (fb.getColorBuffer() != null){ 1700 deleteRenderBuffer(fb, fb.getColorBuffer()); 1701 } 1702 1703 intBuf1.put(0, fb.getId()); 1704 glDeleteFramebuffersEXT(intBuf1); 1705 fb.resetObject(); 1706 1707 statistics.onDeleteFrameBuffer(); 1708 } 1709 } 1710 */ 1711 1712 /*********************************************************************\ 1713 |* Textures *| 1714 \*********************************************************************/ 1715 private int convertTextureType(Texture.Type type) { 1716 switch (type) { 1717 case TwoDimensional: 1718 return GLES20.GL_TEXTURE_2D; 1719 // case TwoDimensionalArray: 1720 // return EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT; 1721 // case ThreeDimensional: 1722 // return GLES20.GL_TEXTURE_3D; 1723 case CubeMap: 1724 return GLES20.GL_TEXTURE_CUBE_MAP; 1725 default: 1726 throw new UnsupportedOperationException("Unknown texture type: " + type); 1727 } 1728 } 1729 1730 private int convertMagFilter(Texture.MagFilter filter) { 1731 switch (filter) { 1732 case Bilinear: 1733 return GLES20.GL_LINEAR; 1734 case Nearest: 1735 return GLES20.GL_NEAREST; 1736 default: 1737 throw new UnsupportedOperationException("Unknown mag filter: " + filter); 1738 } 1739 } 1740 1741 private int convertMinFilter(Texture.MinFilter filter) { 1742 switch (filter) { 1743 case Trilinear: 1744 return GLES20.GL_LINEAR_MIPMAP_LINEAR; 1745 case BilinearNearestMipMap: 1746 return GLES20.GL_LINEAR_MIPMAP_NEAREST; 1747 case NearestLinearMipMap: 1748 return GLES20.GL_NEAREST_MIPMAP_LINEAR; 1749 case NearestNearestMipMap: 1750 return GLES20.GL_NEAREST_MIPMAP_NEAREST; 1751 case BilinearNoMipMaps: 1752 return GLES20.GL_LINEAR; 1753 case NearestNoMipMaps: 1754 return GLES20.GL_NEAREST; 1755 default: 1756 throw new UnsupportedOperationException("Unknown min filter: " + filter); 1757 } 1758 } 1759 1760 private int convertWrapMode(Texture.WrapMode mode) { 1761 switch (mode) { 1762 case BorderClamp: 1763 case Clamp: 1764 case EdgeClamp: 1765 return GLES20.GL_CLAMP_TO_EDGE; 1766 case Repeat: 1767 return GLES20.GL_REPEAT; 1768 case MirroredRepeat: 1769 return GLES20.GL_MIRRORED_REPEAT; 1770 default: 1771 throw new UnsupportedOperationException("Unknown wrap mode: " + mode); 1772 } 1773 } 1774 1775 /** 1776 * <code>setupTextureParams</code> sets the OpenGL context texture parameters 1777 * @param tex the Texture to set the texture parameters from 1778 */ 1779 private void setupTextureParams(Texture tex) { 1780 int target = convertTextureType(tex.getType()); 1781 1782 // filter things 1783 int minFilter = convertMinFilter(tex.getMinFilter()); 1784 int magFilter = convertMagFilter(tex.getMagFilter()); 1785 1786 if (verboseLogging) { 1787 logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")"); 1788 } 1789 1790 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter); 1791 1792 if (verboseLogging) { 1793 logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")"); 1794 } 1795 1796 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter); 1797 1798 /* 1799 if (tex.getAnisotropicFilter() > 1){ 1800 1801 if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){ 1802 glTexParameterf(target, 1803 EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, 1804 tex.getAnisotropicFilter()); 1805 } 1806 1807 } 1808 */ 1809 // repeat modes 1810 1811 switch (tex.getType()) { 1812 case ThreeDimensional: 1813 case CubeMap: // cubemaps use 3D coords 1814 // GL_TEXTURE_WRAP_R is not available in api 8 1815 //GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); 1816 case TwoDimensional: 1817 case TwoDimensionalArray: 1818 1819 if (verboseLogging) { 1820 logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T))); 1821 } 1822 1823 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); 1824 1825 // fall down here is intentional.. 1826 // case OneDimensional: 1827 1828 if (verboseLogging) { 1829 logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S))); 1830 } 1831 1832 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); 1833 break; 1834 default: 1835 throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); 1836 } 1837 1838 // R to Texture compare mode 1839 /* 1840 if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off){ 1841 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_MODE, GLES20.GL_COMPARE_R_TO_TEXTURE); 1842 GLES20.glTexParameteri(target, GLES20.GL_DEPTH_TEXTURE_MODE, GLES20.GL_INTENSITY); 1843 if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual){ 1844 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_GEQUAL); 1845 }else{ 1846 GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_LEQUAL); 1847 } 1848 } 1849 */ 1850 } 1851 1852 /** 1853 * <code>updateTexImageData</code> activates and binds the texture 1854 * @param img 1855 * @param type 1856 * @param mips 1857 */ 1858 public void updateTexImageData(Image img, Texture.Type type, boolean mips) { 1859 int texId = img.getId(); 1860 if (texId == -1) { 1861 // create texture 1862 if (verboseLogging) { 1863 logger.info("GLES20.glGenTexture(1, buffer)"); 1864 } 1865 1866 GLES20.glGenTextures(1, intBuf1); 1867 texId = intBuf1.get(0); 1868 img.setId(texId); 1869 objManager.registerForCleanup(img); 1870 1871 statistics.onNewTexture(); 1872 } 1873 1874 // bind texture 1875 int target = convertTextureType(type); 1876 if (context.boundTextures[0] != img) { 1877 if (context.boundTextureUnit != 0) { 1878 if (verboseLogging) { 1879 logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)"); 1880 } 1881 1882 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 1883 context.boundTextureUnit = 0; 1884 } 1885 1886 if (verboseLogging) { 1887 logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")"); 1888 } 1889 1890 GLES20.glBindTexture(target, texId); 1891 context.boundTextures[0] = img; 1892 } 1893 1894 1895 if (target == GLES20.GL_TEXTURE_CUBE_MAP) { 1896 // Upload a cube map / sky box 1897 @SuppressWarnings("unchecked") 1898 List<AndroidImageInfo> bmps = (List<AndroidImageInfo>) img.getEfficentData(); 1899 if (bmps != null) { 1900 // Native android bitmap 1901 if (bmps.size() != 6) { 1902 throw new UnsupportedOperationException("Invalid texture: " + img 1903 + "Cubemap textures must contain 6 data units."); 1904 } 1905 for (int i = 0; i < 6; i++) { 1906 TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i).getBitmap(), false, powerOf2); 1907 } 1908 } else { 1909 // Standard jme3 image data 1910 List<ByteBuffer> data = img.getData(); 1911 if (data.size() != 6) { 1912 logger.log(Level.WARNING, "Invalid texture: {0}\n" 1913 + "Cubemap textures must contain 6 data units.", img); 1914 return; 1915 } 1916 for (int i = 0; i < 6; i++) { 1917 TextureUtil.uploadTexture(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, false, powerOf2); 1918 } 1919 } 1920 } else { 1921 TextureUtil.uploadTexture(img, target, 0, 0, tdc, false, powerOf2); 1922 1923 if (verboseLogging) { 1924 logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)"); 1925 } 1926 1927 if (!img.hasMipmaps() && mips) { 1928 // No pregenerated mips available, 1929 // generate from base level if required 1930 if (verboseLogging) { 1931 logger.info("GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D)"); 1932 } 1933 GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D); 1934 } 1935 } 1936 1937 img.clearUpdateNeeded(); 1938 } 1939 1940 public void setTexture(int unit, Texture tex) { 1941 Image image = tex.getImage(); 1942 if (image.isUpdateNeeded()) { 1943 /* 1944 Bitmap bmp = (Bitmap)image.getEfficentData(); 1945 if (bmp != null) 1946 { 1947 // Check if the bitmap got recycled, can happen after wakeup/restart 1948 if ( bmp.isRecycled() ) 1949 { 1950 // We need to reload the bitmap 1951 Texture textureReloaded = JmeSystem.newAssetManager().loadTexture((TextureKey)tex.getKey()); 1952 image.setEfficentData( textureReloaded.getImage().getEfficentData()); 1953 } 1954 } 1955 */ 1956 updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels()); 1957 } 1958 1959 int texId = image.getId(); 1960 assert texId != -1; 1961 1962 if (texId == -1) { 1963 logger.warning("error: texture image has -1 id"); 1964 } 1965 1966 Image[] textures = context.boundTextures; 1967 1968 int type = convertTextureType(tex.getType()); 1969 if (!context.textureIndexList.moveToNew(unit)) { 1970 // if (context.boundTextureUnit != unit){ 1971 // glActiveTexture(GL_TEXTURE0 + unit); 1972 // context.boundTextureUnit = unit; 1973 // } 1974 // glEnable(type); 1975 } 1976 1977 if (textures[unit] != image) { 1978 if (context.boundTextureUnit != unit) { 1979 if (verboseLogging) { 1980 logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + " + unit + ")"); 1981 } 1982 GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + unit); 1983 context.boundTextureUnit = unit; 1984 } 1985 1986 if (verboseLogging) { 1987 logger.info("GLES20.glBindTexture(" + type + ", " + texId + ")"); 1988 } 1989 1990 GLES20.glBindTexture(type, texId); 1991 textures[unit] = image; 1992 1993 statistics.onTextureUse(tex.getImage(), true); 1994 } else { 1995 statistics.onTextureUse(tex.getImage(), false); 1996 } 1997 1998 setupTextureParams(tex); 1999 } 2000 2001 public void clearTextureUnits() { 2002 IDList textureList = context.textureIndexList; 2003 Image[] textures = context.boundTextures; 2004 for (int i = 0; i < textureList.oldLen; i++) { 2005 int idx = textureList.oldList[i]; 2006 // if (context.boundTextureUnit != idx){ 2007 // glActiveTexture(GL_TEXTURE0 + idx); 2008 // context.boundTextureUnit = idx; 2009 // } 2010 // glDisable(convertTextureType(textures[idx].getType())); 2011 textures[idx] = null; 2012 } 2013 context.textureIndexList.copyNewToOld(); 2014 } 2015 2016 public void deleteImage(Image image) { 2017 int texId = image.getId(); 2018 if (texId != -1) { 2019 intBuf1.put(0, texId); 2020 intBuf1.position(0).limit(1); 2021 2022 if (verboseLogging) { 2023 logger.info("GLES20.glDeleteTexture(1, buffer)"); 2024 } 2025 2026 GLES20.glDeleteTextures(1, intBuf1); 2027 image.resetObject(); 2028 2029 statistics.onDeleteTexture(); 2030 } 2031 } 2032 2033 /*********************************************************************\ 2034 |* Vertex Buffers and Attributes *| 2035 \*********************************************************************/ 2036 private int convertUsage(Usage usage) { 2037 switch (usage) { 2038 case Static: 2039 return GLES20.GL_STATIC_DRAW; 2040 case Dynamic: 2041 return GLES20.GL_DYNAMIC_DRAW; 2042 case Stream: 2043 return GLES20.GL_STREAM_DRAW; 2044 default: 2045 throw new RuntimeException("Unknown usage type."); 2046 } 2047 } 2048 2049 private int convertFormat(Format format) { 2050 switch (format) { 2051 case Byte: 2052 return GLES20.GL_BYTE; 2053 case UnsignedByte: 2054 return GLES20.GL_UNSIGNED_BYTE; 2055 case Short: 2056 return GLES20.GL_SHORT; 2057 case UnsignedShort: 2058 return GLES20.GL_UNSIGNED_SHORT; 2059 case Int: 2060 return GLES20.GL_INT; 2061 case UnsignedInt: 2062 return GLES20.GL_UNSIGNED_INT; 2063 /* 2064 case Half: 2065 return NVHalfFloat.GL_HALF_FLOAT_NV; 2066 // return ARBHalfFloatVertex.GL_HALF_FLOAT; 2067 */ 2068 case Float: 2069 return GLES20.GL_FLOAT; 2070 // case Double: 2071 // return GLES20.GL_DOUBLE; 2072 default: 2073 throw new RuntimeException("Unknown buffer format."); 2074 2075 } 2076 } 2077 2078 public void updateBufferData(VertexBuffer vb) { 2079 2080 if (verboseLogging) { 2081 logger.info("updateBufferData(" + vb + ")"); 2082 } 2083 2084 int bufId = vb.getId(); 2085 boolean created = false; 2086 if (bufId == -1) { 2087 // create buffer 2088 2089 if (verboseLogging) { 2090 logger.info("GLES20.glGenBuffers(" + 1 + ", buffer)"); 2091 } 2092 2093 GLES20.glGenBuffers(1, intBuf1); 2094 bufId = intBuf1.get(0); 2095 vb.setId(bufId); 2096 objManager.registerForCleanup(vb); 2097 2098 created = true; 2099 } 2100 2101 // bind buffer 2102 int target; 2103 if (vb.getBufferType() == VertexBuffer.Type.Index) { 2104 target = GLES20.GL_ELEMENT_ARRAY_BUFFER; 2105 2106 if (verboseLogging) { 2107 logger.info("vb.getBufferType() == VertexBuffer.Type.Index"); 2108 } 2109 2110 if (context.boundElementArrayVBO != bufId) { 2111 2112 if (verboseLogging) { 2113 logger.info("GLES20.glBindBuffer(" + target + ", " + bufId + ")"); 2114 } 2115 2116 GLES20.glBindBuffer(target, bufId); 2117 context.boundElementArrayVBO = bufId; 2118 } 2119 } else { 2120 if (verboseLogging) { 2121 logger.info("vb.getBufferType() != VertexBuffer.Type.Index"); 2122 } 2123 2124 target = GLES20.GL_ARRAY_BUFFER; 2125 2126 if (context.boundArrayVBO != bufId) { 2127 2128 if (verboseLogging) { 2129 logger.info("GLES20.glBindBuffer(" + target + ", " + bufId + ")"); 2130 } 2131 2132 GLES20.glBindBuffer(target, bufId); 2133 context.boundArrayVBO = bufId; 2134 } 2135 } 2136 2137 int usage = convertUsage(vb.getUsage()); 2138 vb.getData().clear(); 2139 2140 if (created || vb.hasDataSizeChanged()) { 2141 // upload data based on format 2142 int size = vb.getData().capacity() * vb.getFormat().getComponentSize(); 2143 2144 switch (vb.getFormat()) { 2145 case Byte: 2146 case UnsignedByte: 2147 2148 if (verboseLogging) { 2149 logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); 2150 } 2151 2152 GLES20.glBufferData(target, size, (ByteBuffer) vb.getData(), usage); 2153 break; 2154 // case Half: 2155 case Short: 2156 case UnsignedShort: 2157 2158 if (verboseLogging) { 2159 logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); 2160 } 2161 2162 GLES20.glBufferData(target, size, (ShortBuffer) vb.getData(), usage); 2163 break; 2164 case Int: 2165 case UnsignedInt: 2166 2167 if (verboseLogging) { 2168 logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); 2169 } 2170 2171 GLES20.glBufferData(target, size, (IntBuffer) vb.getData(), usage); 2172 break; 2173 case Float: 2174 if (verboseLogging) { 2175 logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); 2176 } 2177 2178 GLES20.glBufferData(target, size, (FloatBuffer) vb.getData(), usage); 2179 break; 2180 case Double: 2181 if (verboseLogging) { 2182 logger.info("GLES20.glBufferData(" + target + ", " + size + ", (data), " + usage + ")"); 2183 } 2184 2185 GLES20.glBufferData(target, size, (DoubleBuffer) vb.getData(), usage); 2186 break; 2187 default: 2188 throw new RuntimeException("Unknown buffer format."); 2189 } 2190 } else { 2191 int size = vb.getData().capacity() * vb.getFormat().getComponentSize(); 2192 2193 switch (vb.getFormat()) { 2194 case Byte: 2195 case UnsignedByte: 2196 if (verboseLogging) { 2197 logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); 2198 } 2199 2200 GLES20.glBufferSubData(target, 0, size, (ByteBuffer) vb.getData()); 2201 break; 2202 case Short: 2203 case UnsignedShort: 2204 if (verboseLogging) { 2205 logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); 2206 } 2207 2208 GLES20.glBufferSubData(target, 0, size, (ShortBuffer) vb.getData()); 2209 break; 2210 case Int: 2211 case UnsignedInt: 2212 if (verboseLogging) { 2213 logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); 2214 } 2215 2216 GLES20.glBufferSubData(target, 0, size, (IntBuffer) vb.getData()); 2217 break; 2218 case Float: 2219 if (verboseLogging) { 2220 logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); 2221 } 2222 2223 GLES20.glBufferSubData(target, 0, size, (FloatBuffer) vb.getData()); 2224 break; 2225 case Double: 2226 if (verboseLogging) { 2227 logger.info("GLES20.glBufferSubData(" + target + ", 0, " + size + ", (data))"); 2228 } 2229 2230 GLES20.glBufferSubData(target, 0, size, (DoubleBuffer) vb.getData()); 2231 break; 2232 default: 2233 throw new RuntimeException("Unknown buffer format."); 2234 } 2235 } 2236 // }else{ 2237 // if (created || vb.hasDataSizeChanged()){ 2238 // glBufferData(target, vb.getData().capacity() * vb.getFormat().getComponentSize(), usage); 2239 // } 2240 // 2241 // ByteBuffer buf = glMapBuffer(target, 2242 // GL_WRITE_ONLY, 2243 // vb.getMappedData()); 2244 // 2245 // if (buf != vb.getMappedData()){ 2246 // buf = buf.order(ByteOrder.nativeOrder()); 2247 // vb.setMappedData(buf); 2248 // } 2249 // 2250 // buf.clear(); 2251 // 2252 // switch (vb.getFormat()){ 2253 // case Byte: 2254 // case UnsignedByte: 2255 // buf.put( (ByteBuffer) vb.getData() ); 2256 // break; 2257 // case Short: 2258 // case UnsignedShort: 2259 // buf.asShortBuffer().put( (ShortBuffer) vb.getData() ); 2260 // break; 2261 // case Int: 2262 // case UnsignedInt: 2263 // buf.asIntBuffer().put( (IntBuffer) vb.getData() ); 2264 // break; 2265 // case Float: 2266 // buf.asFloatBuffer().put( (FloatBuffer) vb.getData() ); 2267 // break; 2268 // case Double: 2269 // break; 2270 // default: 2271 // throw new RuntimeException("Unknown buffer format."); 2272 // } 2273 // 2274 // glUnmapBuffer(target); 2275 // } 2276 2277 vb.clearUpdateNeeded(); 2278 } 2279 2280 public void deleteBuffer(VertexBuffer vb) { 2281 int bufId = vb.getId(); 2282 if (bufId != -1) { 2283 // delete buffer 2284 intBuf1.put(0, bufId); 2285 intBuf1.position(0).limit(1); 2286 if (verboseLogging) { 2287 logger.info("GLES20.glDeleteBuffers(1, buffer)"); 2288 } 2289 2290 GLES20.glDeleteBuffers(1, intBuf1); 2291 vb.resetObject(); 2292 } 2293 } 2294 2295 public void clearVertexAttribs() { 2296 IDList attribList = context.attribIndexList; 2297 for (int i = 0; i < attribList.oldLen; i++) { 2298 int idx = attribList.oldList[i]; 2299 2300 if (verboseLogging) { 2301 logger.info("GLES20.glDisableVertexAttribArray(" + idx + ")"); 2302 } 2303 2304 GLES20.glDisableVertexAttribArray(idx); 2305 context.boundAttribs[idx] = null; 2306 } 2307 context.attribIndexList.copyNewToOld(); 2308 } 2309 2310 public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) { 2311 if (verboseLogging) { 2312 logger.info("setVertexAttrib(" + vb + ", " + idb + ")"); 2313 } 2314 2315 if (vb.getBufferType() == VertexBuffer.Type.Index) { 2316 throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); 2317 } 2318 2319 if (vb.isUpdateNeeded() && idb == null) { 2320 updateBufferData(vb); 2321 } 2322 2323 int programId = context.boundShaderProgram; 2324 if (programId > 0) { 2325 Attribute attrib = boundShader.getAttribute(vb.getBufferType()); 2326 int loc = attrib.getLocation(); 2327 if (loc == -1) { 2328 2329 if (verboseLogging) { 2330 logger.warning("location is invalid for attrib: [" + vb.getBufferType().name() + "]"); 2331 } 2332 2333 return; // not defined 2334 } 2335 2336 if (loc == -2) { 2337 // stringBuf.setLength(0); 2338 // stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); 2339 // updateNameBuffer(); 2340 2341 String attributeName = "in" + vb.getBufferType().name(); 2342 2343 if (verboseLogging) { 2344 logger.info("GLES20.glGetAttribLocation(" + programId + ", " + attributeName + ")"); 2345 } 2346 2347 loc = GLES20.glGetAttribLocation(programId, attributeName); 2348 2349 // not really the name of it in the shader (inPosition\0) but 2350 // the internal name of the enum (Position). 2351 if (loc < 0) { 2352 attrib.setLocation(-1); 2353 2354 if (verboseLogging) { 2355 logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]"); 2356 } 2357 2358 return; // not available in shader. 2359 } else { 2360 attrib.setLocation(loc); 2361 } 2362 } 2363 2364 VertexBuffer[] attribs = context.boundAttribs; 2365 if (!context.attribIndexList.moveToNew(loc)) { 2366 if (verboseLogging) { 2367 logger.info("GLES20.glEnableVertexAttribArray(" + loc + ")"); 2368 } 2369 2370 GLES20.glEnableVertexAttribArray(loc); 2371 //System.out.println("Enabled ATTRIB IDX: "+loc); 2372 } 2373 if (attribs[loc] != vb) { 2374 // NOTE: Use id from interleaved buffer if specified 2375 int bufId = idb != null ? idb.getId() : vb.getId(); 2376 assert bufId != -1; 2377 2378 if (bufId == -1) { 2379 logger.warning("invalid buffer id"); 2380 } 2381 2382 if (context.boundArrayVBO != bufId) { 2383 if (verboseLogging) { 2384 logger.info("GLES20.glBindBuffer(" + GLES20.GL_ARRAY_BUFFER + ", " + bufId + ")"); 2385 } 2386 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufId); 2387 context.boundArrayVBO = bufId; 2388 } 2389 2390 vb.getData().clear(); 2391 2392 if (verboseLogging) { 2393 logger.info("GLES20.glVertexAttribPointer(" 2394 + "location=" + loc + ", " 2395 + "numComponents=" + vb.getNumComponents() + ", " 2396 + "format=" + vb.getFormat() + ", " 2397 + "isNormalized=" + vb.isNormalized() + ", " 2398 + "stride=" + vb.getStride() + ", " 2399 + "data.capacity=" + vb.getData().capacity() + ")"); 2400 } 2401 2402 Android22Workaround.glVertexAttribPointer(loc, 2403 vb.getNumComponents(), 2404 convertFormat(vb.getFormat()), 2405 vb.isNormalized(), 2406 vb.getStride(), 2407 0); 2408 2409 attribs[loc] = vb; 2410 } 2411 } else { 2412 throw new IllegalStateException("Cannot render mesh without shader bound"); 2413 } 2414 } 2415 2416 public void setVertexAttrib(VertexBuffer vb) { 2417 setVertexAttrib(vb, null); 2418 } 2419 2420 public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) { 2421 /* if (count > 1){ 2422 ARBDrawInstanced.glDrawArraysInstancedARB(convertElementMode(mode), 0, 2423 vertCount, count); 2424 }else{*/ 2425 if (verboseLogging) { 2426 logger.info("GLES20.glDrawArrays(" + vertCount + ")"); 2427 } 2428 2429 GLES20.glDrawArrays(convertElementMode(mode), 0, vertCount); 2430 /* 2431 }*/ 2432 } 2433 2434 public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { 2435 2436 if (verboseLogging) { 2437 logger.info("drawTriangleList(" + count + ")"); 2438 } 2439 2440 if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { 2441 throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); 2442 } 2443 2444 if (indexBuf.isUpdateNeeded()) { 2445 if (verboseLogging) { 2446 logger.info("updateBufferData for indexBuf."); 2447 } 2448 updateBufferData(indexBuf); 2449 } 2450 2451 int bufId = indexBuf.getId(); 2452 assert bufId != -1; 2453 2454 if (bufId == -1) { 2455 logger.info("invalid buffer id!"); 2456 } 2457 2458 if (context.boundElementArrayVBO != bufId) { 2459 if (verboseLogging) { 2460 logger.log(Level.INFO, "GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, {0})", bufId); 2461 } 2462 2463 GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufId); 2464 context.boundElementArrayVBO = bufId; 2465 } 2466 2467 int vertCount = mesh.getVertexCount(); 2468 boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); 2469 2470 Buffer indexData = indexBuf.getData(); 2471 2472 if (mesh.getMode() == Mode.Hybrid) { 2473 int[] modeStart = mesh.getModeStart(); 2474 int[] elementLengths = mesh.getElementLengths(); 2475 2476 int elMode = convertElementMode(Mode.Triangles); 2477 int fmt = convertFormat(indexBuf.getFormat()); 2478 int elSize = indexBuf.getFormat().getComponentSize(); 2479 int listStart = modeStart[0]; 2480 int stripStart = modeStart[1]; 2481 int fanStart = modeStart[2]; 2482 int curOffset = 0; 2483 for (int i = 0; i < elementLengths.length; i++) { 2484 if (i == stripStart) { 2485 elMode = convertElementMode(Mode.TriangleStrip); 2486 } else if (i == fanStart) { 2487 elMode = convertElementMode(Mode.TriangleStrip); 2488 } 2489 int elementLength = elementLengths[i]; 2490 2491 if (useInstancing) { 2492 //ARBDrawInstanced. 2493 throw new IllegalArgumentException("instancing is not supported."); 2494 /* 2495 GLES20.glDrawElementsInstancedARB(elMode, 2496 elementLength, 2497 fmt, 2498 curOffset, 2499 count); 2500 */ 2501 } else { 2502 indexBuf.getData().position(curOffset); 2503 if (verboseLogging) { 2504 logger.log(Level.INFO, "glDrawElements(): {0}, {1}", new Object[]{elementLength, curOffset}); 2505 } 2506 2507 GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); 2508 /* 2509 glDrawRangeElements(elMode, 2510 0, 2511 vertCount, 2512 elementLength, 2513 fmt, 2514 curOffset); 2515 */ 2516 } 2517 2518 curOffset += elementLength * elSize; 2519 } 2520 } else { 2521 if (useInstancing) { 2522 throw new IllegalArgumentException("instancing is not supported."); 2523 //ARBDrawInstanced. 2524 /* 2525 GLES20.glDrawElementsInstancedARB(convertElementMode(mesh.getMode()), 2526 indexBuf.getData().capacity(), 2527 convertFormat(indexBuf.getFormat()), 2528 0, 2529 count); 2530 */ 2531 } else { 2532 indexData.clear(); 2533 2534 if (verboseLogging) { 2535 logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); 2536 } 2537 2538 GLES20.glDrawElements( 2539 convertElementMode(mesh.getMode()), 2540 indexBuf.getData().capacity(), 2541 convertFormat(indexBuf.getFormat()), 2542 0); 2543 } 2544 } 2545 } 2546 2547 /*********************************************************************\ 2548 |* Render Calls *| 2549 \*********************************************************************/ 2550 public int convertElementMode(Mesh.Mode mode) { 2551 switch (mode) { 2552 case Points: 2553 return GLES20.GL_POINTS; 2554 case Lines: 2555 return GLES20.GL_LINES; 2556 case LineLoop: 2557 return GLES20.GL_LINE_LOOP; 2558 case LineStrip: 2559 return GLES20.GL_LINE_STRIP; 2560 case Triangles: 2561 return GLES20.GL_TRIANGLES; 2562 case TriangleFan: 2563 return GLES20.GL_TRIANGLE_FAN; 2564 case TriangleStrip: 2565 return GLES20.GL_TRIANGLE_STRIP; 2566 default: 2567 throw new UnsupportedOperationException("Unrecognized mesh mode: " + mode); 2568 } 2569 } 2570 2571 public void updateVertexArray(Mesh mesh) { 2572 logger.log(Level.INFO, "updateVertexArray({0})", mesh); 2573 int id = mesh.getId(); 2574 /* 2575 if (id == -1){ 2576 IntBuffer temp = intBuf1; 2577 // ARBVertexArrayObject.glGenVertexArrays(temp); 2578 GLES20.glGenVertexArrays(temp); 2579 id = temp.get(0); 2580 mesh.setId(id); 2581 } 2582 2583 if (context.boundVertexArray != id){ 2584 // ARBVertexArrayObject.glBindVertexArray(id); 2585 GLES20.glBindVertexArray(id); 2586 context.boundVertexArray = id; 2587 } 2588 */ 2589 VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); 2590 if (interleavedData != null && interleavedData.isUpdateNeeded()) { 2591 updateBufferData(interleavedData); 2592 } 2593 2594 2595 for (VertexBuffer vb : mesh.getBufferList().getArray()){ 2596 2597 if (vb.getBufferType() == Type.InterleavedData 2598 || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers 2599 || vb.getBufferType() == Type.Index) { 2600 continue; 2601 } 2602 2603 if (vb.getStride() == 0) { 2604 // not interleaved 2605 setVertexAttrib(vb); 2606 } else { 2607 // interleaved 2608 setVertexAttrib(vb, interleavedData); 2609 } 2610 } 2611 } 2612 2613 /** 2614 * renderMeshVertexArray renders a mesh using vertex arrays 2615 * @param mesh 2616 * @param lod 2617 * @param count 2618 */ 2619 private void renderMeshVertexArray(Mesh mesh, int lod, int count) { 2620 if (verboseLogging) { 2621 logger.info("renderMeshVertexArray"); 2622 } 2623 2624 // IntMap<VertexBuffer> buffers = mesh.getBuffers(); 2625 for (VertexBuffer vb : mesh.getBufferList().getArray()){ 2626 2627 if (vb.getBufferType() == Type.InterleavedData 2628 || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers 2629 || vb.getBufferType() == Type.Index) { 2630 continue; 2631 } 2632 2633 if (vb.getStride() == 0) { 2634 // not interleaved 2635 setVertexAttrib_Array(vb); 2636 } else { 2637 // interleaved 2638 VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); 2639 setVertexAttrib_Array(vb, interleavedData); 2640 } 2641 } 2642 2643 VertexBuffer indices = null; 2644 if (mesh.getNumLodLevels() > 0) { 2645 indices = mesh.getLodLevel(lod); 2646 } else { 2647 indices = mesh.getBuffer(Type.Index);//buffers.get(Type.Index.ordinal()); 2648 } 2649 if (indices != null) { 2650 drawTriangleList_Array(indices, mesh, count); 2651 } else { 2652 if (verboseLogging) { 2653 logger.log(Level.INFO, "GLES20.glDrawArrays({0}, {1}, {2})", 2654 new Object[]{mesh.getMode(), 0, mesh.getVertexCount()}); 2655 } 2656 2657 GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); 2658 } 2659 clearVertexAttribs(); 2660 clearTextureUnits(); 2661 } 2662 2663 private void renderMeshDefault(Mesh mesh, int lod, int count) { 2664 if (verboseLogging) { 2665 logger.log(Level.INFO, "renderMeshDefault({0}, {1}, {2})", 2666 new Object[]{mesh, lod, count}); 2667 } 2668 VertexBuffer indices = null; 2669 2670 VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); 2671 if (interleavedData != null && interleavedData.isUpdateNeeded()) { 2672 updateBufferData(interleavedData); 2673 } 2674 2675 //IntMap<VertexBuffer> buffers = mesh.getBuffers(); ; 2676 if (mesh.getNumLodLevels() > 0) { 2677 indices = mesh.getLodLevel(lod); 2678 } else { 2679 indices = mesh.getBuffer(Type.Index);// buffers.get(Type.Index.ordinal()); 2680 } 2681 for (VertexBuffer vb : mesh.getBufferList().getArray()){ 2682 2683 if (vb.getBufferType() == Type.InterleavedData 2684 || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers 2685 || vb.getBufferType() == Type.Index) { 2686 continue; 2687 } 2688 2689 if (vb.getStride() == 0) { 2690 // not interleaved 2691 setVertexAttrib(vb); 2692 } else { 2693 // interleaved 2694 setVertexAttrib(vb, interleavedData); 2695 } 2696 } 2697 if (indices != null) { 2698 drawTriangleList(indices, mesh, count); 2699 } else { 2700 // throw new UnsupportedOperationException("Cannot render without index buffer"); 2701 if (verboseLogging) { 2702 logger.log(Level.INFO, "GLES20.glDrawArrays({0}, 0, {1})", 2703 new Object[]{convertElementMode(mesh.getMode()), mesh.getVertexCount()}); 2704 } 2705 2706 GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); 2707 } 2708 clearVertexAttribs(); 2709 clearTextureUnits(); 2710 } 2711 2712 public void renderMesh(Mesh mesh, int lod, int count) { 2713 if (context.pointSize != mesh.getPointSize()) { 2714 2715 if (verboseLogging) { 2716 logger.log(Level.INFO, "GLES10.glPointSize({0})", mesh.getPointSize()); 2717 } 2718 2719 GLES10.glPointSize(mesh.getPointSize()); 2720 context.pointSize = mesh.getPointSize(); 2721 } 2722 if (context.lineWidth != mesh.getLineWidth()) { 2723 2724 if (verboseLogging) { 2725 logger.log(Level.INFO, "GLES20.glLineWidth({0})", mesh.getLineWidth()); 2726 } 2727 2728 GLES20.glLineWidth(mesh.getLineWidth()); 2729 context.lineWidth = mesh.getLineWidth(); 2730 } 2731 2732 statistics.onMeshDrawn(mesh, lod); 2733 // if (GLContext.getCapabilities().GL_ARB_vertex_array_object){ 2734 // renderMeshVertexArray(mesh, lod, count); 2735 // }else{ 2736 2737 if (useVBO) { 2738 if (verboseLogging) { 2739 logger.info("RENDERING A MESH USING VertexBufferObject"); 2740 } 2741 2742 renderMeshDefault(mesh, lod, count); 2743 } else { 2744 if (verboseLogging) { 2745 logger.info("RENDERING A MESH USING VertexArray"); 2746 } 2747 2748 renderMeshVertexArray(mesh, lod, count); 2749 } 2750 2751 // } 2752 } 2753 2754 /** 2755 * drawTriangleList_Array uses Vertex Array 2756 * @param indexBuf 2757 * @param mesh 2758 * @param count 2759 */ 2760 public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count) { 2761 if (verboseLogging) { 2762 logger.log(Level.INFO, "drawTriangleList_Array(Count = {0})", count); 2763 } 2764 2765 if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { 2766 throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); 2767 } 2768 2769 boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); 2770 if (useInstancing) { 2771 throw new IllegalArgumentException("Caps.MeshInstancing is not supported."); 2772 } 2773 2774 int vertCount = mesh.getVertexCount(); 2775 Buffer indexData = indexBuf.getData(); 2776 indexData.clear(); 2777 2778 if (mesh.getMode() == Mode.Hybrid) { 2779 int[] modeStart = mesh.getModeStart(); 2780 int[] elementLengths = mesh.getElementLengths(); 2781 2782 int elMode = convertElementMode(Mode.Triangles); 2783 int fmt = convertFormat(indexBuf.getFormat()); 2784 int elSize = indexBuf.getFormat().getComponentSize(); 2785 int listStart = modeStart[0]; 2786 int stripStart = modeStart[1]; 2787 int fanStart = modeStart[2]; 2788 int curOffset = 0; 2789 for (int i = 0; i < elementLengths.length; i++) { 2790 if (i == stripStart) { 2791 elMode = convertElementMode(Mode.TriangleStrip); 2792 } else if (i == fanStart) { 2793 elMode = convertElementMode(Mode.TriangleStrip); 2794 } 2795 int elementLength = elementLengths[i]; 2796 2797 indexBuf.getData().position(curOffset); 2798 if (verboseLogging) { 2799 logger.log(Level.INFO, "glDrawElements(): {0}, {1}", new Object[]{elementLength, curOffset}); 2800 } 2801 2802 GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); 2803 2804 curOffset += elementLength * elSize; 2805 } 2806 } else { 2807 if (verboseLogging) { 2808 logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); 2809 } 2810 2811 GLES20.glDrawElements( 2812 convertElementMode(mesh.getMode()), 2813 indexBuf.getData().capacity(), 2814 convertFormat(indexBuf.getFormat()), 2815 indexBuf.getData()); 2816 } 2817 } 2818 2819 /** 2820 * setVertexAttrib_Array uses Vertex Array 2821 * @param vb 2822 * @param idb 2823 */ 2824 public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb) { 2825 if (verboseLogging) { 2826 logger.log(Level.INFO, "setVertexAttrib_Array({0}, {1})", new Object[]{vb, idb}); 2827 } 2828 2829 if (vb.getBufferType() == VertexBuffer.Type.Index) { 2830 throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); 2831 } 2832 2833 // Get shader 2834 int programId = context.boundShaderProgram; 2835 if (programId > 0) { 2836 VertexBuffer[] attribs = context.boundAttribs; 2837 2838 Attribute attrib = boundShader.getAttribute(vb.getBufferType()); 2839 int loc = attrib.getLocation(); 2840 if (loc == -1) { 2841 //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]"); 2842 if (verboseLogging) { 2843 logger.log(Level.WARNING, "attribute is invalid in shader: [{0}]", vb.getBufferType().name()); 2844 } 2845 return; 2846 } else if (loc == -2) { 2847 String attributeName = "in" + vb.getBufferType().name(); 2848 2849 if (verboseLogging) { 2850 logger.log(Level.INFO, "GLES20.glGetAttribLocation({0}, {1})", new Object[]{programId, attributeName}); 2851 } 2852 2853 loc = GLES20.glGetAttribLocation(programId, attributeName); 2854 if (loc < 0) { 2855 attrib.setLocation(-1); 2856 if (verboseLogging) { 2857 logger.log(Level.WARNING, "attribute is invalid in shader: [{0}]", vb.getBufferType().name()); 2858 } 2859 return; // not available in shader. 2860 } else { 2861 attrib.setLocation(loc); 2862 } 2863 2864 } // if (loc == -2) 2865 2866 if ((attribs[loc] != vb) || vb.isUpdateNeeded()) { 2867 // NOTE: Use data from interleaved buffer if specified 2868 VertexBuffer avb = idb != null ? idb : vb; 2869 avb.getData().clear(); 2870 avb.getData().position(vb.getOffset()); 2871 2872 if (verboseLogging) { 2873 logger.log(Level.INFO, 2874 "GLES20.glVertexAttribPointer(" + 2875 "location={0}, " + 2876 "numComponents={1}, " + 2877 "format={2}, " + 2878 "isNormalized={3}, " + 2879 "stride={4}, " + 2880 "data.capacity={5})", 2881 new Object[]{loc, vb.getNumComponents(), 2882 vb.getFormat(), 2883 vb.isNormalized(), 2884 vb.getStride(), 2885 avb.getData().capacity()}); 2886 } 2887 2888 2889 // Upload attribute data 2890 GLES20.glVertexAttribPointer(loc, 2891 vb.getNumComponents(), 2892 convertFormat(vb.getFormat()), 2893 vb.isNormalized(), 2894 vb.getStride(), 2895 avb.getData()); 2896 checkGLError(); 2897 2898 GLES20.glEnableVertexAttribArray(loc); 2899 2900 attribs[loc] = vb; 2901 } // if (attribs[loc] != vb) 2902 } else { 2903 throw new IllegalStateException("Cannot render mesh without shader bound"); 2904 } 2905 } 2906 2907 /** 2908 * setVertexAttrib_Array uses Vertex Array 2909 * @param vb 2910 */ 2911 public void setVertexAttrib_Array(VertexBuffer vb) { 2912 setVertexAttrib_Array(vb, null); 2913 } 2914 2915 public void setAlphaToCoverage(boolean value) { 2916 if (value) { 2917 GLES20.glEnable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE); 2918 } else { 2919 GLES20.glDisable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE); 2920 } 2921 } 2922 2923 @Override 2924 public void invalidateState() { 2925 context.reset(); 2926 boundShader = null; 2927 lastFb = null; 2928 } 2929 } 2930