Version bump, preparation for the layer subsystem implementation
This commit is contained in:
parent
7daa8c00c7
commit
0e4ec26b62
|
@ -1,33 +1,22 @@
|
||||||
## Features targeted for 22.1.0.0-alpha.0
|
|
||||||
* `[PlutoGUI]` Initial implementation of the new font renderer
|
|
||||||
* Full rewrite
|
|
||||||
* High quality font rendering
|
|
||||||
* Subpixel rendering support [?]
|
|
||||||
* Possibly a new system for bitmap fonts
|
|
||||||
* Improve upon the support of thread-local Pluto instances
|
|
||||||
* The long term goal is to allow an unlimited amount of Pluto applications at any given time
|
|
||||||
|
|
||||||
## Features targeted for 22.2.0.0-alpha.0
|
## Features targeted for 22.2.0.0-alpha.0
|
||||||
* The stage subsystem
|
* The layer subsystem
|
||||||
* A "stage", in this context, is a set of assets bound together
|
* A "layer", in this context, is a set of assets bound together
|
||||||
by programming logic, not necessarily a game level.
|
by programming logic.
|
||||||
Stage switching and asset management are handled by the engine.
|
Layer switching and asset management are handled by the engine.
|
||||||
* Upon stage switch
|
* Layers can be stacked on top of each other and run sequentially
|
||||||
|
from bottom to top
|
||||||
|
* Upon layer switch
|
||||||
1. Unload unused assets
|
1. Unload unused assets
|
||||||
2. Load new assets
|
2. Load new assets
|
||||||
* Provide multiple means of stage switching
|
* Provide multiple means of layer switching
|
||||||
* Three modes with the initial release
|
* Two modes with the initial release, asynchronous switching will come at a later date
|
||||||
1. Instant switch
|
1. Instant switch
|
||||||
* Assets will be loaded and unloaded synchronously
|
* Assets will be loaded and unloaded synchronously
|
||||||
* The stage switch will happen in one frame
|
* The layer switch will happen in one frame
|
||||||
2. Deferred switch
|
2. Deferred switch
|
||||||
* The stage will continue running until all assets load
|
* The layer will continue running until all assets load
|
||||||
* Assets will load synchronously, but at a slower pace
|
* Assets will load synchronously, but at a slower pace
|
||||||
to avoid frame stutter
|
to avoid frame stutter
|
||||||
3. Asynchronous switch
|
|
||||||
* Assets will be loaded in asynchronously, where applicable
|
|
||||||
* Falls back to deferred switching for synchronous loading,
|
|
||||||
such as OpenGL texture upload
|
|
||||||
* Automated asset loading
|
* Automated asset loading
|
||||||
* All asset management will eventually be handled by `PlutoCore`
|
* All asset management will eventually be handled by `PlutoCore`
|
||||||
* This includes audio clips, textures, sprites
|
* This includes audio clips, textures, sprites
|
||||||
|
@ -39,3 +28,23 @@
|
||||||
instances
|
instances
|
||||||
* Allow stages to be inherited from, creating a stack-like structure
|
* Allow stages to be inherited from, creating a stack-like structure
|
||||||
* `[PlutoAudio]` Integrate the Audio API with the Stage API
|
* `[PlutoAudio]` Integrate the Audio API with the Stage API
|
||||||
|
|
||||||
|
## Features targeted for an unspecified future release
|
||||||
|
* `[PlutoSpritesheet]` Expanded capabilities
|
||||||
|
* Support for 9-slice rendering
|
||||||
|
* Support for animated sprite rendering
|
||||||
|
* Support for multidirectional sprite rendering
|
||||||
|
* A spritesheet skeleton editor
|
||||||
|
|
||||||
|
* `[PlutoRuntime]`
|
||||||
|
* Asynchronous switch
|
||||||
|
* Assets will be loaded in asynchronously, where applicable
|
||||||
|
* Falls back to deferred switching for synchronous loading,
|
||||||
|
such as OpenGL texture upload
|
||||||
|
|
||||||
|
* `[PlutoGUI]` A fully-fledged GUI engine
|
||||||
|
* Improve font-rendering capabilities
|
||||||
|
* Subpixel rendering support [?]
|
||||||
|
* Reimplement support for bitmap fonts
|
||||||
|
* Improve upon the support of thread-local Pluto instances
|
||||||
|
* The long term goal is to allow an unlimited amount of Pluto applications at any given time
|
||||||
|
|
|
@ -50,7 +50,6 @@ See `NEXT_RELEASE_DRAFT.md` for details.
|
||||||
### Very high priority
|
### Very high priority
|
||||||
[ *Implemented in the current release.* ]
|
[ *Implemented in the current release.* ]
|
||||||
* Improve image loading capabilities, possibly rewrite PlutoLib#TPL
|
* Improve image loading capabilities, possibly rewrite PlutoLib#TPL
|
||||||
* The stage system and automated asset loading
|
|
||||||
|
|
||||||
### High priority
|
### High priority
|
||||||
[ *Implemented in the next release.* ]
|
[ *Implemented in the next release.* ]
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
## 22.2.0.0-alpha.0
|
||||||
|
* `[PlutoRuntime,PlutoCore]` **Initial implementation of the layer system (formerly known as "stage")**
|
||||||
|
* `[PlutoComponent]` **Added support for dependencies and strengtened type checks**
|
||||||
|
* `[PlutoComponent]` *Removed* `IComponent` as it was redundant to `AbstractComponent`
|
||||||
|
* `[Pluto*]` *Removed* JSR 305 annotations in favor of JetBrains annotations
|
||||||
|
* `[Pluto*]` *Removed* the `ConstantExpression` annotation in favor of `Contract`
|
||||||
|
* `[PlutoRuntime]` *Moved* `ThreadSensitive` to `org.plutoengine.address`
|
||||||
|
* `[PlutoAudio]` Transformed into a PlutoLocalComponent
|
||||||
|
* `[PlutoAudio]` `IAudioStream` is now `AutoCloseable`
|
||||||
|
* `[PlutoCore]` `InputBus` now tied to a specific `Display` instead of searching for one in the Local
|
||||||
|
* `[PlutoCore]` Separated `Mouse` and `Keyboard` from `InputBus` into child components
|
||||||
|
|
||||||
## 22.1.0.0-alpha.1
|
## 22.1.0.0-alpha.1
|
||||||
* `plutoengine-demos/basic-application` Made the gradient in the fragment font shader rotatable
|
* `plutoengine-demos/basic-application` Made the gradient in the fragment font shader rotatable
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,13 @@ object Versions {
|
||||||
const val steamworks4jServerVersion = "1.8.0"
|
const val steamworks4jServerVersion = "1.8.0"
|
||||||
|
|
||||||
const val versionYear = 22
|
const val versionYear = 22
|
||||||
const val versionMajor = 1
|
const val versionMajor = 2
|
||||||
const val versionMinor = 0
|
const val versionMinor = 0
|
||||||
const val versionPatch = 0
|
const val versionPatch = 0
|
||||||
|
|
||||||
const val isPrerelease = true
|
const val isPrerelease = true
|
||||||
const val prereleaseName = "alpha"
|
const val prereleaseName = "alpha"
|
||||||
const val prerealeaseUpdate = 1
|
const val prerealeaseUpdate = 0
|
||||||
|
|
||||||
val versionFull =
|
val versionFull =
|
||||||
if (isPrerelease)
|
if (isPrerelease)
|
||||||
|
|
|
@ -4,6 +4,9 @@ import org.lwjgl.stb.STBVorbis;
|
||||||
import org.lwjgl.stb.STBVorbisInfo;
|
import org.lwjgl.stb.STBVorbisInfo;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
import org.plutoengine.buffer.BufferHelper;
|
||||||
|
import org.plutoengine.logger.Logger;
|
||||||
|
import org.plutoengine.logger.SmartSeverity;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -12,10 +15,6 @@ import java.nio.ShortBuffer;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import org.plutoengine.buffer.BufferHelper;
|
|
||||||
import org.plutoengine.logger.Logger;
|
|
||||||
import org.plutoengine.logger.SmartSeverity;
|
|
||||||
|
|
||||||
public class AudioLoader
|
public class AudioLoader
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.plutoengine.audio;
|
||||||
|
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
public interface IAudioStream
|
public interface IAudioStream extends AutoCloseable
|
||||||
{
|
{
|
||||||
int getSamples(ShortBuffer pcm);
|
int getSamples(ShortBuffer pcm);
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,11 @@ import org.joml.Vector3f;
|
||||||
import org.lwjgl.openal.*;
|
import org.lwjgl.openal.*;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
import org.plutoengine.Pluto;
|
import org.plutoengine.Pluto;
|
||||||
|
import org.plutoengine.component.ComponentToken;
|
||||||
|
import org.plutoengine.component.PlutoLocalComponent;
|
||||||
import org.plutoengine.logger.Logger;
|
import org.plutoengine.logger.Logger;
|
||||||
import org.plutoengine.logger.SmartSeverity;
|
import org.plutoengine.logger.SmartSeverity;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
@ -15,16 +16,21 @@ import java.nio.IntBuffer;
|
||||||
* @author 493msi
|
* @author 493msi
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
public class AudioEngine extends PlutoLocalComponent
|
||||||
public class AudioEngine
|
|
||||||
{
|
{
|
||||||
private static final ThreadLocal<Long> device = ThreadLocal.withInitial(() -> MemoryUtil.NULL);
|
private long device = MemoryUtil.NULL;
|
||||||
|
private long context = MemoryUtil.NULL;
|
||||||
|
private ALCapabilities capabilities;
|
||||||
|
|
||||||
private static final ThreadLocal<Long> context = ThreadLocal.withInitial(() -> MemoryUtil.NULL);
|
public static final ComponentToken<AudioEngine> TOKEN = ComponentToken.create(AudioEngine::new);
|
||||||
|
|
||||||
private static final ThreadLocal<ALCapabilities> capabilities = new ThreadLocal<>();
|
private AudioEngine()
|
||||||
|
{
|
||||||
|
|
||||||
public static void initialize()
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMount(ComponentDependencyManager manager)
|
||||||
{
|
{
|
||||||
var devicePtr = ALC10.alcOpenDevice((ByteBuffer) null);
|
var devicePtr = ALC10.alcOpenDevice((ByteBuffer) null);
|
||||||
if (devicePtr == MemoryUtil.NULL)
|
if (devicePtr == MemoryUtil.NULL)
|
||||||
|
@ -35,7 +41,7 @@ public class AudioEngine
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
device.set(devicePtr);
|
this.device = devicePtr;
|
||||||
|
|
||||||
var contextPtr = ALC10.alcCreateContext(devicePtr, (IntBuffer) null);
|
var contextPtr = ALC10.alcCreateContext(devicePtr, (IntBuffer) null);
|
||||||
if (contextPtr == MemoryUtil.NULL)
|
if (contextPtr == MemoryUtil.NULL)
|
||||||
|
@ -48,7 +54,7 @@ public class AudioEngine
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.set(contextPtr);
|
this.context = contextPtr;
|
||||||
|
|
||||||
EXTThreadLocalContext.alcSetThreadContext(contextPtr);
|
EXTThreadLocalContext.alcSetThreadContext(contextPtr);
|
||||||
|
|
||||||
|
@ -61,25 +67,27 @@ public class AudioEngine
|
||||||
Logger.logf(SmartSeverity.AUDIO, "OpenAL11: %b\n", alCapabilities.OpenAL11);
|
Logger.logf(SmartSeverity.AUDIO, "OpenAL11: %b\n", alCapabilities.OpenAL11);
|
||||||
}
|
}
|
||||||
|
|
||||||
capabilities.set(alCapabilities);
|
this.capabilities = alCapabilities;
|
||||||
|
|
||||||
|
Logger.log(SmartSeverity.AUDIO_PLUS, "Audio engine started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setSpeed(Vector3f speed)
|
public void setSpeed(Vector3f speed)
|
||||||
{
|
{
|
||||||
AL10.alListener3f(AL10.AL_VELOCITY, speed.x, speed.y, speed.z);
|
AL10.alListener3f(AL10.AL_VELOCITY, speed.x, speed.y, speed.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setPosition(Vector3f position)
|
public void setPosition(Vector3f position)
|
||||||
{
|
{
|
||||||
AL10.alListener3f(AL10.AL_POSITION, position.x, position.y, position.z);
|
AL10.alListener3f(AL10.AL_POSITION, position.x, position.y, position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setVolume(float volume)
|
public void setVolume(float volume)
|
||||||
{
|
{
|
||||||
AL10.alListenerf(AL10.AL_GAIN, volume);
|
AL10.alListenerf(AL10.AL_GAIN, volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setOrientation(Vector3f at, Vector3f up)
|
public void setOrientation(Vector3f at, Vector3f up)
|
||||||
{
|
{
|
||||||
float[] data = new float[6];
|
float[] data = new float[6];
|
||||||
data[0] = at.x;
|
data[0] = at.x;
|
||||||
|
@ -91,18 +99,29 @@ public class AudioEngine
|
||||||
AL10.alListenerfv(AL10.AL_ORIENTATION, data);
|
AL10.alListenerfv(AL10.AL_ORIENTATION, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReady()
|
public boolean isReady()
|
||||||
{
|
{
|
||||||
return capabilities.get() != null;
|
return this.capabilities != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void exit()
|
@Override
|
||||||
|
protected void onUnmount()
|
||||||
{
|
{
|
||||||
EXTThreadLocalContext.alcSetThreadContext(MemoryUtil.NULL);
|
Logger.log(SmartSeverity.AUDIO_MINUS, "Shutting down the audio engine.");
|
||||||
ALC10.alcDestroyContext(context.get());
|
|
||||||
ALC10.alcCloseDevice(device.get());
|
|
||||||
|
|
||||||
context.remove();
|
EXTThreadLocalContext.alcSetThreadContext(MemoryUtil.NULL);
|
||||||
device.remove();
|
|
||||||
|
ALC10.alcDestroyContext(this.context);
|
||||||
|
ALC10.alcCloseDevice(this.device);
|
||||||
|
|
||||||
|
this.context = MemoryUtil.NULL;
|
||||||
|
this.device = MemoryUtil.NULL;
|
||||||
|
this.capabilities = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnique()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,11 @@ package org.plutoengine.audio.al;
|
||||||
import org.lwjgl.openal.AL10;
|
import org.lwjgl.openal.AL10;
|
||||||
import org.lwjgl.openal.SOFTDirectChannels;
|
import org.lwjgl.openal.SOFTDirectChannels;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
import org.plutoengine.audio.IAudioStream;
|
||||||
|
import org.plutoengine.audio.ISeekableAudioTrack;
|
||||||
|
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
import org.plutoengine.audio.ISeekableAudioTrack;
|
|
||||||
import org.plutoengine.audio.IAudioStream;
|
|
||||||
|
|
||||||
public class AudioTrack extends AudioSource
|
public class AudioTrack extends AudioSource
|
||||||
{
|
{
|
||||||
private static final int BUFFER_SIZE_PER_CHANNEL = 16384;
|
private static final int BUFFER_SIZE_PER_CHANNEL = 16384;
|
||||||
|
@ -56,10 +55,8 @@ public class AudioTrack extends AudioSource
|
||||||
|
|
||||||
public boolean play()
|
public boolean play()
|
||||||
{
|
{
|
||||||
if (this.track instanceof ISeekableAudioTrack)
|
if (this.track instanceof ISeekableAudioTrack seekableAudioTrack)
|
||||||
{
|
seekableAudioTrack.rewind();
|
||||||
((ISeekableAudioTrack) this.track).rewind();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int buf : this.buffers)
|
for (int buf : this.buffers)
|
||||||
{
|
{
|
||||||
|
@ -82,9 +79,7 @@ public class AudioTrack extends AudioSource
|
||||||
int samplesPerChannel = this.track.getSamples(this.pcm);
|
int samplesPerChannel = this.track.getSamples(this.pcm);
|
||||||
|
|
||||||
if (samplesPerChannel == 0)
|
if (samplesPerChannel == 0)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var samples = samplesPerChannel * this.track.getChannels();
|
var samples = samplesPerChannel * this.track.getChannels();
|
||||||
this.pcm.limit(samples);
|
this.pcm.limit(samples);
|
||||||
|
|
|
@ -6,8 +6,9 @@ plugins {
|
||||||
description = "A module acting as glue for all PlutoEngine components."
|
description = "A module acting as glue for all PlutoEngine components."
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api("org.apache.commons:commons-lang3:3.12.0")
|
api("org.jetbrains", "annotations", "23.0.0")
|
||||||
api("org.apache.commons:commons-collections4:4.4")
|
|
||||||
|
implementation("org.apache.commons", "commons-lang3", "3.12.0")
|
||||||
|
implementation("org.apache.commons", "commons-collections4", "4.4")
|
||||||
|
|
||||||
api("com.google.code.findbugs:jsr305:3.0.2")
|
|
||||||
}
|
}
|
|
@ -1,33 +1,61 @@
|
||||||
package org.plutoengine.component;
|
package org.plutoengine.component;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public abstract class AbstractComponent implements IComponent
|
public abstract class AbstractComponent<T extends AbstractComponent<? super T>>
|
||||||
{
|
{
|
||||||
private static final AtomicLong ID_SOURCE = new AtomicLong();
|
private static final AtomicLong ID_SOURCE = new AtomicLong();
|
||||||
|
|
||||||
private final long id;
|
private final long id;
|
||||||
|
|
||||||
|
private ComponentDependencyManager manager;
|
||||||
|
|
||||||
protected AbstractComponent()
|
protected AbstractComponent()
|
||||||
{
|
{
|
||||||
this.id = ID_SOURCE.getAndIncrement();
|
this.id = ID_SOURCE.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getID()
|
public long getID()
|
||||||
{
|
{
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void onMount() throws Exception
|
* Denotes whether this component should be unique.
|
||||||
|
* Unique components can only exist once per instance
|
||||||
|
* in a given {@link ComponentManager}.
|
||||||
|
*
|
||||||
|
* @return whether this component should be unique
|
||||||
|
*/
|
||||||
|
public abstract boolean isUnique();
|
||||||
|
|
||||||
|
void initialize(ComponentManager<? super T> manager) throws Exception
|
||||||
|
{
|
||||||
|
this.manager = this.new ComponentDependencyManager(manager);
|
||||||
|
|
||||||
|
onMount(this.manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onMount(ComponentDependencyManager manager) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void destroy(ComponentManager<? super T> manager) throws Exception
|
||||||
public void onUnmount() throws Exception
|
{
|
||||||
|
if (this.manager.dependencies != null)
|
||||||
|
{
|
||||||
|
this.manager.dependencies.forEach(manager::removeComponent);
|
||||||
|
this.manager.dependencies.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onUnmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onUnmount() throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,7 +65,7 @@ public abstract class AbstractComponent implements IComponent
|
||||||
{
|
{
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || this.getClass() != o.getClass()) return false;
|
if (o == null || this.getClass() != o.getClass()) return false;
|
||||||
AbstractComponent that = (AbstractComponent) o;
|
AbstractComponent<?> that = (AbstractComponent<?>) o;
|
||||||
return this.id == that.id;
|
return this.id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,4 +74,27 @@ public abstract class AbstractComponent implements IComponent
|
||||||
{
|
{
|
||||||
return Objects.hash(this.id);
|
return Objects.hash(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ComponentDependencyManager
|
||||||
|
{
|
||||||
|
private final ComponentManager<? super T> manager;
|
||||||
|
private Deque<T> dependencies;
|
||||||
|
|
||||||
|
private ComponentDependencyManager(ComponentManager<? super T> componentManager)
|
||||||
|
{
|
||||||
|
this.manager = componentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <R extends T> R declareDependency(ComponentToken<R> token)
|
||||||
|
{
|
||||||
|
if (this.dependencies == null)
|
||||||
|
this.dependencies = new ArrayDeque<>();
|
||||||
|
|
||||||
|
var dependency = this.manager.addComponent(token);
|
||||||
|
|
||||||
|
this.dependencies.push(dependency);
|
||||||
|
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,21 +4,21 @@ import org.apache.commons.collections4.MultiValuedMap;
|
||||||
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
||||||
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
|
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
|
||||||
import org.apache.commons.lang3.ClassUtils;
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ComponentManager<R extends AbstractComponent>
|
public class ComponentManager<R extends AbstractComponent<R>>
|
||||||
{
|
{
|
||||||
private final Class<R> base;
|
private final Class<R> base;
|
||||||
|
|
||||||
protected final MultiValuedMap<ComponentToken<? extends R>, R> components;
|
protected final MultiValuedMap<ComponentToken<?>, R> components;
|
||||||
protected final Map<R, ComponentToken<? extends R>> tokens;
|
protected final Map<R, ComponentToken<?>> tokens;
|
||||||
protected final MultiValuedMap<Class<?>, R> implementationProviders;
|
protected final MultiValuedMap<Class<?>, R> implementationProviders;
|
||||||
protected final MultiValuedMap<R, Class<?>> implementationReceivers;
|
protected final MultiValuedMap<R, Class<?>> implementationReceivers;
|
||||||
|
|
||||||
public ComponentManager(@Nonnull Class<R> base)
|
public ComponentManager(@NotNull Class<R> base)
|
||||||
{
|
{
|
||||||
this.base = base;
|
this.base = base;
|
||||||
this.components = new HashSetValuedHashMap<>();
|
this.components = new HashSetValuedHashMap<>();
|
||||||
|
@ -27,7 +27,7 @@ public class ComponentManager<R extends AbstractComponent>
|
||||||
this.implementationReceivers = new ArrayListValuedHashMap<>();
|
this.implementationReceivers = new ArrayListValuedHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends R> T addComponent(@Nonnull ComponentToken<T> token)
|
public <T extends R> T addComponent(@NotNull ComponentToken<T> token)
|
||||||
{
|
{
|
||||||
T component = token.createInstance();
|
T component = token.createInstance();
|
||||||
var clazz = component.getClass();
|
var clazz = component.getClass();
|
||||||
|
@ -52,7 +52,7 @@ public class ComponentManager<R extends AbstractComponent>
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.onMount();
|
component.initialize(this);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -67,33 +67,33 @@ public class ComponentManager<R extends AbstractComponent>
|
||||||
return this.base;
|
return this.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends R> Stream<T> streamComponents(@Nonnull Class<T> componentClazz)
|
public <T extends R> Stream<T> streamComponents(@NotNull Class<T> componentClazz)
|
||||||
{
|
{
|
||||||
var providers = this.implementationProviders.get(componentClazz);
|
var providers = this.implementationProviders.get(componentClazz);
|
||||||
|
|
||||||
return providers.stream().map(componentClazz::cast);
|
return providers.stream().map(componentClazz::cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends R> T getComponent(@Nonnull Class<T> componentClazz) throws NoSuchElementException
|
public <T extends R> T getComponent(@NotNull Class<T> componentClazz) throws NoSuchElementException
|
||||||
{
|
{
|
||||||
return this.streamComponents(componentClazz)
|
return this.streamComponents(componentClazz)
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends R> T getComponent(@Nonnull Class<T> componentClazz, @Nonnull Comparator<T> heuristic) throws NoSuchElementException
|
public <T extends R> T getComponent(@NotNull Class<T> componentClazz, @NotNull Comparator<T> heuristic) throws NoSuchElementException
|
||||||
{
|
{
|
||||||
return this.streamComponents(componentClazz)
|
return this.streamComponents(componentClazz)
|
||||||
.max(heuristic)
|
.max(heuristic)
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends R> List<T> getComponents(@Nonnull Class<T> componentClazz)
|
public <T extends R> List<T> getComponents(@NotNull Class<T> componentClazz)
|
||||||
{
|
{
|
||||||
return this.streamComponents(componentClazz).toList();
|
return this.streamComponents(componentClazz).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeComponent(@Nonnull R component) throws IllegalArgumentException
|
public void removeComponent(@NotNull R component) throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
var token = this.tokens.remove(component);
|
var token = this.tokens.remove(component);
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ public class ComponentManager<R extends AbstractComponent>
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.onUnmount();
|
component.destroy(this);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -116,7 +116,7 @@ public class ComponentManager<R extends AbstractComponent>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends R> void removeComponents(@Nonnull ComponentToken<T> componentToken)
|
public <T extends R> void removeComponents(@NotNull ComponentToken<T> componentToken)
|
||||||
{
|
{
|
||||||
var activeComponents = this.components.remove(componentToken);
|
var activeComponents = this.components.remove(componentToken);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package org.plutoengine.component;
|
package org.plutoengine.component;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public final class ComponentToken<T extends IComponent>
|
public final class ComponentToken<T extends AbstractComponent<? super T>>
|
||||||
{
|
{
|
||||||
private static final AtomicLong ID_SOURCE = new AtomicLong();
|
private static final AtomicLong ID_SOURCE = new AtomicLong();
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ public final class ComponentToken<T extends IComponent>
|
||||||
this.supplier = valueSupplier;
|
this.supplier = valueSupplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends IComponent> ComponentToken<T> create(@Nonnull Supplier<T> valueSupplier)
|
public static <G extends AbstractComponent<? super G>> ComponentToken<G> create(@NotNull Supplier<G> valueSupplier)
|
||||||
{
|
{
|
||||||
return new ComponentToken<>(valueSupplier);
|
return new ComponentToken<>(valueSupplier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package org.plutoengine.component;
|
|
||||||
|
|
||||||
public interface IComponent
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Denotes whether this component should be unique.
|
|
||||||
* Unique components can only exist once per instance
|
|
||||||
* in a given {@link ComponentManager}.
|
|
||||||
*
|
|
||||||
* @return whether this component should be unique
|
|
||||||
*
|
|
||||||
* @author 493msi
|
|
||||||
* @since 20.2.0.0-alpha.3
|
|
||||||
*/
|
|
||||||
boolean isUnique();
|
|
||||||
|
|
||||||
long getID();
|
|
||||||
|
|
||||||
void onMount() throws Exception;
|
|
||||||
|
|
||||||
void onUnmount() throws Exception;
|
|
||||||
}
|
|
|
@ -243,9 +243,8 @@ public abstract class PlutoApplication
|
||||||
|
|
||||||
this.display.createOpenGLCapabilities();
|
this.display.createOpenGLCapabilities();
|
||||||
|
|
||||||
components.addComponent(InputBus.TOKEN);
|
var inputBus = components.addComponent(InputBus.fromDisplay(this.display));
|
||||||
|
var audioEngine = components.addComponent(AudioEngine.TOKEN);
|
||||||
AudioEngine.initialize();
|
|
||||||
|
|
||||||
var modLoader = components.addComponent(ModLoader.TOKEN);
|
var modLoader = components.addComponent(ModLoader.TOKEN);
|
||||||
|
|
||||||
|
@ -259,7 +258,6 @@ public abstract class PlutoApplication
|
||||||
this.display.setIcons(icons);
|
this.display.setIcons(icons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while (!this.display.isClosing())
|
while (!this.display.isClosing())
|
||||||
{
|
{
|
||||||
GL33.glViewport(0, 0, this.display.getWidth(), this.display.getHeight());
|
GL33.glViewport(0, 0, this.display.getWidth(), this.display.getHeight());
|
||||||
|
@ -270,20 +268,19 @@ public abstract class PlutoApplication
|
||||||
|
|
||||||
this.display.swapBuffers();
|
this.display.swapBuffers();
|
||||||
|
|
||||||
InputBus.resetStates();
|
inputBus.resetStates();
|
||||||
|
|
||||||
this.display.pollEvents();
|
this.display.pollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioEngine.exit();
|
components.removeComponent(audioEngine);
|
||||||
|
|
||||||
modLoader.unload();
|
modLoader.unload();
|
||||||
|
|
||||||
GL.destroy();
|
GL.destroy();
|
||||||
|
|
||||||
components.removeComponent(modLoader);
|
components.removeComponent(modLoader);
|
||||||
|
components.removeComponent(inputBus);
|
||||||
components.removeComponents(InputBus.TOKEN);
|
|
||||||
|
|
||||||
this.display.destroy();
|
this.display.destroy();
|
||||||
|
|
||||||
|
|
|
@ -1,100 +1,37 @@
|
||||||
package org.plutoengine.input;
|
package org.plutoengine.input;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
import org.plutoengine.PlutoLocal;
|
|
||||||
import org.plutoengine.address.ThreadSensitive;
|
|
||||||
import org.plutoengine.component.ComponentToken;
|
import org.plutoengine.component.ComponentToken;
|
||||||
import org.plutoengine.component.PlutoLocalComponent;
|
import org.plutoengine.component.PlutoLocalComponent;
|
||||||
import org.plutoengine.display.Display;
|
import org.plutoengine.display.Display;
|
||||||
|
|
||||||
@ThreadSensitive(localContexts = true)
|
|
||||||
public class InputBus extends PlutoLocalComponent
|
public class InputBus extends PlutoLocalComponent
|
||||||
{
|
{
|
||||||
public static final ComponentToken<InputBus> TOKEN = ComponentToken.create(InputBus::new);
|
public static ComponentToken<InputBus> fromDisplay(Display display)
|
||||||
|
|
||||||
private final KeyboardInputCallback keyboard = new KeyboardInputCallback();
|
|
||||||
private final MouseButtonCallback mouseButton = new MouseButtonCallback();
|
|
||||||
private final CursorPositionCallback cursorPosition = new CursorPositionCallback();
|
|
||||||
private final ScrollInputCallback scroll = new ScrollInputCallback();
|
|
||||||
private final KeyboardCharInput charInput = new KeyboardCharInput();
|
|
||||||
|
|
||||||
private long windowPointer;
|
|
||||||
|
|
||||||
private InputBus()
|
|
||||||
{
|
{
|
||||||
|
return ComponentToken.create(() -> new InputBus(display));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputBus instance()
|
private final Display display;
|
||||||
|
|
||||||
|
private Keyboard keyboard;
|
||||||
|
private Mouse mouse;
|
||||||
|
|
||||||
|
private InputBus(Display display)
|
||||||
{
|
{
|
||||||
return PlutoLocal.components().getComponent(InputBus.class);
|
this.display = display;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMount()
|
protected void onMount(ComponentDependencyManager manager)
|
||||||
{
|
{
|
||||||
var display = PlutoLocal.components().getComponent(Display.class);
|
this.keyboard = manager.declareDependency(ComponentToken.create(() -> new Keyboard(this.display.getWindowPointer())));
|
||||||
this.windowPointer = display.getWindowPointer();
|
this.mouse = manager.declareDependency(ComponentToken.create(() -> new Mouse(this.display.getWindowPointer())));
|
||||||
|
|
||||||
GLFW.glfwSetKeyCallback(this.windowPointer, this.keyboard);
|
|
||||||
GLFW.glfwSetMouseButtonCallback(this.windowPointer, this.mouseButton);
|
|
||||||
GLFW.glfwSetCursorPosCallback(this.windowPointer, this.cursorPosition);
|
|
||||||
GLFW.glfwSetScrollCallback(this.windowPointer, this.scroll);
|
|
||||||
GLFW.glfwSetCharCallback(this.windowPointer, this.charInput);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resetStates()
|
||||||
@Override
|
|
||||||
public void onUnmount()
|
|
||||||
{
|
{
|
||||||
GLFW.glfwSetKeyCallback(this.windowPointer, null);
|
this.keyboard.resetStates();
|
||||||
GLFW.glfwSetMouseButtonCallback(this.windowPointer, null);
|
this.mouse.resetStates();
|
||||||
GLFW.glfwSetCursorPosCallback(this.windowPointer, null);
|
|
||||||
GLFW.glfwSetScrollCallback(this.windowPointer, null);
|
|
||||||
GLFW.glfwSetCharCallback(this.windowPointer, null);
|
|
||||||
|
|
||||||
this.scroll.free();
|
|
||||||
this.mouseButton.free();
|
|
||||||
this.keyboard.free();
|
|
||||||
this.cursorPosition.free();
|
|
||||||
this.charInput.free();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyboardInputCallback keyboard()
|
|
||||||
{
|
|
||||||
return instance().keyboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MouseButtonCallback mouseButtons()
|
|
||||||
{
|
|
||||||
return instance().mouseButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScrollInputCallback scroll()
|
|
||||||
{
|
|
||||||
return instance().scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CursorPositionCallback cursorPosition()
|
|
||||||
{
|
|
||||||
return instance().cursorPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KeyboardCharInput charInput()
|
|
||||||
{
|
|
||||||
return instance().charInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void resetStates()
|
|
||||||
{
|
|
||||||
var instance = instance();
|
|
||||||
|
|
||||||
instance.keyboard.resetPressed();
|
|
||||||
instance.mouseButton.reset();
|
|
||||||
instance.scroll.reset();
|
|
||||||
instance.cursorPosition.reset();
|
|
||||||
instance.charInput.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,81 +40,4 @@ public class InputBus extends PlutoLocalComponent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadSensitive(localContexts = true)
|
|
||||||
public static class Mouse
|
|
||||||
{
|
|
||||||
public static boolean clicked(int button)
|
|
||||||
{
|
|
||||||
return instance().mouseButton.buttonClicked[button];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean released(int button)
|
|
||||||
{
|
|
||||||
return instance().mouseButton.buttonReleased[button];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isButtonDown(int button)
|
|
||||||
{
|
|
||||||
return instance().mouseButton.buttonDown[button];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getX()
|
|
||||||
{
|
|
||||||
return instance().cursorPosition.getX();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getY()
|
|
||||||
{
|
|
||||||
return instance().cursorPosition.getY();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isInside(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
return instance().cursorPosition.isInside(x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getDX()
|
|
||||||
{
|
|
||||||
return instance().cursorPosition.getDeltaX();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getDY()
|
|
||||||
{
|
|
||||||
return instance().cursorPosition.getDeltaY();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getScrollX()
|
|
||||||
{
|
|
||||||
return instance().scroll.getXScroll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getScrollY()
|
|
||||||
{
|
|
||||||
return instance().scroll.getYScroll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ThreadSensitive(localContexts = true)
|
|
||||||
public static class Keyboard
|
|
||||||
{
|
|
||||||
public static boolean pressed(int key)
|
|
||||||
{
|
|
||||||
return instance().keyboard.hasBeenPressed(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean released(int key)
|
|
||||||
{
|
|
||||||
return instance().keyboard.hasBeenReleased(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isKeyDown(int key)
|
|
||||||
{
|
|
||||||
return instance().keyboard.isKeyDown(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getTypedText()
|
|
||||||
{
|
|
||||||
return instance().charInput.getTypedText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package org.plutoengine.input;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.plutoengine.component.PlutoLocalComponent;
|
||||||
|
import org.plutoengine.input.callback.KeyboardCharInput;
|
||||||
|
import org.plutoengine.input.callback.KeyboardInputCallback;
|
||||||
|
|
||||||
|
public class Keyboard extends PlutoLocalComponent
|
||||||
|
{
|
||||||
|
private final KeyboardInputCallback keyboard = new KeyboardInputCallback();
|
||||||
|
private final KeyboardCharInput charInput = new KeyboardCharInput();
|
||||||
|
|
||||||
|
private final long windowPointer;
|
||||||
|
|
||||||
|
Keyboard(long windowPointer)
|
||||||
|
{
|
||||||
|
this.windowPointer = windowPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyboardInputCallback keyboard()
|
||||||
|
{
|
||||||
|
return this.keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyboardCharInput charInput()
|
||||||
|
{
|
||||||
|
return this.charInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetStates()
|
||||||
|
{
|
||||||
|
this.keyboard.resetPressed();
|
||||||
|
this.charInput.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMount(ComponentDependencyManager manager)
|
||||||
|
{
|
||||||
|
GLFW.glfwSetKeyCallback(this.windowPointer, this.keyboard);
|
||||||
|
GLFW.glfwSetCharCallback(this.windowPointer, this.charInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onUnmount() throws Exception
|
||||||
|
{
|
||||||
|
GLFW.glfwSetKeyCallback(this.windowPointer, null);
|
||||||
|
GLFW.glfwSetCharCallback(this.windowPointer, null);
|
||||||
|
|
||||||
|
this.keyboard.free();
|
||||||
|
this.charInput.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean pressed(int key)
|
||||||
|
{
|
||||||
|
return this.keyboard.hasBeenPressed(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean released(int key)
|
||||||
|
{
|
||||||
|
return this.keyboard.hasBeenReleased(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKeyDown(int key)
|
||||||
|
{
|
||||||
|
return this.keyboard.isKeyDown(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypedText()
|
||||||
|
{
|
||||||
|
return this.charInput.getTypedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnique()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package org.plutoengine.input;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.plutoengine.component.PlutoLocalComponent;
|
||||||
|
import org.plutoengine.input.callback.CursorPositionCallback;
|
||||||
|
import org.plutoengine.input.callback.MouseButtonCallback;
|
||||||
|
import org.plutoengine.input.callback.ScrollInputCallback;
|
||||||
|
|
||||||
|
public class Mouse extends PlutoLocalComponent
|
||||||
|
{
|
||||||
|
private final MouseButtonCallback mouseButton = new MouseButtonCallback();
|
||||||
|
private final CursorPositionCallback cursorPosition = new CursorPositionCallback();
|
||||||
|
private final ScrollInputCallback scroll = new ScrollInputCallback();
|
||||||
|
|
||||||
|
private final long windowPointer;
|
||||||
|
|
||||||
|
Mouse(long windowPointer)
|
||||||
|
{
|
||||||
|
this.windowPointer = windowPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MouseButtonCallback mouseButtons()
|
||||||
|
{
|
||||||
|
return this.mouseButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScrollInputCallback scroll()
|
||||||
|
{
|
||||||
|
return this.scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CursorPositionCallback cursorPosition()
|
||||||
|
{
|
||||||
|
return this.cursorPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetStates()
|
||||||
|
{
|
||||||
|
this.mouseButton.reset();
|
||||||
|
this.scroll.reset();
|
||||||
|
this.cursorPosition.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMount(ComponentDependencyManager manager)
|
||||||
|
{
|
||||||
|
GLFW.glfwSetMouseButtonCallback(this.windowPointer, this.mouseButton);
|
||||||
|
GLFW.glfwSetCursorPosCallback(this.windowPointer, this.cursorPosition);
|
||||||
|
GLFW.glfwSetScrollCallback(this.windowPointer, this.scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onUnmount() throws Exception
|
||||||
|
{
|
||||||
|
GLFW.glfwSetMouseButtonCallback(this.windowPointer, null);
|
||||||
|
GLFW.glfwSetCursorPosCallback(this.windowPointer, null);
|
||||||
|
GLFW.glfwSetScrollCallback(this.windowPointer, null);
|
||||||
|
|
||||||
|
this.mouseButton.free();
|
||||||
|
this.cursorPosition.free();
|
||||||
|
this.scroll.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean clicked(int button)
|
||||||
|
{
|
||||||
|
return this.mouseButton.buttonClicked[button];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean released(int button)
|
||||||
|
{
|
||||||
|
return this.mouseButton.buttonReleased[button];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isButtonDown(int button)
|
||||||
|
{
|
||||||
|
return this.mouseButton.buttonDown[button];
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX()
|
||||||
|
{
|
||||||
|
return this.cursorPosition.getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY()
|
||||||
|
{
|
||||||
|
return this.cursorPosition.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInside(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
return this.cursorPosition.isInside(x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDX()
|
||||||
|
{
|
||||||
|
return this.cursorPosition.getDeltaX();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDY()
|
||||||
|
{
|
||||||
|
return this.cursorPosition.getDeltaY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScrollX()
|
||||||
|
{
|
||||||
|
return this.scroll.getXScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScrollY()
|
||||||
|
{
|
||||||
|
return this.scroll.getYScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnique()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package org.plutoengine.input;
|
package org.plutoengine.input.callback;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFWCursorPosCallback;
|
import org.lwjgl.glfw.GLFWCursorPosCallback;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.plutoengine.input;
|
package org.plutoengine.input.callback;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFWCharCallback;
|
import org.lwjgl.glfw.GLFWCharCallback;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.plutoengine.input;
|
package org.plutoengine.input.callback;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFWKeyCallback;
|
import org.lwjgl.glfw.GLFWKeyCallback;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.plutoengine.input;
|
package org.plutoengine.input.callback;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
import org.lwjgl.glfw.GLFWMouseButtonCallback;
|
import org.lwjgl.glfw.GLFWMouseButtonCallback;
|
|
@ -1,4 +1,4 @@
|
||||||
package org.plutoengine.input;
|
package org.plutoengine.input.callback;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFWScrollCallback;
|
import org.lwjgl.glfw.GLFWScrollCallback;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import org.lwjgl.opengl.*;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import org.plutoengine.Pluto;
|
import org.plutoengine.Pluto;
|
||||||
import org.plutoengine.address.ThreadSensitive;
|
import org.plutoengine.annotation.ThreadSensitive;
|
||||||
import org.plutoengine.component.PlutoLocalComponent;
|
import org.plutoengine.component.PlutoLocalComponent;
|
||||||
import org.plutoengine.gl.GLDebugInfo;
|
import org.plutoengine.gl.GLDebugInfo;
|
||||||
import org.plutoengine.logger.Logger;
|
import org.plutoengine.logger.Logger;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.plutoengine;
|
package org.plutoengine;
|
||||||
|
|
||||||
import org.plutoengine.address.ThreadSensitive;
|
import org.plutoengine.annotation.ThreadSensitive;
|
||||||
import org.plutoengine.component.PlutoLocalComponent;
|
import org.plutoengine.component.PlutoLocalComponent;
|
||||||
import org.plutoengine.component.ComponentManager;
|
import org.plutoengine.component.ComponentManager;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package org.plutoengine;
|
package org.plutoengine;
|
||||||
|
|
||||||
import org.plutoengine.address.ConstantExpression;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public final class PlutoVersion implements IVersion<PlutoVersion>
|
public final class PlutoVersion implements IVersion<PlutoVersion>
|
||||||
|
@ -75,12 +74,11 @@ public final class PlutoVersion implements IVersion<PlutoVersion>
|
||||||
return this.prereleaseNumber;
|
return this.prereleaseNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConstantExpression
|
public static PlutoVersion of(@NotNull String str)
|
||||||
public static PlutoVersion of(@Nonnull String str)
|
|
||||||
{
|
{
|
||||||
assert !str.isBlank();
|
assert !str.isBlank();
|
||||||
|
|
||||||
assert str.matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+([+\\-][a-zA-Z0-9]+(\\.[0-9]+)?)?");
|
assert str.matches("\\d+\\.\\d+\\.\\d+\\.\\d+([+\\-][a-zA-Z\\d]+(\\.\\d+)?)?");
|
||||||
|
|
||||||
var parts = str.split("[+\\-]");
|
var parts = str.split("[+\\-]");
|
||||||
|
|
||||||
|
@ -141,7 +139,7 @@ public final class PlutoVersion implements IVersion<PlutoVersion>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(@Nonnull PlutoVersion o)
|
public int compareTo(@NotNull PlutoVersion o)
|
||||||
{
|
{
|
||||||
int yearDiff = this.year - o.year;
|
int yearDiff = this.year - o.year;
|
||||||
if (yearDiff != 0)
|
if (yearDiff != 0)
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package org.plutoengine.address;
|
|
||||||
|
|
||||||
import javax.annotation.meta.TypeQualifier;
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Denotes that the target field or method should be a constant expression - it is final, has no state
|
|
||||||
* and always yields the same deterministic result for given input. Generally, annotated methods
|
|
||||||
* should be thread-safe, however this is not required.
|
|
||||||
*
|
|
||||||
* @author 493msi
|
|
||||||
*
|
|
||||||
* @since 20.2.0.0-alpha.3
|
|
||||||
* */
|
|
||||||
@TypeQualifier
|
|
||||||
@Documented
|
|
||||||
@Retention(RetentionPolicy.CLASS)
|
|
||||||
@Target({ ElementType.METHOD, ElementType.FIELD })
|
|
||||||
public @interface ConstantExpression
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,9 +1,6 @@
|
||||||
package org.plutoengine.address;
|
package org.plutoengine.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.*;
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -22,6 +19,7 @@ import java.lang.annotation.Target;
|
||||||
*/
|
*/
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@Inherited
|
||||||
public @interface ThreadSensitive
|
public @interface ThreadSensitive
|
||||||
{
|
{
|
||||||
/**
|
/**
|
|
@ -1,5 +1,5 @@
|
||||||
package org.plutoengine.component;
|
package org.plutoengine.component;
|
||||||
|
|
||||||
public abstract class PlutoGlobalComponent extends AbstractComponent
|
public abstract class PlutoGlobalComponent extends AbstractComponent<PlutoGlobalComponent>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package org.plutoengine.component;
|
package org.plutoengine.component;
|
||||||
|
|
||||||
public abstract class PlutoLocalComponent extends AbstractComponent
|
import org.plutoengine.annotation.ThreadSensitive;
|
||||||
|
|
||||||
|
@ThreadSensitive(localContexts = true)
|
||||||
|
public abstract class PlutoLocalComponent extends AbstractComponent<PlutoLocalComponent>
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package org.plutoengine.logger;
|
package org.plutoengine.logger;
|
||||||
|
|
||||||
|
import org.plutoengine.component.ComponentToken;
|
||||||
|
import org.plutoengine.component.PlutoGlobalComponent;
|
||||||
|
import org.plutoengine.resource.filesystem.ResourceManager;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import org.plutoengine.component.ComponentToken;
|
|
||||||
import org.plutoengine.component.PlutoGlobalComponent;
|
|
||||||
import org.plutoengine.resource.filesystem.ResourceManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* A simple static logger writing to both standard output and a log file.
|
* A simple static logger writing to both standard output and a log file.
|
||||||
|
@ -48,7 +48,7 @@ public class Logger extends PlutoGlobalComponent
|
||||||
* @since pre-alpha
|
* @since pre-alpha
|
||||||
* */
|
* */
|
||||||
@Override
|
@Override
|
||||||
public void onMount() throws Exception
|
protected void onMount(ComponentDependencyManager manager) throws Exception
|
||||||
{
|
{
|
||||||
this.onUnmount();
|
this.onUnmount();
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ public class Logger extends PlutoGlobalComponent
|
||||||
* @since pre-alpha
|
* @since pre-alpha
|
||||||
* */
|
* */
|
||||||
@Override
|
@Override
|
||||||
public void onUnmount() throws Exception
|
protected void onUnmount() throws Exception
|
||||||
{
|
{
|
||||||
if (fileLog != null)
|
if (fileLog != null)
|
||||||
fileLog.close();
|
fileLog.close();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.plutoengine.logger;
|
package org.plutoengine.logger;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
@ -37,14 +38,14 @@ public class OutputSplitStream extends OutputStream
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@Nonnull byte[] b) throws IOException
|
public void write(byte @NotNull [] b) throws IOException
|
||||||
{
|
{
|
||||||
this.outputStreamA.write(b);
|
this.outputStreamA.write(b);
|
||||||
this.outputStreamB.write(b);
|
this.outputStreamB.write(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(@Nonnull byte[] b, int off, int len) throws IOException
|
public void write(byte @NotNull [] b, int off, int len) throws IOException
|
||||||
{
|
{
|
||||||
this.outputStreamA.write(b, off, len);
|
this.outputStreamA.write(b, off, len);
|
||||||
this.outputStreamB.write(b, off, len);
|
this.outputStreamB.write(b, off, len);
|
||||||
|
|
|
@ -3,19 +3,15 @@ package org.plutoengine.resource.filesystem;
|
||||||
import org.plutoengine.address.VirtualAddress;
|
import org.plutoengine.address.VirtualAddress;
|
||||||
import org.plutoengine.mod.Mod;
|
import org.plutoengine.mod.Mod;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileSystems;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.ProviderNotFoundException;
|
import java.nio.file.ProviderNotFoundException;
|
||||||
import java.nio.file.spi.FileSystemProvider;
|
import java.nio.file.spi.FileSystemProvider;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.ServiceConfigurationError;
|
import java.util.ServiceConfigurationError;
|
||||||
import java.util.ServiceLoader;
|
|
||||||
|
|
||||||
@ThreadSafe
|
|
||||||
public class ResourceManager implements Closeable
|
public class ResourceManager implements Closeable
|
||||||
{
|
{
|
||||||
public static final Path GLOBAL_ROOT = Path.of("");
|
public static final Path GLOBAL_ROOT = Path.of("");
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
package org.plutoengine.tpl;
|
package org.plutoengine.tpl;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import org.lwjgl.BufferUtils;
|
import org.lwjgl.BufferUtils;
|
||||||
import org.plutoengine.logger.Logger;
|
import org.plutoengine.logger.Logger;
|
||||||
import org.plutoengine.logger.SmartSeverity;
|
import org.plutoengine.logger.SmartSeverity;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.DataBufferByte;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quick ABGR (8-bit per channel, 32 bits per pixel) and grayscale image loader for OpenGL textures.
|
* Quick ABGR (8-bit per channel, 32 bits per pixel) and grayscale image loader for OpenGL textures.
|
||||||
* Color component swizzling may be needed.
|
* Color component swizzling may be needed.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.plutoengine.graphics.ImmediateFontRenderer;
|
||||||
import org.plutoengine.graphics.PlutoGUIMod;
|
import org.plutoengine.graphics.PlutoGUIMod;
|
||||||
import org.plutoengine.graphics.RectangleRenderer2D;
|
import org.plutoengine.graphics.RectangleRenderer2D;
|
||||||
import org.plutoengine.graphics.gui.FontShader;
|
import org.plutoengine.graphics.gui.FontShader;
|
||||||
import org.plutoengine.input.InputBus;
|
import org.plutoengine.input.Keyboard;
|
||||||
import org.plutoengine.libra.paint.LiGradientPaint;
|
import org.plutoengine.libra.paint.LiGradientPaint;
|
||||||
import org.plutoengine.libra.paint.LiPaint;
|
import org.plutoengine.libra.paint.LiPaint;
|
||||||
import org.plutoengine.libra.text.shaping.TextStyleOptions;
|
import org.plutoengine.libra.text.shaping.TextStyleOptions;
|
||||||
|
@ -92,7 +92,7 @@ public class Main extends PlutoApplication
|
||||||
welcomeStyle.setPaint(LiPaint.horizontaLinearGradient(stops));
|
welcomeStyle.setPaint(LiPaint.horizontaLinearGradient(stops));
|
||||||
ImmediateFontRenderer.drawString(0, 100, "Welcome to PlutoEngine v. %s!".formatted(Pluto.VERSION), BasicApplicationDemoMod.font, welcomeStyle);
|
ImmediateFontRenderer.drawString(0, 100, "Welcome to PlutoEngine v. %s!".formatted(Pluto.VERSION), BasicApplicationDemoMod.font, welcomeStyle);
|
||||||
|
|
||||||
if (InputBus.Keyboard.pressed(GLFW.GLFW_KEY_R))
|
if (PlutoLocal.components().getComponent(Keyboard.class).pressed(GLFW.GLFW_KEY_R))
|
||||||
{
|
{
|
||||||
var shader = PlutoGUIMod.fontShader;
|
var shader = PlutoGUIMod.fontShader;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue