OSDN Git Service

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