OSDN Git Service

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