Home | History | Annotate | Download | only in android
      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