- turn off libgdx load screen
- block contextmenu
- add osm attribution
- read initial position from url hash
- disable text stroke for firefox/linux (canvas2d is 10 times slower than chromium..)
This commit is contained in:
Hannes Janetzek 2013-08-05 02:54:21 +02:00
parent 05440542b9
commit dfec023e6e
9 changed files with 299 additions and 129 deletions

View File

@ -9,6 +9,7 @@ import com.google.gwt.canvas.dom.client.Context2d.LineJoin;
public class GwtCanvas implements org.oscim.backend.canvas.Canvas {
GwtBitmap bitmap;
public GwtCanvas() {
// canvas comes with gdx pixmap
}
@ -16,38 +17,38 @@ public class GwtCanvas implements org.oscim.backend.canvas.Canvas {
@Override
public void setBitmap(Bitmap bitmap) {
this.bitmap = (GwtBitmap) bitmap;
//this.bitmap.pixmap.setColor(0x00ffffff);
this.bitmap.pixmap.getContext().clearRect(0, 0, this.bitmap.getWidth(), this.bitmap.getHeight());
Context2d ctx = this.bitmap.pixmap.getContext();
ctx.clearRect(0, 0, this.bitmap.getWidth(), this.bitmap.getHeight());
ctx.setLineJoin(LineJoin.BEVEL);
}
@Override
public void drawText(String string, float x, float y, Paint paint) {
if (bitmap == null){
Log.d("", "no bitmap set on canvas");
if (bitmap == null) {
Log.d("BUG", "no bitmap set");
return;
}
GwtPaint p = (GwtPaint) paint;
if (p.stroke && GwtCanvasAdapter.NO_STROKE_TEXT)
return;
Context2d ctx = bitmap.pixmap.getContext();
ctx.setFont(p.font);
ctx.setLineJoin(LineJoin.ROUND);
if (p.stroke){
//Log.d("", "stroke " + p.stroke + " " + p.color + " " + p.font + " "+ string);
if (p.stroke) {
ctx.setLineWidth(p.strokeWidth);
ctx.setStrokeStyle(p.color);
//ctx.strokeText(string, p.strokeWidth + x, p.strokeWidth + y);
ctx.strokeText(string, x + 1, y + 1);
} else{
//Log.d("", "fill " + p.stroke + " " + p.color + " " + p.font + " "+ string);
ctx.strokeText(string, (int) (x + 1), (int) (y + 1));
} else {
ctx.setFillStyle(p.color);
ctx.fillText(string, x + 1, y + 1);
ctx.fillText(string, (int) (x + 1), (int) (y + 1));
}
}
@Override
public void drawBitmap(Bitmap bitmap, float x, float y) {
// TODO Auto-generated method stub
}
}

View File

@ -12,8 +12,11 @@ import com.google.gwt.canvas.dom.client.TextMetrics;
public class GwtCanvasAdapter extends CanvasAdapter {
public static boolean NO_STROKE_TEXT = false;
public static final GwtCanvasAdapter INSTANCE = new GwtCanvasAdapter();
static final Context2d ctx;
static {
Canvas canvas = Canvas.createIfSupported();
canvas.setCoordinateSpaceWidth(1);
@ -24,7 +27,7 @@ public class GwtCanvasAdapter extends CanvasAdapter {
static synchronized float getTextWidth(String text, String font) {
ctx.setFont(font);
TextMetrics tm = ctx.measureText(text);
return (float)tm.getWidth();
return (float) tm.getWidth();
}
@Override

View File

@ -4,18 +4,32 @@ package org.oscim.gdx.client;
import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.GL20;
import org.oscim.backend.GLAdapter;
import org.oscim.backend.Log;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile;
import org.oscim.gdx.GdxMap;
import org.oscim.layers.Layer;
import org.oscim.layers.tile.bitmap.BitmapTileLayer;
import org.oscim.layers.tile.bitmap.NaturalEarth;
import org.oscim.renderer.GLRenderer;
import org.oscim.tilesource.TileSource;
import org.oscim.tilesource.oscimap2.OSciMap2TileSource;
import org.oscim.tilesource.oscimap4.OSciMap4TileSource;
import org.oscim.view.MapView;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.gwt.GwtApplication;
import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration;
import com.badlogic.gdx.backends.gwt.GwtGraphics;
import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderCallback;
import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderState;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.RootPanel;
public class GwtLauncher extends GwtApplication {
@ -24,6 +38,24 @@ public class GwtLauncher extends GwtApplication {
GwtApplicationConfiguration cfg = new GwtApplicationConfiguration(
GwtGraphics.getWindowWidthJSNI(),
GwtGraphics.getWindowHeightJSNI());
DockLayoutPanel p = new DockLayoutPanel(Unit.EM);
p.setHeight("100%");
p.setWidth("100%");
RootPanel.get().add(p);
//HTML header = new HTML("header");
//p.addNorth(header, 2);
//header.setStyleName("header");
//HTML footer = new HTML("footer");
//footer.setStyleName("footer");
//p.addSouth(footer, 2);
cfg.rootPanel = new FlowPanel();
p.add(cfg.rootPanel);
cfg.stencil = true;
cfg.fps = 30;
@ -40,6 +72,21 @@ public class GwtLauncher extends GwtApplication {
return new GwtGdxMap();
}
@Override
public PreloaderCallback getPreloaderCallback() {
return new PreloaderCallback() {
@Override
public void update(PreloaderState state) {
}
@Override
public void error(String file) {
Log.d(this.getClass().getName(), "error loading " + file);
}
};
}
private static native String getMapConfig(String key)/*-{
return $wnd.mapconfig && $wnd.mapconfig[key] || null;
}-*/;
@ -48,34 +95,112 @@ public class GwtLauncher extends GwtApplication {
@Override
public void create() {
CanvasAdapter.g = GwtCanvasAdapter.INSTANCE;
GLAdapter.g = (GL20)Gdx.graphics.getGL20();
GLAdapter.GDX_WEBGL_QUIRKS = true;
// stroke text takes about 70% cpu time in firefox:
// https://bug568526.bugzilla.mozilla.org/attachment.cgi?id=447932
// <- circle/stroke test 800ms firefox, 80ms chromium..
// TODO use texture atlas to avoid drawing text-textures
if (GwtApplication.agentInfo().isLinux() && GwtApplication.agentInfo().isFirefox())
GwtCanvasAdapter.NO_STROKE_TEXT = true;
//GLAdapter.NON_PREMUL_CANVAS = true;
CanvasAdapter.g = GwtCanvasAdapter.INSTANCE;
GLAdapter.g = (GL20) Gdx.graphics.getGL20();
GLAdapter.GDX_WEBGL_QUIRKS = true;
GLRenderer.setBackgroundColor(0xffffff);
//Gdx.app.setLogLevel(Application.LOG_DEBUG);
super.create();
double lat = Double.parseDouble(getMapConfig("latitude"));
double lon = Double.parseDouble(getMapConfig("longitude"));
int zoom = Integer.parseInt(getMapConfig("zoom"));
double lat = Double.parseDouble(getMapConfig("latitude"));
double lon = Double.parseDouble(getMapConfig("longitude"));
int zoom = Integer.parseInt(getMapConfig("zoom"));
float tilt = 0;
float rotation = 0;
if (Window.Location.getHash() != null) {
String hash = Window.Location.getHash();
//Log.d("...", "hash: " + hash);
hash = hash.substring(1);
String[] pairs = hash.split(",");
for (String p : pairs) {
try {
if (p.startsWith("lat="))
lat = Double.parseDouble(p.substring(4));
else if (p.startsWith("lon="))
lon = Double.parseDouble(p.substring(4));
else if (p.startsWith("scale="))
zoom = Integer.parseInt(p.substring(6));
else if (p.startsWith("rot="))
rotation = Float.parseFloat(p.substring(4));
else if (p.startsWith("tilt="))
tilt = Float.parseFloat(p.substring(5));
} catch (NumberFormatException e) {
}
}
}
MapPosition p = new MapPosition();
p.setZoomLevel(zoom);
p.setPosition(lat, lon);
mMapView.setMapPosition(p);
mMapView.getMapViewPosition().setTilt(tilt);
mMapView.getMapViewPosition().setRotation(rotation);
String url = getMapConfig("tileurl");
TileSource tileSource;
if ("oscimap4".equals(getMapConfig("tilesource")))
tileSource = new OSciMap4TileSource();
else
tileSource = new OSciMap2TileSource();
tileSource.setOption("url", url);
mMapView.setBaseMap(tileSource);
initDefaultMap(tileSource, false, true, true);
mMapView.getLayerManager().add(new UrlPositionUpdate(mMapView));
mMapView.setBackgroundMap(new BitmapTileLayer(mMapView, NaturalEarth.INSTANCE));
}
}
class UrlPositionUpdate extends Layer {
public UrlPositionUpdate(MapView mapView) {
super(mapView);
}
private int curLon, curLat, curZoom, curTilt, curRot;
@Override
public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
if (!changed)
return;
int lat = (int) (MercatorProjection.toLatitude(pos.y) * 1000);
int lon = (int) (MercatorProjection.toLongitude(pos.x) * 1000);
int rot = (int) (pos.angle);
rot = (int) (pos.angle) % 360;
rot = rot < 0 ? -rot : rot;
if (curZoom != pos.zoomLevel
|| curLat != lat
|| curLon != lon
|| curTilt != rot
|| curRot != (int) (pos.angle)) {
curLat = lat;
curLon = lon;
curZoom = pos.zoomLevel;
curTilt = (int) pos.tilt;
curRot = rot;
//String newURL = Window.Location.createUrlBuilder()
// .setHash("scale=" + pos.zoomLevel + ",rot=" + curRot + ",tilt=" +
// curTilt + ",lat=" + (curLat / 1000f) + ",lon=" + (curLon / 1000f))
// .buildString();
//Window.Location.replace(newURL);
//Window.Location.
}
}
}
}

View File

@ -16,6 +16,8 @@
package com.badlogic.gdx.backends.gwt;
import org.oscim.backend.GL20;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Audio;
@ -43,7 +45,6 @@ import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
@ -130,7 +131,6 @@ public abstract class GwtApplication implements EntryPoint, Application {
private void setupLoop() {
// setup modules
consoleLog("setupLoop");
try {
graphics = new GwtGraphics(root, config);
} catch (Throwable e) {
@ -167,10 +167,17 @@ public abstract class GwtApplication implements EntryPoint, Application {
throw new RuntimeException(t);
}
final int frameTime = (int) ((1f / config.fps) * 1000);
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// setup rendering timer
new Timer() {
//long lastRun;
@Override
public void run() {
//long startRender = 0;
try {
graphics.update();
if (graphics.getWidth() != lastWidth
@ -188,14 +195,26 @@ public abstract class GwtApplication implements EntryPoint, Application {
runnablesHelper.get(i).run();
}
runnablesHelper.clear();
//startRender = System.currentTimeMillis();
listener.render();
input.justTouched = false;
} catch (Throwable t) {
error("GwtApplication", "exception: " + t.getMessage(), t);
throw new RuntimeException(t);
}
long now = System.currentTimeMillis();
int diff = (int)(now - graphics.lastTimeStamp);
//if (diff > 80)
// consoleLog("diff " + diff + " " + (now - startRender) + " " + graphics.getFramesPerSecond() );
diff = frameTime - diff;
//lastRun = now;
this.schedule(diff > 5 ? diff : 5);
}
}.scheduleRepeating((int) ((1f / config.fps) * 1000));
}.schedule(0); //scheduleRepeating((int) ((1f / config.fps) * 1000));
}
public Panel getRootPanel() {
@ -207,9 +226,11 @@ public abstract class GwtApplication implements EntryPoint, Application {
public PreloaderCallback getPreloaderCallback() {
final Panel preloaderPanel = new VerticalPanel();
preloaderPanel.setStyleName("gdx-preloader");
final Image logo = new Image(GWT.getModuleBaseURL() + "logo.png");
logo.setStyleName("logo");
preloaderPanel.add(logo);
//final Image logo = new Image(GWT.getModuleBaseURL() + "logo.png");
//logo.setStyleName("logo");
//preloaderPanel.add(logo);
final Panel meterPanel = new SimplePanel();
meterPanel.setStyleName("gdx-meter");
meterPanel.addStyleName("red");

View File

@ -47,7 +47,7 @@ public class GwtGraphics implements Graphics {
boolean inFullscreenMode = false;
double pixelRatio;
public GwtGraphics(Panel root, GwtApplicationConfiguration config) {
public GwtGraphics(Panel root, final GwtApplicationConfiguration config) {
Canvas canvasWidget = Canvas.createIfSupported();
if (canvasWidget == null)
throw new GdxRuntimeException("Canvas not supported");
@ -61,7 +61,6 @@ public class GwtGraphics implements Graphics {
canvas.getStyle().setWidth(config.width, Unit.PX);
canvas.getStyle().setHeight(config.height, Unit.PX);
this.config = config;
WebGLContextAttributes attributes = WebGLContextAttributes.create();
@ -72,17 +71,18 @@ public class GwtGraphics implements Graphics {
context = WebGLRenderingContext.getContext(canvas, attributes);
context.viewport(0, 0, config.width, config.height);
// this actually *enables* the option to use std derivatives in shader..
// this actually *enables* the option to use std derivatives in shader..
context.getExtension("OES_standard_derivatives");
this.gl = config.useDebugGL ? new GwtGL20Debug(context) : new GwtGL20(context);
canvas.setId("gdx-canvas");
Window.addResizeHandler(new ResizeHandler() {
@Override
public void onResize(ResizeEvent event) {
int w = getWindowWidthJSNI();
int h = getWindowHeightJSNI();
int w = config.rootPanel.getOffsetWidth();
int h = config.rootPanel.getOffsetHeight();
canvas.getStyle().setWidth(w, Unit.PX);
canvas.getStyle().setHeight(h, Unit.PX);

View File

@ -382,6 +382,10 @@ public class GwtInput implements Input {
.addEventListener(
name,
function(e) {
if (capture){
e.preventDefault();
e.stopPropagation();
}
handler.@com.badlogic.gdx.backends.gwt.GwtInput::handleEvent(Lcom/google/gwt/dom/client/NativeEvent;)(e);
}, capture);
}-*/;
@ -440,6 +444,7 @@ public class GwtInput implements Input {
private void hookEvents() {
addEventListener(canvas, "mousedown", this, true);
addEventListener(canvas, "contextmenu", this, true);
addEventListener(Document.get(), "mousedown", this, true);
addEventListener(canvas, "mouseup", this, true);
addEventListener(Document.get(), "mouseup", this, true);

View File

@ -17,14 +17,17 @@ package org.oscim.layers.tile.bitmap;
import java.net.URL;
import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.gdx.client.GwtBitmap;
import org.oscim.layers.tile.MapTile;
import org.oscim.layers.tile.TileLayer;
import org.oscim.layers.tile.TileLoader;
import org.oscim.layers.tile.TileManager;
import org.oscim.layers.tile.bitmap.TileSource.FadeStep;
import org.oscim.renderer.sublayers.BitmapLayer;
import org.oscim.renderer.sublayers.Layers;
import org.oscim.utils.FastMath;
import org.oscim.view.MapView;
import com.google.gwt.event.dom.client.ErrorEvent;
@ -37,10 +40,41 @@ import com.google.gwt.user.client.ui.RootPanel;
public class BitmapTileLayer extends TileLayer<TileLoader> {
final TileSource mTileSource;
private final FadeStep[] mFade;
public BitmapTileLayer(MapView mapView, TileSource tileSource) {
super(mapView, tileSource.getZoomLevelMin(), tileSource.getZoomLevelMax(), 100);
mTileSource = tileSource;
mFade = mTileSource.getFadeSteps();
}
@Override
public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
super.onUpdate(pos, changed, clear);
if (mFade == null) {
mRenderLayer.setBitmapAlpha(1);
return;
}
float alpha = 0;
for (FadeStep f : mFade) {
if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
continue;
if (f.alphaStart == f.alphaEnd) {
alpha = f.alphaStart;
break;
}
double range = f.scaleEnd / f.scaleStart;
float a = (float)((range - (pos.scale / f.scaleStart)) / range);
a = FastMath.clamp(a, 0, 1);
// interpolate alpha between start and end
alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
break;
}
mRenderLayer.setBitmapAlpha(alpha);
}
@Override

View File

@ -16,16 +16,12 @@ package org.oscim.tilesource.common;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import org.oscim.backend.Log;
import org.oscim.layers.tile.MapTile;
import org.oscim.tilesource.ITileDataSink;
import org.oscim.tilesource.ITileDataSource;
import org.oscim.backend.Log;
/**
*
*
@ -50,42 +46,15 @@ public abstract class PbfTileDataSource implements ITileDataSource {
mSink = sink;
try {
mConn.sendRequest(tile, this);
//InputStream is;
// if (!mConn.sendRequest(tile, this)) {
// Log.d(TAG, tile + " Request Failed");
// result = QueryResult.FAILED;
// } else if ((is = mConn.readHeader()) != null) {
// boolean win = mTileDecoder.decode(tile, sink, is, mConn.getContentLength());
// if (!win)
// Log.d(TAG, tile + " failed");
// } else {
// Log.d(TAG, tile + " Network Error");
// result = QueryResult.FAILED;
// }
// } catch (SocketException e) {
// Log.d(TAG, tile + " Socket exception: " + e.getMessage());
// result = QueryResult.FAILED;
// } catch (SocketTimeoutException e) {
// Log.d(TAG, tile + " Socket Timeout");
// result = QueryResult.FAILED;
// } catch (UnknownHostException e) {
// Log.d(TAG, tile + " No Network");
// result = QueryResult.FAILED;
} catch (Exception e) {
e.printStackTrace();
result = QueryResult.FAILED;
}
//mConn.requestCompleted();
//if (result != QueryResult.SUCCESS)
// mConn.close();
return result;
}
public void process(InputStream is, int length) {
//Log.d(TAG, mTile + " process " + is + " " + length + " " + mSink);
boolean win = false;
if (length >= 0) {
@ -100,9 +69,6 @@ public abstract class PbfTileDataSource implements ITileDataSource {
mConn.requestCompleted();
mSink.completed(win);
//mTile = null;
//mSink = null;
}
@Override

View File

@ -1,68 +1,83 @@
<!doctype html>
<html>
<head>
<title>vtm-gdx</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<head>
<title>vtm-gdx</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!-- pixel and dpi are way too simple concepts for web devs, lets also have css-pixels! -->
<!-- http://www.html5rocks.com/de/mobile/touch/ -->
<!-- http://www.quirksmode.org/mobile/viewports.html -->
<!-- http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html -->
<!-- devicePixelRatio: http://coding.smashingmagazine.com/2012/08/20/towards-retina-web/ -->
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no">
<!-- pixel and dpi are way too simple concepts for web devs, lets also have css-pixels! -->
<!-- http://www.html5rocks.com/de/mobile/touch/ -->
<!-- http://www.quirksmode.org/mobile/viewports.html -->
<!-- http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html -->
<!-- devicePixelRatio: http://coding.smashingmagazine.com/2012/08/20/towards-retina-web/ -->
<meta name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no">
<style>
canvas {
cursor: default;
outline: none;
position: fixed;
left: 0;
top: 0;
}
</style>
<style>
.header {
background-color: #ddd;
text-align: center;
}
gdx-canvas {
cursor: default;
outline: none;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
html, body {
height: 100%;
width: 100%;
margin: 0 0 0 0;
}
<script type="text/javascript">
var mapconfig = {
tilesource : "oscimap4",
tileurl : "/osci/testing2",
zoom: "4",
latitude: "0.0",
longitude: "0.0"
}
</script>
#credits {
position: absolute;
bottom: 0.2em;
right: 0.2em;
z-index: 20000;
color: white;
background-color: #000;
opacity: 0.5;
padding: 0.2em 0.5em 0.2em 0.5em;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
font-size: 11px;
font-family: Arial, "MS Trebuchet", sans-serif;
}
#credits a {
color: white;
text-decoration: none;
font-variant: small-caps;
}
</style>
</head>
<script type="text/javascript">
var mapconfig = {
tilesource : "oscimap4",
tileurl : "/tiles/vtm",
zoom : "2",
latitude : "0.0",
longitude : "0.0"
}
</script>
<body>
</head>
<div align="center" id="embed-org.oscim.gdx.GwtDefinition"></div>
<body>
<script type="text/javascript" src="js/_tessellate.js"></script>
<script type="text/javascript" src="js/tessellate.js"></script>
<script type="text/javascript" src="js/_tessellate.js"></script>
<script type="text/javascript" src="js/tessellate.js"></script>
<script type="text/javascript"
<script type="text/javascript"
src="org.oscim.gdx.GwtDefinition/org.oscim.gdx.GwtDefinition.nocache.js"></script>
</body>
<script>
function handleMouseDown(evt) {
evt.preventDefault();
evt.stopPropagation();
evt.target.style.cursor = 'default';
}
<div id="credits">
<a href="https://github.com/hjanetzek/vtm">Source</a>
| map data © <a href="http://www.openstreemap.org">OpenStreetMap</a> contributors
| <a href="http://www.opensciencemap.org">OpenScienceMap</a>
</div>
</body>
function handleMouseUp(evt) {
evt.preventDefault();
evt.stopPropagation();
evt.target.style.cursor = '';
}
document.getElementById('embed-org.oscim.gdx.GwtDefinition')
.addEventListener('mousedown', handleMouseDown, false);
document.getElementById('embed-org.oscim.gdx.GwtDefinition')
.addEventListener('contextmenu', handleMouseDown, false);
document.getElementById('embed-org.oscim.gdx.GwtDefinition')
.addEventListener('mouseup', handleMouseUp, false);
</script>
</html>