diff --git a/TODO.md b/TODO.md index bd93217f..b686e8b3 100644 --- a/TODO.md +++ b/TODO.md @@ -2,64 +2,12 @@ # 1 * new InputComponent interacting with MapComponent - * panning - * zooming - * - * Command-Queue (->) - * add commands to queue (/) - * A Command is a class with a type and can check by itself if its condition is met or not. (/) - * Commands are Singletons or at least reusable (/) - * Commands have to be registered/activated in the central InputManager (/) - * execute commands in update by InputComponents (/) - * after execution, remove command from queue (after Input has been processed; clear queue) (/) - * Commands: (<-) - * - * - * There are two types of commands: Instant and Continuous - * Instant/Sequential Commands (e.g. MouseClick) - * Sequence (amount of repetitions, delay between repetitions is counted by the command ITSELF -> stored in central event-queue and popped by the command itself after update delta time) - * Instant Commands are executed immediately after they are added to the queue - * Instant Commands are removed from the queue after they are executed - * Mouse Commands: - * Left ( Pixel position ) - * Right ( Pixel position ) - * Center ( Pixel position ) - * Double Click ( Pixel position ) - * Mouse Wheel ( Pixel position, Wheel delta ) - * Keyboard Commands: - * Key Press ( Key ) - * Keys can be pressed multiple times - * Key is pressed after key-release - * Continuous Commands (e.g. MouseDrag) - * Continuous Commands are executed every update cycle as long as they are in the queue - * Continuous Commands are removed from the queue after they are released - * Mouse Commands: - * Drag Left ( Pixel position, Drag vector ) - * Drag Right ( Pixel position, Drag vector ) - * Drag Center ( Pixel position, Drag vector ) - * Hold Left ( Pixel position, Drag vector ) - * Hold Right ( Pixel position, Drag vector ) - * Hold Center ( Pixel position, Drag vector ) - * Mouse Click - * Left ( Pixel position ) - * Right ( Pixel position ) - * Drag Left ( Pixel position, Drag vector ) - * Drag Right ( Pixel position, Drag vector ) - * Mouse Wheel ( Pixel position, Wheel delta ) - * - * + * panning (/) + * zooming (<-) * - * PhysicsCore holds position in TransformComponent or Object - * Transform is modified when moved! - - * RenderPipeline Renders a SceneGraph ... our MergeableLayer is kind of a SceneGraph - * a RenderableComponent could be a node in the SceneGraph - * so other RenderableComponents could be added to the RenderableComponent Node - * this way we could implement a "graphical" scene graph - * the both interfaces: ParentPropagatableDirtyState + ChildPropagatableDirtyState will be put into the graph-node concept! -* -* + * NULLImplementations -> Optionals ... +* * dynamic changeable render properties! * optimize Layers so that they must not be reinstantiated every time on update. Reuse layers and remove/extend entities on update * diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/Updatable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/IsUpdatable.java similarity index 73% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/Updatable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/IsUpdatable.java index a16d96ad..cbef3a78 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/Updatable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/IsUpdatable.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine; -public interface Updatable { +public interface IsUpdatable { void update(final long elapsedNanoTime); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/CanvasBufferSwapCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/SwappableCanvasBuffer.java similarity index 96% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/CanvasBufferSwapCommand.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/SwappableCanvasBuffer.java index 542e67b6..5a9bd52b 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/CanvasBufferSwapCommand.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/SwappableCanvasBuffer.java @@ -10,7 +10,7 @@ import java.nio.IntBuffer; -public class CanvasBufferSwapCommand { +public class SwappableCanvasBuffer { @NonNull private final Canvas canvas; @@ -28,7 +28,7 @@ public class CanvasBufferSwapCommand { public int lastBackBufferIndex = -1; - public CanvasBufferSwapCommand( + public SwappableCanvasBuffer( @NonNull final Canvas canvas, @NonNull final RendererProperties rendererProperties, @NonNull final ScreenComposer screenComposer diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/TacViewer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/TacViewer.java index be7bfbbc..297a0bd5 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/TacViewer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/TacViewer.java @@ -1,9 +1,11 @@ package com.recom.tacview.engine; import com.recom.tacview.engine.graphics.ScreenComposer; -import com.recom.tacview.engine.input.GenericInputEventListener; +import com.recom.tacview.engine.input.GenericFXInputEventListener; import com.recom.tacview.engine.input.InputManager; -import com.recom.tacview.engine.input.command.mapper.MouseClickCommandMapper; +import com.recom.tacview.engine.input.mapper.keyboard.JavaFxKeyboardCommandMapper; +import com.recom.tacview.engine.input.mapper.mousebutton.JavaFxMouseButtonCommandMapper; +import com.recom.tacview.engine.input.mapper.scroll.JavaFxMouseScrollCommandMapper; import com.recom.tacview.engine.module.EngineModule; import com.recom.tacview.property.RendererProperties; import com.recom.tacview.property.TickProperties; @@ -31,13 +33,13 @@ public class TacViewer extends Canvas { @NonNull private final EngineModule engineModule; @NonNull - private final GenericInputEventListener genericInputEventListener; + private final GenericFXInputEventListener genericFXInputEventListener; @NonNull private final InputManager inputManager; @NonNull - private final CanvasBufferSwapCommand canvasBuffer; + private final SwappableCanvasBuffer canvasBuffer; @NonNull private final AnimationTimer animationTimerLoop; @@ -53,7 +55,7 @@ public TacViewer( @NonNull final ProfilerProvider profilerProvider, @NonNull final ScreenComposer screenComposer, @NonNull final EngineModule engineModule, - @NonNull final GenericInputEventListener genericInputEventListener, + @NonNull final GenericFXInputEventListener genericFXInputEventListener, @NonNull final InputManager inputManager ) { super(rendererProperties.getWidth(), rendererProperties.getHeight()); @@ -61,10 +63,12 @@ public TacViewer( this.tickProperties = tickProperties; this.screenComposer = screenComposer; this.engineModule = engineModule; - this.genericInputEventListener = genericInputEventListener; + this.genericFXInputEventListener = genericFXInputEventListener; this.inputManager = inputManager; - this.canvasBuffer = new CanvasBufferSwapCommand(this, rendererProperties, screenComposer); +// this.setScaleX(2); +// this.setScaleY(2); + this.canvasBuffer = new SwappableCanvasBuffer(this, rendererProperties, screenComposer); this.profiler = new TacViewerProfiler(profilerProvider); this.profiler.startProfiling(); @@ -72,9 +76,12 @@ public TacViewer( this.setFocusTraversable(true); this.requestFocus(); - this.setEventHandler(InputEvent.ANY, this.genericInputEventListener); - this.inputManager.registerCommandMapper(new MouseClickCommandMapper()); + // register input event listener + this.setEventHandler(InputEvent.ANY, this.genericFXInputEventListener); + this.inputManager.registerCommandMapper(new JavaFxMouseButtonCommandMapper()); + this.inputManager.registerCommandMapper(new JavaFxMouseScrollCommandMapper()); + this.inputManager.registerCommandMapper(new JavaFxKeyboardCommandMapper()); } @NonNull @@ -111,7 +118,7 @@ private void engineLoop( // HANDLE INPUT final long inputHandlingStart = System.nanoTime(); inputManager.mapInputEventsToCommands(); - engineModule.handleInputCommands(inputManager.getCreatedInputCommands()); + engineModule.handleInputCommands(inputManager.popInputCommands()); inputManager.clearInputQueues(); profiler.inputHandlingNanoTime = System.nanoTime() - inputHandlingStart; diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/commands/CommandTemplate.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/commands/CommandTemplate.java deleted file mode 100644 index 5dafabca..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/commands/CommandTemplate.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.recom.tacview.engine.commands; - -public abstract class CommandTemplate implements Commandable { - - @Override - public abstract void execute(); - -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/commands/Commandable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/commands/Commandable.java deleted file mode 100644 index 5b5dc256..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/commands/Commandable.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.recom.tacview.engine.commands; - -public interface Commandable { - - void execute(); - -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/HandlesInputCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/HandlesInputCommand.java index 579845eb..3277ff7b 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/HandlesInputCommand.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/HandlesInputCommand.java @@ -1,10 +1,10 @@ package com.recom.tacview.engine.entitycomponentsystem.component; -import com.recom.tacview.engine.input.command.IsInputCommand; +import com.recom.tacview.engine.input.command.IsCommand; import lombok.NonNull; public interface HandlesInputCommand { - void handleInputCommand(@NonNull final IsInputCommand inputCommand); + void handleInputCommand(@NonNull final IsCommand inputCommand); } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/InputComponent.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/InputComponent.java index da151e71..6ea26f90 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/InputComponent.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/InputComponent.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.entitycomponentsystem.component; -import com.recom.tacview.engine.input.command.IsInputCommand; +import com.recom.tacview.engine.input.command.IsCommand; import lombok.NonNull; public abstract class InputComponent extends ComponentTemplate implements HandlesInputCommand { @@ -10,6 +10,6 @@ public InputComponent() { } @Override - public abstract void handleInputCommand(@NonNull final IsInputCommand inputCommand); + public abstract void handleInputCommand(@NonNull final IsCommand inputCommand); } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/IsComponent.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/IsComponent.java index 90afac35..e57711bc 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/IsComponent.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/IsComponent.java @@ -1,9 +1,9 @@ package com.recom.tacview.engine.entitycomponentsystem.component; -import com.recom.tacview.engine.Updatable; +import com.recom.tacview.engine.IsUpdatable; import lombok.NonNull; -public interface IsComponent extends BelongsToEntity, HasComponentType, Updatable { +public interface IsComponent extends BelongsToEntity, HasComponentType, IsUpdatable { @NonNull ComponentType componentType(); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/RenderableComponent.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/RenderableComponent.java index 64bddb37..d4a690cb 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/RenderableComponent.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/component/RenderableComponent.java @@ -53,4 +53,5 @@ public void propagateDirtyStateToParent() { public void prepareBuffer() { } + } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/Entity.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/Entity.java index decff3a8..ad092314 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/Entity.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/Entity.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.entitycomponentsystem.entity; -import com.recom.tacview.engine.Updatable; +import com.recom.tacview.engine.IsUpdatable; import com.recom.tacview.engine.entitycomponentsystem.component.ComponentType; import com.recom.tacview.engine.entitycomponentsystem.component.IsComponent; import com.recom.tacview.engine.entitycomponentsystem.environment.IsEnvironment; @@ -29,6 +29,7 @@ public class Entity implements IsEntity { @Override public void addComponent(@NonNull final IsComponent component) { components.add(component); + component.setEntity(this); components.sort(Comparator.comparing(IsComponent::getComponentProcessingOrder)); reIndexComponents(); } @@ -50,6 +51,7 @@ public void reIndexComponents() { @Override public void removeComponent(@NonNull final IsComponent component) { components.remove(component); + component.setEntity(NullEntity.INSTANCE); reIndexComponents(); } @@ -83,7 +85,7 @@ public List getComponents() { @Override public void update(final long elapsedNanoTime) { - for (@NonNull final Updatable component : components) { + for (@NonNull final IsUpdatable component : components) { component.update(elapsedNanoTime); } } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/IsEntity.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/IsEntity.java index 18e421db..1082a06a 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/IsEntity.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/entity/IsEntity.java @@ -1,7 +1,7 @@ package com.recom.tacview.engine.entitycomponentsystem.entity; -import com.recom.tacview.engine.Updatable; +import com.recom.tacview.engine.IsUpdatable; -public interface IsEntity extends BelongsToEnvironment, HasLocatableComponents, Updatable { +public interface IsEntity extends BelongsToEnvironment, HasLocatableComponents, IsUpdatable { } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/environment/IsEnvironment.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/environment/IsEnvironment.java index 621f8a3a..15d04eb5 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/environment/IsEnvironment.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/entitycomponentsystem/environment/IsEnvironment.java @@ -1,13 +1,13 @@ package com.recom.tacview.engine.entitycomponentsystem.environment; -import com.recom.tacview.engine.Updatable; +import com.recom.tacview.engine.IsUpdatable; import com.recom.tacview.engine.graphics.renderpipeline.IsRenderPipeline; import com.recom.tacview.engine.renderer.RenderProvider; import com.recom.tacview.property.RendererProperties; import com.recom.tacview.service.RendererExecutorProvider; import lombok.NonNull; -public interface IsEnvironment extends Updatable, HasManagableEntities { +public interface IsEnvironment extends IsUpdatable, HasManagableEntities { void update(final long elapsedNanoTime); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Bufferable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsBufferable.java similarity index 80% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Bufferable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsBufferable.java index 4918548e..0d2554a9 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Bufferable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsBufferable.java @@ -1,9 +1,9 @@ package com.recom.tacview.engine.graphics; -import com.recom.tacview.engine.renderables.Soilable; +import com.recom.tacview.engine.renderables.IsSoilable; import com.recom.tacview.engine.units.PixelDimension; -public interface Bufferable extends Scanable, Soilable { +public interface IsBufferable extends IsScanable, IsSoilable { PixelDimension getDimension(); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Composable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsComposable.java similarity index 82% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Composable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsComposable.java index 6fc616e3..7bf68745 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Composable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsComposable.java @@ -4,7 +4,7 @@ import com.recom.tacview.engine.renderables.HasPixelBuffer; import lombok.NonNull; -public interface Composable extends HasPixelBuffer { +public interface IsComposable extends HasPixelBuffer { int compose(@NonNull final Environment environment); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Renderable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsRenderable.java similarity index 59% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Renderable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsRenderable.java index f0009bb7..736699d2 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Renderable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsRenderable.java @@ -1,34 +1,34 @@ package com.recom.tacview.engine.graphics; -import com.recom.tacview.engine.renderables.Mergeable; +import com.recom.tacview.engine.renderables.IsMergeable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import lombok.NonNull; -public interface Renderable { +public interface IsRenderable { void render( - @NonNull final Scanable sourceScanable, - @NonNull final Bufferable targetBuffer, + @NonNull final IsScanable sourceScanable, + @NonNull final IsBufferable targetBuffer, final int xOffset, final int yOffset ); void renderMergeable( - @NonNull final Mergeable source, + @NonNull final IsMergeable source, @NonNull final PixelBuffer targetBuffer, final int xOffset, final int yOffset ); void renderMergeable( - @NonNull final Mergeable source, - @NonNull final Bufferable target, + @NonNull final IsMergeable source, + @NonNull final IsBufferable target, final int xOffset, final int yOffset ); void setPixelAt( - @NonNull final Bufferable target, + @NonNull final IsBufferable target, final int x, final int y, final int newPixelValue diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Scanable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsScanable.java similarity index 89% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Scanable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsScanable.java index 4861e03e..e66a1684 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/Scanable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/IsScanable.java @@ -3,7 +3,7 @@ import com.recom.tacview.engine.units.PixelDimension; -public interface Scanable { +public interface IsScanable { PixelDimension getDimension(); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/ScreenComposer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/ScreenComposer.java index b2bc7edb..944f5819 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/ScreenComposer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/ScreenComposer.java @@ -16,7 +16,7 @@ @Slf4j @Component -public class ScreenComposer implements Composable { +public class ScreenComposer implements IsComposable { @NonNull private final ExecutorService renderExecutorService; @@ -39,7 +39,7 @@ public int compose(@NonNull final Environment environment) { } else { pixelRingBuffer.next(); pixelRingBuffer.getPixelBuffer().clearBuffer(); - renderLayerPipelineInParallel(environment.getRenderPipeline()); + renderLayersInParallel(environment.getRenderPipeline()); environment.getRenderPipeline().getLayers().forEach(layer -> { layer.mergeBufferWith(pixelRingBuffer.getPixelBuffer(), 0, 0); layer.dispose(); @@ -51,7 +51,7 @@ public int compose(@NonNull final Environment environment) { } } - private void renderLayerPipelineInParallel(@NonNull final IsRenderPipeline renderPipeline) { + private void renderLayersInParallel(@NonNull final IsRenderPipeline renderPipeline) { final CountDownLatch latch = new CountDownLatch(renderPipeline.getLayers().size()); for (final MergeableComponentLayer mergeableLayer : renderPipeline.getLayers()) { renderExecutorService.execute(() -> { diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/buffer/PixelBuffer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/buffer/PixelBuffer.java index 44f75c96..31c7291a 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/buffer/PixelBuffer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/buffer/PixelBuffer.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.graphics.buffer; -import com.recom.tacview.engine.graphics.Bufferable; +import com.recom.tacview.engine.graphics.IsBufferable; import com.recom.tacview.engine.units.PixelDimension; import lombok.Getter; import lombok.NonNull; @@ -8,7 +8,7 @@ import java.util.Arrays; -public class PixelBuffer implements Bufferable { +public class PixelBuffer implements IsBufferable { @Getter protected PixelDimension dimension; diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/renderpipeline/RenderPipeline.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/renderpipeline/RenderPipeline.java index 2beb6afb..01a8230b 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/renderpipeline/RenderPipeline.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/renderpipeline/RenderPipeline.java @@ -40,18 +40,19 @@ public void updateLayers() { @NonNull private List createMergeableComponentLayers() { - return getRenderableComponentsFromEnvironment().entrySet().stream() + return provideRenderableComponentsFromRegisteredEntities().entrySet().stream() .map(entrySet -> new MergeableComponentLayer(environment, entrySet.getKey(), entrySet.getValue())) .toList(); } @NonNull - private Map> getRenderableComponentsFromEnvironment() { + private Map> provideRenderableComponentsFromRegisteredEntities() { if (isDirty()) { renderableComponentList.clear(); renderableComponentList.putAll(environment.getEntities().stream() .flatMap(entity -> entity.locateComponents(ComponentType.RenderableComponent).stream()) - .collect(Collectors.groupingBy(RenderableComponent::getZIndex))); + .collect(Collectors.groupingBy(RenderableComponent::getZIndex)) + ); setDirty(true); } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/scanable/ScanableNoise.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/scanable/ScanableNoise.java index 6855b6dc..96e22b23 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/scanable/ScanableNoise.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/graphics/scanable/ScanableNoise.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.graphics.scanable; -import com.recom.tacview.engine.graphics.Scanable; +import com.recom.tacview.engine.graphics.IsScanable; import com.recom.tacview.engine.units.PixelDimension; import com.recom.tacview.service.RandomProvider; import lombok.Getter; @@ -8,7 +8,7 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor -public class ScanableNoise implements Scanable { +public class ScanableNoise implements IsScanable { @NonNull private final RandomProvider randomProvider; diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/GenericInputEventListener.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/GenericFXInputEventListener.java similarity index 69% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/GenericInputEventListener.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/GenericFXInputEventListener.java index fcdd0a47..5059a070 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/GenericInputEventListener.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/GenericFXInputEventListener.java @@ -1,10 +1,7 @@ package com.recom.tacview.engine.input; -import com.recom.tacview.engine.input.InputManager; -import com.recom.tacview.engine.input.NanoTimedEvent; import javafx.event.EventHandler; import javafx.scene.input.InputEvent; -import javafx.scene.input.MouseEvent; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -13,7 +10,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class GenericInputEventListener implements EventHandler { +public class GenericFXInputEventListener implements EventHandler { @NonNull private final InputManager inputManager; diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/InputManager.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/InputManager.java index 502374b5..c5c391f1 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/InputManager.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/InputManager.java @@ -1,7 +1,7 @@ package com.recom.tacview.engine.input; -import com.recom.tacview.engine.input.command.IsInputCommand; -import com.recom.tacview.engine.input.command.mapper.IsInputCommandMapper; +import com.recom.tacview.engine.input.command.IsCommand; +import com.recom.tacview.engine.input.mapper.IsInputCommandMapper; import javafx.scene.input.InputEvent; import lombok.Getter; import lombok.NonNull; @@ -21,37 +21,34 @@ public class InputManager { private final LinkedList> inputEventQueue = new LinkedList<>(); @NonNull - private final LinkedList registeredInputCommands = new LinkedList<>(); + private final LinkedList> registeredCommandsMappers = new LinkedList<>(); - @Getter @NonNull - private final LinkedList createdInputCommands = new LinkedList<>(); + private final LinkedList> createdInputCommands = new LinkedList<>(); public void mapInputEventsToCommands() { - for (final IsInputCommandMapper mapper : registeredInputCommands) { + for (final IsInputCommandMapper mapper : registeredCommandsMappers) { if (mapper.mapEvents(inputEventQueue.stream())) { - createdInputCommands.addAll(mapper.getCreatedCommands()); + createdInputCommands.addAll(mapper.popCreatedCommands()); } } } public void clearInputQueues() { inputEventQueue.clear(); - createdInputCommands.clear(); } - public void registerCommandMapper(@NonNull final IsInputCommandMapper inputCommand) { - registeredInputCommands.add(inputCommand); - } + @NonNull + public LinkedList> popInputCommands() { + final LinkedList> createdInputCommandsCopy = new LinkedList<>(createdInputCommands); + createdInputCommands.clear(); - public void unregisterInputCommand(@NonNull final IsInputCommandMapper inputCommand) { - registeredInputCommands.remove(inputCommand); + return createdInputCommandsCopy; } - public void clearRegisteredInputCommands() { - registeredInputCommands.clear(); + public void registerCommandMapper(@NonNull final IsInputCommandMapper inputCommandMapper) { + registeredCommandsMappers.add(inputCommandMapper); } - } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/NanoTimedEvent.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/NanoTimedEvent.java index 80d4ef1f..c23622ce 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/NanoTimedEvent.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/NanoTimedEvent.java @@ -26,4 +26,9 @@ public static NanoTimedEvent of( return new NanoTimedEvent(timestamp, event); } + @SuppressWarnings("unchecked") + public NanoTimedEvent cast() { + return new NanoTimedEvent<>(this.getNanos(), (TARGET) this.getEvent()); + } + } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/IsCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/IsCommand.java new file mode 100644 index 00000000..a6893d1e --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/IsCommand.java @@ -0,0 +1,14 @@ +package com.recom.tacview.engine.input.command; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import javafx.scene.input.InputEvent; +import lombok.NonNull; + +public interface IsCommand { + + long getNanos(); + + @NonNull + NanoTimedEvent getNanoTimedEvent(); + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/IsInputCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/IsInputCommand.java deleted file mode 100644 index 6cd2e1da..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/IsInputCommand.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.recom.tacview.engine.input.command; - -public interface IsInputCommand { -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/MouseClickCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/MouseClickCommand.java deleted file mode 100644 index db7638f8..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/MouseClickCommand.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.recom.tacview.engine.input.command; - -import com.recom.tacview.engine.input.NanoTimedEvent; -import javafx.scene.input.MouseEvent; -import lombok.Getter; -import lombok.NonNull; - -public class MouseClickCommand implements IsInputCommand { - - @NonNull - private final NanoTimedEvent nanoTimedMouseEvent; - @Getter - private final boolean isDoubleClick; - @Getter - @NonNull - private final MouseButton mouseButton; - - - @NonNull - public static MouseClickCommand singleClickCommand( - @NonNull final NanoTimedEvent nanoTimedMouseEvent - ) { - return new MouseClickCommand(nanoTimedMouseEvent, false); - } - - @NonNull - public static MouseClickCommand doubleClickCommand( - @NonNull final NanoTimedEvent nanoTimedMouseEvent - ) { - return new MouseClickCommand(nanoTimedMouseEvent, true); - } - - public MouseClickCommand( - @NonNull final NanoTimedEvent nanoTimedMouseEvent, - final boolean isDoubleClick - ) { - this.nanoTimedMouseEvent = nanoTimedMouseEvent; - this.isDoubleClick = isDoubleClick; - this.mouseButton = determineMouseButton(nanoTimedMouseEvent.getEvent()); - } - - @NonNull - private MouseButton determineMouseButton(@NonNull final MouseEvent event) { - return switch (event.getButton()) { - case PRIMARY -> MouseButton.PRIMARY; - case SECONDARY -> MouseButton.SECONDARY; - case MIDDLE -> MouseButton.TERNARY; - default -> MouseButton.OTHER; - }; - } - - public double getPositionX() { - return nanoTimedMouseEvent.getEvent().getX(); - } - - public double getPositionY() { - return nanoTimedMouseEvent.getEvent().getY(); - } - - @NonNull - public NanoTimedEvent getNanoTimedMouseEvent() { - nanoTimedMouseEvent.getEvent().getEventType(); - nanoTimedMouseEvent.getEvent().getButton(); - - - return nanoTimedMouseEvent; - } - - enum MouseButton { - PRIMARY, - SECONDARY, - TERNARY, - OTHER - } - -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/keyboard/KeyboardCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/keyboard/KeyboardCommand.java new file mode 100644 index 00000000..8cd42535 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/keyboard/KeyboardCommand.java @@ -0,0 +1,29 @@ +package com.recom.tacview.engine.input.command.keyboard; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.IsCommand; +import javafx.scene.input.KeyEvent; +import lombok.Getter; +import lombok.NonNull; + +@Getter +public class KeyboardCommand implements IsCommand { + + @NonNull + private final NanoTimedEvent nanoTimedEvent; + + + @NonNull + public static KeyboardCommand of(@NonNull final NanoTimedEvent nanoTimedEvent) { + return new KeyboardCommand(nanoTimedEvent); + } + + public KeyboardCommand(@NonNull final NanoTimedEvent nanoTimedEvent) { + this.nanoTimedEvent = nanoTimedEvent; + } + + public long getNanos() { + return nanoTimedEvent.getNanos(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/IsInputCommandMapper.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/IsInputCommandMapper.java deleted file mode 100644 index eac89b9e..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/IsInputCommandMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.recom.tacview.engine.input.command.mapper; - -import com.recom.tacview.engine.input.NanoTimedEvent; -import com.recom.tacview.engine.input.command.IsInputCommand; -import javafx.scene.input.InputEvent; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.stream.Stream; - -public interface IsInputCommandMapper { - - boolean mapEvents(final Stream> inputEventStream); - - LinkedList getCreatedCommands(); - -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/MouseClickCommandMapper.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/MouseClickCommandMapper.java deleted file mode 100644 index 77288ebd..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/MouseClickCommandMapper.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.recom.tacview.engine.input.command.mapper; - -import com.recom.tacview.engine.input.NanoTimedEvent; -import com.recom.tacview.engine.input.command.MouseClickCommand; -import javafx.scene.input.InputEvent; -import javafx.scene.input.MouseEvent; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; - -import java.time.Duration; -import java.util.LinkedList; -import java.util.stream.Stream; - -@Slf4j -public class MouseClickCommandMapper implements IsInputCommandMapper { - - @NonNull - private final LinkedList> unprocessedMouseClicks = new LinkedList<>(); - @NonNull - private final MouseClickMachine fsm = new MouseClickMachine(Duration.ofMillis(250)); - - - @Override - public boolean mapEvents(Stream> timedMouseEventStream) { -/* - leerer stream kann hier kommen ... - wir können als in jedem tick rückwirkend schauen ob es einen unprocessedMouseClickStream eintrag - dazu schauen wir ob das erste event 200ms alt ist - wenn ja, dann ist es ein click-kanidat - wenn es ein zweites, nachfolgendes event gibt welches maximal 200 ms älter ist, dann ist es ein doubleclick-event; - wird gemapped und die beiden events werden aus der liste entfernt; dann wird der strom rekursiv weiterverarbeitet - bis er leer ist oder kein klick-kandidadat oder doubleclick-event mehr gefunden wird - - das machen wir mit einem Zustandsautomaten? Ist das nicht zu kompliziert? - Eignet sich ein Zustandsautomat dafür? - Zustände: idle/leer, klick-kandidat, doubleclick-kandidat, klick-emitter, doubleclick-emitter - */ - timedMouseEventStream - .filter(nanoTimedEvent -> nanoTimedEvent.getEvent().getEventType() == MouseEvent.MOUSE_CLICKED) - .forEach(unprocessedMouseClicks::add); - - return runMouseClickFSM(); - } - - @SuppressWarnings("unchecked") - private boolean runMouseClickFSM() { - while (!unprocessedMouseClicks.isEmpty()) { - fsm.iterate((NanoTimedEvent) unprocessedMouseClicks.poll()); - } - fsm.iterate(); - - return !fsm.getBufferedCommands().isEmpty(); - } - - @Override - @SuppressWarnings("unchecked") - public LinkedList getCreatedCommands() { - final LinkedList createdCommands = (LinkedList) fsm.getBufferedCommands().clone(); - fsm.getBufferedCommands().clear(); - - return createdCommands; - } - -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/MouseClickMachine.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/MouseClickMachine.java deleted file mode 100644 index 357761ae..00000000 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mapper/MouseClickMachine.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.recom.tacview.engine.input.command.mapper; - -import com.recom.tacview.engine.input.NanoTimedEvent; -import com.recom.tacview.engine.input.command.MouseClickCommand; -import javafx.scene.input.MouseEvent; -import lombok.Getter; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.springframework.lang.Nullable; - -import java.time.Duration; -import java.util.LinkedList; - -@Slf4j -public class MouseClickMachine { - - @NonNull - private final long doubleClickThresholdNanos; - - @NonNull - private STATE currentMachineState = STATE.IDLE; - - @Nullable - private NanoTimedEvent eventCandidateBuffer; - - @Getter - @NonNull - private final LinkedList bufferedCommands = new LinkedList<>(); - - - public MouseClickMachine(@NonNull final Duration doubleClickThreshold) { - this.doubleClickThresholdNanos = doubleClickThreshold.toNanos(); - } - - public void iterate() { - update(null); - } - - public void iterate(@NonNull final NanoTimedEvent nextNanoTimedMouseEvent) { - update(nextNanoTimedMouseEvent); - } - - private void update(@Nullable final NanoTimedEvent nextEvent) { - final INPUT_ALPHABET input = determineInputAlphabet(nextEvent); - switch (currentMachineState) { - case IDLE -> { - if (input == INPUT_ALPHABET.NEW_CLICK_CANDIDATE) { - assert nextEvent != null; - eventCandidateBuffer = nextEvent; - currentMachineState = STATE.CLICK_CANDIDATE; - } - } - case CLICK_CANDIDATE -> { - if (input == INPUT_ALPHABET.EMPTY) { - assert nextEvent == null; - assert eventCandidateBuffer != null; - if (doubleClickThresholdExpired(eventCandidateBuffer)) { - bufferedCommands.add(MouseClickCommand.singleClickCommand(eventCandidateBuffer)); - eventCandidateBuffer = null; - currentMachineState = STATE.IDLE; - } - } else if (input == INPUT_ALPHABET.NEW_CLICK_CANDIDATE) { - assert nextEvent != null; - assert eventCandidateBuffer != null; - if (doubleClickThresholdExpired(eventCandidateBuffer)) { - bufferedCommands.add(MouseClickCommand.singleClickCommand(eventCandidateBuffer)); - eventCandidateBuffer = nextEvent; - currentMachineState = STATE.CLICK_CANDIDATE; - } else { - eventCandidateBuffer = null; - bufferedCommands.add(MouseClickCommand.doubleClickCommand(nextEvent)); - currentMachineState = STATE.IDLE; - } - } - } - default -> { - throw new IllegalStateException(String.format("Unexpected Transition via State:%1s -> Input:%2s", currentMachineState, input)); - } - } - } - - private boolean doubleClickThresholdExpired(@NonNull final NanoTimedEvent event) { - return (System.nanoTime() - event.getNanos()) > doubleClickThresholdNanos; - } - - @NonNull - private INPUT_ALPHABET determineInputAlphabet(@Nullable final NanoTimedEvent nextNanoTimedMouseEvent) { - if (nextNanoTimedMouseEvent == null) { - return INPUT_ALPHABET.EMPTY; - } else { - return INPUT_ALPHABET.NEW_CLICK_CANDIDATE; - } - } - - enum STATE { - IDLE, - CLICK_CANDIDATE - } - - enum INPUT_ALPHABET { - EMPTY, - NEW_CLICK_CANDIDATE - } - -} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/IsMouseCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/IsMouseCommand.java new file mode 100644 index 00000000..0b62a455 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/IsMouseCommand.java @@ -0,0 +1,12 @@ +package com.recom.tacview.engine.input.command.mousebutton; + +import com.recom.tacview.engine.input.command.IsCommand; +import javafx.scene.input.MouseEvent; + +public interface IsMouseCommand extends IsCommand { + + double getPositionX(); + + double getPositionY(); + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseButton.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseButton.java new file mode 100644 index 00000000..fb2cb59f --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseButton.java @@ -0,0 +1,8 @@ +package com.recom.tacview.engine.input.command.mousebutton; + +public enum MouseButton { + PRIMARY, + SECONDARY, + MIDDLE, + OTHER +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseButtonCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseButtonCommand.java new file mode 100644 index 00000000..51bec60d --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseButtonCommand.java @@ -0,0 +1,64 @@ +package com.recom.tacview.engine.input.command.mousebutton; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import javafx.scene.input.MouseEvent; +import lombok.Getter; +import lombok.NonNull; + +@Getter +public class MouseButtonCommand implements IsMouseCommand { + + @NonNull + private final NanoTimedEvent nanoTimedEvent; + private final boolean doubleClick; + @NonNull + private final MouseButton mouseButton; + + + @NonNull + public static MouseButtonCommand singleClickCommand( + @NonNull final NanoTimedEvent nanoTimedMouseEvent + ) { + return new MouseButtonCommand(nanoTimedMouseEvent, false); + } + + @NonNull + public static MouseButtonCommand doubleClickCommand(@NonNull final NanoTimedEvent nanoTimedMouseEvent) { + return new MouseButtonCommand(nanoTimedMouseEvent, true); + } + + public MouseButtonCommand( + @NonNull final NanoTimedEvent nanoTimedEvent, + final boolean isDoubleClick + ) { + this.nanoTimedEvent = nanoTimedEvent; + this.doubleClick = isDoubleClick; + this.mouseButton = determineMouseButton(nanoTimedEvent.getEvent()); + } + + @NonNull + private MouseButton determineMouseButton(@NonNull final MouseEvent event) { + return switch (event.getButton()) { + case PRIMARY -> MouseButton.PRIMARY; + case SECONDARY -> MouseButton.SECONDARY; + case MIDDLE -> MouseButton.MIDDLE; + default -> MouseButton.OTHER; + }; + } + + @Override + public double getPositionX() { + return nanoTimedEvent.getEvent().getX(); + } + + @Override + public double getPositionY() { + return nanoTimedEvent.getEvent().getY(); + } + + @Override + public long getNanos() { + return nanoTimedEvent.getNanos(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseDragCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseDragCommand.java new file mode 100644 index 00000000..bf820a79 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/mousebutton/MouseDragCommand.java @@ -0,0 +1,79 @@ +package com.recom.tacview.engine.input.command.mousebutton; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import javafx.scene.input.MouseEvent; +import lombok.Getter; +import lombok.NonNull; + +@Getter +public class MouseDragCommand implements IsMouseCommand { + + private final boolean dragStart; + private final boolean dragStop; + @NonNull + private final NanoTimedEvent nanoTimedEvent; + @NonNull + private final MouseButton mouseButton; + + // send event with current x,y (/) + // radiant 0 + // distance from source to current position 0 + // vector from source to current position 0 0 + + + @NonNull + public static MouseDragCommand dragStartCommand(@NonNull final NanoTimedEvent nanoTimedMouseEvent) { + return new MouseDragCommand(nanoTimedMouseEvent, true, false); + } + + @NonNull + public static MouseDragCommand dragStopCommand(@NonNull final NanoTimedEvent nanoTimedMouseEvent) { + return new MouseDragCommand(nanoTimedMouseEvent, false, true); + } + + @NonNull + public static MouseDragCommand dragginCommand(@NonNull final NanoTimedEvent nanoTimedMouseEvent) { + return new MouseDragCommand(nanoTimedMouseEvent, false, false); + } + + public MouseDragCommand( + @NonNull final NanoTimedEvent nanoTimedEvent, + final boolean startMouseDrag, + final boolean stopMouseDrag + ) { + this.nanoTimedEvent = nanoTimedEvent; + this.dragStart = startMouseDrag; + this.dragStop = stopMouseDrag; + this.mouseButton = determineMouseButton(nanoTimedEvent.getEvent()); + } + + @NonNull + private MouseButton determineMouseButton(@NonNull final MouseEvent event) { + return switch (event.getButton()) { + case PRIMARY -> MouseButton.PRIMARY; + case SECONDARY -> MouseButton.SECONDARY; + case MIDDLE -> MouseButton.MIDDLE; + default -> MouseButton.OTHER; + }; + } + + public boolean isDragging() { + return !dragStart && !dragStop; + } + + @Override + public double getPositionX() { + return nanoTimedEvent.getEvent().getX(); + } + + @Override + public double getPositionY() { + return nanoTimedEvent.getEvent().getY(); + } + + @Override + public long getNanos() { + return nanoTimedEvent.getNanos(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/scroll/ScrollCommand.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/scroll/ScrollCommand.java new file mode 100644 index 00000000..06238c9e --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/command/scroll/ScrollCommand.java @@ -0,0 +1,37 @@ +package com.recom.tacview.engine.input.command.scroll; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.IsCommand; +import javafx.scene.input.ScrollEvent; +import lombok.Getter; +import lombok.NonNull; + +@Getter +public class ScrollCommand implements IsCommand { + + @NonNull + private final NanoTimedEvent nanoTimedEvent; + + + @NonNull + public static ScrollCommand of(@NonNull final NanoTimedEvent nanoTimedEvent) { + return new ScrollCommand(nanoTimedEvent); + } + + public ScrollCommand(@NonNull final NanoTimedEvent nanoTimedEvent) { + this.nanoTimedEvent = nanoTimedEvent; + } + + public double getPositionX() { + return nanoTimedEvent.getEvent().getX(); + } + + public double getPositionY() { + return nanoTimedEvent.getEvent().getY(); + } + + public long getNanos() { + return nanoTimedEvent.getNanos(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/IsInputCommandMapper.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/IsInputCommandMapper.java new file mode 100644 index 00000000..093f5b26 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/IsInputCommandMapper.java @@ -0,0 +1,18 @@ +package com.recom.tacview.engine.input.mapper; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.IsCommand; +import javafx.scene.input.InputEvent; +import lombok.NonNull; + +import java.util.LinkedList; +import java.util.stream.Stream; + +public interface IsInputCommandMapper> extends AutoCloseable { + + boolean mapEvents(@NonNull final Stream> inputEventStream); + + @NonNull + LinkedList popCreatedCommands(); + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/keyboard/JavaFxKeyboardCommandMapper.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/keyboard/JavaFxKeyboardCommandMapper.java new file mode 100644 index 00000000..9d3c44ba --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/keyboard/JavaFxKeyboardCommandMapper.java @@ -0,0 +1,67 @@ +package com.recom.tacview.engine.input.mapper.keyboard; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.IsCommand; +import com.recom.tacview.engine.input.command.keyboard.KeyboardCommand; +import com.recom.tacview.engine.input.mapper.IsInputCommandMapper; +import javafx.scene.input.InputEvent; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +public class JavaFxKeyboardCommandMapper implements IsInputCommandMapper { + + @NonNull + private final LinkedList> unprocessedKeypressEvents = new LinkedList<>(); + @NonNull + private final KeyboardCommandGenerator keyboardCommandGenerator = new KeyboardCommandGenerator(); + + + @Override + @SuppressWarnings("unchecked") + public boolean mapEvents(@NonNull final Stream> timedMouseEventStream) { + timedMouseEventStream + .filter(event -> event.getEvent() instanceof KeyEvent) + .map(event -> (NanoTimedEvent) event) + .filter(this::isObservedKeyEvent) + .forEach(unprocessedKeypressEvents::add); + + return runKeypresGenerator(); + } + + private boolean isObservedKeyEvent(@NonNull final NanoTimedEvent nanoTimedEvent) { + return nanoTimedEvent.getEvent().getEventType() == KeyEvent.KEY_PRESSED + || nanoTimedEvent.getEvent().getEventType() == KeyEvent.KEY_RELEASED; + } + + private boolean runKeypresGenerator() { + while (!unprocessedKeypressEvents.isEmpty()) { + keyboardCommandGenerator.updateKeyStates(unprocessedKeypressEvents.poll()); + } + keyboardCommandGenerator.generate(); + + return keyboardCommandGenerator.hasBufferedCommands(); + } + + @NonNull + @Override + public LinkedList popCreatedCommands() { + return keyboardCommandGenerator.popBufferedCommands() + .sorted(Comparator.comparing(IsCommand::getNanos)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + @Override + public void close() { + keyboardCommandGenerator.clear(); + unprocessedKeypressEvents.clear(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/keyboard/KeyboardCommandGenerator.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/keyboard/KeyboardCommandGenerator.java new file mode 100644 index 00000000..1646cc52 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/keyboard/KeyboardCommandGenerator.java @@ -0,0 +1,70 @@ +package com.recom.tacview.engine.input.mapper.keyboard; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.keyboard.KeyboardCommand; +import javafx.event.EventType; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.stream.Stream; + +import static javafx.scene.input.KeyEvent.KEY_PRESSED; +import static javafx.scene.input.KeyEvent.KEY_RELEASED; + +@Slf4j +public class KeyboardCommandGenerator { + + @NonNull + private final HashMap> pressedKeyEventsBuffer = new HashMap<>(); + + @NonNull + private final LinkedList bufferedCommands = new LinkedList<>(); + + @NonNull + private final HashSet ignoredKeyCodes = new HashSet<>(); + + public KeyboardCommandGenerator() { + ignoredKeyCodes.add(KeyCode.WINDOWS); + } + + public void generate() { + pressedKeyEventsBuffer.forEach((keyCode, nanoTimedEvent) -> { + bufferedCommands.add(KeyboardCommand.of(nanoTimedEvent)); + }); + } + + public void updateKeyStates(@NonNull final NanoTimedEvent nextKeyEventNanoTimedKeyEvent) { + final EventType eventType = nextKeyEventNanoTimedKeyEvent.getEvent().getEventType(); + final KeyCode keyCode = nextKeyEventNanoTimedKeyEvent.getEvent().getCode(); + if (ignoredKeyCodes.contains(keyCode)) { + // do nothing + } else if (eventType == KEY_PRESSED) { + pressedKeyEventsBuffer.put(nextKeyEventNanoTimedKeyEvent.getEvent().getCode(), nextKeyEventNanoTimedKeyEvent); + } else if (eventType == KEY_RELEASED) { + pressedKeyEventsBuffer.remove(nextKeyEventNanoTimedKeyEvent.getEvent().getCode()); + } + } + + public boolean hasBufferedCommands() { + return !bufferedCommands.isEmpty(); + } + + @NonNull + public Stream popBufferedCommands() { + final LinkedList bufferedCommandsCopy = new LinkedList<>(bufferedCommands); + bufferedCommands.clear(); + + return bufferedCommandsCopy.stream(); + } + + public void clear() { + pressedKeyEventsBuffer.clear(); + bufferedCommands.clear(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/JavaFxMouseButtonCommandMapper.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/JavaFxMouseButtonCommandMapper.java new file mode 100644 index 00000000..746dc621 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/JavaFxMouseButtonCommandMapper.java @@ -0,0 +1,91 @@ +package com.recom.tacview.engine.input.mapper.mousebutton; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.IsCommand; +import com.recom.tacview.engine.input.command.mousebutton.IsMouseCommand; +import com.recom.tacview.engine.input.mapper.IsInputCommandMapper; +import com.recom.tacview.engine.input.mapper.mousebutton.fsm.IsMouseButtonEventFSM; +import com.recom.tacview.engine.input.mapper.mousebutton.fsm.MouseButtonEventFSM1; +import javafx.scene.input.InputEvent; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.time.Duration; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +public class JavaFxMouseButtonCommandMapper implements IsInputCommandMapper> { + + @NonNull + private final LinkedList> unprocessedMouseEvents = new LinkedList<>(); + @NonNull + private final LinkedList mouseButtonEventFSMs = new LinkedList<>(); + + public JavaFxMouseButtonCommandMapper() { + mouseButtonEventFSMs.add(new MouseButtonEventFSM1(Duration.ofMillis(150), Duration.ofMillis(150), MouseButton.PRIMARY)); + mouseButtonEventFSMs.add(new MouseButtonEventFSM1(Duration.ofMillis(150), Duration.ofMillis(150), MouseButton.SECONDARY)); + mouseButtonEventFSMs.add(new MouseButtonEventFSM1(Duration.ofMillis(150), Duration.ofMillis(150), MouseButton.MIDDLE)); + + startMachines(); + } + + private void startMachines() { + mouseButtonEventFSMs.forEach(IsMouseButtonEventFSM::start); + } + + + @Override + @SuppressWarnings("unchecked") + public boolean mapEvents(@NonNull final Stream> timedMouseEventStream) { + timedMouseEventStream + .filter(event -> event.getEvent() instanceof MouseEvent) + .map(event -> (NanoTimedEvent) event) + .filter(this::isObservedMouseButtonEvent) + .forEach(unprocessedMouseEvents::add); + + return runMouseButtonFSM(); + } + + private boolean isObservedMouseButtonEvent(@NonNull final NanoTimedEvent nanoTimedEvent) { + return nanoTimedEvent.getEvent().getEventType() == MouseEvent.MOUSE_PRESSED + || nanoTimedEvent.getEvent().getEventType() == MouseEvent.MOUSE_RELEASED + || nanoTimedEvent.getEvent().getEventType() == MouseEvent.MOUSE_DRAGGED; + } + + private boolean runMouseButtonFSM() { + if (unprocessedMouseEvents.isEmpty()) { + mouseButtonEventFSMs.forEach(IsMouseButtonEventFSM::iterate); + } else { + while (!unprocessedMouseEvents.isEmpty()) { + final NanoTimedEvent polledMouseEvent = unprocessedMouseEvents.poll(); + mouseButtonEventFSMs.forEach(fsm -> fsm.iterate(polledMouseEvent)); + } + } + + return mouseButtonEventFSMs.stream() + .map(IsMouseButtonEventFSM::hasBufferedCommands) + .reduce(false, (a, b) -> a || b); + } + + @NonNull + @Override + public LinkedList> popCreatedCommands() { + return mouseButtonEventFSMs.stream() + .flatMap(IsMouseButtonEventFSM::popBufferedCommands) + .sorted(Comparator.comparing(IsCommand::getNanos)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + @Override + public void close() { + mouseButtonEventFSMs.forEach(IsMouseButtonEventFSM::stop); + mouseButtonEventFSMs.clear(); + unprocessedMouseEvents.clear(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/FSMStates.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/FSMStates.java new file mode 100644 index 00000000..d504acf9 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/FSMStates.java @@ -0,0 +1,9 @@ +package com.recom.tacview.engine.input.mapper.mousebutton.fsm; + +enum FSMStates { + NEW, + IDLE, + CLICK_CANDIDATE, + MOUSE_DRAGGING, + STOPPED +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/InputAlphabet.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/InputAlphabet.java new file mode 100644 index 00000000..1670c21f --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/InputAlphabet.java @@ -0,0 +1,12 @@ +package com.recom.tacview.engine.input.mapper.mousebutton.fsm; + +enum InputAlphabet { + IDLEING, + CLICK, + MOUSE_PRESSED, + DOUBLECLICK, + MOUSE_RELEASED, + MOUSE_DRAG_STARTED, + MOUSE_DRAGGING, + UNHANDLED, +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/IsMouseButtonEventFSM.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/IsMouseButtonEventFSM.java new file mode 100644 index 00000000..6c8ebfb8 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/IsMouseButtonEventFSM.java @@ -0,0 +1,26 @@ +package com.recom.tacview.engine.input.mapper.mousebutton.fsm; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.mousebutton.IsMouseCommand; +import javafx.scene.input.MouseEvent; +import lombok.NonNull; + +import java.util.stream.Stream; + +public interface IsMouseButtonEventFSM { + + void iterate(); + + void iterate(@NonNull final NanoTimedEvent nextNanoTimedMouseEvent); + + void start(); + + void stop(); + + boolean hasBufferedCommands(); + + @NonNull + Stream> popBufferedCommands(); + + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/MouseButtonEventFSM1.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/MouseButtonEventFSM1.java new file mode 100644 index 00000000..d0a4048d --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/MouseButtonEventFSM1.java @@ -0,0 +1,234 @@ +package com.recom.tacview.engine.input.mapper.mousebutton.fsm; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.mousebutton.IsMouseCommand; +import com.recom.tacview.engine.input.command.mousebutton.MouseButtonCommand; +import com.recom.tacview.engine.input.command.mousebutton.MouseDragCommand; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.lang.Nullable; + +import java.time.Duration; +import java.util.LinkedList; +import java.util.stream.Stream; + +@Slf4j +public class MouseButtonEventFSM1 implements IsMouseButtonEventFSM { + + @NonNull + private final long doubleClickThresholdNanos; + + @NonNull + private final long dragThresholdNanos; + + @NonNull + private final MouseButton responsibleForMouseButton; + + @NonNull + private FSMStates currentMachineState = FSMStates.NEW; + + @Nullable + private NanoTimedEvent lastMouseEventBuffer; + @Nullable + private NanoTimedEvent mouseDragOriginEventBuffer; + + @NonNull + private final LinkedList> bufferedCommands = new LinkedList<>(); + + + public MouseButtonEventFSM1( + @NonNull final Duration doubleClickThreshold, + @NonNull final Duration dragThreshold, + @NonNull final MouseButton responsibleForMouseButton + ) { + this.doubleClickThresholdNanos = doubleClickThreshold.toNanos(); + this.dragThresholdNanos = dragThreshold.toNanos(); + this.responsibleForMouseButton = responsibleForMouseButton; + } + + public void iterate() { + machineRevolution(null); + } + + public void iterate(@NonNull final NanoTimedEvent nextNanoTimedMouseEvent) { + machineRevolution(nextNanoTimedMouseEvent); + } + + @Override + public void start() { + currentMachineState = FSMStates.IDLE; + } + + @Override + public void stop() { + currentMachineState = FSMStates.STOPPED; + } + + @Override + public boolean hasBufferedCommands() { + return !bufferedCommands.isEmpty(); + } + + + @NonNull + @Override + public Stream> popBufferedCommands() { + final LinkedList> bufferedCommandsCopy = new LinkedList<>(bufferedCommands); + bufferedCommands.clear(); + + return bufferedCommandsCopy.stream(); + } + + private void machineRevolution(@Nullable final NanoTimedEvent nextEvent) { + if (fsmIsNotResponsibleForMouseButtonRelatedEvents(nextEvent)) { + return; + } + + switch (currentMachineState) { + case IDLE -> { + switch (idleAlphabet(nextEvent)) { + case IDLEING -> { + // do nothing + } + case MOUSE_PRESSED -> { + assert nextEvent != null; + + lastMouseEventBuffer = nextEvent; + currentMachineState = FSMStates.CLICK_CANDIDATE; + } + } + } + case CLICK_CANDIDATE -> { + assert lastMouseEventBuffer != null; + switch (clickCandidateAlphabet(nextEvent, lastMouseEventBuffer)) { + case MOUSE_RELEASED -> { + assert nextEvent != null; + + lastMouseEventBuffer = nextEvent; + } + case CLICK -> { + bufferedCommands.add(MouseButtonCommand.singleClickCommand(lastMouseEventBuffer)); + lastMouseEventBuffer = null; + currentMachineState = FSMStates.IDLE; + } + case DOUBLECLICK -> { + assert nextEvent != null; + + bufferedCommands.add(MouseButtonCommand.doubleClickCommand(nextEvent)); + lastMouseEventBuffer = null; + currentMachineState = FSMStates.IDLE; + } + case MOUSE_DRAG_STARTED -> { + assert nextEvent == null; + assert lastMouseEventBuffer != null; + assert lastMouseEventBuffer.getEvent().getEventType().equals(MouseEvent.MOUSE_PRESSED); + + mouseDragOriginEventBuffer = lastMouseEventBuffer; + bufferedCommands.add(MouseDragCommand.dragStartCommand(mouseDragOriginEventBuffer)); + currentMachineState = FSMStates.MOUSE_DRAGGING; + } + case IDLEING -> { + // do nothing + } + } + } + case MOUSE_DRAGGING -> { + switch (mouseDraggingAlphabet(nextEvent)) { + case IDLEING -> { + assert nextEvent == null; + assert lastMouseEventBuffer != null; + assert mouseDragOriginEventBuffer != null; + + // emit last known mouse drag command + bufferedCommands.add(MouseDragCommand.dragginCommand(lastMouseEventBuffer)); + } + case MOUSE_DRAGGING -> { + assert nextEvent != null; + assert lastMouseEventBuffer != null; + assert lastMouseEventBuffer.getEvent().getEventType() == MouseEvent.MOUSE_PRESSED || lastMouseEventBuffer.getEvent().getEventType() == MouseEvent.MOUSE_DRAGGED; + assert mouseDragOriginEventBuffer != null; + assert mouseDragOriginEventBuffer.getEvent().getEventType() == MouseEvent.MOUSE_PRESSED; + + lastMouseEventBuffer = nextEvent; + bufferedCommands.add(MouseDragCommand.dragginCommand(lastMouseEventBuffer)); + } + case MOUSE_RELEASED -> { + assert nextEvent != null; + assert nextEvent.getEvent().getEventType().equals(MouseEvent.MOUSE_RELEASED); + assert lastMouseEventBuffer != null; + assert mouseDragOriginEventBuffer != null; + + bufferedCommands.add(MouseDragCommand.dragStopCommand(nextEvent)); + lastMouseEventBuffer = null; + mouseDragOriginEventBuffer = null; + currentMachineState = FSMStates.IDLE; + } + } + } + default -> { + throw new IllegalStateException(String.format("Unexpected Transition via State:%1s -> Input:%2s", currentMachineState, nextEvent)); + } + } + } + + private boolean fsmIsNotResponsibleForMouseButtonRelatedEvents(@Nullable final NanoTimedEvent nextEvent) { + return nextEvent != null && (nextEvent.getEvent().getButton() != responsibleForMouseButton); + } + + @NonNull + private InputAlphabet idleAlphabet(@Nullable final NanoTimedEvent nextEvent) { + if (nextEvent == null) { + return InputAlphabet.IDLEING; + } else if (nextEvent.getEvent().getEventType() == MouseEvent.MOUSE_PRESSED) { + return InputAlphabet.MOUSE_PRESSED; + } else { + return InputAlphabet.IDLEING; + } + } + + @NonNull + private InputAlphabet clickCandidateAlphabet( + @Nullable final NanoTimedEvent nextEvent, + @NonNull final NanoTimedEvent clickCandidateBuffer + ) { + if (nextEvent == null && clickThresholdExceeded(clickCandidateBuffer)) { + return InputAlphabet.CLICK; + } else if (nextEvent == null && dragThresholdExceeded(clickCandidateBuffer) && clickCandidateBuffer.getEvent().getEventType() == MouseEvent.MOUSE_PRESSED) { + return InputAlphabet.MOUSE_DRAG_STARTED; + } else if (nextEvent != null && nextEvent.getEvent().getEventType() == MouseEvent.MOUSE_PRESSED) { + return InputAlphabet.DOUBLECLICK; + } else if (nextEvent != null && nextEvent.getEvent() instanceof MouseEvent && nextEvent.getEvent().getEventType() == MouseEvent.MOUSE_RELEASED) { + return InputAlphabet.MOUSE_RELEASED; + } else { + return InputAlphabet.IDLEING; + } + } + + @NonNull + private InputAlphabet mouseDraggingAlphabet(@Nullable final NanoTimedEvent nextEvent) { + if (nextEvent == null) { + return InputAlphabet.IDLEING; + } else if (nextEvent != null && nextEvent.getEvent().getEventType() == MouseEvent.MOUSE_RELEASED) { + return InputAlphabet.MOUSE_RELEASED; + } else if (nextEvent != null && nextEvent.getEvent() instanceof MouseEvent && nextEvent.getEvent().getEventType() == MouseEvent.MOUSE_DRAGGED) { + return InputAlphabet.MOUSE_DRAGGING; + } else { + return InputAlphabet.IDLEING; + } + } + + private boolean clickThresholdExceeded(@NonNull final NanoTimedEvent clickCandidateBuffer) { + if (clickCandidateBuffer.getEvent().getEventType().equals(MouseEvent.MOUSE_RELEASED)) { + return (System.nanoTime() - clickCandidateBuffer.getNanos()) > doubleClickThresholdNanos; + } else { + return false; + } + } + + private boolean dragThresholdExceeded(@NonNull final NanoTimedEvent event) { + return (System.nanoTime() - event.getNanos()) > dragThresholdNanos; + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/MouseButtonEventFSM1.puml b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/MouseButtonEventFSM1.puml new file mode 100644 index 00000000..e97b6928 --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/mousebutton/fsm/MouseButtonEventFSM1.puml @@ -0,0 +1,38 @@ +@startuml + +header RECOM Tacviewer +title Mouse Button Event FSM v1.0 +caption (i) Each mouse button has its own state machine +footer RECOM.one + + +[*] --> IDLE :start + +IDLE --> IDLE : IDLEING +IDLE --> CLICK_CANDIDATE : MOUSE_PRESSED +CLICK_CANDIDATE --> IDLE : CLICK\n DOUBLECLICK\n +CLICK_CANDIDATE --> MOUSE_DRAGGING : MOUSE_DRAG_STARTED +CLICK_CANDIDATE --> CLICK_CANDIDATE : IDLEING\n MOUSE_RELEASED +MOUSE_DRAGGING --> MOUSE_DRAGGING : MOUSE_DRAGGING +MOUSE_DRAGGING --> IDLE : MOUSE_RELEASED + +IDLE --> [*] :stop +CLICK_CANDIDATE --> [*] :stop +MOUSE_DRAGGING --> [*] :stop + + +legend left +__**ALPHABET**__ +| **Symbol** | **Description** | +| start | on start() | +| stop | on autoclosable close() | +| IDLEING | new engine revolution without event | +| CLICK | "click threshold exceeded" after MOUSE_RELEASED | +| MOUSE_PRESSED | mouse button pressed event | +| DOUBLECLICK | second MOUSE_PRESSED before "click threshold exceeded" | +| MOUSE_RELEASED | mouse button released | +| MOUSE_DRAG_STARTED | when mouse is pushed and not released within mouse click threshold | +| MOUSE_DRAGGING | when mouse button is pushed and moved | +endlegend + +@enduml \ No newline at end of file diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/scroll/JavaFxMouseScrollCommandMapper.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/scroll/JavaFxMouseScrollCommandMapper.java new file mode 100644 index 00000000..b4d7dfee --- /dev/null +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/input/mapper/scroll/JavaFxMouseScrollCommandMapper.java @@ -0,0 +1,64 @@ +package com.recom.tacview.engine.input.mapper.scroll; + +import com.recom.tacview.engine.input.NanoTimedEvent; +import com.recom.tacview.engine.input.command.scroll.ScrollCommand; +import com.recom.tacview.engine.input.mapper.IsInputCommandMapper; +import javafx.scene.input.InputEvent; +import javafx.scene.input.ScrollEvent; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +import java.util.LinkedList; +import java.util.stream.Stream; + +@Slf4j +public class JavaFxMouseScrollCommandMapper implements IsInputCommandMapper { + + @NonNull + private final LinkedList> unprocessedScrollEvents = new LinkedList<>(); + + @NonNull + private final LinkedList mappedCommands = new LinkedList<>(); + + + @Override + @SuppressWarnings("unchecked") + public boolean mapEvents(@NonNull final Stream> timedMouseEventStream) { + timedMouseEventStream + .filter(event -> event.getEvent() instanceof ScrollEvent) + .map(event -> (NanoTimedEvent) event) + .filter(this::isMouseScrollEvent) + .forEach(unprocessedScrollEvents::add); + + return mapEventsToCommands(); + } + + private boolean mapEventsToCommands() { + unprocessedScrollEvents.stream() + .map(ScrollCommand::of) + .forEach(mappedCommands::add); + unprocessedScrollEvents.clear(); + + return !mappedCommands.isEmpty(); + } + + private boolean isMouseScrollEvent(@NonNull final NanoTimedEvent nanoTimedEvent) { + return nanoTimedEvent.getEvent().getEventType() == ScrollEvent.SCROLL; + } + + @NonNull + @Override + public LinkedList popCreatedCommands() { + final LinkedList scrollCommandsCopy = new LinkedList<>(mappedCommands); + mappedCommands.clear(); + + return scrollCommandsCopy; + } + + @Override + public void close() { + unprocessedScrollEvents.clear(); + mappedCommands.clear(); + } + +} diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/module/EngineModule.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/module/EngineModule.java index 20ea668d..582d2681 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/module/EngineModule.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/module/EngineModule.java @@ -1,11 +1,10 @@ package com.recom.tacview.engine.module; -import com.recom.tacview.engine.Updatable; +import com.recom.tacview.engine.IsUpdatable; import com.recom.tacview.engine.entitycomponentsystem.component.ComponentType; import com.recom.tacview.engine.entitycomponentsystem.component.InputComponent; import com.recom.tacview.engine.entitycomponentsystem.environment.Environment; -import com.recom.tacview.engine.input.command.IsInputCommand; -import com.recom.tacview.engine.input.command.mapper.IsInputCommandMapper; +import com.recom.tacview.engine.input.command.IsCommand; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -15,7 +14,7 @@ @Getter @RequiredArgsConstructor -public abstract class EngineModule implements Updatable { +public abstract class EngineModule implements IsUpdatable { @NonNull private final Environment environment; @@ -34,12 +33,12 @@ public void update(final long elapsedNanoTime) { environment.update(elapsedNanoTime); } - public void handleInputCommands(@NonNull final List inputEventQueue) { + public void handleInputCommands(@NonNull final List> inputEventQueue) { final List inputComponents = environment.getEntities().stream() .flatMap(entity -> entity.locateComponents(ComponentType.InputComponent).stream()) .toList(); - for (final IsInputCommand inputCommand : inputEventQueue) { + for (final IsCommand inputCommand : inputEventQueue) { for (final InputComponent inputComponent : inputComponents) { inputComponent.handleInputCommand(inputCommand); } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/HasMergeable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/HasMergeable.java index 132c1220..18380b16 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/HasMergeable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/HasMergeable.java @@ -5,6 +5,6 @@ public interface HasMergeable { @NonNull - Mergeable getMergeable(); + IsMergeable getMergeable(); } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Mergeable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsMergeable.java similarity index 75% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Mergeable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsMergeable.java index 7fc42c14..2eaf493b 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Mergeable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsMergeable.java @@ -1,10 +1,10 @@ package com.recom.tacview.engine.renderables; -import com.recom.tacview.engine.graphics.Bufferable; +import com.recom.tacview.engine.graphics.IsBufferable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import lombok.NonNull; -public interface Mergeable extends Soilable { +public interface IsMergeable extends IsSoilable { boolean isDirty(); @@ -18,7 +18,7 @@ void mergeBufferWith( ); void mergeBufferWith( - @NonNull final Bufferable targetBuffer, + @NonNull final IsBufferable targetBuffer, final int offsetX, final int offsetY ); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Positionable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsPositionable.java similarity index 80% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Positionable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsPositionable.java index 813a6ea9..e0d9ead9 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Positionable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsPositionable.java @@ -2,7 +2,7 @@ import com.recom.tacview.engine.units.PixelCoordinate; -public interface Positionable { +public interface IsPositionable { PixelCoordinate getPosition(); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Soilable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsSoilable.java similarity index 79% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Soilable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsSoilable.java index 59c8311e..f88b9e27 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/Soilable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/IsSoilable.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.renderables; -public interface Soilable { +public interface IsSoilable { boolean isDirty(); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/BufferedMergeableTemplate.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/BufferedMergeableTemplate.java index a90ccdb6..52f7bead 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/BufferedMergeableTemplate.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/BufferedMergeableTemplate.java @@ -1,16 +1,16 @@ package com.recom.tacview.engine.renderables.mergeable; -import com.recom.tacview.engine.graphics.Bufferable; +import com.recom.tacview.engine.graphics.IsBufferable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import com.recom.tacview.engine.renderables.HasPixelBuffer; -import com.recom.tacview.engine.renderables.Mergeable; +import com.recom.tacview.engine.renderables.IsMergeable; import com.recom.tacview.engine.renderer.RenderProvider; import com.recom.tacview.engine.units.PixelDimension; import lombok.Getter; import lombok.NonNull; -public abstract class BufferedMergeableTemplate implements Mergeable, HasPixelBuffer { +public abstract class BufferedMergeableTemplate implements IsMergeable, HasPixelBuffer { @Getter @NonNull @@ -59,7 +59,7 @@ public void mergeBufferWith( @Override public void mergeBufferWith( - @NonNull final Bufferable targetBuffer, + @NonNull final IsBufferable targetBuffer, final int offsetX, final int offsetY ) { @@ -69,7 +69,7 @@ public void mergeBufferWith( @Override public void prepareBuffer() { - + this.pixelBuffer.clearBuffer(); } @Override diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/IsMergeableComponentLayer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/IsMergeableComponentLayer.java index 0995f2c4..ab566fbc 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/IsMergeableComponentLayer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/IsMergeableComponentLayer.java @@ -3,8 +3,8 @@ import com.recom.tacview.engine.entitycomponentsystem.ChildPropagateableSoilableState; import com.recom.tacview.engine.entitycomponentsystem.ParentPropagateableSoilableState; import com.recom.tacview.engine.renderables.HasPixelBuffer; -import com.recom.tacview.engine.renderables.Mergeable; +import com.recom.tacview.engine.renderables.IsMergeable; -public interface IsMergeableComponentLayer extends Mergeable, HasPixelBuffer, ParentPropagateableSoilableState, ChildPropagateableSoilableState { +public interface IsMergeableComponentLayer extends IsMergeable, HasPixelBuffer, ParentPropagateableSoilableState, ChildPropagateableSoilableState { } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/MergeableComponentLayer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/MergeableComponentLayer.java index 505714ea..cf41a972 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/MergeableComponentLayer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/MergeableComponentLayer.java @@ -1,5 +1,7 @@ package com.recom.tacview.engine.renderables.mergeable; +import com.recom.tacview.engine.entitycomponentsystem.component.ComponentType; +import com.recom.tacview.engine.entitycomponentsystem.component.PhysicCoreComponent; import com.recom.tacview.engine.entitycomponentsystem.component.RenderableComponent; import com.recom.tacview.engine.entitycomponentsystem.environment.IsEnvironment; import lombok.Getter; @@ -7,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import java.util.List; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -48,12 +51,19 @@ public void prepareBuffer() { for (final RenderableComponent component : components) { int offsetX = 0; int offsetY = 0; + + final Optional maybePhysicCoreComponent = component.getEntity().locateComponent(ComponentType.PhysicsCoreComponent); + if (maybePhysicCoreComponent.isPresent()) { + offsetX = (int) maybePhysicCoreComponent.get().getPositionX(); + offsetY = (int) maybePhysicCoreComponent.get().getPositionY(); + } + environment.getRenderProvider().provide().render(component.getPixelBuffer(), this.getPixelBuffer(), offsetX, offsetY); } - // @TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + // @TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // @TODO da müssen jetzt camera position und entity/physic_component_core position mit rein - // @TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + // @TODO <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> } private void prepareComponentBufferInParallel(@NonNull final List renderableComponents) { diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/NullMergeableComponentLayer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/NullMergeableComponentLayer.java index 294bb6f8..4f57ed71 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/NullMergeableComponentLayer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/NullMergeableComponentLayer.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.renderables.mergeable; -import com.recom.tacview.engine.graphics.Bufferable; +import com.recom.tacview.engine.graphics.IsBufferable; import com.recom.tacview.engine.graphics.buffer.NullPixelBuffer; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import lombok.NonNull; @@ -35,7 +35,7 @@ public void mergeBufferWith(@NonNull PixelBuffer targetBuffer, int offsetX, int } @Override - public void mergeBufferWith(@NonNull Bufferable targetBuffer, int offsetX, int offsetY) { + public void mergeBufferWith(@NonNull IsBufferable targetBuffer, int offsetX, int offsetY) { } diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableMergeableTemplate.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableMergeableTemplate.java index d20b8b46..ec6a36be 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableMergeableTemplate.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableMergeableTemplate.java @@ -1,14 +1,14 @@ package com.recom.tacview.engine.renderables.mergeable; -import com.recom.tacview.engine.graphics.Scanable; -import com.recom.tacview.engine.renderables.Mergeable; +import com.recom.tacview.engine.graphics.IsScanable; +import com.recom.tacview.engine.renderables.IsMergeable; import com.recom.tacview.engine.units.PixelDimension; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor -public abstract class ScanableMergeableTemplate implements Scanable, Mergeable { +public abstract class ScanableMergeableTemplate implements IsScanable, IsMergeable { @Getter @NonNull diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableNoiseMergeable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableNoiseMergeable.java index 31fb21b6..9694a620 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableNoiseMergeable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/mergeable/ScanableNoiseMergeable.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.renderables.mergeable; -import com.recom.tacview.engine.graphics.Bufferable; +import com.recom.tacview.engine.graphics.IsBufferable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import com.recom.tacview.engine.graphics.scanable.ScanableNoise; import com.recom.tacview.engine.renderer.RenderProvider; @@ -37,7 +37,7 @@ public void mergeBufferWith( @Override public void mergeBufferWith( - @NonNull final Bufferable targetBuffer, + @NonNull final IsBufferable targetBuffer, final int offsetX, final int offsetY ) { diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/tile/Tile.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/tile/IsTile.java similarity index 78% rename from libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/tile/Tile.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/tile/IsTile.java index 8536094d..ecd7acaf 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/tile/Tile.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderables/tile/IsTile.java @@ -2,12 +2,12 @@ import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import com.recom.tacview.engine.renderables.HasPixelBuffer; -import com.recom.tacview.engine.renderables.Positionable; +import com.recom.tacview.engine.renderables.IsPositionable; import com.recom.tacview.engine.renderables.sprite.Sprite; import com.recom.tacview.engine.units.PixelCoordinate; import lombok.NonNull; -public interface Tile extends HasPixelBuffer, Positionable { +public interface IsTile extends HasPixelBuffer, IsPositionable { @NonNull PixelCoordinate getPosition(); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRenderer.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRenderer.java index 3b1d322c..5a0124ba 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRenderer.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRenderer.java @@ -1,7 +1,7 @@ package com.recom.tacview.engine.renderer; -import com.recom.tacview.engine.graphics.Bufferable; -import com.recom.tacview.engine.graphics.Scanable; +import com.recom.tacview.engine.graphics.IsBufferable; +import com.recom.tacview.engine.graphics.IsScanable; import com.recom.tacview.service.RendererExecutorProvider; import com.recom.tacview.service.argb.ARGBCalculatorProvider; import lombok.NonNull; @@ -29,8 +29,8 @@ class MultithreadedSoftwareRenderer extends RendererTemplate { @Override public void render( - @NonNull final Scanable source, - @NonNull final Bufferable target, + @NonNull final IsScanable source, + @NonNull final IsBufferable target, final int xOffset, final int yOffset ) { diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RenderProvider.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RenderProvider.java index d67b730d..6cfe1960 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RenderProvider.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RenderProvider.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.renderer; -import com.recom.tacview.engine.graphics.Renderable; +import com.recom.tacview.engine.graphics.IsRenderable; import com.recom.tacview.property.RendererProperties; import com.recom.tacview.service.RendererExecutorProvider; import com.recom.tacview.service.argb.ARGBCalculatorProvider; @@ -20,9 +20,9 @@ public final class RenderProvider { @NonNull private final ARGBCalculatorProvider argbCalculatorProvider; @Nullable - private Renderable instance; + private IsRenderable instance; - public Renderable provide() { + public IsRenderable provide() { if (instance == null) { if (rendererProperties.isParallelizedRendering()) { instance = new MultithreadedSoftwareRenderer(rendererExecutorProvider, argbCalculatorProvider); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RendererTemplate.java b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RendererTemplate.java index 13001d06..eaf8c4bb 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RendererTemplate.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/engine/renderer/RendererTemplate.java @@ -1,16 +1,16 @@ package com.recom.tacview.engine.renderer; -import com.recom.tacview.engine.graphics.Bufferable; -import com.recom.tacview.engine.graphics.Renderable; -import com.recom.tacview.engine.graphics.Scanable; +import com.recom.tacview.engine.graphics.IsBufferable; +import com.recom.tacview.engine.graphics.IsRenderable; +import com.recom.tacview.engine.graphics.IsScanable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; -import com.recom.tacview.engine.renderables.Mergeable; +import com.recom.tacview.engine.renderables.IsMergeable; import com.recom.tacview.service.argb.ARGBCalculatorProvider; import lombok.NonNull; import org.springframework.stereotype.Component; @Component -abstract class RendererTemplate implements Renderable { +abstract class RendererTemplate implements IsRenderable { @NonNull protected final ARGBCalculatorProvider argbCalculatorProvider; @@ -20,8 +20,8 @@ public RendererTemplate(@NonNull final ARGBCalculatorProvider argbCalculatorProv } public void render( - @NonNull final Scanable source, - @NonNull final Bufferable target, + @NonNull final IsScanable source, + @NonNull final IsBufferable target, final int xOffset, final int yOffset ) { @@ -52,7 +52,7 @@ public void render( @Override public void renderMergeable( - @NonNull final Mergeable source, + @NonNull final IsMergeable source, @NonNull final PixelBuffer targetBuffer, final int xOffset, final int yOffset @@ -62,8 +62,8 @@ public void renderMergeable( @Override public void renderMergeable( - @NonNull final Mergeable source, - @NonNull final Bufferable target, + @NonNull final IsMergeable source, + @NonNull final IsBufferable target, final int xOffset, final int yOffset ) { @@ -72,7 +72,7 @@ public void renderMergeable( @Override public void setPixelAt( - @NonNull final Bufferable target, + @NonNull final IsBufferable target, final int x, final int y, final int newPixelValue diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/FPSProfilable.java b/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/IsFPSProfilable.java similarity index 76% rename from libs/tacviewfx/src/main/java/com/recom/tacview/strategy/FPSProfilable.java rename to libs/tacviewfx/src/main/java/com/recom/tacview/strategy/IsFPSProfilable.java index fb6765da..ae3d3d5b 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/FPSProfilable.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/IsFPSProfilable.java @@ -2,7 +2,7 @@ import lombok.NonNull; -public interface FPSProfilable { +public interface IsFPSProfilable { void setFPS(@NonNull final String profiled); diff --git a/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/ProfileFPSStrategy.java b/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/ProfileFPSStrategy.java index babfadcc..93fa0073 100644 --- a/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/ProfileFPSStrategy.java +++ b/libs/tacviewfx/src/main/java/com/recom/tacview/strategy/ProfileFPSStrategy.java @@ -9,7 +9,7 @@ public class ProfileFPSStrategy { @NonNull - private final FPSProfilable runnable; + private final IsFPSProfilable runnable; public void execute(@NonNull final String profiled) { runnable.setFPS(profiled); diff --git a/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRendererTest.java b/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRendererTest.java index 1c64785f..ab3bdfb0 100644 --- a/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRendererTest.java +++ b/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/MultithreadedSoftwareRendererTest.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.renderer; -import com.recom.tacview.engine.graphics.Scanable; +import com.recom.tacview.engine.graphics.IsScanable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import com.recom.tacview.engine.renderables.sprite.SpriteAtlas; import com.recom.tacview.engine.units.PixelDimension; @@ -61,7 +61,7 @@ void renderScanableToBuffer() { sourceBuffer.fillBuffer(sourceBufferContent); // EXECUTE - rendererToTest.render((Scanable) sourceBuffer, targetBuffer, 0, 0); + rendererToTest.render((IsScanable) sourceBuffer, targetBuffer, 0, 0); // ASSERT assertEquals(sourceBufferContent, targetBuffer.scanPixelAt(0, 0)); @@ -79,7 +79,7 @@ void renderScanableToBufferWithOffset() { sourceBuffer.fillBuffer(sourceBufferContent); // EXECUTE - rendererToTest.render((Scanable) sourceBuffer, targetBuffer, 1, 1); + rendererToTest.render((IsScanable) sourceBuffer, targetBuffer, 1, 1); // ASSERT assertEquals(0, targetBuffer.scanPixelAt(0, 0)); @@ -97,7 +97,7 @@ void renderScanableToBufferWithNegativeOffset() { sourceBuffer.fillBuffer(sourceBufferContent); // EXECUTE - rendererToTest.render((Scanable) sourceBuffer, targetBuffer, -1, -1); + rendererToTest.render((IsScanable) sourceBuffer, targetBuffer, -1, -1); // ASSERT assertEquals(sourceBufferContent, targetBuffer.scanPixelAt(0, 0)); diff --git a/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/SoftwareRendererTest.java b/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/SoftwareRendererTest.java index 93b8d53d..29316a52 100644 --- a/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/SoftwareRendererTest.java +++ b/libs/tacviewfx/src/test/java/com/recom/tacview/engine/renderer/SoftwareRendererTest.java @@ -1,6 +1,6 @@ package com.recom.tacview.engine.renderer; -import com.recom.tacview.engine.graphics.Scanable; +import com.recom.tacview.engine.graphics.IsScanable; import com.recom.tacview.engine.graphics.buffer.PixelBuffer; import com.recom.tacview.engine.renderables.sprite.SpriteAtlas; import com.recom.tacview.engine.units.PixelDimension; @@ -55,7 +55,7 @@ void renderScanableToBuffer() { sourceBuffer.fillBuffer(sourceBufferContent); // EXECUTE - rendererToTest.render((Scanable) sourceBuffer, targetBuffer, 0, 0); + rendererToTest.render((IsScanable) sourceBuffer, targetBuffer, 0, 0); // ASSERT assertEquals(sourceBufferContent, targetBuffer.scanPixelAt(0, 0)); @@ -73,7 +73,7 @@ void renderScanableToBufferWithOffset() { sourceBuffer.fillBuffer(sourceBufferContent); // EXECUTE - rendererToTest.render((Scanable) sourceBuffer, targetBuffer, 1, 1); + rendererToTest.render((IsScanable) sourceBuffer, targetBuffer, 1, 1); // ASSERT assertEquals(0, targetBuffer.scanPixelAt(0, 0)); @@ -91,7 +91,7 @@ void renderScanableToBufferWithNegativeOffset() { sourceBuffer.fillBuffer(sourceBufferContent); // EXECUTE - rendererToTest.render((Scanable) sourceBuffer, targetBuffer, -1, -1); + rendererToTest.render((IsScanable) sourceBuffer, targetBuffer, -1, -1); // ASSERT assertEquals(sourceBufferContent, targetBuffer.scanPixelAt(0, 0)); diff --git a/services/recom-commander/src/main/java/com/recom/commander/configuration/RECOMMapEntityConfiguration.java b/services/recom-commander/src/main/java/com/recom/commander/configuration/RECOMMapEntityConfiguration.java index 3107fd4e..5fac65a7 100644 --- a/services/recom-commander/src/main/java/com/recom/commander/configuration/RECOMMapEntityConfiguration.java +++ b/services/recom-commander/src/main/java/com/recom/commander/configuration/RECOMMapEntityConfiguration.java @@ -4,6 +4,7 @@ import com.recom.commander.enginemodule.entity.component.RECOMMapComponent; import com.recom.commander.enginemodule.entity.component.RECOMMapInputComponent; import com.recom.tacview.engine.entitycomponentsystem.component.InputComponent; +import com.recom.tacview.engine.entitycomponentsystem.component.PhysicCoreComponent; import lombok.NonNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -18,6 +19,7 @@ public RECOMMapEntity getRECOMMapEntity( final RECOMMapEntity recomMapEntity = new RECOMMapEntity(); recomMapEntity.addComponent(recomMapComponent); recomMapEntity.addComponent(new RECOMMapInputComponent()); + recomMapEntity.addComponent(new PhysicCoreComponent()); return recomMapEntity; } diff --git a/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapComponent.java b/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapComponent.java index b4a9e6bb..0936d3a2 100644 --- a/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapComponent.java +++ b/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapComponent.java @@ -77,7 +77,6 @@ private TakeNoticeRunnable onReloadMapTopographyDataReac final PixelBuffer pixelBuffer = new PixelBuffer(dimension, pixelBufferArray); this.pixelBuffer = pixelBuffer; - log.debug("Set pixel buffer in {}", getClass().getSimpleName()); propagateDirtyStateToParent(); }; } diff --git a/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapInputComponent.java b/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapInputComponent.java index 7aa6a86f..409b4662 100644 --- a/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapInputComponent.java +++ b/services/recom-commander/src/main/java/com/recom/commander/enginemodule/entity/component/RECOMMapInputComponent.java @@ -1,8 +1,16 @@ package com.recom.commander.enginemodule.entity.component; +import com.recom.tacview.engine.entitycomponentsystem.component.ComponentType; import com.recom.tacview.engine.entitycomponentsystem.component.InputComponent; -import com.recom.tacview.engine.input.command.IsInputCommand; -import com.recom.tacview.engine.input.command.MouseClickCommand; +import com.recom.tacview.engine.entitycomponentsystem.component.PhysicCoreComponent; +import com.recom.tacview.engine.entitycomponentsystem.component.RenderableComponent; +import com.recom.tacview.engine.input.command.IsCommand; +import com.recom.tacview.engine.input.command.keyboard.KeyboardCommand; +import com.recom.tacview.engine.input.command.mousebutton.MouseButtonCommand; +import com.recom.tacview.engine.input.command.mousebutton.MouseDragCommand; +import com.recom.tacview.engine.input.command.scroll.ScrollCommand; +import javafx.scene.input.KeyCode; +import javafx.scene.input.ScrollEvent; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -12,10 +20,61 @@ public class RECOMMapInputComponent extends InputComponent { @Override - public void handleInputCommand(@NonNull IsInputCommand inputCommand) { - if (inputCommand instanceof MouseClickCommand) { - final MouseClickCommand mouseClickCommand = (MouseClickCommand) inputCommand; - log.info("Mouse click command received: {} is doubleClick: {}", mouseClickCommand.getMouseButton(), mouseClickCommand.isDoubleClick()); + public void handleInputCommand(@NonNull final IsCommand inputCommand) { + switch (inputCommand) { + case KeyboardCommand keyboardCommand -> { + this.getEntity().locateComponent(ComponentType.PhysicsCoreComponent).ifPresent(physicsCoreComponent -> { + if (keyboardCommand.getNanoTimedEvent().getEvent().getCode().equals(KeyCode.LEFT)) { + physicsCoreComponent.setPositionX(physicsCoreComponent.getPositionX() + 5f); + this.getEntity().locateComponent(ComponentType.RenderableComponent).ifPresent(RenderableComponent::propagateDirtyStateToParent); + } else if (keyboardCommand.getNanoTimedEvent().getEvent().getCode().equals(KeyCode.RIGHT)) { + physicsCoreComponent.setPositionX(physicsCoreComponent.getPositionX() - 5f); + this.getEntity().locateComponent(ComponentType.RenderableComponent).ifPresent(RenderableComponent::propagateDirtyStateToParent); + } else if (keyboardCommand.getNanoTimedEvent().getEvent().getCode().equals(KeyCode.UP)) { + physicsCoreComponent.setPositionY(physicsCoreComponent.getPositionY() + 5f); + this.getEntity().locateComponent(ComponentType.RenderableComponent).ifPresent(RenderableComponent::propagateDirtyStateToParent); + } else if (keyboardCommand.getNanoTimedEvent().getEvent().getCode().equals(KeyCode.DOWN)) { + physicsCoreComponent.setPositionY(physicsCoreComponent.getPositionY() - 5f); + this.getEntity().locateComponent(ComponentType.RenderableComponent).ifPresent(RenderableComponent::propagateDirtyStateToParent); + } + }); + } + case ScrollCommand scrollCommand -> { + // log.info("ScrollCommand received: {} ({})", inputCommand.getClass().getSimpleName(), mapToScrollDirection(scrollCommand.getNanoTimedEvent().getEvent())); + // code to zoom in/out + } + default -> logInputCommand(inputCommand); } } + + private void logInputCommand(@NonNull final IsCommand inputCommand) { + switch (inputCommand) { + case MouseButtonCommand mouseButtonCommand -> + log.info("MouseButtonCommand received: {} (doubleClick: {})", mouseButtonCommand.getMouseButton(), mouseButtonCommand.isDoubleClick()); + case MouseDragCommand mouseDragCommand -> + log.info("MouseDragCommand received: {} ({})", mouseDragCommand.getMouseButton(), inputCommand.getNanoTimedEvent().getEvent().getEventType()); + case ScrollCommand scrollCommand -> + log.info("ScrollCommand received: {} ({})", inputCommand.getClass().getSimpleName(), mapToScrollDirection(scrollCommand.getNanoTimedEvent().getEvent())); + case KeyboardCommand keyboardCommand -> + log.info("KeyboardCommand received: {} ({})", keyboardCommand.getNanoTimedEvent().getEvent().getEventType(), keyboardCommand.getNanoTimedEvent().getEvent().getCode()); + default -> + log.info("GenericInputCommand received: {} -> {}", inputCommand.getClass().getSimpleName(), inputCommand.getNanoTimedEvent().getEvent().getEventType()); + } + } + + @NonNull + private String mapToScrollDirection(@NonNull final ScrollEvent scrollEvent) { + if (scrollEvent.getDeltaX() < 0) { + return "RIGHT"; + } else if (scrollEvent.getDeltaX() > 0) { + return "LEFT"; + } else if (scrollEvent.getDeltaY() > 0) { + return "UP"; + } else if (scrollEvent.getDeltaY() < 0) { + return "DOWN"; + } else { + return "NONE"; + } + } + } diff --git a/services/recom-commander/src/main/java/com/recom/commander/initializr/TacViewStageInitializer.java b/services/recom-commander/src/main/java/com/recom/commander/initializr/TacViewStageInitializer.java index 6b29709c..b16b742f 100644 --- a/services/recom-commander/src/main/java/com/recom/commander/initializr/TacViewStageInitializer.java +++ b/services/recom-commander/src/main/java/com/recom/commander/initializr/TacViewStageInitializer.java @@ -7,7 +7,7 @@ import com.recom.tacview.engine.TacViewer; import com.recom.tacview.engine.graphics.ScreenComposer; import com.recom.tacview.engine.input.InputManager; -import com.recom.tacview.engine.input.GenericInputEventListener; +import com.recom.tacview.engine.input.GenericFXInputEventListener; import com.recom.tacview.engine.module.EngineModule; import com.recom.tacview.property.RendererProperties; import com.recom.tacview.property.TickProperties; @@ -49,7 +49,7 @@ public class TacViewStageInitializer { @NonNull private final EngineModule engineModule; @NonNull - private final GenericInputEventListener genericInputEventListener; + private final GenericFXInputEventListener genericFXInputEventListener; @NonNull private final InputManager inputManager; @@ -79,7 +79,7 @@ private void populateTacViewStage(@NonNull final Stage stage) { profilerProvider, screenComposer, engineModule, - genericInputEventListener, + genericFXInputEventListener, inputManager ); root.setCenter(tacViewer);