]> gerrit.simantics Code Review - simantics/3d.git/blob - dev/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java
Release
[simantics/3d.git] / dev / org.simantics.proconf.g3d / src / org / simantics / proconf / g3d / common / JmeSinglePassRenderingComponent.java
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
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package org.simantics.proconf.g3d.common;\r
12 \r
13 import java.net.URL;\r
14 \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
20 \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
44 \r
45 \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
57     \r
58         protected int projectionPolicy;\r
59     \r
60     /** The root node of our text. */\r
61         protected Node orthoNode = new Node("ortho");\r
62 \r
63     /** Displays all the lovely information at the bottom. */\r
64     protected Text fps;\r
65     protected Text debug;\r
66     protected String debugText  = "";\r
67     public static String fontLocation = "data/defaultfont.tga";//AppProperties.PATH_DEFAULT_FONT;\r
68     \r
69     \r
70     protected BasicPassManager pManager = new BasicPassManager();\r
71     \r
72     private boolean showBounds = false;\r
73     private boolean showNormals = false;\r
74     private WireframeState ws = null;\r
75     \r
76     private boolean projectionUpdated = false;\r
77     \r
78         public JmeSinglePassRenderingComponent() {\r
79                 \r
80         }\r
81         \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
99         cam.update();\r
100         displaySystem.getRenderer().setCamera(cam);\r
101         timer = Timer.getTimer();\r
102         displaySystem.setTitle("ShapeEditor");\r
103         displaySystem.getRenderer().enableStatistics(true);\r
104         \r
105         initRoot();\r
106         }\r
107         \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
112         }\r
113         \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
124         \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
133         \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
140         \r
141         ws = displaySystem.getRenderer().createWireframeState();\r
142         ws.setEnabled(false);\r
143         rootNode.setRenderState(ws);\r
144         \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
152         \r
153         TextureState font = displaySystem.getRenderer().createTextureState();\r
154         /** The texture is loaded from fontLocation */\r
155         font.setTexture(loadFontTexture());\r
156 \r
157         font.setEnabled(true);\r
158 \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
164         \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
169 \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
178         \r
179         rootNode.updateGeometricState(0.0f, true);\r
180         rootNode.updateRenderState();\r
181         \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
196         } else {\r
197                 RenderPass rootPass = new RenderPass();\r
198                 rootPass.add(rootNode);\r
199                 pManager.add(rootPass);\r
200         }\r
201                 \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
209                         }\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
215                         }\r
216                 }\r
217 \r
218                 \r
219                 RenderPass fpsPass = new RenderPass();\r
220                 fpsPass.add(orthoNode);\r
221                 pManager.add(fpsPass);\r
222         }\r
223         \r
224         public void render() {\r
225                 displaySystem.setCurrent();\r
226                  /** Recalculate the framerate. */\r
227         timer.update();\r
228         \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
234         /**\r
235          * Update the physics for this world.\r
236          */\r
237         debug.print(debugText);\r
238 \r
239         /** Update controllers/render states/transforms/bounds for rootNode. */\r
240         rootNode.updateGeometricState(tpf, true);\r
241         rootNode.updateRenderState();\r
242        \r
243         orthoNode.updateGeometricState(tpf, true);\r
244         orthoNode.updateRenderState();\r
245         \r
246         displaySystem.getRenderer().clearStatistics();\r
247         /** Clears the previously rendered information. */\r
248         displaySystem.getRenderer().clearBuffers();\r
249 \r
250         pManager.updatePasses(tpf);\r
251         \r
252         pManager.renderPasses(displaySystem.getRenderer());\r
253         if ( showBounds ) {\r
254             Debugger.drawBounds( shadowRootNode, displaySystem.getRenderer(), true );\r
255         }\r
256 \r
257         if ( showNormals ) {\r
258             Debugger.drawNormals( shadowRootNode, displaySystem.getRenderer());\r
259         }\r
260         displaySystem.getRenderer().displayBackBuffer();\r
261         \r
262         \r
263         \r
264         //swap buffers\r
265         ((SWTRenderer)displaySystem.getRenderer()).swap();\r
266         }\r
267         \r
268         @Override\r
269         public void resize(int width, int height) {\r
270                 updateProjection();\r
271         }\r
272         \r
273         @Override\r
274         public Node getShadowRoot() {\r
275                 return shadowRootNode;\r
276         }\r
277         \r
278         @Override\r
279         public Node getNoCastRoot() {\r
280                 return noCastShadowRootNode;\r
281         }\r
282         \r
283         @Override\r
284         public Node getRoot() {\r
285                 return rootNode;\r
286         }\r
287         \r
288         @Override\r
289         public Node getOrthoNode() {\r
290                 return orthoNode;\r
291         }\r
292         \r
293         @Override\r
294         public Node getNoShadowRoot() {\r
295                 return noShadowRootNode;\r
296         }\r
297         \r
298 //      public void setRootNode(Node node) {\r
299 //              rootNode = node;\r
300 //              initRoot();\r
301 //      }\r
302         \r
303         @Override\r
304         public int getProjectionPolicy() {\r
305                 return projectionPolicy;\r
306         }\r
307         \r
308         @Override\r
309         public void setProjectionPolicy(int policy) {\r
310                 if (policy != projectionPolicy) {\r
311                         projectionPolicy = policy;\r
312                         updateProjection();\r
313                 }\r
314         }\r
315         \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
323                         break;\r
324                         \r
325                 case PARALLEL_PROJECTION:\r
326                         cam.setParallelProjection(true);\r
327                         break;\r
328                 }\r
329                 cam.update();\r
330                 projectionUpdated = true;\r
331         }\r
332         \r
333         @Override\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
337         }\r
338         \r
339         @Override\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
344         }\r
345         \r
346         @Override\r
347         public float getFieldOfView() {\r
348                 return fov;\r
349         }\r
350         \r
351         @Override\r
352         public void dispose() {\r
353                 pManager.cleanUp();\r
354                 rootNode.dispose();\r
355                 rootNode = null;\r
356                 noShadowRootNode = null;\r
357                 noCastShadowRootNode = null;\r
358                 orthoNode = null;\r
359                 shadowRootNode = null;\r
360         }\r
361         \r
362         @Override\r
363         public boolean update() {\r
364                 if (!projectionUpdated) {\r
365                         return false;\r
366                 }\r
367                 projectionUpdated = false;\r
368                 return true;\r
369         }\r
370         \r
371         @Override\r
372         public Camera getCamera() {\r
373                 return cam;\r
374         }\r
375         \r
376         @Override\r
377         public DisplaySystem getDisplaySystem() {\r
378                 return displaySystem;\r
379         }\r
380         \r
381         public void setDebugText(String text) {\r
382                 this.debugText = text;\r
383                 //System.out.println("JmeSinglePass.setDebugText() " + text);\r
384         }\r
385         \r
386         public void setShowNormals(boolean b) {\r
387                 showNormals = b;\r
388         }\r
389         \r
390         public void setShowBounds(boolean b) {\r
391                 showBounds = b;\r
392         }\r
393         \r
394         public void setShowWireframe(boolean b) {\r
395                 ws.setEnabled(b);\r
396         }\r
397         \r
398         public boolean isShowNormals() {\r
399                 return showNormals;\r
400         }\r
401         \r
402         public boolean isShowBounds() {\r
403                 return showBounds;\r
404         }\r
405         \r
406         public boolean isShowWireframe() {\r
407                 return ws.isEnabled();\r
408         }\r
409         \r
410         \r
411 }\r