/* * Copyright 2012, 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.oscim.renderer.bucket; import static org.oscim.backend.GLAdapter.gl; import static org.oscim.renderer.MapRenderer.COORD_SCALE; import static org.oscim.renderer.MapRenderer.MAX_INDICES; import java.nio.ShortBuffer; import org.oscim.backend.GL; import org.oscim.renderer.GLShader; import org.oscim.renderer.GLState; import org.oscim.renderer.GLViewport; import org.oscim.renderer.MapRenderer; import org.oscim.renderer.bucket.TextureItem.TexturePool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TextureBucket extends RenderBucket { static final Logger log = LoggerFactory.getLogger(TextureBucket.class); public final static int INDICES_PER_SPRITE = 6; final static int VERTICES_PER_SPRITE = 4; final static int SHORTS_PER_VERTICE = 6; public final static int TEXTURE_HEIGHT = 256; public final static int TEXTURE_WIDTH = 1024; final static int POOL_FILL = 4; /** pool shared by TextLayers */ public final static TexturePool pool = new TexturePool(POOL_FILL, TEXTURE_WIDTH, TEXTURE_HEIGHT); public TextureBucket(int type) { super(type, false, true); } /** holds textures and offset in vbo */ public TextureItem textures; /** scale mode */ public boolean fixed; @Override protected void compile(ShortBuffer vboData, ShortBuffer iboData) { for (TextureItem t = textures; t != null; t = t.next) t.upload(); /* add vertices to vbo */ compileVertexItems(vboData); } protected void clear() { while (textures != null) textures = textures.dispose(); super.clear(); } static class Shader extends GLShader { int uMV, uProj, uScale, uTexSize, aPos, aTexCoord; Shader() { if (!create("texture_layer")) return; uMV = getUniform("u_mv"); uProj = getUniform("u_proj"); uScale = getUniform("u_scale"); uTexSize = getUniform("u_div"); aPos = getAttrib("vertex"); aTexCoord = getAttrib("tex_coord"); } @Override public boolean useProgram() { if (super.useProgram()) { GLState.enableVertexArrays(aPos, aTexCoord); return true; } return false; } } static Shader shader; public static final class Renderer { static void init() { shader = new Shader(); /* FIXME pool should be disposed on exit... */ pool.init(0); } public static RenderBucket draw(RenderBucket b, GLViewport v, float scale) { GLState.test(false, false); GLState.blend(true); shader.useProgram(); TextureBucket tb = (TextureBucket) b; gl.uniform1f(shader.uScale, tb.fixed ? 1 / scale : 1); v.proj.setAsUniform(shader.uProj); v.mvp.setAsUniform(shader.uMV); MapRenderer.bindQuadIndicesVBO(); for (TextureItem t = tb.textures; t != null; t = t.next) { gl.uniform2f(shader.uTexSize, 1f / (t.width * COORD_SCALE), 1f / (t.height * COORD_SCALE)); t.bind(); /* draw up to maxVertices in each iteration */ for (int i = 0; i < t.indices; i += MAX_INDICES) { /* to.offset * (24(shorts) * 2(short-bytes) * / 6(indices) == 8) */ int off = (t.offset + i) * 8 + tb.vertexOffset; int numIndices = t.indices - i; if (numIndices > MAX_INDICES) numIndices = MAX_INDICES; tb.render(off, numIndices); } } return b.next; } } public TextureItem getTextures() { return textures; } public void render(int offset, int numIndices) { gl.vertexAttribPointer(shader.aPos, 4, GL.SHORT, false, 12, offset); gl.vertexAttribPointer(shader.aTexCoord, 2, GL.SHORT, false, 12, offset + 8); gl.drawElements(GL.TRIANGLES, numIndices, GL.UNSIGNED_SHORT, 0); } }