diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java b/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java index e272adcc..9713a0ac 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java @@ -7,6 +7,7 @@ import com.bartlomiejpluta.base.api.character.Character; import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.gui.GUI; +import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.map.model.GameMap; @@ -43,6 +44,8 @@ public interface Context extends Updatable, Renderable, Disposable { Animation createAnimation(String animationUid); + Icon createIcon(String iconSetUid, int row, int column); + Image getImage(String imageUid); GUI newGUI(); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java b/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java new file mode 100644 index 00000000..0a90e122 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java @@ -0,0 +1,9 @@ +package com.bartlomiejpluta.base.api.icon; + +import com.bartlomiejpluta.base.api.entity.Entity; + +public interface Icon extends Entity { + void changeIcon(int row, int column); + + void changeIcon(String iconSetUid, int row, int column); +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/manager/DefaultContextManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/manager/DefaultContextManager.java index 3a1bf2e8..753202a1 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/manager/DefaultContextManager.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/manager/DefaultContextManager.java @@ -16,6 +16,8 @@ import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader; import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterSetManager; +import com.bartlomiejpluta.base.engine.world.icon.manager.IconManager; +import com.bartlomiejpluta.base.engine.world.icon.manager.IconSetManager; import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; import com.bartlomiejpluta.base.engine.world.tileset.manager.TileSetManager; @@ -37,8 +39,10 @@ public class DefaultContextManager implements ContextManager { private final ImageManager imageManager; private final CharacterSetManager characterSetManager; private final FontManager fontManager; + private final IconSetManager iconSetManager; private final CharacterManager characterManager; private final AnimationManager animationManager; + private final IconManager iconManager; private final ClassLoader classLoader; private final Inflater inflater; private final WidgetDefinitionManager widgetDefinitionManager; @@ -58,6 +62,7 @@ public class DefaultContextManager implements ContextManager { project.getImageAssets().forEach(imageManager::registerAsset); project.getCharacterSetAssets().forEach(characterSetManager::registerAsset); project.getAnimationAssets().forEach(animationManager::registerAsset); + project.getIconSetAssets().forEach(iconSetManager::registerAsset); project.getFontAssets().forEach(fontManager::registerAsset); project.getWidgetDefinitionAssets().forEach(widgetDefinitionManager::registerAsset); project.getSoundAssets().forEach(soundManager::registerAsset); @@ -70,17 +75,18 @@ public class DefaultContextManager implements ContextManager { var context = DefaultContext.builder() .engine(engine) .characterManager(characterManager) - .animationManager(animationManager) - .imageManager(imageManager) - .mapManager(mapManager) - .fontManager(fontManager) - .inflater(inflater) - .widgetDefinitionManager(widgetDefinitionManager) - .soundManager(soundManager) - .databaseService(databaseService) - .gameRunner(gameRunner) - .projectName(project.getName()) - .build(); + .animationManager(animationManager) + .iconManager(iconManager) + .imageManager(imageManager) + .mapManager(mapManager) + .fontManager(fontManager) + .inflater(inflater) + .widgetDefinitionManager(widgetDefinitionManager) + .soundManager(soundManager) + .databaseService(databaseService) + .gameRunner(gameRunner) + .projectName(project.getName()) + .build(); ContextHolder.INSTANCE.setContext(context); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java index c77810b8..500982d6 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java @@ -9,6 +9,7 @@ import com.bartlomiejpluta.base.api.context.GamePauseEvent; import com.bartlomiejpluta.base.api.event.Event; import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.gui.GUI; +import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.map.handler.MapHandler; @@ -23,6 +24,7 @@ import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI; import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater; import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterManager; +import com.bartlomiejpluta.base.engine.world.icon.manager.IconManager; import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap; @@ -55,6 +57,9 @@ public class DefaultContext implements Context { @NonNull private final AnimationManager animationManager; + @NonNull + private final IconManager iconManager; + @NonNull private final ImageManager imageManager; @@ -146,16 +151,20 @@ public class DefaultContext implements Context { } @Override - public Character createCharacter(String characterSetUid) { - log.info("Creating new character with UID: [{}]", characterSetUid); + public Character createCharacter(@NonNull String characterSetUid) { return characterManager.createCharacter(characterSetUid); } @Override - public Animation createAnimation(String animationUid) { + public Animation createAnimation(@NonNull String animationUid) { return animationManager.loadObject(animationUid); } + @Override + public Icon createIcon(@NonNull String iconSetUid, int row, int column) { + return iconManager.createIcon(iconSetUid, row, column); + } + @Override public Image getImage(@NonNull String imageUid) { return imageManager.loadObject(imageUid); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/Project.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/Project.java index fdf325f4..c58d07d3 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/Project.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/Project.java @@ -5,6 +5,7 @@ import com.bartlomiejpluta.base.engine.gui.asset.FontAsset; import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset; import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset; import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset; +import com.bartlomiejpluta.base.engine.world.icon.asset.IconSetAsset; import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset; import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset; import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset; @@ -39,6 +40,9 @@ public class Project { @NonNull private final List animationAssets; + @NonNull + private final List iconSetAssets; + @NonNull private final List fontAssets; diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/serial/ProtobufProjectDeserializer.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/serial/ProtobufProjectDeserializer.java index 31bc11b4..aabf4851 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/serial/ProtobufProjectDeserializer.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/serial/ProtobufProjectDeserializer.java @@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.engine.gui.asset.WidgetDefinitionAsset; import com.bartlomiejpluta.base.engine.project.model.Project; import com.bartlomiejpluta.base.engine.world.animation.asset.AnimationAsset; import com.bartlomiejpluta.base.engine.world.character.asset.CharacterSetAsset; +import com.bartlomiejpluta.base.engine.world.icon.asset.IconSetAsset; import com.bartlomiejpluta.base.engine.world.image.asset.ImageAsset; import com.bartlomiejpluta.base.engine.world.map.asset.GameMapAsset; import com.bartlomiejpluta.base.engine.world.tileset.asset.TileSetAsset; @@ -30,11 +31,12 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer { .mapAssets(proto.getMapsList().stream().map(this::parseGameMapAsset).collect(toList())) .imageAssets(proto.getImagesList().stream().map(this::parseImageAsset).collect(toList())) .characterSetAssets(proto.getCharacterSetsList().stream().map(this::parseCharacterSetAsset).collect(toList())) - .animationAssets(proto.getAnimationsList().stream().map(this::parseAnimationAsset).collect(toList())) - .fontAssets(proto.getFontsList().stream().map(this::parseFontAsset).collect(toList())) - .widgetDefinitionAssets(proto.getWidgetsList().stream().map(this::parseWidgetAsset).collect(toList())) - .soundAssets(proto.getSoundsList().stream().map(this::parseSoundAsset).collect(toList())) - .build(); + .animationAssets(proto.getAnimationsList().stream().map(this::parseAnimationAsset).collect(toList())) + .iconSetAssets(proto.getIconSetsList().stream().map(this::parseIconSetAsset).collect(toList())) + .fontAssets(proto.getFontsList().stream().map(this::parseFontAsset).collect(toList())) + .widgetDefinitionAssets(proto.getWidgetsList().stream().map(this::parseWidgetAsset).collect(toList())) + .soundAssets(proto.getSoundsList().stream().map(this::parseSoundAsset).collect(toList())) + .build(); } private TileSetAsset parseTileSetAsset(ProjectProto.TileSetAsset proto) { @@ -65,6 +67,10 @@ public class ProtobufProjectDeserializer extends ProjectDeserializer { return new AnimationAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns()); } + private IconSetAsset parseIconSetAsset(ProjectProto.IconSetAsset proto) { + return new IconSetAsset(proto.getUid(), proto.getSource(), proto.getRows(), proto.getColumns()); + } + private SoundAsset parseSoundAsset(ProjectProto.SoundAsset proto) { return new SoundAsset(proto.getUid(), proto.getSource()); } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/asset/IconSetAsset.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/asset/IconSetAsset.java new file mode 100644 index 00000000..1aa01b0e --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/asset/IconSetAsset.java @@ -0,0 +1,17 @@ +package com.bartlomiejpluta.base.engine.world.icon.asset; + +import com.bartlomiejpluta.base.engine.common.asset.Asset; +import lombok.Getter; +import lombok.NonNull; + +@Getter +public class IconSetAsset extends Asset { + private final int rows; + private final int columns; + + public IconSetAsset(@NonNull String uid, @NonNull String source, int rows, int columns) { + super(uid, source); + this.rows = rows; + this.columns = columns; + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/DefaultIconManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/DefaultIconManager.java new file mode 100644 index 00000000..df4a810a --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/DefaultIconManager.java @@ -0,0 +1,34 @@ +package com.bartlomiejpluta.base.engine.world.icon.manager; + +import com.bartlomiejpluta.base.api.icon.Icon; +import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; +import com.bartlomiejpluta.base.engine.util.mesh.MeshManager; +import com.bartlomiejpluta.base.engine.world.icon.model.DefaultIcon; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class DefaultIconManager implements IconManager { + private final MeshManager meshManager; + private final IconSetManager iconSetManager; + private Mesh mesh; + + @Override + public void init() { + this.mesh = meshManager.createQuad(1, 1, 0.5f, 1); + } + + @Override + public Icon createIcon(String iconSetUid, int row, int column) { + return new DefaultIcon(mesh, iconSetManager, iconSetUid, row, column); + } + + @Override + public void cleanUp() { + log.info("There is nothing to clean up here"); + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/DefaultIconSetManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/DefaultIconSetManager.java new file mode 100644 index 00000000..c3ae55ee --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/DefaultIconSetManager.java @@ -0,0 +1,43 @@ +package com.bartlomiejpluta.base.engine.world.icon.manager; + +import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; +import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; +import com.bartlomiejpluta.base.engine.error.AppException; +import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; +import com.bartlomiejpluta.base.engine.world.icon.asset.IconSetAsset; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class DefaultIconSetManager implements IconSetManager { + private final TextureManager textureManager; + private final Map assets = new HashMap<>(); + private final ProjectConfiguration configuration; + + @Override + public void registerAsset(IconSetAsset asset) { + log.info("Registering [{}] icon set asset under UID: [{}]", asset.getSource(), asset.getUid()); + assets.put(asset.getUid(), asset); + } + + @Override + public Material loadObject(String uid) { + var asset = assets.get(uid); + + if (asset == null) { + throw new AppException("The icon set asset with UID: [%s] does not exist", uid); + } + + var source = configuration.projectFile("iconsets", asset.getSource()); + var texture = textureManager.loadTexture(source, asset.getRows(), asset.getColumns()); + + return Material.textured(texture); + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/IconManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/IconManager.java new file mode 100644 index 00000000..39e88141 --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/IconManager.java @@ -0,0 +1,9 @@ +package com.bartlomiejpluta.base.engine.world.icon.manager; + +import com.bartlomiejpluta.base.api.icon.Icon; +import com.bartlomiejpluta.base.engine.common.init.Initializable; +import com.bartlomiejpluta.base.internal.gc.Cleanable; + +public interface IconManager extends Initializable, Cleanable { + Icon createIcon(String iconSetUid, int row, int column); +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/IconSetManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/IconSetManager.java new file mode 100644 index 00000000..43c2adf0 --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/manager/IconSetManager.java @@ -0,0 +1,8 @@ +package com.bartlomiejpluta.base.engine.world.icon.manager; + +import com.bartlomiejpluta.base.engine.common.manager.AssetManager; +import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; +import com.bartlomiejpluta.base.engine.world.icon.asset.IconSetAsset; + +public interface IconSetManager extends AssetManager { +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/model/DefaultIcon.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/model/DefaultIcon.java new file mode 100644 index 00000000..aff77bb2 --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/icon/model/DefaultIcon.java @@ -0,0 +1,135 @@ +package com.bartlomiejpluta.base.engine.world.icon.model; + +import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.icon.Icon; +import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; +import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; +import com.bartlomiejpluta.base.engine.error.AppException; +import com.bartlomiejpluta.base.engine.world.icon.manager.IconSetManager; +import com.bartlomiejpluta.base.engine.world.location.LocationableSprite; +import com.bartlomiejpluta.base.lib.event.EventHandler; +import lombok.Getter; +import lombok.Setter; +import org.joml.Vector2f; +import org.joml.Vector2fc; + +public class DefaultIcon extends LocationableSprite implements Icon { + private final EventHandler eventHandler = new EventHandler(); + private final IconSetManager iconSetManager; + private final Vector2f iconScale = new Vector2f(1, 1); + private Vector2fc iconSetSize; + + @Setter + @Getter + private boolean blocking; + + @Getter + private ObjectLayer layer; + + @Setter + @Getter + private int zIndex; + + public DefaultIcon(Mesh mesh, IconSetManager iconSetManager, String iconSetUid, int row, int column) { + super(mesh, iconSetManager.loadObject(iconSetUid)); + this.iconSetManager = iconSetManager; + material.setSpritePosition(column, row); + + var texture = material.getTexture(); + if (texture != null) { + this.iconSetSize = texture.getSpriteSize(); + super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y); + } + } + + @Override + public void onAdd(ObjectLayer layer) { + this.layer = layer; + } + + @Override + public void onRemove(ObjectLayer layer) { + this.layer = null; + } + + @Override + public void handleEvent(E event) { + eventHandler.handleEvent(event); + } + + @Override + public void changeIcon(int row, int column) { + material.setSpritePosition(column, row); + } + + @Override + public void changeIcon(String iconSetUid, int row, int column) { + this.material = iconSetManager.loadObject(iconSetUid); + material.setSpritePosition(column, row); + + var texture = material.getTexture(); + if (texture != null) { + this.iconSetSize = texture.getSpriteSize(); + super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y); + } else { + this.iconSetSize = null; + } + } + + @Override + public void setScaleX(float scaleX) { + if (iconSetSize == null) { + throw new AppException("Cannot change Icon scale if no Icon Set is provided"); + } + + this.iconScale.x = scaleX; + super.setScaleX(iconSetSize.x() * scaleX); + } + + @Override + public void setScaleY(float scaleY) { + if (iconSetSize == null) { + throw new AppException("Cannot change Icon scale if no Icon Set is provided"); + } + + this.iconScale.y = scaleY; + super.setScaleY(iconSetSize.y() * scaleY); + } + + @Override + public void setScale(float scale) { + if (iconSetSize == null) { + throw new AppException("Cannot change Icon scale if no Icon Set is provided"); + } + + this.iconScale.x = scale; + this.iconScale.y = scale; + super.setScale(iconSetSize.x() * scale, iconSetSize.y() * scale); + } + + @Override + public void setScale(float scaleX, float scaleY) { + if (iconSetSize == null) { + throw new AppException("Cannot change Icon scale if no Icon Set is provided"); + } + + this.iconScale.x = scaleX; + this.iconScale.y = scaleY; + super.setScale(iconSetSize.x() * scaleX, iconSetSize.y() * scaleY); + } + + @Override + public float getScaleX() { + return iconScale.x; + } + + @Override + public float getScaleY() { + return iconScale.y; + } + + @Override + public void update(float dt) { + // noop + } +}