From: luukkainen Date: Mon, 29 Sep 2008 11:10:35 +0000 (+0000) Subject: latest release (0.41), third attempt X-Git-Tag: simantics-1.19.0~25 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=ef97fbd29eb1b561ef7fa5a3bf581618abfaa2b2;p=simantics%2F3d.git latest release (0.41), third attempt git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@6847 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.proconf.g3d/.classpath b/org.simantics.proconf.g3d/.classpath new file mode 100644 index 00000000..2e6482e2 --- /dev/null +++ b/org.simantics.proconf.g3d/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.proconf.g3d/.project b/org.simantics.proconf.g3d/.project new file mode 100644 index 00000000..a27da2fb --- /dev/null +++ b/org.simantics.proconf.g3d/.project @@ -0,0 +1,28 @@ + + + org.simantics.proconf.g3d + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.proconf.g3d/META-INF/MANIFEST.MF b/org.simantics.proconf.g3d/META-INF/MANIFEST.MF new file mode 100644 index 00000000..ae81bc87 --- /dev/null +++ b/org.simantics.proconf.g3d/META-INF/MANIFEST.MF @@ -0,0 +1,43 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: G3D Plug-in +Bundle-SymbolicName: org.simantics.proconf.g3d;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.simantics.proconf.g3d.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.simantics.g2d.stubs, + javax.vecmath, + com.jme.eclipse, + org.simantics.proconf.image, + org.eclipse.ui.views, + org.simantics.db, + org.simantics.layer0.stubs, + org.simantics.layer0.utils, + org.simantics.image.stubs, + org.simantics.utils, + org.simantics.utils.datastructures, + org.simantics.utils.ui, + org.simantics.proconf.ui, + org.simantics.equation, + org.simantics.proconf.browsing, + org.eclipse.ui.forms, + org.eclipse.core.expressions, + org.simantics.animation +Eclipse-LazyStart: true +Export-Package: org.simantics.proconf.g3d.actions, + org.simantics.proconf.g3d.animation, + org.simantics.proconf.g3d.animation.ui, + org.simantics.proconf.g3d.base, + org.simantics.proconf.g3d.common, + org.simantics.proconf.g3d.dialogs, + org.simantics.proconf.g3d.dnd, + org.simantics.proconf.g3d.gizmo, + org.simantics.proconf.g3d.input, + org.simantics.proconf.g3d.preferences, + org.simantics.proconf.g3d.scenegraph, + org.simantics.proconf.g3d.shapes, + org.simantics.proconf.g3d.stubs, + org.simantics.proconf.g3d.tools, + org.simantics.proconf.g3d.views diff --git a/org.simantics.proconf.g3d/build.properties b/org.simantics.proconf.g3d/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.proconf.g3d/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.proconf.g3d/data/defaultfont.tga b/org.simantics.proconf.g3d/data/defaultfont.tga new file mode 100644 index 00000000..e215541c Binary files /dev/null and b/org.simantics.proconf.g3d/data/defaultfont.tga differ diff --git a/org.simantics.proconf.g3d/icons/batch.png b/org.simantics.proconf.g3d/icons/batch.png new file mode 100644 index 00000000..424fd1b6 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/batch.png differ diff --git a/org.simantics.proconf.g3d/icons/batch.svg b/org.simantics.proconf.g3d/icons/batch.svg new file mode 100644 index 00000000..23ba494d --- /dev/null +++ b/org.simantics.proconf.g3d/icons/batch.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + B + + diff --git a/org.simantics.proconf.g3d/icons/delete.png b/org.simantics.proconf.g3d/icons/delete.png new file mode 100644 index 00000000..31f061a0 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/delete.png differ diff --git a/org.simantics.proconf.g3d/icons/delete.svg b/org.simantics.proconf.g3d/icons/delete.svg new file mode 100644 index 00000000..888616fa --- /dev/null +++ b/org.simantics.proconf.g3d/icons/delete.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/eye.png b/org.simantics.proconf.g3d/icons/eye.png new file mode 100644 index 00000000..0e78cfd6 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/eye.png differ diff --git a/org.simantics.proconf.g3d/icons/eye.svg b/org.simantics.proconf.g3d/icons/eye.svg new file mode 100644 index 00000000..cfb5620e --- /dev/null +++ b/org.simantics.proconf.g3d/icons/eye.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/ff.png b/org.simantics.proconf.g3d/icons/ff.png new file mode 100644 index 00000000..9fb120a6 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/ff.png differ diff --git a/org.simantics.proconf.g3d/icons/ff.svg b/org.simantics.proconf.g3d/icons/ff.svg new file mode 100644 index 00000000..5d9ddc9c --- /dev/null +++ b/org.simantics.proconf.g3d/icons/ff.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/geometry.png b/org.simantics.proconf.g3d/icons/geometry.png new file mode 100644 index 00000000..b06b5534 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/geometry.png differ diff --git a/org.simantics.proconf.g3d/icons/geometry.svg b/org.simantics.proconf.g3d/icons/geometry.svg new file mode 100644 index 00000000..e0e8ab76 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/geometry.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + G + + diff --git a/org.simantics.proconf.g3d/icons/node.png b/org.simantics.proconf.g3d/icons/node.png new file mode 100644 index 00000000..a2cb4c46 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/node.png differ diff --git a/org.simantics.proconf.g3d/icons/node.svg b/org.simantics.proconf.g3d/icons/node.svg new file mode 100644 index 00000000..8fe1dd33 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/node.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + N + + diff --git a/org.simantics.proconf.g3d/icons/play.png b/org.simantics.proconf.g3d/icons/play.png new file mode 100644 index 00000000..10f00bbc Binary files /dev/null and b/org.simantics.proconf.g3d/icons/play.png differ diff --git a/org.simantics.proconf.g3d/icons/play.svg b/org.simantics.proconf.g3d/icons/play.svg new file mode 100644 index 00000000..dafc8200 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/play.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/rotate.png b/org.simantics.proconf.g3d/icons/rotate.png new file mode 100644 index 00000000..bcc829f0 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/rotate.png differ diff --git a/org.simantics.proconf.g3d/icons/rotate.svg b/org.simantics.proconf.g3d/icons/rotate.svg new file mode 100644 index 00000000..1b8d04bf --- /dev/null +++ b/org.simantics.proconf.g3d/icons/rotate.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/rw.png b/org.simantics.proconf.g3d/icons/rw.png new file mode 100644 index 00000000..ccc1ce6e Binary files /dev/null and b/org.simantics.proconf.g3d/icons/rw.png differ diff --git a/org.simantics.proconf.g3d/icons/rw.svg b/org.simantics.proconf.g3d/icons/rw.svg new file mode 100644 index 00000000..dc4aed23 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/rw.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/silk/control_eject.png b/org.simantics.proconf.g3d/icons/silk/control_eject.png new file mode 100644 index 00000000..924d817b Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_eject.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_eject_blue.png b/org.simantics.proconf.g3d/icons/silk/control_eject_blue.png new file mode 100644 index 00000000..2bd49638 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_eject_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_end.png b/org.simantics.proconf.g3d/icons/silk/control_end.png new file mode 100644 index 00000000..036e04dc Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_end.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_end_blue.png b/org.simantics.proconf.g3d/icons/silk/control_end_blue.png new file mode 100644 index 00000000..72079357 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_end_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_equalizer.png b/org.simantics.proconf.g3d/icons/silk/control_equalizer.png new file mode 100644 index 00000000..46060872 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_equalizer.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_equalizer_blue.png b/org.simantics.proconf.g3d/icons/silk/control_equalizer_blue.png new file mode 100644 index 00000000..1b2e6a37 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_equalizer_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_fastforward.png b/org.simantics.proconf.g3d/icons/silk/control_fastforward.png new file mode 100644 index 00000000..31f7fd3a Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_fastforward.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_fastforward_blue.png b/org.simantics.proconf.g3d/icons/silk/control_fastforward_blue.png new file mode 100644 index 00000000..4a2f9d4e Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_fastforward_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_pause.png b/org.simantics.proconf.g3d/icons/silk/control_pause.png new file mode 100644 index 00000000..2d9ce9c4 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_pause.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_pause_blue.png b/org.simantics.proconf.g3d/icons/silk/control_pause_blue.png new file mode 100644 index 00000000..ec61099b Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_pause_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_play.png b/org.simantics.proconf.g3d/icons/silk/control_play.png new file mode 100644 index 00000000..0846555d Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_play.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_play_blue.png b/org.simantics.proconf.g3d/icons/silk/control_play_blue.png new file mode 100644 index 00000000..f8c8ec68 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_play_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_repeat.png b/org.simantics.proconf.g3d/icons/silk/control_repeat.png new file mode 100644 index 00000000..1c4f57a1 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_repeat.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_repeat_blue.png b/org.simantics.proconf.g3d/icons/silk/control_repeat_blue.png new file mode 100644 index 00000000..406ec333 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_repeat_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_rewind.png b/org.simantics.proconf.g3d/icons/silk/control_rewind.png new file mode 100644 index 00000000..c0294477 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_rewind.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_rewind_blue.png b/org.simantics.proconf.g3d/icons/silk/control_rewind_blue.png new file mode 100644 index 00000000..15d1584b Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_rewind_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_start.png b/org.simantics.proconf.g3d/icons/silk/control_start.png new file mode 100644 index 00000000..7dd1c07f Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_start.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_start_blue.png b/org.simantics.proconf.g3d/icons/silk/control_start_blue.png new file mode 100644 index 00000000..6f11fcb0 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_start_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_stop.png b/org.simantics.proconf.g3d/icons/silk/control_stop.png new file mode 100644 index 00000000..893bb60e Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_stop.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/control_stop_blue.png b/org.simantics.proconf.g3d/icons/silk/control_stop_blue.png new file mode 100644 index 00000000..e6f75d23 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/control_stop_blue.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/lock.png b/org.simantics.proconf.g3d/icons/silk/lock.png new file mode 100644 index 00000000..2ebc4f6f Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/lock.png differ diff --git a/org.simantics.proconf.g3d/icons/silk/lock_open.png b/org.simantics.proconf.g3d/icons/silk/lock_open.png new file mode 100644 index 00000000..a471765f Binary files /dev/null and b/org.simantics.proconf.g3d/icons/silk/lock_open.png differ diff --git a/org.simantics.proconf.g3d/icons/stop.png b/org.simantics.proconf.g3d/icons/stop.png new file mode 100644 index 00000000..ef86eb54 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/stop.png differ diff --git a/org.simantics.proconf.g3d/icons/stop.svg b/org.simantics.proconf.g3d/icons/stop.svg new file mode 100644 index 00000000..58381c76 --- /dev/null +++ b/org.simantics.proconf.g3d/icons/stop.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/icons/translate.png b/org.simantics.proconf.g3d/icons/translate.png new file mode 100644 index 00000000..21f52847 Binary files /dev/null and b/org.simantics.proconf.g3d/icons/translate.png differ diff --git a/org.simantics.proconf.g3d/icons/translate.svg b/org.simantics.proconf.g3d/icons/translate.svg new file mode 100644 index 00000000..b600c2fd --- /dev/null +++ b/org.simantics.proconf.g3d/icons/translate.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/org.simantics.proconf.g3d/logging.properties b/org.simantics.proconf.g3d/logging.properties new file mode 100644 index 00000000..d8ec9e42 --- /dev/null +++ b/org.simantics.proconf.g3d/logging.properties @@ -0,0 +1,54 @@ +############################################################ +# Default Logging Configuration File +# +# You can use a different file by specifying a filename +# with the java.util.logging.config.file system property. +# For example java -Djava.util.logging.config.file=myfile +############################################################ + +############################################################ +# Global properties +############################################################ + +# "handlers" specifies a comma separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler, which will only +# show messages at the INFO and above levels. +handlers= java.util.logging.ConsoleHandler + +# To also add the FileHandler, use the following line instead. +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. For any given facility this global level +# can be overriden by a facility specific level +# Note that the ConsoleHandler also has a separate level +# setting to limit messages printed to the console. +.level= OFF + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +# default file output is in user's home directory. +java.util.logging.FileHandler.pattern = %h/java%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter + +# Limit the message that are printed on the console to INFO and above. +java.util.logging.ConsoleHandler.level = OFF +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + + +############################################################ +# Facility specific properties. +# Provides extra control for each logger. +############################################################ + +# For example, set the com.xyz.foo logger to only log SEVERE +# messages: +# com.xyz.foo.level = SEVERE diff --git a/org.simantics.proconf.g3d/plugin.xml b/org.simantics.proconf.g3d/plugin.xml new file mode 100644 index 00000000..fc55861e --- /dev/null +++ b/org.simantics.proconf.g3d/plugin.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d/schema/geometry.exsd b/org.simantics.proconf.g3d/schema/geometry.exsd new file mode 100644 index 00000000..f6af1286 --- /dev/null +++ b/org.simantics.proconf.g3d/schema/geometry.exsd @@ -0,0 +1,112 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + + + + + diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java new file mode 100644 index 00000000..38b8b6ff --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Activator.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.management.ISessionContextChangedListener; +import org.simantics.db.management.SessionContextChangedEvent; +import org.simantics.proconf.ui.ProConfUI; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.proconf.g3d"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + ProConfUI.getSessionContextProvider().addContextChangedListener(new ISessionContextChangedListener() { + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + ISessionContext ctx = event.getNewValue(); + if (ctx != null) { + ctx.getSession().asyncRead(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + Resources.initialize(g); + return GraphRequestStatus.transactionComplete(); + }; + }); + } else { + Resources.deinitialize(); + } + } + }); + try { + ProConfUI.getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Resources.initialize(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } catch (Exception e) { + + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java new file mode 100644 index 00000000..f0cacb41 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/Resources.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d; + +import org.simantics.db.Graph; +import org.simantics.equation.stubs.EquationResource; +import org.simantics.g2d.stubs.anim.AnimationResource; +import org.simantics.animation.curve.CurveBuilder; +import org.simantics.animation.curve.CurveBuilderImpl; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.stubs.G3DResource; + +public class Resources { + public static AnimationResource animationResource; + public static G3DResource g3dResource; + public static CurveBuilder curveBuilder; + public static EquationResource equationResource; + + public static void initialize(Graph g) { + animationResource = AnimationResource.getInstance(g); + g3dResource = G3DResource.getInstance(g); + curveBuilder = new CurveBuilderImpl(Resources.animationResource); + equationResource = EquationResource.getInstance(g); + G3DTools.initialize(); + } + + public static void deinitialize() { + animationResource = null; + g3dResource = null; + curveBuilder = null; + equationResource = null; + G3DTools.deinitialize(); + } + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java new file mode 100644 index 00000000..2f619046 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/CameraAction.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.OrbitalCamera; + + + +public class CameraAction extends InteractiveAction{ + + private JmeRenderingComponent component; + private OrbitalCamera camera; + + public CameraAction(ThreeDimensionalEditorBase parent) { + super(parent); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + } + + @Override + public void activate() { + + } + + @Override + public void deactivate() { + + } + + @Override + public boolean usable(Graph graph,List resources) { + return true; + } + + Vector3d prevIntersectPoint = new Vector3d(); + @Override + public void update() { + double scale = 1.0; + if (input.keyDown(KeyEvent.VK_CONTROL)) + scale = -1.0; + if (input.keyPressed(KeyEvent.VK_NUMPAD5)) { + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) + component.setProjectionPolicy(JmeRenderingComponent.PARALLEL_PROJECTION); + else + component.setProjectionPolicy(JmeRenderingComponent.PERSPECTIVE_PROJECTION); + parent.setViewChanged(true); + } + if (input.keyPressed(KeyEvent.VK_NUMPAD7)) { + camera.setCameraPosRelativeToTarget(new Vector3d(camera.getDistanceToTarget() * scale, 0, 0)); + parent.setViewChanged(true); + } + if (input.keyPressed(KeyEvent.VK_NUMPAD1)) { + camera.setCameraPosRelativeToTarget(new Vector3d(0, 0, camera.getDistanceToTarget() * scale)); + parent.setViewChanged(true); + } + if (input.keyPressed(KeyEvent.VK_NUMPAD9)) { + camera.setCameraPosRelativeToTarget(new Vector3d(0, camera.getDistanceToTarget() * scale, 0)); + parent.setViewChanged(true); + } + + if (input.mousePressed() && ((input.pressModifiers() & MouseEvent.BUTTON1_MASK) > 0)) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d point = new Vector3d(camera.getTarget()); + Vector3d normal = camera.getUnNormalizedHeading(); + normal.normalize(); + MathTools.intersectStraightPlane(o, d, point, normal, prevIntersectPoint); + } + if (!input.mouseDragged()) + return; + parent.setViewChanged(true); + Vector3d msTmp = new Vector3d(); + msTmp.x = (input.prevMouseX() - input.mouseX()) / 100f; + msTmp.y = (input.prevMouseY() - input.mouseY()) / 100f; + + if ((input.dragModifiers() & MouseEvent.BUTTON1_MASK) > 0) { + if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d point = new Vector3d(camera.getTarget()); + Vector3d normal = camera.getUnNormalizedHeading(); + normal.normalize(); + Vector3d intersectPoint = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, point, normal, intersectPoint)) { + Vector3d delta = new Vector3d(intersectPoint); + delta.sub(prevIntersectPoint); + prevIntersectPoint = intersectPoint; + delta.negate(); + camera.translate(delta); + prevIntersectPoint.add(delta); + } else { + camera.moveRight((float) msTmp.x); + camera.moveUp(-(float) msTmp.y); + } + } else { + camera.rotateRight((float) msTmp.x); + camera.rotateUp((float) msTmp.y); + } + } else if ((input.dragModifiers() & MouseEvent.BUTTON2_MASK) > 0) { + // System.out.println("zoom"); + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) { + camera.moveScaledToTarget((float) msTmp.y * 0.5f); + } else { + component.setScreenScale(component.getScreenScale() - (float) msTmp.y * 0.5f * component.getScreenScale()); + } + } +// } else { +// System.out.println("cameraAction!"); +// System.out.println(input); +// } + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java new file mode 100644 index 00000000..1cd0b595 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ConstrainedTransformAction.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.ConstraintDetector; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.OrbitalCamera; + + +public abstract class ConstrainedTransformAction extends WriteInteractiveAction { + private static final ImageDescriptor LOCK_ICON = Activator.imageDescriptorFromPlugin("org.simantic.proconf.g3d", "icons/silk/lock.png"); + private static final ImageDescriptor LOCK_OPEN_ICON = Activator.imageDescriptorFromPlugin("org.simantic.proconf.g3d", "icons/silk/lock_open.png"); + + protected JmeRenderingComponent component; + protected OrbitalCamera camera; + + protected boolean useConstraints = false; + protected ConstraintDetector detector; + + protected Action useConstraintsAction; + + //protected IToolBarManager manager; + + public ConstrainedTransformAction(ThreeDimensionalEditorBase editor) { + super(editor, true); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + detector = new ConstraintDetector(parent); + useConstraintsAction = new Action("Constraints", Action.AS_CHECK_BOX) { + public void run() { + useConstraints = this.isChecked(); + } + + public void setChecked(boolean b) { + super.setChecked(b); + if (b) { + setImageDescriptor(LOCK_ICON); + } else { + setImageDescriptor(LOCK_OPEN_ICON); + } + } + }; + useConstraintsAction.setImageDescriptor(LOCK_OPEN_ICON); + + } + + @Override + public void deactivate() { + detector.clearConstraintHighlights(); + } + + @Override + public void fillToolBar(IToolBarManager manager) { + //this.manager = manager; + useConstraintsAction.setChecked(useConstraints); + manager.add(useConstraintsAction); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java new file mode 100644 index 00000000..c86858d8 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextAction.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +/** + * Context / selection dependent action + * + * @author Marko Luukkainen + * + */ +public abstract class ContextAction extends Action { + protected ThreeDimensionalEditorBase parent; + + public ContextAction(ThreeDimensionalEditorBase parent) { + this.parent = parent; + init(); + } + + /** + * Initialization + */ + public void init(){}; + + /** + * Runs the action + */ + public abstract void run(); + + /** + * Used to check if action is usable for given resources + * @param resources + * @return + */ + public abstract boolean usable(Graph graph, List resources); + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java new file mode 100644 index 00000000..ce6638aa --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionFactory.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +public interface ContextActionFactory { + + + public ContextAction createAction(ThreeDimensionalEditorBase editor); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java new file mode 100644 index 00000000..bb8ffbce --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ContextActionRegistry.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.utils.ui.plugin.Extension; +import org.simantics.utils.ui.plugin.ExtensionLoader; + + + +public class ContextActionRegistry { + /* + private static ContextActionRegistry instance; + public final static String ELEMENT_NAME = "ContextAction"; + public final static String NAME_SPACE = "org.simantics.proconf.g3d"; + public final static String EP_NAME = "contextaction"; + + private ExtensionLoader loader; + + private ContextActionRegistry() { + loader = new ExtensionLoader(ELEMENT_NAME, NAME_SPACE, EP_NAME); + } + + public static ContextActionRegistry getInstance() { + if (instance==null) instance = new ContextActionRegistry(); + return instance; + } + + public Extension[] getExtensions() { + return loader.getExtensions(); + } + + + public static ContextActionFactory[] getActions(String editorID) { + List list = new ArrayList(); + for (Extension e : getInstance().getExtensions()) { + if(e.getStringField("editorid").compareTo(editorID) == 0) { + list.add(e.getInstance()); + } + } + return list.toArray(new ContextActionFactory[0]); + } + */ +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java new file mode 100644 index 00000000..7893f230 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/FocusAction.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.Collection; +import java.util.List; + +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.stubs.Tuple3; + +public class FocusAction extends ContextAction{ + + private OrbitalCamera camera; + + Vector3d focusPoint = null; + + public FocusAction(ThreeDimensionalEditorBase parent) { + super(parent); + camera = parent.getCamera(); + } + + public void init() { + this.setText("Focus"); + this.setToolTipText("Focus"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/eye.png")); + } + + + + @Override + public boolean usable(Graph graph,List resources) { + if (resources.size() != 1) + return false; + IEntity t = EntityFactory.create(graph, resources.get(0)); + + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasWorldPosition); + if (p == null || p.size() != 1) + return false; + else + //focusPoint = new Vector3d(G3DTools.getPoint(new Position(graph,p.iterator().next().getResource()))); + focusPoint = new Vector3d(G3DTools.getPoint(new Tuple3(graph,p.iterator().next().getResource()))); + } + return true; + } + + public void run() { + camera.setTarget(focusPoint); + parent.setViewChanged(true); + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java new file mode 100644 index 00000000..a7974345 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/InteractiveAction.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.input.InputProvider; + + + +/** + * Context / selection dependent action that requires user's interaction + * + * @author Marko Luukkainen + * + */ +public abstract class InteractiveAction extends ContextAction { + protected InputProvider input; + + public InteractiveAction(ThreeDimensionalEditorBase parent) { + super(parent); + input = parent.getInputProvider(); + } + + public abstract void update() ; + + /** + * Activates the action + */ + public abstract void activate(); + + /** + * Deactivates / ends the action + */ + public abstract void deactivate(); + + /** + * Activates the action in the viewer. Normally there's no need to override this method. + */ + public final void run() { + parent.setCurrentAction(this); + } + + /** + * This method is used to end the action, call this from update(). + * + */ + public void end() { + parent.setCurrentAction(parent.getDefaultAction()); + } + + public void fillToolBar(IToolBarManager manager) { + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java new file mode 100644 index 00000000..36fcc4bf --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadAction.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + +public abstract class ReadAction extends ContextAction { + boolean sync; + public ReadAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void run() { + Session session = parent.getSession(); + if(!canActivate()) { + return; + } + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + doChanges(g); + return GraphRequestStatus.transactionComplete(); + } + }; + if (sync) { + session.syncRead(r); + } else { + session.asyncRead(r); + } + } + + public abstract void doChanges(Graph graph) throws Exception; + + public boolean canActivate() { + return true; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java new file mode 100644 index 00000000..9bd972c6 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/ReadInteractiveAction.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + +public abstract class ReadInteractiveAction extends InteractiveAction { + boolean sync; + + public ReadInteractiveAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void update(){ + Session session = parent.getSession(); + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + doChanges(g); + return GraphRequestStatus.transactionComplete(); + } + }; + if (sync) { + session.syncRead(r); + } else { + session.asyncRead(r); + } + } + + + public abstract void doChanges(Graph graph) throws Exception; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java new file mode 100644 index 00000000..ac9bdfa4 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RemoveAction.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +public class RemoveAction extends WriteAction { + + public RemoveAction(ThreeDimensionalEditorBase parent) { + super(parent,false); + } + + public void init() { + setText("Remove"); + setToolTipText("Remove the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/delete.png")); + } + public GraphRequestStatus doChanges(Graph graph) { + StructuredResourceSelection sel = parent.getSelectionAdapter().getCurrentSelection(); + List res = sel.getSelectionList(); + for (Resource r : res) { + IEntity t = EntityFactory.create(graph, r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + IEntity parentNode = t.getSingleRelatedObject(Resources.g3dResource.HasParent); + parentNode.removeStatement(Resources.g3dResource.HasChild, t); + } + + } + return GraphRequestStatus.transactionComplete(); + + } + + @Override + public boolean usable(Graph graph,List resources) { + return resources.size() > 0; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java new file mode 100644 index 00000000..fe6fc71b --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java @@ -0,0 +1,453 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.gizmo.RotateGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +public class RotateAction extends WriteInteractiveAction { + + private JmeRenderingComponent component; + + private RotateGizmo gizmo; + + private OrbitalCamera camera; + + private Map rotations = new HashMap(); + + private int steps; + private double angles[]; + + private Action csAction; + private boolean worldCoord = true; + private IToolBarManager manager; + + private List mos; + AxisAngle4d aa; + Quat4d q; + + public RotateAction(ThreeDimensionalEditorBase parent) { + super(parent,true); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + gizmo = new RotateGizmo(component.getDisplaySystem().getRenderer()); + csAction = new Action("World",Action.AS_CHECK_BOX) { + public void run() { + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + setWorldCoord(g,!isChecked()); + return GraphRequestStatus.transactionComplete(); + } + }; + RotateAction.this.parent.getSession().asyncRead(r); + + } + }; + } + + public void init() { + this.setText("Rotate"); + this.setToolTipText("Rotate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/rotate.png")); + steps = 36; + angles = new double[steps+1]; + for (int i = 0; i < angles.length; i++) { + angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps); + } + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() == 0) + return false; + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasLocalOrientation); + if (p == null || p.size() != 1) + return false; + } + + } + return true; + + } + + @Override + public void deactivate() { + inputType = InputType.NONE; + parent.setGizmo(null); + mos = null; + + } + + public void fillToolBar(IToolBarManager manager) { + super.fillToolBar(manager); + this.manager = manager; + csAction.setChecked(!worldCoord); + manager.add(csAction); + + } + + private void setWorldCoord(Graph graph,boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + updateWorldCoord(graph); + } + + private void updateWorldCoord(Graph graph) { + if (worldCoord) { + csAction.setText("World"); + gizmo.setRotation(new AxisAngle4f()); + aa = null; + q = null; + } else { + csAction.setText("Local"); + aa = G3DTools.getOrientation(mos.get(0).getParent().getG3DNode(graph).getWorldOrientation()); + if (aa == null) + aa = new AxisAngle4d(); + gizmo.setRotation(new AxisAngle4f(aa)); + q = new Quat4d(); + q.set(aa); + } + if (manager != null) + manager.update(true); + this.parent.setViewChanged(true); + } + + @Override + public void activate() { + + Session session = parent.getSession(); + + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + parent.setGizmo(gizmo); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + updateGizmo(); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); + rotations = new HashMap(); + for (IGraphicsNode mo : mos) { + G3DNode n = mo.getG3DNode(g); + rotations.put(mo,G3DTools.getOrientation(n.getLocalOrientation())); + text += G3DTools.getOrientation(n.getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(g).getLocalOrientation())) + " "; + } + setInfoText(text); + parent.setViewChanged(true); + inputType = InputType.NONE; + return GraphRequestStatus.transactionComplete(); + } + }; + + session.syncRead(r); + + + } + + + private Vector3d getRotationAxis() { + switch (gizmo.getSelected()) { + case RotateGizmo.X: + return new Vector3d(1.0,0.0,0.0); + case RotateGizmo.Y: + return new Vector3d(0.0,1.0,0.0); + case RotateGizmo.Z: + return new Vector3d(0.0,0.0,1.0); + case RotateGizmo.XYZ: + Vector3d axis = camera.getUnNormalizedHeading(); + axis.normalize(); + return axis; + default: + return null; + } + } + private double prevS = 0.0; + + private Vector3d i = new Vector3d(); + private Vector3d j = new Vector3d(); + private double prevAngle = 0; + + enum InputType{INTERSECT,NONINTERSECT,KEY,NONE}; + InputType inputType; + private boolean useStep = false; + + @Override + public void doChanges(Graph graph) throws Exception { + + if (input.mousePressed()) { + Vector3d axis = getRotationAxis(); + if (axis != null) { + if (!worldCoord) { + MathTools.rotate(q, axis, axis); + } + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + if ((input.pressModifiers() & MouseEvent.CTRL_MASK) > 0) { + useStep = true; + } else { + useStep = false; + } + if (MathTools.intersectStraightPlane(o, d, p, axis, i2, s) && Math.abs(d.dot(axis)) > 0.2) + inputType = InputType.INTERSECT; + else + inputType = InputType.NONINTERSECT; + + + if (inputType == InputType.INTERSECT) { + // picking ray and plane defined by gizmo's center point and + // rotation axis can intersect + // vector from center point to intersection point + i2.sub(p); + // creating vectors i and j that are lying on the plane and + // are perpendicular + // vectors are used to calculate polar coordinate for + // intersection point + j.set(i2); + i.cross(j, axis); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + } else { + // picking ray and plane defined by gizmo's center point and + // rotation axis are parallel, + // so we'll use cross product of rotation axis and picking + // ray to detect amount of rotation + i.cross(d, axis); + MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s); + prevS = s[1]; + } + } + + + } + if (input.mouseClicked()) { + end(); + return; + } + Vector3d axis = null; + if (input.keyPressed(KeyEvent.VK_LEFT)) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,1.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_RIGHT)) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,-1.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_UP)) { + inputType = InputType.KEY; + axis = new Vector3d(1.0,0.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_DOWN)) { + inputType = InputType.KEY; + axis = new Vector3d(-1.0,0.0,0.0); + } else if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + updateGizmo(); + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (inputType != InputType.KEY) + axis = getRotationAxis(); + if (axis == null) { + parent.getDefaultAction().update(); + return; + } + Vector3d taxis = null; + if (!worldCoord) { + taxis = new Vector3d(axis); + MathTools.rotate(q, axis, axis); + } + String text = ""; + if (inputType == InputType.INTERSECT) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + MathTools.intersectStraightPlane(o, d, p, axis, i2, s); + i2.sub(p); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + if(!worldCoord) + axis = taxis; + if (false && useStep) { + for (IGraphicsNode mo : mos) { + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); + // FIXME : commit + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + //mo.setRotation(rotations.get(mo)); + //mo.modifyWorldRotation(axis, angle - prevAngle); + AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); + rotations.put(mo, aa); + prevAngle = angle; + Vector3d euler = MathTools.getEuler(aa); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + aa = MathTools.getFromEuler2(euler); + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); + //mo.setRotation(aa); + Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); + e.scale(180.0/Math.PI); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + } + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation + (mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + prevAngle = angle; + } + + } else if (inputType == InputType.NONINTERSECT){ + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s); + if(!worldCoord) + axis = taxis; + if (false && useStep) { + for (IGraphicsNode mo : mos) { + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + //mo.setRotation(rotations.get(mo)); + //mo.modifyWorldRotation(axis, s[1] - prevS); + AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); + rotations.put(mo, aa); + Vector3d euler = MathTools.getEuler(aa); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + aa = MathTools.getFromEuler2(euler); + prevS = s[1]; + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); + //mo.setRotation(aa); + Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); + e.scale(180.0/Math.PI); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + } + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + prevS = s[1]; + + } + + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + } + setInfoText(text); + + } + /* + private double roundAngle(double current, double modify) { + double angle = roundAngle(current+modify); + if (Double.isNaN(angle)) { + angle = current+modify; + } + //System.out.println(angle + " " + (current+modify)); + return angle; + } + */ + + private double roundAngle(double angle) { + while (angle < - Math.PI) + angle += Math.PI*2.0; + while (angle > Math.PI) + angle -= Math.PI*2.0; + + + int index = 0; + while (angle > angles[index]) + index++; + if (index == 0) { + angle = angles[0]; + } else { + double d = angle - angles[index - 1]; + double d2 = angles[index] - angle; + if (d < d2) + angle = angles[index - 1]; + else + angle = angles[index]; + } + return angle; + } + + private void updateGizmo() { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + //gizmo.update(XithTools.getPosition(mos.get(0).getGroup()),camera.getCameraPos(),component); + gizmo.update(VecmathJmeTools.getD(mos.get(0).getGroup().getWorldTranslation()),camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java new file mode 100644 index 00000000..d4630a1c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateAction.java @@ -0,0 +1,422 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.MouseEvent; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.gizmo.TransformGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.proconf.g3d.stubs.Position; + + +public class TranslateAction extends ConstrainedTransformAction { + + + private TransformGizmo gizmo; + + private double istep = 10.0; + private int decimals = 2; + + + private Action csAction; + List mos = null; + + private boolean worldCoord = true; + + + private AxisAngle4d aa; + private Quat4d q; + + public TranslateAction(ThreeDimensionalEditorBase parent) { + super(parent); + + csAction = new Action("World",Action.AS_CHECK_BOX) { + public void run() { + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + setWorldCoord(g,!isChecked()); + return GraphRequestStatus.transactionComplete(); + } + }; + TranslateAction.this.parent.getSession().asyncRead(r); + + } + }; + gizmo = new TransformGizmo(component.getDisplaySystem().getRenderer()); + } + + public void init() { + this.setText("Translate"); + this.setToolTipText("Translate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/translate.png")); + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() == 0) + return false; + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasLocalPosition); + if (p == null || p.size() != 1) + return false; + } + + } + return true; + + } + + @Override + public void deactivate() { + super.deactivate(); + parent.setGizmo(null); + mos = null; + } + + private void setWorldCoord(Graph graph,boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + updateWorldCoord(graph); + } + + private void updateWorldCoord(Graph graph) { + if (worldCoord) { + csAction.setText("World"); + gizmo.setRotation(new AxisAngle4f()); + aa = null; + q = null; + } else { + csAction.setText("Local"); + Orientation o = mos.get(0).getParent().getG3DNode(graph).getWorldOrientation(); + if (o == null) { + aa = new AxisAngle4d(); + } else { + aa = G3DTools.getOrientation(o); + } + + gizmo.setRotation(new AxisAngle4f(aa)); + q = new Quat4d(); + q.set(aa); + } +// if (manager != null) +// parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { +// public void run() { +// manager.update(true); +// } +// }); + + this.parent.setViewChanged(true); + } + + public void fillToolBar(IToolBarManager manager) { + super.fillToolBar(manager); + csAction.setChecked(!worldCoord); + manager.add(csAction); + } + + @Override + public void activate() { + GraphRequest r = new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + parent.setGizmo(gizmo); + + updateGizmo(g); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); + for (IGraphicsNode mo : mos) { + if (worldCoord) + text += G3DTools.getVector(mo.getG3DNode(g).getWorldPosition()) + " ";//mo.getWorldPosition() + " "; + else + text += G3DTools.getVector(mo.getG3DNode(g).getLocalPosition()) + " "; + } + final String fText = text; + parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() { + public void run() { + setInfoText(fText); + } + }); + + Resource r[] = new Resource[mos.size()]; + for (int i = 0; i < mos.size(); i++) { + r[i] = mos.get(i).getResource(); + } + + TranslateActionConstraints.addConstraints(r, detector); + updateWorldCoord(g); + return GraphRequestStatus.transactionComplete(); + }; + + }; + parent.getSession().asyncRead(r); + + } + + Vector3d getTranslate(Graph graph) { + return getTranslate(graph,new Vector3d()); + } + + Vector3d getTranslate(Graph graph,Vector3d offset) { + Vector3d translate = new Vector3d(); + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = G3DTools.getVector(mos.get(0).getG3DNode(graph).getWorldPosition());//gizmo.getPosition(); + Vector3d dir = null; + switch (gizmo.getSelected()) { + case TransformGizmo.XYZ : + Vector3d normal = camera.getUnNormalizedHeading(); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + normal.normalize(); + double s[] = new double[1]; + Vector3d r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + translate.z = r.z; + } + break; + case TransformGizmo.X : + dir = new Vector3d(1.0,0.0,0.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + Vector3d i1 = new Vector3d(); + Vector3d i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.x = s[0]; + + break; + case TransformGizmo.Y : + dir = new Vector3d(0.0,1.0,0.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.y = s[0]; + break; + case TransformGizmo.Z : + dir = new Vector3d(0.0,0.0,1.0); + if(!worldCoord) + MathTools.rotate(q, dir, dir); + i1 = new Vector3d(); + i2 = new Vector3d(); + s = new double[2]; + MathTools.intersectStraightStraight( p, dir,o, d, i2, i1,s); + translate.z = s[0]; + break; + case TransformGizmo.XY : + normal = new Vector3d(0.0,0.0,1.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.y = r.y; + } + break; + case TransformGizmo.XZ : + normal = new Vector3d(0.0,1.0,0.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.x = r.x; + translate.z = r.z; + } + break; + case TransformGizmo.YZ : + normal = new Vector3d(1.0,0.0,0.0); + if(!worldCoord) + MathTools.rotate(q, normal, normal); + r = new Vector3d(); + if (MathTools.intersectStraightPlane(o, d, p, normal, r)) { + r.sub(p); + translate.y = r.y; + translate.z = r.z; + } + break; + default : + + return null; + } + translate.sub(offset); + + if (useConstraints && dir != null) { + switch (gizmo.getSelected()) { + case TransformGizmo.X: + case TransformGizmo.Y: + case TransformGizmo.Z: + Vector3d t = new Vector3d(translate); + // TODO : to the test against all translated objects and snap to closest one + Point3d pos = G3DTools.getPoint(mos.get(0).getG3DNode(graph).getWorldPosition()); + t.add(pos); + Point3d snap = detector.getPointSnap2(t, dir); + if (snap != null) { + // System.out.print("t: " + translate); + translate = new Vector3d(snap); + translate.sub(pos); + // System.out.println(" " + translate); + } + break; + + } + } + return translate; + } + + Vector3d prevTranslate = new Vector3d(); + + @Override + public void doChanges(Graph graph) throws Exception { + if (input.mousePressed()) { + boolean b = useConstraints; + useConstraints = false; + prevTranslate = getTranslate(graph); + useConstraints = b; + } + if (input.mouseClicked()) { + end(); + return; + } + if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + detector.clearConstraintHighlights(); + parent.setViewChanged(true); + + + + Vector3d translate = getTranslate(graph,prevTranslate); + + if (translate == null) { + //cameraRotateAction.update(); + parent.getDefaultAction().update(); + updateGizmo(graph); + return; + } + //translate.sub(prevTranslate); + + if ((input.dragModifiers() & MouseEvent.CTRL_MASK) > 0) { + String text = ""; + for (IGraphicsNode mo : mos) { + + Point3d p; + if (worldCoord) + p = G3DTools.getPoint(mo.getG3DNode(graph).getWorldPosition());//mo.getWorldPosition(); + else + p = G3DTools.getPoint(mo.getG3DNode(graph).getLocalPosition()); + p.add(translate); + if (gizmo.getSelected() == TransformGizmo.X || gizmo.getSelected() == TransformGizmo.XY || gizmo.getSelected() == TransformGizmo.XZ || gizmo.getSelected() == TransformGizmo.XYZ) { + p.x = Math.round(istep * p.x) / istep; + BigDecimal bx = new BigDecimal(p.x); + bx.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.x = bx.doubleValue(); + } + if (gizmo.getSelected() == TransformGizmo.Y || gizmo.getSelected() == TransformGizmo.XY || gizmo.getSelected() == TransformGizmo.YZ || gizmo.getSelected() == TransformGizmo.XYZ) { + p.y = Math.round(istep * p.y) / istep; + BigDecimal by = new BigDecimal(p.y); + by.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.y = by.doubleValue(); + } + if (gizmo.getSelected() == TransformGizmo.Z || gizmo.getSelected() == TransformGizmo.YZ || gizmo.getSelected() == TransformGizmo.XZ || gizmo.getSelected() == TransformGizmo.XYZ) { + p.z = Math.round(istep * p.z) / istep; + BigDecimal bz = new BigDecimal(p.z); + bz.setScale(decimals, BigDecimal.ROUND_HALF_UP); + p.z = bz.doubleValue(); + } + text += p + " "; + if (worldCoord) + G3DTools.setTuple3(mo.getG3DNode(graph).getWorldPosition(), p); + else + G3DTools.setTuple3(mo.getG3DNode(graph).getLocalPosition(), p); + //mo.setWorldTranslation(p); + + } + if (useConstraints) + text+=detector.getSnapString(); + setInfoText(text); + + } else { + String text = ""; + for (IGraphicsNode mo : mos) { + Position pos; + if (worldCoord) { + pos = mo.getG3DNode(graph).getWorldPosition(); + } else { + pos = mo.getG3DNode(graph).getLocalPosition(); + } + Point3d p = G3DTools.getPoint(pos); + p.add(translate); + text += p; + G3DTools.setTuple3(pos, p); + } + if (useConstraints) + text+=detector.getSnapString(); + setInfoText(text); + // parent.getGraph().commitChanges(CommitMessage.CHANGE_MESSAGE); + } + updateGizmo(graph); + + } + + protected void updateGizmo(Graph graph) { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (mos.size() == 0) { + end(); + return; + } + gizmo.update(G3DTools.getVector(mos.get(0).getG3DNode(graph).getWorldPosition()),camera.getCameraPos(),component); + + } + + public void setInfoText(String text) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java new file mode 100644 index 00000000..c1a7236d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/TranslateActionConstraints.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ConstraintDetector; + + +/** + * Temporary class to handle "Automatic" constraints for translation + * TODO : create extension point / extension that can provide constraints + * TODO : how to override previously added constraints ? + * + * @author Marko Luukkainen + * + */ +public class TranslateActionConstraints { + + + public static void addConstraints(Resource translated[], ConstraintDetector detector) { + detector.clearConstraints(); + // these must be provided through extension point ! +// if (isElbow(translated)) { +// addElbowConstraints(translated, detector); +// } else if (isPipeControlPoint(translated)) { +// addPipeControlPointConstraints(translated, detector); +// } else if (isEndComponent(translated)) { +// addEndComponentConstraints(translated, detector); +// } + + + } + + /* + * These methods must be inserted into extension + */ + +// private static boolean isElbow(Resource translated[]) { +// for (Resource r : translated) { +// if (!r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.ELBOW))) { +// return false; +// } +// } +// return true; +// } +// +// private static boolean isEndComponent(Resource translated[]) { +// for (Resource r : translated) { +// if (!r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.END_COMPONENT))) { +// return false; +// } +// } +// return true; +// } +// +// private static boolean isPipeControlPoint(Resource translated[]) { +// for (Resource r : translated) { +// if (!r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.PIPE_CONTROL_POINT))) { +// return false; +// } +// } +// return true; +// } +// +// private static void addElbowConstraints(Resource translated[], ConstraintDetector detector) { +// Set res = new HashSet(); +// // add all controlpoints connected to every elbow's controlpoint +// for (Resource r : translated) { +// Elbow elbow = ElbowFactory.create(r); +// PipeControlPoint p = elbow.getHasControlPoint(); +// PipeControlPoint next = PipingTools.findNextEnd(p); +// PipeControlPoint previous = PipingTools.findPreviousEnd(p); +// if (next != null) +// res.add(next.getResource()); +// if (previous != null) +// res.add(previous.getResource()); +// +// } +// // remove all controlpoints that are elbows' controlpoints +// for (Resource r : translated) { +// Elbow elbow = ElbowFactory.create(r); +// res.remove(elbow.getHasControlPoint().getResource()); +// } +// for (Resource r : res) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// detector.addContraintPoint(GraphicsNodeTools.getPoint(p.getLocalPosition())); +// } +// } +// +// private static void addEndComponentConstraints(Resource translated[], ConstraintDetector detector) { +// Set res = new HashSet(); +// // add all controlpoints connected to every elbow's controlpoint +// for (Resource r : translated) { +// EndComponent elbow = EndComponentFactory.create(r); +// PipeControlPoint p = elbow.getHasControlPoint(); +// PipeControlPoint next = PipingTools.findNextEnd(p); +// PipeControlPoint previous = PipingTools.findPreviousEnd(p); +// if (next != null) +// res.add(next.getResource()); +// if (previous != null) +// res.add(previous.getResource()); +// +// } +// // remove all controlpoints that are elbows' controlpoints +// for (Resource r : translated) { +// EndComponent elbow = EndComponentFactory.create(r); +// res.remove(elbow.getHasControlPoint().getResource()); +// } +// for (Resource r : res) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// detector.addContraintPoint(GraphicsNodeTools.getPoint(p.getLocalPosition())); +// } +// } +// +// +// private static void addPipeControlPointConstraints(Resource translated[], ConstraintDetector detector) { +// Set res = new HashSet(); +// // add all controlpoints connected to every elbow's controlpoint +// for (Resource r : translated) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// PipeControlPoint next = PipingTools.findNextEnd(p); +// PipeControlPoint previous = PipingTools.findPreviousEnd(p); +// if (next != null) +// res.add(next.getResource()); +// if (previous != null) +// res.add(previous.getResource()); +// +// } +// // remove all controlpoints that are elbows' controlpoints +// for (Resource r : translated) { +// res.remove(r); +// } +// for (Resource r : res) { +// PipeControlPoint p = PipeControlPointFactory.create(r); +// detector.addContraintPoint(GraphicsNodeTools.getPoint(p.getLocalPosition())); +// } +// } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java new file mode 100644 index 00000000..58aa02a7 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteAction.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + +public abstract class WriteAction extends ContextAction { + boolean sync; + public WriteAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void run() { + Session session = parent.getSession(); + if(!canActivate()) { + return; + } + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + return doChanges(g); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + afterChanges(status); + } + }; + if (sync) { + session.syncWrite(r); + } else { + session.asyncWrite(r); + } + } + + public abstract GraphRequestStatus doChanges(Graph graph) throws Exception; + + public void afterChanges(GraphRequestStatus status) { + + } + + public boolean canActivate() { + return true; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java new file mode 100644 index 00000000..1208b75c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/actions/WriteInteractiveAction.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; + + +public abstract class WriteInteractiveAction extends InteractiveAction { + boolean sync; + + public WriteInteractiveAction(ThreeDimensionalEditorBase parent, boolean sync) { + super(parent); + this.sync = sync; + } + + @Override + public final void update(){ + Session session = parent.getSession(); + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + doChanges(g); + return GraphRequestStatus.transactionComplete(); + } + }; + if (sync) { + session.syncWrite(r); + } else { + session.asyncWrite(r); + } + } + + + public abstract void doChanges(Graph graph) throws Exception; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java new file mode 100644 index 00000000..5777f8e8 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AbstractScalarInterpolator.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public abstract class AbstractScalarInterpolator implements ScalarInterpolator { + public void interpolate(double delta) { + throw new UnsupportedOperationException(""); + + } + + public void setTarget(Object target) { + throw new UnsupportedOperationException(""); + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java new file mode 100644 index 00000000..435cb0dd --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animatable.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + + +/** + * + * TODO : multiple animations + * TODO : remove setRandomAnimation + * + * @author Marko Luukkainen + * + */ +public interface Animatable { + + /** + * Sets used animation + * @param animation + */ + public boolean setAnimation(Graph graph, Resource animation); + + /** + * Updates animation + * @param delta + */ + public void animate(double delta, double frameTime); + + /** + * Sets random animation + * (Testing purposes) + */ + public boolean setRandomAnimation(Graph graph); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java new file mode 100644 index 00000000..9dd7f5ea --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Animation.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +public class Animation { + private List interpolators = new ArrayList(); + + + public void addInterpolator(Interpolator i) { + interpolators.add(i); + } + + public void removeInterpolator(Interpolator i) { + interpolators.remove(i); + } + + public void interpolate(double delta) { + for (Interpolator i : interpolators) { + i.interpolate(delta); + } + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java new file mode 100644 index 00000000..809ec605 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationController.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.db.Graph; + + +public interface AnimationController { + + public void updateAnimation(Graph graph, double frameTime); + public void setAnimatable(Animatable animatable); + public void addAnimatable(Animatable animatable); + public void dispose(); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java new file mode 100644 index 00000000..8085405a --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystem.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.base.ScenegraphAdapter; + + +public class AnimationSystem { + private ScenegraphAdapter adapter; + private List animationControllers = new ArrayList(); + + private List listeners = new ArrayList(); + + private boolean pause = false; + + public AnimationSystem(ScenegraphAdapter adapter) { + if (adapter == null) + throw new IllegalArgumentException("ScenegraphAdapter must not be null"); + this.adapter = adapter; + } + + public void add(AnimationController controller) { + animationControllers.add(controller); + for (AnimationSystemListener l : listeners) + l.animationAdded(this, controller); + } + + public void addListener(AnimationSystemListener l) { + listeners.add(l); + } + + public void removeListener(AnimationSystemListener l) { + listeners.remove(l); + } + + public boolean isRunning() { + return animationControllers.size() > 0; + } + + public void pause() { + if (pause) + return; + pause = true; + for (AnimationSystemListener l : listeners) + l.animationPaused(this); + } + + public void play() { + if(!pause) + return; + pause = false; + for (AnimationSystemListener l : listeners) + l.animationPlay(this); + } + + public void stop() { + for (AnimationController c : animationControllers) + c.dispose(); + animationControllers.clear(); + for (AnimationSystemListener l : listeners) + l.animationStopped(this); + } + + public boolean isPause() { + return pause; + } + + public void run(Graph graph, double frameTime) { + if (pause) + return; + if (animationControllers.size() > 0) { + for (AnimationController c : animationControllers) + c.updateAnimation(graph, frameTime); + adapter.setChanged(true); + } + } + + public List getAnimationControllers() { + return animationControllers; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java new file mode 100644 index 00000000..f45c3b49 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/AnimationSystemListener.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public interface AnimationSystemListener { + public void animationStopped(AnimationSystem animationSystem); + public void animationPaused(AnimationSystem animationSystem); + public void animationPlay(AnimationSystem animationSystem); + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java new file mode 100644 index 00000000..5a80e834 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledColorInterpolator.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.state.MaterialState; + +public class ChanneledColorInterpolator implements Interpolator { + private ScalarInterpolator rInterpolator; + private ScalarInterpolator gInterpolator; + private ScalarInterpolator bInterpolator; + + //Material m = null; + MaterialState m = null; + int type = 1; + + public static final int AMBIENT = 0; + public static final int DIFFUSE = 1; + public static final int SPECULAR = 2; + public static final int EMISSIVE = 3; + + + public ChanneledColorInterpolator(ScalarInterpolator rInterpolator, ScalarInterpolator gInterpolator, ScalarInterpolator bInterpolator) { + this.rInterpolator = rInterpolator; + this.gInterpolator = gInterpolator; + this.bInterpolator = bInterpolator; + } + + public void interpolate(double delta) { + double r = rInterpolator.evaluate(delta); + double g = gInterpolator.evaluate(delta); + double b = bInterpolator.evaluate(delta); + + ColorRGBA c = new ColorRGBA((float)r, (float)g, (float)b,0.f); + switch (type) { + case AMBIENT : + m.setAmbient(c); + break; + case DIFFUSE: + m.setDiffuse(c); + break; + case SPECULAR: + m.setSpecular(c); + break; + case EMISSIVE: + m.setEmissive(c); + break; + } + } + + public void setTarget(Object target) { + // m = (Material)target; + m = (MaterialState)target; + } + + public void setType(int type) { + this.type = type; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java new file mode 100644 index 00000000..5b6aeb60 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ChanneledPositionInterpolator.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + + +import com.jme.math.Vector3f; +import com.jme.scene.Node; + + +public class ChanneledPositionInterpolator implements Interpolator { + private ScalarInterpolator xInterpolator; + private ScalarInterpolator yInterpolator; + private ScalarInterpolator zInterpolator; + + Node node; + + public ChanneledPositionInterpolator(ScalarInterpolator xInterpolator, ScalarInterpolator yInterpolator, ScalarInterpolator zInterpolator) { + this.xInterpolator = xInterpolator; + this.yInterpolator = yInterpolator; + this.zInterpolator = zInterpolator; + } + + public void interpolate(double delta) { + double x = xInterpolator.evaluate(delta); + double y = yInterpolator.evaluate(delta); + double z = zInterpolator.evaluate(delta); + + node.setLocalTranslation(new Vector3f((float)x,(float)y,(float)z)); + } + + public void setTarget(Object target) { + node = (Node)target; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java new file mode 100644 index 00000000..5e273d1e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ConstantInterpolator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public class ConstantInterpolator extends AbstractScalarInterpolator{ + double constant; + + + public ConstantInterpolator(double constant) { + this.constant = constant; + } + + public double evaluate(double delta) { + return constant; + } + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java new file mode 100644 index 00000000..630434f6 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/Interpolator.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public interface Interpolator { + + public void interpolate(double delta); + public void setTarget(Object target); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java new file mode 100644 index 00000000..d359c341 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ResourceAnimationController.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + +public class ResourceAnimationController implements AnimationController { + List animatables = new ArrayList(); + + Resource source; + + public ResourceAnimationController(Resource source) { + this.source = source; + } + + public void addAnimatable(Animatable animatable) { + animatables.add(animatable); + + } + + public void setAnimatable(Animatable animatable) { + animatables.clear(); + animatables.add(animatable); + + } + + protected double getValue(Graph graph) { + //return PropertyUtils.getScalarDoubleValue(source); + return graph.getScalarDouble(source); + //source.getDoubleValue(); + } + + public void updateAnimation(Graph graph, double frameTime) { + double d = getValue(graph); + d = d - Math.floor(d); + if (d > 1.0) { + d = 1.0; + } else if (d < 0.0) { + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } + + public void dispose() { + + } + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java new file mode 100644 index 00000000..afe75976 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScalarInterpolator.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +public interface ScalarInterpolator extends Interpolator{ + + public double evaluate(double delta); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java new file mode 100644 index 00000000..c3562693 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ScaledResourceAnimationController.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + +public class ScaledResourceAnimationController extends ResourceAnimationController { + double min; + double max; + double irange; + + public ScaledResourceAnimationController(Resource source, double min, double max) { + super(source); + this.max = max; + this.min = min; + this.irange = 1.0/(max - min); + } + + + @Override + public void updateAnimation(Graph graph, double frameTime) { + double d = (getValue(graph) - min) * irange; + if (d > 1.0) { + d = 1.0; + } else if (d < 0.0) { + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java new file mode 100644 index 00000000..33e565c9 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/SlerpInterpolator.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import javax.vecmath.Quat4d; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + + +import com.jme.scene.Node; + +import org.simantics.animation.curve.SlerpCurve; + + +public class SlerpInterpolator implements Interpolator{ + private SlerpCurve curve; + + //private TransformGroup group; + //private Transform3D transform; + private Node node = null; + + public SlerpInterpolator(SlerpCurve curve) { + this.curve = curve; + //transform = new Transform3D(); + } + + public void interpolate(double delta) { + Quat4d q = curve.evaluate(delta); + //transform.set(new Quat4f(q)); + //group.setTransform(transform); + node.setLocalRotation(VecmathJmeTools.get(q)); + } + + public void setTarget(Object target) { + //group = (TransformGroup)target; + node = (Node)target; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java new file mode 100644 index 00000000..063b0a62 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TCBInterpolator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import org.simantics.animation.curve.TCBCurve; + + +public class TCBInterpolator extends AbstractScalarInterpolator{ + TCBCurve curve; + + public TCBInterpolator(TCBCurve curve) { + this.curve = curve; + } + + public double evaluate(double delta) { + return curve.evaluate(delta); + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java new file mode 100644 index 00000000..ec40dea7 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/TestAnimationController.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.db.Graph; + +public class TestAnimationController implements AnimationController { + List animatables = new ArrayList(); + + private double d = 0.0; + private double delta = 0.01; + + public void addAnimatable(Animatable animatable) { + animatables.add(animatable); + + } + + public void setAnimatable(Animatable animatable) { + animatables.clear(); + animatables.add(animatable); + + } + + public void updateAnimation(Graph graph, double frameTime) { + d += delta; + if (d > 1.0) { + d = 1.0; + delta = -delta; + } else if (d < 0.0) { + delta = -delta; + d = 0.0; + } + for (Animatable a : animatables) + a.animate(d,frameTime); + } + + public void dispose() { + + } + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java new file mode 100644 index 00000000..b433d22c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/animation/ui/AnimationControlCreator.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.animation.ui; + +import org.eclipse.jface.action.Action; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.animation.AnimationController; +import org.simantics.proconf.g3d.animation.AnimationSystem; +import org.simantics.proconf.g3d.animation.AnimationSystemListener; + + + +public class AnimationControlCreator { + + private AnimationSystem animationSystem; + + public AnimationControlCreator(AnimationSystem animationSystem) { + if (animationSystem == null) + throw new IllegalArgumentException("AnimationSystem must not be null"); + this.animationSystem = animationSystem; + } + + public Action createStopAction() { + return new StopAction(); + } + + public Action createPauseAction() { + return new PauseAction(); + } + + public Action createPlayAction() { + return new PlayAction(); + } + + private class StopAction extends Action implements AnimationSystemListener { + + public StopAction() { + super(); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_stop_blue.png")); + this.setDisabledImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_stop.png")); + animationSystem.addListener(this); + if (!animationSystem.isRunning()) + this.setEnabled(false); + } + + public void run() { + animationSystem.stop(); + } + + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController) { + this.setEnabled(true); + } + + public void animationPaused(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationPlay(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationStopped(AnimationSystem animationSystem) { + this.setEnabled(false); + } + } + + private class PlayAction extends Action implements AnimationSystemListener { + + public PlayAction() { + super(); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_play_blue.png")); + this.setDisabledImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_play.png")); + animationSystem.addListener(this); + if (!animationSystem.isPause() || !animationSystem.isRunning()) + this.setEnabled(false); + } + + public void run() { + animationSystem.play(); + } + + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController) { + this.setEnabled(animationSystem.isPause()); + } + + public void animationPaused(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationPlay(AnimationSystem animationSystem) { + this.setEnabled(false); + } + + public void animationStopped(AnimationSystem animationSystem) { + this.setEnabled(false); + } + } + + private class PauseAction extends Action implements AnimationSystemListener { + + public PauseAction() { + super(); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_pause_blue.png")); + this.setDisabledImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/silk/control_pause.png")); + animationSystem.addListener(this); + if (animationSystem.isPause() || !animationSystem.isRunning()) + this.setEnabled(false); + } + + public void run() { + animationSystem.pause(); + } + + public void animationAdded(AnimationSystem animationSystem, AnimationController animationController) { + this.setEnabled(!animationSystem.isPause()); + } + + public void animationPaused(AnimationSystem animationSystem) { + this.setEnabled(false); + } + + public void animationPlay(AnimationSystem animationSystem) { + this.setEnabled(true); + } + + public void animationStopped(AnimationSystem animationSystem) { + this.setEnabled(false); + } + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java new file mode 100644 index 00000000..5cc4304b --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/AppearanceTools.java @@ -0,0 +1,454 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.graphics.Device; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.StubLinkedList; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.Appearance; +import org.simantics.proconf.g3d.stubs.Color; +import org.simantics.proconf.g3d.stubs.G3DResource; +import org.simantics.proconf.g3d.stubs.ImageTexture; +import org.simantics.proconf.g3d.stubs.Material; +import org.simantics.proconf.g3d.stubs.MultiTexture; +import org.simantics.proconf.g3d.stubs.MultiTextureMode; +import org.simantics.proconf.g3d.stubs.Shader; +import org.simantics.proconf.g3d.stubs.Texture; +import org.simantics.utils.ErrorLogger; + +import com.jme.image.Image; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.FragmentProgramState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.VertexProgramState; + + +public class AppearanceTools { + + + + + public static void setColor(Color color, org.eclipse.swt.graphics.Color c) { + color.setRed(new double[]{(double)c.getRed() / 255.0}); + color.setGreen(new double[]{(double)c.getGreen() / 255.0}); + color.setBlue(new double[]{(double)c.getBlue() / 255.0}); + } + + public static org.eclipse.swt.graphics.Color getColor(Color color, Device device) { + org.eclipse.swt.graphics.Color c = new org.eclipse.swt.graphics.Color(device, (int)(color.getRed()[0] * 255.0), (int)(color.getGreen()[0] * 255.0),(int)(color.getBlue()[0] * 255.0)); + return c; + } + + /** + * Returns collection of renderstates that represent the given appearance. + * Note : if collection contains an alphastate, node must be inserted to transparent rendering queue.! + * @param appearance + * @param renderer + * @return + */ + public static Collection getAppearance(Appearance appearance, Renderer renderer) { + Material m = appearance.getMaterial(); + List states = new ArrayList(); + if (m != null) { + states.addAll(getMaterial(m, renderer)); + } + Texture t = appearance.getTexture(); + if (t != null) { + if (t.isInstanceOf(Resources.g3dResource.ImageTexture)) { + states.addAll(getPatternTexture(t, renderer)); + } else if (t.isInstanceOf(Resources.g3dResource.Texture3D)) { + ErrorLogger.getDefault().logWarning("JME doesn't support volume textures!", null); + } else if (t.isInstanceOf(Resources.g3dResource.MultiTexture)) { + states.addAll(getMultiTexture(t, renderer)); + } else if (t.isInstanceOf(Resources.g3dResource.CubeMapTexture)) { + ErrorLogger.getDefault().logWarning("JME doesn't support cubemap textures!", null); + } else { + throw new UnsupportedOperationException("Unsupported texture"); + } + } + Shader s = appearance.getShader(); + if (s != null) { + states.addAll(getShader(s, renderer)); + } + return states; + + } + + private static ColorRGBA getJMEColor(Color color) { + return new ColorRGBA((float)color.getRed()[0],(float)color.getGreen()[0],(float)color.getBlue()[0],0.f); + } + + private static ColorRGBA getJMEColor(Color color, float alpha) { + return new ColorRGBA((float)color.getRed()[0],(float)color.getGreen()[0],(float)color.getBlue()[0],alpha); + } + + private static Collection getMaterial(Material m , Renderer renderer) { + float alpha = 0.f; + MaterialState ms = renderer.createMaterialState(); + List states = new ArrayList(); + if (m.getTransparency()[0] > 0.0) { + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + states.add(as); + alpha = 1.f - (float)m.getTransparency()[0]; + //node.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + } else { + //node.setRenderQueueMode(Renderer.QUEUE_OPAQUE); + } + + ms.setEmissive(getJMEColor(m.getEmissiveColor())); + ms.setSpecular(getJMEColor(m.getSpecularColor())); + ms.setAmbient(getJMEColor(m.getAmbientColor())); + ms.setDiffuse(getJMEColor(m.getDiffuseColor(),alpha)); + ms.setShininess((float) m.getShininess()[0]); + //node.setRenderState(ms); + states.add(ms); + return states; + } + + private static Collection getShader(Shader s , Renderer renderer) { + List states = new ArrayList(); + VertexProgramState vs = renderer.createVertexProgramState(); + vs.load(s.getVertexShader()[0]); + FragmentProgramState fs = renderer.createFragmentProgramState(); + fs.load(s.getFragmentShader()[0]); + states.add(vs); + states.add(fs); + return states; + } + + private static Collection getPatternTexture(Texture t, Renderer renderer) { + + List states = new ArrayList(); + com.jme.image.Texture texture = ResourceTextureCache.getInstance().loadTexture(t.getGraph(), t.getResource()); + if (texture == null) + return states; + TextureState state = renderer.createTextureState(); + state.setTexture(texture); + state.setEnabled(true); + states.add(state); + return states; + + } + + private static Image getPatternTexture(ImageTexture t) { + return ResourceTextureCache.getInstance().loadImage(t.getGraph(), t.getResource()); + } + + + + + + private static Collection getMultiTexture(Texture t, Renderer renderer) { + List states = new ArrayList(); + TextureState state = renderer.createTextureState(); + MultiTexture t3 = new MultiTexture(t); + Collection mtList = t3.getRelatedObjects(Resources.g3dResource.HasMultiTextureElementList); + assert (mtList.size() == 1); //this is required in the ontology! + StubLinkedList list = new StubLinkedList(mtList.iterator().next()); + + for (int i = 0; i < list.size(); i++) { + IEntity ie = list.get(i); + //MultiTextureElement e = new MultiTextureElement(ie); + Texture tex = new Texture(ie); //e.getTexture(); + MultiTextureMode mode = tex.getTextureMode();//e.getTextureMode(); + com.jme.image.Texture texture = new com.jme.image.Texture(); + texture.setFilter(com.jme.image.Texture.FM_LINEAR); + texture.setMipmapState(com.jme.image.Texture.MM_LINEAR_LINEAR); + texture.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); + if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_add)) { + texture.setApply(com.jme.image.Texture.AM_ADD); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_modulate)) { + texture.setApply(com.jme.image.Texture.AM_MODULATE); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_decal)) { + texture.setApply(com.jme.image.Texture.AM_DECAL); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_blend)) { + texture.setApply(com.jme.image.Texture.AM_BLEND); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_replace)) { + texture.setApply(com.jme.image.Texture.AM_REPLACE); + } else if (mode.getResource().equals(Resources.g3dResource.MultiTextureMode_combine)) { + texture.setApply(com.jme.image.Texture.AM_COMBINE); + //CombineMode cm = e.getCombineMode(); + //CombineSource cs = e.getCombineSource(); + StubLinkedList combine = new StubLinkedList(tex.getCombineDefinition()); + setCombineAttributes(texture, combine); + + + + //att.setBlendColor(blendColor) + //att.setTexBlendColor(texBlendColor) + //att.setTextureBlendColor(color) + //att.setTextureTransform(transform) + } else { + throw new UnsupportedOperationException("Texture mode not supported"); + } + + + if (tex.isInstanceOf(Resources.g3dResource.MultiTexture)) { + ErrorLogger.defaultLogError("MultiTexture contains another MultiTexture which is not allowed", null); + continue; + } else if (tex.isInstanceOf(Resources.g3dResource.ImageTexture)) { + Image image = getPatternTexture(new ImageTexture(tex)); + if (image != null) + texture.setImage(image); + + } else if (tex.isInstanceOf(Resources.g3dResource.Texture3D)) { + ErrorLogger.getDefault().logWarning("JME doesn't support volume textures!", null); + + } else if (tex.isInstanceOf(Resources.g3dResource.CubeMapTexture)) { + ErrorLogger.getDefault().logWarning("JME doesn't support cubemap textures!", null); + + } else { + throw new UnsupportedOperationException("Unsupported texture"); + } + + state.setTexture(texture, i); + } + states.add(state); + return states; + + //MultiTextureElementList texturesList = t3.getMultiTextureElementList(); + //List textures = texturesList.toStandAloneList(); + //ArrayList states = new ArrayList(); + // for (MultiTextureElement e : textures) { + // Texture tex = e.getTexture(); + + //int index = e.getMultiTextureIndexValue(); + //String mode = e.getMultiTextureModeValue(); + + // com.jme.image.Texture texture = new com.jme.image.Texture(); + // texture.setFilter(com.jme.image.Texture.FM_LINEAR); + // texture.setMipmapState(com.jme.image.Texture.MM_LINEAR_LINEAR); + // texture.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); +// if (mode.startsWith(TEXTURE_MODE_MODULATE)) { +// texture.setApply(com.jme.image.Texture.AM_MODULATE); +// } else if (mode.startsWith(TEXTURE_MODE_DECAL)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_DECAL); +// } else if (mode.startsWith(TEXTURE_MODE_BLEND)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_MODULATE); +// } else if (mode.startsWith(TEXTURE_MODE_REPLACE)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_REPLACE); +// } else if (mode.startsWith(TEXTURE_MODE_COMBINE)) { +// texture.setCombineFuncRGB(com.jme.image.Texture.AM_COMBINE); +// +// mode = mode.substring(TEXTURE_MODE_COMBINE.length()+1); +// setCombineAttributes(texture, mode); + + + + //att.setBlendColor(blendColor) + //att.setTexBlendColor(texBlendColor) + //att.setTextureBlendColor(color) + //att.setTextureTransform(transform) +// } else { +// throw new UnsupportedOperationException("Texture mode not supported"); +// } +// +// +// if (tex.isInstanceOf(Resources.g3dResource.MultiTexture)) { +// ErrorLogger.defaultLogError("MultiTexture contains another MultiTexture which is not allowed", null); +// continue; +// } else if (tex.isInstanceOf(Resources.g3dResource.ImageTexture)) { +// Image image = getPatternTexture(ImageTextureFactory.create(tex)); +// if (image != null) +// texture.setImage(image); +// +// } else if (tex.isInstanceOf(Resources.g3dResource.Texture3D)) { +// ErrorLogger.getDefault().logWarning("JME doesn't support volume textures!", null); +// +// } else if (tex.isInstanceOf(Resources.g3dResource.CubeMapTexture)) { +// ErrorLogger.getDefault().logWarning("JME doesn't support cubemap textures!", null); +// +// } else { +// throw new UnsupportedOperationException("Unsupported texture"); +// } + + //FIXME ! + //state.setTexture(texture, index); + // } + // node.setRenderState(state); + + + + } + + + private static void setCombineAttributes(com.jme.image.Texture texture, StubLinkedList definition) { + // TODO : rgb and alpha scale + Iterator it = definition.iterator(); + IEntity mode = it.next(); + if (mode.getResource().equals(Resources.g3dResource.CombineMode_add)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_ADD); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_addsigned)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_ADD_SIGNED); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_dot3)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_DOT3_RGB); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_interpolate)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_INTERPOLATE); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_modulate)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_MODULATE); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_replace)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_REPLACE); + } else if (mode.getResource().equals(Resources.g3dResource.CombineMode_subtract)) { + texture.setCombineFuncRGB(com.jme.image.Texture.ACF_SUBTRACT); + } else { + throw new UnsupportedOperationException("Unsupported combine mode"); + } + mode = it.next(); + int i = 0; + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineSource_constantcolor)) { + m = com.jme.image.Texture.ACS_CONSTANT; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_objectcolor)) { + m = com.jme.image.Texture.ACS_PRIMARY_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_previousstate)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texturecolor)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture0)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture1)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else { + break; + //throw new UnsupportedOperationException("Texture combine source not supported"); + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineSrc0RGB(m); + break; + case 1: + texture.setCombineSrc1RGB(m); + break; + case 2: + texture.setCombineSrc2RGB(m); + break; + + } + } + if (i > 0) { + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srccolor)) { + m = com.jme.image.Texture.ACO_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srcalpha)) { + m = com.jme.image.Texture.ACO_SRC_ALPHA; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrccolor)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrcalpha)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_ALPHA; + } else { + break; + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineOp0RGB(m); + break; + case 1: + texture.setCombineOp1RGB(m); + break; + case 2: + texture.setCombineOp2RGB(m); + break; + + } + } + } + + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineSource_constantcolor)) { + m = com.jme.image.Texture.ACS_CONSTANT; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_objectcolor)) { + m = com.jme.image.Texture.ACS_PRIMARY_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_previousstate)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texturecolor)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture0)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else if (mode.getResource().equals(Resources.g3dResource.CombineSource_texture1)) { + m = com.jme.image.Texture.ACS_TEXTURE; + } else { + break; + //throw new UnsupportedOperationException("Texture combine source not supported"); + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineSrc0Alpha(m); + break; + case 1: + texture.setCombineSrc1Alpha(m); + break; + case 2: + texture.setCombineSrc2Alpha(m); + break; + + } + } + if (i > 0) { + for (i = 0; i < 3; i++) { + int m; + if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srccolor)) { + m = com.jme.image.Texture.ACO_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_srcalpha)) { + m = com.jme.image.Texture.ACO_SRC_ALPHA; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrccolor)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_COLOR; + } else if (mode.getResource().equals(Resources.g3dResource.CombineFunction_oneminussrcalpha)) { + m = com.jme.image.Texture.ACO_ONE_MINUS_SRC_ALPHA; + } else { + break; + } + mode = it.next(); + switch (i) { + case 0: + texture.setCombineOp0Alpha(m); + break; + case 1: + texture.setCombineOp1Alpha(m); + break; + case 2: + texture.setCombineOp2Alpha(m); + break; + + } + } + } + } + + public static void copyMaterial(Geometry from, Geometry to) { + for (int i = RenderState.RS_ALPHA; i < RenderState.RS_MAX_STATE; i++) { + RenderState rs = from.getRenderState(i); + if (rs != null) + to.setRenderState(rs); + } + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java new file mode 100644 index 00000000..9d48d3ed --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/Constraint.java @@ -0,0 +1,19 @@ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +public class Constraint { + + public Constraint() { + points = new ArrayList(); + dirs = new ArrayList(); + } + + public List points; + public List dirs; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java new file mode 100644 index 00000000..3a18c27c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java @@ -0,0 +1,442 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.proconf.g3d.Resources; +import org.simantics.utils.ErrorLogger; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class ConstraintDetector { + + private static final int X = 0; + private static final int Y = 1; + private static final int Z = 2; + + + private ThreeDimensionalEditorBase editor; + //private G3DNode constraintReference = null; + private Resource constraintReference = null; + private ArrayList constraintPoints = new ArrayList(); + private ArrayList constraintDirections = new ArrayList(); + private MaterialState ms; + + private ColorRGBA xColor = new ColorRGBA(1.f,0.f,0.f,1.f); + private ColorRGBA yColor = new ColorRGBA(0.f,1.f,0.f,1.f); + private ColorRGBA zColor = new ColorRGBA(0.f,0.f,1.f,1.f); + + + public ConstraintDetector(ThreeDimensionalEditorBase editor) { + this.editor = editor; + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setColorMaterial(MaterialState.CM_EMISSIVE); + } + + + public void clearConstraints() { + //System.out.println("ConstraintDetector.clearConstraints()"); + constraintPoints.clear(); + constraintDirections.clear(); + } + + private void updateConstraints() { + clearConstraints(); + if (constraintReference == null) + return; + GraphRequestWithResult request = new GraphRequestWithResult() { + @Override + public Constraint performWithResult(Graph g) throws Exception { + try { + return g.adapt(constraintReference, Resources.g3dResource.HasConstraints); + } catch (AdaptionException e) { + ErrorLogger.defaultLogWarning("Cannot add constraint", e); + return null; + } + } + }; + editor.getSession().syncRead(request); + Constraint c = request.getResult(); + if (c == null) + return; + constraintPoints.addAll(c.points); + constraintDirections.addAll(c.dirs); + } + + + public ArrayList getConstraintPoints() { + return constraintPoints; + } + + public ArrayList getConstraintDirections() { + return constraintDirections; + } + + public void updateConstraintReference() { + + Resource interactive = null; + if (editor.getSelectionAdapter().getHighlightSelection().size() > 0) { + interactive = editor.getSelectionAdapter().getInteractiveSelectedObjects().iterator().next().getResource(); + if (constraintReference == null) { + constraintReference = interactive; + updateConstraints(); + } else if (!constraintReference.getResource().equals(interactive.getResource())) { + constraintReference = interactive; + updateConstraints(); + } + } else { + constraintReference = null; + updateConstraints(); + } + + } + + public void addContraintPoint(Point3d p) { + //System.out.println("ConstraintDetector.addConstraintPoint() " + p); + constraintPoints.add(p); + } + + public void addContraintDirection(Vector3d v) { + //System.out.println("ConstraintDetector.addConstraintDirection() " + v); + constraintDirections.add(v); + } + + private double snapAngle = 0.1; + private String snapString = ""; + + private ArrayList constraintHighlights = new ArrayList(); + + public Point3d getSnappedPoint(Vector3d pickPoint, Vector3d pickDir, Vector3d requestedPoint) { + + + Vector3d snappedPoint = new Vector3d(); + Vector3d t = new Vector3d(); + Point3d currentPoint = null; + // TODO : snap to closest angle + for (Vector3d constraintDir : constraintDirections) { + + MathTools.intersectStraightStraight(pickPoint,pickDir, requestedPoint, constraintDir, t, snappedPoint); + t.sub(snappedPoint); + if (t.lengthSquared() < snapAngle) { + + snapString += "Angle snap "; + currentPoint = new Point3d(snappedPoint); + break; + } + } + if (currentPoint != null) { + Vector3d dir = new Vector3d(currentPoint); + dir.sub(requestedPoint); + Point3d p = getPointSnap(requestedPoint, dir); + if (p != null) + currentPoint = p; + } else { + List distances = new ArrayList(); + List snapPoints = new ArrayList(); + List snapStrings = new ArrayList(); + List snapColors = new ArrayList(); + for (Point3d constraintPoint : constraintPoints) { + distances.clear(); + snapPoints.clear(); + snapStrings.clear(); + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(1.0, 0.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + double distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point x-snap "); + snapColors.add(xColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 1.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point y-snap "); + snapColors.add(yColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 0.0, 1.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point z-snap "); + snapColors.add(zColor); + + } + if (distances.size() > 0) { + if (distances.size() > 1) { + // more than one axes snape + Vector3d ref = MathTools.closestPointOnStraight(constraintPoint, new Point3d(pickPoint), pickDir); + ref.sub(constraintPoint); + distance = ref.lengthSquared(); + if (distance < snapAngle) { + // we are close enought to point, so we'll just snap there + currentPoint = new Point3d(constraintPoint); + snapString += "Point snap "; + } else { + // select the closest of axes snap to + int min = 0; + for (int i = 1; i < distances.size(); i++) { + if (distances.get(i) < distances.get(min)) + min = i; + } + currentPoint = snapPoints.get(min); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(min)); + snapString += snapStrings.get(min); + } + } else { + // only one of the axes snaps + currentPoint = snapPoints.get(0); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(0)); + snapString += snapStrings.get(0); + } + break; + } + } + } + return currentPoint; + + } + + public void clearConstraintHighlights() { + snapString = ""; + + for (Geometry s : constraintHighlights) + s.removeFromParent(); + + constraintHighlights.clear(); + } + + private void addConstrainLineHighlight(Point3d p1, Point3d p2, ColorRGBA color) { + + float coord[] = new float[6]; + ColorRGBA colors[] = new ColorRGBA[2]; + colors[0] = color; + colors[1] = color; + coord[0] = (float)p1.x; + coord[1] = (float)p1.y; + coord[2] = (float)p1.z; + coord[3] = (float)p2.x; + coord[4] = (float)p2.y; + coord[5] = (float)p2.z; + Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); + editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); + shape.setRenderState(ms); + constraintHighlights.add(shape); + } + + private void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) { + + float coord[] = new float[9]; + ColorRGBA colors[] = new ColorRGBA[3]; + coord[0] = (float)p1.x; + coord[1] = (float)p1.y; + coord[2] = (float)p1.z; + switch (axis) { + case X: + coord[3] = (float)p1.x; + coord[4] = (float)p1.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = xColor; + break; + case Y: + coord[3] = (float)p1.x; + coord[4] = (float)p1.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = yColor; + break; + case Z: + coord[3] = (float)p1.x; + coord[4] = (float)p2.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = zColor; + break; + + } + coord[6] = (float)p2.x; + coord[7] = (float)p2.y; + coord[8] = (float)p2.z; + Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); + shape.setMode(Line.CONNECTED); + editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); + shape.setRenderState(ms); + constraintHighlights.add(shape); + } + + /** + * Snaps position to axis-aligned planes defined by constraint points + * Form of position is p+v, meaning that the position that is snapped is requestedPoint + requestedDir + * @param requestedPoint one part of the position to be snapped + * @param requestedDir second part of the position to be snapped and direction that the position is allowed to move + * @return + */ + public Point3d getPointSnap(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + List p1s = new ArrayList(); + List p2s = new ArrayList(); + List axes = new ArrayList(); + + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(X), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane x-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(X); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Y), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane y-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Y); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Z), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane z-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Z); + } + if (snap) + break; + } + if (p1s.size() == 0) + return null; + if (p1s.size() == 1) { + snapString += "Point/Plane "; + switch (axes.get(0)) { + case X: + snapString += "x"; + break; + case Y: + snapString += "y"; + break; + case Z: + snapString += "z"; + break; + } + snapString += "-snap "; + addConstrainPlaneHighlight(p1s.get(0), p2s.get(0),axes.get(0)); + return currentPoint; + } else if (p1s.size() == 3){ + // all axial planes are intersecting, snapping point must be the constraint point + // all constraint points are the same, so just pick the first in the list + snapString += "Point/Point "; + return p1s.get(0); + } else { + Vector3d dir = new Vector3d(); + dir.cross(getAxialVector(axes.get(0)), getAxialVector(axes.get(1))); + currentPoint = new Point3d(MathTools.closestPointOnStraight(currentPoint, p1s.get(0), dir)); + addConstrainLineHighlight(p1s.get(0), currentPoint, xColor); + snapString += "Point/Line "; + return currentPoint; + } + + } + + private Vector3d getAxialVector(int axis) { + switch (axis) { + case X: + return new Vector3d(1.0,0.0,0.0); + case Y: + return new Vector3d(0.0,1.0,0.0); + case Z: + return new Vector3d(0.0,0.0,1.0); + } + throw new RuntimeException("Unknown axis " + axis); + } + + /** + * Snaps the position to axis-aligned planes defined by constraint points + * @param requestedPoint point that is snapped + * @param requestedDir direction that point is allowed to move + * @return + */ + + public Point3d getPointSnap2(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + //System.out.println(requestedPoint + " " + requestedDir); + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + //System.out.print(constraintPoint + " "); + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(1.0,0.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane x-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + //System.out.print(" x " + u[0]); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,1.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane y-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + //System.out.print(" y " + u[0]); + } + + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,0.0,1.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane z-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + //System.out.print(" z " + u[0]); + } + //System.out.println(); + if (snap) + break; + } + return currentPoint; + } + + public String getSnapString() { + return snapString; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java new file mode 100644 index 00000000..0cca6ecb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/EditorContribution.java @@ -0,0 +1,70 @@ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Graph; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +public interface EditorContribution { + + public String getName(); + + /** + * Initializes the contribution + * @param graph + */ + void initialize(Graph graph); + + + /** + * Allows contribution to modify current ui. + * @param parent + */ + void createControl(Composite parent); + + /** + * Removes all changes created by createControl + */ + void disposeControl(); + + /** + * Fills context menu + * @param graph + * @param manager + */ + void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection); + + /** + * Fills toolbar + * + * @param manager + */ + void fillLocalToolBar(IToolBarManager manager); + + /** + * Fills menumanager + * + * + * @param manager + */ + void fillLocalPullDown(IMenuManager manager); + + + /** + * Returns context dependent actions + * @return + */ + Collection getActions(); + + /** + * + */ + void run(); + + void dispose(); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java new file mode 100644 index 00000000..3bec68d2 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DAPI.java @@ -0,0 +1,94 @@ +package org.simantics.proconf.g3d.base; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Tuple3d; + +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.Resources; + +/** + * Set of methods that make scene-graph handling easier. + * + * + * @author Marko Luukkainen + * + */ +public class G3DAPI { + + + public static void setWorldPosition(IEntity node, Tuple3d position) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), position); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateWorldTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + } + + public static void setLocalPosition(IEntity node, Tuple3d position) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), position); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateLocalTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + } + + public static void setWorldOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateWorldTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + } + + public static void setLocalOrientation(IEntity node, AxisAngle4d orientation) { + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateLocalTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + + } + + public static void setWorldTransformation(IEntity node, Tuple3d position, AxisAngle4d orientation) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), position); + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateWorldTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + + } + + public static void setLocalTransformation(IEntity node, Tuple3d position, AxisAngle4d orientation) { + G3DTools.setTuple3(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), position); + G3DTools.setOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), orientation); + //G3DTools.transformationUpdate(node.getGraph(), node.getResource()); + G3DTools.propagateLocalTransformChange(node.getSingleRelatedObject(Resources.g3dResource.HasParent), node); + } + + public static void addNodeWorld(IEntity parent, IEntity node) { + parent.addStatement(Resources.g3dResource.HasChild, node); + G3DTools.propagateWorldTransformChange(parent,node); + } + + public static void addNodeLocal(IEntity parent, IEntity node) { + parent.addStatement(Resources.g3dResource.HasChild, node); + G3DTools.propagateLocalTransformChange(parent,node); + } + + public static void addNodeWorld(IEntity parent, Resource relation, IEntity node) { + assert(parent.getGraph().isSubrelationOf(relation, Resources.g3dResource.HasChild)); + parent.addStatement(relation, node); + G3DTools.propagateWorldTransformChange(parent,node); + } + + public static void addNodeLocal(IEntity parent, Resource relation, IEntity node) { + assert(parent.getGraph().isSubrelationOf(relation, Resources.g3dResource.HasChild)); + parent.addStatement(relation, node); + G3DTools.propagateLocalTransformChange(parent,node); + } + + public static void removeNode(IEntity node) { + node.removeRelatedStatements(Resources.g3dResource.HasParent); + } + + public static void moveNode(IEntity node, IEntity newParent) { + node.removeRelatedStatements(Resources.g3dResource.HasParent); + newParent.addStatement(Resources.g3dResource.HasChild, node); + G3DTools.propagateWorldTransformChange(newParent,node); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java new file mode 100644 index 00000000..0b088807 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/G3DTools.java @@ -0,0 +1,399 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; +import java.util.Set; +import java.util.Stack; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Point3d; +import javax.vecmath.Point3f; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple3f; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; + +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.Statement; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.viewpoints.State; +import org.simantics.layer0.utils.viewpoints.TraversalDecision; +import org.simantics.layer0.utils.viewpoints.TraversalResult; +import org.simantics.layer0.utils.viewpoints.TraversalRule; +import org.simantics.layer0.utils.viewpoints.TraversalUtils; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.proconf.g3d.stubs.Position; + +/** + * Basic ThreeDimensionalModelingOntology tools + * + * @author Marko Luukkainen + * + */ +public class G3DTools { + + private static boolean DEBUG = false; + + private static TransformationTools tt; + + public static void initialize() { + tt = new TransformationTools(Resources.g3dResource.HasChild, Resources.g3dResource.HasParent); + } + + public static void deinitialize() { + tt = null; + } + + public static Point3d getPoint(IEntity p) { + return new Point3d(p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static Point3f getPointFloat(IEntity p) { + return new Point3f((float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + + public static Vector3d getVector(IEntity p) { + return new Vector3d(p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static Vector3f getVectorFloat(IEntity p) { + return new Vector3f((float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + (float)p.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + + public static void setTuple3(IEntity d, Tuple3d translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z); + } + + public static void setTuple3(IEntity d, Tuple3f translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z); + } + + public static void setTuple3(IEntity d, double x, double y, double z) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, x); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, y); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, z); + } + + public static void addTuple3(IEntity d, Tuple3d translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasX)); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasY)); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static void addTuple3(IEntity d, Tuple3f translation) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, translation.x + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasX)); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, translation.y + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasY)); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, translation.z + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static void addTuple3(IEntity d, double x, double y, double z) { + d.setRelatedScalarDouble(Resources.g3dResource.HasX, x + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasX)); + d.setRelatedScalarDouble(Resources.g3dResource.HasY, y + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasY)); + d.setRelatedScalarDouble(Resources.g3dResource.HasZ, z + d.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ)); + } + + public static AxisAngle4d getOrientation(IEntity r) { + return new AxisAngle4d(r.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + r.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + r.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ), + r.getSingleRelatedScalarDouble(Resources.g3dResource.HasAngle)); + } + + public static AxisAngle4f getOrientationFloat(IEntity r) { + return new AxisAngle4f((float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasX), + (float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasY), + (float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasZ), + (float)r.getSingleRelatedScalarDouble(Resources.g3dResource.HasAngle)); + } + + public static void setOrientation(IEntity r, AxisAngle4d aa) { + r.setRelatedScalarDouble(Resources.g3dResource.HasX, aa.x); + r.setRelatedScalarDouble(Resources.g3dResource.HasY, aa.y); + r.setRelatedScalarDouble(Resources.g3dResource.HasZ, aa.z); + r.setRelatedScalarDouble(Resources.g3dResource.HasAngle, aa.angle); + } + + + public static void multiplyOrientation(IEntity r, AxisAngle4d rot) { + AxisAngle4d current = getOrientation(r); + Quat4d q1 = new Quat4d(); + q1.set(current); + Quat4d q2 = new Quat4d(); + // q2.set(rot); + q2.set(rot); + q2.mul(q1); + rot.set(q2); + setOrientation(r, rot); + } + + + public static AxisAngle4d getWorldFromLocal(IEntity node, AxisAngle4d localRot) { + return tt.getWorldFromLocal(node, localRot); + } + + public static Point3d getWorldFromLocal(IEntity node, Point3d localRot) { + return tt.getWorldFromLocal(node, localRot); + } + + public static AxisAngle4d getLocalFromWorld(IEntity node, AxisAngle4d localRot) { + return tt.getLocalFromWorld(node, localRot); + } + + public static Point3d getLocalFromWorld(IEntity node, Point3d localRot) { + return tt.getLocalFromWorld(node, localRot); + } + + public static void propagateLocalTransformChange(IEntity node, IEntity child) { + tt.propagateLocalTransformChange(node, child); + } + + public static void propagateWorldTransformChange(IEntity node, IEntity child) { + tt.propagateWorldTransformChange(node, child); + } + + public static void transformationUpdate(Graph graph, Resource resource) { + tt.transformationUpdate(graph, resource); + } + + public static void resetTransformation(IEntity shape) { + Graph graph = shape.getGraph(); + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition) == null) { + + // LocalPosition p = LocalPosition.createDefault(graph); + Position p = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalPosition, p); + // WorldPosition p2 = WorldPosition.createDefault(graph); + Position p2 = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldPosition, p2); + p.setX(new double[] { 0.0 }); + p.setY(new double[] { 0.0 }); + p.setZ(new double[] { 0.0 }); + + p2.setX(new double[] { 0.0 }); + p2.setY(new double[] { 0.0 }); + p2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), 0.0, 0.0, 0.0); + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), 0.0, 0.0, 0.0); + } + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation) == null) { + + // LocalOrientation r = LocalOrientationFactory.create(graph); + Orientation r = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalOrientation, r); + // WorldOrientation r2 = WorldOrientationFactory.create(graph); + Orientation r2 = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldOrientation, r2); + r.setAngle(new double[] { 0.0 }); + r.setX(new double[] { 1.0 }); + r.setY(new double[] { 0.0 }); + r.setZ(new double[] { 0.0 }); + r2.setAngle(new double[] { 0.0 }); + r2.setX(new double[] { 1.0 }); + r2.setY(new double[] { 0.0 }); + r2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + } + } + + + public static G3DNode getModelFromResource(Graph graph,Resource resource) { + G3DNode node = new G3DNode(graph, resource); + while (true) { + G3DNode parent = node.getParent(); + if (parent == null) + break; + node = parent; + } + return node; + } + + /** + * Checks if instance has a certain property instance + * @param instance + * @param propertyInstance + * @return + */ + public static boolean hasProperty(Graph graph,Resource instance, Resource propertyInstance) { + Builtins builtins = graph.getBuiltins(); + Stack props = new Stack(); + IEntity IEntity = EntityFactory.create(graph, instance); + Collection res = IEntity.getRelatedObjects(builtins.HasProperty); + for (IEntity t : res) + props.add(t); + + while (!props.isEmpty()) { + IEntity property = props.pop(); + if (property.getResource().equals(propertyInstance)) { + return true; + } + res = property.getRelatedObjects(builtins.HasProperty); + for (IEntity r : res) { + props.add(r); + } + } + return false; + } + + /** + * Checks if one of shapes subshapes has a certain property + * @param instance shape instance + * @param propertyInstance instance of a property + * @return + * + */ + public static boolean hasSubProperty(Graph graph,Resource instance, Resource propertyInstance) { + Builtins builtins = graph.getBuiltins(); + Stack instances = new Stack(); + + //Resource res[] = instance.getRelatedResources(Builtins.HasProperty); + IEntity entity = EntityFactory.create(graph, instance); + Collection res; +// res = entity.getRelatedObjects(Resources.g3dResource.HasChild); +// for (IEntity t : res) { +// Collection sub = t.getRelatedObjects(Resources.g3dResource.HasGeometryDefinition); +// if (sub.size() > 0) +// instances.addAll(sub); +// } + { + Collection sub = entity.getRelatedObjects(Resources.g3dResource.HasGeometryDefinition); + if (sub.size() > 0) + instances.addAll(sub); + } + while (!instances.isEmpty()) { + IEntity i = instances.pop(); + Stack props = new Stack(); + res = i.getRelatedObjects(builtins.HasProperty); + for (IEntity r : res) { + props.add(r); + } + while (!props.isEmpty()) { + IEntity property = props.pop(); + if (property.equals(propertyInstance)) { + return true; + } + res = property.getRelatedObjects(builtins.HasProperty); + for (IEntity r : res) { + props.add(r); + } + } + res = i.getRelatedObjects(Resources.g3dResource.HasGeometryDefinition); + for (IEntity r : res) { + // TODO : unnecessary check + Collection sub = r.getRelatedObjects(Resources.g3dResource.GeometryDefinitionOf); + if (sub.size() > 0) + instances.add(r); + } + + } + return false; + } + + + + + + + /** + * Loads positions of control point to rule cache + * + * @param root resource of the modeled plant + */ + public static void reloadCache(Graph graph, Resource root) { +// TraverseHandler handler = new TraverseHandler() { +// public boolean addToResult(Resource r) { +// if (r.isInstanceOf(GlobalIdMap.get(ThreeDimensionalModelingOntologyMapping.GRAPHICS_NODE))) +// return true; +// return false; +// } +// +// public TraverseRelation[] traverseFromResource(Resource resource) { +// return new TraverseRelation[] { new TraverseRelation( +// ThreeDimensionalModelingOntologyMapping.HAS_SUBNODES, +// TraverseDirection.OUTBOUND)}; +// } +// +// +// }; + + IEntity IEntity = EntityFactory.create(graph, root); + State s = new State() {}; + TraversalResult res = TraversalUtils.traverse(new TraversalRule (){ + + + @Override + public boolean areAllStatesRelevant() { + return true; + } + + @Override + public TraversalDecision makeTraversalDecision(State state, + Statement statement) { + if (statement.getPredicate().isInstanceOf(Resources.g3dResource.HasChild)) + return TraversalDecision.continueTraversal(state); + else + return TraversalDecision.stopTraversal; + } + + @Override + public Collection relevantStates() { + return null; + } + }, IEntity,s + ); + + + Set cps = res.get(s); + + //Collection cps = TraverseUtils.traverseGraph(root, handler); + for (Resource r : cps) { + G3DNode cp = new G3DNode(graph,r); + if (cp.getLocalPosition() != null) + tt.storeProperty(cp.getLocalPosition().getResource(),G3DTools.getPoint(cp.getLocalPosition())); + if (cp.getWorldPosition() != null) + tt.storeProperty(cp.getWorldPosition().getResource(),G3DTools.getPoint(cp.getWorldPosition())); + if (cp.getLocalOrientation() != null) + tt.storeProperty(cp.getLocalOrientation().getResource(),G3DTools.getOrientation(cp.getLocalOrientation())); + if (cp.getWorldOrientation() != null) + tt.storeProperty(cp.getWorldOrientation().getResource(),G3DTools.getOrientation(cp.getWorldOrientation())); + + } + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java new file mode 100644 index 00000000..8ebb5066 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProvider.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import org.simantics.layer0.utils.IEntity; + + +/** + * Interface for geometryProviders + * + * TODO : instead of using Geometry array, create class that is passed through + * TODO : Current animation system links resources; what about code generated meshes ? + * + * @author Marko Luukkainen + * + */ +public interface GeometryProvider { + + /** + * Used to check if GeometryProvider can generate mesh + * @param instance + * @return + */ + public boolean canHandle(IEntity instance); + + /** + * Generates mesh + * @param instance + * @param transform + * @return + */ + public com.jme.scene.Geometry[] getGeometryFromResource(IEntity instance, boolean transform); + + /** + * Updates mesh + * @param instance + * @param transform + * @param geometry + * @return + */ + public boolean reconstructGeometry(IEntity instance, boolean transform, com.jme.scene.Geometry[] geometry); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java new file mode 100644 index 00000000..fa92b87f --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/GeometryProviderRegistry.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.utils.ui.plugin.Extension; +import org.simantics.utils.ui.plugin.ExtensionLoader; + +import com.jme.scene.Geometry; + +public class GeometryProviderRegistry { + private static GeometryProviderRegistry instance; + public final static String ELEMENT_NAME = "Geometry"; + public final static String NAME_SPACE = "org.simantics.proconf.g3d"; + public final static String EP_NAME = "geometry"; + + private ExtensionLoader loader; + private Map providers; + + private GeometryProviderRegistry() { + loader = new ExtensionLoader(ELEMENT_NAME, NAME_SPACE, EP_NAME); + providers = new HashMap(); + } + + public static GeometryProviderRegistry getInstance() { + if (instance==null) instance = new GeometryProviderRegistry(); + return instance; + } + + public Extension[] getExtensions() { + return loader.getExtensions(); + } + + private Map getProviderMap() { + return providers; + } + + public static Geometry[] getGeometry(IEntity thing, boolean transform) { + GeometryProvider provider = getGeometryProvider(thing); + return provider.getGeometryFromResource(thing, transform); + } + + public static GeometryProvider getGeometryProvider(IEntity thing) { + Collection types = thing.getRelatedObjects(thing.getGraph().getBuiltins().InstanceOf); + + //Resource types[] = OntologyUtils.getTypes(resource); + for (IEntity t : types) { + GeometryProvider provider = getInstance().getProviderMap().get(t.getResource()); + if (provider == null) { + for (Extension e : getInstance().getExtensions()) { + if (e.getInstance().canHandle(thing)) { + getInstance().getProviderMap().put(t.getResource(), e.getInstance()); + return e.getInstance(); + } + } + + } else { + return provider; + } + } + + throw new UnsupportedOperationException("Cannot handle resource " + thing); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java new file mode 100644 index 00000000..4e4905d3 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/JmeRenderingComponent.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import com.jme.renderer.Camera; +import com.jme.scene.Node; +import com.jme.system.DisplaySystem; + + + + +/** + * Rendering component + * Allows to change underlying rendering so that + * additional information can be presented to the user + * + * @author Marko Luukkainen + * + */ +public abstract class JmeRenderingComponent { + public static final int PARALLEL_PROJECTION = 0; + public static final int PERSPECTIVE_PROJECTION = 1; + + /** + * Returns root node for nodes that cast and receive shadows. + * @return + */ + public abstract Node getShadowRoot(); + + /** + * Returns root node for nodes that do not cast shadows. + * @return + */ + public abstract Node getNoCastRoot(); + + /** + * Returns root node of the scenegraph + * @return + */ + public abstract Node getRoot(); + + /** + * Returns root node of orthogonal nodes (nodes that always face the camera) + * @return + */ + public abstract Node getOrthoNode(); + + /** + * Returns root node for nodes that do not cast or receive shadows. + * @return + */ + public abstract Node getNoShadowRoot(); + + public abstract void init(DisplaySystem displaySystem); + + /** + * Sets projection policy. + * FIXME : this was for Xith compatibility! + * @param policy + */ + public abstract void setProjectionPolicy(int policy); + public abstract int getProjectionPolicy(); + + public abstract float getScreenScale(); + public abstract void setScreenScale(float screenScale); + public abstract float getFieldOfView(); + public abstract void dispose(); + + /** + * Update flag (Return true if view needs to be rendered) + * @return + */ + public boolean update() {return false;} + public abstract Camera getCamera(); + + public abstract void render(); + public abstract void resize(int width, int height); + public abstract DisplaySystem getDisplaySystem(); + + /** + * TODO : this is for debugging purposes and will be removed. + * @param text + */ + public abstract void setDebugText(String text); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java new file mode 100644 index 00000000..2a89a4af --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/MathTools.java @@ -0,0 +1,395 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import com.jme.math.Vector2f; + +/** + * Some useful geometry related math functions. Beware, methods may modify their input parameters! + * + * @author Marko Luukkainen + * + */ +public class MathTools { + + static double EPS = 0.001; + + public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) { + point.sub(edgePoint1); + Vector3d v = new Vector3d(edgePoint2); + v.sub(edgePoint1); + double t = v.dot(point); + t /= v.lengthSquared(); + if (t <= 0.0f) + return edgePoint1; + if (t >= 1.0f) + return edgePoint2; + v.scale(t); + v.add(edgePoint1); + return v; + } + + public static Vector3d closestPointOnStraight(Point3d point, Point3d straightPoint, Vector3d straightDir) { + Vector3d v = new Vector3d(point); + v.sub(straightPoint); + double t = straightDir.dot(v); + t /= straightDir.lengthSquared(); + v.set(straightDir); + v.scale(t); + v.add(straightPoint); + return v; + } + + public static Vector3d closestPointOnStraight(Point3d point, Point3d straightPoint, Vector3d straightDir, double u[]) { + Vector3d v = new Vector3d(point); + v.sub(straightPoint); + u[0] = straightDir.dot(v); + u[0] /= straightDir.lengthSquared(); + v.set(straightDir); + v.scale(u[0]); + v.add(straightPoint); + return v; + } + + public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) { + point.sub(planePoint); + + return planeNormal.dot(point); + } + + public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) { + return (planeNormal.dot(point) + d); + } + + public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) { + intersectPoint.set(planePoint); + intersectPoint.sub(linePoint); + double u = planeNormal.dot(new Vector3d(intersectPoint)); + double v = planeNormal.dot(lineDir); + if (Math.abs(v) < EPS) + return false; + u /= v; + intersectPoint.set(lineDir); + intersectPoint.scale(u); + intersectPoint.add(linePoint); + return true; + } + + public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) { + intersectPoint.set(planePoint); + intersectPoint.sub(linePoint); + u[0] = planeNormal.dot(intersectPoint); + double v = planeNormal.dot(lineDir); + if (Math.abs(v) < EPS) + return false; + u[0] /= v; + intersectPoint.set(lineDir); + intersectPoint.scale(u[0]); + intersectPoint.add(linePoint); + return true; + } + + public static boolean intersectLineLine(Vector3d p1,Vector3d p2,Vector3d p3,Vector3d p4,Vector3d pa,Vector3d pb) { + Vector3d p13 = new Vector3d(); + Vector3d p43 = new Vector3d(); + Vector3d p21 = new Vector3d(); + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + p13.sub(p1, p3); + p43.sub(p4,p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + p21.sub(p2,p1); + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * mua) / d4343; + + pa.x = p1.x + mua * p21.x; + pa.y = p1.y + mua * p21.y; + pa.z = p1.z + mua * p21.z; + pb.x = p3.x + mub * p43.x; + pb.y = p3.y + mub * p43.y; + pb.z = p3.z + mub * p43.z; + + return true; + } + + public static boolean intersectStraightStraight(Vector3d p1,Vector3d p21,Vector3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) { + Vector3d p13 = new Vector3d(); + + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + + p13.sub(p1, p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + double mua = numer / denom; + double mub = (d1343 + d4321 * mua) / d4343; + + pa.x = p1.x + mua * p21.x; + pa.y = p1.y + mua * p21.y; + pa.z = p1.z + mua * p21.z; + pb.x = p3.x + mub * p43.x; + pb.y = p3.y + mub * p43.y; + pb.z = p3.z + mub * p43.z; + + return true; + } + + /** + * Calculate the line segment PaPb that is the shortest route between + * two lines P1P2 and P3P4. Calculate also the values of mua and mub where + * Pa = P1 + mua (P2 - P1) + * Pb = P3 + mub (P4 - P3) + * @param p1 + * @param p21 + * @param p3 + * @param p43 + * @param pa + * @param pb + * @param mu + * @return + */ + public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) { + Vector3d p13 = new Vector3d(); + + double d1343,d4321,d1321,d4343,d2121; + double numer,denom; + double EPS = 0.001; + p13.sub(p1, p3); + if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) + return false; + if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) + return false; + + d1343 = p13.dot(p43); + d4321 = p43.dot(p21); + d1321 = p13.dot(p21); + d4343 = p43.lengthSquared(); + d2121 = p21.lengthSquared(); + + denom = d2121 * d4343 - d4321 * d4321; + if (Math.abs(denom) < EPS) + return false; + numer = d1343 * d4321 - d1321 * d4343; + + mu[0] = numer / denom; + mu[1] = (d1343 + d4321 * mu[0]) / d4343; + + pa.x = p1.x + mu[0] * p21.x; + pa.y = p1.y + mu[0] * p21.y; + pa.z = p1.z + mu[0] * p21.z; + pb.x = p3.x + mu[1] * p43.x; + pb.y = p3.y + mu[1] * p43.y; + pb.z = p3.z + mu[1] * p43.z; + + return true; + } + + public static AxisAngle4d getFromEuler2(Vector3d euler) { + AxisAngle4d aa = new AxisAngle4d(); + aa.angle = euler.length(); + Vector3d normal = new Vector3d(euler); + if (aa.angle > EPS) { + normal.normalize(); + aa.x = normal.x; + aa.y = normal.y; + aa.z = normal.z; + } else { + aa.x = 1.0; + aa.y = 0.0; + aa.z = 0.0; + } + + return aa; + } + + public static Vector3d getEuler(AxisAngle4d aa) { + Vector3d euler = new Vector3d(aa.x,aa.y,aa.z); + euler.scale(aa.angle); + return euler; + } + + public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) { + // p' = q * p * q' + double tw = - q.x*in.x - q.y*in.y - q.z*in.z; + double tx = q.w*in.x + q.y*in.z - q.z*in.y; + double ty = q.w*in.y - q.x*in.z + q.z*in.x; + double tz = q.w*in.z + q.x*in.y - q.y*in.x ; + + //temp * q' -> x = -x, y = -y z = -z + //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z; + out.x = -tw*q.x + tx*q.w - ty*q.z + tz*q.y; + out.y = -tw*q.y + tx*q.z + ty*q.w - tz*q.x; + out.z = -tw*q.z - tx*q.y + ty*q.x + tz*q.w; + } + + public static void getMatrix(Quat4d quat, Matrix3d m) { + m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z); + m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z); + m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y); + m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z); + m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z); + m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x); + m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y); + m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x); + m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y); + + } + + public static void getQuat(Matrix3d mat, Quat4d quat) { + double tr = mat.m00 + mat.m11 + mat.m22; + if (tr > 0.0) { + double s = Math.sqrt(tr + 1.0); + quat.w = 0.5 * s; + s = 0.5 / s; + quat.x = (mat.m21 - mat.m12) * s; + quat.y = (mat.m02 - mat.m20) * s; + quat.z = (mat.m10 - mat.m01) * s; + } else { + int i = 0, j, k; + if (mat.m11 > mat.m00) + i = 1; + if (mat.m22 > mat.getElement(i, i)) + i = 2; + int nxt[] = { 1, 2, 0 }; + + j = nxt[i]; + k = nxt[j]; + + double s = Math + .sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat + .getElement(k, k))) + 1.0); + + double q[] = new double[3]; + q[i] = s * 0.5; + + if (Math.abs(s) > 0.001) + s = 0.5 / s; + + quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s; + q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s; + q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s; + + quat.x = q[0]; + quat.y = q[1]; + quat.z = q[2]; + } + } + + + /* + * Cohen-Sutherland + */ + + private static final int IN = 0; + private static final int LEFT = 1; + private static final int RIGHT = 2; + private static final int BOTTOM = 4; + private static final int TOP = 8; + + + private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) { + int code = IN; + if (p1.x < min.x) + code |= LEFT; + else if (p1.x > max.x) + code |= RIGHT; + if (p1.y < min.y) + code |= BOTTOM; + else if (p1.y > max.y) + code |= TOP; + return code; + } + + public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) { + while (true) { + int o1 = bitcode(p1, min, max); + int o2 = bitcode(p2, min, max); + int and = o1 & o2; + int or = o1 | o2; + if (and != IN) { + return false; + } + if (or == IN) { + r1.set(p1); + r2.set(p2); + return true; + } + if (o1 == IN) { + Vector2f t = p1; + p1 = p2; + p2 = t; + int t2 = o1; + o1 = o2; + o2 = t2; + } + if ((o1 & TOP) != IN) { + float t = (max.y - p1.y) / (p2.y - p1.y); + p1.x += t * (p2.x - p1.x); + p1.y = max.y; + } else if ((o1 & BOTTOM) != IN) { + float t = (min.y - p1.y) / (p2.y - p1.y); + p1.x += t * (p2.x - p1.x); + p1.y = min.y; + } else if ((o1 & LEFT) != IN) { + float t = (min.x - p1.x) / (p2.x - p1.x); + p1.y += t * (p2.y - p1.y); + p1.x = min.x; + } else if ((o1 & RIGHT) != IN) { + float t = (max.x - p1.x) / (p2.x - p1.x); + p1.y += t * (p2.y - p1.y); + p1.x = max.x; + } else { + throw new RuntimeException("Error in clipping code"); + } + } + + } + + public static double square(double d) { + return d * d; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java new file mode 100644 index 00000000..bbba901f --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ResourceTextureCache.java @@ -0,0 +1,220 @@ +package org.simantics.proconf.g3d.base; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.graphics.ImageData; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.ImageTexture; +import org.simantics.proconf.g3d.stubs.TextureCoordinateGenerator; +import org.simantics.proconf.image.interfaces.IImage; +import org.simantics.proconf.image.interfaces.IImageFactory; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.gfx.ImageUtils; +import org.simantics.utils.ui.gfx.PixelDimension; + +import com.jme.image.Image; +import com.jme.image.Texture; +import com.jme.util.TextureManager; + +/** + * Caches resource based textures. + * TODO : use queries to update textures, now textures are read once and cannot be updated + * TODO : either use shared context or use separate cache for each editor + * TODO : ShapeNode implementation won't use release texture yet + * TODO : Texture is released when reference count goes to zero; we probably want to wait for a while before texture is released because it might be used again. + * + * @author Marko Luukkainen + * + */ +public class ResourceTextureCache { + + public static PixelDimension DEFAULT_SIZE = new PixelDimension(128,128); + + private static ResourceTextureCache instance = new ResourceTextureCache(); + + private Map images = new HashMap(); + private Map imageReferences = new HashMap(); + + private Map textures = new HashMap(); + private Map textureReferences = new HashMap(); + + + private ResourceTextureCache() { + + } + + public Texture loadTexture(Graph g, Resource res) { + Texture t = textures.get(res); + if (t == null) { + ImageTexture it = new ImageTexture(g,res); + org.simantics.image.stubs.Image pattern = it.getImage(); + Image image = loadImage(g, pattern.getResource()); +// image.getData().rewind(); +// while (image.getData().hasRemaining()) +// image.getData().put((byte)(Math.random()*256.0 - 127.0)); + if (image == null) { + return null; + } + t = new Texture(); + t.setImage(image); + + //t = TextureManager.loadTexture(image, Texture.MM_LINEAR, Texture.FM_LINEAR); +// t.setImageLocation(res.toString()); +// URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path("data/texture/clouds.png"),null); +// t = TextureManager.loadTexture(url, Texture.MM_LINEAR, Texture.FM_LINEAR); + + t.setFilter(com.jme.image.Texture.FM_LINEAR); + t.setMipmapState(com.jme.image.Texture.MM_LINEAR); + t.setApply(Texture.AM_COMBINE); + t.setCombineFuncRGB(Texture.ACF_MODULATE); + t.setCombineScaleRGB(2.f); + + //t.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); + + TextureCoordinateGenerator gen = it.getTextureCoordinateGenerator(); + setTextureCoordGenerator(gen, t); + textures.put(res, t); + } + addTextureReference(res); + return t; + } + + public void releaseTexture(Graph g, Resource res) { + Integer i = textureReferences.get(res); + if (i != null) { + i = i - 1; + if (i == 0) { + Texture t = textures.get(res); + ImageTexture it = new ImageTexture(g,res); + org.simantics.image.stubs.Image pattern = it.getImage(); + releaseImage(pattern.getResource()); + t.setImage(null); + textureReferences.remove(res); + //FIXME : release the texture + } else { + textureReferences.put(res, i); + } + + } else { + throw new RuntimeException("Cannot released texture that does not exist " + res); + } + } + + public Image loadImage(Graph g, Resource res) { + Image image = images.get(res); + if (image == null) { + org.simantics.image.stubs.Image pattern = new org.simantics.image.stubs.Image(g,res); + IImageFactory f = org.simantics.proconf.image.ImageUtils.getImageFactoryForResource(g,pattern.getResource()); + try { + IImage p = f.createImageForResource(g,pattern.getResource()); + PixelDimension pd = p.getDimensions().getPixelDimension(); + if (pd==null) pd = DEFAULT_SIZE; + ImageData data = p.rasterize(pd.getWidth(), pd.getHeight()); + image = getImage(data); + images.put(res, image); + + } catch (Exception e) { + ErrorLogger.defaultLogError("Cannor create pattern texture for resource " + pattern, e); + return null; + } + } + addImageReference(res); + return image; + + } + + private void addTextureReference(Resource res) { + Integer i = textureReferences.get(res); + if (i != null) { + imageReferences.put(res, i + 1); + } else { + imageReferences.put(res, 1); + } + } + + private void addImageReference(Resource res) { + Integer i = imageReferences.get(res); + if (i != null) { + imageReferences.put(res, i + 1); + } else { + imageReferences.put(res, 1); + } + } + + public void releaseImage(Resource res) { + Integer i = imageReferences.get(res); + if (i != null) { + i = i - 1; + if (i == 0) { + Image image = images.get(res); + image.getData().clear(); + image.setData(null); + images.remove(res); + imageReferences.remove(res); + } else { + imageReferences.put(res, i); + } + } else { + throw new RuntimeException("Cannot release image that does not exist."); + } + } + + public static ResourceTextureCache getInstance() { + return instance; + } + + private static Image getImage(ImageData imageData) { + int width = imageData.width; + int height = imageData.height; + int type = 0; + + int components = 3; + + type = Image.RGB888; + if (imageData.alphaData != null) { + type = Image.RGBA8888; + components = 4; + } + + ByteBuffer buf = ByteBuffer.allocateDirect(components * width * height); + ImageUtils.convertToRGBA(imageData, buf); + return new Image(type,width,height,buf); + } + + + public static void setTextureCoordGenerator(TextureCoordinateGenerator gen, com.jme.image.Texture texture) { + if (gen == null) + return ; + + //g3dResource. + if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_sphere)) + texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_SPHERE); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_eyelinear)) + texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_EYE_LINEAR); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_objectlinear)) + texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_OBJECT_LINEAR); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_normal)) + ErrorLogger.getDefault().logWarning("JME doesn't support normal texture coordinate generation", null); + else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_reflection)) + ErrorLogger.getDefault().logWarning("JME doesn't support reflection texture coordinate generation", null); + else + ErrorLogger.getDefault().logWarning("Unsupported TexGen type " + gen.getName(), null); + } + + public void clear() { + for (Image i : images.values()) + i.setData(null); + for (Texture t : textures.values()) + t.setImage(null); + imageReferences.clear(); + textureReferences.clear(); + images.clear(); + textures.clear(); + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java new file mode 100644 index 00000000..e2d02874 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapter.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +public interface ScenegraphAdapter { + + /** + * Disposes the adapter + */ + public void dispose(); + + /** + * Returns scene-graph node of the resource + * @param resource + * @return + */ + public IGraphicsNode getNode(Resource resource); + + /** + * Returns scene-graph node of the resource + * @param thing + * @return + */ + public IGraphicsNode getNode(IEntity thing); + + /** + * Returns node (resource) for the uid. + * @param uid + * @return the node (resource) + */ + public Resource getNodeResource(String uid); + + /** + * @return all nodes in the scene-graph + */ + public Collection getNodes(); + + /** + * Returns uid of the node. + * @param nodeResource + * @return + */ + public String getNodeUID(Resource nodeResource); + + public JmeRenderingComponent getRenderingComponent(); + + public Node getRoot(); + + public IGraphicsNode getRootNode(); + + public Resource getRootResource(); + + /** + * Returns true if the scene-graph contains the node + * @param resource + * @return + */ + public boolean hasNode(Resource resource); + + /** + * Checks if the view has been changed (and needs redrawing). + * @return + */ + public boolean isChanged(); + + /** + * Checks if any geometries needs updating + * @return + */ + public boolean needsUpdateGeometry(); + + /** + * + * @param changed + */ + public void setChanged(boolean changed); + + /** + * Sets the root node of the scene-graph + * @param rootNode + */ + public void setRootNode(G3DNode rootNode); + + /** + * Updates requested geometries. + * + * @param graph + */ + public void updateGeometry(Graph graph); + + /** + * Updates node's geometry + * @param node + */ + public void updateGeometry(IGeometryNode node); + + /** + * Updates node's geometry + * @param nodeResource + */ + public void updateGeometry(Resource nodeResource); + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java new file mode 100644 index 00000000..43a53a27 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ScenegraphAdapterImpl.java @@ -0,0 +1,828 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.simantics.db.AbstractQuery; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.queries.IGraphQuery; +import org.simantics.db.queries.IQuery; +import org.simantics.db.queries.IQueryListener; +import org.simantics.db.utils.transaction.MergingTransactionRunner; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.Property; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.RootGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.datastructures.BijectionMap; + +import com.jme.scene.Node; + + +/** + * Scene-graph adapter : + * 1. Adapts graph change events into changes in actual scene-graph nodes. + * 2. Handles instantiating and disposing of Scene-graph nodes. + * 3. + * + * @author Marko Luukkainen + * + */ +public abstract class ScenegraphAdapterImpl implements ScenegraphAdapter { + + protected static boolean DEBUG = false; + + private RootGraphicsNode root; + private HashMap scenegraphQueries = new HashMap(); + private HashMap propertyQueries = new HashMap(); + private HashMap transformationQueries = new HashMap(); + private HashMap abstractGraphicsNodes = new HashMap(); + protected Queue geometryUpdates = new ConcurrentLinkedQueue(); + + private BijectionMap nameMap = new BijectionMap(); + + protected JmeRenderingComponent component; + + protected boolean viewChanged = false; + + protected Session session; + + private MergingTransactionRunner transactionRunner; + + public ScenegraphAdapterImpl(Session session, JmeRenderingComponent component) { + this.component = component; + this.session = session; + transactionRunner = new MergingTransactionRunner(session,true); + } + + + @Override + public JmeRenderingComponent getRenderingComponent() { + return component; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#setRootNode(fi.vtt.simantics.g3d.stubs.G3DNode) + */ + public void setRootNode(G3DNode rootNode) { + addSubnodeListener(rootNode); + root = new RootGraphicsNode(component,rootNode.getResource()); + abstractGraphicsNodes.put(rootNode.getResource(),root); + G3DTools.reloadCache(rootNode.getGraph(),root.getResource()); + addRootPropertyListener(rootNode.getGraph()); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#needsUpdateGeometry() + */ + public boolean needsUpdateGeometry() { + return geometryUpdates.size() > 0; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#updateGeometry(fi.vtt.simantics.g3d.scenegraph.IGeometryNode) + */ + public void updateGeometry(IGeometryNode node) { + geometryUpdates.add(node); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#updateGeometry(fi.vtt.simantics.db.connection.Resource) + */ + public void updateGeometry(Resource nodeResource) { + geometryUpdates.add((IGeometryNode)abstractGraphicsNodes.get(nodeResource)); + } + + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#updateGeometry(fi.vtt.simantics.db.connection.Graph) + */ + public synchronized void updateGeometry(Graph graph) { + if (geometryUpdates.size() > 0) { + for (IGeometryNode n : geometryUpdates) { + try { + n.updateGeometry(graph); + if (DEBUG) System.out.println("ScenegraphAdapterImpl: geometryUpdated " + n.getResource()); + } catch (Exception e) { + ErrorLogger.defaultLogError("Failed to update geometry of node" + n.getResource(), e); + } + } + geometryUpdates.clear(); + viewChanged = true; + //if (DEBUG) System.out.println("ScenegraphAdapterImpl: geometryUpdated"); + } + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNodes() + */ + public Collection getNodes() { + return abstractGraphicsNodes.values(); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNode(fi.vtt.simantics.db.connection.Resource) + */ + public IGraphicsNode getNode(Resource resource) { + return abstractGraphicsNodes.get(resource); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getRootNode() + */ + public IGraphicsNode getRootNode() { + return getNode(getRootResource()); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNode(fi.vtt.simantics.layer0.utils.IEntity) + */ + public IGraphicsNode getNode(IEntity IEntity) { + return abstractGraphicsNodes.get(IEntity.getResource()); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNodeResource(java.lang.String) + */ + public Resource getNodeResource(String uid) { + return nameMap.getLeft(uid); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getNodeUID(fi.vtt.simantics.db.connection.Resource) + */ + public String getNodeUID(Resource nodeResource) { + String name = nameMap.getRight(nodeResource); + if (name == null) { + //name = UUID.randomUUID().toString(); + name = Long.toString(nodeResource.getResourceId()); + nameMap.map(nodeResource, name); + } + return name; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#hasNode(fi.vtt.simantics.db.connection.Resource) + */ + public boolean hasNode(Resource resource) { + return abstractGraphicsNodes.containsKey(resource); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getRootResource() + */ + public Resource getRootResource() { + if (root == null) + return null; + return root.getResource(); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#getRoot() + */ + public Node getRoot() { + return root.getGroup(); + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#dispose() + */ + public void dispose() { + Set shapes = new HashSet(abstractGraphicsNodes.keySet()); + for (Resource r : shapes) { + removeNode(r); + } + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#isChanged() + */ + public boolean isChanged() { + return viewChanged; + } + + /* (non-Javadoc) + * @see fi.vtt.simantics.g3d.scenegraph.IScenegraphAdapter#setChanged(boolean) + */ + public void setChanged(boolean changed) { + viewChanged = changed; + } + + + /** + * Instantiates Listener that listens hierarchy changes in the node (subnode + * added and/or removed) + * + * @param node + * @return + */ + protected abstract ScenegraphQuery newSubnodeListener(G3DNode node); + + protected void addSubnodeListener(G3DNode node) { + if (DEBUG) System.out.println("ScenegraphAdapter.addSubnodeListener( " + node.getResource() + " )"); + ScenegraphQuery q = newSubnodeListener(node); + node.getGraph().performQuery(q); + scenegraphQueries.put(node.getResource(), q); + } + + /** + * Returns propertyQuery for a single scene-graph node. + * @param node + * @return + */ + protected abstract NodePropertyQuery newPropertyListener(G3DNode node); + + /** + * Returns transformationQuery for a single scene-graph node + * @param root + * @return + */ + protected abstract NodeTransformationQuery newTransformationListener(G3DNode root); + + /** + * Returns propertyQuery for the root node. + * May return null if root node has no interesting properties. + * + * Potentially root node could contain lighting settings, and so on... + * + * @param root + * @return + */ + protected abstract NodePropertyQuery newRootPropertyListener(G3DNode root); + + protected void addPropertyListener(G3DNode node) { + if (DEBUG) System.out.println("ScenegraphAdapter.addPropertyListener( " + node.getResource() + " )"); + NodePropertyQuery q = newPropertyListener(node); + node.getGraph().performQuery(q); + propertyQueries.put(node.getResource(),q); + } + + + protected void addTransformationListener(G3DNode node) { + if (DEBUG) System.out.println("ScenegraphAdapter.addPropertyListener( " + node.getResource() + " )"); + NodeTransformationQuery q = newTransformationListener(node); + node.getGraph().performQuery(q); + transformationQueries.put(node.getResource(),q); + } + + protected void addRootPropertyListener(Graph g) { + G3DNode node = root.getG3DNode(g); + if (DEBUG) System.out.println("ScenegraphAdapter.addRootPropertyListener( " + node.getResource() + " )"); + NodePropertyQuery q = newRootPropertyListener(node); + if (q == null) + return; + node.getGraph().performQuery(q); + propertyQueries.put(node.getResource(),q); + } + + /** + * Instantiates a new scene-graph node + * + * @param parent the parent of the new node. + * @param node the new node. + * @return + */ + protected abstract IGraphicsNode instantiateNode(IGraphicsNode parent, G3DNode node); + + + /** + * Adds node into scene-graph + * @param parent the parent of the node + * @param r resource of the node + * @return created scene-graph node + */ + protected IGraphicsNode addNode(IEntity parent, IEntity r) { + if (!r.isInstanceOf(Resources.g3dResource.G3DNode)) { + ErrorLogger.defaultLogError("Trying to add node into scenegraph that is not instance of graphicsnode " + r,new Exception("ASSERT!")); + return null; + } + if (parent.equals(r)) { + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") adding node to itself?!"); + ErrorLogger.defaultLogError("Adding scnegraphnode " + r.getResource().getResourceId() + " to itself!", new Exception("ASSERT!")); + return abstractGraphicsNodes.get(r); + } + + if (abstractGraphicsNodes.containsKey(r)) { + + IGraphicsNode inView = abstractGraphicsNodes.get(r); + if (inView.getParent() == null) { + //if graphicsNode has no parent it must be the root node + ErrorLogger.defaultLogError("Trying to add rootnode into scenegraph " + r, null); + return null; + } + if (parent.equals(inView.getParent().getResource())) { + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") already in view"); + return inView; + } else { + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") already in view, but has different parent, current parent is ("+inView.getParent().getResource()+") and node is added to ("+parent+") -> removing from old parent and inserting to new"); + removeNode(inView.getParent().getResource(),r.getResource()); + } + } + + G3DNode node = new G3DNode(r); + + IGraphicsNode mo; + IGraphicsNode parentNode = abstractGraphicsNodes.get(parent); + if (parentNode == null) { + if (DEBUG) System.out.println("No graphicsnode for (" + parent.getResource().getResourceId() + ")"); + return null; + } else { + mo = instantiateNode(parentNode, node); + if (mo == null) { + ErrorLogger.defaultLogError("Could not instantiate scenegraph node for " + r.getResource().getResourceId(), null); + return null; + } + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.addNodeP(" + r.getResource().getResourceId() + ") added to parent (" + parent.getResource().getResourceId() + ") " + mo.getClass()); + } + addSubnodeListener(node); + addPropertyListener(node); + addTransformationListener(node); + + abstractGraphicsNodes.put(r.getResource(), mo); + + + + // FIXME : this is a hack to fix transformations of instantiated nodes +// if (graph.getCurrentTransaction() != null) { +// try { +// G3DTools.propagateWorldTransformChange(parentNode +// .getG3DNode()); +// graph.commitChanges(CommitMessage.CHANGE_MESSAGE); +// // G3DNodeTools.transformationUpdate(graph, r.getId()); +// } catch (Exception e) { +// ErrorLogger.defaultLogError(e); +// } +// } + + + return mo; + } + + /** + * This is used only when view is disposed! + * + * @param r + */ + private void removeNode(Resource r) { + NodeTransformationQuery tq = transformationQueries.get(r); + //StructuralChangeMonitor monitor = monitors.getLeft(r); + if (tq == null) { + if (abstractGraphicsNodes.containsKey(r)) { + // root node has no monitor (no transformation to monitor) + //System.out.println("ThreeDimensionalEditorBase.removeNode(" + r + ") node has no monitor, but has node in scenegraph"); + abstractGraphicsNodes.remove(r); + if(scenegraphQueries.get(r) != null) { + scenegraphQueries.get(r).dispose(); + scenegraphQueries.remove(r); + } + } else { + //System.out.println("ThreeDimensionalEditorBase.removeNode(" + r + ") not in view"); + } + return; + } + // remove listeners + propertyQueries.remove(r).dispose(); + transformationQueries.remove(r).dispose(); + scenegraphQueries.get(r); + scenegraphQueries.remove(r).dispose(); + // remove children + IGraphicsNode node = abstractGraphicsNodes.get(r); + ArrayList children = new ArrayList(node.getChildren()); + for (IGraphicsNode n : children) { + removeNode(n.getResource()); + } + // remove the node + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNode(" + r + ") removed"); + + node.dispose(); + abstractGraphicsNodes.remove(r); + + } + + /** + * Removes a scene-graph node. + * @param parent the parent of the node + * @param r the node. + */ + protected void removeNode(Resource parent,Resource r) { + NodePropertyQuery q = propertyQueries.get(r); + if (q == null) { + assert(!abstractGraphicsNodes.containsKey(r)); + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNodeP(" + r + ") not in view"); + return; + } + + IGraphicsNode node = abstractGraphicsNodes.get(r); + Resource rParent = node.getParent().getResource(); + if (!rParent.equals(parent)) { + // this event may happen, depending of the order of events in transaction + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNodeP(" + r + ") trying to remove from wrong parent current ("+rParent+") remove parentnode null("+parent+")"); + return; + } + // removing listeners + propertyQueries.remove(r).dispose(); + transformationQueries.remove(r).dispose(); + scenegraphQueries.remove(r).dispose(); + // remove node's children + ArrayList children = new ArrayList(node.getChildren()); + for (IGraphicsNode n : children) { + removeNode(r,n.getResource()); + } + if (DEBUG) System.out.println("ThreeDimensionalEditorBase.removeNodeP(" + r + ") from ("+parent+")"); + // remove the node + + abstractGraphicsNodes.remove(r); + if (geometryUpdates.contains(node)) { + geometryUpdates.remove(node); + } + node.dispose(); + } + + + /** + * Query that tracks changes in resources. + * + * @author Marko Luukkainen + * + */ + public abstract class NodeQuery extends AbstractQuery{ + protected Resource nodeResource; + private boolean disposed = false; + private IQueryListener listener; + //private OverridingTransactionRunner runner; + + + public NodeQuery(Resource r) { + this.nodeResource = r; + //runner = new OverridingTransactionRunner(session,true); + + } + + protected abstract Object compute2(Graph graph); + + @Override + public Object performQuery(Graph graph) { + if (disposed) return null; + return compute2(graph); + } + + /** + * + * @param oldResult result of the query before the change. + * @param newResult result of the query after the change. + */ + public abstract boolean updated(Graph graph, Object oldResult, Object newResult); + + @Override + public int getType() { + return IQuery.SCHEDULED_UPDATE; + } + + @Override + public void resultChangedRaw(final Object oldResult, final Object newResult) { + if (disposed) + throw new RuntimeException("Updating disposed query"); //return; + transactionRunner.run(new GraphRequestAdapter() { + //session.asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + if (!disposed) { + if (oldResult == IQueryListener.NO_VALUE) + updated(g, null, newResult); + else + updated(g, oldResult, newResult); + } + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + + @Override + public boolean equalsQuery(IGraphQuery other) { + return nodeResource.equals(((NodeQuery)other).nodeResource); + } + + @Override + final public int hash() { + return nodeResource.hashCode(); + } + + + /** + * Disposes the query + */ + public void dispose() { + disposed = true; + if (DEBUG) System.out.println("NodeQuery " + nodeResource + " disposed()" + " " + this.getClass()); + } + + //public abstract NodeQuery instantiateQuery(Resource node); + //public abstract void attach(); + + @Override + public boolean isDisposed() { + return disposed; + } + + @Override + public IQueryListener getListener() { + if (listener == null) { + listener = new IQueryListener() { + @Override + public boolean isDisposed() { + return NodeQuery.this.disposed; + } + + @Override + public void resultChangedRaw(Object oldResult, Object newResult) { + NodeQuery.this.resultChangedRaw(oldResult, newResult); + } + }; + } + return listener; + } + + } + + /** + * + * Query that tracks changes in scene-graph structure (parent/child relationships). + * + * @author Marko Luukkainen + * + */ + public abstract class ScenegraphQuery extends NodeQuery { + + List added = new ArrayList(); + List removed = new ArrayList(); + + private boolean initialized; + + public ScenegraphQuery(Resource nodeResource) { + super(nodeResource); + initialized = false; + if(DEBUG)System.out.println("ScenegraphQuery created for " + nodeResource); + } + + @Override + public List compute2(Graph g) { + IEntity node = EntityFactory.create(g,nodeResource); + Collection children = node.getRelatedObjects(Resources.g3dResource.HasChild); + List list = new ArrayList(); + for (IEntity n: children) + list.add(n.getResource()); + if (DEBUG) System.out.println("ScenegraphQuery " + nodeResource + " has " + list.size() + " children"); + return list; + } + + @SuppressWarnings("unchecked") + @Override + public boolean updated(Graph graph, Object oldResult, Object newResult) { + List oldChildren; + if (oldResult != null) + oldChildren = (List)oldResult; + else + oldChildren = new ArrayList(); + List newChildren = (List)newResult; + + if (DEBUG) System.out.println("ScenegraphQuery " + nodeResource + " updated: had " + oldChildren.size() + " children, but now has " + newChildren.size() + " children"); + added.clear(); + removed.clear(); + if (initialized) { + for (Resource r : oldChildren) + if (!newChildren.contains(r)) + removed.add(r); + for (Resource r : newChildren) + if (!oldChildren.contains(r)) + added.add(r); + for (Resource r : removed) { + if (DEBUG) + System.out.println("ScenegraphQuery " + nodeResource + + " removed " + r); + removeNode(nodeResource, r); + } + if (added.size() > 0) { + G3DNode parent = new G3DNode(graph, nodeResource); + /* + * try { + * + * G3DTools.propagateTransformChange(parent); } catch + * (Exception e) { ErrorLogger.defaultLogError(e); } + */ + for (Resource r : added) { + IEntity e = EntityFactory.create(graph, r); + G3DTools.propagateLocalTransformChange(parent, e); + IGraphicsNode n = addNode(parent, e); + shapeAdded(graph, n); + } + } + return (added.size() > 0 || removed.size() > 0); + } else { + // when query is run for the first time, we can assume that transformations are correct. + initialized = true; + for (Resource r : newChildren) + added.add(r); + if (added.size() > 0) { + G3DNode parent = new G3DNode(graph, nodeResource); + for (Resource r : added) { + IEntity e = EntityFactory.create(graph, r); + IGraphicsNode n = addNode(parent, e); + shapeAdded(graph, n); + } + return true; + } + return false; + } + + } + + + /** + * This method is run after a node is added to scene-graph. + * + * @param graph Graph of the current transaction. + * @param node the newly added scene-graph node + */ + public abstract void shapeAdded(Graph graph,IGraphicsNode node); + +// @Override +// public void attach() { +// scenegraphQueries.put(nodeResource, this); +// } + + + } + + /** + * Tracks changes in scene-graph nodes' properties + * + * @author Marko Luukkainen + * + */ + public abstract class NodePropertyQuery extends NodeQuery { + + private boolean initialized; + + public NodePropertyQuery(Resource nodeResource) { + super(nodeResource); + initialized = false; + if(DEBUG)System.out.println("NodePropertyQuery created for " + nodeResource); + } + + @Override + public List compute2(Graph g) { + IEntity t = EntityFactory.create(g,nodeResource); + + Collection properties = t.getRelatedProperties(Resources.g3dResource.HasNonTransformation); + List propertyValues = new ArrayList(); + p(properties,propertyValues); + + return propertyValues; + } + + private void p(Collection properties, List propertyValues) { + for (Property p : properties) { + Collection subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty); + if (subProperties.size() != 0) { + p(subProperties,propertyValues); + } + if (p.hasValue()){ + propertyValues.add(p.getValue()); + } + } + } + + @Override + public boolean updated(Graph graph, Object oldResult, Object newResult) { + if (initialized) { + if (DEBUG) System.out.println("NodePropertyQuery changed " + nodeResource + " " + abstractGraphicsNodes.size()); + IGraphicsNode mo = abstractGraphicsNodes.get(nodeResource); + if (mo == null) { + if (DEBUG) System.out.println("NodePropertyQuery invalid change " + nodeResource + " " + abstractGraphicsNodes.size()); + ErrorLogger.defaultLogError("Got update from resource " + nodeResource + " but its not part of the scenegraph", null); + dispose(); + return false; + } + shapeUpdated(graph,mo); + return true; + } else { + initialized = true; + return false; + } + } + + + /** + * This method is run when a scene-graph node is changed. + * + * @param shape the changed node + */ + public abstract void shapeUpdated(Graph graph,IGraphicsNode shape); + +// @Override +// public void attach() { +// propertyQueries.put(nodeResource, this); +// } + + } + + public abstract class NodeTransformationQuery extends NodeQuery { + + private boolean initialized; + + public NodeTransformationQuery(Resource nodeResource) { + super(nodeResource); + initialized = false; + if(DEBUG)System.out.println("NodeTransformationQuery created for " + nodeResource); + } + + @Override + public List compute2(Graph g) { + IEntity t = EntityFactory.create(g,nodeResource); + + Collection properties = t.getRelatedProperties(Resources.g3dResource.HasTransformation); + + List propertyValues = new ArrayList(); + p(properties,propertyValues); + return propertyValues; + + } + + private void p(Collection properties, List propertyValues) { + for (Property p : properties) { + Collection subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty); + if (subProperties.size() != 0) { + p(subProperties,propertyValues); + } + if (p.hasValue()){ + propertyValues.add(p.getValue()); + } + } + } + + @Override + public boolean updated(Graph graph,Object oldResult, Object newResult) { + if (initialized) { + if (DEBUG) System.out.println("NodeTransformationQuery changed " + nodeResource + " " + abstractGraphicsNodes.size()); + + G3DTools.transformationUpdate(graph, nodeResource); + + IGraphicsNode mo = abstractGraphicsNodes.get(nodeResource); + if (mo == null) { + if (DEBUG) System.out.println("NodeTransformationQuery invalid change " + nodeResource + " " + abstractGraphicsNodes.size()); + ErrorLogger.defaultLogError("Got update from resource " + nodeResource + " but its not part of the scenegraph", null); + dispose(); + return false; + } + shapeUpdated(graph,mo); + return true; + } else { + initialized = true; + return false; + } + } + + + /** + * This method is run when a scene-graph node is changed. + * + * @param shape the changed node + */ + public abstract void shapeUpdated(Graph graph,IGraphicsNode shape); + +// @Override +// public void attach() { +// transformationQueries.put(nodeResource, this); +// } + + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java new file mode 100644 index 00000000..22b6bc6e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/SelectionAdapter.java @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.g3d.gizmo.Gizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; + +import com.jme.intersection.PickData; +import com.jme.intersection.PickResults; +import com.jme.intersection.TrianglePickResults; +import com.jme.math.Ray; + +import org.simantics.db.Resource; + +/** + * Manages highlighting and selecting of objects. + * + * @author Marko Luukkainen + * + */ +public abstract class SelectionAdapter implements ISelectionProvider{ + + protected ScenegraphAdapter adapter; + + private Gizmo currentGizmo = null; + + public SelectionAdapter(ScenegraphAdapter adapter) { + this.adapter = adapter; + } + + public enum SelectionType { + SET, MODIFY + }; + + protected SelectionType mouseClickType = SelectionType.SET; + + public SelectionType getSelectionType() { + return mouseClickType; + } + + public void setSelectionType(SelectionType type) { + mouseClickType = type; + } + + public void setCurrentGizmo(Gizmo gizmo) { + currentGizmo = gizmo; + } + + /** + * Lists all selected objects + *

+ * Selection may contain objects that are not in this view: those are NOT + * returned + *

+ * + * @return + */ + public List getSelectedObjects() { + return getSelectedObjects(selection); + } + + /** + * Lists all highlighted objects. + *

+ * Typically there may be only one highlighted object. + *

+ * @return + */ + public List getHighlightedObjects() { + return getSelectedObjects(interactiveSelection); + } + + /** + * Lists all selected objects + *

+ * Selection may contain objects that are not in this view: those are NOT + * returned + *

+ * + * @return + */ + public List getInteractiveSelectedObjects() { + return getSelectedObjects(interactiveSelection); + } + + /** + * Lists all selected objects + *

+ * Selection may contain objects that are not in this view: those are NOT + * returned + *

+ * + * @return + */ + protected List getSelectedObjects(StructuredResourceSelection selection) { + List l = new ArrayList(); + Iterator i = selection.iterator(); + while (i.hasNext()) { + Resource s = i.next(); + IGraphicsNode shape = adapter.getNode(s); + if (shape != null) + l.add(shape); + + } + return l; + } + + /** + * Return selected objects + *

+ * May contain objects that are NOT in this view + *

+ * + * @return + */ + public List getSelectedResources() { + List l = new ArrayList(); + Iterator i = selection.iterator(); + while (i.hasNext()) { + Resource s = (Resource) i.next(); + l.add(s); + + } + return l; + } + + private ArrayList processed = new ArrayList(); + + private class ExtTrianglePickResults extends TrianglePickResults { + public ExtTrianglePickResults() { + this.setCheckDistance(true); + } + + public void processPick() { + processed.clear(); + if (getNumber() > 0) { + for (int j = 0; j < getNumber(); j++) { + PickData pData = getPickData(j); + ArrayList tris = pData.getTargetTris(); + if (tris != null && tris.size() > 0) { + processed.add(pData); + } + } + + } + + } + } + + private PickResults result = new ExtTrianglePickResults(); + + + private void pickPrefix(String prefix) { + + ArrayList r= new ArrayList(); + for (int i = 0; i < processed.size(); i++) { + PickData pData = processed.get(i); + if (pData.getTargetMesh().getParentGeom().getName().startsWith(prefix)) + r.add(pData); + } + processed = r; + } + + /** + * Updates highlighted objects according to mouse position. + * + * @param mouseRay + */ + public void updateHighlights(Ray mouseRay) { + result.clear(); + adapter.getRenderingComponent().getRoot().calculatePick(mouseRay, result); + if (currentGizmo != null) { + pickPrefix(currentGizmo.getPickPrefix()); + } + doHighlightPick(processed); + } + + /** + * Picks highlighted objects + */ + public void pickHighlighted() { + doPick(processed); + } + + /** + * Processes pick. + * @param result + */ + protected void doPick(ArrayList result) { + if (result != null) { + + if (result.size() == 0) { + if (mouseClickType != SelectionType.MODIFY) + updateSelection(new StructuredResourceSelection()); + return; + } + + String nodeName = result.get(0).getTargetMesh().getParentGeom().getName(); + + StructuredResourceSelection s = new StructuredResourceSelection(); + + Resource selectedResource = adapter.getNodeResource(nodeName); + if (adapter.getNode(selectedResource) == null) { + updateSelection(new StructuredResourceSelection()); + return; + //throw new RuntimeException("Picked resource that has no node ?!"); + } + if (mouseClickType == SelectionType.MODIFY) { + ArrayList selected = new ArrayList(getSelectedResources()); + if (selected.contains(selectedResource)) + selected.remove(selectedResource); + else + selected.add(selectedResource); + for (Resource r : selected) + s.add(r); + + } else { + s.add(selectedResource); + } + + updateSelection(s); + } else { + // System.out.println("Picked nothing"); + if (mouseClickType != SelectionType.MODIFY) + updateSelection(new StructuredResourceSelection()); + } + } + + /** + * Processes highlight pick + * @param result + */ + protected void doHighlightPick(ArrayList result) { + if (result != null) { + + if (result.size() == 0) { + updateGizmo(null); + //System.out.println("IPicked nothing"); + updateHighlightSelection(new StructuredResourceSelection()); + return; + } + + String nodeName = result.get(0).getTargetMesh().getParentGeom().getName(); + + updateGizmo(null); + + // System.out.println("hits: " + result); + StructuredResourceSelection s = new StructuredResourceSelection(); + + Resource selectedResource = adapter.getNodeResource(nodeName); + + if (selectedResource == null) { + if (currentGizmo != null && nodeName.startsWith(currentGizmo.getPickPrefix())) { + updateGizmo(nodeName); + } + return; + } + + if (adapter.getNode(selectedResource) != null) + s.add(selectedResource); + + updateHighlightSelection(s); + } else { + updateGizmo(null); + // System.out.println("IPicked nothing"); + updateHighlightSelection(new StructuredResourceSelection()); + } + } + + /** + * Updates gizmo according to picked object + * @param pickName + */ + private void updateGizmo(String pickName) { + if (currentGizmo != null) { + currentGizmo.setSelected(pickName); + if (currentGizmo.isChanged()) { + adapter.setChanged(true); + currentGizmo.setChanged(false); + } + } + } + + + /** + * Contains selection + */ + protected StructuredResourceSelection selection = new StructuredResourceSelection(); + + protected StructuredResourceSelection interactiveSelection = new StructuredResourceSelection(); + + public StructuredResourceSelection getCurrentSelection() { + return selection; + } + + public void setCurrentSelection(StructuredResourceSelection s) { + selection = s; + } + + public StructuredResourceSelection getHighlightSelection() { + return interactiveSelection; + } + + protected void setHighlightSelection(StructuredResourceSelection s) { + interactiveSelection = s; + } + + private ArrayList selectionChangedListeners = new ArrayList(); + + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + public void addSelectionChangedListener(ISelectionChangedListener listener) { + selectionChangedListeners.add(listener); + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() + */ + public ISelection getSelection() { + return selection; + } + + + + public static StructuredResourceSelection transformSelection(ISelection sel) { + if (sel instanceof StructuredResourceSelection) + return (StructuredResourceSelection)sel; + StructuredResourceSelection res = new StructuredResourceSelection(); + Resource resources[] = ResourceAdaptionUtils.toResources(sel); + for (Resource r : resources) + res.add(r); + return res; + } + + + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + selectionChangedListeners.remove(listener); + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) + */ + public void setSelection(ISelection selection) { + // System.out.println(); + StructuredResourceSelection s = filterSelection(selection); + if (this.selection.equals(s)) + return; + this.selection = s; + adapter.setChanged(true); + setEditorSelection(); + + } + + /** + * Filters selection given with setSelection(ISelection selection) This + * allows impemented editors to modify selection before it's applied into + * this editor + * + * @param s + * @return the filtered selection + */ + protected abstract StructuredResourceSelection filterSelection(ISelection s); + + /** + * Updates visual part of selection event. Use getCurrentSelection() to get + * the selection + */ + public abstract void setEditorSelection(); + + /** + * Updates visual part of selection event. Use getInteractiveSelection() to + * get the selection + */ + protected abstract void setEditorHighlightSelection(); + + /** + * Editor's internal selection update
+ * Sends events to other editors and views about changed selection + * + * @param selection + * @return + */ + public boolean updateSelection(StructuredResourceSelection s) { + if (this.selection.equals(s)) + return false; + + this.selection = s; + adapter.setChanged(true); + fireSelectionChangedEvent(); + setEditorSelection(); + return true; + } + + protected boolean updateHighlightSelection(StructuredResourceSelection s) { + if (interactiveSelection.equals(s)) + return false; + this.interactiveSelection = s; + adapter.setChanged(true); + setEditorHighlightSelection(); + return true; + } + + /** + * Fires selection changed events. + */ + protected void fireSelectionChangedEvent() { + SelectionChangedEvent e = new SelectionChangedEvent(this, this.selection); + for (ISelectionChangedListener l : selectionChangedListeners) + l.selectionChanged(e); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java new file mode 100644 index 00000000..0a04a229 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorBase.java @@ -0,0 +1,741 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorActionBarContributor; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.internal.WorkbenchWindow; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.events.GraphChangeEvent; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.actions.CameraAction; +import org.simantics.proconf.g3d.actions.ContextAction; +import org.simantics.proconf.g3d.actions.InteractiveAction; +import org.simantics.proconf.g3d.base.SelectionAdapter.SelectionType; +import org.simantics.proconf.g3d.common.JmeComposite; +import org.simantics.proconf.g3d.common.JmeSinglePassRenderingComponent; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.dialogs.JMEDialog; +import org.simantics.proconf.g3d.dnd.ShapeDropTarget; +import org.simantics.proconf.g3d.gizmo.Gizmo; +import org.simantics.proconf.g3d.input.InputProvider; +import org.simantics.proconf.g3d.input.SWTInputProvider; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.tools.ScenegraphLockTraverser; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.jface.MenuTools; + +import com.jme.math.Ray; +import com.jme.math.Vector2f; +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; + + +public abstract class ThreeDimensionalEditorBase implements Runnable { + + private Resource inputResource; + + private List editorContributions = new ArrayList(); + + private EditorContribution currentEditorContribution; + + protected List actions = new ArrayList(); + + private List contributionSelectionActions = new ArrayList(); + + protected Composite parent; + + protected ISessionContext sessionContext; + + protected Session session; + + protected ScenegraphAdapter adapter; + + protected SelectionAdapter selectionAdapter; + + protected Action refreshAction; + + protected Action configureJMEAction; + + private Action lockScenegraphAction; + + protected Menu contextMenu; + + private JmeComposite renderingComposite = null; + + protected OrbitalCamera camera = new OrbitalCamera(); + + protected boolean viewChanged = true; + + private InteractiveAction currentAction = null; + + private Gizmo currentGizmo = null; + + private InteractiveAction cameraAction = null; + + private JmeRenderingComponent component = null; + + protected InputProvider input = null; + + protected ShapeDropTarget dropTarget; + +// protected IEditorActionBarContributor actionBarContributor; + protected IActionBars actionBars; + protected IToolBarManager toolBarManager; + protected IMenuManager menuManager; + + public ThreeDimensionalEditorBase(ISessionContext session) { + this.sessionContext = session; + this.session = session.getSession(); + component = new JmeSinglePassRenderingComponent(); + } + + public ThreeDimensionalEditorBase(ISessionContext session, JmeRenderingComponent component) { + this.sessionContext = session; + this.session = session.getSession(); + this.component = component; + } + +// public void setActionBarContributor(IEditorActionBarContributor contributor) { +// actionBarContributor = contributor; +// } + + public void setActionBars(IActionBars actionBars) { + this.actionBars = actionBars; + this.menuManager = actionBars.getMenuManager(); + this.toolBarManager = actionBars.getToolBarManager(); + } + + + + + public ISessionContext getSessionContext() { + return sessionContext; + } + + public Session getSession() { + return session; + } + + /** + * Creates basic UI for ThreeDimenionalEditors. + * Note : inputResource has not been set at this point. + * + * @param graph + * @param parent + */ + public void createControl(Graph graph, Composite parent) { + this.parent = parent; + renderingComposite = new JmeComposite(parent,component); + // add listeners to force repaint on size changes + renderingComposite.getCanvas().addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + viewChanged = true; + } + }); + + + input = new SWTInputProvider(); + + renderingComposite.initGL(); + camera.setCamera(component.getCamera()); + camera.updateCamera(); + makeActions(graph); + hookContextMenu(); + + // provide selection events for properies view + this.adapter = createScenegraphAdapter(); + this.selectionAdapter = createSelectionAdapter(); + + this.selectionAdapter.addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + setCurrentAction(getDefaultAction()); + } + }); + hookDragAndDrop(); + hookInput(); + VisualizationScheduler.getInstance().addVisualization(this); + + if (editorContributions.size() > 0) { + // setActiveEditorContribution(editorContributions.get(0)); + // } else if (editorContributions.size() > 1) { + // create actions for selecting contribution + for (EditorContribution ec : editorContributions) { + final EditorContribution e = ec; + Action a = new Action(e.getName(),Action.AS_RADIO_BUTTON) { + @Override + public void run() { + + setActiveEditorContribution(e); + } + }; + contributionSelectionActions.add(a); + + } + } + + } + + public void addEditorContribution(EditorContribution e) { + if (parent != null) + throw new RuntimeException("Editor contributions must be added before editor is created."); + editorContributions.add(e); + } + + private void initializeEditorContributions(Graph graph) { + for (EditorContribution e : editorContributions) { + e.initialize(graph); + } + if (editorContributions.size() > 0) + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + setActiveEditorContribution(editorContributions.get(0)); + } + }); + } + + + private void hookInput() { + renderingComposite.getCanvas().addKeyListener((SWTInputProvider) input); + renderingComposite.getCanvas().addMouseListener((SWTInputProvider) input); + renderingComposite.getCanvas().addMouseMoveListener((SWTInputProvider) input); + renderingComposite.getCanvas().addMouseTrackListener((SWTInputProvider) input); + renderingComposite.getCanvas().addFocusListener((SWTInputProvider) input); + } + + protected abstract ScenegraphAdapter createScenegraphAdapter(); + protected abstract SelectionAdapter createSelectionAdapter(); + + + public JmeComposite getRenderingComposite() { + return renderingComposite; + } + + public JmeRenderingComponent getRenderingComponent() { + return component; + } + + public ScenegraphAdapter getScenegraphAdapter() { + return adapter; + } + + public SelectionAdapter getSelectionAdapter() { + return selectionAdapter; + } + + public OrbitalCamera getCamera() { + return camera; + } + + public void setViewChanged(boolean b) { + viewChanged = b; + } + + protected void hookContextMenu() { + MenuManager menuMgr = new MenuManager("#PopupMenu"); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + final IMenuManager m = manager; + GraphRequestAdapter r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + ThreeDimensionalEditorBase.this.fillContextMenu(g,m); + return GraphRequestStatus.transactionComplete(); + } + }; + + session.syncRead(r); + + } + }); + + contextMenu = menuMgr.createContextMenu(renderingComposite); + } + + + + protected void fillContextMenu(Graph graph,IMenuManager manager) { + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + + List selected = selectionAdapter.getSelectedResources(); + for (ContextAction action : actions) { + if(action.usable(graph,selected)) { + manager.add(action); + } + } + if (currentEditorContribution != null) { + currentEditorContribution.fillContextMenu(graph, manager, selectionAdapter.getCurrentSelection()); + for (ContextAction action : currentEditorContribution.getActions()) { + if(action.usable(graph,selected)) { + manager.add(action); + } + } + } + + } + + protected void fillLocalToolBar() { + + if (currentEditorContribution != null) + currentEditorContribution.fillLocalToolBar(toolBarManager); + } + + protected void fillLocalPullDown() { + for (Action a : contributionSelectionActions) { + IMenuManager menu = MenuTools.getOrCreate(getMenuID(),"View", menuManager); + menu.add(a); + } + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(refreshAction); + if (configureJMEAction != null) { + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureJMEAction); + } + + MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(lockScenegraphAction); + if (currentEditorContribution != null) + currentEditorContribution.fillLocalPullDown(menuManager); + } + + public String getMenuID() { + return Long.toString(getInputResource().getResourceId()); + } + + protected void makeActions(Graph graph) { + + refreshAction = new Action() { + + public void run() { + GraphRequestAdapter r = new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { +// Stack stack = new Stack(); +// stack.push(adapter.getNode(adapter.getRootResource())); +// while(!stack.isEmpty()) { +// IGraphicsNode node = stack.pop(); +// stack.addAll(node.getChildren()); +// if (node instanceof IGeometryNode) { +// ((IGeometryNode)node).updateGeometry(g); +// } +// } + for (IGraphicsNode node : adapter.getNodes()) + if (node instanceof IGeometryNode) + ((IGeometryNode)node).updateGeometry(g); + viewChanged = true; + return GraphRequestStatus.transactionComplete(); + }; + }; + session.asyncRead(r); + + } + }; + refreshAction.setText("Refresh"); + refreshAction.setToolTipText("Refreshes the visualization"); + refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor( + ISharedImages.IMG_TOOL_UP)); + if (getRenderingComponent() instanceof JmeSinglePassRenderingComponent) { + configureJMEAction = new Action() { + public void run() { + JmeSinglePassRenderingComponent c = (JmeSinglePassRenderingComponent)getRenderingComponent(); + JMEDialog dialog = new JMEDialog(ThreeDimensionalEditorBase.this.parent.getShell()); + c.getDisplaySystem().setCurrent(); + dialog.setBounds(c.isShowBounds()); + dialog.setNormals(c.isShowNormals()); + dialog.setWireframe(c.isShowWireframe()); + ColorRGBA col = c.getDisplaySystem().getRenderer().getBackgroundColor(); + dialog.setFloatColor(new float[]{col.r,col.g,col.b}); + if (dialog.open() == JMEDialog.CANCEL) + return; + c.setShowBounds(dialog.isBounds()); + c.setShowNormals(dialog.isNormals()); + c.setShowWireframe(dialog.isWireframe()); + if (dialog.getFloatColor() != null) { + c.getDisplaySystem().setCurrent(); + c.getDisplaySystem().getRenderer().setBackgroundColor(new ColorRGBA(dialog.getFloatColor()[0],dialog.getFloatColor()[1],dialog.getFloatColor()[2],0.f)); + } + } + }; + configureJMEAction.setText("Configure JME"); + configureJMEAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/wrench.png")); + } + + lockScenegraphAction = new Action("Lock scenegraph",Action.AS_CHECK_BOX) { + public void run() { + new ScenegraphLockTraverser(adapter.getRoot(),this.isChecked()); + } + }; + + cameraAction = new CameraAction(this); + currentAction = cameraAction; + + + } + + public InteractiveAction getDefaultAction() { + return cameraAction; + } + + public void createPickRay(Vector3d o, Vector3d d) { + Ray r = createPickRay(); + o.x = r.origin.x; + o.y = r.origin.y; + o.z = r.origin.z; + d.x = r.direction.x; + d.y = r.direction.y; + d.z = r.direction.z; + d.normalize(); + } + + public Ray createPickRay() { + Vector2f screenPos = new Vector2f(); + screenPos.set(input.mouseX(),renderingComposite.getBounds().height - input.mouseY()); + + + Ray mouseRay; + if (component.getCamera().isParallelProjection()) { + Vector3f worldCoords = renderingComposite.getDisplaySystem().getWorldCoordinates(screenPos, 0.0f); + mouseRay = new Ray(worldCoords, + component.getCamera().getDirection()); + } else { + Vector3f worldCoords = renderingComposite.getDisplaySystem().getWorldCoordinates(screenPos, 1.0f); + mouseRay = new Ray(component.getCamera().getLocation(), worldCoords + .subtractLocal(component.getCamera().getLocation())); + } + return mouseRay; + } + + public Vector2f getScreenCoord(Tuple3d worldCoord) { + Vector3f v = renderingComposite.getDisplaySystem().getScreenCoordinates(VecmathJmeTools.get(worldCoord)); + return new Vector2f(v.x,v.y); + } + + + public InputProvider getInputProvider() { + return input; + } + + /** + * Changes current action + * + * @param type + */ + public void setCurrentAction(InteractiveAction action) { + if (currentAction == action) + return; + if (toolBarManager != null) { + toolBarManager.removeAll(); + fillLocalToolBar(); + } + if (currentAction != null) + currentAction.deactivate(); + currentAction = action; + if (currentAction != null) { + currentAction.activate(); + if (toolBarManager != null) { + currentAction.fillToolBar(toolBarManager); + } + } + + updateBars(); + } + + public InteractiveAction getCurrentAction() { + return currentAction; + } + + public void setActiveEditorContribution(EditorContribution contribution) { + if (currentEditorContribution == contribution) + return; + if (currentAction != getDefaultAction()) + return; + if (currentEditorContribution != null) + currentEditorContribution.disposeControl(); + currentEditorContribution = contribution; + int index = editorContributions.indexOf(contribution); + for (int i = 0; i < contributionSelectionActions.size(); i++) { + if (i != index) + contributionSelectionActions.get(i).setChecked(false); + else + contributionSelectionActions.get(i).setChecked(true); + } + if (currentEditorContribution != null) + currentEditorContribution.createControl(parent); + + actionBars.clearGlobalActionHandlers(); + + parent.layout(true, true); + if (toolBarManager != null) { + toolBarManager.removeAll(); + fillLocalToolBar(); + } + if (menuManager != null) { + menuManager.removeAll(); + fillLocalPullDown(); + } + + updateBars(); + } + + protected void updateBars() { + // TODO : actionBars.updateActionBars does not update toolbar, updating toolBar directly layouts code + // generated widgets top of contributed (extension) widgets. Only way to achieve proper update + // is to use WorkbenchWindow.getCoolBarManager.update(true) + actionBars.updateActionBars(); +// if (toolBarManager != null) { +// toolBarManager.update(true); +// } + WorkbenchWindow w = (WorkbenchWindow)PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + w.getCoolBarManager().update(true); + } + + public void setGizmo(Gizmo gizmo) { + if (currentGizmo != null) { + currentGizmo.getNode().removeFromParent(); + } + currentGizmo = gizmo; + selectionAdapter.setCurrentGizmo(gizmo); + viewChanged = true; + } + +// public void setInfoText(String text) { +// if (useInfoComposite) { +// infoText.setText(text); +// } +// } + + public void showMessage(String message) { + MessageDialog.openInformation(parent.getShell(), "Shape Editor", //$NON-NLS-1$ + message); + } + + + /** + * Passing the focus request to the viewer's control. + */ + public void setFocus() { + renderingComposite.getCanvas().setFocus(); + } + + public void dispose() { + //System.out.println("ThreeDimensionalEditorBase.dispose()"); + VisualizationScheduler.getInstance().removeVisualization(this); + + if (currentAction != null) + currentAction.deactivate(); + + for (EditorContribution e : editorContributions) + e.dispose(); + + renderingComposite.dispose(); + + // copy of the set is needed to avoid ConcurrentModificationException + adapter.dispose(); + component.dispose(); + } + + public final void reload(Graph g, Resource res) { + inputResource = res; + reloadFrom(EntityFactory.create(g, res)); + // at this point we can initialize editor contributions, which may require inputResource + initializeEditorContributions(g); + } + + public Resource getInputResource() { + return inputResource; + } + + public void update(GraphChangeEvent event) { +// System.out.println("Transaction " + this + " : " + event.getTransactionId() + " Arg1: " + event.getArg1() +// + " arg2: " + event.getArg2() + " sender: " + event.getSender() + " source: " + event.getSource()); + +// if (event.added.size() > 0) { +// System.out.println("Added:"); +// for (Triplet t : event.added) +// System.out.println(t); +// } +// if (event.changed.size() > 0) { +// System.out.println("Changed:"); +// for (Triplet t : event.changed) +// System.out.println(t); +// } +// if (event.removed.size() > 0) { +// System.out.println("Removed:"); +// for (Triplet t : event.removed) +// System.out.println(t); +// } + + } + + + + /** + * Loads the initial scene: all further updates to the view are done by + * listening changes in the shapes and int the shape group + * + * @param resource + */ + protected abstract void reloadFrom(IEntity thing); + + + protected void viewUpdated() { + + } + + /* + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + public void run() { + if (currentEditorContribution != null) + currentEditorContribution.run(); + if (parent.isDisposed() || !parent.isVisible()) + return; + //renderingComposite.getDisplaySystem().setCurrent(); + input.update(); + if (input.mouseClicked()) { + int downMask = MouseEvent.CTRL_DOWN_MASK; + + if ((input.clickModifiers() & downMask) > 0) { + selectionAdapter.setSelectionType(SelectionType.MODIFY); + } else { + selectionAdapter.setSelectionType(SelectionType.SET); + } + } + if (input.mouseMoved()) { + Ray mouseRay = createPickRay(); + selectionAdapter.updateHighlights(mouseRay); + } + if (currentAction == cameraAction && input.mouseClicked()) { + selectionAdapter.pickHighlighted(); + } + if (currentAction == cameraAction && input.mousePressed() + && (input.pressModifiers() & MouseEvent.BUTTON3_MASK) > 0) { + Point p = renderingComposite.toDisplay(input.mouseX(), input + .mouseY()); + contextMenu.setLocation(p.x, p.y); + contextMenu.setVisible(true); + } + + if (currentAction != null) + try { + currentAction.update(); + } catch (Exception e) { + ErrorLogger.defaultLogError("Action error!", e); + setCurrentAction(getDefaultAction()); + } + + if (component.update()) + viewChanged = true; + + if (!geometryUpdateRequestAdapter.isRunning() && adapter.needsUpdateGeometry()) { + session.asyncRead(geometryUpdateRequestAdapter); + } + + viewChanged |= adapter.isChanged(); + if (viewChanged) { + viewChanged = false; + adapter.setChanged(false); + camera.updateCamera(); + viewUpdated(); + component.render(); + } + } + // TODO : there is some sort of synchronization bug in rendering: + // part of the rendered objects are rendered with different camera transformation than others. + // re-rendering the scene hides the worst problems. + // Using shadows is the reason: shadowed objects are rendered with different transformation than non-shadowed. + //private boolean lastChanged = false; + + private GeometryUpdateRequestAdapter geometryUpdateRequestAdapter = new GeometryUpdateRequestAdapter(); + + private class GeometryUpdateRequestAdapter extends GraphRequestAdapter { + private boolean running; + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + running = true; + adapter.updateGeometry(g); + return GraphRequestStatus.transactionComplete(); + } + @Override + public void requestCompleted(GraphRequestStatus status) { + running = false; + adapter.setChanged(true); + } + + public boolean isRunning() { + return running; + } + } + + + + protected void hookDragAndDrop() { + dropTarget = new ShapeDropTarget(this); + } + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected abstract void pageSelectionChanged(IWorkbenchPart part, ISelection selection); + + /** + * EditorPart or ViewPart uses this method to forward getAdapter(Class) + * @see org.eclipse.ui.part.WorkbenchPart.getAdapter(Class adapter) + * @param adapter + * @return + */ + public Object getAdapter(Class adapter) { + return null; + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java new file mode 100644 index 00000000..4ad22bd2 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorPart.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.db.Resource; +import org.simantics.db.events.GraphChangeEvent; +import org.simantics.db.management.ISessionContext; +import org.simantics.proconf.ui.workbench.ResourceEditorPart; +import org.simantics.utils.ErrorLogger; + + +public abstract class ThreeDimensionalEditorPart extends ResourceEditorPart implements ThreeDimensionalEditorProvider{ + + protected Composite parent; + + protected ThreeDimensionalEditorBase editor; + + protected ISelectionListener pageSelectionListener; + + protected abstract ThreeDimensionalEditorBase createEditor(ISessionContext session); + + /** + * This is a callback that will allow us to create the viewer and it. + */ + @Override + public void createPartControl(Composite p) { + this.parent = p; + try { + editor = createEditor(getSessionContext()); + + // add partlistener that loads the scene-graph when the view has been created + this.getEditorSite().getPage().addPartListener(new IPartListener() { + + boolean opened = false; + boolean activated = false; + + public void partOpened(IWorkbenchPart part) { + if (part.equals(ThreeDimensionalEditorPart.this.getEditorSite().getPart())) { + opened = true; + } + } + + public void partActivated(IWorkbenchPart part) { + if (part.equals(ThreeDimensionalEditorPart.this.getEditorSite().getPart())) { + if (opened & !activated) { + activated = true; + load(); + } + } + } + + public void partBroughtToTop(IWorkbenchPart part) {} + + public void partClosed(IWorkbenchPart part) {} + + public void partDeactivated(IWorkbenchPart part) {} + + private void load() { + //System.out.println("ThreeDimensionalEditorPart.reload()"); + Session ses = ThreeDimensionalEditorPart.this.getSession(); + GraphRequestAdapter r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + reload(g); + return GraphRequestStatus.transactionComplete(); + } + }; + ses.asyncRead(r); + } + }); + + IActionBars actionBar = getEditorSite().getActionBars(); +// editor.setActionBarContributor(getEditorSite().getActionBarContributor()); + editor.setActionBars(actionBar); + getSession().syncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + editor.createControl(g,parent); + return GraphRequestStatus.transactionComplete(); + } + }); + + contributeStatusBar(actionBar.getStatusLineManager()); + hookPageSelection(); + getSite().setSelectionProvider(editor.selectionAdapter); + + + + } catch (Exception e) { + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + getSite().getPage().closeEditor(ThreeDimensionalEditorPart.this,false); + } + }); + + ErrorLogger logger = ErrorLogger.getDefault(); + logger.logError("Shape editor failed to open, see exception for details", e); + } + + } + + + protected void contributeStatusBar(IStatusLineManager manager) { + } + + + @Override + public void reload(Graph g) { + Resource inputResource = getInputResource(); + if (inputResource != null) { + editor.reload(g,inputResource); + } else { + + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + editor.showMessage("Failed to load model."); + getSite().getPage().closeEditor(ThreeDimensionalEditorPart.this,false); + } + }); + } + } + + @Override + public void update(GraphChangeEvent e) { + editor.update(e); + } + + @Override + public void setFocus() { + editor.setFocus(); + } + + /** + * Hooks selection listening + */ + private void hookPageSelection() { + pageSelectionListener = new ISelectionListener() { + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if (part == ThreeDimensionalEditorPart.this) + return; + pageSelectionChanged(part, selection); + } + }; + getSite().getPage().addPostSelectionListener(pageSelectionListener); + ISelection sel = getSite().getPage().getSelection(); + IWorkbenchPart wb = getSite().getPage().getActivePart(); + pageSelectionChanged(wb, sel); + } + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + editor.pageSelectionChanged(part, selection); + } + + public void dispose() { + if (pageSelectionListener != null) + getSite().getPage().removePostSelectionListener(pageSelectionListener); + editor.dispose(); + super.dispose(); + } + + public ThreeDimensionalEditorBase getEditor() { + return editor; + } + + @Override + public Object getAdapter(Class adapter) { + Object o = super.getAdapter(adapter); + if (o == null) { + o = editor.getAdapter(adapter); + } + return o; + } + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java new file mode 100644 index 00000000..df2d14dd --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/ThreeDimensionalEditorProvider.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +/** + * Interface which selectionProviders containing ThreeDimensionalEditorPart + * must implement. + * + * This enables usage of ThreeDimensionalEditorPart in views, editors, dialogs, and so on. + * + * @author Marko Luukkainen + * + */ +public interface ThreeDimensionalEditorProvider { + + public ThreeDimensionalEditorBase getEditor(); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java new file mode 100644 index 00000000..9ca2754c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java @@ -0,0 +1,520 @@ +package org.simantics.proconf.g3d.base; + +import java.util.Collection; +import java.util.HashMap; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Point3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Tuple3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.proconf.g3d.stubs.Position; + +public class TransformationTools { + + private static boolean DEBUG = false; + + private Resource childRelation; + private Resource parentRelation; + + public TransformationTools(Resource childRelation, Resource parentRelation) { + this.childRelation = childRelation; + this.parentRelation = parentRelation; + } + + public IEntity getParent(IEntity node) { + return node.getAtMostOneRelatedObject(parentRelation); + } + + public Point3d getLocalFromWorld(IEntity node, Point3d worldCoord) { + IEntity parent = getParent(node); + if (parent == null) {// this is a rootnode ( has no transformation) + return worldCoord; + } + + Point3d local = getLocalFromWorld2(parent,worldCoord); + return local; + } + + + private Point3d getLocalFromWorld2(IEntity node, Point3d worldCoord) { + IEntity parent = getParent(node); + if (parent == null) {// this is a root node ( has no transformation) + return worldCoord; + } + + Point3d local = getLocalFromWorld2(parent,worldCoord); + if (node.hasStatement(Resources.g3dResource.HasLocalPosition)) + local.sub(G3DTools.getPoint(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition))); + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + q.inverse(); + MathTools.rotate(q, local, local); + } + return local; + } + + public Point3d getWorldFromLocal(IEntity node,Point3d localCoord) { + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localCoord; + return getWorldFromLocal2(parent, localCoord); + } + + private Point3d getWorldFromLocal2(IEntity node,Point3d localCoord) { + + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + MathTools.rotate(q, localCoord, localCoord); + } + if (node.hasStatement(Resources.g3dResource.HasLocalPosition)) + localCoord.add(G3DTools.getPoint(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition))); + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localCoord; + + return getWorldFromLocal2(parent,localCoord); + } + + + public AxisAngle4d getLocalFromWorld(IEntity node, AxisAngle4d worldRot) { + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return worldRot; + + AxisAngle4d local = getLocalFromWorld2(parent,worldRot); + + return local; + } + + private AxisAngle4d getLocalFromWorld2(IEntity node, AxisAngle4d worldRot) { + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return worldRot; + AxisAngle4d local = getLocalFromWorld2(parent,worldRot); + + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + q.inverse(); + Quat4d q2 = new Quat4d(); + q2.set(local); + q.mul(q2); + local.set(q); + } + + return local; + } + + public AxisAngle4d getWorldFromLocal(IEntity node,AxisAngle4d localRot) { + IEntity parent = getParent(node); + if (parent == null) + return localRot; + + return getWorldFromLocal2(parent,localRot); + } + + private AxisAngle4d getWorldFromLocal2(IEntity node,AxisAngle4d localRot) { + + //System.out.print("wtl " + node.getResource() + " " + localCoord); + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + Quat4d q2 = new Quat4d(); + q2.set(localRot); + q.mul(q2); + localRot.set(q); + } + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localRot; + + //System.out.println(" " + localCoord); + return getWorldFromLocal2(parent,localRot); + } + + public Point3d getLocalFromWorldR(IEntity node, Point3d worldCoord) { + + Point3d local = getLocalFromWorldR(null,worldCoord); + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + q.inverse(); + MathTools.rotate(q, local, local); + } + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return worldCoord; + + return local; + } + + public Point3d getWorldFromLocalR(IEntity node,Point3d localCoord) { + + if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) { + Quat4d q = new Quat4d(); + q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation))); + MathTools.rotate(q, localCoord, localCoord); + } + + IEntity parent = getParent(node); + if (parent == null) // this is a rootnode ( has no transformation) + return localCoord; + + return getWorldFromLocalR(parent,localCoord); + } + + /** + * Updates transformations of all children of given node + * @param node + */ + public void propagateTransformChange(IEntity node) { + Collection children = node.getRelatedObjects(childRelation); + IEntity wp = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity wr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + Quat4d rot = new Quat4d(); + if (wr != null) + rot.set(G3DTools.getOrientation(wr)); + else + rot.w = 1.0; + Point3d pos = new Point3d(); + if (wp != null) + pos = G3DTools.getPoint(wp); + if (DEBUG) { + if (wr != null) + System.out.println("propagate transform " + node.getResource() + " " + pos + " " + G3DTools.getOrientation(wr)); + else + System.out.println("propagate transform " + node.getResource() + " " + pos); + } + for (IEntity n : children) { + IEntity lPos = n.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition); + IEntity lRot = n.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation); + if (DEBUG) System.out.print(n); + if (lRot != null) { + AxisAngle4d la = G3DTools.getOrientation(lRot); + AxisAngle4d wa = getWorldFromLocal(n, la); + IEntity wo = n.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation); + G3DTools.setOrientation(wo,wa); + storeProperty(wo.getResource(), wa); + } + if (lPos != null) { + Point3d lp = G3DTools.getPoint(lPos); + if (DEBUG) System.out.println(lp); + MathTools.rotate(rot, lp, lp); + lp.add(pos); + IEntity nwp = n.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition); + G3DTools.setTuple3(nwp, lp); + if (DEBUG) System.out.print(" " + lp); + storeProperty(nwp.getResource(), lp); + } + if (DEBUG) System.out.println(); + propagateTransformChange(n); + + } + } + + /** + * Updates transformation of one child node without changing its local transformation. + * @param parent + * @param node + */ + public void propagateLocalTransformChange(IEntity parent, IEntity node) { + //Collection children = parent.getRelatedObjects(childRelation); + IEntity parentWP = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity parentWR = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + Quat4d parentWRot = new Quat4d(); + if (parentWR != null) { + parentWRot.set(G3DTools.getOrientation(parentWR)); + + } else + parentWRot.w = 1.0; + Point3d parentWPos = new Point3d(); + if (parentWP != null) { + parentWPos = G3DTools.getPoint(parentWP); + } + if (DEBUG) { + if (parentWR != null) + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos + " " + G3DTools.getOrientation(parentWR)); + else + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos); + } + //for (IEntity n : children) { + // if (!n.equals(node)) + // continue; + IEntity lPos = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition); + IEntity lRot = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation); + if (DEBUG) System.out.print(node); + if (lRot != null) { + AxisAngle4d aa = G3DTools.getOrientation(lRot); + storeProperty(lRot.getResource(), aa); + AxisAngle4d la = getWorldFromLocal(node, aa); + IEntity wo = node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation); + G3DTools.setOrientation(wo,la); + storeProperty(wo.getResource(), la); + } + if (lPos != null) { + Point3d lp = G3DTools.getPoint(lPos); + storeProperty(lPos.getResource(), lp); + MathTools.rotate(parentWRot, lp, lp); + lp.add(parentWPos); + IEntity nwp = node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition); + G3DTools.setTuple3(nwp, lp); + storeProperty(nwp.getResource(), lp); + } + if (DEBUG) System.out.println(); + propagateTransformChange(node); + + } +// } + + public static void resetTransformation(IEntity shape) { + Graph graph = shape.getGraph(); + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition) == null) { + + // LocalPosition p = LocalPosition.createDefault(graph); + Position p = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalPosition, p); + // WorldPosition p2 = WorldPosition.createDefault(graph); + Position p2 = Position.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldPosition, p2); + p.setX(new double[] { 0.0 }); + p.setY(new double[] { 0.0 }); + p.setZ(new double[] { 0.0 }); + + p2.setX(new double[] { 0.0 }); + p2.setY(new double[] { 0.0 }); + p2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), 0.0, 0.0, 0.0); + G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), 0.0, 0.0, 0.0); + } + if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation) == null) { + + // LocalOrientation r = LocalOrientationFactory.create(graph); + Orientation r = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasLocalOrientation, r); + // WorldOrientation r2 = WorldOrientationFactory.create(graph); + Orientation r2 = Orientation.createDefault(graph); + shape.addStatement(Resources.g3dResource.HasWorldOrientation, r2); + r.setAngle(new double[] { 0.0 }); + r.setX(new double[] { 1.0 }); + r.setY(new double[] { 0.0 }); + r.setZ(new double[] { 0.0 }); + r2.setAngle(new double[] { 0.0 }); + r2.setX(new double[] { 1.0 }); + r2.setY(new double[] { 0.0 }); + r2.setZ(new double[] { 0.0 }); + + } else { + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation), + new AxisAngle4d(0.0, 1.0, 0.0, 0.0)); + } + } + + /** + * Updates transformation of one child node without changing its world transformation. + * @param parent + * @param node + */ + public void propagateWorldTransformChange(IEntity parent, IEntity node) { + //Collection children = parent.getRelatedObjects(childRelation); + IEntity parentWP = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity parentWR = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + Quat4d parentWQuat = new Quat4d(); + if (parentWR != null) { + parentWQuat.set(G3DTools.getOrientation(parentWR)); + } + else + parentWQuat.w = 1.0; + Point3d parentWPos = new Point3d(); + if (parentWP != null) { + parentWPos = G3DTools.getPoint(parentWP); + } + if (DEBUG){ + if (parentWR != null) + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos + " " + G3DTools.getOrientation(parentWR)); + else + System.out.println("propagate transform " + parent.getResource() + " " + parentWPos); + } + //for (IEntity n : children) { + // if (!n.equals(node)) + // continue; + IEntity wPos = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity wRot = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + + if (DEBUG) System.out.print(node); + if (wRot != null) { + AxisAngle4d aa = G3DTools.getOrientation(wRot); + storeProperty(wRot.getResource(), aa); + AxisAngle4d la = getLocalFromWorld(node, aa); + IEntity lRot = node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation); + G3DTools.setOrientation(lRot,la); + storeProperty(lRot.getResource(), la); + } + if (wPos != null) { + Point3d lp = G3DTools.getPoint(wPos); + storeProperty(wPos.getResource(), lp); + lp.sub(parentWPos); + parentWQuat.inverse(); + MathTools.rotate(parentWQuat, lp, lp); + IEntity lPos = node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition); + G3DTools.setTuple3(lPos, lp); + storeProperty(lPos.getResource(), lp); + } + if (DEBUG) System.out.println(); + propagateTransformChange(node); + + // } + } + + public boolean transformationUpdate(Graph graph, Resource resource) { + + //resources.startTransaction("transformationUpdate"); + IEntity entity = EntityFactory.create(graph,resource); + return transformationUpdate(entity); + } + + public boolean transformationUpdate(IEntity node) { + if (DEBUG) System.out.println("Node transformation update " + node.getResource()); + IEntity worldPos = node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition); + IEntity localPos = node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition); + IEntity worldOr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation); + IEntity localOr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation); + + Tuple3d worldP =G3DTools.getPoint(worldPos); + Tuple3d localP = G3DTools.getPoint(localPos); + + AxisAngle4d worldR = null; + AxisAngle4d localR = null; + if (worldOr != null) { + worldR = G3DTools.getOrientation(worldOr); + localR = G3DTools.getOrientation(localOr); + } + + boolean changed = false; + if (localP != null && worldP != null) { + Tuple3d cachedWorldP = (Tuple3d)getProperty(worldPos.getResource()); + Tuple3d cachedLocalP = (Tuple3d)getProperty(localPos.getResource()); + boolean changedLocalP = false; + boolean changedWorldP = false; + if (cachedLocalP == null) + changedLocalP = true; + else if (changed(cachedLocalP,localP)) + changedLocalP = true; + + if (cachedWorldP == null) { + changedWorldP = true; + } else if (changed(cachedWorldP,worldP)){ + changedWorldP = true; + } + if (changedLocalP) { + storeProperty(localPos.getResource(), localP); + Tuple3d p = getWorldFromLocal(node, new Point3d(localP)); + storeProperty(worldPos.getResource(), p); + G3DTools.setTuple3(worldPos, p); + if (DEBUG) System.out.println("Node changed local: wp " + worldP + " lp " + p + " old " + cachedLocalP); + changed = true; + } else if (changedWorldP) { + storeProperty(worldPos.getResource(), worldP); + Tuple3d p = getLocalFromWorld(node, new Point3d(worldP)); + G3DTools.setTuple3(localPos, p); + storeProperty(localPos.getResource(), p); + if (DEBUG) System.out.println("Node changed world: wp " + worldP + " lp " + p + " old " + cachedWorldP); + changed = true; + } + } + + if (localR != null || worldR != null) { + AxisAngle4d cachedWorldR = (AxisAngle4d)getProperty(worldOr.getResource()); + AxisAngle4d cachedLocalR = (AxisAngle4d)getProperty(localOr.getResource()); + boolean changedLocalR = false; + boolean changedWorldR = false; + + if (cachedLocalR == null) + changedLocalR = true; + else if (changed(cachedLocalR,localR)) + changedLocalR = true; + + if (cachedWorldR == null) { + changedWorldR = true; + } else if (changed(cachedWorldR,worldR)){ + changedWorldR = true; + } + + if (changedLocalR) { + storeProperty(localOr.getResource(), localR); + AxisAngle4d p = getWorldFromLocal(node, new AxisAngle4d(localR)); + G3DTools.setOrientation(worldOr, p); + storeProperty(worldOr.getResource(), p); + if (DEBUG) System.out.println("Node changed localR: wr " + p + " lr " + localR + " old " + cachedLocalR); + changed = true; + } else if (changedWorldR) { + storeProperty(worldOr.getResource(), worldR); + AxisAngle4d p = getLocalFromWorld(node, new AxisAngle4d(worldR)); + G3DTools.setOrientation(localOr, p); + storeProperty(localOr.getResource(), p); + if (DEBUG) System.out.println("Node changed worldR: wr " + worldR + " lr " + p + " old " + cachedWorldR); + changed = true; + } + } + + if (changed) + propagateTransformChange(node); + else if (DEBUG) + System.out.println("No Node transformation change detected " + node.getResource()); + return changed; + } + + public static boolean changed(Tuple3d v1, Tuple3d v2) { + Vector3d t = new Vector3d(v1); + t.sub(v2); + return t.lengthSquared() > 0.00001; + } + + public static boolean changed (double d1 , double d2) { + return (Math.abs(d1 - d2) > 0.00001 ); + + } + + public static boolean changed(AxisAngle4d aa1, AxisAngle4d aa2) { + if (Math.abs(aa1.angle - aa2.angle) > 0.00001) + return true; + Vector3d t1 = new Vector3d(aa1.x-aa2.x,aa1.y-aa2.y,aa1.z-aa2.z); + if (t1.lengthSquared() > 0.00001) { + if (Math.abs(aa1.angle) < 0.0001) + return false; + return true; + } + return false; + } + + + private HashMap properties = new HashMap(); + + public Object getProperty(Object key) { + return properties.get(key); + } + + public void storeProperty(Object key, Object value) { + properties.put(key, value); + } + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java new file mode 100644 index 00000000..21cfcff0 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VecmathJmeTools.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import javax.vecmath.Color4f; + +import com.jme.renderer.ColorRGBA; + +public class VecmathJmeTools { + + public static javax.vecmath.Vector3f get(com.jme.math.Vector3f v) { + return new javax.vecmath.Vector3f(v.x,v.y,v.z); + } + + public static javax.vecmath.Vector3d getD(com.jme.math.Vector3f v) { + return new javax.vecmath.Vector3d(v.x,v.y,v.z); + } + + public static com.jme.math.Vector3f get(javax.vecmath.Tuple3f v) { + return new com.jme.math.Vector3f(v.x,v.y,v.z); + } + + public static com.jme.math.Vector3f get(javax.vecmath.Tuple3d v) { + return new com.jme.math.Vector3f((float)v.x,(float)v.y,(float)v.z); + } + + public static com.jme.math.Matrix3f get(javax.vecmath.Matrix3d m) { + return new com.jme.math.Matrix3f((float)m.m00,(float)m.m01,(float)m.m02,(float)m.m10,(float)m.m11,(float)m.m12,(float)m.m20,(float)m.m21,(float)m.m22); + } + + public static javax.vecmath.Quat4f get(com.jme.math.Quaternion v) { + return new javax.vecmath.Quat4f(v.x,v.y,v.z,v.w); + } + + public static javax.vecmath.Quat4d getD(com.jme.math.Quaternion v) { + return new javax.vecmath.Quat4d(v.x,v.y,v.z,v.w); + } + + + public static com.jme.math.Quaternion get(javax.vecmath.Quat4f v) { + return new com.jme.math.Quaternion(v.x,v.y,v.z,v.w); + } + + public static com.jme.math.Quaternion get(javax.vecmath.Quat4d v) { + return new com.jme.math.Quaternion((float)v.x,(float)v.y,(float)v.z,(float)v.w); + } + + public static com.jme.math.Quaternion get(javax.vecmath.AxisAngle4f aa) { + javax.vecmath.Quat4f v = new javax.vecmath.Quat4f(); + v.set(aa); + return new com.jme.math.Quaternion(v.x,v.y,v.z,v.w); + + } + + public static com.jme.math.Quaternion get(javax.vecmath.AxisAngle4d aa) { + javax.vecmath.Quat4f v = new javax.vecmath.Quat4f(); + v.set(aa); + return new com.jme.math.Quaternion(v.x,v.y,v.z,v.w); + + } + + public static ColorRGBA get(Color4f c) { + return new ColorRGBA(c.x,c.y,c.z,c.w); + } + + public static Color4f get(ColorRGBA c) { + return new Color4f(c.r,c.g,c.b,c.a); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java new file mode 100644 index 00000000..e7011eb7 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/base/VisualizationScheduler.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.simantics.utils.ErrorLogger; + + +/** + * TODO : This is a copy-paste from old proconf.utils plug-ing: + * : PreferencePage is not ported, + * : Using Webmon ? + * + * + * VisualizationScheduler is singleton class that schedules + * visualization redraws. + * + * Scheduler has three behaviour patters: + * + * ONCE : Redraws all visualizations one by one and then sleeps for + * a while so that visualizations won't use all available cpu-time. + * + * ALWAYS : Redraws one visualization and sleeps before updating next + * visualization. + * + * OFF : uses asyncExec busy-loop (doesn't block eclipse, but other applications may suffer) + * + * + * @author Marko Luukkainen + * + */ +public class VisualizationScheduler implements Runnable{ + private static VisualizationScheduler instance; + private Display display; + private ArrayList visualizations; + private boolean isDisposed = false; + private boolean stateFlag = false; + private static int sleepTime = 40; + private int index = 0; + + public enum SleepType{ONCE,ALWAYS,OFF}; + + private static SleepType sleepType = SleepType.ONCE; + + private VisualizationScheduler() { + visualizations = new ArrayList(); + display = PlatformUI.getWorkbench().getDisplay(); + //sleepTime = UtilsPlugin.getDefault().getPreferenceStore().getInt(PreferenceConstants.SLEEP_TIME); + //sleepType = SleepType.valueOf(UtilsPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.SLEEP_TYPE)); + run(); + } + + /** + * Scheduler's run loop
+ *
+ * Loop contains two stages:
+ * In the first stage scheduler runs asyncExec for each visualization + * and after that it runs itself with asyncExec.
+ * In the second stage scheduler runs itself with timerExec which allows OS to run it's own code. + */ + public void run() { + if (!isDisposed && !display.isDisposed() && !PlatformUI.getWorkbench().isClosing()) { + switch(sleepType) { + case ALWAYS: + stateFlag = !stateFlag; + if (stateFlag) { + if (visualizations.size() > 0) { + if (index >= visualizations.size()) + index = 0; + Runnable scene = visualizations.get(index); + try { + display.asyncExec(scene); + } catch (Exception e) { + ErrorLogger.defaultLogWarning("Scheduler exception", e); + } + index++; + } + display.asyncExec(this); + } else { + display.timerExec(sleepTime, this); + } + break; + case ONCE: + stateFlag = !stateFlag; + if (stateFlag) { + for (Runnable scene : visualizations) { + try { + display.asyncExec(scene); + } catch (Exception e) { + ErrorLogger.defaultLogWarning("Scheduler exception",e); + } + } + display.asyncExec(this); + } else { + display.timerExec(sleepTime,this); + } + break; + case OFF: + for (Runnable scene : visualizations) { + try { + display.asyncExec(scene); + } catch (Exception e) { + ErrorLogger.defaultLogWarning("Scheduler exception",e); + } + } + display.asyncExec(this); + break; + } + } + } + + /** + * Adds visualization into scheduler + * @param scene + */ + public void addVisualization(Runnable scene) { + visualizations.add(scene); + } + + /** + * Removes visualization from scheduler + * @param scene + */ + public void removeVisualization(Runnable scene) { + visualizations.remove(scene); + } + + /** + * disposes scheduler. + * + */ + public void dispose() { + isDisposed = true; + } + + /** + * @return scheduler's instance + */ + public static VisualizationScheduler getInstance() { + if (instance == null) + instance = new VisualizationScheduler(); + + return instance; + } + + /** + * @return the sleep time of the scheduler + */ + public int getSleepTime() { + return sleepTime; + } + + /** + *

+ * Sets scheduler's sleep time. Larger sleep time gives more + * cpu time to other applications, but makes visualizations less + * responsive. + *

+ * + * @param sleepTime + */ + public static void setSleepTime(int time) { + sleepTime = time; + } + +// public boolean isSleepAlways() { +// return sleepAlways; +// } + + /** + * if this flag is set scheludler gives time to other aplications + * between each visualization update. Otherwise all visualizations are updated in row and + * then priority is given to other applications. + * @param sleepAlways + */ +// public static void setSleepAlways(boolean sleep) { +// sleepAlways = sleep; +// } + + public static SleepType getSleepType() { + return sleepType; + } + + public static void setSleepType(SleepType s) { + sleepType = s; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java new file mode 100644 index 00000000..5cff3ffb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeComposite.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + + +import java.util.logging.LogManager; + +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.opengl.GLCanvas; +import org.eclipse.swt.widgets.Composite; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.ResourceTextureCache; +import org.simantics.utils.ErrorLogger; + +import com.jme.renderer.Renderer; +import com.jme.renderer.lwjgl.LWJGLRenderer; +import com.jme.scene.Node; +import com.jme.system.DisplaySystem; +import com.jme.system.swt.SWTDisplaySystem; +import com.jme.util.TextureManager; + + +public class JmeComposite extends Composite { + protected Node rootNode = new Node("root"); + private SWTDisplaySystem displaySystem; + protected GLCanvas renderingCanvas; + private JmeRenderingComponent component; + + public JmeComposite(Composite parent, JmeRenderingComponent component) { + super(parent,SWT.NONE); + if (component == null) + throw new NullPointerException("Rendering component must not be null."); + disableLog(); + //LoggingSystem.getLogger().setLevel(Level.OFF); + this.component = component; + this.setLayout(new FillLayout()); + displaySystem = (SWTDisplaySystem)DisplaySystem.getDisplaySystem("SWT"); + renderingCanvas = displaySystem.createCanvas(640, 480, this); + renderingCanvas.addControlListener(new ControlAdapter() { + public void controlResized(ControlEvent e) { + resize(); + } + }); + + + } + + private void disableLog() { + //URL url = FileLocator.find(org.simantics.proconf.g3d.Activator.getDefault().getBundle(),new Path("logging.properties"),null); + + try { + LogManager.getLogManager().readConfiguration(org.simantics.proconf.g3d.Activator.getDefault().openStream(new Path("logging.properties"))); + } catch (Exception e) { + ErrorLogger.defaultLogError(e); + } + } + + public void resize() { + displaySystem.setCurrent(); + LWJGLRenderer renderer = (LWJGLRenderer) displaySystem.getRenderer(); + if (renderer!= null) { + Rectangle r = new Rectangle(renderingCanvas.getClientArea().x,renderingCanvas.getClientArea().y, renderingCanvas.getClientArea().width, renderingCanvas.getClientArea().height ); + if (r.width > 0 && r.height > 0) + renderer.reinit(r.width, r.height); + component.resize(r.width, r.height); + } + } + + public GLCanvas getCanvas() { + return renderingCanvas; + } + + public Renderer getRenderer() { + return displaySystem.getRenderer(); + } + + public void initGL() { + component.init(displaySystem); + } + + public void dispose() { + LWJGLRenderer renderer = (LWJGLRenderer) displaySystem.getRenderer(); + renderer.clearVBOCache(); + renderer.clearQueue(); + renderer.clearStatistics(); + renderingCanvas.dispose(); + if (displaySystem.destroy()) { + + TextureManager.doTextureCleanup(); + TextureManager.clearCache(); + ResourceTextureCache.getInstance().clear(); + } + super.dispose(); + } + + public DisplaySystem getDisplaySystem() { + return displaySystem; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java new file mode 100644 index 00000000..fb9aff60 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/JmeSinglePassRenderingComponent.java @@ -0,0 +1,411 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.preferences.PreferenceConstants; + +import com.jme.image.Texture; +import com.jme.light.DirectionalLight; +import com.jme.math.Vector3f; +import com.jme.renderer.Camera; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.pass.BasicPassManager; +import com.jme.renderer.pass.RenderPass; +import com.jme.renderer.pass.ShadowedRenderPass; +import com.jme.renderer.swt.SWTRenderer; +import com.jme.scene.Node; +import com.jme.scene.Spatial; +import com.jme.scene.Text; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.LightState; +import com.jme.scene.state.TextureState; +import com.jme.scene.state.WireframeState; +import com.jme.scene.state.ZBufferState; +import com.jme.system.DisplaySystem; +import com.jme.util.TextureManager; +import com.jme.util.Timer; +import com.jme.util.geom.Debugger; +import com.jmex.effects.glsl.BloomRenderPass; +import com.jmex.effects.glsl.SketchRenderPass; + + +public class JmeSinglePassRenderingComponent extends JmeRenderingComponent { + protected DisplaySystem displaySystem; + protected Timer timer; + protected Node rootNode = new Node("Root"); + protected Node shadowRootNode = new Node("Shadow"); + protected Node noCastShadowRootNode = new Node("No Cast Shadow"); + protected Node noShadowRootNode = new Node("No Shadow"); + protected Camera cam; + protected float near = .1f; + protected float far = 3000f; + protected float fov = 55f; + + protected int projectionPolicy; + + /** The root node of our text. */ + protected Node orthoNode = new Node("ortho"); + + /** Displays all the lovely information at the bottom. */ + protected Text fps; + protected Text debug; + protected String debugText = ""; + public static String fontLocation = "data/defaultfont.tga";//AppProperties.PATH_DEFAULT_FONT; + + + protected BasicPassManager pManager = new BasicPassManager(); + + private boolean showBounds = false; + private boolean showNormals = false; + private WireframeState ws = null; + + private boolean projectionUpdated = false; + + public JmeSinglePassRenderingComponent() { + + } + + public void init(DisplaySystem displaySystem) { + this.displaySystem = displaySystem; + cam = displaySystem.getRenderer().createCamera( + displaySystem.getRenderer().getWidth(), displaySystem.getRenderer().getHeight()); + displaySystem.getRenderer().setBackgroundColor(new ColorRGBA(0.2f,0.2f,0.2f,0.f));//(0.357F, 0.647F, 0.890F, 1.0F)); + displaySystem.getRenderer().getQueue().setTwoPassTransparency(true); + cam.setFrustumPerspective(fov, + (float) displaySystem.getRenderer().getWidth()/ + (float) displaySystem.getRenderer().getHeight(),near, far); + projectionPolicy = PERSPECTIVE_PROJECTION; + Vector3f loc = new Vector3f(0.0f, 0.0f, 10.0f); + Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f); + Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f); + Vector3f dir = new Vector3f(0.0f, 0f, -1.0f); + /** Move our camera to a correct place and orientation. */ + cam.setFrame(loc, left, up, dir); + /** Signal that we've changed our camera's location/frustum. */ + cam.update(); + displaySystem.getRenderer().setCamera(cam); + timer = Timer.getTimer(); + displaySystem.setTitle("ShapeEditor"); + displaySystem.getRenderer().enableStatistics(true); + + initRoot(); + } + + protected Texture loadFontTexture() { + URL url = FileLocator.find(org.simantics.proconf.g3d.Activator.getDefault().getBundle(),new Path(fontLocation),null); + return TextureManager.loadTexture(url, Texture.MM_LINEAR, + Texture.FM_LINEAR); + } + + protected void initRoot() { + ZBufferState buf = displaySystem.getRenderer().createZBufferState(); + buf.setEnabled(true); + buf.setFunction(ZBufferState.CF_LEQUAL); + //buf.setWritable(false); + rootNode.setRenderState(buf); + rootNode.attachChild(noShadowRootNode); + rootNode.attachChild(noCastShadowRootNode); + rootNode.attachChild(shadowRootNode); + noShadowRootNode.setCullMode(Spatial.CULL_NEVER); + + //PointLight light = new PointLight(); + DirectionalLight light = new DirectionalLight(); + light.setDiffuse( new ColorRGBA( 0.75f, 0.75f, 0.75f, 0.75f ) ); + light.setAmbient( new ColorRGBA( 0.5f, 0.5f, 0.5f, 0.5f ) ); + //light.setLocation( new Vector3f( 100, 100, 100 ) ); + light.setDirection(new Vector3f( -100, -150, -100 )); + light.setEnabled( true ); + light.setShadowCaster(true); + + LightState lightState = displaySystem.getRenderer().createLightState(); + lightState.setEnabled( true ); + lightState.attach( light ); + lightState.setSeparateSpecular(true); + lightState.setTwoSidedLighting(false); + rootNode.setRenderState( lightState ); + + ws = displaySystem.getRenderer().createWireframeState(); + ws.setEnabled(false); + rootNode.setRenderState(ws); + + AlphaState as1 = displaySystem.getRenderer().createAlphaState(); + as1.setBlendEnabled(true); + as1.setSrcFunction(AlphaState.SB_SRC_ALPHA); + as1.setDstFunction(AlphaState.DB_ONE); + as1.setTestEnabled(true); + as1.setTestFunction(AlphaState.TF_GREATER); + as1.setEnabled(true); + + TextureState font = displaySystem.getRenderer().createTextureState(); + /** The texture is loaded from fontLocation */ + font.setTexture(loadFontTexture()); + + font.setEnabled(true); + + // Then our font Text object. + /** This is what will actually have the text at the bottom. */ + fps = new Text("FPS label", ""); + fps.setCullMode(Spatial.CULL_NEVER); + fps.setTextureCombineMode(TextureState.REPLACE); + + debug = new Text("Debug", "Debug"); + debug.setCullMode(Spatial.CULL_NEVER); + debug.setTextureCombineMode(TextureState.REPLACE); + debug.setLocalTranslation(new Vector3f(1.f,10.f,0.f)); + + // Finally, a stand alone node (not attached to root on purpose) + Node fpsNode = new Node("FPS node"); + fpsNode.attachChild(fps); + fpsNode.attachChild(debug); + fpsNode.setRenderState(font); + fpsNode.setRenderState(as1); + fpsNode.setCullMode(Spatial.CULL_NEVER); + orthoNode.attachChild(fpsNode); + + rootNode.updateGeometricState(0.0f, true); + rootNode.updateRenderState(); + + orthoNode.updateGeometricState(0.0f, true); + orthoNode.updateRenderState(); + if (Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.SHADOWS)) { + ShadowedRenderPass shadowRootPass = new ShadowedRenderPass(); + shadowRootPass.add(shadowRootNode); + shadowRootPass.add(noCastShadowRootNode); + shadowRootPass.addOccluder(shadowRootNode); + pManager.add(shadowRootPass); + //rootPass.setRenderShadows(false); + shadowRootPass.setShadowColor(new ColorRGBA(0.1f,0.1f,0.1f,0.9f)); + shadowRootPass.setLightingMethod(ShadowedRenderPass.MODULATIVE); + RenderPass rootPass = new RenderPass(); + rootPass.add(noShadowRootNode); + pManager.add(rootPass); + } else { + RenderPass rootPass = new RenderPass(); + rootPass.add(rootNode); + pManager.add(rootPass); + } + + String postProcess = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.POST_PROCESS); + if (postProcess.startsWith("bloom")) { + BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4); + if (bloomRenderPass.isSupported()) { + bloomRenderPass.add(rootNode); + bloomRenderPass.setUseCurrentScene(false); + pManager.add(bloomRenderPass); + } + } else if (postProcess.startsWith("sketch")) { + SketchRenderPass sketchRenderPass = new SketchRenderPass(cam, 4); + if (sketchRenderPass.isSupported()) { + sketchRenderPass.add(rootNode); + pManager.add(sketchRenderPass); + } + } + + + RenderPass fpsPass = new RenderPass(); + fpsPass.add(orthoNode); + pManager.add(fpsPass); + } + + public void render() { + displaySystem.setCurrent(); + /** Recalculate the framerate. */ + timer.update(); + + /** Update tpf to time per frame according to the Timer. */ + float tpf = timer.getTimePerFrame(); + /** Send the fps to our fps bar at the bottom. */ + fps.print("FPS: " + (int) timer.getFrameRate() + " - " + + displaySystem.getRenderer().getStatistics()); + /** + * Update the physics for this world. + */ + debug.print(debugText); + + /** Update controllers/render states/transforms/bounds for rootNode. */ + rootNode.updateGeometricState(tpf, true); + rootNode.updateRenderState(); + + orthoNode.updateGeometricState(tpf, true); + orthoNode.updateRenderState(); + + displaySystem.getRenderer().clearStatistics(); + /** Clears the previously rendered information. */ + displaySystem.getRenderer().clearBuffers(); + + pManager.updatePasses(tpf); + + pManager.renderPasses(displaySystem.getRenderer()); + if ( showBounds ) { + Debugger.drawBounds( shadowRootNode, displaySystem.getRenderer(), true ); + } + + if ( showNormals ) { + Debugger.drawNormals( shadowRootNode, displaySystem.getRenderer()); + } + displaySystem.getRenderer().displayBackBuffer(); + + + + //swap buffers + ((SWTRenderer)displaySystem.getRenderer()).swap(); + } + + @Override + public void resize(int width, int height) { + updateProjection(); + } + + @Override + public Node getShadowRoot() { + return shadowRootNode; + } + + @Override + public Node getNoCastRoot() { + return noCastShadowRootNode; + } + + @Override + public Node getRoot() { + return rootNode; + } + + @Override + public Node getOrthoNode() { + return orthoNode; + } + + @Override + public Node getNoShadowRoot() { + return noShadowRootNode; + } + +// public void setRootNode(Node node) { +// rootNode = node; +// initRoot(); +// } + + @Override + public int getProjectionPolicy() { + return projectionPolicy; + } + + @Override + public void setProjectionPolicy(int policy) { + if (policy != projectionPolicy) { + projectionPolicy = policy; + updateProjection(); + } + } + + private void updateProjection() { + switch (projectionPolicy) { + case PERSPECTIVE_PROJECTION: + cam.setParallelProjection(false); + cam.setFrustumPerspective(fov, + (float) displaySystem.getRenderer().getWidth() / + (float) displaySystem.getRenderer().getHeight(),near, far); + break; + + case PARALLEL_PROJECTION: + cam.setParallelProjection(true); + break; + } + cam.update(); + projectionUpdated = true; + } + + @Override + public float getScreenScale() { + //System.out.println(cam.getFrustumLeft() + " " + cam.getFrustumRight() + " " + cam.getFrustumBottom() + " " + cam.getFrustumTop()+ " " + cam.getFrustumNear() + " " + cam.getFrustumFar()); + return Math.abs(cam.getFrustumTop()); + } + + @Override + public void setScreenScale(float screenScale) { + float aspect = (float) displaySystem.getRenderer().getWidth() / + (float) displaySystem.getRenderer().getHeight(); + cam.setFrustum(-screenScale*8.f, cam.getFrustumFar(), -screenScale*aspect, screenScale*aspect, -screenScale, screenScale); + } + + @Override + public float getFieldOfView() { + return fov; + } + + @Override + public void dispose() { + pManager.cleanUp(); + rootNode.dispose(); + rootNode = null; + noShadowRootNode = null; + noCastShadowRootNode = null; + orthoNode = null; + shadowRootNode = null; + } + + @Override + public boolean update() { + if (!projectionUpdated) { + return false; + } + projectionUpdated = false; + return true; + } + + @Override + public Camera getCamera() { + return cam; + } + + @Override + public DisplaySystem getDisplaySystem() { + return displaySystem; + } + + public void setDebugText(String text) { + this.debugText = text; + //System.out.println("JmeSinglePass.setDebugText() " + text); + } + + public void setShowNormals(boolean b) { + showNormals = b; + } + + public void setShowBounds(boolean b) { + showBounds = b; + } + + public void setShowWireframe(boolean b) { + ws.setEnabled(b); + } + + public boolean isShowNormals() { + return showNormals; + } + + public boolean isShowBounds() { + return showBounds; + } + + public boolean isShowWireframe() { + return ws.isEnabled(); + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java new file mode 100644 index 00000000..4b0aa6fc --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/OrbitalCamera.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Matrix3d; +import javax.vecmath.Vector3d; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.renderer.Camera; + + +/** + * Orbital camera + *

+ * Modified version of fi.vtt.proconf.webmon.graphics3d.utils.OrbitalCamera
+ * Using floats instead of double
+ *

+ * + * + * @author Marko Luukkainen + * + */ +public class OrbitalCamera { + + private Vector3d up = new Vector3d(0.0,1.0,0.0); + private static Vector3d up2 = new Vector3d(0.0,0.0,-1.0); + private static double minDistance = 0.5; + private Vector3d target = new Vector3d(); + private Vector3d cameraPos = new Vector3d(10.0,0.0,0.0); + + + public void translate(Vector3d v) { + target.add(v); + cameraPos.add(v); + } + + public void rotateAroundTarget(Vector3d axis, double angle) { + Vector3d temp = new Vector3d(cameraPos); + temp.sub(target); + Matrix3d rotation = new Matrix3d(); + rotation.set(new AxisAngle4d(axis,angle)); + rotation.transform(temp); + temp.add(target); + cameraPos.set(temp); + } + + public Vector3d getUnNormalizedHeading() { + Vector3d heading = new Vector3d(target); + heading.sub(cameraPos); + return heading; + } + + public Vector3d getUnNormalizedRight() { + Vector3d heading = getUnNormalizedHeading(); + Vector3d right = new Vector3d(); + right.cross(heading,up); + if (right.lengthSquared() < 0.01) + right.cross(heading,up2); + return right; + } + + public double getDistanceToTarget() { + Vector3d t = new Vector3d(target); + t.sub(cameraPos); + return t.length(); + } + + public void moveToTarget(double distance) { + Vector3d heading = getUnNormalizedHeading(); + double length = heading.length(); + if (length + distance < minDistance) { + // cannot move closer + return; + } + heading.scale(distance / length); //normalizing and scaling by distance + cameraPos.add(heading); + } + + public void moveScaledToTarget(double s) { + Vector3d heading = getUnNormalizedHeading(); + double currentLength = heading.length(); + double length = currentLength * (1.0 - s);// heading.length(); + if (length < minDistance) { + s = -minDistance / currentLength + 1.0; + } + heading.scale(s); + //normalizing and scaling by distance + cameraPos.add(heading); + } + + public void rotateUp(double angle) { + Vector3d right = getUnNormalizedRight(); + double length = right.length(); + // TODO : better handling of singular cases + if (length > 0.01) + right.scale(1.0/length); + else + right.set(-1.0,0.0,0.0); + rotateAroundTarget(right,angle); + } + + public void rotateRight(double angle) { + rotateAroundTarget(up,angle); + } + + public void moveRight(double length) { + Vector3d right = getUnNormalizedRight(); + right.normalize(); + right.scale(length); + translate(right); + } + + public void moveUp(double length) { + Vector3d u = new Vector3d(up); + u.scale(length); + translate(u); + } + + public void moveFront(double length) { + Vector3d right = getUnNormalizedRight(); + Vector3d front = new Vector3d(); + front.cross(up,right); + front.normalize(); + front.scale(length); + translate(front); + } + + public void updateCamera() { + Vector3d t = new Vector3d(cameraPos); + t.sub(target); + t.normalize(); + cam.setLocation(VecmathJmeTools.get(cameraPos)); + + if (Math.abs(t.dot(up)) > 0.99) { + cam.lookAt(VecmathJmeTools.get(target), VecmathJmeTools.get(up2)); + } else { + cam.lookAt(VecmathJmeTools.get(target), VecmathJmeTools.get(up)); + } + cam.update(); + cam.apply(); + + } + + /** + * @return Returns the cameraPos. + */ + public Vector3d getCameraPos() { + return cameraPos; + } + + /** + * @param cameraPos The cameraPos to set. + */ + public void setCameraPos(Vector3d cameraPos) { + this.cameraPos = cameraPos; + } + + /** + * @return Returns the target. + */ + public Vector3d getTarget() { + return target; + } + + /** + * @param target The target to set. + */ + public void setTarget(Vector3d target) { + this.target = target; + } + + public void setCameraPosRelativeToTarget(Vector3d targetToCam) { + targetToCam.add(target); + setCameraPos(targetToCam); + } + + public void setUp(Vector3d v) { + up.set(v); + } + + public Vector3d getUp() { + return up; + } + + public void setDefaultUp() { + up.set(0.0,1.0,0.0); + } + + private Camera cam; + + public void setCamera(Camera cam) { + this.cam = cam; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java new file mode 100644 index 00000000..0f57f7ae --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/PropertyTester2.java @@ -0,0 +1,18 @@ +package org.simantics.proconf.g3d.common; + +import org.eclipse.core.expressions.PropertyTester; + +public class PropertyTester2 extends PropertyTester { + + public PropertyTester2() { + // TODO Auto-generated constructor stub + } + + @Override + public boolean test(Object receiver, String property, Object[] args, + Object expectedValue) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java new file mode 100644 index 00000000..a13062a8 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/common/StructuredResourceSelection.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.simantics.db.Resource; + + +/** + * StructuredSelection that contains ResourceSelections + * + * @author Marko Luukkainen + * @author Tuukka Lehtonen + */ +public class StructuredResourceSelection implements IStructuredSelection { + + public static final StructuredResourceSelection EMPTY = new StructuredResourceSelection() { + // Create an empty fixed size List to ensure the list is not modified. + private List empty = Arrays.asList(); + + public void add(Resource rs) { + throw new UnsupportedOperationException("BUG: attempted to modify StructuredResourceSelection.EMPTY"); + } + public List getSelectionList() { + return empty; + } + }; + + private List selections; + + /** + * Creates a new selection that doesn't contain any items + */ + public StructuredResourceSelection() { + } + + public StructuredResourceSelection(Resource rs) { + getSelectionList().add(rs); + } + + public StructuredResourceSelection(Resource... rss) { + List s = getSelectionList(); + for (Resource rs : rss) + s.add(rs); + } + + public void add(Resource rs) { + getSelectionList().add(rs); + } + + public List getSelectionList() { + if (selections == null) { + selections = new ArrayList(); + } + return selections; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ISelection#isEmpty() + */ + public boolean isEmpty() { + return selections == null || selections.isEmpty(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#getFirstElement() + */ + public Object getFirstElement() { + if (!isEmpty()) + return selections.get(0); + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#iterator() + */ + public Iterator iterator() { + return getSelectionList().iterator(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#size() + */ + public int size() { + return selections == null ? 0 : selections.size(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#toArray() + */ + public Object[] toArray() { + return selections == null ? new Object[0] : selections.toArray(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredSelection#toList() + */ + public List toList() { + return selections == null ? Arrays.asList(new Resource[0]) : selections; + } + + /** + * Returns whether this structured selection is equal to the given object. + * Two structured selections are equal iff they contain the same elements + * in the same order. + * + * @param o the other object + * @return true if they are equal, and false otherwise + */ + public boolean equals(Object o) { + if (this == o) { + return true; + } + // null and other classes + if (!(o instanceof StructuredResourceSelection)) { + return false; + } + StructuredResourceSelection other = (StructuredResourceSelection) o; + + // either or both empty? + if (isEmpty()) { + return other.isEmpty(); + } + if (other.isEmpty()) { + return false; + } + + // check size + if (size() != other.size()) + return false; + + // element comparison + Iterator it = iterator(); + Iterator otherIt = other.iterator(); + while (it.hasNext()) { + if (!it.next().equals(otherIt.next())) + return false; + } + + return true; + } + + @Override + public String toString() { + return Arrays.toString(getSelectionList().toArray()); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java new file mode 100644 index 00000000..9e2950db --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dialogs/JMEDialog.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +public class JMEDialog extends Dialog { + private boolean bounds; + private boolean normals; + private boolean wireframe; + private float[] floatColor = null; + private Button boundsButton; + private Button normalsButton; + private Button wireframeButton; + private Composite colorComposite; + private Color color = null; + + public JMEDialog(Shell parentShell) { + super(parentShell); + } + + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure new pipeline"); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + Label label = new Label(composite, SWT.WRAP); + label.setText("JME Configuration"); + GridData data = new GridData(GridData.GRAB_HORIZONTAL + | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL + | GridData.VERTICAL_ALIGN_CENTER); + + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); + boundsButton = new Button(composite,SWT.CHECK); + boundsButton.setText("Show bounds"); + boundsButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + bounds = boundsButton.getSelection(); + } + }); + boundsButton.setSelection(bounds); + normalsButton = new Button(composite,SWT.CHECK); + normalsButton.setText("Show normals"); + normalsButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + normals = normalsButton.getSelection(); + } + }); + normalsButton.setSelection(normals); + wireframeButton = new Button(composite,SWT.CHECK); + wireframeButton.setText("Show wireframe"); + wireframeButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + wireframe = wireframeButton.getSelection(); + } + }); + wireframeButton.setSelection(wireframe); + + colorComposite = new Composite(composite,SWT.BORDER); + colorComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(JMEDialog.this.getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + if (color != null) + color.dispose(); + color = new Color(JMEDialog.this.getShell().getDisplay(),rgb); + colorComposite.setBackground(color); + floatColor = new float[]{rgb.red/255.f,rgb.green/255.f,rgb.blue/255.f}; + } + } + }); + updateColor(); + + return composite; + } + + @Override + public int open() { + return super.open(); + } + + + public boolean isBounds() { + return bounds; + } + + + public void setBounds(boolean bounds) { + this.bounds = bounds; + } + + + public boolean isNormals() { + return normals; + } + + + public void setNormals(boolean normals) { + this.normals = normals; + } + + + public boolean isWireframe() { + return wireframe; + } + + + public void setWireframe(boolean wireframe) { + this.wireframe = wireframe; + } + + + public float[] getFloatColor() { + return floatColor; + } + + public void setFloatColor(float[] c) { + this.floatColor = c; + if (floatColor == null) + return; + + updateColor(); + } + + private void updateColor() { + if (colorComposite == null) + return; + if (color != null) + color.dispose(); + RGB rgb = new RGB((int)(floatColor[0]*255.f),(int)(floatColor[1]*255.f),(int)(floatColor[2]*255.f)); + color = new Color(JMEDialog.this.getShell().getDisplay(),rgb); + colorComposite.setBackground(color); + } + + + + + + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java new file mode 100644 index 00000000..70e9610f --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/DropListener.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.dnd; + +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + + + +public interface DropListener { + + boolean acceptDrop(StructuredResourceSelection s, Resource res[]); + void doDrop(StructuredResourceSelection s, Resource res[]); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java new file mode 100644 index 00000000..fe832e65 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/dnd/ShapeDropTarget.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.dnd; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.DropTargetListener; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Control; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.ui.dnd.ResourceReferenceTransfer; + +public class ShapeDropTarget implements DropTargetListener{ + ThreeDimensionalEditorBase editor; + List listeners; + final Control control; + private DropTarget target; + + public ShapeDropTarget(ThreeDimensionalEditorBase editor) { + this.editor = editor; + listeners = new ArrayList(); + this.control = editor.getRenderingComposite(); + + target = new DropTarget(control, DND.DROP_LINK); + target.setTransfer(new Transfer[] { ResourceReferenceTransfer.getInstance() }); + target.addDropListener(this); + } + + public void addDropListener(DropListener listener) { + listeners.add(listener); + } + + public void removeDropListener(DropListener listener) { + listeners.remove(listener); + } + + @Override + public void dragEnter(DropTargetEvent event) { + event.detail = DND.DROP_LINK; + dragOver(event); + } + + public void dragOperationChanged(DropTargetEvent event) { + } + + public void dropAccept(DropTargetEvent event) { + } + + public void dragLeave(DropTargetEvent event) { + } + + + @Override + public void dragOver(DropTargetEvent event) { + // FIXME : a hack to get the actual data (probably works only in Windows) + TransferData data = event.currentDataType; + if(!TextTransfer.getInstance().isSupportedType(data)) + return; + Object o = TextTransfer.getInstance().nativeToJava(data); + + Point p = getLocalCoords(event); + editor.getInputProvider().setMouseMoved(true); + editor.getInputProvider().setMouseX(p.x); + editor.getInputProvider().setMouseY(p.y); + editor.run(); + StructuredResourceSelection sel = editor.getSelectionAdapter().getHighlightSelection(); + + event.data = o; + Resource ids[] = parseEventData(event); + for (DropListener l : listeners) { + if(l.acceptDrop(sel, ids)) { + event.detail = DND.DROP_LINK; + return; + } + } + event.detail = DND.DROP_NONE; + } + + @Override + public void drop(DropTargetEvent event) { + StructuredResourceSelection sel = editor.getSelectionAdapter().getHighlightSelection(); + Resource ids[] = parseEventData(event); + for (DropListener l : listeners) { + if(l.acceptDrop(sel, ids)) { + l.doDrop(sel, ids); + return; + } + } + } + + protected Point getLocalCoords(DropTargetEvent event) { + return editor.getRenderingComposite().toControl(event.x, event.y); + } + + public void dispose() + { + target.removeDropListener(this); + target = null; + } + + private Resource[] parseEventData(DropTargetEvent event) { + if (ResourceReferenceTransfer.getInstance().isSupportedType(event.currentDataType) && (event.data instanceof Resource[])) { + return (Resource[]) event.data; + } + return null; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java new file mode 100644 index 00000000..e6f7b61c --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/AbstractGizmo.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Color4f; +import javax.vecmath.Quat4f; +import javax.vecmath.Tuple3d; +import javax.vecmath.Tuple3f; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; + +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.preferences.PreferenceConstants; + +import com.jme.renderer.Renderer; +import com.jme.scene.Node; + + +public abstract class AbstractGizmo implements Gizmo{ + + private Node position; + private Node rotate; + private Node scale; + + private boolean changed = false; + + private double userScale = 1.0; + + public AbstractGizmo() { + createGroups(); + } + + public void setChanged(boolean b) { + changed = b; + } + + public boolean isChanged() { + return changed; + } + + public double getUserScale() { + return Activator.getDefault().getPreferenceStore().getDouble(PreferenceConstants.GIZMO_SCALE); + } + + + public void setScale(float scale) { + this.scale.setLocalScale(scale); + } + + public void setScale(Vector3f scale) { + this.scale.setLocalScale(VecmathJmeTools.get(scale)); + } + + public Vector3d getPosition() { + return VecmathJmeTools.getD(position.getWorldTranslation()); + } + + public Vector3f getPositionFloat() { + return VecmathJmeTools.get(position.getWorldTranslation()); + } + + public void setPosition(Tuple3d position) { + this.position.setLocalTranslation(VecmathJmeTools.get(position)); + } + + public void setPosition(Vector3f position) { + this.position.setLocalTranslation(VecmathJmeTools.get(position)); + } + + public void setRotation(Quat4f q) { + rotate.setLocalRotation(VecmathJmeTools.get(q)); + } + + public void setRotation(AxisAngle4f q) { + rotate.setLocalRotation(VecmathJmeTools.get(q)); + } + + public Node getNode() { + userScale = getUserScale(); + return position; + } + + protected Node getGizmoNode() { + return scale; + } + + private void createGroups() { + + position = new Node(); + rotate = new Node(); + scale = new Node(); + position.attachChild(rotate); + rotate.attachChild(scale); + position.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + } + + public void update(Tuple3d position, Tuple3d cameraPosition, JmeRenderingComponent component) { + setPosition(position); + com.jme.math.Vector3f p = VecmathJmeTools.get(position); + p.subtractLocal(VecmathJmeTools.get(cameraPosition)); + rotate.getLocalRotation().inverse().multLocal(p); + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) { + + double distance = p.length(); + // (bug caused in Xith->JME translation ?) + p.negateLocal(); + double fov = component.getFieldOfView(); + float s = (float) (Math.sin(fov) * distance * 0.1); // scaling factor was 0.2 with Xith + s *= (float)userScale; + Vector3f scale = new Vector3f(1.f, 1.f, 1.f); + + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + } else { + Vector3f scale = new Vector3f(1.f, 1.f, 1.f); + float s = component.getScreenScale() / 5.f; + s *= (float)userScale; + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + + } + } + + public void update(Tuple3d cameraPosition, JmeRenderingComponent component) { + + com.jme.math.Vector3f p = VecmathJmeTools.get(getPosition()); + p.subtractLocal(VecmathJmeTools.get(cameraPosition)); + rotate.getLocalRotation().inverse().multLocal(p); + if (component.getProjectionPolicy() == JmeRenderingComponent.PERSPECTIVE_PROJECTION) { + + double distance = p.length(); + double fov = component.getFieldOfView(); + float s = (float)(Math.sin(fov) * distance * 0.1); // scaling factor was 0.2 with Xith + s *= (float)userScale; + Vector3f scale = new Vector3f(1.f,1.f,1.f); + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + } else { + + Vector3f scale = new Vector3f(1.f,1.f,1.f); + float s = component.getScreenScale()/5.f; + s *= (float)userScale; + if (p.x > 0.f) + scale.x = -1.f; + if (p.y > 0.f) + scale.y = -1.f; + if (p.z > 0.f) + scale.z = -1.f; + scale.scale(s); + setScale(scale); + + } + } + + protected void setCoordinate(float array[], int index, Tuple3f c) { + index *= 3; + array[index++] = c.x; + array[index++] = c.y; + array[index] = c.z; + } + + protected void setColor(float array[], int index, Color4f c) { + index *= 4; + array[index++] = c.x; + array[index++] = c.y; + array[index++] = c.z; + array[index] = c.w; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java new file mode 100644 index 00000000..0e791cac --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/Gizmo.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import com.jme.scene.Node; + +/** + * Interface for gizmos, interactive components in the scene-graph. + * + * @author Marko Luukkainen + * + */ +public interface Gizmo { + + /** + * Must return unique identifier for this gizmo + * @return + */ + public abstract String getPickPrefix(); + + /** + * Sets selected component (where mouse is hovering) by using its name. + * Name includes pick prefix + * @param name + */ + public abstract void setSelected(String name); + + /** + * Returns root-node of the gizmo. It is used for inserting the gizmo into scenegraph. + * @return + */ + public abstract Node getNode(); + + /** + * Returns true if gizmo needs to be redrawn. + * @return + */ + public boolean isChanged(); + + public void setChanged(boolean b); + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java new file mode 100644 index 00000000..b73b8865 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/MultiSelectionGizmo.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import java.nio.FloatBuffer; + +import javax.vecmath.Color4f; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.TriMesh; +import com.jme.util.geom.BufferUtils; + + + +public abstract class MultiSelectionGizmo extends AbstractGizmo { + + public static final int UNSELECTED = 0; + public static final int SELECTED = 1; + + private TriMesh geoms[] = new TriMesh[4]; + private ColorRGBA colors[][] = new ColorRGBA[4][2]; + + + private boolean selected[]; + + + private int selectedIndex = -1; + + + public MultiSelectionGizmo() { + super(); + + colors = new ColorRGBA[getCount()][2]; + geoms = new TriMesh[getCount()]; + selected = new boolean[getCount()]; + for (int i = 0; i < selected.length; i++) { + selected[i] = false; + } + } + + protected abstract int getCount(); + protected abstract int getIndexForName(String name); + + public int getSelected() { + return selectedIndex; + } + + private void updateColor(int index, int selected) { + + FloatBuffer buff = geoms[index].getColorBuffer(0); + for (int i = 0; i < geoms[index].getBatch(0).getVertexCount(); i++) { + BufferUtils.setInBuffer(colors[index][selected], buff, i); + } + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#changeSelected(java.lang.String) + */ + public void setSelected(String name) { + + if (name == null) { + for (int j = 0; j < getCount(); j++) { + if (selected[j]) { + selected[j] = false; + updateColor(j,UNSELECTED); + setChanged(true); + } + } + selectedIndex = -1; + return; + } + int index = getIndexForName(name); + if (index == -1) + return; + selectedIndex = index; + if (!selected[index]) { + selected[index] = true; + updateColor(index,SELECTED); + setChanged(true); + } + for (int j = 0; j < getCount(); j++) { + if (j != index) { + if (selected[j]) { + selected[j] = false; + updateColor(j,UNSELECTED); + setChanged(true); + } + } + } + } + + + protected void setGeometry(int index, TriMesh geom) { + geoms[index] = geom; + } + + protected void setColor(int index, int selected, Color4f color) { + colors[index][selected] = VecmathJmeTools.get(color); + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java new file mode 100644 index 00000000..dcf18d52 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/RotateGizmo.java @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.Renderer; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.geom.BufferUtils; + + + +public class RotateGizmo extends MultiSelectionGizmo { + + + public static String PICK_NAME = "rotate"; + public static String X_NAME = "rx"; + public static String Y_NAME = "ry"; + public static String Z_NAME = "rz"; + public static String XYZ_NAME = "ra"; + + public static final int X = 0; + public static final int Y = 1; + public static final int Z = 2; + public static final int XYZ = 3; + + + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#getPickPrefix() + */ + public String getPickPrefix() { + return PICK_NAME; + } + + public int getIndexForName(String name) { + if (!name.startsWith(PICK_NAME)) { + return -1; + } + name = name.substring(PICK_NAME.length()); + if (name.startsWith(X_NAME)) + return X; + if (name.startsWith(Y_NAME)) + return Y; + if (name.startsWith(Z_NAME)) + return Z; + if (name.startsWith(XYZ_NAME)) + return XYZ; + return -1; + } + + + @Override + public int getCount() { + return 4; + } + + public RotateGizmo(Renderer renderer) { + super(); + float radius = 2.f; + float radius2 = 1.8f; + int div = 9; + + float x[] = new float[div+1]; + float y[] = new float[div+1]; + float x2[] = new float[div+1]; + float y2[] = new float[div+1]; + x[0] = radius; + y[0] = 0.f; + x[div] = 0.f; + y[div] = radius; + x2[0] = radius2; + y2[0] = 0.f; + x2[div] = 0.f; + y2[div] = radius2; + + for (int i = 1; i < div; i++) { + float angle = (float)i/(float)div; + angle *= Math.PI * 0.5f; + float c = (float)Math.cos(angle); + float s = (float)Math.sin(angle); + x[i] = radius * c; + y[i] = radius * s; + x2[i] = radius2 * c; + y2[i] = radius2 * s; + + } + + Color4f colorx = new Color4f(0.5f,0.f,0.f,0.5f); + Color4f colory = new Color4f(0.f,0.5f,0.f,0.5f); + Color4f colorz = new Color4f(0.f,0.f,0.5f,0.5f); + Color4f scolorx = new Color4f(1.f,0.f,0.f,0.7f); + Color4f scolory = new Color4f(0.f,1.f,0.f,0.7f); + Color4f scolorz = new Color4f(0.f,0.f,1.f,0.7f); + + + Color4f colorxyz = new Color4f(); + colorxyz.x = colorx.x + colory.x + colorz.x; + colorxyz.y = colorx.y + colory.y + colorz.y; + colorxyz.z = colorx.z +colory.z + colorz.z; + colorxyz.w = 0.5f; + + Color4f scolorxyz = new Color4f(); + scolorxyz.x = scolorx.x + scolory.x + scolorz.x; + scolorxyz.y = scolorx.y + scolory.y + scolorz.y; + scolorxyz.z = scolorx.z + scolory.z + scolorz.z; + scolorxyz.w = 0.5f; + + int numVertices = div*2; + float coordinates[] = new float[numVertices*3 + numVertices*3]; + float cols[] = new float[numVertices*4*2]; + int[] indices = new int[numVertices*3-6+numVertices*3 - 12]; + for (int i = 0; i < div; i++) { + if (i == 0) { + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + continue; + } + int vIndex = i * 2 - 1; + int index = i * 6 - 3; + if (i == div - 1) { + indices[index] = vIndex; + indices[index+1] = vIndex+1; + indices[index+2] = vIndex+2; + + } else { + indices[index] = vIndex; + indices[index+1] = vIndex+1; + indices[index+2] = vIndex+2; + indices[index+3] = vIndex+1; + indices[index+4] = vIndex+3; + indices[index+5] = vIndex+2; + } + } + + for (int i = div+1; i < div * 2 - 1; i++) { + int vIndex = i * 2 - 1; + int index = i * 6 - 12; + + indices[index] = vIndex; + indices[index+1] = vIndex+1; + indices[index+2] = vIndex+2; + indices[index+3] = vIndex+1; + indices[index+4] = vIndex+3; + indices[index+5] = vIndex+2; + } + + for (int i = 0; i < numVertices*2; i++) + setColor(cols,i, colorx); + + setCoordinate(coordinates,0, new Point3f(0.f, x[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = i * 2 - 1; + setCoordinate(coordinates,index,new Point3f(0.f,x[i],y[i])); + setCoordinate(coordinates,index+1,new Point3f(y[1],x[i],y[i])); + } + setCoordinate(coordinates,numVertices - 1, new Point3f(0.f, 0.f, y[div])); + + setCoordinate(coordinates,numVertices, new Point3f(0.f, x2[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = (div+i) * 2 - 1; + setCoordinate(coordinates,index,new Point3f(y[1],x[i],y[i])); + setCoordinate(coordinates,index+1,new Point3f(y2[1],x2[i],y2[i])); + } + setCoordinate(coordinates,numVertices*2 - 1, new Point3f(0.f, 0.f, y2[div])); + + TriMesh linex = new TriMesh(PICK_NAME+X_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + for (int i = 0; i < numVertices*2; i++) + setColor(cols,i, colory); + + setCoordinate(coordinates,0, new Point3f(x[0], 0.f, 0.f)); + for (int i = 1; i < div; i++) { + int index = i * 2 - 1; + setCoordinate(coordinates,index,new Point3f(x[i],0.f,y[i])); + setCoordinate(coordinates,index+1,new Point3f(x[i],y[1],y[i])); + } + setCoordinate(coordinates,numVertices - 1, new Point3f(0.f, 0.f, y[div])); + + setCoordinate(coordinates,numVertices, new Point3f(x2[0], 0.f, 0.f)); + for (int i = 1; i < div; i++) { + int index = (div+i) * 2 - 1; + setCoordinate(coordinates,index,new Point3f(x[i],y[1],y[i])); + setCoordinate(coordinates,index+1,new Point3f(x2[i],y2[1],y2[i])); + } + setCoordinate(coordinates,numVertices*2 - 1, new Point3f(0.f, 0.f, y2[div])); + + TriMesh liney = new TriMesh(PICK_NAME+Y_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + for (int i = 0; i < numVertices*2; i++) + setColor(cols,i, colorz); + + setCoordinate(coordinates,0, new Point3f(0.f, x[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = i * 2 - 1; + setCoordinate(coordinates,index,new Point3f(y[i],x[i],0.f)); + setCoordinate(coordinates,index+1,new Point3f(y[i],x[i],y[1])); + } + setCoordinate(coordinates,numVertices - 1, new Point3f(y[div],0.f, 0.f)); + + setCoordinate(coordinates,numVertices, new Point3f(0.f, x2[0], 0.f)); + for (int i = 1; i < div; i++) { + int index = (div+i) * 2 - 1; + setCoordinate(coordinates,index,new Point3f(y[i],x[i],y[1])); + setCoordinate(coordinates,index+1,new Point3f(y2[i],x2[i],y2[1])); + } + setCoordinate(coordinates,numVertices*2 - 1, new Point3f(y2[div],0.f, 0.f)); + + TriMesh linez = new TriMesh(PICK_NAME+Z_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + numVertices = (div-2)*3+1; + coordinates = new float[numVertices*3]; + cols = new float[numVertices*4]; + indices = new int[(div-2)*3*3]; + + for (int i = 0; i < numVertices; i++) + setColor(cols,i, colorxyz); + float center = radius * 0.5f;//(float)Math.cos(Math.PI*0.25); + setCoordinate(coordinates,0,new Point3f(center,center,center)); + for (int i = 1; i < div; i++) { + int index = i; + setCoordinate(coordinates,index,new Point3f(y2[1],x2[i],y2[i])); + } + for (int i = 1; i < div; i++) { + int index = i + div-1 - 1; + setCoordinate(coordinates,index,new Point3f(y2[i],y2[1],x2[i])); + } + for (int i = 1; i < div-1; i++) { + int index = i + 2*(div-1) -2; + setCoordinate(coordinates,index,new Point3f(x2[i],y2[i],y2[1])); + } + for (int i = 0; i < (div-2)*3; i++) { + int index = i*3; + int iindex = i+1; + indices[index] = 0; + indices[index+1] = iindex; + indices[index+2] = iindex+1; + if (iindex == (numVertices -1)) + indices[index+2] = 1; + + } + + TriMesh trianglexyz = new TriMesh(PICK_NAME+XYZ_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + + getGizmoNode().attachChild(linex); + getGizmoNode().attachChild(liney); + getGizmoNode().attachChild(linez); + getGizmoNode().attachChild(trianglexyz); + getGizmoNode().setModelBound(new BoundingBox()); + getGizmoNode().updateModelBound(); + + linex.getBatch(0).setCastsShadows(false); + liney.getBatch(0).setCastsShadows(false); + linez.getBatch(0).setCastsShadows(false); + trianglexyz.getBatch(0).setCastsShadows(false); + + setGeometry(0,linex); + setGeometry(1,liney); + setGeometry(2,linez); + setGeometry(3,trianglexyz); + + setColor(0,0,colorx); + setColor(0,1,scolorx); + setColor(1,0,colory); + setColor(1,1,scolory); + setColor(2,0,colorz); + setColor(2,1,scolorz); + setColor(3,0,colorxyz); + setColor(3,1,scolorxyz); + + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setEnabled(true); + getGizmoNode().setRenderState(as); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + getGizmoNode().setRenderState(ms); + ZBufferState zs = renderer.createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + zs.setEnabled(true); + getGizmoNode().setRenderState(zs); + + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java new file mode 100644 index 00000000..b0e6df44 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformGizmo.java @@ -0,0 +1,316 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.Renderer; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.geom.BufferUtils; + + +public class TransformGizmo extends MultiSelectionGizmo { + + + public static String PICK_NAME = "translate"; + public static String X_NAME = "ax"; + public static String Y_NAME = "ay"; + public static String Z_NAME = "az"; + public static String XZ_NAME = "xz"; + public static String XY_NAME = "xy"; + public static String YZ_NAME = "yz"; + public static String XYZ_NAME = "aa"; + + public static final int X = 0; + public static final int Y = 1; + public static final int Z = 2; + public static final int XY = 3; + public static final int XZ = 4; + public static final int YZ = 5; + public static final int XYZ = 6; + + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#getPickPrefix() + */ + public String getPickPrefix() { + return PICK_NAME; + } + + public int getIndexForName(String name) { + if (!name.startsWith(PICK_NAME)) { + return -1; + } + name = name.substring(PICK_NAME.length()); + if (name.startsWith(X_NAME)) + return X; + if (name.startsWith(Y_NAME)) + return Y; + if (name.startsWith(Z_NAME)) + return Z; + if (name.startsWith(XY_NAME)) + return XY; + if (name.startsWith(XZ_NAME)) + return XZ; + if (name.startsWith(YZ_NAME)) + return YZ; + if (name.startsWith(XYZ_NAME)) + return XYZ; + return -1; + } + + @Override + public int getCount() { + return 7; + } + + + /* + public TransformGizmo() { + */ + public TransformGizmo(Renderer renderer) { + super(); + float size = 2.f; + float sizeD2 = 1.f; + float offset = 0.2f; + + Color4f colorx = new Color4f(0.5f,0.f,0.f,0.5f); + Color4f colory = new Color4f(0.f,0.5f,0.f,0.5f); + Color4f colorz = new Color4f(0.f,0.f,0.5f,0.5f); + Color4f scolorx = new Color4f(1.f,0.f,0.f,0.7f); + Color4f scolory = new Color4f(0.f,1.f,0.f,0.7f); + Color4f scolorz = new Color4f(0.f,0.f,1.f,0.7f); + + Color4f colorxy = new Color4f(); + colorxy.x = colorx.x + colory.x; + colorxy.y = colorx.y + colory.y; + colorxy.z = colorx.z + colory.z; + colorxy.w = 0.5f; + + Color4f colorxz = new Color4f(); + colorxz.x = colorx.x + colorz.x; + colorxz.y = colorx.y + colorz.y; + colorxz.z = colorx.z + colorz.z; + colorxz.w = 0.5f; + + Color4f coloryz = new Color4f(); + coloryz.x = colory.x + colorz.x; + coloryz.y = colory.y + colorz.y; + coloryz.z = colory.z + colorz.z; + coloryz.w = 0.5f; + + Color4f colorxyz = new Color4f(); + colorxyz.x = colorx.x + colory.x + colorz.x; + colorxyz.y = colorx.y + colory.y + colorz.y; + colorxyz.z = colorx.z +colory.z + colorz.z; + colorxyz.w = 0.5f; + + Color4f scolorxy = new Color4f(); + scolorxy.x = scolory.x + scolorx.x; + scolorxy.y = scolory.y + scolorx.y; + scolorxy.z = scolory.z + scolorx.z; + scolorxy.w = 0.5f; + + Color4f scolorxz = new Color4f(); + scolorxz.x = scolorx.x + scolorz.x; + scolorxz.y = scolorx.y + scolorz.y; + scolorxz.z = scolorx.z + scolorz.z; + scolorxz.w = 0.5f; + + Color4f scoloryz = new Color4f(); + scoloryz.x = scolory.x + scolorz.x; + scoloryz.y = scolory.y + scolorz.y; + scoloryz.z = scolory.z + scolorz.z; + scoloryz.w = 0.5f; + + Color4f scolorxyz = new Color4f(); + scolorxyz.x = scolorx.x + scolory.x + scolorz.x; + scolorxyz.y = scolorx.y + scolory.y + scolorz.y; + scolorxyz.z = scolorx.z + scolory.z + scolorz.z; + scolorxyz.w = 0.5f; + + + float coordinates[] = new float[6*3]; + float cols[] = new float[6*4]; + int[] indices = new int[]{0,1,3, + 1,2,3, + 0,3,5, + 3,4,5}; + for (int i = 0; i < 6; i++) + setColor(cols,i, colorx); + + setCoordinate(coordinates,0, new Point3f(size, 0.f, 0.f)); + setCoordinate(coordinates,1, new Point3f(size - offset, offset, 0.f)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(sizeD2, 0.f, 0.f)); + setCoordinate(coordinates,4, new Point3f(sizeD2 - offset, 0.f, offset)); + setCoordinate(coordinates,5, new Point3f(size - offset, 0.f, offset)); + + TriMesh linex = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 6; i++) + setColor(cols,i, colory); + + setCoordinate(coordinates,0, new Point3f(0.f, size, 0.f)); + setCoordinate(coordinates,1, new Point3f(offset, size - offset, 0.f)); + setCoordinate(coordinates,2, new Point3f(offset, sizeD2 - offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(0.f, sizeD2, 0.f)); + setCoordinate(coordinates,4, new Point3f(0.f, sizeD2 - offset, offset)); + setCoordinate(coordinates,5, new Point3f(0.f, size - offset, offset)); + + TriMesh liney = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 6; i++) + setColor(cols,i, colorz); + + setCoordinate(coordinates,0, new Point3f(0.f, 0.f,size)); + setCoordinate(coordinates,1, new Point3f(offset, 0.f, size - offset)); + setCoordinate(coordinates,2, new Point3f(offset, 0.f, sizeD2 - offset)); + setCoordinate(coordinates,3, new Point3f(0.f, 0.f, sizeD2)); + setCoordinate(coordinates,4, new Point3f(0.f, offset, sizeD2 - offset)); + setCoordinate(coordinates,5, new Point3f(0.f, offset, size - offset)); + + TriMesh linez = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + // TODO : picking did not work properly without chancing indices; this must be investigated + indices = new int[]{2,1,3,0,1,3};//{0,1,3,1,2,3}; + coordinates = new float[4*3]; + cols = new float[4*4]; + + for (int i = 0; i < 4; i++) + setColor(cols,i, colorxz); + setCoordinate(coordinates,0, new Point3f(offset, 0.f, size-offset)); + setCoordinate(coordinates,1, new Point3f(offset, 0.f, sizeD2 - offset)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, 0.f, offset)); + setCoordinate(coordinates,3, new Point3f(size-offset, 0.f, offset)); + + TriMesh trianglexz = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 4; i++) + setColor(cols,i, colorxy); + setCoordinate(coordinates,0, new Point3f(offset, size-offset, 0.f)); + setCoordinate(coordinates,1, new Point3f(offset, sizeD2 - offset, 0.f)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(size-offset, offset, 0.f)); + + TriMesh trianglexy = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + for (int i = 0; i < 4; i++) + setColor(cols,i, coloryz); + setCoordinate(coordinates,0, new Point3f( 0.f,offset, size-offset)); + setCoordinate(coordinates,1, new Point3f( 0.f,offset, sizeD2 - offset)); + setCoordinate(coordinates,2, new Point3f( 0.f,sizeD2 - offset, offset)); + setCoordinate(coordinates,3, new Point3f( 0.f,size-offset, offset)); + + TriMesh triangleyz = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + indices = new int[]{0,1,2, + 0,2,3, + 0,3,4, + 0,4,5, + 0,5,6, + 0,6,7, + 0,7,8, + 0,8,9, + 0,9,1}; + coordinates = new float[10*3]; + cols = new float[10*4]; + + for (int i = 0; i < 10; i++) + setColor(cols,i, colorxyz); + setCoordinate(coordinates,0, new Point3f(0.f, 0.f, 0.f)); + setCoordinate(coordinates,1, new Point3f(sizeD2, 0.f, 0.f)); + setCoordinate(coordinates,2, new Point3f(sizeD2 - offset, offset, 0.f)); + setCoordinate(coordinates,3, new Point3f(offset, sizeD2 - offset, 0.f)); + setCoordinate(coordinates,4, new Point3f(0.f, sizeD2, 0.f)); + setCoordinate(coordinates,5, new Point3f(0.f, sizeD2 - offset, offset)); + setCoordinate(coordinates,6, new Point3f(0.f, offset, sizeD2-offset)); + setCoordinate(coordinates,7, new Point3f(0.f, 0.f, sizeD2)); + setCoordinate(coordinates,8, new Point3f(offset, 0.f, sizeD2-offset)); + setCoordinate(coordinates,9, new Point3f(sizeD2-offset, 0.f, offset)); + + TriMesh trianglexyz = new TriMesh("",BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + linex.setName(PICK_NAME+X_NAME); + liney.setName(PICK_NAME+Y_NAME); + linez.setName(PICK_NAME+Z_NAME); + trianglexy.setName(PICK_NAME+XY_NAME); + trianglexz.setName(PICK_NAME+XZ_NAME); + triangleyz.setName(PICK_NAME+YZ_NAME); + trianglexyz.setName(PICK_NAME+XYZ_NAME); + + linex.getBatch(0).setCastsShadows(false); + liney.getBatch(0).setCastsShadows(false); + linez.getBatch(0).setCastsShadows(false); + trianglexy.getBatch(0).setCastsShadows(false); + trianglexz.getBatch(0).setCastsShadows(false); + triangleyz.getBatch(0).setCastsShadows(false); + trianglexyz.getBatch(0).setCastsShadows(false); + + getGizmoNode().attachChild(linex); + getGizmoNode().attachChild(liney); + getGizmoNode().attachChild(linez); + getGizmoNode().attachChild(trianglexy); + getGizmoNode().attachChild(trianglexz); + getGizmoNode().attachChild(triangleyz); + getGizmoNode().attachChild(trianglexyz); + getGizmoNode().setModelBound(new BoundingBox()); + getGizmoNode().updateModelBound(); + + setGeometry(0,linex); + setGeometry(1,liney); + setGeometry(2,linez); + setGeometry(3,trianglexy); + setGeometry(4,trianglexz); + setGeometry(5,triangleyz); + setGeometry(6,trianglexyz); + + + setColor(0,0,colorx); + setColor(0,1,scolorx); + setColor(1,0,colory); + setColor(1,1,scolory); + setColor(2,0,colorz); + setColor(2,1,scolorz); + setColor(3,0,colorxy); + setColor(3,1,scolorxy); + setColor(4,0,colorxz); + setColor(4,1,scolorxz); + setColor(5,0,coloryz); + setColor(5,1,scoloryz); + setColor(6,0,colorxyz); + setColor(6,1,scolorxyz); + + + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setEnabled(true); + getGizmoNode().setRenderState(as); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + getGizmoNode().setRenderState(ms); + ZBufferState zs = renderer.createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + zs.setEnabled(true); + zs.setWritable(false); + getGizmoNode().setRenderState(zs); + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java new file mode 100644 index 00000000..23ba6e00 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/gizmo/TransformInlineGizmo.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.gizmo; + +import java.nio.FloatBuffer; + +import javax.vecmath.Color4f; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +import org.simantics.proconf.g3d.base.VecmathJmeTools; + +import com.jme.bounding.BoundingBox; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.ZBufferState; +import com.jme.util.geom.BufferUtils; + + +public class TransformInlineGizmo extends AbstractGizmo { + + TriMesh geom = new TriMesh(); + ColorRGBA colors[] = new ColorRGBA[2]; + + + public static String PICK_NAME = "translate"; + public static String X_NAME = "ax"; + + public static final int X = 0; + + public static final int SELECTED = 1; + public static final int UNSELECTED = 0; + + private boolean selected = false; + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#getPickPrefix() + */ + public String getPickPrefix() { + return PICK_NAME; + } + + public int getIndexForName(String name) { + if (!name.startsWith(PICK_NAME)) { + return -1; + } + name = name.substring(PICK_NAME.length()); + if (name.startsWith(X_NAME)) + return X; + return -1; + } + + private void updateColor(int sel) { + FloatBuffer buff = geom.getColorBuffer(0); + for (int i = 0; i < geom.getBatch(0).getVertexCount(); i++) { + BufferUtils.setInBuffer(colors[sel], buff, i); + } + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.common.Gizmo#changeSelected(java.lang.String) + */ + public void setSelected(String name) { + + if (name == null) { + setChanged(true); + updateColor(UNSELECTED); + selected = false; + return; + } + int index = getIndexForName(name); + if (index == -1) { + selected = false; + return; + } + + selected = true; + updateColor(SELECTED); + setChanged(true); + + } + + @Override + public void setScale(Vector3f scale) { + /** + * A bug in JME (?) + * Negative scaling breaks picking (ray hits the bounding box, but ray doesn't intersect any triangles) + */ + scale.x = Math.abs(scale.x); + scale.y = Math.abs(scale.y); + scale.z = Math.abs(scale.z); + + super.setScale(scale); + } + + + /* + public TransformInlineGizmo(){ + */ + public TransformInlineGizmo(Renderer renderer) { + super(); + float size = 2.f; + float sizeD2 = 1.f; + float offset = 0.07f; + + Color4f colorx = new Color4f(0.5f,0.f,0.f,0.5f); + Color4f scolorx = new Color4f(1.f,0.f,0.f,0.7f); + + + float coordinates[] = new float[18*3]; + float cols[] = new float[18*4]; + int[] indices = new int[]{0,2,1, + 0,3,2, + 0,4,3, + 0,1,4, + 1,2,6, + 1,6,5, + 2,3,7, + 2,7,6, + 3,4,8, + 3,8,7, + 4,1,5, + 4,5,8, + 5,6,7, + 5,7,8, + + 9,11,10, + 9,12,11, + 9,13,12, + 9,10,13, + 10,11,15, + 10,15,14, + 11,12,16, + 11,16,15, + 12,13,17, + 12,17,16, + 13,10,14, + 13,14,17, + 14,15,16, + 14,16,17 + + }; + for (int i = 0; i < 18; i++) + setColor(cols,i, colorx); + + setCoordinate(coordinates,0, new Point3f(size, 0.f, 0.f)); + setCoordinate(coordinates,1, new Point3f(size - offset*2, offset, offset)); + setCoordinate(coordinates,2, new Point3f(size - offset*2, offset, -offset)); + setCoordinate(coordinates,3, new Point3f(size - offset*2, -offset, -offset)); + setCoordinate(coordinates,4, new Point3f(size - offset*2, -offset, offset)); + setCoordinate(coordinates,5, new Point3f(sizeD2, offset, offset)); + setCoordinate(coordinates,6, new Point3f(sizeD2, offset, -offset)); + setCoordinate(coordinates,7, new Point3f(sizeD2, -offset, -offset)); + setCoordinate(coordinates,8, new Point3f(sizeD2, -offset, offset)); + + setCoordinate(coordinates,9, new Point3f(-size, 0.f, 0.f)); + setCoordinate(coordinates,10, new Point3f(-size + offset*2, offset, offset)); + setCoordinate(coordinates,11, new Point3f(-size + offset*2, offset, -offset)); + setCoordinate(coordinates,12, new Point3f(-size + offset*2, -offset, -offset)); + setCoordinate(coordinates,13, new Point3f(-size + offset*2, -offset, offset)); + setCoordinate(coordinates,14, new Point3f(-sizeD2, offset, offset)); + setCoordinate(coordinates,15, new Point3f(-sizeD2, offset, -offset)); + setCoordinate(coordinates,16, new Point3f(-sizeD2, -offset, -offset)); + setCoordinate(coordinates,17, new Point3f(-sizeD2, -offset, offset)); + + TriMesh linex = new TriMesh(PICK_NAME+X_NAME,BufferUtils.createFloatBuffer(coordinates),null,BufferUtils.createFloatBuffer(cols),null,BufferUtils.createIntBuffer(indices)); + + getGizmoNode().attachChild(linex); + getGizmoNode().setModelBound(new BoundingBox()); + getGizmoNode().updateModelBound(); + + geom = linex; + geom.getBatch(0).setCastsShadows(false); + + colors[0] = VecmathJmeTools.get(colorx); + colors[1] = VecmathJmeTools.get(scolorx); + + AlphaState as = renderer.createAlphaState(); + as.setBlendEnabled(true); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setEnabled(true); + getGizmoNode().setRenderState(as); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_AMBIENT_AND_DIFFUSE); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + getGizmoNode().setRenderState(ms); + ZBufferState zs = renderer.createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + zs.setEnabled(true); + getGizmoNode().setRenderState(zs); + + } + + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java new file mode 100644 index 00000000..ec152390 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/AWTInputProvider.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.input; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +public class AWTInputProvider implements KeyListener, MouseListener, MouseMotionListener , InputProvider{ + + private boolean keyPressed[] = new boolean[1024]; + private boolean keyTemp[] = new boolean[1024]; + private boolean keyDown[] = new boolean[1024]; + private boolean keyUp[] = new boolean[1024]; + + private int awtMouseX = 0; + private int awtMouseY = 0; + private boolean awtPressed = false; + private boolean awtDragged = false; + private boolean awtReleased = false; + private boolean awtMouseClicked = false; + private boolean awtMouseMoved = false; + + private int awtPressModifiers = 0; + private int awtDragModifiers = 0; + private int awtClickModifiers = 0; + private int awtMoveModifiers = 0; + private int awtClickButton = 0; + + private int mouseX = 0; + private int mouseY = 0; + + private int prevMouseX = 0; + private int prevMouseY = 0; + + private boolean mousePressed = false; + private boolean mouseDragged = false; + private boolean mouseReleased = false; + private boolean mouseClicked = false; + private boolean mouseMoved = false; + + private int pressModifiers = 0; + private int clickModifiers = 0; + private int dragModifiers = 0; + private int clickButton = 0; + private int moveModifiers = 0; + + public AWTInputProvider() { + for (int i = 0; i < keyDown.length; i++) { + keyDown[i] = false; + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + } + + public boolean keyPressed(int i) { + return keyPressed[i]; + } + + public boolean keyDown(int i) { + return keyDown[i]; + } + + public boolean keyUp(int i) { + return keyUp[i]; + } + + public int mouseX() { + return mouseX; + } + + public int mouseY() { + return mouseY; + } + + public int prevMouseX() { + return prevMouseX; + } + + public int prevMouseY() { + return prevMouseY; + } + + public boolean mousePressed() { + return mousePressed; + } + + public boolean mouseMoved() { + return mouseMoved; + } + + public boolean mouseReleased() { + return mouseReleased; + } + + public boolean mouseClicked() { + return mouseClicked; + } + + public boolean mouseDragged() { + return mouseDragged; + } + + public int pressModifiers() { + return pressModifiers; + } + + public int clickModifiers() { + return clickModifiers; + } + + public int dragModifiers() { + return dragModifiers; + } + + public int moveModifiers() { + return moveModifiers; + } + + public int clickButton() { + return clickButton; + } + + + public void update() { + prevMouseX = mouseX; + prevMouseY = mouseY; + mouseX = awtMouseX; + mouseY = awtMouseY; + //System.out.println(mouseX + " " + mouseY); + mousePressed = awtPressed; + awtPressed = false; + mouseReleased = awtReleased; + awtReleased = false; + mouseMoved = awtMouseMoved; + awtMouseMoved = false; + mouseDragged = awtDragged; + awtDragged = false; + mouseClicked = awtMouseClicked; + awtMouseClicked = false; + pressModifiers = awtPressModifiers; + // awtPressModifiers = 0; + clickModifiers = awtClickModifiers; + //awtClickModifiers = 0; + dragModifiers = awtDragModifiers; + // awtDragModifiers = 0; + moveModifiers = awtMoveModifiers; + //awtMoveModifiers = 0; + clickButton = awtClickButton; + awtClickButton = 0; + for (int i = 0; i < keyDown.length; i++) { + if (keyDown[i] && !keyTemp[i]) { + keyTemp[i] = true; + keyPressed[i] = true; + } + else if (keyDown[i] && keyTemp[i]) { + keyPressed[i] = false; + } + else if (!keyDown[i] && keyTemp[i]) { + keyUp[i] = true; + keyTemp[i] = false; + keyPressed[i] = false; + } + else if (!keyDown[i]) { + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + } + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) + */ + public void mouseDragged(MouseEvent e) { + awtMouseX = e.getX(); + awtMouseY = e.getY(); + awtDragged = true; + awtDragModifiers = e.getModifiers() | e.getButton(); + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) + */ + public void mouseReleased(MouseEvent e) { + awtReleased = true; + //ms.set(msTmp); + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) + */ + public void mouseClicked(MouseEvent e) { + + awtMouseX = e.getX(); + awtMouseY = e.getY(); + e.getButton(); + + awtClickModifiers = e.getModifiersEx(); + awtClickButton = e.getButton(); + awtMouseClicked = true; + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) + */ + public void mouseEntered(MouseEvent arg0) { + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) + */ + public void mouseExited(MouseEvent arg0) { + + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) + */ + public void mouseMoved(MouseEvent arg0) { + + awtMouseMoved = true; + awtMouseX = arg0.getX(); + awtMouseY = arg0.getY(); + awtMoveModifiers = arg0.getModifiersEx(); + + } + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) + */ + public void keyPressed(KeyEvent arg0) { + keyDown[arg0.getKeyCode()] = true; + } + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) + */ + public void keyReleased(KeyEvent arg0) { + keyDown[arg0.getKeyCode()] = false; + } + + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) + */ + public void keyTyped(KeyEvent e) { + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) + */ + public void mousePressed(MouseEvent e) { + awtMouseX = e.getX(); + awtMouseY = e.getY(); + awtPressed = true; + awtPressModifiers = e.getModifiers() | e.getButton(); + } + + public void setMouseMoved(boolean b) { + + } + + public void setMouseX(int x) { + + } + + public void setMouseY(int y) { + + } + + public String toString() { + String s = ""; + s += "(" + mouseX + "," + mouseY + ")\n"; + s += "Pressed " + mousePressed + "\n"; + s += "Released " + mouseReleased + "\n"; + s += "Moved " + mouseMoved + "\n"; + s += "Dragged " + mouseDragged + "\n"; + s += "Clicked " + mouseClicked + "\n"; + s += "DragModifiers " + dragModifiers + "\n"; + s += "ClickModifiers " + clickModifiers + "\n"; + s += "PressModifiers " + pressModifiers + "\n"; + return s; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java new file mode 100644 index 00000000..1f1f56bd --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/InputProvider.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.input; + + +/** + * InputProvider is used to listen inputs from AWT-thread, + * and then input actions can be polled from the provider. + * + * TODO : use methods instead of public members + * + * @author Marko Luukkainen + * + */ +public interface InputProvider { + + + + public boolean keyPressed(int i); + + public boolean keyDown(int i); + + public boolean keyUp(int i); + + public int mouseX(); + + public int mouseY(); + + public int prevMouseX(); + + public int prevMouseY(); + + public boolean mousePressed(); + + public boolean mouseMoved(); + + public boolean mouseReleased(); + + public boolean mouseClicked(); + + public boolean mouseDragged(); + + public int pressModifiers(); + + public int clickModifiers(); + + public int dragModifiers(); + + public int moveModifiers(); + + public int clickButton(); + + + public void update(); + + // FIXME : when dnd is used, mouse inputs won't get passed + + public void setMouseX(int x); + public void setMouseY(int y); + public void setMouseMoved(boolean b); + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java new file mode 100644 index 00000000..a21d3b79 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/input/SWTInputProvider.java @@ -0,0 +1,511 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.input; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; + +public class SWTInputProvider implements KeyListener, MouseListener, MouseMoveListener, MouseTrackListener, InputProvider, FocusListener { + + private static final int PRESS_TIME = 200; + + private boolean keyPressed[] = new boolean[1024]; + private boolean keyTemp[] = new boolean[1024]; + private boolean keyDown[] = new boolean[1024]; + private boolean keyUp[] = new boolean[1024]; + + private int awtMouseX = 0; + private int awtMouseY = 0; + private boolean awtPressed = false; + private boolean awtDragged = false; + private boolean awtReleased = false; + private boolean awtMouseClicked = false; + private boolean awtMouseMoved = false; + + private boolean swtMouse1Down = false; + private boolean swtMouse2Down = false; + private boolean swtMouse3Down = false; + + long mouse1DownTime = 0; + long mouse2DownTime = 0; + long mouse3DownTime = 0; + + private int awtPressModifiers = 0; + private int awtDragModifiers = 0; + private int awtClickModifiers = 0; + private int awtMoveModifiers = 0; + private int awtClickButton = 0; + + private int mouseX = 0; + private int mouseY = 0; + + private int prevMouseX = 0; + private int prevMouseY = 0; + + private boolean mousePressed = false; + private boolean mouseDragged = false; + private boolean mouseReleased = false; + private boolean mouseClicked = false; + private boolean mouseMoved = false; + + private int pressModifiers = 0; + private int clickModifiers = 0; + private int dragModifiers = 0; + private int clickButton = 0; + private int moveModifiers = 0; + + public SWTInputProvider() { + reset(); + } + + private void reset() { + for (int i = 0; i < keyDown.length; i++) { + keyDown[i] = false; + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + mousePressed = false; + mouseDragged = false; + mouseReleased = false; + mouseClicked = false; + mouseMoved = false; + + pressModifiers = 0; + clickModifiers = 0; + dragModifiers = 0; + clickButton = 0; + moveModifiers = 0; + } + + public boolean keyPressed(int i) { + return keyPressed[i]; + } + + public boolean keyDown(int i) { + return keyDown[i]; + } + + public boolean keyUp(int i) { + return keyUp[i]; + } + + public int mouseX() { + return mouseX; + } + + public int mouseY() { + return mouseY; + } + + public int prevMouseX() { + return prevMouseX; + } + + public int prevMouseY() { + return prevMouseY; + } + + public boolean mousePressed() { + return mousePressed; + } + + public boolean mouseMoved() { + return mouseMoved; + } + + public boolean mouseReleased() { + return mouseReleased; + } + + public boolean mouseClicked() { + return mouseClicked; + } + + public boolean mouseDragged() { + return mouseDragged; + } + + public int pressModifiers() { + return pressModifiers; + } + + public int clickModifiers() { + return clickModifiers; + } + + public int dragModifiers() { + return dragModifiers; + } + + public int moveModifiers() { + return moveModifiers; + } + + public int clickButton() { + return clickButton; + } + + + public void update() { + prevMouseX = mouseX; + prevMouseY = mouseY; + mouseX = awtMouseX; + mouseY = awtMouseY; + //System.out.println(mouseX + " " + mouseY); + mousePressed = awtPressed; + awtPressed = false; + mouseReleased = awtReleased; + awtReleased = false; + mouseMoved = awtMouseMoved; + awtMouseMoved = false; + mouseDragged = awtDragged; + awtDragged = false; + mouseClicked = awtMouseClicked; + awtMouseClicked = false; + pressModifiers = awtPressModifiers; + // awtPressModifiers = 0; + clickModifiers = awtClickModifiers; + //awtClickModifiers = 0; + dragModifiers = awtDragModifiers; + // awtDragModifiers = 0; + moveModifiers = awtMoveModifiers; + //awtMoveModifiers = 0; + clickButton = awtClickButton; + awtClickButton = 0; + for (int i = 0; i < keyDown.length; i++) { + if (keyDown[i] && !keyTemp[i]) { + keyTemp[i] = true; + keyPressed[i] = true; + } + else if (keyDown[i] && keyTemp[i]) { + keyPressed[i] = false; + } + else if (!keyDown[i] && keyTemp[i]) { + keyUp[i] = true; + keyTemp[i] = false; + keyPressed[i] = false; + } + else if (!keyDown[i]) { + keyTemp[i] = false; + keyPressed[i] = false; + keyUp[i] = false; + } + } + + } + + + + + private int getAWTKeyCode(int swtKeyCode) { + if(swtKeyCode > keyDown.length) { + int keyCode = 0; + switch (swtKeyCode) { + case SWT.CTRL: + keyCode = java.awt.event.KeyEvent.VK_CONTROL; + break; + case SWT.ALT: + keyCode = java.awt.event.KeyEvent.VK_ALT; + break; + + case SWT.SHIFT: + keyCode = java.awt.event.KeyEvent.VK_SHIFT; + break; + case SWT.ARROW_LEFT: + keyCode = java.awt.event.KeyEvent.VK_LEFT; + break; + case SWT.ARROW_RIGHT: + keyCode = java.awt.event.KeyEvent.VK_RIGHT; + break; + case SWT.ARROW_UP: + keyCode = java.awt.event.KeyEvent.VK_UP; + break; + case SWT.ARROW_DOWN: + keyCode = java.awt.event.KeyEvent.VK_DOWN; + break; + case SWT.KEYPAD_0: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD0; + break; + case SWT.KEYPAD_1: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD1; + break; + case SWT.KEYPAD_2: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD2; + break; + case SWT.KEYPAD_3: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD3; + break; + case SWT.KEYPAD_4: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD4; + break; + case SWT.KEYPAD_5: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD5; + break; + case SWT.KEYPAD_6: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD6; + break; + case SWT.KEYPAD_7: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD7; + break; + case SWT.KEYPAD_8: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD8; + break; + case SWT.KEYPAD_9: + keyCode = java.awt.event.KeyEvent.VK_NUMPAD9; + break; + case SWT.KEYPAD_CR: + keyCode = java.awt.event.KeyEvent.VK_ENTER; + break; + case SWT.NUM_LOCK: + keyCode = java.awt.event.KeyEvent.VK_NUM_LOCK; + break; + case SWT.SCROLL_LOCK: + keyCode = java.awt.event.KeyEvent.VK_SCROLL_LOCK; + break; + case SWT.CAPS_LOCK: + keyCode = java.awt.event.KeyEvent.VK_CAPS_LOCK; + break; + case SWT.INSERT: + keyCode = java.awt.event.KeyEvent.VK_INSERT; + break; + case SWT.HOME: + keyCode = java.awt.event.KeyEvent.VK_HOME; + break; + case SWT.END: + keyCode = java.awt.event.KeyEvent.VK_END; + break; + case SWT.PAGE_UP: + keyCode = java.awt.event.KeyEvent.VK_PAGE_UP; + break; + case SWT.PAGE_DOWN: + keyCode = java.awt.event.KeyEvent.VK_PAGE_DOWN; + break; + case SWT.PAUSE: + keyCode = java.awt.event.KeyEvent.VK_PAUSE; + break; + case SWT.BREAK: + keyCode = java.awt.event.KeyEvent.VK_PAUSE; + break; + case SWT.PRINT_SCREEN: + keyCode = java.awt.event.KeyEvent.VK_PRINTSCREEN; + break; + case SWT.HELP: + keyCode = java.awt.event.KeyEvent.VK_HELP; + break; + default : + keyCode = 0; + break; + } + + return keyCode; + } else if (swtKeyCode == 8) { + return java.awt.event.KeyEvent.VK_BACK_SPACE; + } + else if (swtKeyCode >= 97 ) + return swtKeyCode - 32; + else + return swtKeyCode; + } + + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) + */ + public void keyPressed(KeyEvent arg0) { + //System.out.println("KeyPressed " + arg0.character + " " + arg0.keyCode + " " + getAWTKeyCode(arg0.keyCode)); + keyDown[getAWTKeyCode(arg0.keyCode)] = true; + } + + /* (non-Javadoc) + * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) + */ + public void keyReleased(KeyEvent arg0) { + //System.out.println("KeyReleased " + arg0.character + " " + arg0.keyCode + " " + getAWTKeyCode(arg0.keyCode)); + + keyDown[getAWTKeyCode(arg0.keyCode)] = false; + } + + public void mouseMove(MouseEvent e) { + awtMouseX = e.x; + awtMouseY = e.y; + if (swtMouse1Down || swtMouse2Down || swtMouse3Down) { + // comparing times so that drag event won't be send at the time when mouse button was pressed + long time = e.time & 0xFFFFFFFFL; + boolean drag = false; + if (swtMouse1Down) { + drag = time > mouse1DownTime; + } else if (swtMouse2Down) { + drag = time > mouse2DownTime; + } else { + drag = time > mouse3DownTime; + } + if (drag) { + awtDragged = true; + awtDragModifiers = createButtonMask(e); + } + } else { + awtMoveModifiers = createButtonMask(e); + awtMouseMoved = true; + } + } + + public void mouseDoubleClick(MouseEvent e) { + /* + awtMouseClicked = true; + awtClickModifiers = createButtonMask(e); + switch (e.button) { + case 1: + awtClickButton = java.awt.event.MouseEvent.BUTTON1; + break; + case 2: + awtClickButton = java.awt.event.MouseEvent.BUTTON2; + break; + case 3: + awtClickButton = java.awt.event.MouseEvent.BUTTON3; + break; + + } + */ + } + + private int createButtonMask(MouseEvent e) { + int mask = 0; + if (swtMouse1Down) + mask |= java.awt.event.MouseEvent.BUTTON1_DOWN_MASK | java.awt.event.MouseEvent.BUTTON1_MASK; + if (swtMouse2Down) + mask |= java.awt.event.MouseEvent.BUTTON2_DOWN_MASK | java.awt.event.MouseEvent.BUTTON2_MASK; + if (swtMouse3Down) + mask |= java.awt.event.MouseEvent.BUTTON3_DOWN_MASK | java.awt.event.MouseEvent.BUTTON3_MASK; + if ((e.stateMask & SWT.CTRL) > 0) + mask |= java.awt.event.MouseEvent.CTRL_DOWN_MASK | java.awt.event.MouseEvent.CTRL_MASK; + if ((e.stateMask & SWT.CTRL) > 0) + mask |= java.awt.event.MouseEvent.ALT_DOWN_MASK | java.awt.event.MouseEvent.ALT_MASK; + + + return mask; + } + + public void mouseDown(MouseEvent e) { + switch (e.button) { + case 1: + swtMouse1Down = true; + mouse1DownTime = e.time & 0xFFFFFFFFL; + break; + case 2: + swtMouse2Down = true; + mouse2DownTime = e.time & 0xFFFFFFFFL; + break; + case 3: + swtMouse3Down = true; + mouse3DownTime = e.time & 0xFFFFFFFFL; + }; + + awtPressed = true; + awtPressModifiers = createButtonMask(e); + } + + public void mouseUp(MouseEvent e) { + long mouseUpTime = e.time & 0xFFFFFFFFL; + long delta = 1000; + switch (e.button) { + case 1: + swtMouse1Down = false; + delta = mouseUpTime - mouse1DownTime; + break; + case 2: + swtMouse2Down = false; + delta = mouseUpTime - mouse2DownTime; + break; + case 3: + swtMouse3Down = false; + delta = mouseUpTime - mouse3DownTime; + }; + awtReleased = true; + + if (delta < PRESS_TIME) { + awtMouseClicked = true; + awtClickModifiers = createButtonMask(e); + switch (e.button) { + case 1: + awtClickButton = java.awt.event.MouseEvent.BUTTON1; + break; + case 2: + awtClickButton = java.awt.event.MouseEvent.BUTTON2; + break; + case 3: + awtClickButton = java.awt.event.MouseEvent.BUTTON3; + break; + + } + } + } + + + public void mouseEnter(MouseEvent e) { + + } + + public void mouseExit(MouseEvent e) { + awtReleased = false; + awtPressed = false; + swtMouse1Down = false; + swtMouse2Down = false; + swtMouse3Down = false; + + + } + + public void focusGained(FocusEvent e) { + + } + + public void focusLost(FocusEvent e) { + reset(); + } + + public void mouseHover(MouseEvent e) { + + } + + public void setMouseMoved(boolean b) { + awtMouseMoved = b; + } + + public void setMouseX(int x) { + awtMouseX = x; + } + + public void setMouseY(int y) { + awtMouseY = y; + } + + public String toString() { + String s = ""; + s += "(" + mouseX + "," + mouseY + ")\n"; + s += "Pressed " + mousePressed + "\n"; + s += "Released " + mouseReleased + "\n"; + s += "Moved " + mouseMoved + "\n"; + s += "Dragged " + mouseDragged + "\n"; + s += "Clicked " + mouseClicked + "\n"; + s += "DragModifiers " + dragModifiers + "\n"; + s += "ClickModifiers " + clickModifiers + "\n"; + s += "PressModifiers " + pressModifiers + "\n"; + return s; + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java new file mode 100644 index 00000000..98230ebe --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/G3DPreferencesPage.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.preferences; + +import org.eclipse.jface.preference.*; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.IWorkbench; +import org.simantics.proconf.g3d.Activator; + + +/** + * This class represents a preference page that + * is contributed to the Preferences dialog. By + * subclassing FieldEditorPreferencePage, we + * can use the field support built into JFace that allows + * us to create a page that is small and knows how to + * save, restore and apply itself. + *

+ * This page is used to modify preferences only. They + * are stored in the preference store that belongs to + * the main plug-in class. That way, preferences can + * be accessed directly via the preference store. + */ + +public class G3DPreferencesPage + extends FieldEditorPreferencePage + implements IWorkbenchPreferencePage { + + public G3DPreferencesPage() { + super(GRID); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + setDescription("A demonstration of a preference page implementation"); + } + + /** + * Creates the field editors. Field editors are abstractions of + * the common GUI blocks needed to manipulate various types + * of preferences. Each field editor knows how to save and + * restore itself. + */ + public void createFieldEditors() { +// addField(new DirectoryFieldEditor(PreferenceConstants.P_PATH, +// "&Directory preference:", getFieldEditorParent())); +// addField( +// new BooleanFieldEditor( +// PreferenceConstants.P_BOOLEAN, +// "&An example of a boolean preference", +// getFieldEditorParent())); +// +// addField(new RadioGroupFieldEditor( +// PreferenceConstants.P_CHOICE, +// "An example of a multiple-choice preference", +// 1, +// new String[][] { { "&Choice 1", "choice1" }, { +// "C&hoice 2", "choice2" } +// }, getFieldEditorParent())); +// addField( +// new StringFieldEditor(PreferenceConstants.P_STRING, "A &text preference:", getFieldEditorParent())); + addField(new BooleanFieldEditor(PreferenceConstants.SHADOWS,"Use Shadows",getFieldEditorParent())); + addField(new RadioGroupFieldEditor(PreferenceConstants.POST_PROCESS, "Post Processing", 1, + new String[][] { { "None", "none" }, + { "Sketch", "sketch" }, + { "Bloom", "bloom" }}, + getFieldEditorParent())); + addField(new ScaleFieldEditor(PreferenceConstants.GIZMO_SCALE,"Gizmo scale",getFieldEditorParent(),5,100,1,10) { + private double oldValue; + + @Override + protected void doStore() { + getPreferenceStore() + .setValue(getPreferenceName(), scale.getSelection()*0.1); + } + + @Override + protected void doLoadDefault() { + if (scale != null) { + double value = getPreferenceStore().getDefaultDouble(getPreferenceName()); + scale.setSelection((int)(value*10.0)); + } + valueChanged(); + } + + @Override + protected void doLoad() { + if (scale != null) { + double value = getPreferenceStore().getDouble(getPreferenceName()); + scale.setSelection((int)(value*10.0)); + oldValue = value; + }; + } + + @Override + protected void valueChanged() { + setPresentsDefaultValue(false); + + double newValue = scale.getSelection()*0.1; + if (newValue != oldValue) { + fireStateChanged(IS_VALID, false, true); + fireValueChanged(VALUE, new Double(oldValue), + new Double(newValue)); + oldValue = newValue; + } + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + public void init(IWorkbench workbench) { + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java new file mode 100644 index 00000000..c0163e7e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceConstants.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.preferences; + +/** + * Constant definitions for plug-in preferences + */ +public class PreferenceConstants { + + public static final String POST_PROCESS = "postProcess"; + public static final String SHADOWS = "shadows"; + public static final String GIZMO_SCALE = "gizmoScale"; + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java new file mode 100644 index 00000000..5a40d2fb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/preferences/PreferenceInitializer.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; +import org.simantics.proconf.g3d.Activator; + + +/** + * Class used to initialize default preference values. + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + public void initializeDefaultPreferences() { + IPreferenceStore store = Activator.getDefault() + .getPreferenceStore(); +// store.setDefault(PreferenceConstants.P_BOOLEAN, true); +// store.setDefault(PreferenceConstants.P_CHOICE, "choice2"); +// store.setDefault(PreferenceConstants.P_STRING,"Default value"); + store.setDefault(PreferenceConstants.POST_PROCESS, "none"); + store.setDefault(PreferenceConstants.SHADOWS, true); + store.setDefault(PreferenceConstants.GIZMO_SCALE, 1.0); + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java new file mode 100644 index 00000000..d1dde38e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/AbstractGraphicsNode.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Matrix3d; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3f; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + + +public abstract class AbstractGraphicsNode implements ISelectableNode { + + protected ThreeDimensionalEditorBase editor; + + protected IGraphicsNode parent = null; + + protected Resource shapeResource = null; + + protected boolean selected; + + protected Node parentGroup = null; + protected Node transform = null; + // protected Node center = null; + + protected String id; + + private ArrayList children = new ArrayList(); + + public AbstractGraphicsNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource shapeResource) { + assert (parent != null); + this.editor = editor; + this.parent = parent; + this.parentGroup = parent.getGroup(); + this.shapeResource = shapeResource; + this.id = editor.getScenegraphAdapter().getNodeUID(shapeResource); + createGroups(); + updateTransform(graph); + parent.addChild(this); + } + + @Override + public String getID() { + return id; + } + + public void setID(String id) { + this.id = id; + } + + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#getParent() + */ + public IGraphicsNode getParent() { + return parent; + } + + public Collection getChildren() { + return children; + } + + private void createGroups() { + transform = new Node(); // TODO : uid + parentGroup.attachChild(transform); + } + + public void addChild(IGraphicsNode node) { + children.add(node); + } + + public void removeChild(IGraphicsNode node) { + children.remove(node); + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#getGroup() + */ + public Node getGroup() { + //return center; + + return transform; + } + + /** + * Updates rotation and translation of the shape without recalculating + * geometry + */ + public void updateTransform(Graph graph) { + G3DNode shape = getG3DNode(graph); + if (shape.getLocalPosition() != null) + transform.setLocalTranslation(VecmathJmeTools.get(G3DTools.getVectorFloat(shape.getLocalPosition()))); + if (shape.getLocalOrientation() != null) + transform.setLocalRotation(VecmathJmeTools.get(G3DTools.getOrientationFloat(shape.getLocalOrientation()))); +// if (GraphicsNodeTools.hasCenter(shape)) { +// center.setLocalTranslation(VecmathJmeTools.get(GraphicsNodeTools.getCenterFloat(shape))); +// } + // FIXME : typically transforms are updated once per frame (root as initiator) but with threaded access transformation may be read wrong. + transform.updateWorldVectors(); + editor.getScenegraphAdapter().setChanged(true); + } + + + + protected void update(Matrix3d aa) { + transform.setLocalRotation(VecmathJmeTools.get(aa)); + } + protected void update(AxisAngle4f aa) { + transform.setLocalRotation(VecmathJmeTools.get(aa)); + } + + protected void update(AxisAngle4d aa) { + transform.setLocalRotation(VecmathJmeTools.get(aa)); + } + + protected void update(Quat4d q) { + transform.setLocalRotation(VecmathJmeTools.get(q)); + } + + protected void update(Vector3f v) { + transform.setLocalTranslation(VecmathJmeTools.get(v)); + } + + + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + } + + public boolean isSelected() { + return selected; + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#getResource() + */ + public Resource getResource() { + return shapeResource; + } + + public G3DNode getG3DNode(Graph graph) { + return new G3DNode(graph,shapeResource); + } + + /* (non-Javadoc) + * @see fi.vtt.proconf.shapeeditor.geometry.IGraphicsNode#dispose() + */ + public void dispose() { +// if (children.size() != 0) { +// System.out.print(getResource() + " contains children: "); +// ArrayList c = new ArrayList(children); +// for (IGraphicsNode n : c) { +// System.out.print(n.getResource() + " "); +// } +// System.out.println(); +// return; +// } + assert (children.size() == 0); + + transform.removeFromParent(); + transform.dispose(); + if (parent != null) + parent.removeChild(this); + } + + + public abstract void setPickable(boolean pickable); + + public String toString() { + return this.getClass().toString(); + } + + @Override + public int hashCode() { + return shapeResource.hashCode(); + } + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java new file mode 100644 index 00000000..94d3daed --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGeometryNode.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import org.simantics.db.Graph; + +public interface IGeometryNode extends IGraphicsNode{ + + public void updateGeometry(Graph graph); + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java new file mode 100644 index 00000000..a72aa5f1 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/IGraphicsNode.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +public interface IGraphicsNode { + + public IGraphicsNode getParent(); + + public Node getGroup(); + + public Resource getResource(); + + /** + * Disposes the node. Disposing of node that has children is not allowed. + */ + public void dispose(); + + public void updateTransform(Graph graph); + + public G3DNode getG3DNode(Graph graph); + + public void addChild(IGraphicsNode node); + public void removeChild(IGraphicsNode node); + public Collection getChildren(); + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java new file mode 100644 index 00000000..4abd1b3a --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ISelectableNode.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +public interface ISelectableNode extends IGraphicsNode{ + public void setVisible(boolean visible); + public boolean isVisible(); + public void setSelected(boolean selected); + public boolean isSelected(); + public void setHighlighted(boolean higlighted); + public boolean isHighlighted(); + public void setPickable(boolean pickable); + public String getID(); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java new file mode 100644 index 00000000..40e845a1 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ModelNode.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; + +public class ModelNode extends AbstractGraphicsNode implements Animatable, IGeometryNode{ + protected List shapes = new ArrayList(); + private boolean highlighted; + + protected Resource modelResource; + + private boolean geometryCreated = false; + + public ModelNode(ThreeDimensionalEditorBase editor,IGraphicsNode parent, Graph graph, Resource shapeResource) { + super(editor,parent, graph, shapeResource); + + } + + protected void createGeometry(Graph graph) { + + if (modelResource != null) { + G3DModel model = getG3DModel(graph); + Collection nodes = model.getChild(); + if (nodes.size() == 0) { + ErrorLogger.defaultLogError("ModelNode " + model.getResource() + " has no shapes", null); + return; + } + for (G3DNode node: nodes) { + ShapeNode shape = new ShapeNode(editor,this,graph,node.getResource()); + shapes.add(shape); + + shape.setID(getID()); + shape.setVisible(true); + shape.updateGeometry(graph); + createRecursive(graph,shape); + } + geometryCreated = true; + } + } + + private void createRecursive(Graph graph,IGraphicsNode parentNode) { + Collection nodes = parentNode.getG3DNode(graph).getChild(); + for (G3DNode node: nodes) { + if (node.getRelatedObjects(Resources.g3dResource.GeometryDefinitionOf).size() == 0) { + ShapeNode shape = new ShapeNode(editor,parentNode,graph,node.getResource()); + shapes.add(shape); + + shape.setID(getID()); + shape.setVisible(true); + shape.updateGeometry(graph); + createRecursive(graph,shape); + } + } + } + + public void updateGeometry(Graph graph) { + if (!geometryCreated) { + createGeometry(graph); + return; + } + updateTransform(graph); +// for (IGraphicsNode node : getChildren()) { +// ((IGeometryNode)node).updateGeometry(); +// } + for (ShapeNode node : shapes) + node.updateGeometry(graph); + } + + public boolean isVisible() { + for (IGraphicsNode n : getChildren()) + if (n instanceof ISelectableNode) + if (!((ISelectableNode)n).isVisible()) + return false; + return true; + } + + public void setVisible(boolean visible) { + for (IGraphicsNode node : getChildren()) { + if (node instanceof ISelectableNode) + ((ISelectableNode)node).setVisible(visible); + } + } + + @Override + public void dispose() { + // shapes must be removed reverse order (leafs first) + for (int i = shapes.size() - 1; i >= 0; i--) { + shapes.get(i).dispose(); + } + super.dispose(); + } + + + @Override + public void setPickable(boolean pickable) { + for(ShapeNode n : shapes) { + n.setPickable(pickable); + } + } + + public boolean isHighlighted() { + return highlighted; + } + + public void setHighlighted(boolean selected) { + if (this.highlighted == selected) + return; + this.highlighted = selected; + for (ShapeNode n : shapes) + n.setHighlighted(selected); + + } + + @Override + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + for (ShapeNode n : shapes) + n.setSelected(selected); + } + + public void animate(double delta, double frameTime) { + for (ShapeNode n : shapes) + n.animate(delta,frameTime); + } + + public G3DModel getG3DModel(Graph graph) { + return new G3DModel(graph, modelResource); + } + + public boolean setAnimation(Graph graph, Resource animation) { + if (modelResource == null) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it has no graphics", null); + return false; + } + Collection animations = graph.getObjects(modelResource, Resources.animationResource.HasAnimation); + if (!animations.contains(animation)) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it doesn't have requested animation " + animation.getResource(), null); + return false; + } + + boolean set = false; + for (ShapeNode n : shapes) { + if (n.setAnimation(graph,animation)) + set = true; + } + return set; + } + + public boolean setRandomAnimation(Graph graph) { + if (modelResource == null) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it has no graphics", null); + return false; + } + G3DModel model = getG3DModel(graph); + Collection animations = model.getAnimation(); + int num = animations.size(); + if (num == 0) { + ErrorLogger.getDefault().logWarning("Cannot set animation for " + shapeResource + " since it has no animations", null); + return false; + } + int random = (int)Math.round(Math.random() * (num-1)); + Iterator i = animations.iterator(); + while(random > 0) { + i.next(); + random--; + } + return setAnimation(graph,i.next().getResource()); + + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java new file mode 100644 index 00000000..2c020971 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/NonTransformableNode.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; + +public abstract class NonTransformableNode implements IGraphicsNode { + + private IGraphicsNode parent; + private ArrayList children = new ArrayList(); + protected Node parentGroup = null; + protected Resource nodeResource; + + public NonTransformableNode(IGraphicsNode parent, Resource nodeResource) { + this.parent = parent; + this.nodeResource = nodeResource; + parentGroup = parent.getGroup(); + parent.addChild(this); + } + + public void addChild(IGraphicsNode node) { + children.add(node); + + } + + public Collection getChildren() { + return children; + } + + public void removeChild(IGraphicsNode node) { + children.remove(node); + + } + + public void dispose() { + assert(children.size() == 0); + if (parent != null) + parent.removeChild(this); + } + + public G3DNode getG3DNode(Graph graph) { + return new G3DNode(graph, nodeResource); + } + + public Node getGroup() { + return parentGroup; + } + + + public IGraphicsNode getParent() { + return parent; + } + + + public Resource getResource() { + return nodeResource; + } + + public void updateTransform(Graph graph) { + + } + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java new file mode 100644 index 00000000..511a2fa9 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ParameterizedModelNode.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.simantics.db.Builtins; +import org.simantics.db.ContextGraph; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.equation.solver.Solver; +import org.simantics.g2d.stubs.anim.Animation; +import org.simantics.layer0.utils.Property; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.Statement; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.utils.ErrorLogger; + +/** + * IGraphicsNode for parameterized models. Implementation assumes that G3DNode itself does not contain + * graphical representation but has link to it. + * + * @author Marko Luukkainen + * + */ +public class ParameterizedModelNode extends ModelNode { + + /** + * @param editor + * @param parent + * @param graph + * @param resource this node (G3DNode). + * @param nodeToModelRelation relation from this node to the model, or from type of this node to the model. + * @param modelToParametersRelation relation from the model to its sizing parameters + */ + public ParameterizedModelNode(ThreeDimensionalEditorBase editor, IGraphicsNode parent, Graph graph, Resource resource, Resource nodeToModelRelation) { + super(editor,parent,graph,resource); + G3DNode shape = getG3DNode(graph); + List models = new ArrayList(); + models.addAll(shape.getRelatedObjects(nodeToModelRelation)); + if (models.size() == 0) { + Collection types = shape.getTypes(); + for (IEntity type : types) { + models.addAll(type.getRelatedObjects(nodeToModelRelation)); + } + } + if (models.size() != 1) + throw new IllegalArgumentException("Cannot find proper model: found " + models.size() + " models."); + + this.modelResource = models.iterator().next().getResource(); + } + + @Override + protected void createGeometry(Graph graph) { + super.createGeometry(createParameterization(graph)); + } + + @Override + public void updateGeometry(Graph graph) { + super.updateGeometry(createParameterization(graph)); + } + + private void updateSizeParameters(ContextGraph graph, Solver solver) { + Builtins builtins = graph.getBuiltins(); + + + G3DNode node = getG3DNode(graph); + //Collection nodeProperties = node.getRelatedProperties(builtins.HasProperty); + Collection nodeProperties = node.getRelatedStatements(builtins.HasProperty); + G3DModel model = getG3DModel(graph); + Collection modelProperties = model.getRelatedProperties(Resources.g3dResource.HasSizingParameter); + + // there are no relations between then nodes properties and the model's sizing parameters + // link between them is done by matching names + for (Property m : modelProperties) { + boolean set = false; + //if(m.canBeSet(builtins.HasName)) { + + String modelPropertyname = m.getAtMostOneRelatedProperty(builtins.HasName).getScalarString(); + for (Statement n : nodeProperties) { + String relationName = n.getPredicate().getName(); + if (relationName.startsWith("Has ")) + relationName = relationName.substring(4); + if (relationName.equalsIgnoreCase(modelPropertyname)) { + // found a match + // set property's value for Solver + solver.setValue(m.getResource(), graph.getValueAsObject(n.getObject().getResource())); + set = true; + break; + } + + } + if (!set) { + ErrorLogger.defaultLogError("Cannot map property " + modelPropertyname, null); + } + //} + + } + + for (Property p : modelProperties) { + IEntity t = EntityFactory.create(graph, p.getResource()); + Collection exp = t.getRelatedObjects(Resources.equationResource.HasTarget); + if (exp.size() > 0) { + Iterator i = exp.iterator(); + while(i.hasNext()) + solver.evaluate(i.next()); + } else + ErrorLogger.defaultLogError("Model property " + p + " is not bound to a expression",null); + } + solver.pushToGraph(graph); + Collection animations = model.getAnimation(); + for (Animation animation : animations) { + Collection interpolators = animation.getInterpolator(); + for (org.simantics.g2d.stubs.anim.Interpolator interpolator : interpolators) { + IEntity target = interpolator.getTarget(); + // check all model properties + for (Property p : modelProperties) { + IEntity t = EntityFactory.create(graph,p.getResource()); + // get parameterization equations + Collection equations = t.getRelatedObjects(Resources.equationResource.HasTarget); + // get parameterized values + Collection parameterTargets = new ArrayList(); + for (IEntity eq : equations) { + Collection tgts = eq.getRelatedObjects(Resources.equationResource.HasTarget); + assert(tgts.size() == 1); + parameterTargets.add(tgts.iterator().next()); + } + // do matching between interpolator targets and parameterized values + // TODO : old system did not have inverse relations but current system does. + // it is possible to take interpolation target and find if it is connected to an equation + // this would make code much faster (no more stupid loops over everything) + for (IEntity d : parameterTargets) { + if (d.getResource().equals(target.getResource())) { + // get default value for sizing property + Collection prop = t.getRelatedObjects(Resources.g3dResource.HasDefaultDoubleValue); + if (prop.size() == 1) { + Resources.curveBuilder.parameterize(interpolator, prop.iterator().next().toProperty().getDoubleArray(), p.getDoubleArray()); + } else { + ErrorLogger.defaultLogError("Cannot parameterize interpolator " + interpolator.getResource() + " of animation " + animation.getResource() + " since parameter " + p.getResource() + " has no default value", null); + } + } + } + } + } + } + + } + + protected Graph createParameterization(Graph graph) { + // create ContextGraph if needed + ContextGraph g; + if (!(graph instanceof ContextGraph)) + g = new ContextGraph(graph); + else + g = (ContextGraph)graph; + // set the context + g.setContext(this.shapeResource); + // create solver and calculate parameterized values + Solver solver = new Solver(); + updateSizeParameters(g, solver); + // push parameterized values to context + solver.pushToGraph(g); + // return graph with parameterized values + return g; + } + + @Override + public boolean setAnimation(Graph graph, Resource animation) { + return super.setAnimation(createParameterization(graph), animation); + } + + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java new file mode 100644 index 00000000..9937f4cf --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/RootGraphicsNode.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.stubs.G3DNode; + +import com.jme.scene.Node; + +public class RootGraphicsNode implements IGraphicsNode { + + JmeRenderingComponent component; + Resource rootNode; + private ArrayList children = new ArrayList(); + + + public RootGraphicsNode(JmeRenderingComponent component, Resource rootNode) { + this.component = component; + this.rootNode = rootNode; + } + + public void addChild(IGraphicsNode node) { + children.add(node); + } + + public void removeChild(IGraphicsNode node) { + children.remove(node); + } + + public Collection getChildren() { + return children; + } + + public void dispose() { + //throw new RuntimeException("Root cannot be disposed"); + } + + public Node getGroup() { + return component.getShadowRoot(); + } + + public IGraphicsNode getParent() { + return null; + } + + public Resource getResource() { + return rootNode; + } + + public void updateTransform(Graph graph) { + + } + + public String toString() { + return this.getClass().toString(); + } + + public G3DNode getG3DNode(Graph graph) { + return new G3DNode(graph, rootNode); + } + + + +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java new file mode 100644 index 00000000..7c89be4d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java @@ -0,0 +1,719 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.scenegraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.Quat4d; + +import org.simantics.g2d.stubs.anim.Interpolator; +import org.simantics.animation.curve.SlerpCurve; +import org.simantics.animation.curve.TCBCurve; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.animation.Animatable; +import org.simantics.proconf.g3d.animation.Animation; +import org.simantics.proconf.g3d.animation.ChanneledColorInterpolator; +import org.simantics.proconf.g3d.animation.ChanneledPositionInterpolator; +import org.simantics.proconf.g3d.animation.ConstantInterpolator; +import org.simantics.proconf.g3d.animation.ScalarInterpolator; +import org.simantics.proconf.g3d.animation.SlerpInterpolator; +import org.simantics.proconf.g3d.animation.TCBInterpolator; +import org.simantics.proconf.g3d.base.AppearanceTools; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.GeometryProvider; +import org.simantics.proconf.g3d.base.GeometryProviderRegistry; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.stubs.Appearance; +import org.simantics.proconf.g3d.stubs.Color; +import org.simantics.proconf.g3d.stubs.G3DModel; +import org.simantics.proconf.g3d.stubs.G3DNode; +import org.simantics.proconf.g3d.stubs.Orientation; +import org.simantics.utils.ErrorLogger; + +import com.jme.bounding.BoundingBox; +import com.jme.bounding.CollisionTreeManager; +import com.jme.intersection.PickResults; +import com.jme.math.Ray; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.SharedMesh; +import com.jme.scene.TriMesh; +import com.jme.scene.state.AlphaState; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.RenderState; +import com.jme.scene.state.WireframeState; +import com.jme.scene.state.ZBufferState; + +import org.simantics.db.Builtins; +import org.simantics.db.ContextGraph; +import org.simantics.db.Graph; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; + +public class ShapeNode extends AbstractGraphicsNode implements Animatable, IGeometryNode{ + + public static final int NORMAL = 0; + public static final int TRANSPARENT = 1; + public static final int SELECTED_EDGE = 2; + public static final int HIGHLIGHTED_EDGE = 3; + + private boolean highlighted = false; + + protected Geometry mesh = null; + protected Geometry lines = null; + protected Geometry[] geometry = null; + + private boolean visible[] = new boolean[4]; + + private Node body; + private Node transparent; + private Node edge; + + private MaterialState selectedEdgeState; + private MaterialState highlightedEdgeState; + + private Collection renderStates; + private boolean isTransparent; + + + public ShapeNode(ThreeDimensionalEditorBase editor,IGraphicsNode parent, Graph graph, Resource shapeResource) { + super(editor,parent, graph, shapeResource); + for (int i = 0; i < visible.length; i++) + visible[i] = false; + + body = new Node(); + + body.setName(id); + + + transparent = new Node() { + private static final long serialVersionUID = 1L; + @Override + public void calculatePick(Ray ray, PickResults results) { + + } + }; + + // transparent.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + + edge = new Node(){ + private static final long serialVersionUID = 1L; + @Override + public void calculatePick(Ray ray, PickResults results) { + + } + }; + transparent.setIsCollidable(false); + edge.setIsCollidable(false); + + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(0.0f, 0.75f, 0.0f,0.3f)); + ms.setEmissive(new ColorRGBA(0f, 0f, 0f,0.3f)); + ms.setSpecular(new ColorRGBA(0.5f, 0.5f, 0.5f,0.3f)); + ms.setAmbient(new ColorRGBA(0.0f, 0.75f, 0.0f,0.3f)); + ms.setShininess(128.f); + ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK); + transparent.setRenderState(ms); + + AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + transparent.setRenderState(as); + + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setEmissive(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setSpecular(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setAmbient(new ColorRGBA(1.f, 1.f, 1.f, 1.f)); + ms.setShininess(128.f); + selectedEdgeState = ms; + + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setDiffuse(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setEmissive(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setSpecular(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setAmbient(new ColorRGBA(1.f, 0.f, 1.f, 1.f)); + ms.setShininess(128.f); + + highlightedEdgeState = ms; + + + } + + + /** + * This method is used to get implementation specific geometry. + * Arrays first element is a mesh, second contains edges. + * @return + */ + public Geometry[] getGeometry(Graph graph, boolean update) { + G3DNode shape = getG3DNode(graph); + final GeometryProvider provider = GeometryProviderRegistry.getGeometryProvider(shape); + if (!update) { + return provider.getGeometryFromResource(shape, false); + } else { + if (geometry == null) { + geometry = provider.getGeometryFromResource(shape, false); + } else { + provider.reconstructGeometry(shape, false, geometry); + } + return geometry; + } + } + + /** + * Updates shapes and it's ancestors geometry + */ + public void updateGeometry(Graph graph) { + updateTransform(graph); + // cleanAnimation(); + //System.out.println("ShapeNode.updateGeometry() " + name); + if (geometry == null) { + Geometry g[] = getGeometry(graph,true); + if (g != null) { + mesh = g[0]; + //TODO : uid + mesh.setName(id); + mesh.setModelBound(new BoundingBox()); + if (g.length > 1) { + lines = g[1]; + } else { + lines = null; + } + body.attachChild(mesh); + transparent.detachAllChildren(); + SharedMesh m = new SharedMesh("",(TriMesh)mesh); + m.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + m.getBatch(0).setCastsShadows(false); + transparent.attachChild(m); + + + if (lines == null) { + WireframeState ws = editor.getRenderingComponent().getDisplaySystem().getRenderer().createWireframeState(); + edge.attachChild(new SharedMesh("",(TriMesh)mesh)); + edge.setRenderState(ws); + } else { + ZBufferState zs = editor.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState(); + zs.setFunction(ZBufferState.CF_ALWAYS); + AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState(); + as.setBlendEnabled(true); + as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA); + as.setSrcFunction(AlphaState.DB_SRC_ALPHA); + lines.setRenderState(zs); + lines.setRenderState(as); + lines.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + edge.attachChild(lines); + } + + } + } + if (geometry != null) { + getGeometry(graph,true); + + + G3DNode shape = getG3DNode(graph); + if (renderStates == null) + updateAppearance(shape); + + if (isVisible()) { + getGroup().attachChild(body); + } else { + body.removeFromParent(); + } + if (isTransparentVisible()) { + getGroup().attachChild(transparent); + //setVisible(TRANSPARENT, true); + } else { + transparent.removeFromParent(); + } + + if (isSelectedVisible() || isHighlightedVisible()) { + getGroup().attachChild(edge); + //setVisible(SELECTED_EDGE, true); + } else { + edge.removeFromParent(); + //setVisible(SELECTED_EDGE,false); + } + + + mesh.updateModelBound(); + CollisionTreeManager.getInstance().updateCollisionTree(mesh); + //mesh.updateCollisionTree(); + + } + } + + protected void updateAppearance(IEntity shape) { + Collection appearanceResource; + if ((appearanceResource = shape.getRelatedObjects(Resources.g3dResource.HasAppearance)) != null && appearanceResource.size() > 0) { + renderStates = AppearanceTools.getAppearance(new Appearance(shape.getGraph(),appearanceResource.iterator().next().getResource()), editor.getRenderingComponent().getDisplaySystem().getRenderer()); + } else { + renderStates = getMaterial(); + } + + isTransparent = false; + for (RenderState s : renderStates) { + if (s instanceof AlphaState) + isTransparent = true; + } + setAppearance(); + } + + protected void setAppearance() { + if (mesh == null || renderStates == null) { + return; + } + for (RenderState s : renderStates) + mesh.setRenderState(s); + if (isTransparent) + mesh.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); + else + mesh.setRenderQueueMode(Renderer.QUEUE_OPAQUE); + } + + public void setSelected(boolean selected) { + if (this.selected == selected) + return; + this.selected = selected; + if (selected) { + + setSelectedVisible(true); + setTransparentVisible(true); + } else { + setSelectedVisible(false); + setTransparentVisible(false); + } + } + + public boolean isSelected() { + return selected; + } + + + + public boolean isHighlighted() { + return highlighted; + } + + public void setHighlighted(boolean highlighted) { + if (this.highlighted == highlighted) + return; + this.highlighted = highlighted; + if (highlighted) { + setHighlightedVisible(true); + } else { + setHighlightedVisible(false); + } + } + + public boolean isVisible(int shape) { + return visible[shape]; + } + + public void setVisible(int shape, boolean visible) { + if (this.visible[shape] == visible) + return; + this.visible[shape] = visible; + if (mesh == null) { + return; + } + if (this.visible[NORMAL]){ + getGroup().attachChild(body); + } else { + body.removeFromParent(); + } + if (this.visible[TRANSPARENT]) { + getGroup().attachChild(transparent); + } else { + transparent.removeFromParent(); + } + if (this.visible[SELECTED_EDGE] || this.visible[HIGHLIGHTED_EDGE]) { + if (this.visible[HIGHLIGHTED_EDGE]) + edge.setRenderState(highlightedEdgeState); + else + edge.setRenderState(selectedEdgeState); + getGroup().attachChild(edge); + edge.updateRenderState(); + } else { + edge.removeFromParent(); + } + } + + public boolean isVisible() { + return isVisible(NORMAL); + } + + public void setVisible(boolean visible) { + setVisible(NORMAL, visible); + } + + public boolean isSelectedVisible() { + return isVisible(SELECTED_EDGE); + } + + public void setSelectedVisible(boolean visible) { + setVisible(SELECTED_EDGE, visible); + } + + public boolean isHighlightedVisible() { + return isVisible(HIGHLIGHTED_EDGE); + } + + public void setHighlightedVisible(boolean visible) { + setVisible(HIGHLIGHTED_EDGE, visible); + + } + + + + public boolean isTransparentVisible() { + return isVisible(TRANSPARENT); + } + + public void setTransparentVisible(boolean visible) { + setVisible(TRANSPARENT, visible); + } + + public void setPickable(boolean pickable) { + body.setIsCollidable(pickable); + } + + public Collection getMaterial() { + List states = new ArrayList(); + MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f)); + ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setDiffuse(new ColorRGBA(0.75f,0.f,0.f,0.f)); + ms.setAmbient(new ColorRGBA(0.75f,0.f,0.f,0.f)); + ms.setEnabled(true); + ms.setShininess(128.f); + states.add(ms); + + return states; + } + + private Animation animation; + private static int preCalcSteps = 9; + private Geometry[] preCalc = null; + private int currentPreCalc = 0; + + public void animate(double delta,double frameTime) { + if (animation != null) + animation.interpolate(delta); + if (preCalc != null) { + int newPreCalc = (int)Math.round(delta*(preCalc.length-1)); + if (currentPreCalc != newPreCalc) { + + preCalc[currentPreCalc].removeFromParent(); + currentPreCalc = newPreCalc; + + body.attachChild(preCalc[currentPreCalc]); + } + } + } + + private void cleanAnimation() { + this.animation = null; + if (preCalc != null) { + for (Geometry g : preCalc) { + if (g != null) { + g.removeFromParent(); + g.clearBuffers(); + } + } + preCalc = null; + } + } + + /** + * Sets shape's animation + * TODO : multiple animations at the same time! (must check common animatable properties) + * TODO : initial values (material, ..) (requires changes in the ontology) + * TODO : messy code, refactor! + * TODO : calculate number of required pre-calculated geometries + * @param animation + */ + public boolean setAnimation(Graph g, Resource res) { + ContextGraph graph; + if (g instanceof ContextGraph) { + graph = (ContextGraph)g; + } else { + graph = new ContextGraph(g); + graph.setContext(shapeResource); + } + cleanAnimation(); + if (res == null) { + if (isVisible()) + body.attachChild(mesh); + return false; + } + org.simantics.g2d.stubs.anim.Animation animation = new org.simantics.g2d.stubs.anim.Animation(graph,res); + G3DNode shape = getG3DNode(graph); + G3DNode modelResource = G3DTools.getModelFromResource(graph,shape.getResource()); + assert (modelResource != null); + G3DModel model = new G3DModel(graph,modelResource.getResource()); + Collection animations = model.getAnimation(); + boolean found = false; + for (org.simantics.g2d.stubs.anim.Animation a : animations) { + if (a.getResource().equals(animation.getResource())) { + found = true; + break; + } + } + if (!found) { + ErrorLogger.getDefault().logWarning("Shape " + shape.getResource() + " cannot handle animation " + animation.getResource() + " because it isn't model's animation", null); + return false; + } + Collection interpolators = animation.getInterpolator(); + List handled = new ArrayList(); + List precalculated = new ArrayList(); + for (org.simantics.g2d.stubs.anim.Interpolator i : interpolators) { + IEntity target = i.getTarget(); + if (G3DTools.hasProperty(graph,shape.getResource(),target.getResource())) + handled.add(i); + else if (G3DTools.hasSubProperty(graph,shape.getResource(),target.getResource())) { + precalculated.add(i); + } + } + if (handled.size() == 0 && precalculated.size() == 0) { + ErrorLogger.getDefault().logWarning("Shape " + shape.getResource() + " cannot handle animation " + animation.getResource() + " since it doesn't change any of shape's properties", null); + return false; + } + + + this.animation = new Animation(); + + org.simantics.g2d.stubs.anim.Interpolator[] pos = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] ambient = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] diffuse = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] specular = new org.simantics.g2d.stubs.anim.Interpolator[3]; + org.simantics.g2d.stubs.anim.Interpolator[] emissive = new org.simantics.g2d.stubs.anim.Interpolator[3]; + + Builtins builtins = graph.getBuiltins(); + + + for (org.simantics.g2d.stubs.anim.Interpolator i : handled) { + IEntity target = i.getTarget(); + //if (target.isInstanceOf(Resources.g3dResource.LocalOrientation)) { + if (target.isInstanceOf(Resources.g3dResource.Orientation) && target.getRelatedObjects(Resources.g3dResource.LocalOrientationOf).size() == 1) { + SlerpInterpolator si = new SlerpInterpolator((SlerpCurve)Resources.curveBuilder.loadInterpolator(i)); + si.setTarget(transform); + this.animation.addInterpolator(si); + } else if (target.isInstanceOf(builtins.Double)) { + Resource targetResource = target.getResource(); + Collection p = target.getRelatedObjects(builtins.PropertyOf); + if (p.size() == 1) { + IEntity parent = p.iterator().next(); + //if (parent.isInstanceOf(Resources.g3dResource.LocalPosition)) { + if (parent.isInstanceOf(Resources.g3dResource.Position) && parent.getRelatedObjects(Resources.g3dResource.LocalPositionOf).size() == 1) { + if (parent.getSingleRelatedObject(Resources.g3dResource.HasX).getResource().equals(targetResource)) { + pos[0] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasY).getResource().equals(targetResource)) { + pos[1] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasZ).getResource().equals(targetResource)) { + pos[2] = i; + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Position ?)" + target.getResource(), null); + } + } else if (parent.isInstanceOf(Resources.g3dResource.Color)) { + org.simantics.g2d.stubs.anim.Interpolator[] color = null; + if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.AmbientColorOf).size() > 0) { + color = ambient; + } else if (parent.isInstanceOf(Resources.g3dResource.Color)&& parent.getRelatedObjects(Resources.g3dResource.DiffuseColorOf).size() > 0) { + color = diffuse; + } else if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.SpecularColorOf).size() > 0) { + color = specular; + } else if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.EmissiveColorOf).size() > 0) { + color = emissive; + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Color)" + target.getResource() + " unknown color type", null); + } + if (color != null) { + if (parent.getSingleRelatedObject(Resources.g3dResource.HasRed).getResource().equals(targetResource)) { + color[0] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasGreen).getResource().equals(targetResource)) { + color[1] = i; + } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasBlue).getResource().equals(targetResource)) { + color[2] = i; + } else { + ErrorLogger.getDefault().logWarning( + "Cannot map animation interpolator " + i.getResource() + + " to target (Color ?)" + target.getResource(), null); + } + } + } else if (parent.isInstanceOf(Resources.g3dResource.Material)) { + // TODO : transparency or shininess + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target" + target.getResource() + " adding it to precalculated interpolators", null); + precalculated.add(i); + } + } else { + if (p.size() == 0) { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Double)" + target.getResource() + " since it is not a part of a property", null); + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Double)" + target.getResource() + " since it acts as a property to more than one entity", null); + } + } + } else { + ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target" + target.getResource(), null); + } + } + + if (pos[0] != null || pos[1] != null || pos[2] != null) { + ScalarInterpolator xIp; + ScalarInterpolator yIp; + ScalarInterpolator zIp; + if (pos[0] != null) { + xIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[0])); + } else { + xIp = new ConstantInterpolator(shape.getLocalPosition().getX()[0]); + } + if (pos[1] != null) { + yIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[1])); + } else { + yIp = new ConstantInterpolator(shape.getLocalPosition().getY()[0]); + } + if (pos[2] != null) { + zIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[2])); + } else { + zIp = new ConstantInterpolator(shape.getLocalPosition().getZ()[0]); + } + ChanneledPositionInterpolator ip = new ChanneledPositionInterpolator(xIp,yIp,zIp); + ip.setTarget(transform); + this.animation.addInterpolator(ip); + + } + addColorInterpolator(shape, ambient, ChanneledColorInterpolator.AMBIENT); + addColorInterpolator(shape, diffuse, ChanneledColorInterpolator.DIFFUSE); + addColorInterpolator(shape, emissive, ChanneledColorInterpolator.EMISSIVE); + addColorInterpolator(shape, specular, ChanneledColorInterpolator.SPECULAR); + + if (precalculated.size() == 0) { + preCalc = null; + } else { + preCalc = new Geometry[preCalcSteps+1]; + for (int i = 0; i <= preCalcSteps; i++) { + double delta = ((double)i / (double)preCalcSteps); + // TODO : copy-paste from CSGAnimatorView + // FIXME : does not update transformations (since ContextGraph does not support queries for context dependent values) + for (Interpolator ip : precalculated) { + if (ip.isInstanceOf(Resources.animationResource.ScalarInterpolator)) { + // TODO : creating curve each time when time is set is slow. + // Curve should be cached + TCBCurve c = (TCBCurve)Resources.curveBuilder.loadInterpolator(ip); + double out = c.evaluate(delta); + //Double d = DoubleFactory.create(ip.getTarget()); + //d.setValue(new double[]{out}); + IEntity d = ip.getTarget(); + d.toProperty().setDoubleArray(new double[]{out}); + } else if (ip.isInstanceOf(Resources.animationResource.SlerpInterpolator)) { + // TODO : creating curve each time when time is set is slow. + // Curve should be cached + SlerpCurve c = (SlerpCurve)Resources.curveBuilder.loadInterpolator(ip); + Quat4d out = c.evaluate(delta); + Orientation r = new Orientation(ip.getTarget()); + AxisAngle4d aa = new AxisAngle4d(); + aa.set(out); + G3DTools.setOrientation(r, aa); + } + } + preCalc[i] = getGeometry(graph,false)[0]; + preCalc[i].setIsCollidable(false); + AppearanceTools.copyMaterial(mesh, preCalc[i]); + } + + // We'll have to remove original (non-animated) shape from the node + mesh.removeFromParent(); + body.attachChild(preCalc[0]); + + } + return true; + } + + private void addColorInterpolator(G3DNode shape, org.simantics.g2d.stubs.anim.Interpolator[] color, int type) { + if (color[0] != null || color[1] != null || color[2] != null) { + ScalarInterpolator xIp; + ScalarInterpolator yIp; + ScalarInterpolator zIp; + Color col = null; + Collection appearanceResource = shape.getRelatedObjects(Resources.g3dResource.HasAppearance); + if (appearanceResource.size() == 0) { + ErrorLogger.getDefault().logWarning("Cannot create interpolator for color because shape " + shape.getResource() + " has no appearance", null); + } + Appearance a = new Appearance(shape.getGraph(),appearanceResource.iterator().next().getResource()); + switch (type) { + case ChanneledColorInterpolator.AMBIENT: + col = a.getMaterial().getAmbientColor(); + break; + case ChanneledColorInterpolator.DIFFUSE: + col = a.getMaterial().getDiffuseColor(); + break; + case ChanneledColorInterpolator.EMISSIVE: + col = a.getMaterial().getEmissiveColor(); + break; + case ChanneledColorInterpolator.SPECULAR: + col = a.getMaterial().getSpecularColor(); + break; + default: + ErrorLogger.defaultLogError("Unknown color type", null); + return; + } + + if (color[0] != null) { + xIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[0]));//CurveUtils.loadCurve(color[0].getResource())); + } else { + xIp = new ConstantInterpolator(col.getRed()[0]); + } + if (color[1] != null) { + yIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[1]));//CurveUtils.loadCurve(color[1].getResource())); + } else { + yIp = new ConstantInterpolator(col.getGreen()[0]); + } + if (color[1] != null) { + zIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[2]));//CurveUtils.loadCurve(color[2].getResource())); + } else { + zIp = new ConstantInterpolator(col.getBlue()[0]); + } + ChanneledColorInterpolator ip = new ChanneledColorInterpolator(xIp,yIp,zIp); + ip.setType(type); + ip.setTarget(mesh.getRenderState(RenderState.RS_MATERIAL)); + this.animation.addInterpolator(ip); + } + } + + public boolean setRandomAnimation(Graph graph) { + return false; + } + + public void dispose() { +// mesh.clearBuffers(); +// mesh.clearBatches(); +// lines.clearBuffers(); +// lines.clearBatches(); + if (mesh != null) { + mesh.removeFromParent(); + mesh.dispose(); + mesh = null; + } + if (lines != null) { + lines.removeFromParent(); + lines.dispose(); + lines = null; + } + super.dispose(); + } +} \ No newline at end of file diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java new file mode 100644 index 00000000..461087cb --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/AxesShape.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class AxesShape { + + + public static Geometry getShape(Renderer renderer) { + float[] coords = new float[]{0.f,0.f,0.f, + 1.f,0.f,0.f, + 0.f,0.f,0.f, + 0.f,1.f,0.f, + 0.f,0.f,0.f, + 0.f,0.f,1.f}; + float colors[] = new float[]{1.f,0.f,0.f,0.f, + 1.f,0.f,0.f,0.f, + 0.f,1.f,0.f,0.f, + 0.f,1.f,0.f,0.f, + 0.f,0.f,1.f,0.f, + 0.f,0.f,1.f,0.f}; + + + Line shape = new Line("",BufferUtils.createFloatBuffer(coords),null,BufferUtils.createFloatBuffer(colors),null); + shape.setMode(Line.SEGMENTS); + shape.setIsCollidable(false); + shape.setLineWidth(3.f); + MaterialState ms = renderer.createMaterialState(); + ms.setColorMaterial(MaterialState.CM_EMISSIVE); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + shape.setRenderState(ms); + + return shape; + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java new file mode 100644 index 00000000..cd289ad5 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/FloorShape.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; + +import com.jme.image.Texture; +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.TriMesh; +import com.jme.scene.state.MaterialState; +import com.jme.scene.state.TextureState; +import com.jme.util.TextureManager; +import com.jme.util.geom.BufferUtils; + +public class FloorShape { + + private static String textureLocation = "src/jmetest/data/texture/Detail.jpg"; + + public static Geometry getShape(Renderer renderer, float size, float texScale) { + + float coords[] = new float[3 * 4]; + float normals[] = new float[3 * 4]; + float texcoords[] = new float[2 * 4]; + int indices[] = new int[] { 0, 2, 1, 1, 2, 3 }; + coords[0] = -size; + coords[1] = 0.f; + coords[2] = -size; + coords[3] = size; + coords[4] = 0.f; + coords[5] = -size; + coords[6] = -size; + coords[7] = 0.f; + coords[8] = size; + coords[9] = size; + coords[10] = 0.f; + coords[11] = size; + texcoords[0] = -size*texScale; + texcoords[1] = -size*texScale; + texcoords[2] = size*texScale; + texcoords[3] = -size*texScale; + texcoords[4] = -size*texScale; + texcoords[5] = size*texScale; + texcoords[6] = size*texScale; + texcoords[7] = size*texScale; + normals[0] = 0.f; + normals[1] = 1.f; + normals[2] = 0.f; + normals[3] = 0.f; + normals[4] = 1.f; + normals[5] = 0.f; + normals[6] = 0.f; + normals[7] = 1.0f; + normals[8] = 0.f; + normals[9] = 0.f; + normals[10] = 1.f; + normals[11] = 0.f; + + TriMesh shape = new TriMesh("",BufferUtils.createFloatBuffer(coords),BufferUtils.createFloatBuffer(normals),null,BufferUtils.createFloatBuffer(texcoords),BufferUtils.createIntBuffer(indices)); + MaterialState ms = renderer.createMaterialState(); + ms.setEmissive(new ColorRGBA(0.5f,0.5f,0.5f,0.f)); + ms.setDiffuse(new ColorRGBA(1.f,1.f,1.f,0.f)); + ms.setShininess(128.f); + shape.setRenderState(ms); + shape.setCullMode(Geometry.CULL_NEVER); + + TextureState ts = renderer.createTextureState(); + URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path(textureLocation),null); + Texture tex = TextureManager.loadTexture(url, Texture.MM_LINEAR_LINEAR, + Texture.FM_LINEAR); + tex.setWrap(Texture.WM_WRAP_S_WRAP_T); + ts.setTexture(tex); + shape.setRenderState(ts); + shape.lockShadows(); + return shape; + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java new file mode 100644 index 00000000..284b357e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/GridShape.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import com.jme.renderer.ColorRGBA; +import com.jme.renderer.Renderer; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class GridShape { + + + public static Geometry getShape(Renderer renderer, int lineCount, float delta) { + + float[] coords = new float[lineCount*lineCount*2*3]; + float size = delta * lineCount; + float halfSize = size * 0.5f; + + for (int i = 0 ; i <= lineCount; i++) { + int index = i*3*2; + coords[index++] = -halfSize + i * delta; + coords[index++] = 0.f; + coords[index++] = -halfSize; + coords[index++] = -halfSize + i * delta; + coords[index++] = 0.f; + coords[index++] = +halfSize; + } + for (int i = 0 ; i <= lineCount; i++) { + int index = (i + lineCount + 1)*3*2; + coords[index++] = -halfSize; + coords[index++] = 0.f; + coords[index++] = -halfSize + i * delta; + coords[index++] = +halfSize; + coords[index++] = 0.f; + coords[index++] = -halfSize + i * delta; + } + + Line shape = new Line("",BufferUtils.createFloatBuffer(coords),null,null,null); + MaterialState ms = renderer.createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,0.f)); + shape.setRenderState(ms); + shape.setCullMode(Geometry.CULL_NEVER); + return shape; + + } + +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java new file mode 100644 index 00000000..cab5e37e --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/shapes/Quad.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.shapes; + +import java.nio.FloatBuffer; + +import com.jme.math.Vector3f; +import com.jme.renderer.ColorRGBA; +import com.jme.scene.TriMesh; +import com.jme.scene.batch.TriangleBatch; +import com.jme.util.geom.BufferUtils; + +public class Quad extends TriMesh { + + private static final long serialVersionUID = 1L; + + public Quad() { + + } + + /** + * Constructor creates a new Quad object. That data for the + * Quad is not set until a call to initialize + * is made. + * + * @param name + * the name of this Quad. + */ + public Quad(String name) { + super(name); + } + + /** + * Constructor creates a new Quade object with the provided + * width and height. + * + * @param name + * the name of the Quad. + * @param width + * the width of the Quad. + * @param height + * the height of the Quad. + */ + public Quad(String name, float width, float height) { + super(name); + initialize(width, height); + } + + /** + * resize changes the width and height of the given quad by + * altering its vertices. + * + * @param width + * the new width of the Quad. + * @param height + * the new height of the Quad. + */ + public void resize(float width, float height) { + TriangleBatch batch = getBatch(0); + batch.getVertexBuffer().clear(); + batch.getVertexBuffer().put(-width / 2f).put(height / 2f).put(0); + batch.getVertexBuffer().put(-width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(height / 2f).put(0); + } + + /** + * + * initialize builds the data for the Quad + * object. + * + * + * @param width + * the width of the Quad. + * @param height + * the height of the Quad. + */ + public void initialize(float width, float height) { + TriangleBatch batch = getBatch(0); + batch.setVertexCount(4); + batch.setVertexBuffer(BufferUtils.createVector3Buffer(batch.getVertexCount())); + batch.setNormalBuffer(BufferUtils.createVector3Buffer(batch.getVertexCount())); + FloatBuffer tbuf = BufferUtils.createVector2Buffer(batch.getVertexCount()); + setTextureBuffer(0,tbuf); + batch.setTriangleQuantity(2); + batch.setIndexBuffer(BufferUtils.createIntBuffer(batch.getTriangleCount() * 3)); + + batch.getVertexBuffer().put(-width / 2f).put(height / 2f).put(0); + batch.getVertexBuffer().put(-width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(-height / 2f).put(0); + batch.getVertexBuffer().put(width / 2f).put(height / 2f).put(0); + + batch.getNormalBuffer().put(0).put(0).put(1); + batch.getNormalBuffer().put(0).put(0).put(1); + batch.getNormalBuffer().put(0).put(0).put(1); + batch.getNormalBuffer().put(0).put(0).put(1); + + + tbuf.put(0).put(0); + tbuf.put(0).put(1); + tbuf.put(1).put(1); + tbuf.put(1).put(0); + + setDefaultColor(ColorRGBA.white); + + batch.getIndexBuffer().put(0); + batch.getIndexBuffer().put(1); + batch.getIndexBuffer().put(2); + batch.getIndexBuffer().put(0); + batch.getIndexBuffer().put(2); + batch.getIndexBuffer().put(3); + } + + /** + * getCenter returns the center of the Quad. + * + * @return Vector3f the center of the Quad. + */ + public Vector3f getCenter() { + return worldTranslation; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java new file mode 100644 index 00000000..1af0908d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OEPathSelectionListener.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.tools; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.layer0.utils.viewpoints.TraversalPath; +import org.simantics.proconf.browsing.MutableCachedGraphTreeNode; + +/** + * SelectionListener for OntologyExplorer + * + * Returns Selection as TraversalPath + * + * @author Marko Luukkainen + * + */ +public abstract class OEPathSelectionListener implements ISelectionChangedListener{ + @SuppressWarnings("unchecked") + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection s = (IStructuredSelection)event.getSelection(); + List paths = new ArrayList(); + Iterator i = s.iterator(); + while(i.hasNext()) { + MutableCachedGraphTreeNode node = i.next(); + TraversalPath path = (TraversalPath)node.getObject(); + paths.add(path); + } + pathSelectionUpdated(paths); + } + + protected abstract void pathSelectionUpdated(List paths); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java new file mode 100644 index 00000000..54e4619b --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/OESelectionListener.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.tools; + +import java.util.Iterator; + +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.simantics.db.Resource; +import org.simantics.proconf.browsing.providers.TreeObject; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +/** + * SelectionListener for OntologyExplorer + * + * Returns selection as StrcturedResourceSelection + * + * @author Marko Luukkainen + * + */ +public abstract class OESelectionListener implements ISelectionChangedListener { + @SuppressWarnings("unchecked") + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection s = (IStructuredSelection)event.getSelection(); + StructuredResourceSelection sel = new StructuredResourceSelection(); + Iterator i = s.iterator(); + while(i.hasNext()) { + TreeObject node = i.next(); + sel.add((Resource)node.getAdapter(Resource.class)); + } + resourceSelectionUpdated(sel); + } + + protected abstract void resourceSelectionUpdated(StructuredResourceSelection selection); +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java new file mode 100644 index 00000000..ea7f62db --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/PropertyTree.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.tools; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.simantics.db.Builtins; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.ResourceDebugUtils; +import org.simantics.layer0.utils.Statement; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; + +/** + * PropertyTree finds common properties for set of objects, and + * then based on user's selection returns all property instances. + * + * @author Marko Luukkainen + * + */ +public class PropertyTree { + private Tree tree; + private Session session; + + + public PropertyTree(Tree tree, Session session) { + this.tree = tree; + this.session = session; + } + + public void setProperties(List selectedInstances) { + tree.removeAll(); + addProperties(null,selectedInstances); + tree.redraw(); + } + + public void setProperties(StructuredResourceSelection selection) { + ArrayList selectedInstances = new ArrayList(); + for (Resource r : selection.getSelectionList()) { + if (!contains(selectedInstances,r)) { + selectedInstances.add(r); + + //System.out.println("Added " + name.getName()); + } else { + + // System.out.println("Discarded " + name.getName()); + } + } + setProperties(selectedInstances); + } + + public Tree getTree() { + return tree; + } + + private void addProperties(final TreeItem parent, final List selectedInstances) { + session.asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Builtins builtins = g.getBuiltins(); + ArrayList relationTypes = new ArrayList(); + for (Resource resource : selectedInstances) { + IEntity thing = EntityFactory.create(g, resource); + + Collection properties = thing.getRelatedStatements(builtins.HasProperty); + // RelationSet properties = resource.getRelatedResourcesWithRelationIds(GlobalIdMap.get(Builtins.HasProperty)); + + for (Statement r : properties) { + // Statement contains relation from instance to property(instance) + // Find the property's type(s) + // TODO : seems to be bad way of finding type + Collection types = r.getObject().getRelatedObjects(builtins.InstanceOf); + if (types.size() != 1) + throw new UnsupportedOperationException("Cannot support multi-instances"); + IEntity type = types.iterator().next(); + if (!contains(relationTypes, r.getPredicate().getResource())) { + + if (type.isInheritedFrom(builtins.Double)) { + + relationTypes.add(r.getPredicate().getResource()); + + //System.out.println("Added " + name.getName() + " " + type.getId() + " " + r.getRelationId() + " " + relationType.getId()); + final String name = getNameForThing(r.getPredicate());//getNameForThing(thing); + final Object treeData = r.getPredicate().getResource(); + Display.getDefault().asyncExec(new Runnable() { + //parent.getDisplay().asyncExec(new Runnable() { + TreeItem item = null; + @Override + public void run() { + if (parent != null) + item = new TreeItem(parent,SWT.NONE); + else + item = new TreeItem(tree,SWT.NONE); + item.setData(treeData); + item.setText(name); + + } + }); + + } else { + //Resource pproperties[] = r.getRelatedResources(GlobalIdMap.get(Builtins.PropertyRelationType)); + //Resource pproperties[] = resource.get(r.getObjectId()).getRelatedResources(GlobalIdMap.get(Builtins.HasProperty)); + Collection pproperties = r.getObject().getRelatedObjects(builtins.HasProperty); + if (pproperties.size() > 0) { + final ArrayList list = new ArrayList(); + list.add(r.getObject().getResource()); + + final String name = getNameForThing(r.getPredicate());//getNameForThing(thing); + final Object treeData = r.getPredicate().getResource(); + relationTypes.add(r.getPredicate().getResource()); + Display.getDefault().asyncExec(new Runnable() { + //parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + TreeItem item = null; + if (parent != null) + item = new TreeItem(parent, SWT.NONE); + else + item = new TreeItem(tree, SWT.NONE); + item.setText(name); + item.setData(treeData); + addProperties(item,list); + } + }); + } + } + } + } + } + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + private String getNameForThing(IEntity thing) { + return ResourceDebugUtils.getReadableNameForEntity(thing); + /* + String tName = thing.getName(); + if (tName == null) { + Collection ptypes = thing.getTypes(); + for (Thing pt : ptypes) { + tName = pt.getName(); + if (tName != null) + break; + } + } + if (tName == null) + return "Error / no name for " + thing; + return tName; + */ + } + + private boolean contains(java.util.List list, Resource value) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i).equals(value)) + return true; + } + return false; + } + + /** + * Returns all properties (instances) contained in the list depending on selection in the tree and + * TODO : currently can be run only in UI -thread with transaction. + * + * @param graph + * @param shapes + * @return + */ + public List findLeafPropertyInstances(Graph graph,List shapes) { + TreeItem[] selectedProperties = tree.getSelection(); + List props = new ArrayList(); + for (TreeItem propertyItem : selectedProperties) { + + TreeItem t = propertyItem; + boolean c = false; + // if list contains treeNode's parent, node's property is already mapped / will be mapped later + while (t.getParentItem() != null) { + if (contains(selectedProperties, t.getParentItem())) { + c = true; + break; + } + t = t.getParentItem(); + + } + if (!c) { + props.addAll(findLeafProperties(graph,shapes, propertyItem)); + } + } + return props; + } + + public List findPropertyInstances(Graph graph,List shapes) { + TreeItem[] selectedProperties = tree.getSelection(); + List props = new ArrayList(); + for (TreeItem propertyItem : selectedProperties) { + + TreeItem t = propertyItem; + boolean c = false; + // if list contains treeNode's parent, node's property is already mapped / will be mapped later + while (t.getParentItem() != null) { + if (contains(selectedProperties, t.getParentItem())) { + c = true; + break; + } + t = t.getParentItem(); + + } + if (!c) { + props.addAll(findProperties(graph,shapes, propertyItem)); + } + } + return props; + } + + private List findProperties(Graph graph,java.util.List shapes, TreeItem propertyItem) { + ArrayList propertyChain = new ArrayList(); + TreeItem t = propertyItem; + while (t != null) { + propertyChain.add((Resource) t.getData()); + t = t.getParentItem(); + } + + return findProperties(graph,shapes,propertyChain); + + } + + private List findLeafProperties(Graph graph,java.util.List shapes, TreeItem propertyItem) { + ArrayList propertyChain = new ArrayList(); + TreeItem t = propertyItem; + while (t != null) { + propertyChain.add((Resource)t.getData()); + t = t.getParentItem(); + } + // now propertyChain contains property hierarchy from leaf to root + //Long typeID = (Long) propertyItem.getData(); + if (propertyItem.getItemCount() == 0) { + return findProperties(graph,shapes,propertyChain); + } else { + List props = new ArrayList(); + //Long typeID = (Long) propertyItem.getData(); + TreeItem children[] = propertyItem.getItems(); + //ArrayList props = getPropertiesForType(shapes, typeID); + for (TreeItem i : children) + //mapProperty(parameter,props, i); + props.addAll(findLeafProperties(graph,shapes, i)); + return props; + } + } + + private List findProperties(Graph graph, java.util.List shapes, ArrayList propertyChain) { + ArrayList res = new ArrayList(shapes); + // propertyChain contains hierarhy of properties form leaf to root : + // we'll find root property from shapes and then iterate each property instance + // until we'll fin all requested properties (first element in property chain) + +// System.out.print("instances "); +// for (Resource r : res) { +// System.out.print(r + " "); +// } +// System.out.println(); + + while (propertyChain.size() > 0) { + res = getPropertiesForType(graph, res, propertyChain.get(propertyChain.size() - 1)); +// System.out.print(propertyChain.get(propertyChain.size() - 1) +" instances "); +// for (Resource r : res) { +// System.out.print(r + " "); +// } +// System.out.println(); + propertyChain.remove(propertyChain.size() - 1); + } + // now res contains all instances of requested property + return res; + } + + private ArrayList getPropertiesForType(Graph graph,java.util.List instances, Resource typeID) { + ArrayList properties = new ArrayList(); + for (Resource instance : instances) { + IEntity t = EntityFactory.create(graph,instance); + Collection props = t.getRelatedObjects(typeID); + for (IEntity p : props) + properties.add(p.getResource()); + + } + return properties; + } + + private boolean contains(TreeItem items[], TreeItem item) { + for (TreeItem i : items) + if (i.equals(item)) + return true; + return false; + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java new file mode 100644 index 00000000..c3bf357d --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/tools/ScenegraphLockTraverser.java @@ -0,0 +1,32 @@ +package org.simantics.proconf.g3d.tools; + +import java.util.ArrayList; + +import com.jme.scene.Node; +import com.jme.scene.Spatial; + +public class ScenegraphLockTraverser { + Node root; + boolean lock; + public ScenegraphLockTraverser(Node root, boolean lock) { + this.root = root; + this.lock = lock; + lock(root); + } + + private void lock(Spatial spatial) { + if (lock) + spatial.lock(); + else + spatial.unlock(); + if (spatial instanceof Node) { + Node node = (Node)spatial; + ArrayList children = node.getChildren(); + for (Spatial s : children) { + s.lock(); + lock(s); + } + } + + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java new file mode 100644 index 00000000..69170787 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/AppearanceEditor.java @@ -0,0 +1,1146 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.views; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Slider; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPart; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.StubLinkedList; +import org.simantics.layer0.utils.internal.Entity; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.AppearanceTools; +import org.simantics.proconf.g3d.stubs.Appearance; +import org.simantics.proconf.g3d.stubs.ImageTexture; +import org.simantics.proconf.g3d.stubs.Material; +import org.simantics.proconf.g3d.stubs.MultiTexture; +import org.simantics.proconf.g3d.stubs.Shader; +import org.simantics.proconf.g3d.stubs.Texture; +import org.simantics.proconf.g3d.stubs.TextureCoordinateGenerator; +import org.simantics.proconf.image.ImageUtils; +import org.simantics.proconf.image.interfaces.IImage; +import org.simantics.proconf.image.interfaces.IImageFactory; +import org.simantics.proconf.image.ui.ImageComposite; +import org.simantics.proconf.ui.utils.ResourceAdaptionUtils; +import org.simantics.utils.ErrorLogger; + + +public class AppearanceEditor extends SinglePageResourceView{ + + //Appearance appearance; + Resource shapeResource; + Resource appearanceResource; + + private enum EditorState{NONE,NO_SHAPE,NO_APPEARANCE, APPEARANCE}; + EditorState state = EditorState.NONE; + + Button materialButton; + + Composite ambientComposite; + Composite diffuseComposite; + Composite specularComposite; + Composite emissiveComposite; + Slider specularSlider; + Slider transparencySlider; + + + Composite textureParent; + + Button textureButton; + Button addTextureButton; + + + //Image image = null; + + boolean updating = false; + + private ArrayList textureComposites = new ArrayList(); + + Button shaderButton; + Text fragmentShaderText; + Text vertexShaderText; + + Button apply3Button; + Button apply2Button; + Button applyButton; + + public AppearanceEditor() { + super(); + //super(Activator.PLUGIN_ID); + + } + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + createWidgets(); + } + + @Override + protected String getFormText() { + return "Appearance Editor"; + } + +// @Override +// protected void beforeCreateWidgets() { +// if (!(getInputResource().isInstanceOf(GlobalIdMap.get(ThreeDimensionalModelingOntologyMapping.APPEARANCE)))) +// throw new RuntimeException("Trying to open resource that is not appearance"); +// appearance = AppearanceFactory.create(getInputResource()); +// } + + + + @Override + protected void createWidgets() { + + if (shapeResource == null) { + if (state != EditorState.NO_SHAPE) { + clearForm(); + state = EditorState.NO_SHAPE; + toolkit.createLabel(getBody(), "No shape selected"); + getActiveForm().layout(true, true); + } + } else if (appearanceResource == null){ + if (state != EditorState.NO_APPEARANCE) { + clearForm(); + state = EditorState.NO_APPEARANCE; + toolkit.createLabel(getBody(), "Selected shape does not have material definition."); + Button b = toolkit.createButton(getBody(), "Create Appearance", SWT.PUSH); + b.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = Appearance.createDefault(g); + appearanceResource = appearance.getResource(); + g.addStatement(shapeResource, Resources.g3dResource.HasAppearance, appearanceResource); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted( GraphRequestStatus status) { + reloadInUIThread(); + } + }); + + } + }); + getActiveForm().layout(true, true); + } + } else { + if (state != EditorState.APPEARANCE) { + clearForm(); + state = EditorState.APPEARANCE; + createMaterialGroup(newGridSection(2, 2, false, false, "Material", "Material properties")); + createTextureGroup(newGridSection(1, 1, false, false, "Texture", "Texture properties")); + createShaderGroup(newGridSection(2, 2, false, false, "Shader", "Shader properties")); + getActiveForm().layout(true, true); + } + + } + } + + @Override + public void clearForm() { + super.clearForm(); + textureComposites.clear(); + } + + @Override + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + Resource res[] = ResourceAdaptionUtils.toResources(selection); + if (res.length == 0) { + shapeResource = null; + appearanceResource = null; + reload(); + return; + } + final Resource sel = res[0]; + if (sel.equals(shapeResource)) + return; + //System.out.println("AppearanceEditor.pageSelectionChanged"); + getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + + shapeResource = null; + appearanceResource = null; + // selected object must be a shape + if (!g.isInstanceOf(sel, Resources.g3dResource.Shape)) { + return GraphRequestStatus.transactionCancel(); + } + // the shape must not be ah geometry definition + if (g.getObjects(sel, Resources.g3dResource.GeometryDefinitionOf).size() > 0) + return GraphRequestStatus.transactionCancel(); + + shapeResource = sel; + Collection res = g.getObjects(shapeResource, Resources.g3dResource.HasAppearance); + if (res.size() == 1) + appearanceResource = res.iterator().next(); + return GraphRequestStatus.transactionComplete(); + } + + @Override + public void requestCompleted(GraphRequestStatus status) { + reloadInUIThread(); + } + }); + } + + public void reloadInUIThread() { + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + reload(); + } + }); + } + + public void reload() { + if (updating) + return; + createWidgets(); + if (state == EditorState.APPEARANCE) { + getSession().asyncRead(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + reload(g); + return GraphRequestStatus.transactionComplete(); + } + }); + } + } + + @Override + public void reload(Graph g) { + if (updating) + return; + if (state != EditorState.APPEARANCE) { + return; + } + Appearance appearance = new Appearance(g,appearanceResource); + Material m = appearance.getMaterial(); + Texture t = appearance.getTexture(); + Shader s = appearance.getShader(); + loadMaterial(m); + loadTexture(t); + loadShader(s); + + + } + + private void loadMaterial(Material m) { + final boolean hasMaterial; + final Color ambient; + final Color diffuse; + final Color specular; + final Color emissive; + final int shininess; + final int transparency; + if (m == null) { + hasMaterial = false; + ambient = null; + diffuse = null; + specular = null; + emissive = null; + shininess = 0; + transparency = 0; + } else { + hasMaterial = true; + ambient = AppearanceTools.getColor(m.getAmbientColor(), this.getBody().getDisplay()); + diffuse = AppearanceTools.getColor(m.getDiffuseColor(), this.getBody().getDisplay()); + specular = AppearanceTools.getColor(m.getSpecularColor(), this.getBody().getDisplay()); + emissive = AppearanceTools.getColor(m.getEmissiveColor(), this.getBody().getDisplay()); + shininess = (int)m.getShininess()[0]; + transparency = (int)(m.getTransparency()[0]*100.0); + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + boolean t = hasMaterial; + materialButton.setSelection(t); + ambientComposite.setEnabled(t); + diffuseComposite.setEnabled(t); + specularComposite.setEnabled(t); + emissiveComposite.setEnabled(t); + specularSlider.setEnabled(t); + transparencySlider.setEnabled(t); + if (hasMaterial) { + ambientComposite.setBackground(ambient); + diffuseComposite.setBackground(diffuse); + specularComposite.setBackground(specular); + emissiveComposite.setBackground(emissive); + specularSlider.setSelection(shininess); + transparencySlider.setSelection(transparency); + } else { + Color c = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); + ambientComposite.setBackground(c); + diffuseComposite.setBackground(c); + specularComposite.setBackground(c); + emissiveComposite.setBackground(c); + } + + }; + }); + + } + + private void loadTexture(Texture t) { + //System.out.println("AppearanceEditor.loadTexture"); + if (t == null) { + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + textureButton.setSelection(false); + } + }); + + return; + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + textureButton.setSelection(true); + } + }); + + if (t.isInstanceOf(Resources.g3dResource.ImageTexture)) { + //final ImageTexture t2 = new ImageTexture(t); + final Resource t2 = t.getResource(); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + while (textureComposites.size() > 1) { + textureComposites.remove(textureComposites.size()-1).dispose(); + } + if (textureComposites.size() == 0) { + textureComposites.add(new TextureComposite(textureParent,SWT.NONE)); + } + getSession().asyncWrite(new GraphRequestAdapter() { + public GraphRequestStatus perform(Graph g) throws Exception { + try { + textureComposites.get(0).update(new ImageTexture(g,t2)); + } catch (Exception e) { + ErrorLogger.defaultLogError(e); + } + return GraphRequestStatus.transactionComplete(); + }; + + }); + } + }); + + + } else if (t.isInstanceOf(Resources.g3dResource.MultiTexture)) { + + MultiTexture mt = new MultiTexture(t); + StubLinkedList elements = new StubLinkedList(mt.getMultiTextureElementList()); + final Resource listResource = mt.getMultiTextureElementList().getResource(); + final int count = elements.size(); + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + while (textureComposites.size() > count) { + textureComposites.get(textureComposites.size()-1).dispose(); + textureComposites.remove(textureComposites.size()-1); + } + while (textureComposites.size() < count) { + textureComposites.add(new TextureComposite(textureParent,SWT.NONE)); + } + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + StubLinkedList elements = new StubLinkedList(new Entity(g,listResource)); + Iterator i = elements.iterator(); + int index = 0; + while (i.hasNext()) { + //MultiTextureElement e = new MultiTextureElement(i.next()); + //int index = e.getMultiTextureIndexValue(); + Texture tex = new Texture(i.next());//e.getTexture(); + if (tex.isInstanceOf(Resources.g3dResource.ImageTexture)) { + ImageTexture t2 = new ImageTexture(tex); + try { + textureComposites.get(index).update(t2); + } catch (Exception err) { + ErrorLogger.defaultLogError(err); + } + } + index++; + } + return null; + } + }); + } + }); + + + + } + } + + private void loadShader(Shader s) { + final boolean hasShader = (s != null); + final String vertexShader; + final String fragmentShader; + if (hasShader) { + vertexShader = s.getVertexShader()[0]; + fragmentShader = s.getFragmentShader()[0]; + } else { + vertexShader = null; + fragmentShader = null; + } + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!hasShader) { + shaderButton.setSelection(false); + } else { + shaderButton.setSelection(true); + vertexShaderText.setText(vertexShader); + fragmentShaderText.setText(fragmentShader); + } + + } + }); + + } + + private void createMaterialGroup(Composite parent) { + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + materialButton = toolkit.createButton(parent, "Has Material", SWT.CHECK); + materialButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + boolean t = materialButton.getSelection(); + ambientComposite.setEnabled(t); + diffuseComposite.setEnabled(t); + specularComposite.setEnabled(t); + emissiveComposite.setEnabled(t); + specularSlider.setEnabled(t); + transparencySlider.setEnabled(t); + + } + }); + GridData data = new GridData(GridData.FILL, GridData.FILL, false, false,2,1); + materialButton.setLayoutData(data); + + data = new GridData(GridData.FILL, GridData.FILL, false, false,1,1); + data.widthHint = 100; + data.heightHint = 20; + + toolkit.createLabel(parent, "Ambient"); + ambientComposite = toolkit.createComposite(parent, SWT.BORDER); + ambientComposite.setLayoutData(data); + ambientComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + ambientComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + + toolkit.createLabel(parent, "Diffuse"); + diffuseComposite = toolkit.createComposite(parent, SWT.BORDER); + diffuseComposite.setLayoutData(data); + diffuseComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + diffuseComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + toolkit.createLabel(parent, "Specular"); + specularComposite = toolkit.createComposite(parent, SWT.BORDER); + specularComposite.setLayoutData(data); + specularComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + + RGB rgb = dialog.open(); + if (rgb != null) { + specularComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + toolkit.createLabel(parent, "Emissive"); + emissiveComposite = toolkit.createComposite(parent, SWT.BORDER); + emissiveComposite.setLayoutData(data); + emissiveComposite.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + ColorDialog dialog = new ColorDialog(AppearanceEditor.this.getBody().getShell()); + RGB rgb = dialog.open(); + if (rgb != null) { + emissiveComposite.setBackground(new Color(AppearanceEditor.this.getBody().getDisplay(),rgb)); + + } + } + }); + toolkit.createLabel(parent, "Shininess"); + specularSlider = new Slider(parent,SWT.NONE); + specularSlider.setValues(20, 0, 255, 1, 1, 10); + toolkit.adapt(specularSlider, true, true); + toolkit.createLabel(parent, "Transparency"); + transparencySlider = new Slider(parent,SWT.NONE); + transparencySlider.setValues(0, 0, 100, 1, 1, 10); + toolkit.adapt(transparencySlider, true, true); + apply2Button = toolkit.createButton(parent, "Apply", SWT.PUSH); + apply2Button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + convertMaterial(); + } + }); + + } + + private void createTextureGroup(Composite parent) { + textureParent = parent; + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + + textureButton = toolkit.createButton(parent, "Has Texture", SWT.CHECK); + textureButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + //loadImageButton.setEnabled(textureButton.getSelection()); + //imageComposite.setEnabled(textureButton.getSelection()); + //textureButton.setEnabled(textureButton.getSelection()); + + } + }); + + + + textureButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + //loadImageButton.setEnabled(textureButton.getSelection()); + //imageComposite.setEnabled(textureButton.getSelection()); + //textureButton.setEnabled(textureButton.getSelection()); + + } + }); + addTextureButton = toolkit.createButton(parent, "Add Texture", SWT.PUSH); + addTextureButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + textureComposites.add(new TextureComposite(textureParent,SWT.NONE)); + } + }); + applyButton = toolkit.createButton(parent, "Apply", SWT.PUSH); + applyButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + convertImage(); + } + }); + + } + + private void createShaderGroup(Composite parent) { + toolkit.paintBordersFor(parent); + toolkit.setBorderStyle(SWT.BORDER); + GridData data = new GridData(SWT.FILL,SWT.FILL,true,true,2,1); + shaderButton = toolkit.createButton(parent, "Has Shader", SWT.CHECK); + shaderButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + + } + }); + shaderButton.setLayoutData(data); + data = new GridData(SWT.FILL,SWT.FILL,true,true,1,1); + data.widthHint = 400; + data.heightHint = 200; + toolkit.createLabel(parent, "Vertex Shader"); + vertexShaderText = toolkit.createText(parent,"", SWT.MULTI); + vertexShaderText.setLayoutData(data); + toolkit.createLabel(parent, "Fragment Shader"); + fragmentShaderText = toolkit.createText(parent,"", SWT.MULTI); + fragmentShaderText.setLayoutData(data); + apply3Button = toolkit.createButton(parent, "Apply", SWT.PUSH); + apply3Button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + convertShader(); + } + }); + } + + + + private void convertShader() { + updating = true; + final boolean hasShader = shaderButton.getSelection(); + final String vertexShader = vertexShaderText.getText(); + final String fragmentShader = fragmentShaderText.getText(); + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = new Appearance(g,appearanceResource); + if (hasShader) { + Shader s = appearance.getShader(); + if (s == null) { + s = Shader.createDefault(g); + appearance.setShader(s); + + } + s.setVertexShader(vertexShader); + s.setFragmentShader(fragmentShader); + } else { + appearance.setShader(null); + } + + updating = false; + return GraphRequestStatus.transactionComplete(); + } + }); + + + } + + private void convertMaterial() { + updating = true; + + final boolean hasMaterial = materialButton.getSelection(); + final Color ambientColor = ambientComposite.getBackground(); + final Color diffuseColor = diffuseComposite.getBackground(); + final Color specularColor = specularComposite.getBackground(); + final Color emissiveColor = emissiveComposite.getBackground(); + final double shininess = (double)specularSlider.getSelection(); + final double transparency = (double)transparencySlider.getSelection()/ 100.0; + + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = new Appearance(g,appearanceResource); + if (hasMaterial) { + Material m = appearance.getMaterial(); + if (m == null) { + m = Material.createDefault(g); + } + org.simantics.proconf.g3d.stubs.Color aColor = m.getAmbientColor(); + org.simantics.proconf.g3d.stubs.Color dColor = m.getDiffuseColor(); + org.simantics.proconf.g3d.stubs.Color sColor = m.getSpecularColor(); + org.simantics.proconf.g3d.stubs.Color eColor = m.getEmissiveColor(); + AppearanceTools.setColor(aColor,ambientColor); + AppearanceTools.setColor(dColor,diffuseColor); + AppearanceTools.setColor(sColor, specularColor); + AppearanceTools.setColor(eColor, emissiveColor); + m.setShininess(shininess); + m.setTransparency(transparency); + appearance.setMaterial(m); + } else { + appearance.removeRelatedStatements(Resources.g3dResource.HasMaterial); + } + + updating = false; + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + private void convertImage() { + updating = true; + getSession().syncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + Appearance appearance = new Appearance(g,appearanceResource); + Texture t = appearance.getTexture(); + if (textureComposites.size() == 1) { + ImageTexture t2 = null; + if (t != null && t.isInstanceOf(Resources.g3dResource.ImageTexture)) { + t2 = new ImageTexture(t); + } else { + t2 = ImageTexture.createDefault(g); + appearance.setTexture(t2); + } + final Resource mode = textureComposites.get(0).getModeType(); + + + if (mode != null) + t2.setTextureMode(mode); + textureComposites.get(0).getTexture(t2); + + } else if (textureComposites.size() > 1) { + MultiTexture mt = null; + if (t != null + && t.isInstanceOf(Resources.g3dResource.MultiTexture)) { + mt = new MultiTexture(t); + } else { + mt = MultiTexture.createDefault(g); + appearance.setTexture(mt); + } + StubLinkedList elements = new StubLinkedList(mt.getMultiTextureElementList()); + //PropertyTypeSet elements = mt.getMultiTextureElementSet(); + Iterator it = elements.iterator(); + for (int i = 0; i < textureComposites.size(); i++) { + TextureComposite tc = textureComposites.get(i); + + ImageTexture tex = null; + if (it.hasNext()) + tex = new ImageTexture(it.next()); + else { + tex = ImageTexture.createDefault(g); + elements.add(i,tex); + } + Resource mode = tc.getModeType(); + if (mode == null) + tex.setTextureMode(Resources.g3dResource.CombineMode_modulate); + else + tex.setTextureMode(mode); + + textureComposites.get(i).getTexture(tex); + + } + } else { + appearance.setTexture(null); + } + + updating = false; + return GraphRequestStatus.transactionComplete(); + } + }); + + + + + } + + private class TextureComposite extends Composite { + private Button textureGeneratorButton; + private Button sphereMapButton; + private Button eyeLinearButton; + private Button objectLinearButton; + private Button normalMapButton; + private Button reflectionMapButton; + + private Button modulateButton; + private Button replaceButton; + private Button decalButton; + private Button blendButton; + + + + private Button loadImageButton; + private ImageComposite imageComposite; + private Button removeButton; + + + public TextureComposite(Composite parent, int style) { + super(parent,style); + GridLayout layout = new GridLayout(2,false); + this.setLayout(layout); + + loadImageButton = toolkit.createButton(this, "Load Texture", SWT.PUSH); + loadImageButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + IImage[] images = ImageUtils.loadImagesDialog(getSite().getShell(), false, ImageUtils.getImageFactories()); + if (images == null) + return; + IImage image = images[0]; + setImage(image); + + } + }); + GridData data = new GridData(SWT.LEFT,SWT.FILL,false,false,2,1); + + loadImageButton.setLayoutData(data); + data = new GridData(SWT.FILL,SWT.FILL,true,true,2,1); + imageComposite = new ImageComposite(this,SWT.BORDER); + imageComposite.setLayoutData(data); + + Composite texGenComposite = toolkit.createComposite(this, SWT.BORDER); + layout = new GridLayout(1,false); + texGenComposite.setLayout(layout); + data = new GridData(SWT.FILL,SWT.FILL,true,true,1,1); + data.heightHint = 140; + texGenComposite.setLayoutData(data); + textureGeneratorButton = toolkit.createButton(texGenComposite, "Has Texture Coordinate Generator", SWT.CHECK); + textureGeneratorButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + sphereMapButton.setEnabled(textureGeneratorButton.getSelection()); + eyeLinearButton.setEnabled(textureGeneratorButton.getSelection()); + objectLinearButton.setEnabled(textureGeneratorButton.getSelection()); + normalMapButton.setEnabled(textureGeneratorButton.getSelection()); + reflectionMapButton.setEnabled(textureGeneratorButton.getSelection()); + + } + }); + + sphereMapButton = toolkit.createButton(texGenComposite, "Shpere Map", SWT.RADIO); + sphereMapButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!sphereMapButton.getSelection()) { + sphereMapButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + objectLinearButton.setSelection(false); + normalMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + eyeLinearButton = toolkit.createButton(texGenComposite, "Eye Linear", SWT.RADIO); + eyeLinearButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!eyeLinearButton.getSelection()) { + eyeLinearButton.setSelection(true); + } else { + sphereMapButton.setSelection(false); + objectLinearButton.setSelection(false); + normalMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + objectLinearButton = toolkit.createButton(texGenComposite, "Object Linear", SWT.RADIO); + objectLinearButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!objectLinearButton.getSelection()) { + objectLinearButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + sphereMapButton.setSelection(false); + normalMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + normalMapButton = toolkit.createButton(texGenComposite, "Normal Map", SWT.RADIO); + normalMapButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!normalMapButton.getSelection()) { + normalMapButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + objectLinearButton.setSelection(false); + sphereMapButton.setSelection(false); + reflectionMapButton.setSelection(false); + } + } + }); + reflectionMapButton = toolkit.createButton(texGenComposite, "Reflection Map", SWT.RADIO); + reflectionMapButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (!reflectionMapButton.getSelection()) { + reflectionMapButton.setSelection(true); + } else { + eyeLinearButton.setSelection(false); + objectLinearButton.setSelection(false); + normalMapButton.setSelection(false); + sphereMapButton.setSelection(false); + } + } + }); + + Composite texModeComposite = toolkit.createComposite(this, SWT.BORDER); + texModeComposite.setLayout(layout); + texModeComposite.setLayoutData(data); + modulateButton = toolkit.createButton(texModeComposite, "Modulate", SWT.RADIO); + modulateButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(true); + replaceButton.setSelection(false); + blendButton.setSelection(false); + decalButton.setSelection(false); + + } + }); + blendButton = toolkit.createButton(texModeComposite, "Blend", SWT.RADIO); + blendButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(false); + replaceButton.setSelection(false); + blendButton.setSelection(true); + decalButton.setSelection(false); + + } + }); + replaceButton = toolkit.createButton(texModeComposite, "Replace", SWT.RADIO); + replaceButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(false); + replaceButton.setSelection(true); + blendButton.setSelection(false); + decalButton.setSelection(false); + + } + }); + decalButton = toolkit.createButton(texModeComposite, "Decal", SWT.RADIO); + decalButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + modulateButton.setSelection(false); + replaceButton.setSelection(false); + blendButton.setSelection(false); + decalButton.setSelection(true); + + } + }); + + removeButton = toolkit.createButton(this, "Remove texture", SWT.PUSH); + parent.getParent().getParent().layout(true, true); + } + + public void setImage(IImage image) { + imageComposite.setImage(image); + } + + public IImage getImage() { + return imageComposite.getImage(); + } + + public void update(ImageTexture t2) throws Exception { + Graph graph = t2.getGraph(); + org.simantics.image.stubs.Image i = t2.getImage(); + IImageFactory f = ImageUtils.getImageFactoryForResource(graph,i.getResource()); + final IImage p = f.createImageForResource(graph,i.getResource()); +// PixelDimension pd = p.getDimensions().getPixelDimension(); +// if (pd==null) pd = AppearanceTools.DEFAULT_SIZE; +// final ImageData id = p.rasterize(pd.getWidth(), pd.getHeight()); + + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + //Image im = new Image(AppearanceEditor.this.getBody().getDisplay(),id); + //imageComposite.setImage(im); + //showImage(); + setImage(p); + + } + }); + + TextureCoordinateGenerator gen = t2.getTextureCoordinateGenerator(); + final boolean tg; + final boolean sm; + final boolean el; + final boolean ol; + final boolean nm; + final boolean rm; + if (gen == null) { + tg = false; + sm = false; + el = false; + ol = false; + nm = false; + rm = false; + } else { + //type = gen.getTextureCoordinateGeneratorTypeValue(); + //textureGeneratorButton.setSelection(true); + tg = true; + if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_sphere)) { + sm = true; + el = false; + ol = false; + nm = false; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_eyelinear)) { + sm = false; + el = true; + ol = false; + nm = false; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_objectlinear)) { + sm = false; + el = false; + ol = true; + nm = false; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_normal)) { + sm = false; + el = false; + ol = false; + nm = true; + rm = false; + } else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_reflection)) { + sm = false; + el = false; + ol = false; + nm = false; + rm = true; + } else { + sm = false; + el = false; + ol = false; + nm = false; + rm = false; + } + + } + + parent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + textureGeneratorButton.setSelection(tg); + sphereMapButton.setSelection(sm); + eyeLinearButton.setSelection(el); + objectLinearButton.setSelection(ol); + normalMapButton.setSelection(nm); + reflectionMapButton.setSelection(rm); + sphereMapButton.setEnabled(textureGeneratorButton.getSelection()); + eyeLinearButton.setEnabled(textureGeneratorButton.getSelection()); + objectLinearButton.setEnabled(textureGeneratorButton.getSelection()); + normalMapButton.setEnabled(textureGeneratorButton.getSelection()); + reflectionMapButton.setEnabled(textureGeneratorButton.getSelection()); + + } + }); + } + + + public Resource getGenType() { + if (sphereMapButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_sphere; + else if (eyeLinearButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_eyelinear; + else if (objectLinearButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_objectlinear; + else if (normalMapButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_normal; + else if (reflectionMapButton.getSelection()) + return Resources.g3dResource.TextureCoordinateGenerator_reflection; + return null; + } + + public Resource getModeType() { + if (modulateButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_modulate; + else if (replaceButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_replace; + else if (blendButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_blend; + else if (decalButton.getSelection()) + return Resources.g3dResource.MultiTextureMode_decal; + + return null; + } + + public void getTexture(ImageTexture t2) throws Exception{ + Graph g = t2.getGraph(); + IImage image = getImage(); + if (image != null) { + Resource res = image.instantiateAsResource(g); + t2.setImage(res); + } + final Resource t2res = t2.getResource(); + + if (textureGeneratorButton.getSelection()) { + final Resource type; + if (sphereMapButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_sphere; + else if (eyeLinearButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_eyelinear; + else if (objectLinearButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_objectlinear; + else if (normalMapButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_normal; + else if (reflectionMapButton.getSelection()) + type = Resources.g3dResource.TextureCoordinateGenerator_reflection; + else + type = null; + if (type != null) { + getSession().asyncWrite(new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + ImageTexture t2 = new ImageTexture(g, t2res); + t2.setTextureCoordinateGenerator(type); + return GraphRequestStatus.transactionComplete(); + } + }); + + } + + } + } + + /* + * public void getTexture(ImageTexture t2) { if + * (imageComposite.getImage() != null) { ImageData data = + * imageComposite.getImage().getImageData(); if (!data.palette.isDirect) { + * throw new RuntimeException("Not direct"); } int bytes = 0; String + * type = ""; if (data.depth != 32 && data.depth != 24) { throw new + * UnsupportedOperationException("Cannot handle bitdepth " + + * data.depth); } if (data.depth == 32) { bytes = 4; type = "RGBA"; } + * else if (data.depth == 24) { bytes = 3; type = "RGB"; } String size = + * data.width + " " + data.height; byte texturedata[] = new + * byte[data.width * data.height * bytes]; for (int y = 0; y < + * data.height; y++) { for (int x = 0; x < data.width; x++) { int index = + * (y * data.width + x) * bytes; + * + * texturedata[index] = data.data[index]; texturedata[index + 1] = + * data.data[index + 1]; texturedata[index + 2] = data.data[index + 2]; + * if (bytes == 4) texturedata[index + 3] = data.data[index + 3]; + * } } String base64 = new + * sun.misc.BASE64Encoder().encode(texturedata); // if + * (coreTC.getCurrentTransaction() == null) + * + * + * + * fi.vtt.proconf.threedimensionalmodeling.stub.v1_0.Image i = + * t2.getImage(); if (i == null) { i = ImageFactory.instantiate(graph); + * graph.commitChanges(this); t2.setImage(i); } + * i.setImageDataValue(base64); i.setImageTypeValue(type); + * i.setImageSizeValue(size); graph.commitChanges(this); if + * (textureGeneratorButton.getSelection()) { type = null; if + * (sphereMapButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_SPHERE; else if + * (eyeLinearButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_EYE_LINEAR; else if + * (objectLinearButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_OBJECT_LINEAR; else if + * (normalMapButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_NORMAL; else if + * (reflectionMapButton.getSelection()) type = + * AppearanceTools.TEXTURE_COORD_GEN_REFLECTION; else type = null; if + * (type != null) { TextureCoordinateGenerator gen = + * t2.getTextureCoordinateGenerator(); if (gen == null) { gen = + * TextureCoordinateGeneratorFactory.instantiate(graph); + * graph.commitChanges(this); t2.setTextureCoordinateGenerator(gen); } + * gen.setTextureCoordinateGeneratorTypeValue(type); + * graph.commitChanges(this); } + * } else { //t2.setTextureCoordinateGenerator(null); + * graph.commitChanges(this); } + * } } + */ + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java new file mode 100644 index 00000000..ee3f1277 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/ScenegraphViewPart.java @@ -0,0 +1,610 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.views; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.ui.views.properties.ComboBoxPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.TextPropertyDescriptor; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorPart; +import org.simantics.proconf.g3d.scenegraph.IGeometryNode; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.scenegraph.ISelectableNode; +import org.simantics.utils.ui.gfx.ImageCache; + +import com.jme.scene.Geometry; +import com.jme.scene.Node; +import com.jme.scene.SceneElement; +import com.jme.scene.Spatial; +import com.jme.scene.batch.GeomBatch; + +public class ScenegraphViewPart extends ViewPart{ + + private static final ImageDescriptor GEOMETRY_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/geometry.png"); + private static final ImageDescriptor BATCH_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/batch.png"); + private static final ImageDescriptor NODE_IMAGE = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/node.png"); + + + TreeViewer viewer; + + IPartListener listener; + + Action showJMEAction; + + @Override + public void createPartControl(Composite parent) { + + viewer = new TreeViewer(parent, SWT.SINGLE | SWT.H_SCROLL| SWT.V_SCROLL); + viewer.setContentProvider(new GNScenegraphContentProvider()); + viewer.setLabelProvider(new GNScenegraphLabelProvider()); + getSite().setSelectionProvider(viewer); + + makeActions(); + + IActionBars actionBar = getViewSite().getActionBars(); + contributeToActionBars(actionBar); + + listener = new IPartListener() { + @Override + public void partActivated(IWorkbenchPart part) { + if (part instanceof ThreeDimensionalEditorPart) { + ThreeDimensionalEditorPart p = (ThreeDimensionalEditorPart)part; + Object newInput = p.getEditor(); + if (viewer.getInput() != newInput) + viewer.setInput(newInput); + } else { + //viewer.setInput(null); + } + + } + + @Override + public void partBroughtToTop(IWorkbenchPart part) { + + } + + @Override + public void partClosed(IWorkbenchPart part) { + + } + + @Override + public void partDeactivated(IWorkbenchPart part) { + + } + + @Override + public void partOpened(IWorkbenchPart part) { + + } + }; + for (IWorkbenchWindow w : PlatformUI.getWorkbench().getWorkbenchWindows()) { + w.getPartService().addPartListener(listener); + + } + + } + + protected void makeActions() { + showJMEAction = new Action("jME",Action.AS_CHECK_BOX) { + @Override + public void run() { + Object input = viewer.getInput(); + viewer.setInput(null); + if (this.isChecked()) { + viewer.setContentProvider(new JMEScenegraphContentProvider()); + viewer.setLabelProvider(new JMEScenegraphLabelProvider()); + } else { + viewer.setContentProvider(new GNScenegraphContentProvider()); + viewer.setLabelProvider(new GNScenegraphLabelProvider()); + } + viewer.setInput(input); + } + }; + } + + protected void contributeToActionBars(IActionBars bars) { + fillLocalToolBar(bars.getToolBarManager()); + fillLocalPullDown(bars.getMenuManager()); + bars.updateActionBars(); + } + + protected void fillLocalToolBar(IToolBarManager manager) { + manager.add(showJMEAction); + } + + protected void fillLocalPullDown(IMenuManager manager) { + + } + + @Override + public void setFocus() { + viewer.getControl().setFocus(); + } + + public void dispose() { + for (IWorkbenchWindow w : PlatformUI.getWorkbench().getWorkbenchWindows()) { + w.getPartService().removePartListener(listener); + + } + super.dispose(); + } + + + private class JMEScenegraphContentProvider implements ITreeContentProvider { + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof JMEAdaptable) + parentElement = ((JMEAdaptable)parentElement).getElement(); + + if (parentElement instanceof Node) { + Node n = (Node)parentElement; + Object o[] = new Object[n.getChildren().size()]; + for (int i = 0; i < n.getChildren().size(); i++) { + o[i] = new JMEAdaptable(n.getChild(i)); + } + return o; + } + if (parentElement instanceof Geometry) { + Geometry g = (Geometry)parentElement; + Object o[] = new Object[g.getBatchCount()]; + for (int i = 0 ; i < g.getBatchCount(); i++) + o[i] = new JMEAdaptable(g.getBatch(i)); + return o; + } + return null; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof ThreeDimensionalEditorBase) { + SceneElement root = ((ThreeDimensionalEditorBase)inputElement).getRenderingComponent().getRoot(); + if (root != null) + return new Object[]{new JMEAdaptable(root)}; + } + return new Object[0]; + } + + @Override + public Object getParent(Object element) { + SceneElement e; + if (element instanceof JMEAdaptable) + e = ((JMEAdaptable)element).getElement(); + else + e = (SceneElement)element; + if (e instanceof Spatial) { + Spatial s = (Spatial)e; + return s.getParent(); + } + if (e instanceof GeomBatch) { + GeomBatch g = (GeomBatch)e; + return g.getParentGeom(); + } + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof JMEAdaptable) + element = ((JMEAdaptable)element).getElement(); + if (element instanceof Node) { + Node n = (Node)element; + if (n.getChildren() == null) + return false; + return n.getChildren().size() > 0; + } + if (element instanceof Geometry) { + Geometry g = (Geometry)element; + return g.getBatchCount() > 0; + } + return false; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + @Override + public void dispose() { + + } + } + + private class JMEScenegraphLabelProvider extends LabelProvider { + @Override + public String getText(Object element) { + if (element == null) + return null; + if (element instanceof JMEAdaptable) + element = ((JMEAdaptable)element).getElement(); + SceneElement e = (SceneElement)element; + return e.getName() + " : " + e.getClass(); + } + + @Override + public Image getImage(Object element) { + if (element == null) + return null; + if (element instanceof JMEAdaptable) + element = ((JMEAdaptable)element).getElement(); + ImageDescriptor desc = null; + if (element instanceof GeomBatch) + desc = BATCH_IMAGE; + else if (element instanceof Geometry) + desc = GEOMETRY_IMAGE; + else if (element instanceof Node) + desc = NODE_IMAGE; + else + return null; + return ImageCache.getInstance().getImage(desc); + } + } + + private class GNScenegraphContentProvider implements ITreeContentProvider { + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof GNAdaptable) + parentElement = ((GNAdaptable)parentElement).getNode(); + IGraphicsNode node = (IGraphicsNode)parentElement; + Object children[] = new Object[node.getChildren().size()]; + Iterator it = node.getChildren().iterator(); + for (int i = 0; i < node.getChildren().size(); i++) { + children[i] = new GNAdaptable(it.next()); + } + return children; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof ThreeDimensionalEditorBase) { + IGraphicsNode root = ((ThreeDimensionalEditorBase)inputElement).getScenegraphAdapter().getRootNode(); + if (root != null) + return new Object[]{new GNAdaptable(root)}; + } + return new Object[0]; + } + + @Override + public Object getParent(Object element) { + if (element instanceof GNAdaptable) + element = ((GNAdaptable)element).getNode(); + IGraphicsNode node = (IGraphicsNode)element; + return node.getParent(); + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof GNAdaptable) + element = ((GNAdaptable)element).getNode(); + IGraphicsNode node = (IGraphicsNode)element; + return node.getChildren().size() > 0; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + + } + + @Override + public void dispose() { + + } + } + + private class GNScenegraphLabelProvider extends LabelProvider { + @Override + public String getText(Object element) { + if (element instanceof GNAdaptable) + element = ((GNAdaptable)element).getNode(); + IGraphicsNode node = (IGraphicsNode)element; + return node.getGroup().getName() + " : " + node.getClass(); + } + + @Override + public Image getImage(Object element) { + ImageDescriptor desc = NODE_IMAGE; +// if (element instanceof GeomBatch) +// desc = BATCH_IMAGE; +// else if (element instanceof Geometry) +// desc = GEOMETRY_IMAGE; +// else if (element instanceof Node) +// desc = NODE_IMAGE; +// else +// return null; + return ImageCache.getInstance().getImage(desc); + } + } + + private class JMEAdaptable implements IAdaptable { + SceneElement element; + + public JMEAdaptable(SceneElement element) { + assert (element != null); + this.element = element; + } + + @SuppressWarnings("unchecked") + @Override + public Object getAdapter(Class adapter) { + if (adapter == IPropertySource.class) { + return new JMEProperties(element); + } + return null; + } + + public SceneElement getElement() { + return element; + } + } + + private class GNAdaptable implements IAdaptable { + IGraphicsNode node; + + public GNAdaptable(IGraphicsNode node) { + assert (node != null); + this.node = node; + } + + @SuppressWarnings("unchecked") + @Override + public Object getAdapter(Class adapter) { + if (adapter == IPropertySource.class) { + return new GNProperties(node); + } + return null; + } + + public IGraphicsNode getNode() { + return node; + } + } + + private static final String NAME = "name"; + private static final String CULL_MODE = "cullmode"; + private static final String CULL_MODES[] = {"Inherit","Dynamic","Always","Never"}; + private static final String LIGHT_MODE = "lightmode"; + private static final String LIGHT_MODES[] = {"Off","Combine First","Combine Closest","Combine Recent Enabled","Inherit","Replace"}; + private static final String LOCAL_CULL_MODE = "localcullmode"; + private static final String LOCAL_LIGHT_MODE = "locallightmode"; + private static final String LOCAL_NORMALS_MODE = "localnormalsmode"; + private static final String LOCAL_RENDER_QUEUE_MODE ="localrenderqueuemode"; + private static final String LOCAL_TEXTURE_COMBINE_MODE = "localtexturecombinemode"; + private static final String LOCKS = "locks"; + private static final String NORMALS_MODE = "normalsmode"; + private static final String NORMALS_MODES[] = {"Inherit","Use Provided","Normalize Provided","Normalize if scaled","Off"}; + private static final String RENDER_QUEUE_MODE = "renderqueuemode"; + private static final String RENDER_QUEUE_MODES[] = {"Inherit","Skip","Opaque","Transparent","Ortho"}; + private static final String TEXTURE_COMBINE_MODE = "texturecombinemode"; + private static final String TEXTURE_COMBINE_MODES[] = {"Off","First","Closest","Recent enabled","Inherit","Replace"}; + + private static final String BOOLEAN_VALUES[] = {"False","True"}; + + private class JMEProperties implements IPropertySource { + + SceneElement element; + + public JMEProperties(SceneElement element) { + this.element = element; + } + + @Override + public Object getEditableValue() { + return this; + } + + @Override + public IPropertyDescriptor[] getPropertyDescriptors() { + List desc = new ArrayList(); + desc.add(new TextPropertyDescriptor(NAME,"Name")); + desc.add(new ComboBoxPropertyDescriptor(CULL_MODE,"Cull Mode",CULL_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LIGHT_MODE,"Light Combine Mode",LIGHT_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_CULL_MODE,"Local Cull Mode",CULL_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_LIGHT_MODE,"Local Light Combine Mode",LIGHT_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_NORMALS_MODE,"Local Normals Mode",NORMALS_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_RENDER_QUEUE_MODE,"Local Render Queue Mode",RENDER_QUEUE_MODES)); + desc.add(new ComboBoxPropertyDescriptor(LOCAL_TEXTURE_COMBINE_MODE,"Local Texture Combine Mode",TEXTURE_COMBINE_MODES)); + desc.add(new TextPropertyDescriptor(LOCKS,"Locks")); + desc.add(new ComboBoxPropertyDescriptor(NORMALS_MODE,"Normals Mode",NORMALS_MODES)); + desc.add(new ComboBoxPropertyDescriptor(RENDER_QUEUE_MODE,"Render Queue Mode",RENDER_QUEUE_MODES)); + desc.add(new ComboBoxPropertyDescriptor(TEXTURE_COMBINE_MODE,"Texture Combine Mode",TEXTURE_COMBINE_MODES)); + return desc.toArray(new IPropertyDescriptor[desc.size()]); + + } + + @Override + public Object getPropertyValue(Object id) { + if (id == NAME) { + return element.getName(); + } else if (id == CULL_MODE) { + return element.getCullMode(); + } else if (id == LIGHT_MODE) { + return element.getLightCombineMode(); + } else if (id == LOCAL_CULL_MODE) { + return element.getLocalCullMode(); + } else if (id == LOCAL_LIGHT_MODE) { + return element.getLocalLightCombineMode(); + } else if (id == LOCAL_NORMALS_MODE) { + return element.getLocalNormalsMode(); + } else if (id == LOCAL_RENDER_QUEUE_MODE) { + return element.getLocalRenderQueueMode(); + } else if (id == LOCAL_TEXTURE_COMBINE_MODE) { + return element.getLocalTextureCombineMode(); + } else if (id == LOCKS) { + return element.getLocks(); + } else if (id == NORMALS_MODE) { + return element.getNormalsMode(); + } else if (id == RENDER_QUEUE_MODE) { + return element.getRenderQueueMode(); + } else if (id == TEXTURE_COMBINE_MODE) { + return element.getTextureCombineMode(); + } + +// element.getZOrder(); +// element.isCollidable(); + + return null; + } + + @Override + public boolean isPropertySet(Object id) { + return false; + } + + @Override + public void resetPropertyValue(Object id) { + + } + + @Override + public void setPropertyValue(Object id, Object value) { + if (id == NAME) { + element.setName((String)value); + } else if (id == CULL_MODE) { + element.setCullMode((Integer)value); + } else if (id == LIGHT_MODE) { + element.setLightCombineMode((Integer)value); + } else if (id == LOCAL_CULL_MODE) { + + } else if (id == LOCAL_LIGHT_MODE) { + + } else if (id == LOCAL_NORMALS_MODE) { + + } else if (id == LOCAL_RENDER_QUEUE_MODE) { + + } else if (id == LOCAL_TEXTURE_COMBINE_MODE) { + + } else if (id == LOCKS) { + element.setLocks((Integer)value); + } else if (id == NORMALS_MODE) { + element.setNormalsMode((Integer)value); + } else if (id == RENDER_QUEUE_MODE) { + element.setRenderQueueMode((Integer)value); + } else if (id == TEXTURE_COMBINE_MODE) { + element.setTextureCombineMode((Integer)value); + } + + } + + } + + private static final String SELECTED = "selected"; + private static final String HIGHLIGHTED = "highlighted"; + private static final String VISIBLE = "visible"; + + private class GNProperties implements IPropertySource { + IGraphicsNode node; + + public GNProperties(IGraphicsNode node) { + this.node = node; + } + + + @Override + public Object getEditableValue() { + return this; + } + + @Override + public IPropertyDescriptor[] getPropertyDescriptors() { + List desc = new ArrayList(); + if (node instanceof ISelectableNode) { + //ISelectableNode n = (ISelectableNode)node; + + desc.add(new ComboBoxPropertyDescriptor(SELECTED,"Selected",BOOLEAN_VALUES)); + desc.add(new ComboBoxPropertyDescriptor(HIGHLIGHTED,"Highlighted",BOOLEAN_VALUES)); + desc.add(new ComboBoxPropertyDescriptor(VISIBLE,"Visible",BOOLEAN_VALUES)); + + } + return desc.toArray(new IPropertyDescriptor[desc.size()]); + } + + @Override + public Object getPropertyValue(Object id) { + if (node instanceof ISelectableNode) { + ISelectableNode n = (ISelectableNode)node; + if (id == SELECTED) { + if (n.isSelected()) + return 1; + return 0; + } else if (id == HIGHLIGHTED) { + if (n.isHighlighted()) + return 1; + return 0; + } else if (id == VISIBLE) { + if (n.isVisible()) + return 1; + return 0; + } + } + if (node instanceof IGeometryNode) { + //IGeometryNode n = (IGeometryNode)node; + } + + return null; + } + + @Override + public boolean isPropertySet(Object id) { + return false; + } + + @Override + public void resetPropertyValue(Object id) { + + } + + @Override + public void setPropertyValue(Object id, Object value) { + if (node instanceof ISelectableNode) { + ISelectableNode n = (ISelectableNode)node; + boolean b = ((Integer)value) == 1; + if (id == SELECTED) { + n.setSelected(b); + } else if (id == HIGHLIGHTED) { + n.setHighlighted(b); + } else if (id == VISIBLE) { + n.setVisible(b); + } + } + + } + + + } + +} + + diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java new file mode 100644 index 00000000..1caba9d0 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceEditor.java @@ -0,0 +1,233 @@ +/******************************************************************************* + * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.views; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.proconf.g3d.common.StructuredResourceSelection; +import org.simantics.proconf.ui.workbench.ResourceEditorPart; +import org.simantics.utils.ErrorLogger; +import org.simantics.utils.ui.ISelectionUtils; +import org.simantics.utils.ui.jface.BaseSelectionProvider; + + + +public abstract class SinglePageResourceEditor extends ResourceEditorPart { + private ScrolledForm form; + private BaseSelectionProvider defaultInputSelectionProvider = new BaseSelectionProvider(); + protected FormToolkit toolkit; + + @Override + public void createPartControl(Composite parent) { + this.getEditorSite().getPage().addPartListener(new IPartListener() { + + boolean opened = false; + boolean activated = false; + + public void partOpened(IWorkbenchPart part) { + if (part.equals(SinglePageResourceEditor.this.getEditorSite().getPart())) { + opened = true; + } + } + + public void partActivated(IWorkbenchPart part) { + if (part.equals(SinglePageResourceEditor.this.getEditorSite().getPart())) { + if (opened & !activated) { + activated = true; + load(); + } + } + } + + public void partBroughtToTop(IWorkbenchPart part) {} + + public void partClosed(IWorkbenchPart part) {} + + public void partDeactivated(IWorkbenchPart part) {} + + private void load() { + Session ses = SinglePageResourceEditor.this.getSession(); + GraphRequestAdapter r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) + throws Exception { + reload(g); + return GraphRequestStatus.transactionComplete(); + } + }; + ses.asyncRead(r); + } + }); + try { + toolkit = new FormToolkit(parent.getDisplay()); + form = getToolkit().createScrolledForm(parent); + + GridLayout layout = new GridLayout(2, false); + form.getBody().setLayout(layout); + form.getBody().setLayoutData( + new GridData(GridData.FILL, GridData.FILL, true, true)); + + // By default make this ViewPart use a default ISelectionProvider + // that will offer the viewparts input resource as its selection. + // The Resource is wrapped into a ResourceSelection object. + // Any widgets created in createWidgets may override the default + // selection provider. + getEditorSite().setSelectionProvider(defaultInputSelectionProvider); + + beforeCreateWidgets(); + createWidgets(); + + //reload(); + + form.setText(getFormText()); + + // Finally Set the default selection which will have an effect only + // if nothing in createWidgets has overridden the default selection + // provider. + ISelection s = ISelectionUtils + .createSelection(new StructuredResourceSelection( + getInputResource())); + defaultInputSelectionProvider.setSelection(s); + + } catch (Exception e) { + Display d = getSite().getShell().getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + getSite().getPage().closeEditor( + SinglePageResourceEditor.this, false); + } + }); + + ErrorLogger.defaultLogError("Single-page type editor failed to open, see exception for details",e); + } + } + + public ScrolledForm getActiveForm() { + return form; + } + + protected Composite getBody() { + return form.getBody(); + } + + public Composite newGridSection(int formColumns, int childColumns, + boolean equalWidth, boolean grabVertical, String text, + String description) { + return newGridSection(getBody(), formColumns, childColumns, equalWidth, + grabVertical, text, description); + } + + public Composite newGridSection(Composite parent, int formColumns, + int childColumns, boolean equalWidth, boolean grabVertical, + String text, String description) { + FormToolkit toolkit = getToolkit(); + + Section section = toolkit.createSection(parent, Section.DESCRIPTION + | Section.TWISTIE | Section.TITLE_BAR | Section.EXPANDED); + section.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, + grabVertical, formColumns, 1)); + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(ExpansionEvent e) { + //System.out.println("SinglePageTypeEditor: expansionStateChanged " + e); + //reflow(true); + } + }); + section.setText(text); + section.setDescription(description); + Composite sectionClient = toolkit.createComposite(section); + sectionClient.setLayout(new GridLayout(childColumns, equalWidth)); + sectionClient.setLayoutData(new GridData()); + section.setClient(sectionClient); + return sectionClient; + } + + + + //---------------------------------------------------------------------- + // Getters + + public FormToolkit getToolkit() { + return toolkit; + } + + //---------------------------------------------------------------------- + // Event utilities + + public void reflow(boolean flushCache) { + //System.out.println("FormTypeEditorBase.reflow(" + flushCache + ")"); + getActiveForm().reflow(flushCache); + } + + @Override + public void dispose() { + if (toolkit != null) { + toolkit.dispose(); + } + super.dispose(); + } + + @Override + public void setFocus() { + //System.out.println("FormTypeEditorBase.setFocus(): Input = " + getInput()); + ScrolledForm form = getActiveForm(); + if (form != null) { + form.setFocus(); + } + } + + protected abstract String getFormText(); + + /** + * Returns null by default which makes {@link #updateTitle()} not set the + * part name programmatically, i.e. the plugin-defined view name will stay. + * + * @return + */ + protected String getTitleText() { + return null; + } + + /** + * Return null by default which makes {@link #updateTitle()} clear the + * tooltip. + * + * @return + */ + protected String getTitleTooltip() { + return null; + } + + /** + * A method for performing initializations just before UI initialization. + */ + protected void beforeCreateWidgets() { + } + + /** + * A method for initializing the UI of the view. + */ + protected void createWidgets() { + } +} diff --git a/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java new file mode 100644 index 00000000..d1d3dfd3 --- /dev/null +++ b/org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/views/SinglePageResourceView.java @@ -0,0 +1,155 @@ +package org.simantics.proconf.g3d.views; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; +import org.simantics.proconf.ui.workbench.GraphAccessViewPart; +import org.simantics.utils.ui.jface.BaseSelectionProvider; + +public abstract class SinglePageResourceView extends GraphAccessViewPart{ + protected Composite parent; + private ScrolledForm form; + private BaseSelectionProvider defaultInputSelectionProvider = new BaseSelectionProvider(); + protected FormToolkit toolkit; + protected ISelectionListener pageSelectionListener; + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + this.parent = parent; + + toolkit = new FormToolkit(parent.getDisplay()); + form = getToolkit().createScrolledForm(parent); + + GridLayout layout = new GridLayout(2, false); + form.getBody().setLayout(layout); + form.getBody().setLayoutData( + new GridData(GridData.FILL, GridData.FILL, true, true)); + + getViewSite().setSelectionProvider(defaultInputSelectionProvider); + + // createWidgets(); + + form.setText(getFormText()); + + hookPageSelection(); + + } + + + /** + * Receives selection changes + * + * @param part + * @param selection + */ + protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) { + + } + + + + + + protected abstract String getFormText(); + + protected abstract void createWidgets(); + + @Override + public void setFocus() { + //System.out.println("FormTypeEditorBase.setFocus(): Input = " + getInput()); + ScrolledForm form = getActiveForm(); + if (form != null) { + form.setFocus(); + } + } + + public FormToolkit getToolkit() { + return toolkit; + } + + public ScrolledForm getActiveForm() { + return form; + } + + public void clearForm() { + for (Control c : form.getBody().getChildren()) + c.dispose(); + + } + + protected Composite getBody() { + return form.getBody(); + } + + public Composite newGridSection( + int formColumns, + int childColumns, + boolean equalWidth, + boolean grabVertical, + String text, + String description) + { + return newGridSection(getBody(), formColumns, childColumns, equalWidth, grabVertical, text, description); + } + + public Composite newGridSection( + Composite parent, + int formColumns, + int childColumns, + boolean equalWidth, + boolean grabVertical, + String text, + String description) + { + FormToolkit toolkit = getToolkit(); + + Section section = toolkit.createSection(parent, + Section.DESCRIPTION | Section.TWISTIE | Section.TITLE_BAR | Section.EXPANDED); + section.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, grabVertical, formColumns, 1)); + section.addExpansionListener(new ExpansionAdapter() { + public void expansionStateChanged(ExpansionEvent e) { + //System.out.println("SinglePageTypeEditor: expansionStateChanged " + e); + //reflow(true); + } + }); + section.setText(text); + section.setDescription(description); + Composite sectionClient = toolkit.createComposite(section); + sectionClient.setLayout(new GridLayout(childColumns, equalWidth)); + sectionClient.setLayoutData(new GridData()); + section.setClient(sectionClient); + return sectionClient; + } + + public void dispose() { + if (pageSelectionListener != null) + getSite().getPage().removePostSelectionListener(pageSelectionListener); + + super.dispose(); + } + + private void hookPageSelection() { + pageSelectionListener = new ISelectionListener() { + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + if (part == SinglePageResourceView.this) + return; + pageSelectionChanged(part, selection); + } + }; + getSite().getPage().addPostSelectionListener(pageSelectionListener); + ISelection sel = getSite().getPage().getSelection(); + IWorkbenchPart wb = getSite().getPage().getActivePart(); + pageSelectionChanged(wb, sel); + } + +}