/* * Copyright 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; import static org.oscim.renderer.bucket.RenderBucket.BITMAP; import static org.oscim.renderer.bucket.RenderBucket.HAIRLINE; import static org.oscim.renderer.bucket.RenderBucket.LINE; import static org.oscim.renderer.bucket.RenderBucket.MESH; import static org.oscim.renderer.bucket.RenderBucket.POLYGON; import static org.oscim.renderer.bucket.RenderBucket.SYMBOL; import static org.oscim.renderer.bucket.RenderBucket.TEXLINE; import org.oscim.core.MapPosition; import org.oscim.core.Tile; import org.oscim.renderer.bucket.BitmapBucket; import org.oscim.renderer.bucket.HairLineBucket; import org.oscim.renderer.bucket.LineBucket; import org.oscim.renderer.bucket.LineTexBucket; import org.oscim.renderer.bucket.MeshBucket; import org.oscim.renderer.bucket.PolygonBucket; import org.oscim.renderer.bucket.RenderBucket; import org.oscim.renderer.bucket.RenderBuckets; import org.oscim.renderer.bucket.TextureBucket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class to use the renderer.elements for drawing. * * All methods that modify 'buckets' MUST be synchronized! */ public class BucketRenderer extends LayerRenderer { public static final Logger log = LoggerFactory.getLogger(BucketRenderer.class); /** * Use mMapPosition.copy(position) to keep the position for which * the Overlay is *compiled*. NOTE: required by setMatrix utility * functions to draw this layer fixed to the map */ protected MapPosition mMapPosition; /** Wrap around dateline */ protected boolean mFlipOnDateLine = true; /** Buckets for rendering */ public final RenderBuckets buckets; public BucketRenderer() { buckets = new RenderBuckets(); mMapPosition = new MapPosition(); } protected boolean mInititialzed; /** * Default implementation: * Copy initial Viewport position and compile buckets. */ @Override public void update(GLViewport v) { if (!mInititialzed) { mMapPosition.copy(v.pos); mInititialzed = true; compile(); } } /** * Render all 'buckets' */ @Override public synchronized void render(GLViewport v) { MapPosition layerPos = mMapPosition; GLState.test(false, false); GLState.blend(true); float div = (float) (v.pos.scale / layerPos.scale); boolean project = true; setMatrix(v, project); for (RenderBucket b = buckets.get(); b != null;) { buckets.bind(); if (!project && b.type != SYMBOL) { project = true; setMatrix(v, project); } switch (b.type) { case POLYGON: b = PolygonBucket.Renderer.draw(b, v, 1, true); break; case LINE: b = LineBucket.Renderer.draw(b, v, div, buckets); break; case TEXLINE: b = LineTexBucket.Renderer.draw(b, v, div, buckets); break; case MESH: b = MeshBucket.Renderer.draw(b, v); break; case HAIRLINE: b = HairLineBucket.Renderer.draw(b, v); break; case BITMAP: b = BitmapBucket.Renderer.draw(b, v, 1, 1); break; case SYMBOL: if (project) { project = false; setMatrix(v, project); } b = TextureBucket.Renderer.draw(b, v, div); break; default: log.error("invalid bucket {}", b.type); b = b.next; break; } } } /** * Compile all buckets into one BufferObject. Sets renderer to be ready * when successful. When no data is available (buckets.countVboSize() == 0) * then BufferObject will be released and buckets will not be rendered. */ protected synchronized void compile() { boolean ok = buckets.compile(true); setReady(ok); } /** * Utility: Set matrices.mvp matrix relative to the difference of current * MapPosition and the last updated Overlay MapPosition. * Use this to 'stick' your layer to the map. Note: Vertex coordinates * are assumed to be scaled by MapRenderer.COORD_SCALE (== 8). * * @param v * GLViewport * @param project * if true apply view- and projection, or just view otherwise. */ protected void setMatrix(GLViewport v, boolean project) { setMatrix(v, project, MapRenderer.COORD_SCALE); } protected void setMatrix(GLViewport v, boolean project, float coordScale) { setMatrix(v.mvp, v, project, coordScale); } protected void setMatrix(GLMatrix mvp, GLViewport v, boolean project, float coordScale) { MapPosition oPos = mMapPosition; double tileScale = Tile.SIZE * v.pos.scale; double x = oPos.x - v.pos.x; double y = oPos.y - v.pos.y; if (mFlipOnDateLine) { //wrap around date-line while (x < 0.5) x += 1.0; while (x > 0.5) x -= 1.0; } mvp.setTransScale((float) (x * tileScale), (float) (y * tileScale), (float) (v.pos.scale / oPos.scale) / coordScale); mvp.multiplyLhs(project ? v.viewproj : v.view); } /** * Utility: Set matrices.mvp matrix relative to the difference of current * MapPosition and the last updated Overlay MapPosition and applies * view-projection-matrix. */ protected void setMatrix(GLViewport v) { setMatrix(v, true); } }