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