1/******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17package com.badlogic.gdx.graphics.glutils; 18 19import com.badlogic.gdx.Gdx; 20import com.badlogic.gdx.graphics.Color; 21import com.badlogic.gdx.graphics.Mesh; 22import com.badlogic.gdx.graphics.VertexAttribute; 23import com.badlogic.gdx.graphics.VertexAttributes.Usage; 24import com.badlogic.gdx.math.Matrix4; 25import com.badlogic.gdx.utils.Array; 26 27/** Immediate mode rendering class for GLES 2.0. The renderer will allow you to specify vertices on the fly and provides a default 28 * shader for (unlit) rendering.</p> * 29 * 30 * @author mzechner */ 31public class ImmediateModeRenderer20 implements ImmediateModeRenderer { 32 private int primitiveType; 33 private int vertexIdx; 34 private int numSetTexCoords; 35 private final int maxVertices; 36 private int numVertices; 37 38 private final Mesh mesh; 39 private ShaderProgram shader; 40 private boolean ownsShader; 41 private final int numTexCoords; 42 private final int vertexSize; 43 private final int normalOffset; 44 private final int colorOffset; 45 private final int texCoordOffset; 46 private final Matrix4 projModelView = new Matrix4(); 47 private final float[] vertices; 48 private final String[] shaderUniformNames; 49 50 public ImmediateModeRenderer20 (boolean hasNormals, boolean hasColors, int numTexCoords) { 51 this(5000, hasNormals, hasColors, numTexCoords, createDefaultShader(hasNormals, hasColors, numTexCoords)); 52 ownsShader = true; 53 } 54 55 public ImmediateModeRenderer20 (int maxVertices, boolean hasNormals, boolean hasColors, int numTexCoords) { 56 this(maxVertices, hasNormals, hasColors, numTexCoords, createDefaultShader(hasNormals, hasColors, numTexCoords)); 57 ownsShader = true; 58 } 59 60 public ImmediateModeRenderer20 (int maxVertices, boolean hasNormals, boolean hasColors, int numTexCoords, ShaderProgram shader) { 61 this.maxVertices = maxVertices; 62 this.numTexCoords = numTexCoords; 63 this.shader = shader; 64 65 VertexAttribute[] attribs = buildVertexAttributes(hasNormals, hasColors, numTexCoords); 66 mesh = new Mesh(false, maxVertices, 0, attribs); 67 68 vertices = new float[maxVertices * (mesh.getVertexAttributes().vertexSize / 4)]; 69 vertexSize = mesh.getVertexAttributes().vertexSize / 4; 70 normalOffset = mesh.getVertexAttribute(Usage.Normal) != null ? mesh.getVertexAttribute(Usage.Normal).offset / 4 : 0; 71 colorOffset = mesh.getVertexAttribute(Usage.ColorPacked) != null ? mesh.getVertexAttribute(Usage.ColorPacked).offset / 4 72 : 0; 73 texCoordOffset = mesh.getVertexAttribute(Usage.TextureCoordinates) != null ? mesh 74 .getVertexAttribute(Usage.TextureCoordinates).offset / 4 : 0; 75 76 shaderUniformNames = new String[numTexCoords]; 77 for (int i = 0; i < numTexCoords; i++) { 78 shaderUniformNames[i] = "u_sampler" + i; 79 } 80 } 81 82 private VertexAttribute[] buildVertexAttributes (boolean hasNormals, boolean hasColor, int numTexCoords) { 83 Array<VertexAttribute> attribs = new Array<VertexAttribute>(); 84 attribs.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE)); 85 if (hasNormals) attribs.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE)); 86 if (hasColor) attribs.add(new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE)); 87 for (int i = 0; i < numTexCoords; i++) { 88 attribs.add(new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + i)); 89 } 90 VertexAttribute[] array = new VertexAttribute[attribs.size]; 91 for (int i = 0; i < attribs.size; i++) 92 array[i] = attribs.get(i); 93 return array; 94 } 95 96 public void setShader (ShaderProgram shader) { 97 if (ownsShader) this.shader.dispose(); 98 this.shader = shader; 99 ownsShader = false; 100 } 101 102 public void begin (Matrix4 projModelView, int primitiveType) { 103 this.projModelView.set(projModelView); 104 this.primitiveType = primitiveType; 105 } 106 107 public void color (Color color) { 108 vertices[vertexIdx + colorOffset] = color.toFloatBits(); 109 } 110 111 public void color (float r, float g, float b, float a) { 112 vertices[vertexIdx + colorOffset] = Color.toFloatBits(r, g, b, a); 113 } 114 115 public void color (float colorBits) { 116 vertices[vertexIdx + colorOffset] = colorBits; 117 } 118 119 public void texCoord (float u, float v) { 120 final int idx = vertexIdx + texCoordOffset; 121 vertices[idx + numSetTexCoords] = u; 122 vertices[idx + numSetTexCoords + 1] = v; 123 numSetTexCoords += 2; 124 } 125 126 public void normal (float x, float y, float z) { 127 final int idx = vertexIdx + normalOffset; 128 vertices[idx] = x; 129 vertices[idx + 1] = y; 130 vertices[idx + 2] = z; 131 } 132 133 public void vertex (float x, float y, float z) { 134 final int idx = vertexIdx; 135 vertices[idx] = x; 136 vertices[idx + 1] = y; 137 vertices[idx + 2] = z; 138 139 numSetTexCoords = 0; 140 vertexIdx += vertexSize; 141 numVertices++; 142 } 143 144 public void flush () { 145 if (numVertices == 0) return; 146 shader.begin(); 147 shader.setUniformMatrix("u_projModelView", projModelView); 148 for (int i = 0; i < numTexCoords; i++) 149 shader.setUniformi(shaderUniformNames[i], i); 150 mesh.setVertices(vertices, 0, vertexIdx); 151 mesh.render(shader, primitiveType); 152 shader.end(); 153 154 numSetTexCoords = 0; 155 vertexIdx = 0; 156 numVertices = 0; 157 } 158 159 public void end () { 160 flush(); 161 } 162 163 public int getNumVertices () { 164 return numVertices; 165 } 166 167 @Override 168 public int getMaxVertices () { 169 return maxVertices; 170 } 171 172 public void dispose () { 173 if (ownsShader && shader != null) shader.dispose(); 174 mesh.dispose(); 175 } 176 177 static private String createVertexShader (boolean hasNormals, boolean hasColors, int numTexCoords) { 178 String shader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" 179 + (hasNormals ? "attribute vec3 " + ShaderProgram.NORMAL_ATTRIBUTE + ";\n" : "") 180 + (hasColors ? "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" : ""); 181 182 for (int i = 0; i < numTexCoords; i++) { 183 shader += "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + i + ";\n"; 184 } 185 186 shader += "uniform mat4 u_projModelView;\n"; 187 shader += (hasColors ? "varying vec4 v_col;\n" : ""); 188 189 for (int i = 0; i < numTexCoords; i++) { 190 shader += "varying vec2 v_tex" + i + ";\n"; 191 } 192 193 shader += "void main() {\n" + " gl_Position = u_projModelView * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" 194 + (hasColors ? " v_col = " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" : ""); 195 196 for (int i = 0; i < numTexCoords; i++) { 197 shader += " v_tex" + i + " = " + ShaderProgram.TEXCOORD_ATTRIBUTE + i + ";\n"; 198 } 199 shader += " gl_PointSize = 1.0;\n"; 200 shader += "}\n"; 201 return shader; 202 } 203 204 static private String createFragmentShader (boolean hasNormals, boolean hasColors, int numTexCoords) { 205 String shader = "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n"; 206 207 if (hasColors) shader += "varying vec4 v_col;\n"; 208 for (int i = 0; i < numTexCoords; i++) { 209 shader += "varying vec2 v_tex" + i + ";\n"; 210 shader += "uniform sampler2D u_sampler" + i + ";\n"; 211 } 212 213 shader += "void main() {\n" + " gl_FragColor = " + (hasColors ? "v_col" : "vec4(1, 1, 1, 1)"); 214 215 if (numTexCoords > 0) shader += " * "; 216 217 for (int i = 0; i < numTexCoords; i++) { 218 if (i == numTexCoords - 1) { 219 shader += " texture2D(u_sampler" + i + ", v_tex" + i + ")"; 220 } else { 221 shader += " texture2D(u_sampler" + i + ", v_tex" + i + ") *"; 222 } 223 } 224 225 shader += ";\n}"; 226 return shader; 227 } 228 229 /** Returns a new instance of the default shader used by SpriteBatch for GL2 when no shader is specified. */ 230 static public ShaderProgram createDefaultShader (boolean hasNormals, boolean hasColors, int numTexCoords) { 231 String vertexShader = createVertexShader(hasNormals, hasColors, numTexCoords); 232 String fragmentShader = createFragmentShader(hasNormals, hasColors, numTexCoords); 233 ShaderProgram program = new ShaderProgram(vertexShader, fragmentShader); 234 return program; 235 } 236} 237