1 /*******************************************************************************
\r
2 * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
\r
3 * All rights reserved. This program and the accompanying materials
\r
4 * are made available under the terms of the Eclipse Public License v1.0
\r
5 * which accompanies this distribution, and is available at
\r
6 * http://www.eclipse.org/legal/epl-v10.html
\r
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
11 package org.simantics.proconf.g3d.common;
\r
13 import java.net.URL;
\r
15 import org.eclipse.core.runtime.FileLocator;
\r
16 import org.eclipse.core.runtime.Path;
\r
17 import org.simantics.proconf.g3d.Activator;
\r
18 import org.simantics.proconf.g3d.base.JmeRenderingComponent;
\r
19 import org.simantics.proconf.g3d.preferences.PreferenceConstants;
\r
21 import com.jme.image.Texture;
\r
22 import com.jme.light.DirectionalLight;
\r
23 import com.jme.math.Vector3f;
\r
24 import com.jme.renderer.Camera;
\r
25 import com.jme.renderer.ColorRGBA;
\r
26 import com.jme.renderer.pass.BasicPassManager;
\r
27 import com.jme.renderer.pass.RenderPass;
\r
28 import com.jme.renderer.pass.ShadowedRenderPass;
\r
29 import com.jme.renderer.swt.SWTRenderer;
\r
30 import com.jme.scene.Node;
\r
31 import com.jme.scene.Spatial;
\r
32 import com.jme.scene.Text;
\r
33 import com.jme.scene.state.AlphaState;
\r
34 import com.jme.scene.state.LightState;
\r
35 import com.jme.scene.state.TextureState;
\r
36 import com.jme.scene.state.WireframeState;
\r
37 import com.jme.scene.state.ZBufferState;
\r
38 import com.jme.system.DisplaySystem;
\r
39 import com.jme.util.TextureManager;
\r
40 import com.jme.util.Timer;
\r
41 import com.jme.util.geom.Debugger;
\r
42 import com.jmex.effects.glsl.BloomRenderPass;
\r
43 import com.jmex.effects.glsl.SketchRenderPass;
\r
46 public class JmeSinglePassRenderingComponent extends JmeRenderingComponent {
\r
47 protected DisplaySystem displaySystem;
\r
48 protected Timer timer;
\r
49 protected Node rootNode = new Node("Root");
\r
50 protected Node shadowRootNode = new Node("Shadow");
\r
51 protected Node noCastShadowRootNode = new Node("No Cast Shadow");
\r
52 protected Node noShadowRootNode = new Node("No Shadow");
\r
53 protected Camera cam;
\r
54 protected float near = .1f;
\r
55 protected float far = 3000f;
\r
56 protected float fov = 55f;
\r
58 protected int projectionPolicy;
\r
60 /** The root node of our text. */
\r
61 protected Node orthoNode = new Node("ortho");
\r
63 /** Displays all the lovely information at the bottom. */
\r
65 protected Text debug;
\r
66 protected String debugText = "";
\r
67 public static String fontLocation = "data/defaultfont.tga";//AppProperties.PATH_DEFAULT_FONT;
\r
70 protected BasicPassManager pManager = new BasicPassManager();
\r
72 private boolean showBounds = false;
\r
73 private boolean showNormals = false;
\r
74 private WireframeState ws = null;
\r
76 private boolean projectionUpdated = false;
\r
78 public JmeSinglePassRenderingComponent() {
\r
82 public void init(DisplaySystem displaySystem) {
\r
83 this.displaySystem = displaySystem;
\r
84 cam = displaySystem.getRenderer().createCamera(
\r
85 displaySystem.getRenderer().getWidth(), displaySystem.getRenderer().getHeight());
\r
86 displaySystem.getRenderer().setBackgroundColor(new ColorRGBA(0.2f,0.2f,0.2f,0.f));//(0.357F, 0.647F, 0.890F, 1.0F));
\r
87 displaySystem.getRenderer().getQueue().setTwoPassTransparency(true);
\r
88 cam.setFrustumPerspective(fov,
\r
89 (float) displaySystem.getRenderer().getWidth()/
\r
90 (float) displaySystem.getRenderer().getHeight(),near, far);
\r
91 projectionPolicy = PERSPECTIVE_PROJECTION;
\r
92 Vector3f loc = new Vector3f(0.0f, 0.0f, 10.0f);
\r
93 Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f);
\r
94 Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
\r
95 Vector3f dir = new Vector3f(0.0f, 0f, -1.0f);
\r
96 /** Move our camera to a correct place and orientation. */
\r
97 cam.setFrame(loc, left, up, dir);
\r
98 /** Signal that we've changed our camera's location/frustum. */
\r
100 displaySystem.getRenderer().setCamera(cam);
\r
101 timer = Timer.getTimer();
\r
102 displaySystem.setTitle("ShapeEditor");
\r
103 displaySystem.getRenderer().enableStatistics(true);
\r
108 protected Texture loadFontTexture() {
\r
109 URL url = FileLocator.find(org.simantics.proconf.g3d.Activator.getDefault().getBundle(),new Path(fontLocation),null);
\r
110 return TextureManager.loadTexture(url, Texture.MM_LINEAR,
\r
111 Texture.FM_LINEAR);
\r
114 protected void initRoot() {
\r
115 ZBufferState buf = displaySystem.getRenderer().createZBufferState();
\r
116 buf.setEnabled(true);
\r
117 buf.setFunction(ZBufferState.CF_LEQUAL);
\r
118 //buf.setWritable(false);
\r
119 rootNode.setRenderState(buf);
\r
120 rootNode.attachChild(noShadowRootNode);
\r
121 rootNode.attachChild(noCastShadowRootNode);
\r
122 rootNode.attachChild(shadowRootNode);
\r
123 noShadowRootNode.setCullMode(Spatial.CULL_NEVER);
\r
125 //PointLight light = new PointLight();
\r
126 DirectionalLight light = new DirectionalLight();
\r
127 light.setDiffuse( new ColorRGBA( 0.75f, 0.75f, 0.75f, 0.75f ) );
\r
128 light.setAmbient( new ColorRGBA( 0.5f, 0.5f, 0.5f, 0.5f ) );
\r
129 //light.setLocation( new Vector3f( 100, 100, 100 ) );
\r
130 light.setDirection(new Vector3f( -100, -150, -100 ));
\r
131 light.setEnabled( true );
\r
132 light.setShadowCaster(true);
\r
134 LightState lightState = displaySystem.getRenderer().createLightState();
\r
135 lightState.setEnabled( true );
\r
136 lightState.attach( light );
\r
137 lightState.setSeparateSpecular(true);
\r
138 lightState.setTwoSidedLighting(false);
\r
139 rootNode.setRenderState( lightState );
\r
141 ws = displaySystem.getRenderer().createWireframeState();
\r
142 ws.setEnabled(false);
\r
143 rootNode.setRenderState(ws);
\r
145 AlphaState as1 = displaySystem.getRenderer().createAlphaState();
\r
146 as1.setBlendEnabled(true);
\r
147 as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);
\r
148 as1.setDstFunction(AlphaState.DB_ONE);
\r
149 as1.setTestEnabled(true);
\r
150 as1.setTestFunction(AlphaState.TF_GREATER);
\r
151 as1.setEnabled(true);
\r
153 TextureState font = displaySystem.getRenderer().createTextureState();
\r
154 /** The texture is loaded from fontLocation */
\r
155 font.setTexture(loadFontTexture());
\r
157 font.setEnabled(true);
\r
159 // Then our font Text object.
\r
160 /** This is what will actually have the text at the bottom. */
\r
161 fps = new Text("FPS label", "");
\r
162 fps.setCullMode(Spatial.CULL_NEVER);
\r
163 fps.setTextureCombineMode(TextureState.REPLACE);
\r
165 debug = new Text("Debug", "Debug");
\r
166 debug.setCullMode(Spatial.CULL_NEVER);
\r
167 debug.setTextureCombineMode(TextureState.REPLACE);
\r
168 debug.setLocalTranslation(new Vector3f(1.f,10.f,0.f));
\r
170 // Finally, a stand alone node (not attached to root on purpose)
\r
171 Node fpsNode = new Node("FPS node");
\r
172 fpsNode.attachChild(fps);
\r
173 fpsNode.attachChild(debug);
\r
174 fpsNode.setRenderState(font);
\r
175 fpsNode.setRenderState(as1);
\r
176 fpsNode.setCullMode(Spatial.CULL_NEVER);
\r
177 orthoNode.attachChild(fpsNode);
\r
179 rootNode.updateGeometricState(0.0f, true);
\r
180 rootNode.updateRenderState();
\r
182 orthoNode.updateGeometricState(0.0f, true);
\r
183 orthoNode.updateRenderState();
\r
184 if (Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.SHADOWS)) {
\r
185 ShadowedRenderPass shadowRootPass = new ShadowedRenderPass();
\r
186 shadowRootPass.add(shadowRootNode);
\r
187 shadowRootPass.add(noCastShadowRootNode);
\r
188 shadowRootPass.addOccluder(shadowRootNode);
\r
189 pManager.add(shadowRootPass);
\r
190 //rootPass.setRenderShadows(false);
\r
191 shadowRootPass.setShadowColor(new ColorRGBA(0.1f,0.1f,0.1f,0.9f));
\r
192 shadowRootPass.setLightingMethod(ShadowedRenderPass.MODULATIVE);
\r
193 RenderPass rootPass = new RenderPass();
\r
194 rootPass.add(noShadowRootNode);
\r
195 pManager.add(rootPass);
\r
197 RenderPass rootPass = new RenderPass();
\r
198 rootPass.add(rootNode);
\r
199 pManager.add(rootPass);
\r
202 String postProcess = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.POST_PROCESS);
\r
203 if (postProcess.startsWith("bloom")) {
\r
204 BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4);
\r
205 if (bloomRenderPass.isSupported()) {
\r
206 bloomRenderPass.add(rootNode);
\r
207 bloomRenderPass.setUseCurrentScene(false);
\r
208 pManager.add(bloomRenderPass);
\r
210 } else if (postProcess.startsWith("sketch")) {
\r
211 SketchRenderPass sketchRenderPass = new SketchRenderPass(cam, 4);
\r
212 if (sketchRenderPass.isSupported()) {
\r
213 sketchRenderPass.add(rootNode);
\r
214 pManager.add(sketchRenderPass);
\r
219 RenderPass fpsPass = new RenderPass();
\r
220 fpsPass.add(orthoNode);
\r
221 pManager.add(fpsPass);
\r
224 public void render() {
\r
225 displaySystem.setCurrent();
\r
226 /** Recalculate the framerate. */
\r
229 /** Update tpf to time per frame according to the Timer. */
\r
230 float tpf = timer.getTimePerFrame();
\r
231 /** Send the fps to our fps bar at the bottom. */
\r
232 fps.print("FPS: " + (int) timer.getFrameRate() + " - "
\r
233 + displaySystem.getRenderer().getStatistics());
\r
235 * Update the physics for this world.
\r
237 debug.print(debugText);
\r
239 /** Update controllers/render states/transforms/bounds for rootNode. */
\r
240 rootNode.updateGeometricState(tpf, true);
\r
241 rootNode.updateRenderState();
\r
243 orthoNode.updateGeometricState(tpf, true);
\r
244 orthoNode.updateRenderState();
\r
246 displaySystem.getRenderer().clearStatistics();
\r
247 /** Clears the previously rendered information. */
\r
248 displaySystem.getRenderer().clearBuffers();
\r
250 pManager.updatePasses(tpf);
\r
252 pManager.renderPasses(displaySystem.getRenderer());
\r
253 if ( showBounds ) {
\r
254 Debugger.drawBounds( shadowRootNode, displaySystem.getRenderer(), true );
\r
257 if ( showNormals ) {
\r
258 Debugger.drawNormals( shadowRootNode, displaySystem.getRenderer());
\r
260 displaySystem.getRenderer().displayBackBuffer();
\r
265 ((SWTRenderer)displaySystem.getRenderer()).swap();
\r
269 public void resize(int width, int height) {
\r
270 updateProjection();
\r
274 public Node getShadowRoot() {
\r
275 return shadowRootNode;
\r
279 public Node getNoCastRoot() {
\r
280 return noCastShadowRootNode;
\r
284 public Node getRoot() {
\r
289 public Node getOrthoNode() {
\r
294 public Node getNoShadowRoot() {
\r
295 return noShadowRootNode;
\r
298 // public void setRootNode(Node node) {
\r
299 // rootNode = node;
\r
304 public int getProjectionPolicy() {
\r
305 return projectionPolicy;
\r
309 public void setProjectionPolicy(int policy) {
\r
310 if (policy != projectionPolicy) {
\r
311 projectionPolicy = policy;
\r
312 updateProjection();
\r
316 private void updateProjection() {
\r
317 switch (projectionPolicy) {
\r
318 case PERSPECTIVE_PROJECTION:
\r
319 cam.setParallelProjection(false);
\r
320 cam.setFrustumPerspective(fov,
\r
321 (float) displaySystem.getRenderer().getWidth() /
\r
322 (float) displaySystem.getRenderer().getHeight(),near, far);
\r
325 case PARALLEL_PROJECTION:
\r
326 cam.setParallelProjection(true);
\r
330 projectionUpdated = true;
\r
334 public float getScreenScale() {
\r
335 //System.out.println(cam.getFrustumLeft() + " " + cam.getFrustumRight() + " " + cam.getFrustumBottom() + " " + cam.getFrustumTop()+ " " + cam.getFrustumNear() + " " + cam.getFrustumFar());
\r
336 return Math.abs(cam.getFrustumTop());
\r
340 public void setScreenScale(float screenScale) {
\r
341 float aspect = (float) displaySystem.getRenderer().getWidth() /
\r
342 (float) displaySystem.getRenderer().getHeight();
\r
343 cam.setFrustum(-screenScale*8.f, cam.getFrustumFar(), -screenScale*aspect, screenScale*aspect, -screenScale, screenScale);
\r
347 public float getFieldOfView() {
\r
352 public void dispose() {
\r
353 pManager.cleanUp();
\r
354 rootNode.dispose();
\r
356 noShadowRootNode = null;
\r
357 noCastShadowRootNode = null;
\r
359 shadowRootNode = null;
\r
363 public boolean update() {
\r
364 if (!projectionUpdated) {
\r
367 projectionUpdated = false;
\r
372 public Camera getCamera() {
\r
377 public DisplaySystem getDisplaySystem() {
\r
378 return displaySystem;
\r
381 public void setDebugText(String text) {
\r
382 this.debugText = text;
\r
383 //System.out.println("JmeSinglePass.setDebugText() " + text);
\r
386 public void setShowNormals(boolean b) {
\r
390 public void setShowBounds(boolean b) {
\r
394 public void setShowWireframe(boolean b) {
\r
398 public boolean isShowNormals() {
\r
399 return showNormals;
\r
402 public boolean isShowBounds() {
\r
406 public boolean isShowWireframe() {
\r
407 return ws.isEnabled();
\r