--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.proconf.g3d.common;\r
+\r
+import java.net.URL;\r
+\r
+import org.eclipse.core.runtime.FileLocator;\r
+import org.eclipse.core.runtime.Path;\r
+import org.simantics.proconf.g3d.Activator;\r
+import org.simantics.proconf.g3d.base.JmeRenderingComponent;\r
+import org.simantics.proconf.g3d.preferences.PreferenceConstants;\r
+\r
+import com.jme.image.Texture;\r
+import com.jme.light.DirectionalLight;\r
+import com.jme.math.Vector3f;\r
+import com.jme.renderer.Camera;\r
+import com.jme.renderer.ColorRGBA;\r
+import com.jme.renderer.pass.BasicPassManager;\r
+import com.jme.renderer.pass.RenderPass;\r
+import com.jme.renderer.pass.ShadowedRenderPass;\r
+import com.jme.renderer.swt.SWTRenderer;\r
+import com.jme.scene.Node;\r
+import com.jme.scene.Spatial;\r
+import com.jme.scene.Text;\r
+import com.jme.scene.state.AlphaState;\r
+import com.jme.scene.state.LightState;\r
+import com.jme.scene.state.TextureState;\r
+import com.jme.scene.state.WireframeState;\r
+import com.jme.scene.state.ZBufferState;\r
+import com.jme.system.DisplaySystem;\r
+import com.jme.util.TextureManager;\r
+import com.jme.util.Timer;\r
+import com.jme.util.geom.Debugger;\r
+import com.jmex.effects.glsl.BloomRenderPass;\r
+import com.jmex.effects.glsl.SketchRenderPass;\r
+\r
+\r
+public class JmeSinglePassRenderingComponent extends JmeRenderingComponent {\r
+ protected DisplaySystem displaySystem;\r
+ protected Timer timer;\r
+ protected Node rootNode = new Node("Root");\r
+ protected Node shadowRootNode = new Node("Shadow");\r
+ protected Node noCastShadowRootNode = new Node("No Cast Shadow");\r
+ protected Node noShadowRootNode = new Node("No Shadow");\r
+ protected Camera cam;\r
+ protected float near = .1f;\r
+ protected float far = 3000f;\r
+ protected float fov = 55f;\r
+ \r
+ protected int projectionPolicy;\r
+ \r
+ /** The root node of our text. */\r
+ protected Node orthoNode = new Node("ortho");\r
+\r
+ /** Displays all the lovely information at the bottom. */\r
+ protected Text fps;\r
+ protected Text debug;\r
+ protected String debugText = "";\r
+ public static String fontLocation = "data/defaultfont.tga";//AppProperties.PATH_DEFAULT_FONT;\r
+ \r
+ \r
+ protected BasicPassManager pManager = new BasicPassManager();\r
+ \r
+ private boolean showBounds = false;\r
+ private boolean showNormals = false;\r
+ private WireframeState ws = null;\r
+ \r
+ private boolean projectionUpdated = false;\r
+ \r
+ public JmeSinglePassRenderingComponent() {\r
+ \r
+ }\r
+ \r
+ public void init(DisplaySystem displaySystem) {\r
+ this.displaySystem = displaySystem;\r
+ cam = displaySystem.getRenderer().createCamera(\r
+ displaySystem.getRenderer().getWidth(), displaySystem.getRenderer().getHeight());\r
+ displaySystem.getRenderer().setBackgroundColor(new ColorRGBA(0.2f,0.2f,0.2f,0.f));//(0.357F, 0.647F, 0.890F, 1.0F));\r
+ displaySystem.getRenderer().getQueue().setTwoPassTransparency(true);\r
+ cam.setFrustumPerspective(fov,\r
+ (float) displaySystem.getRenderer().getWidth()/\r
+ (float) displaySystem.getRenderer().getHeight(),near, far);\r
+ projectionPolicy = PERSPECTIVE_PROJECTION;\r
+ Vector3f loc = new Vector3f(0.0f, 0.0f, 10.0f);\r
+ Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f);\r
+ Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);\r
+ Vector3f dir = new Vector3f(0.0f, 0f, -1.0f);\r
+ /** Move our camera to a correct place and orientation. */\r
+ cam.setFrame(loc, left, up, dir);\r
+ /** Signal that we've changed our camera's location/frustum. */\r
+ cam.update();\r
+ displaySystem.getRenderer().setCamera(cam);\r
+ timer = Timer.getTimer();\r
+ displaySystem.setTitle("ShapeEditor");\r
+ displaySystem.getRenderer().enableStatistics(true);\r
+ \r
+ initRoot();\r
+ }\r
+ \r
+ protected Texture loadFontTexture() {\r
+ URL url = FileLocator.find(org.simantics.proconf.g3d.Activator.getDefault().getBundle(),new Path(fontLocation),null);\r
+ return TextureManager.loadTexture(url, Texture.MM_LINEAR,\r
+ Texture.FM_LINEAR);\r
+ }\r
+ \r
+ protected void initRoot() {\r
+ ZBufferState buf = displaySystem.getRenderer().createZBufferState();\r
+ buf.setEnabled(true);\r
+ buf.setFunction(ZBufferState.CF_LEQUAL);\r
+ //buf.setWritable(false);\r
+ rootNode.setRenderState(buf); \r
+ rootNode.attachChild(noShadowRootNode);\r
+ rootNode.attachChild(noCastShadowRootNode);\r
+ rootNode.attachChild(shadowRootNode);\r
+ noShadowRootNode.setCullMode(Spatial.CULL_NEVER);\r
+ \r
+ //PointLight light = new PointLight();\r
+ DirectionalLight light = new DirectionalLight();\r
+ light.setDiffuse( new ColorRGBA( 0.75f, 0.75f, 0.75f, 0.75f ) );\r
+ light.setAmbient( new ColorRGBA( 0.5f, 0.5f, 0.5f, 0.5f ) );\r
+ //light.setLocation( new Vector3f( 100, 100, 100 ) );\r
+ light.setDirection(new Vector3f( -100, -150, -100 ));\r
+ light.setEnabled( true );\r
+ light.setShadowCaster(true);\r
+ \r
+ LightState lightState = displaySystem.getRenderer().createLightState();\r
+ lightState.setEnabled( true );\r
+ lightState.attach( light );\r
+ lightState.setSeparateSpecular(true);\r
+ lightState.setTwoSidedLighting(false);\r
+ rootNode.setRenderState( lightState );\r
+ \r
+ ws = displaySystem.getRenderer().createWireframeState();\r
+ ws.setEnabled(false);\r
+ rootNode.setRenderState(ws);\r
+ \r
+ AlphaState as1 = displaySystem.getRenderer().createAlphaState();\r
+ as1.setBlendEnabled(true);\r
+ as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);\r
+ as1.setDstFunction(AlphaState.DB_ONE);\r
+ as1.setTestEnabled(true);\r
+ as1.setTestFunction(AlphaState.TF_GREATER);\r
+ as1.setEnabled(true);\r
+ \r
+ TextureState font = displaySystem.getRenderer().createTextureState();\r
+ /** The texture is loaded from fontLocation */\r
+ font.setTexture(loadFontTexture());\r
+\r
+ font.setEnabled(true);\r
+\r
+ // Then our font Text object.\r
+ /** This is what will actually have the text at the bottom. */\r
+ fps = new Text("FPS label", "");\r
+ fps.setCullMode(Spatial.CULL_NEVER);\r
+ fps.setTextureCombineMode(TextureState.REPLACE);\r
+ \r
+ debug = new Text("Debug", "Debug");\r
+ debug.setCullMode(Spatial.CULL_NEVER);\r
+ debug.setTextureCombineMode(TextureState.REPLACE);\r
+ debug.setLocalTranslation(new Vector3f(1.f,10.f,0.f));\r
+\r
+ // Finally, a stand alone node (not attached to root on purpose)\r
+ Node fpsNode = new Node("FPS node");\r
+ fpsNode.attachChild(fps);\r
+ fpsNode.attachChild(debug);\r
+ fpsNode.setRenderState(font);\r
+ fpsNode.setRenderState(as1);\r
+ fpsNode.setCullMode(Spatial.CULL_NEVER);\r
+ orthoNode.attachChild(fpsNode);\r
+ \r
+ rootNode.updateGeometricState(0.0f, true);\r
+ rootNode.updateRenderState();\r
+ \r
+ orthoNode.updateGeometricState(0.0f, true);\r
+ orthoNode.updateRenderState();\r
+ if (Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.SHADOWS)) {\r
+ ShadowedRenderPass shadowRootPass = new ShadowedRenderPass();\r
+ shadowRootPass.add(shadowRootNode);\r
+ shadowRootPass.add(noCastShadowRootNode);\r
+ shadowRootPass.addOccluder(shadowRootNode);\r
+ pManager.add(shadowRootPass);\r
+ //rootPass.setRenderShadows(false);\r
+ shadowRootPass.setShadowColor(new ColorRGBA(0.1f,0.1f,0.1f,0.9f));\r
+ shadowRootPass.setLightingMethod(ShadowedRenderPass.MODULATIVE);\r
+ RenderPass rootPass = new RenderPass();\r
+ rootPass.add(noShadowRootNode);\r
+ pManager.add(rootPass);\r
+ } else {\r
+ RenderPass rootPass = new RenderPass();\r
+ rootPass.add(rootNode);\r
+ pManager.add(rootPass);\r
+ }\r
+ \r
+ String postProcess = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.POST_PROCESS);\r
+ if (postProcess.startsWith("bloom")) {\r
+ BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4);\r
+ if (bloomRenderPass.isSupported()) {\r
+ bloomRenderPass.add(rootNode);\r
+ bloomRenderPass.setUseCurrentScene(false);\r
+ pManager.add(bloomRenderPass);\r
+ }\r
+ } else if (postProcess.startsWith("sketch")) {\r
+ SketchRenderPass sketchRenderPass = new SketchRenderPass(cam, 4);\r
+ if (sketchRenderPass.isSupported()) {\r
+ sketchRenderPass.add(rootNode);\r
+ pManager.add(sketchRenderPass);\r
+ }\r
+ }\r
+\r
+ \r
+ RenderPass fpsPass = new RenderPass();\r
+ fpsPass.add(orthoNode);\r
+ pManager.add(fpsPass);\r
+ }\r
+ \r
+ public void render() {\r
+ displaySystem.setCurrent();\r
+ /** Recalculate the framerate. */\r
+ timer.update();\r
+ \r
+ /** Update tpf to time per frame according to the Timer. */\r
+ float tpf = timer.getTimePerFrame();\r
+ /** Send the fps to our fps bar at the bottom. */\r
+ fps.print("FPS: " + (int) timer.getFrameRate() + " - "\r
+ + displaySystem.getRenderer().getStatistics());\r
+ /**\r
+ * Update the physics for this world.\r
+ */\r
+ debug.print(debugText);\r
+\r
+ /** Update controllers/render states/transforms/bounds for rootNode. */\r
+ rootNode.updateGeometricState(tpf, true);\r
+ rootNode.updateRenderState();\r
+ \r
+ orthoNode.updateGeometricState(tpf, true);\r
+ orthoNode.updateRenderState();\r
+ \r
+ displaySystem.getRenderer().clearStatistics();\r
+ /** Clears the previously rendered information. */\r
+ displaySystem.getRenderer().clearBuffers();\r
+\r
+ pManager.updatePasses(tpf);\r
+ \r
+ pManager.renderPasses(displaySystem.getRenderer());\r
+ if ( showBounds ) {\r
+ Debugger.drawBounds( shadowRootNode, displaySystem.getRenderer(), true );\r
+ }\r
+\r
+ if ( showNormals ) {\r
+ Debugger.drawNormals( shadowRootNode, displaySystem.getRenderer());\r
+ }\r
+ displaySystem.getRenderer().displayBackBuffer();\r
+ \r
+ \r
+ \r
+ //swap buffers\r
+ ((SWTRenderer)displaySystem.getRenderer()).swap();\r
+ }\r
+ \r
+ @Override\r
+ public void resize(int width, int height) {\r
+ updateProjection();\r
+ }\r
+ \r
+ @Override\r
+ public Node getShadowRoot() {\r
+ return shadowRootNode;\r
+ }\r
+ \r
+ @Override\r
+ public Node getNoCastRoot() {\r
+ return noCastShadowRootNode;\r
+ }\r
+ \r
+ @Override\r
+ public Node getRoot() {\r
+ return rootNode;\r
+ }\r
+ \r
+ @Override\r
+ public Node getOrthoNode() {\r
+ return orthoNode;\r
+ }\r
+ \r
+ @Override\r
+ public Node getNoShadowRoot() {\r
+ return noShadowRootNode;\r
+ }\r
+ \r
+// public void setRootNode(Node node) {\r
+// rootNode = node;\r
+// initRoot();\r
+// }\r
+ \r
+ @Override\r
+ public int getProjectionPolicy() {\r
+ return projectionPolicy;\r
+ }\r
+ \r
+ @Override\r
+ public void setProjectionPolicy(int policy) {\r
+ if (policy != projectionPolicy) {\r
+ projectionPolicy = policy;\r
+ updateProjection();\r
+ }\r
+ }\r
+ \r
+ private void updateProjection() {\r
+ switch (projectionPolicy) {\r
+ case PERSPECTIVE_PROJECTION:\r
+ cam.setParallelProjection(false);\r
+ cam.setFrustumPerspective(fov,\r
+ (float) displaySystem.getRenderer().getWidth() /\r
+ (float) displaySystem.getRenderer().getHeight(),near, far);\r
+ break;\r
+ \r
+ case PARALLEL_PROJECTION:\r
+ cam.setParallelProjection(true);\r
+ break;\r
+ }\r
+ cam.update();\r
+ projectionUpdated = true;\r
+ }\r
+ \r
+ @Override\r
+ public float getScreenScale() {\r
+ //System.out.println(cam.getFrustumLeft() + " " + cam.getFrustumRight() + " " + cam.getFrustumBottom() + " " + cam.getFrustumTop()+ " " + cam.getFrustumNear() + " " + cam.getFrustumFar());\r
+ return Math.abs(cam.getFrustumTop());\r
+ }\r
+ \r
+ @Override\r
+ public void setScreenScale(float screenScale) {\r
+ float aspect = (float) displaySystem.getRenderer().getWidth() /\r
+ (float) displaySystem.getRenderer().getHeight();\r
+ cam.setFrustum(-screenScale*8.f, cam.getFrustumFar(), -screenScale*aspect, screenScale*aspect, -screenScale, screenScale);\r
+ }\r
+ \r
+ @Override\r
+ public float getFieldOfView() {\r
+ return fov;\r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ pManager.cleanUp();\r
+ rootNode.dispose();\r
+ rootNode = null;\r
+ noShadowRootNode = null;\r
+ noCastShadowRootNode = null;\r
+ orthoNode = null;\r
+ shadowRootNode = null;\r
+ }\r
+ \r
+ @Override\r
+ public boolean update() {\r
+ if (!projectionUpdated) {\r
+ return false;\r
+ }\r
+ projectionUpdated = false;\r
+ return true;\r
+ }\r
+ \r
+ @Override\r
+ public Camera getCamera() {\r
+ return cam;\r
+ }\r
+ \r
+ @Override\r
+ public DisplaySystem getDisplaySystem() {\r
+ return displaySystem;\r
+ }\r
+ \r
+ public void setDebugText(String text) {\r
+ this.debugText = text;\r
+ //System.out.println("JmeSinglePass.setDebugText() " + text);\r
+ }\r
+ \r
+ public void setShowNormals(boolean b) {\r
+ showNormals = b;\r
+ }\r
+ \r
+ public void setShowBounds(boolean b) {\r
+ showBounds = b;\r
+ }\r
+ \r
+ public void setShowWireframe(boolean b) {\r
+ ws.setEnabled(b);\r
+ }\r
+ \r
+ public boolean isShowNormals() {\r
+ return showNormals;\r
+ }\r
+ \r
+ public boolean isShowBounds() {\r
+ return showBounds;\r
+ }\r
+ \r
+ public boolean isShowWireframe() {\r
+ return ws.isEnabled();\r
+ }\r
+ \r
+ \r
+}\r