Add support for Paint which includes gradients and images in GUI

This commit is contained in:
2021-03-14 22:51:33 +01:00
parent 1d8660ba7d
commit 3aac855fea
7 changed files with 274 additions and 2 deletions

View File

@@ -19,6 +19,10 @@ public interface GUI extends Renderable, Disposable, KeyEventHandler {
Color createColor();
Paint createPaint();
Image getImage(String imageUid);
void beginPath();
void closePath();
@@ -71,13 +75,25 @@ public interface GUI extends Renderable, Disposable, KeyEventHandler {
void setFillColor(Color color);
void setFillPaint(Paint paint);
void fill();
void setStrokeColor(Color color);
void setStrokePaint(Paint paint);
void setStrokeWidth(float width);
void stroke();
void boxGradient(float x, float y, float width, float height, float radius, float feather, Color inner, Color outer, Paint target);
void linearGradient(float x, float y, float endX, float endY, Color start, Color end, Paint target);
void radialGradient(float x, float y, float innerRadius, float outerRadius, Color start, Color end, Paint target);
void imagePattern(float x, float y, float width, float height, float angle, float alpha, Image image, Paint target);
void clip(float x, float y, float width, float height);
}

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.base.api.game.gui.base;
public interface Image {
int getWidth();
int getHeight();
}

View File

@@ -0,0 +1,4 @@
package com.bartlomiejpluta.base.api.game.gui.base;
public interface Paint {
}

View File

@@ -0,0 +1,99 @@
package com.bartlomiejpluta.base.api.game.gui.component;
import com.bartlomiejpluta.base.api.game.gui.base.GUI;
import com.bartlomiejpluta.base.api.game.gui.base.Image;
import com.bartlomiejpluta.base.api.game.gui.base.Paint;
import com.bartlomiejpluta.base.api.game.screen.Screen;
import static java.util.Objects.requireNonNull;
public class ImageView extends BaseComponent {
private final GUI gui;
private final Paint paint;
private Image image;
private float angle = 0;
private float opacity = 1;
private float scaleX = 1;
private float scaleY = 1;
public ImageView(GUI gui, String imageUid) {
this.gui = requireNonNull(gui);
this.paint = gui.createPaint();
this.image = gui.getImage(imageUid);
}
public void setImage(String imageUid) {
this.image = gui.getImage(imageUid);
}
public void setAngle(float angle) {
this.angle = angle;
}
public void setOpacity(float opacity) {
this.opacity = opacity;
}
public void setScaleX(float scaleX) {
this.scaleX = scaleX;
}
public void setScaleY(float scaleY) {
this.scaleY = scaleY;
}
public void setScale(float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
}
public void setScale(float scale) {
this.scaleX = scale;
this.scaleY = scale;
}
public Image getImage() {
return image;
}
public float getAngle() {
return angle;
}
public float getOpacity() {
return opacity;
}
public float getScaleX() {
return scaleX;
}
public float getScaleY() {
return scaleY;
}
@Override
protected float getContentWidth() {
return image.getWidth() * scaleX;
}
@Override
protected float getContentHeight() {
return image.getHeight() * scaleY;
}
@Override
public void draw(Screen screen, GUI gui) {
var posX = x + paddingLeft;
var posY = y + paddingTop;
var width = getWidth() - paddingLeft - paddingRight;
var height = getHeight() - paddingTop - paddingBottom;
gui.beginPath();
gui.drawRectangle(posX, posY, width, height);
gui.imagePattern(posX, posY, width, height, angle, opacity, image, paint);
gui.setFillPaint(paint);
gui.fill();
}
}

View File

@@ -13,6 +13,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.lwjgl.nanovg.NVGColor;
import org.lwjgl.nanovg.NVGPaint;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
@@ -32,8 +33,9 @@ public class NanoVGGUI implements GUI {
private ScreenWidget screenWidget;
private final List<NanoVGColor> colors = new LinkedList<>();
private final List<NanoVGPaint> paints = new LinkedList<>();
private final Set<String> loadedFonts = new HashSet<>();
private final Map<String, Integer> loadedImages = new HashMap<>();
private final Map<String, NanoVGImage> loadedImages = new HashMap<>();
public void init(Screen screen) {
context = nvgCreate(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
@@ -73,6 +75,35 @@ public class NanoVGGUI implements GUI {
return color;
}
@Override
public Paint createPaint() {
log.info("Creating new GUI paint");
var paint = new NanoVGPaint(NVGPaint.create());
paints.add(paint);
return paint;
}
@Override
public Image getImage(String imageUid) {
var image = loadedImages.get(imageUid);
if (image == null) {
log.info("Loading GUI image with UID: [{}]", imageUid);
var data = imageManager.loadObjectByteBuffer(imageUid);
var handle = nvgCreateImageMem(context, 0, data);
var width = new int[1];
var height = new int[1];
nvgImageSize(context, handle, width, height);
log.info("GUI image with UID: [{}] and size {}x{} has been loaded", imageUid, width, height);
image = new NanoVGImage(handle, width[0], height[0]);
loadedImages.put(imageUid, image);
}
return image;
}
@Override
public void beginPath() {
nvgBeginPath(context);
@@ -168,6 +199,11 @@ public class NanoVGGUI implements GUI {
nvgFillColor(context, ((NanoVGColor) color).getColor());
}
@Override
public void setFillPaint(Paint paint) {
nvgFillPaint(context, ((NanoVGPaint) paint).getPaint());
}
@Override
public void fill() {
nvgFill(context);
@@ -178,11 +214,75 @@ public class NanoVGGUI implements GUI {
nvgStrokeColor(context, ((NanoVGColor) color).getColor());
}
@Override
public void setStrokePaint(Paint paint) {
nvgStrokePaint(context, ((NanoVGPaint) paint).getPaint());
}
@Override
public void stroke() {
nvgStroke(context);
}
@Override
public void boxGradient(float x, float y, float width, float height, float radius, float feather, Color inner, Color outer, Paint target) {
nvgBoxGradient(
context,
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(
context,
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(
context,
x,
y,
innerRadius,
outerRadius,
((NanoVGColor) start).getColor(),
((NanoVGColor) end).getColor(),
((NanoVGPaint) target).getPaint()
);
}
@Override
public void imagePattern(float x, float y, float width, float height, float angle, float alpha, Image image, Paint target) {
nvgImagePattern(
context,
x,
y,
width,
height,
angle,
((NanoVGImage) image).getImageHandle(),
alpha,
((NanoVGPaint) target).getPaint()
);
}
@Override
public void setStrokeWidth(float width) {
nvgStrokeWidth(context, width);
@@ -255,7 +355,15 @@ public class NanoVGGUI implements GUI {
public void dispose() {
log.info("Disposing GUI color buffers");
colors.forEach(NanoVGColor::dispose);
log.info("Disposed {} GUI colors", colors.size());
log.info("Disposed {} GUI color buffers", colors.size());
log.info("Disposing GUI paint buffers");
paints.forEach(NanoVGPaint::dispose);
log.info("Disposed {} GUI paint buffers", paints.size());
log.info("Disposing GUI images");
loadedImages.values().stream().map(NanoVGImage::getImageHandle).forEach(h -> nvgDeleteImage(context, h));
log.info("Disposed {} GUI images", loadedImages.size());
log.info("Disposing GUI context");
nvgDelete(context);

View File

@@ -0,0 +1,17 @@
package com.bartlomiejpluta.base.engine.gui.render;
import com.bartlomiejpluta.base.api.game.gui.base.Image;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Getter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
public class NanoVGImage implements Image {
private final int imageHandle;
private final int width;
private final int height;
}

View File

@@ -0,0 +1,21 @@
package com.bartlomiejpluta.base.engine.gui.render;
import com.bartlomiejpluta.base.api.game.gui.base.Paint;
import com.bartlomiejpluta.base.api.internal.gc.Disposable;
import lombok.*;
import org.lwjgl.nanovg.NVGPaint;
@Getter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor
public class NanoVGPaint implements Paint, Disposable {
@NonNull
private final NVGPaint paint;
@Override
public void dispose() {
paint.free();
}
}