Revision: 503 http://skycastle.svn.sourceforge.net/skycastle/?rev=503&view=rev Author: zzorn Date: 2008-05-03 02:34:11 -0700 (Sat, 03 May 2008) Log Message: ----------- Started implementing a visual node and signal based language. Modified Paths: -------------- trunk/skycastle/modules/core/src/test/java/org/skycastle/language/LanguageTest.java trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/AbstractCompilableComponent.java trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/PortImpl.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/Canvas3D.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchRenderer.java Added Paths: ----------- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/AbstractBlock.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/Block.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/BlockReference.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/LanguageService.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlock.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlockReference.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalLanguageService.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/TaskInvocationStrategy.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/BasePort.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/ConnectionException.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/Port.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortDirection.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReference.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReferenceImpl.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortType.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroup.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroupType.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/AbstractSignalType.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/IntegerSignalType.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SendSignalTask.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPort.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortImpl.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortType.java trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalType.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRenderer.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRepainter.java trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/CanvasToTextureBufferedScreen.java Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/AbstractBlock.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/AbstractBlock.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/AbstractBlock.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,86 @@ +package org.skycastle.language; + +import org.skycastle.language.port.Port; +import org.skycastle.util.ParameterChecker; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Hans Haggstrom + */ +public abstract class AbstractBlock + implements Block +{ + + //====================================================================== + // Private Fields + + private final Map<String, Port> myPorts = new HashMap<String, Port>(); + + private BlockReference myReference; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Block Implementation + + public BlockReference getReference() + { + return myReference; + } + + public Collection<Port> getPorts() + { + return Collections.unmodifiableCollection( myPorts.values() ); + } + + + /** + * Adds the specified Port. + * + * @param port should not be null or already added. + */ + public void addPort( Port port ) + { + ParameterChecker.checkNotNull( port, "port" ); + ParameterChecker.checkNotAlreadyContained( port, myPorts, "myPorts" ); + + port.setHostBlock( this ); + + myPorts.put( port.getIdentifier(), port ); + } + + public void removePort( Port port ) + { + ParameterChecker.checkNotNull( port, "port" ); + + port.setHostBlock( null ); + + myPorts.remove( port.getIdentifier() ); + } + + + public Port getPort( final String portName ) + { + return myPorts.get( portName ); + } + + //---------------------------------------------------------------------- + // Other Public Methods + + /** + * @param reference the reference that should be used for this {@link Block}. Should only be called + * by the code that creates the block instance. + */ + public void setReference( final BlockReference reference ) + { + ParameterChecker.checkNotNull( reference, "reference" ); + + myReference = reference; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/Block.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/Block.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/Block.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,46 @@ +package org.skycastle.language; + +import org.skycastle.language.port.Port; + +import java.util.Collection; + +/** + * Represents an object in the visual language. + * + * @author Hans Haggstrom + */ +public interface Block +{ + /** + * @return other blocks should refer to this block with the block reference, instead of directly. + * This allows it to work e.g. in Sun Game Server. + */ + BlockReference getReference(); + + /** + * @return the ports available for this {@link Block}. + */ + Collection<Port> getPorts(); + + /** + * @param port a {@link Port} to add to this {@link Block}. + */ + void addPort( final Port port ); + + /** + * @param port the {@link Port} to remove from this {@link Block}. + */ + void removePort( final Port port ); + + /** + * @param portName the identifier of the port to get. + * + * @return the port with the specified identifier, or null if not found. + */ + Port getPort( final String portName ); + + /** + * @return a service that can be used to create new {@link Block}s, and to schedule tasks. + */ + LanguageService getLanguageService(); +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/BlockReference.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/BlockReference.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/BlockReference.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,13 @@ +package org.skycastle.language; + +import java.io.Serializable; + +/** + * @author Hans Haggstrom + */ +public interface BlockReference + extends Serializable +{ + Block getBlock( boolean forWriting ); + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/LanguageService.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/LanguageService.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/LanguageService.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,13 @@ +package org.skycastle.language; + +/** + * Provides functions for creating and referenceing to {@link Block}s. + * + * @author Hans Haggstrom + */ +public interface LanguageService +{ + Block createBlock(); + + void runTask( final Runnable task ); +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlock.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlock.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlock.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,43 @@ +package org.skycastle.language.local; + +import org.skycastle.language.AbstractBlock; +import org.skycastle.language.LanguageService; +import org.skycastle.util.ParameterChecker; + +/** + * A block used only in a local environment (unit tests, client code). + * + * @author Hans Haggstrom + */ +public final class LocalBlock + extends AbstractBlock +{ + + //====================================================================== + // Private Fields + + private final LanguageService myLanguageService; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public LocalBlock( final LanguageService languageService ) + { + ParameterChecker.checkNotNull( languageService, "languageService" ); + + myLanguageService = languageService; + } + + //---------------------------------------------------------------------- + // Block Implementation + + + public LanguageService getLanguageService() + { + return myLanguageService; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlockReference.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlockReference.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalBlockReference.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,49 @@ +package org.skycastle.language.local; + +import org.skycastle.language.Block; +import org.skycastle.language.BlockReference; +import org.skycastle.util.ParameterChecker; + +/** + * A {@link BlockReference} that works in a local environment, such as unit test or client side code. + * A direct referenceis kept to the block, and no difference is made between getting it for writing or reading. + * + * @author Hans Haggstrom + */ +@SuppressWarnings( { "NonSerializableFieldInSerializableClass" } ) +public final class LocalBlockReference + implements BlockReference +{ + + //====================================================================== + // Private Fields + + private final Block myBlock; + + //====================================================================== + // Private Constants + + private static final long serialVersionUID = 1L; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public LocalBlockReference( final Block block ) + { + ParameterChecker.checkNotNull( block, "block" ); + + myBlock = block; + } + + //---------------------------------------------------------------------- + // BlockReference Implementation + + public Block getBlock( final boolean forWriting ) + { + return myBlock; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalLanguageService.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalLanguageService.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/LocalLanguageService.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,54 @@ +package org.skycastle.language.local; + +import org.skycastle.language.AbstractBlock; +import org.skycastle.language.Block; +import org.skycastle.language.LanguageService; +import org.skycastle.util.ParameterChecker; + +/** + * A {@link LanguageService} that works in a local environment, such as a unit test or client code. + * + * @author Hans Haggstrom + */ +public final class LocalLanguageService + implements LanguageService +{ + + //====================================================================== + // Private Fields + + private final TaskInvocationStrategy myTaskInvocationStrategy; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public LocalLanguageService( final TaskInvocationStrategy taskInvocationStrategy ) + { + ParameterChecker.checkNotNull( taskInvocationStrategy, "taskInvocationStrategy" ); + + myTaskInvocationStrategy = taskInvocationStrategy; + } + + //---------------------------------------------------------------------- + // LanguageService Implementation + + + public Block createBlock() + { + final AbstractBlock block = new LocalBlock( this ); + + final LocalBlockReference reference = new LocalBlockReference( block ); + block.setReference( reference ); + + return block; + } + + public void runTask( final Runnable task ) + { + myTaskInvocationStrategy.runTask( task ); + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/TaskInvocationStrategy.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/TaskInvocationStrategy.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/local/TaskInvocationStrategy.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,52 @@ +package org.skycastle.language.local; + +import javax.swing.*; + +/** + * @author Hans Haggstrom + */ +public enum TaskInvocationStrategy +{ + + /** + * Invoke tasks directly. Useful for unit tests, but not recommended for real systems, as it blocks until all task handling is done. + */ + DIRECT( false ), + + /** + * Invokes tasks later in the swing thread. This allows a single threaded model where the thread just runs tasks one after eaach other. + */ + INVOKE_LATER_IN_SWING_THREAD( true ); + + //====================================================================== + // Private Fields + + private final boolean myRunInSwingThread; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + TaskInvocationStrategy( final boolean runInSwingThread ) + { + myRunInSwingThread = runInSwingThread; + } + + //---------------------------------------------------------------------- + // Other Public Methods + + public void runTask( final Runnable task ) + { + if ( myRunInSwingThread ) + { + SwingUtilities.invokeLater( task ); + } + else + { + task.run(); + } + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/BasePort.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/BasePort.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/BasePort.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,168 @@ +package org.skycastle.language.port; + +import org.skycastle.language.Block; +import org.skycastle.language.LanguageService; +import org.skycastle.util.ParameterChecker; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Hans Haggstrom + */ +public abstract class BasePort + implements Port +{ + + //====================================================================== + // Private Fields + + private final String myIdentifier; + private final PortType myType; + private final PortDirection myDirection; + + private final Set<PortReference> myTargetPorts = new HashSet<PortReference>(); + private final Set<PortReference> mySourcePorts = new HashSet<PortReference>(); + + private Block myHostBlock = null; + private PortReference myReference = null; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Port Implementation + + public final String getIdentifier() + { + return myIdentifier; + } + + public final PortType getType() + { + return myType; + } + + public final PortDirection getDirection() + { + return myDirection; + } + + public final PortReference getReference() + { + if ( myHostBlock == null ) + { + throw new IllegalStateException( "Can not get a reference when the host block has not been defined." ); + } + + if ( myReference == null ) + { + myReference = new PortReferenceImpl( myHostBlock.getReference(), myIdentifier ); + } + + return myReference; + } + + public final void addConnectionTo( final PortReference portReference ) + throws ConnectionException + { + ParameterChecker.checkNotNull( portReference, "portReference" ); + + checkOutgoingConnection( portReference ); + + myTargetPorts.add( portReference ); + + final BasePort port = (BasePort) portReference.getPort( true ); + port.addConnectionFrom( getReference() ); + } + + //---------------------------------------------------------------------- + // Other Public Methods + + public final Block getHostBlock() + { + return myHostBlock; + } + + public final void setHostBlock( final Block hostBlock ) + { + myHostBlock = hostBlock; + } + + //====================================================================== + // Protected Methods + + //---------------------------------------------------------------------- + // Protected Constructors + + protected BasePort( final String identifier, final PortType type, final PortDirection direction ) + { + ParameterChecker.checkIsIdentifier( identifier, "identifier" ); + ParameterChecker.checkNotNull( type, "type" ); + ParameterChecker.checkNotNull( direction, "direction" ); + + myIdentifier = identifier; + myType = type; + myDirection = direction; + } + + protected final Set<PortReference> getTargetPorts() + { + return Collections.unmodifiableSet( myTargetPorts ); + } + + protected final Set<PortReference> getSourcePorts() + { + return Collections.unmodifiableSet( mySourcePorts ); + } + + protected final LanguageService getLanguageService() + { + return getHostBlock().getLanguageService(); + } + + //====================================================================== + // Private Methods + + private void addConnectionFrom( final PortReference reference ) + throws ConnectionException + { + ParameterChecker.checkNotNull( reference, "reference" ); + + checkIncomingConnection( reference ); + + mySourcePorts.add( reference ); + } + + private void checkOutgoingConnection( final PortReference portReference ) + throws ConnectionException + { + if ( !myDirection.supportsOutgoingConnections() ) + { + throw new ConnectionException( getReference(), portReference, "Outgoing connections not supported" ); + } + + final PortType targetType = portReference.getPort( false ).getType(); + if ( !getType().canConnectTo( targetType ) ) + { + throw new ConnectionException( getReference(), + portReference, + "Can not connect from port with type '" + getType() + "' to a port with type '" + targetType + "'." ); + } + + // TODO: Check access rights + } + + private void checkIncomingConnection( final PortReference reference ) + throws ConnectionException + { + if ( !myDirection.supportsIncomingConnections() ) + { + throw new ConnectionException( reference, getReference(), "Incoming connections not supported" ); + } + + // TODO: Check access rights + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/ConnectionException.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/ConnectionException.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/ConnectionException.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,74 @@ +package org.skycastle.language.port; + +/** + * An exception caused by a problem to create a connection. + * + * @author Hans Haggstrom + */ +public final class ConnectionException + extends Exception +{ + + //====================================================================== + // Private Fields + + private final PortReference mySource; + private final PortReference myTarget; + private final String myReason; + + //====================================================================== + // Private Constants + + private static final long serialVersionUID = 1L; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public ConnectionException( final PortReference source, final PortReference target, final String reason ) + { + super( composeMessage( source, target, reason ) ); + + mySource = source; + myTarget = target; + myReason = reason; + } + + public ConnectionException( final PortReference source, final PortReference target, final String reason, final Throwable cause ) + { + super( composeMessage( source, target, reason ) + ": " + cause, cause ); + + mySource = source; + myTarget = target; + myReason = reason; + } + + //---------------------------------------------------------------------- + // Other Public Methods + + public PortReference getSource() + { + return mySource; + } + + public PortReference getTarget() + { + return myTarget; + } + + public String getReason() + { + return myReason; + } + + //====================================================================== + // Private Methods + + private static String composeMessage( final PortReference source, final PortReference target, final String reason ) + { + return "Could not create a connection from port '" + source + "' to port '" + target + "': " + reason; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/Port.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/Port.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/Port.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,49 @@ +package org.skycastle.language.port; + +import org.skycastle.language.Block; + + +/** + * Some kind of connection on a {@link Block}. + * + * @author Hans Haggstrom + */ +public interface Port +{ + /** + * @return a name for this port. Conforms to java identifier syntax. + */ + String getIdentifier(); + + /** + * @return description of what kind of type this port is. Ports can only be connected + * with ports that have a compatibel type. + */ + PortType getType(); + + /** + * @return wether this port accepts incoming, outgoing, or both types of connections. + */ + PortDirection getDirection(); + + /** + * @return a reference to this port that can be kept in other {@link Block}s + */ + PortReference getReference(); + + /** + * Create a connection from this port to the specified target port. + * + * @param portReference a reference to the {@link Port} to connect to. + */ + void addConnectionTo( final PortReference portReference ) + throws ConnectionException; + + /** + * Sets the host {@link Block}. Called automatically when a {@link Port} is added to a {@link Block}. + * Before this is called, a reference to the {@link Port} can not be obtained. + * + * @param hostBlock the {@link Block} that contains this {@link Port}. + */ + void setHostBlock( Block hostBlock ); +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortDirection.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortDirection.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortDirection.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,49 @@ +package org.skycastle.language.port; + +/** + * @author Hans Haggstrom + */ +public enum PortDirection +{ + + INCOMING( true, false ), + + OUTGOING( false, true ), + + /** + * A port that can be connected to both in and outgoing ports of matching type. + */ + BIDIRECTIONAL( true, true ); + + //====================================================================== + // Private Fields + + private final boolean myOutgoingOk; + private final boolean myIncomingOk; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + PortDirection( final boolean incomingOk, final boolean outgoingOk ) + { + myIncomingOk = incomingOk; + myOutgoingOk = outgoingOk; + } + + //---------------------------------------------------------------------- + // Other Public Methods + + public boolean supportsOutgoingConnections() + { + return myOutgoingOk; + } + + public boolean supportsIncomingConnections() + { + return myIncomingOk; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReference.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReference.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReference.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,17 @@ +package org.skycastle.language.port; + +import java.io.Serializable; + +/** + * @author Hans Haggstrom + */ +public interface PortReference + extends Serializable +{ + /** + * @param forModification true if the retrieved {@link Port} will be modified, false if not. + * + * @return the {@link Port} that this {@link PortReference} refers to. + */ + Port getPort( final boolean forModification ); +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReferenceImpl.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReferenceImpl.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortReferenceImpl.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,61 @@ +package org.skycastle.language.port; + +import org.skycastle.language.Block; +import org.skycastle.language.BlockReference; +import org.skycastle.util.ParameterChecker; + +/** + * @author Hans Haggstrom + */ +public final class PortReferenceImpl + implements PortReference +{ + + //====================================================================== + // Private Fields + + private final BlockReference myBlockReference; + private final String myPortName; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public PortReferenceImpl( final BlockReference blockReference, final String portName ) + { + ParameterChecker.checkNotNull( blockReference, "blockReference" ); + ParameterChecker.checkIsIdentifier( portName, "portName" ); + + myBlockReference = blockReference; + myPortName = portName; + } + + //---------------------------------------------------------------------- + // Other Public Methods + + public Port getPort( boolean forWriting ) + { + final Block block = myBlockReference.getBlock( forWriting ); + if ( block != null ) + { + return block.getPort( myPortName ); + } + else + { + return null; + } + } + + public BlockReference getBlockReference() + { + return myBlockReference; + } + + public String getPortName() + { + return myPortName; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortType.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortType.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/PortType.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,20 @@ +package org.skycastle.language.port; + +/** + * Metadata for some type of {@link Port}. + * <p/> + * Only ports with compatible metadta can be connected. + * + * @author Hans Haggstrom + */ +public interface PortType +{ + + /** + * @param portType other type to test connection capability to. + * + * @return true if an output {@link Port} of this type can be connected to an input port of the specified other type. + */ + boolean canConnectTo( PortType portType ); + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroup.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroup.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroup.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,10 @@ +package org.skycastle.language.port.group; + +/** + * A group of related ports. + * + * @author Hans Haggstrom + */ +public interface PortGroup +{ +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroupType.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroupType.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/group/PortGroupType.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,11 @@ +package org.skycastle.language.port.group; + +/** + * Type metadata for a {@link PortGroup}. + * + * @author Hans Haggstrom + */ +public interface PortGroupType +{ + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/AbstractSignalType.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/AbstractSignalType.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/AbstractSignalType.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,35 @@ +package org.skycastle.language.port.signal; + +/** + * Provides a generic equals and hashcode method, that checks equality of class type only. + * Override if there are any properties. + * + * @author Hans Haggstrom + */ +public abstract class AbstractSignalType + implements SignalType +{ + + //---------------------------------------------------------------------- + // Caononical Methods + + public boolean equals( final Object o ) + { + if ( this == o ) + { + return true; + } + + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + + return true; + } + + public int hashCode() + { + return getClass().getName().hashCode(); + } +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/IntegerSignalType.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/IntegerSignalType.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/IntegerSignalType.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,13 @@ +package org.skycastle.language.port.signal; + +/** + * A type for integer signals. + * + * @author Hans Haggstrom + */ +public final class IntegerSignalType + extends AbstractSignalType +{ + + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SendSignalTask.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SendSignalTask.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SendSignalTask.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,47 @@ +package org.skycastle.language.port.signal; + +import org.skycastle.language.port.PortReference; +import org.skycastle.util.ParameterChecker; + +import java.io.Serializable; + +/** + * @author Hans Haggstrom + */ +public final class SendSignalTask + implements Runnable +{ + + //====================================================================== + // Private Fields + + private final PortReference myTargetPort; + private final Serializable mySignal; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public SendSignalTask( final PortReference targetPort, final Serializable signal ) + { + ParameterChecker.checkNotNull( targetPort, "targetPort" ); + ParameterChecker.checkNotNull( signal, "signal" ); + + myTargetPort = targetPort; + mySignal = signal; + } + + //---------------------------------------------------------------------- + // Runnable Implementation + + + public void run() + { + SignalPort signalPort = (SignalPort) myTargetPort.getPort( true ); + + signalPort.onSignal( mySignal ); + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPort.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPort.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPort.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,26 @@ +package org.skycastle.language.port.signal; + +import org.skycastle.language.port.Port; + +import java.io.Serializable; + +/** + * A port that sends or recieves signals with a specified type. + * + * @author Hans Haggstrom + */ +public interface SignalPort + extends Port +{ + /** + * @param signal the signal to send from this port. + */ + void sendSignal( Serializable signal ); + + /** + * @return the signal most recently received by this port. + */ + Object getSignal(); + + void onSignal( Serializable signal ); +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortImpl.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortImpl.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortImpl.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,55 @@ +package org.skycastle.language.port.signal; + +import org.skycastle.language.port.BasePort; +import org.skycastle.language.port.PortDirection; +import org.skycastle.language.port.PortReference; + +import java.io.Serializable; + +/** + * @author Hans Haggstrom + */ +public final class SignalPortImpl + extends BasePort + implements SignalPort +{ + + //====================================================================== + // Private Fields + + private Serializable mySignal = null; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public SignalPortImpl( final String identifier, final SignalType signalType, final PortDirection direction ) + { + super( identifier, new SignalPortType( signalType ), direction ); + } + + //---------------------------------------------------------------------- + // SignalPort Implementation + + public void sendSignal( Serializable signal ) + { + for ( PortReference targetPort : getTargetPorts() ) + { + getLanguageService().runTask( new SendSignalTask( targetPort, signal ) ); + } + } + + + public Serializable getSignal() + { + return mySignal; + } + + public void onSignal( Serializable signal ) + { + mySignal = signal; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortType.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortType.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalPortType.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,60 @@ +package org.skycastle.language.port.signal; + +import org.skycastle.language.port.PortType; +import org.skycastle.util.ParameterChecker; + +/** + * The type of ports that receive or send signals. + * + * @author Hans Haggstrom + */ +public final class SignalPortType + implements PortType +{ + + //====================================================================== + // Private Fields + + private final SignalType mySignalType; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + public SignalPortType( final SignalType signalType ) + { + ParameterChecker.checkNotNull( signalType, "signalType" ); + + mySignalType = signalType; + } + + //---------------------------------------------------------------------- + // PortType Implementation + + public boolean canConnectTo( final PortType portType ) + { + ParameterChecker.checkNotNull( portType, "portType" ); + + if ( portType instanceof SignalPortType ) + { + SignalPortType otherPortType = (SignalPortType) portType; + + return getSignalType().equals( otherPortType.getSignalType() ); + } + else + { + return false; + } + } + + //---------------------------------------------------------------------- + // Other Public Methods + + public SignalType getSignalType() + { + return mySignalType; + } + +} Added: trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalType.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalType.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/language/port/signal/SignalType.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,13 @@ +package org.skycastle.language.port.signal; + +/** + * A description of the type structure of a signal. + * <p/> + * Should implement equals so that it is true for equivalent {@link SignalType}s. + * + * @author Hans Haggstrom + */ +public interface SignalType +{ + +} Modified: trunk/skycastle/modules/core/src/test/java/org/skycastle/language/LanguageTest.java =================================================================== --- trunk/skycastle/modules/core/src/test/java/org/skycastle/language/LanguageTest.java 2008-04-30 12:49:30 UTC (rev 502) +++ trunk/skycastle/modules/core/src/test/java/org/skycastle/language/LanguageTest.java 2008-05-03 09:34:11 UTC (rev 503) @@ -1,6 +1,11 @@ package org.skycastle.language; import junit.framework.TestCase; +import org.skycastle.language.local.LocalLanguageService; +import org.skycastle.language.local.TaskInvocationStrategy; +import org.skycastle.language.port.PortDirection; +import org.skycastle.language.port.signal.IntegerSignalType; +import org.skycastle.language.port.signal.SignalPortImpl; /** * @author Hans Haggstrom @@ -9,11 +14,30 @@ extends TestCase { - public void testPropertyReferenceExpression() + //---------------------------------------------------------------------- + // Test Methods + + public void testCreateBlock() throws Exception { + final LanguageService languageService = new LocalLanguageService( TaskInvocationStrategy.DIRECT ); + final Block blockA = languageService.createBlock(); + final Block blockB = languageService.createBlock(); + + final SignalPortImpl fooPort = new SignalPortImpl( "foo", new IntegerSignalType(), PortDirection.OUTGOING ); + final SignalPortImpl barPort = new SignalPortImpl( "bar", new IntegerSignalType(), PortDirection.INCOMING ); + + blockB.addPort( barPort ); + blockA.addPort( fooPort ); + + blockA.getPort( "foo" ).addConnectionTo( blockB.getPort( "bar" ).getReference() ); + + fooPort.sendSignal( 5 ); + + //noinspection AssertEqualsBetweenInconvertibleTypes + assertEquals( 5, barPort.getSignal() ); + } - } Modified: trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/AbstractCompilableComponent.java =================================================================== --- trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/AbstractCompilableComponent.java 2008-04-30 12:49:30 UTC (rev 502) +++ trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/AbstractCompilableComponent.java 2008-05-03 09:34:11 UTC (rev 503) @@ -149,7 +149,7 @@ { ParameterChecker.checkNotNull( addedInputPort, "addedInputPort" ); ParameterChecker.checkNotAlreadyContained( addedInputPort, myInputPorts, "myInputPorts" ); - checkPortName( addedInputPort.getName() ); + checkPortName( addedInputPort.getIdentifier() ); myInputPorts.add( addedInputPort ); } @@ -166,7 +166,7 @@ { ParameterChecker.checkNotNull( addedOutputPort, "addedOutputPort" ); ParameterChecker.checkNotAlreadyContained( addedOutputPort, myOutputPorts, "myOutputPorts" ); - checkPortName( addedOutputPort.getName() ); + checkPortName( addedOutputPort.getIdentifier() ); myOutputPorts.add( addedOutputPort ); } Modified: trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/PortImpl.java =================================================================== --- trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/PortImpl.java 2008-04-30 12:49:30 UTC (rev 502) +++ trunk/skycastle/modules/texture/src/main/java/org/skycastle/texture/component/PortImpl.java 2008-05-03 09:34:11 UTC (rev 503) @@ -172,7 +172,7 @@ public String toString() { return "PortImpl{" + - "getName()='" + getName() + '\'' + + "getIdentifier()='" + getName() + '\'' + ", getType()=" + getType() + ", getComponent()=" + getComponent() + ", myTargetPorts=" + calculateTargetPortNames() + Modified: trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/Canvas3D.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/Canvas3D.java 2008-04-30 12:49:30 UTC (rev 502) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/Canvas3D.java 2008-05-03 09:34:11 UTC (rev 503) @@ -2,24 +2,17 @@ import com.jme.renderer.Camera; import com.jme.renderer.ColorRGBA; -import com.jme.renderer.Renderer; import com.jme.scene.Spatial; -import com.jme.scene.state.CullState; import com.jme.system.DisplaySystem; import com.jmex.awt.JMECanvas; -import com.jmex.awt.SimpleCanvasImpl; import org.skycastle.opengl.navigationgestures.*; import org.skycastle.util.ParameterChecker; import org.skycastle.util.cursor.CursorChangerImpl; -import org.skycastle.util.fpscounter.FpsCounter; -import javax.swing.*; import java.awt.Canvas; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -45,7 +38,6 @@ private final ColorRGBA myBackgroundColor = new ColorRGBA(); private final Set<NavigationGesture> myNavigationGestures = new HashSet<NavigationGesture>(); private final CursorChangerImpl myCursorChanger = new CursorChangerImpl(); - private final FpsCounter myFpsCounter = new FpsCounter(); private final Set<FrameListener> myFrameListeners = new HashSet<FrameListener>(); private final CameraAccessor myCameraAccessor = new CameraAccessor() @@ -65,7 +57,7 @@ private Spatial my3DNode = null; private Component myView3D = null; private Canvas myCanvas = null; - private MyCanvasRenderer myCanvasRenderer = null; + private CanvasRenderer myCanvasRenderer = null; private float myViewDistance; @@ -94,9 +86,9 @@ private static final int DEFAULT_WIDTH = 800; private static final int DEFAULT_HEIGHT = 600; - private static final int CANVAS_REPAINT_INTERVAL_MS = 10; private static final int DEFAULT_VIEW_DISTANCE = 100000; private static final float DEFAULT_FIELD_OF_VIEW_DEGREES = 45; + private static final float MAX_BYTE = 255.0f; //====================================================================== // Public Methods @@ -141,6 +133,11 @@ //---------------------------------------------------------------------- // Other Public Methods + boolean hasFrameListeners() + { + return !myFrameListeners.isEmpty(); + } + /** * @return true if the 3D renderer for the canvas has been created. */ @@ -334,10 +331,10 @@ */ public void setBackgroundColor( final Color color ) { - myBackgroundColor.set( color.getRed() / 255.0f, - color.getGreen() / 255.0f, - color.getBlue() / 255.0f, - color.getAlpha() / 255.0f ); + myBackgroundColor.set( color.getRed() / MAX_BYTE, + color.getGreen() / MAX_BYTE, + color.getBlue() / MAX_BYTE, + color.getAlpha() / MAX_BYTE ); } @@ -371,6 +368,32 @@ myResizeHandler = resizeHandler; } + void notifyOnFrame( final double secondsSinceLastFrame ) + { + for ( FrameListener frameListener : myFrameListeners ) + { + frameListener.onFrame( secondsSinceLastFrame ); + } + } + + + void runInitializers( final DisplaySystem displaySystem ) + { + myInitialized = true; + + for ( final CanvasInitializer initializer : myInitializers ) + { + initializer.initialize( this, displaySystem ); + } + + myInitializers.clear(); + } + + void onScreenResized( final float canvasWidth, final float canvasHeight, final float aspectRatio, final Camera camera ) + { + myResizeHandler.onScreenResized( canvasWidth, canvasHeight, aspectRatio, camera ); + } + //====================================================================== // Private Methods @@ -404,7 +427,7 @@ final JMECanvas jmeCanvas = ( (JMECanvas) myCanvas ); // Set the renderer that renders the canvas contents - myCanvasRenderer = new MyCanvasRenderer( width, height, my3DNode, myCanvas ); + myCanvasRenderer = new CanvasRenderer( this, width, height, my3DNode, myCanvas ); jmeCanvas.setImplementor( myCanvasRenderer ); // Add navigation gesture listeners to the created 3D canvas @@ -414,264 +437,15 @@ } // We need to repaint the component to see the updates, so we create a repaint calling thread - final Thread repaintThread = new Thread( new MyRepainter( myCanvas ) ); + final Thread repaintThread = new Thread( new CanvasRepainter( myCanvas ) ); repaintThread.setDaemon( true ); // Do not keep the JVM alive if only the repaint thread is left running repaintThread.start(); return myCanvas; } - - private void runInitializers( final DisplaySystem displaySystem ) + public ColorRGBA getBackgroundColor() { - myInitialized = true; - - for ( final CanvasInitializer initializer : myInitializers ) - { - initializer.initialize( this, displaySystem ); - } - - myInitializers.clear(); + return myBackgroundColor; } - - //====================================================================== - // Inner Classes - - /** - * A thread for repainting a swing canvas regularily to make it update the 3D view. - */ - private static final class MyRepainter - implements Runnable - { - - //====================================================================== - // Private Fields - - private final Canvas myCanvas; - - //====================================================================== - // Public Methods - - //---------------------------------------------------------------------- - // Constructors - - public MyRepainter( final Canvas canvas ) - { - myCanvas = canvas; - } - - //---------------------------------------------------------------------- - // Runnable Implementation - - public void run() - { - while ( true ) - { - myCanvas.repaint(); - - // TODO: Instead of sleeping a fixed amount, we could try to sleep some amount to maintain some maximum FPS. - try - { - Thread.sleep( CANVAS_REPAINT_INTERVAL_MS ); - } - catch ( InterruptedException e ) - { - // Ignore - } - } - } - - } - - /** - * A renderer that renders a 3D object in a 3D Canvas. - */ - private final class MyCanvasRenderer - extends SimpleCanvasImpl - { - - //====================================================================== - // Private Fields - - private final Canvas myCanvas; - - private final Runnable myFrameListenerUpdater = new Runnable() - { - - public void run() - { - final double secondsSinceLastFrame = myFpsCounter.getSecondsBetweenFrames(); - for ( FrameListener frameListener : myFrameListeners ) - { - frameListener.onFrame( secondsSinceLastFrame ); - } - } - - }; - - private Spatial myCanvasRootNode; - private boolean myAspectRatioNeedsCorrecting = true; - - //====================================================================== - // Public Methods - - //---------------------------------------------------------------------- - // Constructors - - /** - * Creates a new renderer that renders the specified spatial in a 3D canvas. - * - * @param width initial size of the canvas. Should be larger than 0. - * @param height initial size of the canvas. Should be larger than 0. - * @param canvasRootNode the 3D object to render. May be null, in which case nothing is rendered - * (black area) - * @param canvas the canvas we are rendering to. Needed for listening to resize events. - */ - public MyCanvasRenderer( final int width, - final int height, - final Spatial canvasRootNode, - final Canvas canvas ) - { - super( width, height ); - - ParameterChecker.checkPositiveNonZeroInteger( width, "width" ); - ParameterChecker.checkPositiveNonZeroInteger( height, "height" ); - ParameterChecker.checkNotNull( canvas, "canvas" ); - - myCanvasRootNode = canvasRootNode; - myCanvas = canvas; - - // When the component is resized, adjust the size of the 3D viewport too. - myCanvas.addComponentListener( new ComponentAdapter() - { - - public void componentResized( ComponentEvent ce ) - { - resizeCanvas( myCanvas.getWidth(), myCanvas.getHeight() ); - myAspectRatioNeedsCorrecting = true; - } - - } ); - } - - //---------------------------------------------------------------------- - // Other Public Methods - - /** - * @return the number of frames rendered per second, or a negative value if the canvas has not yet - * been rendered. - */ - public double getFramesPerSecond() - { - return myFpsCounter.getFramesPerSecond(); - } - - - /** - * @return number of seconds between the previous frame and the frame before that, or a negative value - * if the canvas has not yet been rendered. - */ - public double getSecondsBetweenFrames() - { - return myFpsCounter.getSecondsBetweenFrames(); - } - - - /** - * @param canvasRootNode the spatial to render with this CanvasRenderer. May be null, in which case - * nothing is rendered (black area) - */ - public void setCanvasRootNode( final Spatial canvasRootNode ) - { - if ( rootNode != null && myCanvasRootNode != null ) - { - rootNode.detachChild( myCanvasRootNode ); - } - - myCanvasRootNode = canvasRootNode; - - if ( rootNode != null && myCanvasRootNode != null ) - { - rootNode.attachChild( myCanvasRootNode ); - } - } - - - @Override - public void simpleSetup() - { - // Remove the back faces when rendering - // REFACTOR: Actually the terrain is backwards at the moment, the camera is 'under' it. Flip it around at some point. - final CullState cullState = DisplaySystem.getDisplaySystem().getRenderer().createCullState(); - cullState.setCullMode( CullState.CS_FRONT ); - rootNode.setRenderState( cullState ); - - - if ( myCanvasRootNode != null ) - { - rootNode.attachChild( myCanvasRootNode ); - } - - getCamera().setFrustumFar( myViewDistance ); - - // Set the background color - getRenderer().setBackgroundColor( myBackgroundColor ); - } - - - @Override - public void simpleUpdate() - { - myFpsCounter.onFrame(); - - if ( !myFrameListeners.isEmpty() ) - { - SwingUtilities.invokeLater( myFrameListenerUpdater ); - } - - // TODO: Is this the correct display system? - runInitializers( DisplaySystem.getDisplaySystem() ); - } - - - @Override - public void simpleRender() - { - // Setup aspect ratio for camera on the first frame (the camera is not created before the rendering starts) - if ( myAspectRatioNeedsCorrecting ) - { - final Renderer canvasRenderer = getRenderer(); - if ( canvasRenderer != null ) - { - // Get size on screen - final float canvasHeight = canvasRenderer.getHeight(); - final float canvasWidth = canvasRenderer.getWidth(); - - // Calculate aspect ratio - float aspectRatio = 1; - if ( canvasHeight > 0 ) - { - aspectRatio = canvasWidth / canvasHeight; - } - - final Camera camera = getCamera(); - - myResizeHandler.onScreenResized( canvasWidth, - canvasHeight, - aspectRatio, - camera ); - -/* - // TODO: Not sure if this is needed? - camera.update(); -*/ - } - - - myAspectRatioNeedsCorrecting = false; - } - } - - } - } Added: trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRenderer.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRenderer.java (rev 0) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRenderer.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,213 @@ +package org.skycastle.opengl; + +import com.jme.renderer.Camera; +import com.jme.renderer.Renderer; +import com.jme.scene.Spatial; +import com.jme.scene.state.CullState; +import com.jme.system.DisplaySystem; +import com.jmex.awt.SimpleCanvasImpl; +import org.skycastle.util.ParameterChecker; +import org.skycastle.util.fpscounter.FpsCounter; + +import javax.swing.*; +import java.awt.Canvas; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; + +/** + * A renderer that renders a 3D object in a 3D Canvas. + */ +final class CanvasRenderer + extends SimpleCanvasImpl +{ + + //====================================================================== + // Private Fields + + private final FpsCounter myFpsCounter = new FpsCounter(); + private final Canvas myCanvas; + + private final Runnable myFrameListenerUpdater = new Runnable() + { + + public void run() + { + final double secondsSinceLastFrame = myFpsCounter.getSecondsBetweenFrames(); + myCanvas3D.notifyOnFrame( secondsSinceLastFrame ); + } + + }; + + private Spatial myCanvasRootNode; + private boolean myAspectRatioNeedsCorrecting = true; + private Canvas3D myCanvas3D; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + /** + * Creates a new renderer that renders the specified spatial in a 3D canvas. + * + * @param width initial size of the canvas. Should be larger than 0. + * @param height initial size of the canvas. Should be larger than 0. + * @param canvasRootNode the 3D object to render. May be null, in which case nothing is rendered + * (black area) + * @param canvas the canvas we are rendering to. Needed for listening to resize events. + */ + CanvasRenderer( final Canvas3D canvas3D, final int width, + final int height, + final Spatial canvasRootNode, + final Canvas canvas ) + { + super( width, height ); + myCanvas3D = canvas3D; + + ParameterChecker.checkPositiveNonZeroInteger( width, "width" ); + ParameterChecker.checkPositiveNonZeroInteger( height, "height" ); + ParameterChecker.checkNotNull( canvas, "canvas" ); + + myCanvasRootNode = canvasRootNode; + myCanvas = canvas; + + // When the component is resized, adjust the size of the 3D viewport too. + myCanvas.addComponentListener( new ComponentAdapter() + { + + public void componentResized( ComponentEvent ce ) + { + resizeCanvas( myCanvas.getWidth(), myCanvas.getHeight() ); + myAspectRatioNeedsCorrecting = true; + } + + } ); + } + + //---------------------------------------------------------------------- + // Other Public Methods + + /** + * @return the number of frames rendered per second, or a negative value if the canvas has not yet + * been rendered. + */ + public double getFramesPerSecond() + { + return myFpsCounter.getFramesPerSecond(); + } + + + /** + * @return number of seconds between the previous frame and the frame before that, or a negative value + * if the canvas has not yet been rendered. + */ + public double getSecondsBetweenFrames() + { + return myFpsCounter.getSecondsBetweenFrames(); + } + + + /** + * @param canvasRootNode the spatial to render with this CanvasRenderer. May be null, in which case + * nothing is rendered (background colored area) + */ + public void setCanvasRootNode( final Spatial canvasRootNode ) + { + if ( rootNode != null && myCanvasRootNode != null ) + { + rootNode.detachChild( myCanvasRootNode ); + } + + myCanvasRootNode = canvasRootNode; + + if ( rootNode != null && myCanvasRootNode != null ) + { + rootNode.attachChild( myCanvasRootNode ); + } + } + + + @Override + public void simpleSetup() + { + // Remove the back faces when rendering + // REFACTOR: Actually the terrain is backwards at the moment, the camera is 'under' it. Flip it around at some point. + final CullState cullState = DisplaySystem.getDisplaySystem().getRenderer().createCullState(); + cullState.setCullMode( CullState.CS_FRONT ); + rootNode.setRenderState( cullState ); + + + if ( myCanvasRootNode != null ) + { + rootNode.attachChild( myCanvasRootNode ); + } + + getCamera().setFrustumFar( myCanvas3D.getViewDistance() ); + + // Set the background color + getRenderer().setBackgroundColor( myCanvas3D.getBackgroundColor() ); + } + + + @Override + public void simpleUpdate() + { + myFpsCounter.onFrame(); + + if ( myCanvas3D.hasFrameListeners() ) + { + SwingUtilities.invokeLater( myFrameListenerUpdater ); + } + + // TODO: Is this the correct display system? + myCanvas3D.runInitializers( DisplaySystem.getDisplaySystem() ); + } + + + @Override + public void simpleRender() + { + // Setup aspect ratio for camera on the first frame (the camera is not created before the rendering starts) + if ( myAspectRatioNeedsCorrecting ) + { + handleScreenResize(); + + myAspectRatioNeedsCorrecting = false; + } + } + + //====================================================================== + // Private Methods + + private void handleScreenResize() + { + final Renderer canvasRenderer = getRenderer(); + if ( canvasRenderer != null ) + { + // Get size on screen + final float canvasHeight = canvasRenderer.getHeight(); + final float canvasWidth = canvasRenderer.getWidth(); + + // Calculate aspect ratio + float aspectRatio = 1; + if ( canvasHeight > 0 ) + { + aspectRatio = canvasWidth / canvasHeight; + } + + final Camera camera = getCamera(); + + myCanvas3D.onScreenResized( canvasWidth, + canvasHeight, + aspectRatio, + camera ); + +/* + // TODO: Not sure if this is needed? + camera.update(); +*/ + } + } + +} Added: trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRepainter.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRepainter.java (rev 0) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/opengl/CanvasRepainter.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,54 @@ +package org.skycastle.opengl; + +import java.awt.Canvas; + +/** + * A thread for repainting a swing canvas regularily to make it update the 3D view. + */ +final class CanvasRepainter + implements Runnable +{ + + //====================================================================== + // Private Fields + + private final Canvas myCanvas; + + //====================================================================== + // Private Constants + + private static final int CANVAS_REPAINT_INTERVAL_MS = 10; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + + CanvasRepainter( final Canvas canvas ) + { + myCanvas = canvas; + } + + //---------------------------------------------------------------------- + // Runnable Implementation + + public void run() + { + while ( true ) + { + myCanvas.repaint(); + + // TODO: Instead of sleeping a fixed amount, we could try to sleep some amount to maintain some maximum FPS. + try + { + Thread.sleep( CANVAS_REPAINT_INTERVAL_MS ); + } + catch ( InterruptedException e ) + { + // Ignore + } + } + } + +} Added: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/CanvasToTextureBufferedScreen.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/CanvasToTextureBufferedScreen.java (rev 0) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/CanvasToTextureBufferedScreen.java 2008-05-03 09:34:11 UTC (rev 503) @@ -0,0 +1,31 @@ +package org.skycastle.sketch; + +import com.jme.scene.Spatial; +import com.jme.system.DisplaySystem; + +/** + * Creates a texture with the current screen content by taking a snapshot of the rendering canvas buffer, + * and setting it to a texture. + * <p/> + * Should work for graphics cards that don't have render to texture support + * + * @author Hans Haggstrom + */ +public final class CanvasToTextureBufferedScreen + implements BufferedScreen +{ + + //---------------------------------------------------------------------- + // BufferedScreen Implementation + + public void renderElement( final Spatial spatial ) + { + throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + } + + public Spatial get3DView( final DisplaySystem displaySystem ) + { + throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + } + +} Modified: trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchRenderer.java =================================================================== --- trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchRenderer.java 2008-04-30 12:49:30 UTC (rev 502) +++ trunk/skycastle/modules/ui/src/main/java/org/skycastle/sketch/SketchRenderer.java 2008-05-03 09:34:11 UTC (rev 503) @@ -22,7 +22,7 @@ // Private Fields private final CollectionListener<GroupElement> mySketchListener = createSketchListener(); - private final BufferedScreen myBufferedScreen = new TextureBufferedScreen(); + private final BufferedScreen myBufferedScreen = new DummyBufferedScreen(); private Sketch mySketch = null; private Spatial myRenderer = null; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.