package org.geogebra.web.geogebra3D.web.euclidian3D.openGL; import org.geogebra.common.awt.GBufferedImage; import org.geogebra.common.euclidian.MyZoomer; import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D; import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawLabel3D; import org.geogebra.common.geogebra3D.euclidian3D.openGL.RendererWithImpl; import org.geogebra.web.geogebra3D.web.euclidian3D.EuclidianView3DW; import org.geogebra.web.html5.gawt.GBufferedImageW; import org.geogebra.web.html5.util.ImageLoadCallback; import org.geogebra.web.html5.util.ImageWrapper; import com.google.gwt.canvas.client.Canvas; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.ImageElement; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.googlecode.gwtgl.binding.WebGLRenderingContext; /** * * Renderer for web, using impl. * * @author mathieu * */ public class RendererWithImplW extends RendererWithImpl implements RendererWInterface { protected Canvas webGLCanvas; protected WebGLRenderingContext glContext; /** * @param view * @param type */ public RendererWithImplW(EuclidianView3D view) { super(view, RendererType.SHADER); webGLCanvas = Canvas.createIfSupported(); setRendererImpl(new RendererImplShadersW(this, view3D)); createGLContext(false); // when window is unload, dispose openGL stuff Window.addCloseHandler(new CloseHandler<Window>() { @Override public void onClose(CloseEvent<Window> event) { getRendererImpl().dispose(); } }); } /** * dummy renderer (when no GL available) */ public RendererWithImplW() { super(); } @Override public Canvas getCanvas() { return webGLCanvas; } @Override public void setLineWidth(double width) { // TODO Auto-generated method stub } @Override public void resumeAnimator() { // no need in web } @Override protected void disableStencilLines() { // TODO Auto-generated method stub } @Override public GBufferedImage createBufferedImage(DrawLabel3D label) { // update width and height label.setDimensionPowerOfTwo( firstPowerOfTwoGreaterThan(label.getWidth()), firstPowerOfTwoGreaterThan(label.getHeight())); // create and return a buffered image with power-of-two dimensions return new GBufferedImageW(label.getWidthPowerOfTwo(), label.getHeightPowerOfTwo(), 1d); } @Override public void createAlphaTexture(DrawLabel3D label, GBufferedImage bimg) { // values for picking (ignore transparent bytes) label.setPickingDimension(0, 0, label.getWidth(), label.getHeight()); // check if image is ready ImageElement image = ((GBufferedImageW) bimg).getImageElement(); if (!image.getPropertyBoolean("complete")) { ImageWrapper.nativeon(image, "load", new AlphaTextureCreator(label, image, (GBufferedImageW) bimg, this)); } else { createAlphaTexture(label, image, (GBufferedImageW) bimg); } } @Override public void textureImage2D(int sizeX, int sizeY, byte[] buf) { // no need (dash and fading are made by the shader) } @Override public void setTextureLinear() { glContext.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MAG_FILTER, WebGLRenderingContext.LINEAR); glContext.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MIN_FILTER, WebGLRenderingContext.LINEAR); glContext.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_WRAP_S, WebGLRenderingContext.CLAMP_TO_EDGE); // prevent repeating the // texture glContext.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_WRAP_T, WebGLRenderingContext.CLAMP_TO_EDGE); // prevent repeating the // texture } @Override public void setTextureNearest() { glContext.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MAG_FILTER, WebGLRenderingContext.NEAREST); glContext.texParameteri(WebGLRenderingContext.TEXTURE_2D, WebGLRenderingContext.TEXTURE_MIN_FILTER, WebGLRenderingContext.NEAREST); } @Override protected void setDepthFunc() { glContext.depthFunc(WebGLRenderingContext.LEQUAL); } @Override protected void enablePolygonOffsetFill() { glContext.enable(WebGLRenderingContext.POLYGON_OFFSET_FILL); } @Override protected void setBlendFunc() { glContext.blendFunc(WebGLRenderingContext.SRC_ALPHA, WebGLRenderingContext.ONE_MINUS_SRC_ALPHA); } @Override public void enableTextures2D() { // glContext.enable(WebGLRenderingContext.TEXTURE_2D); } @Override public void disableTextures2D() { // glContext.disable(WebGLRenderingContext.TEXTURE_2D); } // /////////////////////// // WEB specific methods /** * create the webGL context */ protected void createGLContext(boolean preserveDrawingBuffer) { if (preserveDrawingBuffer) { glContext = getBufferedContext(webGLCanvas.getElement()); } else { glContext = (WebGLRenderingContext) webGLCanvas .getContext("experimental-webgl"); ((RendererImplShadersW) getRendererImpl()).setGL(glContext); } if (glContext == null) { Window.alert("Sorry, Your Browser doesn't support WebGL!"); } } private static native WebGLRenderingContext getBufferedContext( Element element) /*-{ return element.getContext("experimental-webgl", { preserveDrawingBuffer : true }); }-*/; private double ratio = 1; @Override public void setPixelRatio(double ratio) { this.ratio = ratio; } @Override public void setView(int x, int y, int w, int h) { if (glContext == null || webGLCanvas == null) { return; } webGLCanvas.setCoordinateSpaceWidth((int) (w * ratio)); webGLCanvas.setCoordinateSpaceHeight((int) (h * ratio)); webGLCanvas.setWidth(w + "px"); webGLCanvas.setHeight(h + "px"); super.setView(x, y, w, h); start(); } @Override public int getWidthInPixels() { return (int) (getWidth() * ratio); } @Override public int getHeightInPixels() { return (int) (getHeight() * ratio); } private Timer loopTimer; private void start() { ((EuclidianView3DW) view3D).setReadyToRender(); // use loop timer for e.g. automatic rotation loopTimer = new Timer() { @Override public void run() { if (view3D.isAnimated()) { view3D.repaintView(); } } }; loopTimer.scheduleRepeating(MyZoomer.DELAY); } @Override public void drawScene() { super.drawScene(); // clear alpha channel to 1.0 to avoid transparency to html background setColorMask(false, false, false, true); clearColorBuffer(); setColorMask(true, true, true, true); } /** * create alpha texture from image for the label * * @param label * label * @param image * image * @param bimg * buffered image */ protected void createAlphaTexture(DrawLabel3D label, ImageElement image, GBufferedImageW bimg) { ((RendererImplShadersW) getRendererImpl()).createAlphaTexture(label, image, bimg); } private static class AlphaTextureCreator implements ImageLoadCallback { private DrawLabel3D label; private ImageElement image; private GBufferedImageW bimg; private RendererWithImplW renderer; public AlphaTextureCreator(DrawLabel3D label, ImageElement image, GBufferedImageW bimg, RendererWithImplW renderer) { this.label = label; this.image = image; this.bimg = bimg; this.renderer = renderer; } @Override public void onLoad() { // image ready : create the texture renderer.createAlphaTexture(label, image, bimg); // repaint the view renderer.getView().repaintView(); } } @Override public void setBuffering(boolean b) { this.createGLContext(b); } @Override protected final void selectFBO() { // TODO implement? } @Override protected final void unselectFBO() { // TODO implement? } @Override protected void needExportImage(double scale, int w, int h) { // TODO implement? } @Override protected void setExportImageDimension(int w, int h) { // TODO implement? } }