/* * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package net.java.dev.lwuit.speed; import com.sun.lwuit.Component; import com.sun.lwuit.Display; import com.sun.lwuit.Form; import com.sun.lwuit.Graphics; import com.sun.lwuit.Image; import com.sun.lwuit.Label; import com.sun.lwuit.M3G; import com.sun.lwuit.geom.Dimension; import java.io.IOException; import javax.microedition.m3g.AnimationController; import javax.microedition.m3g.AnimationTrack; import javax.microedition.m3g.Appearance; import javax.microedition.m3g.Background; import javax.microedition.m3g.Camera; import javax.microedition.m3g.CompositingMode; import javax.microedition.m3g.Graphics3D; import javax.microedition.m3g.Group; import javax.microedition.m3g.Image2D; import javax.microedition.m3g.IndexBuffer; import javax.microedition.m3g.KeyframeSequence; import javax.microedition.m3g.Mesh; import javax.microedition.m3g.Node; import javax.microedition.m3g.PolygonMode; import javax.microedition.m3g.Texture2D; import javax.microedition.m3g.Transform; import javax.microedition.m3g.TriangleStripArray; import javax.microedition.m3g.VertexArray; import javax.microedition.m3g.VertexBuffer; import javax.microedition.m3g.World; /** * Tests how fast drawing can be performed on the device with LWUIT * * @author Shai Almog */ public class Framerate3D extends Form implements M3G.Callback { private static int averageFramerate; private long oneSecond = System.currentTimeMillis(); private static final int TEST_DURATION = 10000; private static final int RAMP_UP_DURATION = 1000; private long startTime = System.currentTimeMillis(); private static int paintCalls; public static int getFramecount() { return paintCalls; } private World world; public Framerate3D() { // reduce memory usage for S40 phones... getStyle().setBgImage(null); show(); new Thread() { public void run() { startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < TEST_DURATION) { try { Graphics3D.getInstance().setCamera(null, null); Graphics3D.getInstance().resetLights(); } catch(Throwable err) { } world = null; System.gc(); initRotation(); oneSecond = System.currentTimeMillis(); repaint(); while(System.currentTimeMillis() - oneSecond < 1000 && System.currentTimeMillis() - startTime < TEST_DURATION) { try { Thread.sleep(1); } catch (InterruptedException ex) {} repaint(); } } averageFramerate = paintCalls / ((TEST_DURATION - RAMP_UP_DURATION) / 1000); try { Graphics3D.getInstance().setCamera(null, null); Graphics3D.getInstance().resetLights(); } catch(Throwable err) { } world = null; new Form("Please Wait").show(); System.gc(); new ListTest(); } }.start(); } public static int getAverageFramerate() { return averageFramerate; } public void paintBackground(Graphics g) { } public void paint(Graphics g) { if(world != null) { if(System.currentTimeMillis() - startTime > RAMP_UP_DURATION) { paintCalls++; } g.setColor(0); g.fillRect(0, 0, getWidth(), getHeight()); M3G.getInstance().renderM3G(g, true, 0, this); } } public void paintM3G(Graphics3D g) { int time = (int)(System.currentTimeMillis() - oneSecond); world.animate(time); g.render(world); } public void initRotation() { if(!Display.getInstance().isEdt()) { Display.getInstance().callSeriallyAndWait(new Runnable() { public void run() { initRotation(); } }); return; } world = new World(); Camera camera = new Camera(); camera.setPerspective(30.0f, 1, 1.0f, 45.0f); Transform cameraTransform = new Transform(); Graphics3D g3d = Graphics3D.getInstance(); g3d.setCamera(camera, cameraTransform); // the whole world is within a single group in the scene graph tree Group group = new Group(); world.addChild(group); world.setActiveCamera(camera); group.addChild(camera); Background background3D = new Background(); background3D.setColorClearEnable(true); background3D.setDepthClearEnable(true); background3D.setColor(0xff000000); world.setBackground(background3D); Form rotatingForm = new Form("Rotation"); rotatingForm.addComponent(new Label("This form should rotate!")); Mesh destMesh = createMesh(rotatingForm); group.addChild(destMesh); createRotation(group, destMesh, rotatingForm); world.animate(0); } private VertexBuffer makeGeometry() { // create vertices short[] verts = { -1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0 }; VertexArray va = new VertexArray(verts.length / 3, 3, 2); va.set(0, verts.length / 3, verts); // create texture coordinates short[] tcs = { 0, 1, 1, 1, 1, 0, 0, 0 }; VertexArray texArray = new VertexArray(tcs.length / 2, 2, 2); texArray.set(0, tcs.length / 2, tcs); VertexBuffer vb = new VertexBuffer(); vb.setPositions(va, 1.0f, null); // no scale, bias vb.setTexCoords(0, texArray, 1.0f, null); return vb; } /** * Creates a texture making */ private Texture2D createTexture(Image2D img) { Texture2D tex = new Texture2D(img); tex.setFiltering(Texture2D.FILTER_NEAREST, Texture2D.FILTER_NEAREST); tex.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP); tex.setBlending(Texture2D.FUNC_REPLACE); return tex; } private Mesh createMesh(Component c) { Texture2D tex = createTexture(createImage2D(c)); CompositingMode cm = new CompositingMode(); cm.setBlending(CompositingMode.ALPHA); cm.setAlphaWriteEnable(true); cm.setDepthTestEnable(true); Appearance appearance = new Appearance(); PolygonMode polyMode = new PolygonMode(); polyMode.setPerspectiveCorrectionEnable(true); appearance.setPolygonMode(polyMode); appearance.setCompositingMode(cm); appearance.setTexture(0, tex); VertexBuffer vb = makeGeometry(); int[] indicies = {1,2,0,3}; // one quad int[] stripLens = {4}; IndexBuffer ib = new TriangleStripArray(indicies, stripLens); Mesh m = new Mesh(vb, ib, appearance); return m; } private Image2D createImage2D(Component c) { int w = Display.getInstance().getDisplayWidth(); int h = Display.getInstance().getDisplayHeight(); int textureW; int textureH; c.setVisible(true); // use the true texture maximum resolution ignoring light mode... int max = M3G.getInstance().getMaxTextureDimension(); textureW = Math.min(M3G.closestLowerPowerOf2(w), max); textureH = Math.min(M3G.closestLowerPowerOf2(h), max); Image mutable = Image.createImage(c.getWidth(), c.getHeight()); c.paintComponent(mutable.getGraphics()); mutable = mutable.scaled(textureW, textureH); return M3G.getInstance().createImage2D(Image2D.RGB, mutable); } private void createRotation(Group group, Mesh destMesh, Form rotatingForm) { Node sourceMesh = (Node)createMesh(rotatingForm); group.addChild(sourceMesh); sourceMesh.setTranslation(0, 0, -3.79f); destMesh.setTranslation(0, 0, -3.8f); KeyframeSequence rotationSource = new KeyframeSequence(3, 4, KeyframeSequence.SPLINE); KeyframeSequence rotationDest = new KeyframeSequence(3, 4, KeyframeSequence.SPLINE); rotationSource.setDuration(1000); rotationDest.setDuration(1000); int half = 45; int full = 90; // prevent the rotation from staying too long in 90 degrees int halfDest = 150; int fullDest = 180; rotationSource.setKeyframe(0, 0, getYRoation(0)); rotationSource.setKeyframe(1, 1000 / 4, getYRoation(half)); rotationSource.setKeyframe(2, 1000 / 2, getYRoation(full)); rotationDest.setKeyframe(0, 0, getYRoation(full)); rotationDest.setKeyframe(1, 1000 / 2, getYRoation(halfDest)); rotationDest.setKeyframe(2, 1000, getYRoation(fullDest)); AnimationController animation = new AnimationController(); AnimationTrack track = new AnimationTrack(rotationSource, AnimationTrack.ORIENTATION); sourceMesh.addAnimationTrack(track); track.setController(animation); track = new AnimationTrack(rotationDest, AnimationTrack.ORIENTATION); destMesh.addAnimationTrack(track); track.setController(animation); } /** * Creates a rotation matrix on the Y axis */ private float[] getYRoation(float angle) { angle = (float)Math.toRadians(angle); return new float[] {0, (float)Math.sin(angle), 0, (float)Math.cos(angle)}; } }