Enable full support for icon sets in GUI

This commit is contained in:
2022-08-24 12:25:23 +02:00
parent 20a2a5f1e7
commit 18010cbb0f
19 changed files with 293 additions and 60 deletions

View File

@@ -33,6 +33,11 @@ public class DefaultSoundManager implements SoundManager {
assets.put(asset.getUid(), asset);
}
@Override
public SoundAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public Sound loadObject(String uid) {
if (!loadedBuffers.contains(uid)) {

View File

@@ -3,5 +3,7 @@ package com.bartlomiejpluta.base.engine.common.manager;
public interface AssetManager<A, T> {
void registerAsset(A asset);
A getAsset(String uid);
T loadObject(String uid);
}

View File

@@ -77,6 +77,7 @@ public class DefaultContextManager implements ContextManager {
.characterManager(characterManager)
.animationManager(animationManager)
.iconManager(iconManager)
.iconSetManager(iconSetManager)
.imageManager(imageManager)
.mapManager(mapManager)
.fontManager(fontManager)

View File

@@ -27,6 +27,7 @@ import com.bartlomiejpluta.base.engine.world.animation.manager.AnimationManager;
import com.bartlomiejpluta.base.engine.world.character.manager.CharacterManager;
import com.bartlomiejpluta.base.engine.world.entity.AbstractEntity;
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.map.model.DefaultGameMap;
@@ -62,6 +63,9 @@ public class DefaultContext implements Context {
@NonNull
private final IconManager iconManager;
@NonNull
private final IconSetManager iconSetManager;
@NonNull
private final ImageManager imageManager;
@@ -180,7 +184,7 @@ public class DefaultContext implements Context {
@Override
public GUI newGUI() {
log.info("Creating new GUI");
var gui = new NanoVGGUI(this, fontManager, imageManager, inflater, widgetDefinitionManager);
var gui = new NanoVGGUI(this, fontManager, imageManager, iconSetManager, inflater, widgetDefinitionManager);
guis.add(gui);
gui.init(screen);

View File

@@ -26,6 +26,11 @@ public class DefaultWidgetDefinitionManager implements WidgetDefinitionManager {
assets.put(asset.getUid(), asset);
}
@Override
public WidgetDefinitionAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public InputStream loadObject(String uid) {
var asset = assets.get(uid);

View File

@@ -9,6 +9,7 @@ import com.bartlomiejpluta.base.engine.gui.manager.FontManager;
import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager;
import com.bartlomiejpluta.base.engine.gui.widget.ScreenWidget;
import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater;
import com.bartlomiejpluta.base.engine.world.icon.manager.IconSetManager;
import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager;
import com.bartlomiejpluta.base.internal.render.ShaderManager;
import lombok.Getter;
@@ -33,6 +34,7 @@ public class NanoVGGUI implements GUI {
private final Context context;
private final FontManager fontManager;
private final ImageManager imageManager;
private final IconSetManager iconSetManager;
private final Inflater inflater;
private final WidgetDefinitionManager widgetDefinitionManager;
@@ -43,6 +45,7 @@ public class NanoVGGUI implements GUI {
private final List<NanoVGPaint> paints = new LinkedList<>();
private final Set<String> loadedFonts = new HashSet<>();
private final Map<String, NanoVGImage> loadedImages = new HashMap<>();
private final Map<String, NanoVGIconSet> loadedIconSets = new HashMap<>();
private boolean visible = true;
@@ -160,6 +163,28 @@ public class NanoVGGUI implements GUI {
return image;
}
@Override
public IconSet getIconSet(String iconSetUid) {
var iconSet = loadedIconSets.get(iconSetUid);
if (iconSet == null) {
log.info("Loading GUI icon set with UID: [{}] into cache under the key: [{}]", iconSetUid, iconSetUid);
var data = iconSetManager.loadObjectByteBuffer(iconSetUid);
var asset = iconSetManager.getAsset(iconSetUid);
var handle = nvgCreateImageMem(nvg, 0, data);
var width = new int[1];
var height = new int[1];
nvgImageSize(nvg, handle, width, height);
log.info("GUI icon set with UID: [{}], size {}x{} and flags [0b{}] has been loaded", iconSetUid, width[0], height[0], toBinaryString(0));
iconSet = new NanoVGIconSet(handle, width[0], height[0], asset.getRows(), asset.getColumns());
loadedIconSets.put(iconSetUid, iconSet);
}
return iconSet;
}
@Override
public void beginPath() {
nvgBeginPath(nvg);
@@ -282,76 +307,49 @@ public class NanoVGGUI implements GUI {
@Override
public void boxGradient(float x, float y, float width, float height, float radius, float feather, Color inner, Color outer, Paint target) {
nvgBoxGradient(
nvg,
x,
y,
width,
height,
radius,
feather,
((NanoVGColor) inner).getColor(),
((NanoVGColor) outer).getColor(),
((NanoVGPaint) target).getPaint()
);
nvgBoxGradient(nvg, x, y, width, height, radius, feather, ((NanoVGColor) inner).getColor(), ((NanoVGColor) outer).getColor(), ((NanoVGPaint) target).getPaint());
}
@Override
public void linearGradient(float x, float y, float endX, float endY, Color start, Color end, Paint target) {
nvgLinearGradient(
nvg,
x,
y,
endX,
endY,
((NanoVGColor) start).getColor(),
((NanoVGColor) end).getColor(),
((NanoVGPaint) target).getPaint()
);
nvgLinearGradient(nvg, x, y, endX, endY, ((NanoVGColor) start).getColor(), ((NanoVGColor) end).getColor(), ((NanoVGPaint) target).getPaint());
}
@Override
public void radialGradient(float x, float y, float innerRadius, float outerRadius, Color start, Color end, Paint target) {
nvgRadialGradient(
nvg,
x,
y,
innerRadius,
outerRadius,
((NanoVGColor) start).getColor(),
((NanoVGColor) end).getColor(),
((NanoVGPaint) target).getPaint()
);
nvgRadialGradient(nvg, x, y, innerRadius, outerRadius, ((NanoVGColor) start).getColor(), ((NanoVGColor) end).getColor(), ((NanoVGPaint) target).getPaint());
}
@Override
public void imagePattern(float x, float y, float angle, float alpha, Image image, Paint target) {
nvgImagePattern(
nvg,
x,
y,
image.getWidth(),
image.getHeight(),
angle,
((NanoVGImage) image).getImageHandle(),
alpha,
((NanoVGPaint) target).getPaint()
);
public Paint imagePattern(float x, float y, float angle, float alpha, Image image, Paint target) {
return new NanoVGPaint(nvgImagePattern(nvg, x, y, image.getWidth(), image.getHeight(), angle, ((NanoVGImage) image).getImageHandle(), alpha, ((NanoVGPaint) target).getPaint()));
}
@Override
public void imagePattern(float x, float y, float width, float height, float angle, float alpha, Image image, Paint target) {
nvgImagePattern(
nvg,
x,
y,
width,
height,
angle,
((NanoVGImage) image).getImageHandle(),
alpha,
((NanoVGPaint) target).getPaint()
);
public Paint imagePattern(float x, float y, float width, float height, float angle, float alpha, Image image, Paint target) {
return new NanoVGPaint(nvgImagePattern(nvg, x, y, width, height, angle, ((NanoVGImage) image).getImageHandle(), alpha, ((NanoVGPaint) target).getPaint()));
}
@Override
public void image(float x, float y, float scaleX, float scaleY, float angle, float alpha, Image image, Paint target) {
var width = image.getWidth() * scaleX;
var height = image.getHeight() * scaleY;
nvgBeginPath(nvg);
nvgRect(nvg, x, y, width, height);
nvgFillPaint(nvg, nvgImagePattern(nvg, x, y, width, height, angle, ((NanoVGImage) image).getImageHandle(), alpha, ((NanoVGPaint) target).getPaint()));
nvgFill(nvg);
nvgClosePath(nvg);
}
@Override
public void icon(float x, float y, float scaleX, float scaleY, float angle, float alpha, IconSet iconSet, int row, int column, Paint target) {
var width = iconSet.getIconWidth() * scaleX;
var height = iconSet.getIconHeight() * scaleY;
nvgBeginPath(nvg);
nvgRect(nvg, x, y, width, height);
nvgFillPaint(nvg, nvgImagePattern(nvg, x - width * column, y - height * row, width * iconSet.getColumns(), height * iconSet.getRows(), angle, ((NanoVGIconSet) iconSet).getImageHandle(), alpha, ((NanoVGPaint) target).getPaint()));
nvgFill(nvg);
nvgClosePath(nvg);
}
@Override
@@ -436,6 +434,10 @@ public class NanoVGGUI implements GUI {
loadedImages.values().stream().map(NanoVGImage::getImageHandle).forEach(h -> nvgDeleteImage(nvg, h));
log.info("Disposed {} GUI images", loadedImages.size());
log.info("Disposing GUI icon sets");
loadedIconSets.values().stream().map(NanoVGIconSet::getImageHandle).forEach(h -> nvgDeleteImage(nvg, h));
log.info("Disposed {} GUI icon sets", loadedIconSets.size());
log.info("Disposing GUI nvg");
nvgDelete(nvg);
}

View File

@@ -0,0 +1,29 @@
package com.bartlomiejpluta.base.engine.gui.render;
import com.bartlomiejpluta.base.api.gui.IconSet;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
@EqualsAndHashCode
public class NanoVGIconSet implements IconSet {
private final int imageHandle;
private final int width;
private final int height;
private final int rows;
private final int columns;
private final int iconWidth;
private final int iconHeight;
public NanoVGIconSet(int imageHandle, int width, int height, int rows, int columns) {
this.imageHandle = imageHandle;
this.width = width;
this.height = height;
this.rows = rows;
this.columns = columns;
this.iconWidth = width / columns;
this.iconHeight = height / rows;
}
}

View File

@@ -41,6 +41,11 @@ public class DefaultAnimationManager implements AnimationManager {
assets.put(asset.getUid(), asset);
}
@Override
public AnimationAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public Animation loadObject(String uid) {
var asset = assets.get(uid);

View File

@@ -27,6 +27,11 @@ public class DefaultCharacterSetManager implements CharacterSetManager {
assets.put(asset.getUid(), asset);
}
@Override
public CharacterSetAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public Material loadObject(String uid) {
var asset = assets.get(uid);

View File

@@ -4,12 +4,14 @@ 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.util.res.ResourcesManager;
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.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
@@ -18,7 +20,10 @@ import java.util.Map;
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DefaultIconSetManager implements IconSetManager {
private final TextureManager textureManager;
private final ResourcesManager resourcesManager;
private final Map<String, IconSetAsset> assets = new HashMap<>();
private final Map<String, ByteBuffer> iconSets = new HashMap<>();
private final ProjectConfiguration configuration;
@Override
@@ -27,6 +32,11 @@ public class DefaultIconSetManager implements IconSetManager {
assets.put(asset.getUid(), asset);
}
@Override
public IconSetAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public Material loadObject(String uid) {
var asset = assets.get(uid);
@@ -40,4 +50,24 @@ public class DefaultIconSetManager implements IconSetManager {
return Material.textured(texture);
}
@Override
public ByteBuffer loadObjectByteBuffer(String uid) {
var buffer = iconSets.get(uid);
if (buffer == null) {
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());
buffer = resourcesManager.loadResourceAsByteBuffer(source);
log.info("Loading icon set from assets to cache under the key: [{}]", uid);
iconSets.put(uid, buffer);
}
return buffer.duplicate();
}
}

View File

@@ -1,8 +1,9 @@
package com.bartlomiejpluta.base.engine.world.icon.manager;
import com.bartlomiejpluta.base.engine.common.manager.AssetManager;
import com.bartlomiejpluta.base.engine.common.manager.ByteBufferAssetManager;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.world.icon.asset.IconSetAsset;
public interface IconSetManager extends AssetManager<IconSetAsset, Material> {
public interface IconSetManager extends AssetManager<IconSetAsset, Material>, ByteBufferAssetManager<IconSetAsset> {
}

View File

@@ -19,6 +19,15 @@ public class DefaultIcon extends Sprite implements Icon {
private final Vector2f iconScale = new Vector2f(1, 1);
private Vector2fc iconSetSize;
@Getter
private String iconSetUid;
@Getter
private int iconSetRow;
@Getter
private int iconSetColumn;
@Setter
@Getter
private boolean blocking;
@@ -40,6 +49,10 @@ public class DefaultIcon extends Sprite implements Icon {
this.iconSetSize = texture.getSpriteSize();
super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y);
}
this.iconSetUid = iconSetUid;
this.iconSetRow = row;
this.iconSetColumn = column;
}
@Override
@@ -60,6 +73,8 @@ public class DefaultIcon extends Sprite implements Icon {
@Override
public void changeIcon(int row, int column) {
material.setSpritePosition(column, row);
this.iconSetRow = row;
this.iconSetColumn = column;
}
@Override
@@ -67,6 +82,10 @@ public class DefaultIcon extends Sprite implements Icon {
this.material = iconSetManager.loadObject(iconSetUid);
material.setSpritePosition(column, row);
this.iconSetUid = iconSetUid;
this.iconSetRow = row;
this.iconSetColumn = column;
var texture = material.getTexture();
if (texture != null) {
this.iconSetSize = texture.getSpriteSize();

View File

@@ -43,6 +43,11 @@ public class DefaultImageManager implements ImageManager {
assets.put(asset.getUid(), asset);
}
@Override
public ImageAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public Image loadObject(String uid) {
var asset = assets.get(uid);

View File

@@ -38,6 +38,11 @@ public class DefaultMapManager implements MapManager {
assets.put(asset.getUid(), asset);
}
@Override
public GameMapAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public DefaultGameMap loadObject(String uid) {
var map = maps.get(uid);

View File

@@ -37,6 +37,11 @@ public class DefaultTileSetManager implements TileSetManager {
assets.put(asset.getUid(), asset);
}
@Override
public TileSetAsset getAsset(String uid) {
return assets.get(uid);
}
@Override
public TileSet loadObject(String uid) {
var tileset = tileSets.get(uid);