diff --git a/README.md b/README.md index cb76a79..13ed972 100755 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ version numbers.* ### Safe submodules * **PlutoCore** - Stable * **PlutoFramebuffer** - Stable - * **PlutoGUI** - Stable, awaiting a rewrite * **PlutoMesher** - Stable * **PlutoShader** - Stable * **PlutoTexture** - Stable @@ -34,6 +33,7 @@ version numbers.* * **PlutoLib** - Mostly stable ### Unstable submodules + * **PlutoGUI** - Recently rewritten, the API is highly unstable * **PlutoRuntime** - Somewhat tentative, the module API has been rewritten and might contain bugs * **PlutoAudio** - Somewhat usable, unfinished @@ -42,17 +42,25 @@ version numbers.* See `NEXT_RELEASE_DRAFT.md` for details. +### To be fixed +[ *Features or bugs that should be fixed **ASAP*** ] + * Implement gradient variation support for Libra fills + * Finish gradient rendering in FragmentFontShader.glsl + * Improve code quality in PlutoGUI + ### Very high priority [ *Implemented in the current release.* ] - * Streamline PlutoLib, remove bad APIs and improve code quality - * Improve image loading capabilities, possibly rewrite PlutoLib#TPL + * Improve image loading capabilities, possibly rewrite PlutoLib#TPL * The stage system and automated asset loading - * Rewrite PlutoGUI ### High priority [ *Implemented in the next release.* ] * Finish PlutoAudio * Depends on the stage system + * Expand upon the Color API + * Color mixing and blending + * Color transformation + * High-performance serialization ### Normal priority [ *Planned for an upcoming release.* ] @@ -68,7 +76,3 @@ See `NEXT_RELEASE_DRAFT.md` for details. * This feature requires a full rewrite and possibly a complete overhaul * Mods should have limited execution levels, for example restricted file access or disabled native library loading (this is probably not possible) - * Expand upon the Color API - * Color mixing and blending - * Color transformation - * High-performance serialization \ No newline at end of file diff --git a/UPDATE_NOTES.md b/UPDATE_NOTES.md index bda3289..f2d2407 100755 --- a/UPDATE_NOTES.md +++ b/UPDATE_NOTES.md @@ -12,6 +12,7 @@ * `[PlutoRuntime]` Fixed opening .zip filesystems * `[PlutoShader]` Added `UniformArrayFloat`, `UniformArrayRGBA`, `UniformArrayVec2`, `UniformArrayVec3`, `UniformArrayVec4` +* `[PlutoRuntime]` `SmartSeverity.MODULE_CHECK` now correctly uses the standard output instead of `stderr`. ## 22.0.0.0-alpha.7 * `[PlutoRuntime]` Fixed several resource filesystem bugs diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/ImmediateFontRenderer.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/ImmediateFontRenderer.java new file mode 100644 index 0000000..977f06d --- /dev/null +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/ImmediateFontRenderer.java @@ -0,0 +1,115 @@ +package org.plutoengine.graphics; + +import org.joml.Matrix3f; +import org.joml.primitives.Rectanglef; +import org.plutoengine.graphics.gui.PlutoGUICommandParser; +import org.plutoengine.graphics.gui.stbttf.STBTTBasicTextShaper; +import org.plutoengine.graphics.gui.stbttf.STBTTFont; +import org.plutoengine.libra.command.LiCommandBuffer; +import org.plutoengine.libra.command.impl.LiCommandSetTransform; +import org.plutoengine.libra.text.LiTextInfo; +import org.plutoengine.libra.text.font.LiFontFamily; +import org.plutoengine.libra.text.shaping.TextShaper; +import org.plutoengine.libra.text.shaping.TextStyleOptions; + +import java.util.EnumSet; + +public class ImmediateFontRenderer +{ + public static void drawString(float x, float y, String text, LiFontFamily font, TextStyleOptions style) + { + var shaper = new STBTTBasicTextShaper(); + var info = shaper.shape(EnumSet.of(TextShaper.EnumFeature.KERNING), font, text, style); + + draw(x, y, info, style); + } + + public static void drawStringNoKern(float x, float y, String text, LiFontFamily font, TextStyleOptions style) + { + var shaper = new STBTTBasicTextShaper(); + var info = shaper.shape(EnumSet.noneOf(TextShaper.EnumFeature.class), font, text, style); + + draw(x, y, info, style); + } + + public static void draw(float x, float y, LiTextInfo info, TextStyleOptions style) + { + var transformBuf = LiCommandBuffer.uncleared(); + + var fitBox = style.getFitBox(); + + var initialScale = style.getSize() / STBTTFont.PIXEL_HEIGHT; + var scaleX = initialScale; + var scaleY = initialScale; + + var bounds = info.getBoundingBox().scale(scaleX, scaleY, new Rectanglef()); + + if (fitBox != null) + { + // Rescale in sync in both are set to scale + if (style.getOverflowX() == TextStyleOptions.OverflowXStrategy.SCALE_TO_FIT && + style.getOverflowY() == TextStyleOptions.OverflowYStrategy.SCALE_TO_FIT) + { + var smaller = Math.min(fitBox.lengthX() / bounds.lengthX(), fitBox.lengthY() / bounds.lengthY()); + var rescale = Math.min(1.0f, smaller); + scaleX *= rescale; + bounds.scale(rescale, rescale); + } + else + { + if (style.getOverflowX() == TextStyleOptions.OverflowXStrategy.SCALE_TO_FIT) + { + var rescale = Math.min(1.0f, fitBox.lengthX() / bounds.lengthX()); + scaleX *= rescale; + bounds.scale(rescale, 1.0f); + } + + if (style.getOverflowY() == TextStyleOptions.OverflowYStrategy.SCALE_TO_FIT) + { + var rescale = Math.min(1.0f, fitBox.lengthY() / bounds.lengthY()); + scaleY *= rescale; + bounds.scale(1.0f, rescale); + } + } + + x += switch (style.getHorizontalAlign()) { + case START -> fitBox.minX - bounds.minX; + case CENTER -> (fitBox.maxX + fitBox.minX) / 2.0f - bounds.lengthX() / 2.0f; + case END -> fitBox.maxX - bounds.lengthX(); + }; + + y += switch (style.getVerticalAlign()) { + case START -> fitBox.minY - bounds.minY; + case CENTER -> (fitBox.maxY + fitBox.minY) / 2.0f - bounds.lengthY() / 2.0f; + case END -> fitBox.maxY - bounds.lengthY(); + }; + } + else + { + x += switch (style.getHorizontalAlign()) { + case START -> -bounds.minX; + case CENTER -> -bounds.minX + -bounds.lengthX() / 2.0f; + case END -> -bounds.lengthX(); + }; + + y += switch (style.getVerticalAlign()) { + case START -> -bounds.lengthY(); + case CENTER -> -bounds.lengthY() / 2.0f; + case END -> 0; + }; + } + + transformBuf.push(new LiCommandSetTransform(new Matrix3f().scale(scaleX, scaleY, 1.0f).m20(x).m21(y))); + + var buf = info.getDrawCommandBuffer(); + var commandParser = new PlutoGUICommandParser(); + commandParser.add(LiCommandBuffer.cleared()); + commandParser.add(transformBuf); + commandParser.add(buf); + + try (var drawCalls = commandParser.parse()) + { + drawCalls.render(); + } + } +} diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/PlutoGUIMod.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/PlutoGUIMod.java index b2ba32c..542f7dd 100755 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/PlutoGUIMod.java +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/PlutoGUIMod.java @@ -1,6 +1,5 @@ package org.plutoengine.graphics; -import org.joml.Matrix3f; import org.plutoengine.Pluto; import org.plutoengine.graphics.gui.FontShader; import org.plutoengine.graphics.texture.MagFilter; @@ -34,10 +33,6 @@ public class PlutoGUIMod implements IModEntryPoint instance = mod; fontShader = new RenderShaderBuilder(mod.getResource("shaders.VertexFontShader#glsl"), mod.getResource("shaders.FragmentFontShader#glsl")).build(FontShader.class, false); - fontShader.start(); - fontShader.recolor.load(1, 1, 1, 1); - fontShader.transformationMatrix.load(new Matrix3f()); - uiElementsAtlas = new RectangleTexture(); uiElementsAtlas.load(mod.getResource("gui.elements#png"), MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE); diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/TestFontRenderer.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/TestFontRenderer.java deleted file mode 100644 index 5362653..0000000 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/TestFontRenderer.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.plutoengine.graphics; - -import org.joml.Matrix3f; -import org.plutoengine.graphics.gui.PlutoGUICommandParser; -import org.plutoengine.graphics.gui.STBTTBasicTextShaper; -import org.plutoengine.graphics.gui.STBTTFont; -import org.plutoengine.libra.command.LiCommandBuffer; -import org.plutoengine.libra.command.impl.LiCommandSetTransform; -import org.plutoengine.libra.text.shaping.TextShaper; - -import java.util.EnumSet; - -public class TestFontRenderer -{ - public static void drawString(STBTTFont font, String text) - { - var shaper = new STBTTBasicTextShaper(); - var info = shaper.shape(EnumSet.of(TextShaper.EnumFeature.KERNING), font, text); - - var transformBuf = new LiCommandBuffer(); - transformBuf.push(new LiCommandSetTransform(new Matrix3f().scale(.75f).m20(400f).m21(400f))); - - var buf = info.getDrawCommandBuffer(); - var commandParser = new PlutoGUICommandParser(); - commandParser.add(transformBuf); - commandParser.add(buf); - var drawCalls = commandParser.parse(); - - drawCalls.render(); - - drawCalls.close(); - } -} diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/FontShader.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/FontShader.java index b167dfb..1715ec1 100644 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/FontShader.java +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/FontShader.java @@ -2,14 +2,18 @@ package org.plutoengine.graphics.gui; import org.joml.Matrix3fc; import org.plutoengine.graphics.gl.vao.attrib.ReservedAttributes; +import org.plutoengine.libra.paint.LiColorPaint; +import org.plutoengine.libra.paint.LiGradientPaint; +import org.plutoengine.libra.paint.LiPaint; import org.plutoengine.shader.ShaderBase; import org.plutoengine.shader.ShaderProgram; import org.plutoengine.shader.VertexArrayAttribute; import org.plutoengine.shader.uniform.*; import org.plutoengine.shader.uniform.auto.AutoViewportProjection; +import org.plutoengine.util.color.IRGBA; @ShaderProgram -public final class FontShader extends ShaderBase implements IGUIShader +public final class FontShader extends ShaderBase implements ISDFTextShader { @AutoViewportProjection @Uniform(name = "projection") @@ -19,10 +23,25 @@ public final class FontShader extends ShaderBase implements IGUIShader public UniformMat3 transformationMatrix; @Uniform - public UniformRGBA recolor; + public UniformInt paintType; @Uniform - public UniformBoolean italic; + public UniformRGBA paintColor; + + @Uniform + public UniformInt paintGradientStopCount; + + @Uniform + public UniformArrayRGBA paintGradientColors; + + @Uniform + public UniformArrayFloat paintGradientPositions; + + @Uniform + public UniformArrayVec2 paintGradientEnds; + + @Uniform + public UniformFloat pxScale; @VertexArrayAttribute(ReservedAttributes.POSITION) public int position; @@ -33,9 +52,54 @@ public final class FontShader extends ShaderBase implements IGUIShader @VertexArrayAttribute(2) public int page; + @VertexArrayAttribute(3) + public int paintUVCoords; + @Override public void setTransform(Matrix3fc transform) { this.transformationMatrix.load(transform); } + + @Override + public void setPaint(LiPaint paint) + { + switch (paint.getType()) + { + case SOLID_COLOR -> { + var col = ((LiColorPaint) paint).getColor(); + this.paintType.load(0); + this.paintColor.load(col.getFloatComponentsRGBA()); + } + + case GRADIENT -> { + var gradPaint = (LiGradientPaint) paint; + this.paintType.load(1); + this.paintGradientEnds.load(gradPaint.getStart(), gradPaint.getEnd()); + var stops = gradPaint.getStops(); + this.paintGradientStopCount.load(stops.length); + var colors = new IRGBA[stops.length]; + var positions = new float[stops.length]; + + int i = 0; + for (var stop : stops) + { + var col = stop.color(); + + colors[i] = col.getFloatComponentsRGBA(); + positions[i] = stop.position(); + i++; + } + + this.paintGradientColors.load(colors); + this.paintGradientPositions.load(positions); + } + } + } + + @Override + public void setPixelScale(float scale) + { + this.pxScale.load(scale); + } } diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/IGUIShader.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/IGUIShader.java index e94b2bf..6282d27 100644 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/IGUIShader.java +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/IGUIShader.java @@ -1,8 +1,11 @@ package org.plutoengine.graphics.gui; import org.joml.Matrix3fc; +import org.plutoengine.libra.paint.LiPaint; public interface IGUIShader { void setTransform(Matrix3fc transform); + + void setPaint(LiPaint paint); } diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/ISDFTextShader.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/ISDFTextShader.java new file mode 100644 index 0000000..9eb30a7 --- /dev/null +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/ISDFTextShader.java @@ -0,0 +1,6 @@ +package org.plutoengine.graphics.gui; + +public interface ISDFTextShader extends IGUIShader +{ + void setPixelScale(float scale); +} diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoGUICommandParser.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoGUICommandParser.java index e550f89..489b661 100644 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoGUICommandParser.java +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoGUICommandParser.java @@ -4,12 +4,15 @@ import org.plutoengine.graphics.gl.DrawMode; import org.plutoengine.graphics.gl.vao.VertexArray; import org.plutoengine.graphics.gl.vao.VertexArrayBuilder; import org.plutoengine.graphics.gui.command.PlutoCommandDrawMesh; +import org.plutoengine.graphics.gui.command.PlutoCommandDrawMeshDirectBuffer; import org.plutoengine.graphics.gui.command.PlutoCommandSwitchShader; import org.plutoengine.graphics.gui.command.PlutoCommandSwitchTexture; import org.plutoengine.libra.command.AbstractGUICommandParser; import org.plutoengine.libra.command.IGUIRenderer; import org.plutoengine.libra.command.LiCommandBuffer; +import org.plutoengine.libra.command.impl.LiCommandSetPaint; import org.plutoengine.libra.command.impl.LiCommandSetTransform; +import org.plutoengine.libra.command.impl.LiCommandSpecial; import org.plutoengine.shader.ShaderBase; import java.util.ArrayDeque; @@ -52,6 +55,9 @@ public class PlutoGUICommandParser extends AbstractGUICommandParser attribsToEnable.removeAll(alreadyEnabledAttribs); alreadyEnabledAttribs.addAll(attribsToEnable); + if (drawCmd instanceof PlutoCommandDrawMeshDirectBuffer dBuf) + dBuf.close(); + drawCalls.add(() -> { vao.bind(); attribsToEnable.forEach(VertexArray::enableAttribute); @@ -72,6 +78,17 @@ public class PlutoGUICommandParser extends AbstractGUICommandParser drawCalls.add(() -> shaderCapture.setTransform(transformCmd.getTransform())); } + case SET_PAINT -> { + if (!(cmd instanceof LiCommandSetPaint paintCmd)) + throw new IllegalStateException(); + + var shaderCapture = currentShader; + + assert shaderCapture != null; + + drawCalls.add(() -> shaderCapture.setPaint(paintCmd.getPaint())); + } + case SWITCH_SHADER -> { if (!(cmd instanceof PlutoCommandSwitchShader swSh)) throw new IllegalStateException(); @@ -93,6 +110,14 @@ public class PlutoGUICommandParser extends AbstractGUICommandParser drawCalls.add(textureCapture::bind); } + + case SPECIAL -> { + if (!(cmd instanceof LiCommandSpecial cSp)) + throw new IllegalStateException(); + + var af = cSp.getAction(); + drawCalls.add(() -> af.accept(mergedBuffer)); + } } } diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoTextInfo.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoTextInfo.java deleted file mode 100644 index 52115b1..0000000 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/PlutoTextInfo.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.plutoengine.graphics.gui; - -import org.plutoengine.libra.command.LiCommandBuffer; -import org.plutoengine.libra.text.LiTextInfo; - -public class PlutoTextInfo extends LiTextInfo -{ - protected PlutoTextInfo(LiCommandBuffer commandBuffer) - { - super(commandBuffer); - } -} diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMesh.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMesh.java index c23b339..f3a966c 100644 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMesh.java +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMesh.java @@ -1,20 +1,21 @@ package org.plutoengine.graphics.gui.command; import org.plutoengine.graphics.gl.vao.attrib.AttributeInfo; -import org.plutoengine.graphics.gl.vbo.EnumArrayBufferType; import org.plutoengine.libra.command.impl.LiCommand; import org.plutoengine.libra.command.impl.LiCommandDrawMesh; import java.nio.Buffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; -import java.util.*; +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; -public class PlutoCommandDrawMesh extends LiCommandDrawMesh +public abstract sealed class PlutoCommandDrawMesh extends LiCommandDrawMesh permits PlutoCommandDrawMeshDirectBuffer, PlutoCommandDrawMeshHeap { - private final Map attributeInfo; - private final Map data; - private IntBuffer indices; + protected final Map attributeInfo; + protected final Map data; + protected IntBuffer indices; public PlutoCommandDrawMesh() { @@ -48,19 +49,7 @@ public class PlutoCommandDrawMesh extends LiCommandDrawMesh this.addIndices(IntBuffer.wrap(data)); } - public void addIndices(IntBuffer data) - { - if (data == null) - return; - - if (this.indices == null) - this.indices = IntBuffer.allocate(data.remaining()); - - if (this.indices.remaining() < data.remaining()) - this.indices = IntBuffer.allocate(Math.max(this.indices.capacity() << 1, this.indices.capacity() + data.remaining())).put(this.indices.flip()); - - this.indices.put(data); - } + public abstract void addIndices(IntBuffer data); public void addAttribute(int attrib, float[] data, int dimensions) { @@ -70,30 +59,7 @@ public class PlutoCommandDrawMesh extends LiCommandDrawMesh this.addAttribute(attrib, FloatBuffer.wrap(data), dimensions); } - public void addAttribute(int attrib, FloatBuffer data, int dimensions) - { - if (data == null) - return; - - var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.FLOAT, attrib, dimensions)); - - if (meta.dimensions() != dimensions) - throw new IllegalArgumentException("Attribute dimensions mismatch!"); - - this.data.compute(attrib, (k, v) -> { - if (v == null) - return FloatBuffer.allocate(data.remaining()).put(data); - - if (!(v instanceof FloatBuffer fab)) - throw new IllegalArgumentException(); - - if (data.remaining() <= fab.remaining()) - return fab.put(data); - - var newBuf = FloatBuffer.allocate(Math.max(v.capacity() << 1, v.capacity() + data.remaining())); - return newBuf.put(fab.flip()).put(data); - }); - } + public abstract void addAttribute(int attrib, FloatBuffer data, int dimensions); public void addAttribute(int attrib, int[] data, int dimensions) { @@ -103,30 +69,7 @@ public class PlutoCommandDrawMesh extends LiCommandDrawMesh this.addAttribute(attrib, IntBuffer.wrap(data), dimensions); } - public void addAttribute(int attrib, IntBuffer data, int dimensions) - { - if (data == null) - return; - - var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.INT, attrib, dimensions)); - - if (meta.dimensions() != dimensions) - throw new IllegalArgumentException("Attribute dimensions mismatch!"); - - this.data.compute(attrib, (k, v) -> { - if (v == null) - return IntBuffer.allocate(data.remaining()).put(data); - - if (!(v instanceof IntBuffer fab)) - throw new IllegalArgumentException(); - - if (data.remaining() <= fab.remaining()) - return fab.put(data); - - var newBuf = IntBuffer.allocate(Math.max(v.capacity() << 1, v.capacity() + data.remaining())); - return newBuf.put(fab.flip()).put(data); - }); - } + public abstract void addAttribute(int attrib, IntBuffer data, int dimensions); @Override public boolean supportsMerge(LiCommand other) @@ -154,7 +97,7 @@ public class PlutoCommandDrawMesh extends LiCommandDrawMesh } }); - this.addIndices(pcdm.indices); + this.addIndices(pcdm.getIndices()); return this; } diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMeshDirectBuffer.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMeshDirectBuffer.java new file mode 100644 index 0000000..7c252dc --- /dev/null +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMeshDirectBuffer.java @@ -0,0 +1,142 @@ +package org.plutoengine.graphics.gui.command; + +import org.lwjgl.system.MemoryUtil; +import org.plutoengine.graphics.gl.vao.attrib.AttributeInfo; +import org.plutoengine.graphics.gl.vbo.EnumArrayBufferType; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public final class PlutoCommandDrawMeshDirectBuffer extends PlutoCommandDrawMesh implements AutoCloseable +{ + public void addIndices(IntBuffer data) + { + if (data == null) + return; + + if (this.indices == null) + { + if (data.isDirect()) + { + this.indices = data; + var size = this.indices.remaining(); + this.indices.limit(size); + this.indices.position(size); + return; + } + else + { + this.indices = MemoryUtil.memAllocInt(data.remaining()); + } + } + + if (this.indices.remaining() < data.remaining()) + { + var newSize = Math.max(this.indices.capacity() << 1, this.indices.capacity() + data.remaining()); + this.indices = MemoryUtil.memRealloc(this.indices, newSize); + } + + this.indices.put(data); + + if (data.isDirect()) + MemoryUtil.memFree(data); + } + + public void addAttribute(int attrib, FloatBuffer data, int dimensions) + { + if (data == null) + return; + + var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.FLOAT, attrib, dimensions)); + + if (meta.dimensions() != dimensions) + throw new IllegalArgumentException("Attribute dimensions mismatch!"); + + this.data.compute(attrib, (k, v) -> { + if (v == null) + { + if (data.isDirect()) + { + var size = data.remaining(); + data.limit(size); + data.position(size); + return data; + } + else + { + return MemoryUtil.memAllocFloat(data.remaining()).put(data); + } + } + + if (!(v instanceof FloatBuffer fab)) + throw new IllegalArgumentException(); + + if (data.remaining() > fab.remaining()) + { + var newSize = Math.max(fab.capacity() << 1, fab.capacity() + data.remaining()); + fab = MemoryUtil.memRealloc(fab, newSize); + } + + fab.put(data); + + if (data.isDirect()) + MemoryUtil.memFree(data); + + return fab; + }); + } + + + public void addAttribute(int attrib, IntBuffer data, int dimensions) + { + if (data == null) + return; + + var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.INT, attrib, dimensions)); + + if (meta.dimensions() != dimensions) + throw new IllegalArgumentException("Attribute dimensions mismatch!"); + + this.data.compute(attrib, (k, v) -> { + if (v == null) + { + if (data.isDirect()) + { + var size = data.remaining(); + data.limit(size); + data.position(size); + return data; + } + else + { + return MemoryUtil.memAllocInt(data.remaining()).put(data); + } + } + + if (!(v instanceof IntBuffer iab)) + throw new IllegalArgumentException(); + + if (data.remaining() > iab.remaining()) + { + var newSize = Math.max(iab.capacity() << 1, iab.capacity() + data.remaining()); + iab = MemoryUtil.memRealloc(iab, newSize); + } + + iab.put(data); + + if (data.isDirect()) + MemoryUtil.memFree(data); + + return iab; + }); + } + + @Override + public void close() + { + MemoryUtil.memFree(this.indices); + + this.data.values() + .forEach(MemoryUtil::memFree); + } +} diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMeshHeap.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMeshHeap.java new file mode 100644 index 0000000..7ed29e0 --- /dev/null +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/command/PlutoCommandDrawMeshHeap.java @@ -0,0 +1,97 @@ +package org.plutoengine.graphics.gui.command; + +import org.plutoengine.graphics.gl.vao.attrib.AttributeInfo; +import org.plutoengine.graphics.gl.vbo.EnumArrayBufferType; +import org.plutoengine.libra.command.impl.LiCommand; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +public final class PlutoCommandDrawMeshHeap extends PlutoCommandDrawMesh +{ + public void addIndices(IntBuffer data) + { + if (data == null) + return; + + if (this.indices == null) + this.indices = IntBuffer.allocate(data.remaining()); + + if (this.indices.remaining() < data.remaining()) + this.indices = IntBuffer.allocate(Math.max(this.indices.capacity() << 1, this.indices.capacity() + data.remaining())).put(this.indices.flip()); + + this.indices.put(data); + } + + public void addAttribute(int attrib, FloatBuffer data, int dimensions) + { + if (data == null) + return; + + var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.FLOAT, attrib, dimensions)); + + if (meta.dimensions() != dimensions) + throw new IllegalArgumentException("Attribute dimensions mismatch!"); + + this.data.compute(attrib, (k, v) -> { + if (v == null) + return FloatBuffer.allocate(data.remaining()).put(data); + + if (!(v instanceof FloatBuffer fab)) + throw new IllegalArgumentException(); + + if (data.remaining() <= fab.remaining()) + return fab.put(data); + + var newBuf = FloatBuffer.allocate(Math.max(v.capacity() << 1, v.capacity() + data.remaining())); + return newBuf.put(fab.flip()).put(data); + }); + } + + public void addAttribute(int attrib, IntBuffer data, int dimensions) + { + if (data == null) + return; + + var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.INT, attrib, dimensions)); + + if (meta.dimensions() != dimensions) + throw new IllegalArgumentException("Attribute dimensions mismatch!"); + + this.data.compute(attrib, (k, v) -> { + if (v == null) + return IntBuffer.allocate(data.remaining()).put(data); + + if (!(v instanceof IntBuffer iab)) + throw new IllegalArgumentException(); + + if (data.remaining() <= iab.remaining()) + return iab.put(data); + + var newBuf = IntBuffer.allocate(Math.max(v.capacity() << 1, v.capacity() + data.remaining())); + return newBuf.put(iab.flip()).put(data); + }); + } + + @Override + public PlutoCommandDrawMeshHeap merge(LiCommand other) + { + if (!(other instanceof PlutoCommandDrawMesh pcdm)) + throw new UnsupportedOperationException(); + + pcdm.data.forEach((k, v) -> { + var attrInfo = this.attributeInfo.get(k); + + switch (attrInfo.type()) + { + case FLOAT -> this.addAttribute(k, (FloatBuffer) v, attrInfo.dimensions()); + case INT -> this.addAttribute(k, (IntBuffer) v, attrInfo.dimensions()); + case UNSIGNED_INT -> throw new UnsupportedOperationException(); + } + }); + + this.addIndices(pcdm.indices); + + return this; + } +} diff --git a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/STBTTBasicTextShaper.java b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/stbttf/STBTTBasicTextShaper.java similarity index 56% rename from engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/STBTTBasicTextShaper.java rename to engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/stbttf/STBTTBasicTextShaper.java index c079efc..71156e9 100644 --- a/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/STBTTBasicTextShaper.java +++ b/engine-core/plutogui/src/main/java/org/plutoengine/graphics/gui/stbttf/STBTTBasicTextShaper.java @@ -1,26 +1,42 @@ -package org.plutoengine.graphics.gui; +package org.plutoengine.graphics.gui.stbttf; +import org.joml.primitives.Rectanglef; import org.lwjgl.system.MemoryUtil; import org.plutoengine.graphics.PlutoGUIMod; -import org.plutoengine.graphics.gui.command.PlutoCommandDrawMesh; +import org.plutoengine.graphics.gui.command.PlutoCommandDrawMeshDirectBuffer; import org.plutoengine.graphics.gui.command.PlutoCommandSwitchShader; import org.plutoengine.graphics.gui.command.PlutoCommandSwitchTexture; import org.plutoengine.libra.command.LiCommandBuffer; +import org.plutoengine.libra.command.impl.LiCommandSetPaint; +import org.plutoengine.libra.command.impl.LiCommandSpecial; import org.plutoengine.libra.text.LiTextInfo; import org.plutoengine.libra.text.font.GlyphInfo; +import org.plutoengine.libra.text.font.LiFontFamily; import org.plutoengine.libra.text.shaping.IShapingStrategy; import org.plutoengine.libra.text.shaping.TextShaper; +import org.plutoengine.libra.text.shaping.TextStyleOptions; import java.util.Arrays; import java.util.EnumSet; +import java.util.Objects; public class STBTTBasicTextShaper implements IShapingStrategy { + private LiCommandBuffer commandBuffer; + + public STBTTBasicTextShaper setCommandBuffer(LiCommandBuffer commandBuffer) + { + this.commandBuffer = commandBuffer; + + return this; + } @Override - public LiTextInfo shape(EnumSet features, STBTTFont font, String text) + public LiTextInfo shape(EnumSet features, LiFontFamily fontFamily, String text, TextStyleOptions style) { - var commandBuf = new LiCommandBuffer(); + var commandBuf = Objects.requireNonNullElseGet(this.commandBuffer, LiCommandBuffer::uncleared); + + var font = style.pickFont(fontFamily); var atlas = font.getGlyphAtlas(); var atlasTexture = atlas.getGlyphAtlasTexture(); @@ -31,9 +47,11 @@ public class STBTTBasicTextShaper implements IShapingStrategy PlutoGUIMod.fontShader.setPixelScale(style.getSize()))); float x = 0; float y = 0; - GlyphInfo info; + GlyphInfo info; STBTTFont.STBTTGlyphMetrics metrics = null; int cp; + float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY, minY = Float.POSITIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY; while (cpIt.hasNext()) { @@ -82,8 +105,8 @@ public class STBTTBasicTextShaper implements IShapingStrategy implements AutoCloseable { public static final int PIXEL_HEIGHT = 64; - public static final int SDF_PADDING = 4; + public static final int SDF_PADDING = 8; public static final int SHEET_SIZE = 1024; private int descent; @@ -37,6 +38,10 @@ public class STBTTFont extends LiFont glyphIndexLookup; + private Map kerningTable; private record KerningPair(int left, int right) @@ -49,6 +54,11 @@ public class STBTTFont extends LiFont(); var advanceWidth = stack.mallocInt(1); var leftSideBearing = stack.mallocInt(1); @@ -241,10 +249,13 @@ public class STBTTFont extends LiFont(); - kerningTable.forEach(e -> font.kerningTable.put(new KerningPair(e.glyph1(), e.glyph2()), e.advance())); + try (var kerningTable = STBTTKerningentry.malloc(kerningTableLength)) + { + STBTruetype.stbtt_GetKerningTable(fontInfo, kerningTable); + font.kerningTable = new HashMap<>(); + kerningTable.forEach(e -> { + // System.out.printf("%s -> %s = %d%n", Character.toString(e.glyph1()), Character.toString(e.glyph2()), e.advance()); + + font.kerningTable.put(new KerningPair(e.glyph1(), e.glyph2()), e.advance()); + }); + } font.ascent = ascentBuf.get(); font.descent = descentBuf.get(); diff --git a/engine-core/plutomesher/src/main/java/org/plutoengine/graphics/gl/vao/VertexArray.java b/engine-core/plutomesher/src/main/java/org/plutoengine/graphics/gl/vao/VertexArray.java index 0bcd816..7cb715f 100755 --- a/engine-core/plutomesher/src/main/java/org/plutoengine/graphics/gl/vao/VertexArray.java +++ b/engine-core/plutomesher/src/main/java/org/plutoengine/graphics/gl/vao/VertexArray.java @@ -9,9 +9,6 @@ import org.plutoengine.graphics.gl.vbo.IndexArrayBuffer; import java.util.*; -import org.plutoengine.logger.Logger; -import org.plutoengine.logger.SmartSeverity; - public class VertexArray implements AutoCloseable { protected final List usedAttributes; @@ -136,8 +133,6 @@ public class VertexArray implements AutoCloseable this.indices = null; } - Logger.logf(SmartSeverity.REMOVED, "Vertex array ID %d deleted...\n", this.glID); - GL33.glDeleteVertexArrays(this.glID); this.glID = 0; diff --git a/engine-core/plutoruntime/src/main/java/org/plutoengine/logger/SmartSeverity.java b/engine-core/plutoruntime/src/main/java/org/plutoengine/logger/SmartSeverity.java index 7043adb..e10084f 100755 --- a/engine-core/plutoruntime/src/main/java/org/plutoengine/logger/SmartSeverity.java +++ b/engine-core/plutoruntime/src/main/java/org/plutoengine/logger/SmartSeverity.java @@ -31,7 +31,7 @@ public enum SmartSeverity implements ISeverity MODULE_MINUS("[-] [M] ", false), MODULE_WARNING("[!] [M] ", true), MODULE_ERROR("[X] [M] ", true), - MODULE_CHECK("[✓] [M] ", true), + MODULE_CHECK("[✓] [M] ", false), EVENT("[i] [E] ", false), EVENT_PLUS("[+] [E] ", false), diff --git a/engine-demo/basic-application/mods/tefek.demo.basicapplication/fonts.zip b/engine-demo/basic-application/mods/tefek.demo.basicapplication/fonts.zip index 9be05d2..7978195 100644 Binary files a/engine-demo/basic-application/mods/tefek.demo.basicapplication/fonts.zip and b/engine-demo/basic-application/mods/tefek.demo.basicapplication/fonts.zip differ diff --git a/engine-demo/basic-application/mods/tefek.demo.basicapplication/info.json b/engine-demo/basic-application/mods/tefek.demo.basicapplication/info.json index 2d332ce..c846a68 100755 --- a/engine-demo/basic-application/mods/tefek.demo.basicapplication/info.json +++ b/engine-demo/basic-application/mods/tefek.demo.basicapplication/info.json @@ -10,6 +10,10 @@ "fonts": { "path": "fonts.zip", "type": "zip" + }, + "plutofonts": { + "path": "plutofonts", + "type": "open" } } } diff --git a/engine-demo/basic-application/mods/tefek.demo.basicapplication/plutofonts/plutostardust.ttf b/engine-demo/basic-application/mods/tefek.demo.basicapplication/plutofonts/plutostardust.ttf new file mode 100755 index 0000000..543960a Binary files /dev/null and b/engine-demo/basic-application/mods/tefek.demo.basicapplication/plutofonts/plutostardust.ttf differ diff --git a/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/FragmentFontShader.glsl b/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/FragmentFontShader.glsl index 8acca65..9e59eee 100755 --- a/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/FragmentFontShader.glsl +++ b/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/FragmentFontShader.glsl @@ -2,25 +2,67 @@ in vec2 uvCoordinates; flat in int atlasPage; +in vec2 paintUVCoordinates; uniform sampler2DArray textureSampler; -uniform vec4 recolor; + +uniform int paintType; +uniform vec4 paintColor; + +uniform int paintGradientStopCount; +uniform vec4[16] paintGradientColors; +uniform float[16] paintGradientPositions; +uniform vec2[2] paintGradientEnds; + +uniform float pxScale; out vec4 out_Color; +vec4 solidColor(void) +{ + return paintColor; +} + +vec4 gradientColor(void) +{ + float par = smoothstep(paintGradientEnds[0].x, paintGradientEnds[1].x, paintUVCoordinates.x) * (paintGradientStopCount - 1); + + float nPar = clamp(par, 0, float(paintGradientStopCount - 1)) + paintGradientPositions[0] * 0.000001; + vec4 lCol = paintGradientColors[int(floor(nPar))]; + vec4 rCol = paintGradientColors[int(ceil(nPar))]; + + float gamma = 0.45; + + vec4 ilCol = vec4(pow(lCol.r, 1 / gamma), pow(lCol.g, 1 / gamma), pow(lCol.b, 1 / gamma), lCol.a); + vec4 irCol = vec4(pow(rCol.r, 1 / gamma), pow(rCol.g, 1 / gamma), pow(rCol.b, 1 / gamma), rCol.a); + + vec4 fCol = mix(ilCol, irCol, fract(nPar)); + + return vec4(pow(fCol.r, gamma), pow(fCol.g, gamma), pow(fCol.b, gamma), fCol.a); +} + void main(void) { - vec3 textCoords = vec3(uvCoordinates, atlasPage); + vec3 texCoords = vec3(uvCoordinates, atlasPage); - float threshold = 1 - 240.0 / 255.0; + float threshold = 180.0 / 255.0 - 5.0 / pow(pxScale, 1.6); // Also help small text be readable - float signedDist = 1 - texture(textureSampler, textCoords).r; + float signedDist = texture(textureSampler, texCoords).r - threshold; - float fw = fwidth(signedDist); + vec4 col; - vec4 col = recolor; + switch (paintType) + { + case 0: + col = solidColor(); + break; - col.a *= smoothstep(threshold + 0.2, threshold, signedDist); + case 1: + col = gradientColor(); + break; + } + + col.a *= smoothstep(0, 2.4 / pxScale, signedDist); out_Color = col; } \ No newline at end of file diff --git a/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/VertexFontShader.glsl b/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/VertexFontShader.glsl index 0cd8f95..4a66efc 100755 --- a/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/VertexFontShader.glsl +++ b/engine-demo/basic-application/mods/tefek.plutogui/default/shaders/VertexFontShader.glsl @@ -3,20 +3,20 @@ in vec2 position; in vec2 uvCoords; in int page; +in vec2 paintUVCoords; out vec2 uvCoordinates; +out vec2 paintUVCoordinates; flat out int atlasPage; uniform mat4 projection; uniform mat3 transformation; -uniform int italic; - void main(void) { - vec2 pos = vec2(position.x - position.y * italic / 4.0, position.y); atlasPage = page; uvCoordinates = uvCoords; - vec3 transformed = vec3((transformation * vec3(pos, 1.0)).xy, 0.0); + paintUVCoordinates = paintUVCoords; + vec3 transformed = vec3((transformation * vec3(position, 1.0)).xy, 0.0); gl_Position = projection * vec4(transformed, 1.0); } \ No newline at end of file diff --git a/engine-demo/basic-application/src/main/java/org/plutoengine/demo/BasicApplicationDemoMod.java b/engine-demo/basic-application/src/main/java/org/plutoengine/demo/BasicApplicationDemoMod.java index 9cab653..babe586 100755 --- a/engine-demo/basic-application/src/main/java/org/plutoengine/demo/BasicApplicationDemoMod.java +++ b/engine-demo/basic-application/src/main/java/org/plutoengine/demo/BasicApplicationDemoMod.java @@ -1,7 +1,13 @@ package org.plutoengine.demo; import org.plutoengine.graphics.PlutoGUIMod; -import org.plutoengine.graphics.gui.STBTTFont; +import org.plutoengine.graphics.gui.stbttf.STBTTFont; +import org.plutoengine.graphics.texture.MagFilter; +import org.plutoengine.graphics.texture.MinFilter; +import org.plutoengine.graphics.texture.WrapMode; +import org.plutoengine.graphics.texture.texture2d.RectangleTexture; +import org.plutoengine.libra.text.font.LiFontFamily; +import org.plutoengine.libra.text.shaping.TextStyleOptions; import org.plutoengine.mod.IModEntryPoint; import org.plutoengine.mod.Mod; import org.plutoengine.mod.ModEntry; @@ -13,17 +19,25 @@ import org.plutoengine.mod.ModEntry; ) public class BasicApplicationDemoMod implements IModEntryPoint { - public static STBTTFont font; + public static LiFontFamily font; + + public static RectangleTexture plutoLogo; @Override public void onLoad(Mod mod) { - font = STBTTFont.load(mod.getResource("fonts$robotoregular#ttf")); + font = new LiFontFamily<>(); + font.add(TextStyleOptions.STYLE_REGULAR, STBTTFont.load(mod.getResource("plutofonts$plutostardust#ttf"))); + + plutoLogo = new RectangleTexture(); + plutoLogo.load(mod.getResource("icons$icon128#png"), MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE); } @Override public void onUnload() { + plutoLogo.close(); + font.close(); } } diff --git a/engine-demo/basic-application/src/main/java/org/plutoengine/demo/Main.java b/engine-demo/basic-application/src/main/java/org/plutoengine/demo/Main.java index 75f00a7..17791af 100755 --- a/engine-demo/basic-application/src/main/java/org/plutoengine/demo/Main.java +++ b/engine-demo/basic-application/src/main/java/org/plutoengine/demo/Main.java @@ -1,39 +1,40 @@ package org.plutoengine.demo; +import org.joml.primitives.Rectanglef; import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL33; - +import org.plutoengine.Pluto; import org.plutoengine.PlutoApplication; +import org.plutoengine.PlutoLocal; import org.plutoengine.display.Display; +import org.plutoengine.display.Framerate; +import org.plutoengine.graphics.ImmediateFontRenderer; import org.plutoengine.graphics.PlutoGUIMod; -import org.plutoengine.graphics.Renderer2D; -import org.plutoengine.graphics.TestFontRenderer; -import org.plutoengine.graphics.gl.vao.QuadPresets; +import org.plutoengine.graphics.RectangleRenderer2D; import org.plutoengine.graphics.gui.FontShader; -import org.plutoengine.graphics.texture.MagFilter; -import org.plutoengine.graphics.texture.MinFilter; -import org.plutoengine.graphics.texture.WrapMode; -import org.plutoengine.graphics.texture.texture2d.Texture2D; import org.plutoengine.input.InputBus; +import org.plutoengine.libra.paint.LiGradientPaint; +import org.plutoengine.libra.paint.LiPaint; +import org.plutoengine.libra.text.shaping.TextStyleOptions; import org.plutoengine.math.ProjectionMatrix; +import org.plutoengine.mod.ModLoader; import org.plutoengine.shader.RenderShaderBuilder; import org.plutoengine.shader.uniform.auto.AutomaticUniforms; -import org.plutoengine.tpl.ImageLoader; +import org.plutoengine.util.color.Color; +import org.plutoengine.util.color.EnumColorFormat; +import org.plutoengine.util.color.HSB; -import java.awt.image.BufferedImage; -import java.nio.file.Path; -import java.util.List; +import java.util.stream.Collectors; public class Main extends PlutoApplication { public static Main INSTANCE; - public static void main(String[] args) throws Exception + public static void main(String[] args) { var config = new PlutoApplication.StartupConfig(); config.vsync(1); - config.windowName("JSRClone " + VersionInfo.GAME_VERSION); + config.windowName("PlutoEngine Demo " + VersionInfo.GAME_VERSION); INSTANCE = new Main(); INSTANCE.run(args, config); @@ -42,13 +43,55 @@ public class Main extends PlutoApplication @Override public void loop() { - GL33.glEnable(GL11.GL_BLEND); - GL33.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL33.glEnable(GL33.GL_BLEND); + GL33.glBlendFunc(GL33.GL_SRC_ALPHA, GL33.GL_ONE_MINUS_SRC_ALPHA); var projection = ProjectionMatrix.createOrtho2D(this.display.getWidth(), this.display.getHeight()); AutomaticUniforms.VIEWPORT_PROJECTION.fire(projection); - TestFontRenderer.drawString(BasicApplicationDemoMod.font, "Testing "); + var style = new TextStyleOptions(20.0f); + style.setPaint(LiPaint.solidColor(Color.WHITE)); + + var mods = PlutoLocal.components().getComponent(ModLoader.class).getAllMods(); + + var modStr = mods.stream().map(mod -> { + var modManifest = mod.getManifest(); + return String.format("%s %s", modManifest.displayName(), mod.getVersion()); + }).collect(Collectors.joining("\n")); + + ImmediateFontRenderer.drawString(5, 5, Framerate.getInterpolatedFPS() + " FPS", BasicApplicationDemoMod.font, style); + ImmediateFontRenderer.drawString(5, 30, modStr, BasicApplicationDemoMod.font, style); + + var watermarkStyle = new TextStyleOptions(20.0f); + watermarkStyle.setHorizontalAlign(TextStyleOptions.TextAlign.CENTER); + watermarkStyle.setPaint(LiPaint.solidColor(Color.from(0x4f000000, EnumColorFormat.CF_INT_ARGB))); + ImmediateFontRenderer.drawString(this.display.getWidth() / 2.0f, 5, "PlutoEngine demo build licensed the MIT license...", BasicApplicationDemoMod.font, watermarkStyle); + + RectangleRenderer2D.draw() + .at(this.display.getWidth() / 2.0f - 150, this.display.getHeight() / 2.0f - 246, 300, 300) + .recolor(0.5f, 0.5f, 0.5f, 1.0f) + .texture(BasicApplicationDemoMod.plutoLogo).flush(); + + RectangleRenderer2D.draw() + .at(this.display.getWidth() / 2.0f - 150, this.display.getHeight() / 2.0f - 250, 300, 300) + .texture(BasicApplicationDemoMod.plutoLogo).flush(); + + var welcomeStyle = new TextStyleOptions(60.0f) + .setHorizontalAlign(TextStyleOptions.TextAlign.CENTER) + .setVerticalAlign(TextStyleOptions.TextAlign.CENTER) + .setOverflowX(TextStyleOptions.OverflowXStrategy.SCALE_TO_FIT) + .setFitBox(new Rectanglef(50.0f, 50.0f, this.display.getWidth() - 50.0f, this.display.getHeight() - 50.0f)) + .setPaint(LiPaint.solidColor(Color.VERY_DARK_GRAY)); + ImmediateFontRenderer.drawString(0, 102, "Welcome to PlutoEngine v. %s!".formatted(Pluto.VERSION), BasicApplicationDemoMod.font, welcomeStyle); + float gPos = (System.currentTimeMillis() % 7200) / 20.0f; + ImmediateFontRenderer.drawString(500, 50, "Hue: %f".formatted(gPos), BasicApplicationDemoMod.font, style); + + var stops = new LiGradientPaint.Stop[16]; + for (int i = 0; i < stops.length; i++) + stops[i] = new LiGradientPaint.Stop(i / (float) stops.length, Color.from(new HSB(gPos + i * 10, 1.0f, 1.0f).toRGBA())); + + welcomeStyle.setPaint(LiPaint.horizontaLinearGradient(stops)); + ImmediateFontRenderer.drawString(0, 100, "Welcome to PlutoEngine v. %s!".formatted(Pluto.VERSION), BasicApplicationDemoMod.font, welcomeStyle); if (InputBus.Keyboard.pressed(GLFW.GLFW_KEY_R)) { @@ -64,90 +107,8 @@ public class Main extends PlutoApplication shader.stop(); shader.close(); PlutoGUIMod.fontShader = newShader; - - newShader.start(); - newShader.recolor.load(1, 1, 1, 1); } } - - /* - var va = Renderer2D.standardQuad; - va.bind(); - va.enableAllAttributes(); - - var font = BasicApplicationDemoMod.font; - var tex = font.getAtlas(); - - tex.bind(); - - var shader = PlutoGUIMod.fontShader; - - shader.start(); - shader.recolor.load(1, 1, 1, 1); - shader.italic.load(false); - shader.page.load(0); - shader.uvBase.load(0.0f, 0.0f); - shader.uvDelta.load(1.0f, 1.0f); - - for (int i = 0; i < tex.getDepth(); i++) - { - var padding = 8; - var x = i % 3; - var y = i / 3; - var size = this.size; - - shader.transformationMatrix.load(TransformationMatrix.create(20 + x * (size + padding), 20 + y * (size + padding), 0, - 0, 0, 0, - size, size, 1)); - - shader.page.load(i); - va.draw(DrawMode.TRIANGLES); - } - - this.size += InputBus.Mouse.getScrollY() * 20; - - if (InputBus.Keyboard.pressed(GLFW.GLFW_KEY_R)) - { - var newShader = new RenderShaderBuilder( - PlutoGUIMod.instance.getResource("shaders.VertexFontShader#glsl"), - PlutoGUIMod.instance.getResource("shaders.FragmentFontShader#glsl") - ).build(FontShader.class, false); - - if (newShader != null) - { - shader.stop(); - shader.close(); - PlutoGUIMod.fontShader = newShader; - } - } - - */ - - /* - var buildStr = String.format("Build %s", VersionInfo.GAME_BUILD); - var strWidth = FontHelper.calcStringWidth(buildStr, "default", 0.75f); - FontRenderer.drawString(this.display.getWidth() - strWidth + 1, 3, buildStr, 0, 0, 0, 1, 0.75f, true); - FontRenderer.drawString(this.display.getWidth() - strWidth, 2, buildStr, 0.7f, 0.7f, 0.7f, 1, 0.75f, false); - - var fpsStr = String.format("%d FPS", Framerate.getInterpolatedFPS()); - FontRenderer.drawString(3, 3, fpsStr, 0, 0, 0, 1, 0.75f, true); - FontRenderer.drawString(2, 2, fpsStr, 0.13f, 0.75f, 0.62f, 1, 0.75f, false); - - var mods = PlutoLocal.components().getComponent(ModLoader.class).getAllMods(); - int modNr = 0; - - for (var mod : mods) - { - var modManifest = mod.getManifest(); - var modStr = String.format("%s &c[0xff999999]&i1%s", modManifest.displayName(), mod.getVersion()); - - FontRenderer.drawString(8, 50 + modNr * 18, modStr, 0, 0, 0, 0, 0.7f, "default", true); - FontRenderer.drawString(7, 49 + modNr * 18, modStr, 1, 1, 1, 1, 0.7f, "default", false); - - modNr++; - } - - */ } public static Display getDisplay()