/**
* Copyright 2008 - 2015 The Loon Game Engine Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.5
*/
package loon.html5.gwt;
import java.util.Map;
import java.util.HashMap;
import loon.Graphics;
import loon.LGame;
import loon.LSystem;
import loon.Platform.Orientation;
import loon.canvas.Canvas;
import loon.font.Font;
import loon.font.TextFormat;
import loon.font.TextLayout;
import loon.font.TextWrap;
import loon.geom.Dimension;
import loon.html5.gwt.GWTGame.GWTSetting;
import loon.html5.gwt.Loon.OrientationChangedHandler;
import loon.opengl.GL20;
import loon.utils.GLUtils;
import loon.utils.Scale;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.dom.client.CanvasElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.webgl.client.WebGLContextAttributes;
import com.google.gwt.webgl.client.WebGLRenderingContext;
public class GWTGraphics extends Graphics {
private final GWTSetting config;
private final CanvasElement dummyCanvas;
private final Context2d dummyCtx;
private final Element measureElement;
private final Map<Font, GWTFontMetrics> fontMetrics = new HashMap<Font, GWTFontMetrics>();
final Element rootElement;
final CanvasElement canvas;
private final Dimension screenSize = new Dimension();
private static final String HEIGHT_TEXT = "THEQUICKBROWNFOXJUMPEDOVERTHELAZYDOGthequickbrownfoxjumpedoverthelazydog_-+!.,[]0123456789";
private static final String EMWIDTH_TEXT = "m";
static float experimentalScale = 1;
public GWTGraphics(final Panel panel, final LGame game, final GWTSetting cfg) {
super(game, new GWTGL20(), game.setting.scaling() ? Scale.ONE
: new Scale(Loon.devicePixelRatio()));
this.config = cfg;
Document doc = Document.get();
this.dummyCanvas = doc.createCanvasElement();
this.dummyCtx = dummyCanvas.getContext2d();
Element root = panel.getElement();
this.rootElement = root;
measureElement = doc.createDivElement();
measureElement.getStyle().setVisibility(Style.Visibility.HIDDEN);
measureElement.getStyle().setPosition(Style.Position.ABSOLUTE);
measureElement.getStyle().setTop(-500, Unit.PX);
measureElement.getStyle().setOverflow(Style.Overflow.VISIBLE);
measureElement.getStyle().setWhiteSpace(Style.WhiteSpace.NOWRAP);
root.appendChild(measureElement);
canvas = Document.get().createCanvasElement();
root.appendChild(canvas);
if (config.scaling()) {
setSize(config.width_zoom > 0 ? config.width_zoom
: root.getOffsetWidth(),
config.height_zoom > 0 ? config.height_zoom : root
.getOffsetHeight());
} else {
setSize(config.width > 0 ? config.width : root.getOffsetWidth(),
config.height > 0 ? config.height : root.getOffsetHeight());
}
WebGLContextAttributes attrs = WebGLContextAttributes.create();
attrs.setAntialias(config.antiAliasing);
attrs.setStencil(config.stencil);
attrs.setAlpha(config.transparentCanvas);
attrs.setPremultipliedAlpha(config.premultipliedAlpha);
attrs.setPreserveDrawingBuffer(config.preserveDrawingBuffer);
WebGLRenderingContext glc = WebGLRenderingContext.getContext(canvas,
attrs);
if (glc == null) {
throw new RuntimeException("Unable to create GL context");
}
((GWTGL20) gl).init(glc);
if (config.scaling()) {
glc.viewport(0, 0, config.width_zoom, config.height_zoom);
} else {
glc.viewport(0, 0, config.width, config.height);
}
if (config.fullscreen) {
Window.addResizeHandler(new ResizeHandler() {
@Override
public void onResize(ResizeEvent event) {
if (getScreenWidthJSNI() == event.getWidth()
&& getScreenHeightJSNI() == event.getHeight()) {
float width = LSystem.viewSize.width(), height = LSystem.viewSize
.height();
experimentalScale = Math.min(getScreenWidthJSNI()
/ width, getScreenHeightJSNI() / height);
int yOfs = (int) ((getScreenHeightJSNI() - height
* experimentalScale) / 3.f);
int xOfs = (int) ((getScreenWidthJSNI() - width
* experimentalScale) / 2.f);
rootElement.setAttribute("style", "width:"
+ experimentalScale * width + "px; "
+ "height:" + experimentalScale * height
+ "px; " + "position:absolute; left:" + xOfs
+ "px; top:" + yOfs);
Document.get().getBody().addClassName("fullscreen");
} else {
experimentalScale = 1;
rootElement.removeAttribute("style");
Document.get().getBody().removeClassName("fullscreen");
}
}
});
}
Loon.self.addHandler(new OrientationChangedHandler() {
@Override
public void onChanged(Orientation newOrientation) {
int width = Loon.self.getContainerWidth();
int height = Loon.self.getContainerHeight();
game.log().info(
"update screen size width :" + width + " height :"
+ height);
setSize(width, height);
}
});
}
private boolean isFullscreen() {
return isFullscreenJSNI();
}
private native int getScreenWidthJSNI() /*-{
return $wnd.screen.width;
}-*/;
private native int getScreenHeightJSNI() /*-{
return $wnd.screen.height;
}-*/;
private native boolean isFullscreenJSNI() /*-{
if ("webkitIsFullScreen" in $doc) {
return $doc.webkitIsFullScreen;
}
if ("mozFullScreen" in $doc) {
return $doc.mozFullScreen;
}
return false
}-*/;
public void setSize(int width, int height) {
rootElement.getStyle().setWidth(width, Unit.PX);
rootElement.getStyle().setHeight(height, Unit.PX);
canvas.setWidth(scale().scaledCeil(width));
canvas.setHeight(scale().scaledCeil(height));
canvas.getStyle().setWidth(width, Style.Unit.PX);
canvas.getStyle().setHeight(height, Style.Unit.PX);
viewportChanged(scale(), canvas.getWidth(), canvas.getHeight());
}
public void registerFontMetrics(String name, Font font, float lineHeight) {
GWTFontMetrics metrics = getFontMetrics(font);
fontMetrics.put(font, new GWTFontMetrics(font, lineHeight,
metrics.emwidth));
}
@Override
public Dimension screenSize() {
screenSize.setSize(
Document.get().getDocumentElement().getClientWidth(), Document
.get().getDocumentElement().getClientHeight());
return screenSize;
}
@Override
public TextLayout layoutText(String text, TextFormat format) {
return GWTTextLayout.layoutText(this, dummyCtx, text, format);
}
@Override
public TextLayout[] layoutText(String text, TextFormat format, TextWrap wrap) {
return GWTTextLayout.layoutText(this, dummyCtx, text, format, wrap);
}
@Override
protected Canvas createCanvasImpl(Scale scale, int pixelWidth,
int pixelHeight) {
CanvasElement elem = Document.get().createCanvasElement();
elem.setWidth(pixelWidth);
elem.setHeight(pixelHeight);
return new GWTCanvas(this, new GWTImage(this, scale, elem, "<canvas>"));
}
void updateTexture(int tex, ImageElement img) {
GLUtils.bindTexture(gl, tex);
((GWTGL20) gl).glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA,
GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, img);
}
GWTFontMetrics getFontMetrics(Font font) {
GWTFontMetrics metrics = fontMetrics.get(font);
if (metrics == null) {
measureElement.getStyle().setFontSize(font.size, Unit.PX);
measureElement.getStyle().setFontWeight(Style.FontWeight.NORMAL);
measureElement.getStyle().setFontStyle(Style.FontStyle.NORMAL);
measureElement.getStyle().setProperty("fontFamily", font.name);
measureElement.setInnerText(HEIGHT_TEXT);
switch (font.style) {
case BOLD:
measureElement.getStyle().setFontWeight(Style.FontWeight.BOLD);
break;
case ITALIC:
measureElement.getStyle().setFontStyle(Style.FontStyle.ITALIC);
break;
case BOLD_ITALIC:
measureElement.getStyle().setFontWeight(Style.FontWeight.BOLD);
measureElement.getStyle().setFontStyle(Style.FontStyle.ITALIC);
break;
default:
break;
}
float height = measureElement.getOffsetHeight();
measureElement.setInnerText(EMWIDTH_TEXT);
float emwidth = measureElement.getOffsetWidth();
metrics = new GWTFontMetrics(font, height, emwidth);
fontMetrics.put(font, metrics);
}
return metrics;
}
}