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 */
32package com.jme3.renderer.android;
33
34import android.opengl.GLES10;
35import android.opengl.GLES20;
36import android.os.Build;
37import com.jme3.asset.AndroidImageInfo;
38import com.jme3.light.LightList;
39import com.jme3.material.RenderState;
40import com.jme3.math.*;
41import com.jme3.renderer.*;
42import com.jme3.scene.Mesh;
43import com.jme3.scene.Mesh.Mode;
44import com.jme3.scene.VertexBuffer;
45import com.jme3.scene.VertexBuffer.Format;
46import com.jme3.scene.VertexBuffer.Type;
47import com.jme3.scene.VertexBuffer.Usage;
48import com.jme3.shader.Attribute;
49import com.jme3.shader.Shader;
50import com.jme3.shader.Shader.ShaderSource;
51import com.jme3.shader.Shader.ShaderType;
52import com.jme3.shader.Uniform;
53import com.jme3.texture.FrameBuffer;
54import com.jme3.texture.FrameBuffer.RenderBuffer;
55import com.jme3.texture.Image;
56import com.jme3.texture.Texture;
57import com.jme3.texture.Texture.WrapAxis;
58import com.jme3.util.BufferUtils;
59import com.jme3.util.ListMap;
60import com.jme3.util.NativeObjectManager;
61import java.nio.*;
62import java.util.EnumSet;
63import java.util.List;
64import java.util.logging.Level;
65import java.util.logging.Logger;
66
67public 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