Bitmap font renderer, bug fixes and cleanup
This commit is contained in:
parent
6cbdd20731
commit
9df4da27ee
|
@ -1,7 +1,16 @@
|
|||
## 22.2.0.0-alpha.1
|
||||
* `[PlutoGUI]` **Added support for bitmap fonts**
|
||||
* `[PlutoGUI]` Generalized the font renderer API
|
||||
* `plutoengine-demos/` Removed third-party fonts
|
||||
* `[PlutoRuntime]` The `ModLoader` component is now opaque,
|
||||
pre-added mods are now specified when creating the token
|
||||
* `[PlutoRuntime]` Added a linting annotation to `Logger#logf`
|
||||
* `[PlutoRuntime]` Fixed a bug where creating relative resource paths
|
||||
from URIs was not possible
|
||||
* `[PlutoLib]` Fixed `toRGBA` in `HSB` and `HSBA`
|
||||
* `[PlutoLib]` Added `BasicInterpolation`
|
||||
* `[PlutoSpritesheet]` Added `recolor(IRGBA)` to `RectangleRenderer2D` and `Renderer2D`
|
||||
* `[PlutoSpritesheet]` Added `TemporalSprite` and `OrientedSprite`
|
||||
|
||||
## 22.2.0.0-alpha.0
|
||||
* `[PlutoComponent]` **Added support for dependencies and strengtened type checks**
|
||||
|
|
|
@ -14,6 +14,8 @@ public class Framerate
|
|||
|
||||
private static double frameTime = Double.NaN;
|
||||
|
||||
private static double animationTimer = 0;
|
||||
|
||||
private static double FPS = Double.NaN;
|
||||
|
||||
private static int interpolatedFPS;
|
||||
|
@ -37,6 +39,11 @@ public class Framerate
|
|||
return interpolatedFPS;
|
||||
}
|
||||
|
||||
public static float getAnimationTimer()
|
||||
{
|
||||
return (float) animationTimer;
|
||||
}
|
||||
|
||||
public static void tick()
|
||||
{
|
||||
var now = System.nanoTime();
|
||||
|
@ -45,6 +52,9 @@ public class Framerate
|
|||
{
|
||||
var frameTimeNs = now - lastDraw;
|
||||
frameTime = frameTimeNs / (double) TimeUnit.MILLISECONDS.toNanos(1);
|
||||
animationTimer += frameTimeNs / (double) TimeUnit.SECONDS.toNanos(1);
|
||||
// Maintain precision in case the engine runs for many hours
|
||||
animationTimer %= TimeUnit.DAYS.toMinutes(1);
|
||||
FPS = TimeUnit.SECONDS.toMillis(1) / frameTime;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ dependencies {
|
|||
|
||||
api("io.reactivex.rxjava3", "rxjava", "3.1.4")
|
||||
|
||||
implementation("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", "2.12.3")
|
||||
|
||||
implementation("org.lwjgl", "lwjgl-yoga")
|
||||
runtimeOnly("org.lwjgl", "lwjgl-yoga", classifier = org.plutoengine.Versions.lwjglNatives)
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ 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.graphics.gui.font.PlutoFont;
|
||||
import org.plutoengine.libra.command.LiCommandBuffer;
|
||||
import org.plutoengine.libra.command.impl.LiCommandSetTransform;
|
||||
import org.plutoengine.libra.text.LiTextInfo;
|
||||
|
@ -16,17 +15,19 @@ import java.util.EnumSet;
|
|||
|
||||
public class ImmediateFontRenderer
|
||||
{
|
||||
public static void drawString(float x, float y, String text, LiFontFamily<STBTTFont> font, TextStyleOptions style)
|
||||
public static <T extends PlutoFont<T>> void drawString(float x, float y, String text, LiFontFamily<T> fontFamily, TextStyleOptions style)
|
||||
{
|
||||
var shaper = new STBTTBasicTextShaper();
|
||||
var font = style.pickFont(fontFamily);
|
||||
var shaper = font.getDefaultShaper();
|
||||
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<STBTTFont> font, TextStyleOptions style)
|
||||
public static <T extends PlutoFont<T>> void drawStringNoKern(float x, float y, String text, LiFontFamily<T> fontFamily, TextStyleOptions style)
|
||||
{
|
||||
var shaper = new STBTTBasicTextShaper();
|
||||
var font = style.pickFont(fontFamily);
|
||||
var shaper = font.getDefaultShaper();
|
||||
var info = shaper.shape(EnumSet.noneOf(TextShaper.EnumFeature.class), font, text, style);
|
||||
|
||||
draw(x, y, info, style);
|
||||
|
@ -38,7 +39,7 @@ public class ImmediateFontRenderer
|
|||
|
||||
var fitBox = style.getFitBox();
|
||||
|
||||
var initialScale = style.getSize() / STBTTFont.PIXEL_HEIGHT;
|
||||
var initialScale = style.getSize() / PlutoFont.NORMALIZED_PIXEL_HEIGHT;
|
||||
var scaleX = initialScale;
|
||||
var scaleY = initialScale;
|
||||
|
||||
|
|
|
@ -28,12 +28,16 @@ public class PlutoGUIMod implements IModEntryPoint
|
|||
|
||||
public static FontShader fontShader;
|
||||
|
||||
public static FontShader bitmapFontShader;
|
||||
|
||||
public void onLoad(Mod mod)
|
||||
{
|
||||
instance = mod;
|
||||
|
||||
fontShader = new RenderShaderBuilder(mod.getResource("shaders.VertexFontShader#glsl"), mod.getResource("shaders.FragmentFontShader#glsl")).build(FontShader.class, false);
|
||||
|
||||
bitmapFontShader = new RenderShaderBuilder(mod.getResource("shaders.VertexBitmapFontShader#glsl"), mod.getResource("shaders.FragmentBitmapFontShader#glsl")).build(FontShader.class, false);
|
||||
|
||||
uiElementsAtlas = new RectangleTexture();
|
||||
uiElementsAtlas.load(mod.getResource("gui.elements#png"), MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
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 BitmapTextShader extends ShaderBase implements IGUIShader
|
||||
{
|
||||
@AutoViewportProjection
|
||||
@Uniform(name = "projection")
|
||||
public UniformMat4 projectionMatrix;
|
||||
|
||||
@Uniform(name = "transformation")
|
||||
public UniformMat3 transformationMatrix;
|
||||
|
||||
@Uniform
|
||||
public UniformInt paintType;
|
||||
|
||||
@Uniform
|
||||
public UniformRGBA paintColor;
|
||||
|
||||
@Uniform
|
||||
public UniformInt paintGradientStopCount;
|
||||
|
||||
@Uniform
|
||||
public UniformArrayRGBA paintGradientColors;
|
||||
|
||||
@Uniform
|
||||
public UniformArrayFloat paintGradientPositions;
|
||||
|
||||
@Uniform
|
||||
public UniformArrayVec2 paintGradientEnds;
|
||||
|
||||
@VertexArrayAttribute(ReservedAttributes.POSITION)
|
||||
public int position;
|
||||
|
||||
@VertexArrayAttribute(ReservedAttributes.UV)
|
||||
public int uvCoords;
|
||||
|
||||
@VertexArrayAttribute(2)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
package org.plutoengine.graphics.gui.font;
|
||||
|
||||
import org.plutoengine.graphics.texture.Texture;
|
||||
import org.plutoengine.libra.text.font.GlyphMetrics;
|
||||
import org.plutoengine.libra.text.font.LiFont;
|
||||
import org.plutoengine.libra.text.shaping.IShapingStrategy;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class PlutoFont<T extends PlutoFont<? super T>> extends LiFont<PlutoFont<T>.PlutoGlyphAtlas, PlutoFont<T>.PlutoGlyphMetrics> implements AutoCloseable
|
||||
{
|
||||
public static final int NORMALIZED_PIXEL_HEIGHT = 64;
|
||||
|
||||
protected int descent;
|
||||
protected int ascent;
|
||||
protected int lineGap;
|
||||
protected int lineAdvance;
|
||||
|
||||
protected float scale;
|
||||
|
||||
protected Map<Integer, Integer> glyphIndexLookup;
|
||||
|
||||
protected Map<PlutoFont.KerningPair, Integer> kerningTable;
|
||||
|
||||
public record KerningPair(int left, int right)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected PlutoFont(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
public abstract IShapingStrategy<? extends PlutoFont<? super T>.PlutoGlyphMetrics, ? extends PlutoFont<? super T>.PlutoGlyphAtlas, T> getDefaultShaper();
|
||||
|
||||
public float getScale()
|
||||
{
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
public int getAscent()
|
||||
{
|
||||
return this.ascent;
|
||||
}
|
||||
|
||||
public int getDescent()
|
||||
{
|
||||
return this.descent;
|
||||
}
|
||||
|
||||
public int getLineGap()
|
||||
{
|
||||
return this.lineGap;
|
||||
}
|
||||
|
||||
public int getLineAdvance()
|
||||
{
|
||||
return this.lineAdvance;
|
||||
}
|
||||
|
||||
public int getKerningOffset(int left, int right)
|
||||
{
|
||||
var sk = new PlutoFont.KerningPair(glyphIndexLookup.getOrDefault(left, -1), glyphIndexLookup.getOrDefault(right, -1));
|
||||
return this.kerningTable.getOrDefault(sk, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
var tex = this.getGlyphAtlas().getGlyphAtlasTexture();
|
||||
tex.close();
|
||||
}
|
||||
|
||||
public class PlutoGlyphAtlas extends LiFont<PlutoFont<T>.PlutoGlyphAtlas, PlutoFont<T>.PlutoGlyphMetrics>.GlyphAtlas
|
||||
{
|
||||
private Texture glyphAtlasTexture;
|
||||
|
||||
public void setGlyphAtlasTexture(Texture glyphAtlasTexture)
|
||||
{
|
||||
this.glyphAtlasTexture = glyphAtlasTexture;
|
||||
}
|
||||
|
||||
public Texture getGlyphAtlasTexture()
|
||||
{
|
||||
return this.glyphAtlasTexture;
|
||||
}
|
||||
}
|
||||
|
||||
public class PlutoGlyphMetrics extends GlyphMetrics
|
||||
{
|
||||
private final int codepoint;
|
||||
protected int advanceX;
|
||||
protected int leftSideBearing;
|
||||
|
||||
protected int cx0;
|
||||
protected int cy0;
|
||||
protected int cx1;
|
||||
protected int cy1;
|
||||
|
||||
protected int xOrigin;
|
||||
protected int yOrigin;
|
||||
|
||||
public PlutoGlyphMetrics(int codepoint)
|
||||
{
|
||||
this.codepoint = codepoint;
|
||||
}
|
||||
|
||||
public int getAdvanceX()
|
||||
{
|
||||
return this.advanceX;
|
||||
}
|
||||
|
||||
public int getLeftSideBearing()
|
||||
{
|
||||
return this.leftSideBearing;
|
||||
}
|
||||
|
||||
public int getCodepoint()
|
||||
{
|
||||
return this.codepoint;
|
||||
}
|
||||
|
||||
public int getKerning(int cp)
|
||||
{
|
||||
return PlutoFont.this.getKerningOffset(this.codepoint, cp);
|
||||
}
|
||||
|
||||
public int getCX0()
|
||||
{
|
||||
return this.cx0;
|
||||
}
|
||||
|
||||
public int getCY0()
|
||||
{
|
||||
return this.cy0;
|
||||
}
|
||||
|
||||
public int getCX1()
|
||||
{
|
||||
return this.cx1;
|
||||
}
|
||||
|
||||
public int getCY1()
|
||||
{
|
||||
return this.cy1;
|
||||
}
|
||||
|
||||
public int getXOrigin()
|
||||
{
|
||||
return this.xOrigin;
|
||||
}
|
||||
|
||||
public int getYOrigin()
|
||||
{
|
||||
return this.yOrigin;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package org.plutoengine.graphics.gui.font.bitmap;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import org.joml.primitives.Rectanglef;
|
||||
import org.plutoengine.graphics.gui.font.PlutoFont;
|
||||
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.GlyphInfo;
|
||||
import org.plutoengine.libra.text.shaping.IShapingStrategy;
|
||||
import org.plutoengine.logger.Logger;
|
||||
import org.plutoengine.logger.SmartSeverity;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class BitmapFont extends PlutoFont<BitmapFont>
|
||||
{
|
||||
private int padding;
|
||||
|
||||
private BitmapFont(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
public int getPadding()
|
||||
{
|
||||
return this.padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IShapingStrategy<BitmapFont.PlutoGlyphMetrics, BitmapFont.PlutoGlyphAtlas, BitmapFont> getDefaultShaper()
|
||||
{
|
||||
return new BitmapTextShaper();
|
||||
}
|
||||
|
||||
public static BitmapFont load(Path path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var objectMapper = new ObjectMapper(YAMLFactory.builder().build());
|
||||
BitmapFontInfo info;
|
||||
try (var br = Files.newBufferedReader(path))
|
||||
{
|
||||
info = objectMapper.readValue(br, BitmapFontInfo.class);
|
||||
}
|
||||
|
||||
var font = new BitmapFont(info.name());
|
||||
Logger.logf(SmartSeverity.ADDED, "Loading font: %s%n", font.getName());
|
||||
|
||||
font.atlas = font.new PlutoGlyphAtlas();
|
||||
|
||||
var tex = new RectangleTexture();
|
||||
var dir = path.getParent();
|
||||
var texPath = dir.resolve(info.atlas());
|
||||
|
||||
var magFilter = switch (info.filtering()) {
|
||||
case NEAREST -> MagFilter.NEAREST;
|
||||
case LINEAR -> MagFilter.LINEAR;
|
||||
};
|
||||
|
||||
tex.load(texPath, magFilter, MinFilter.LINEAR, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE);
|
||||
|
||||
font.atlas.setGlyphAtlasTexture(tex);
|
||||
|
||||
var meta = info.meta();
|
||||
|
||||
font.ascent = meta.ascent();
|
||||
font.descent = meta.descent();
|
||||
font.lineGap = meta.lineGap();
|
||||
font.lineAdvance = font.ascent - font.descent + font.lineGap;
|
||||
font.scale = 1.0f / meta.scale() * PlutoFont.NORMALIZED_PIXEL_HEIGHT;
|
||||
|
||||
var kern = info.kern();
|
||||
|
||||
font.kerningTable = new HashMap<>();
|
||||
kern.forEach(e -> font.kerningTable.put(new PlutoFont.KerningPair(e.left(), e.right()), e.offset()));
|
||||
|
||||
var glyphs = info.glyphs();
|
||||
font.glyphIndexLookup = new HashMap<>();
|
||||
|
||||
font.padding = meta.padding();
|
||||
|
||||
glyphs.forEach(glyph -> {
|
||||
var sprite = glyph.sprite();
|
||||
|
||||
var cp = glyph.cp();
|
||||
|
||||
var glyphMetrics = font.new PlutoGlyphMetrics(cp) {{
|
||||
this.advanceX = glyph.advance();
|
||||
this.leftSideBearing = glyph.leftBearing();
|
||||
|
||||
this.xOrigin = (this.leftSideBearing - font.padding) * PlutoFont.NORMALIZED_PIXEL_HEIGHT / meta.scale();
|
||||
this.yOrigin = (glyph.topOffset() - font.ascent - font.padding) * PlutoFont.NORMALIZED_PIXEL_HEIGHT / meta.scale();
|
||||
|
||||
this.cx0 = this.leftSideBearing + font.padding;
|
||||
this.cy0 = glyph.topOffset() - font.ascent + font.padding;
|
||||
this.cx1 = this.leftSideBearing + sprite.w() - font.padding;
|
||||
this.cy1 = sprite.h() - font.ascent - font.padding;
|
||||
}};
|
||||
|
||||
var rect = new Rectanglef(
|
||||
sprite.x(),
|
||||
sprite.y(),
|
||||
sprite.x() + sprite.w(),
|
||||
sprite.y() + sprite.h()
|
||||
);
|
||||
|
||||
var glyphInfo = new GlyphInfo<>(font.atlas, 0, rect);
|
||||
|
||||
font.addGlyph(cp, glyphMetrics, glyphInfo);
|
||||
});
|
||||
|
||||
return font;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.logf(SmartSeverity.ERROR, "Failed to load font: %s%n", path);
|
||||
Logger.log(e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package org.plutoengine.graphics.gui.font.bitmap;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.ext.NioPathDeserializer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
record BitmapFontInfo(
|
||||
String name,
|
||||
FontInfoMeta meta,
|
||||
@JsonDeserialize(using = NioPathDeserializer.class) Path atlas,
|
||||
Filtering filtering,
|
||||
@JsonDeserialize(contentAs = KerningInfo.class) List<KerningInfo> kern,
|
||||
@JsonDeserialize(contentAs = GlyphInfo.class) List<GlyphInfo> glyphs
|
||||
)
|
||||
{
|
||||
enum Filtering
|
||||
{
|
||||
NEAREST,
|
||||
LINEAR
|
||||
}
|
||||
|
||||
record FontInfoMeta(
|
||||
int ascent,
|
||||
int descent,
|
||||
int lineGap,
|
||||
int padding,
|
||||
int scale
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
record KerningInfo(
|
||||
int left,
|
||||
int right,
|
||||
int offset
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
record GlyphInfo(
|
||||
int cp,
|
||||
int glyphClass,
|
||||
GlyphSprite sprite,
|
||||
int leftBearing,
|
||||
int advance,
|
||||
int topOffset
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
record GlyphSprite(
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package org.plutoengine.graphics.gui.font.bitmap;
|
||||
|
||||
import org.joml.primitives.Rectanglef;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.plutoengine.graphics.PlutoGUIMod;
|
||||
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.text.LiTextInfo;
|
||||
import org.plutoengine.libra.text.font.GlyphInfo;
|
||||
import org.plutoengine.libra.text.shaping.IShapingStrategy;
|
||||
import org.plutoengine.libra.text.shaping.TextShaper;
|
||||
import org.plutoengine.libra.text.shaping.TextStyleOptions;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BitmapTextShaper implements IShapingStrategy<BitmapFont.PlutoGlyphMetrics, BitmapFont.PlutoGlyphAtlas, BitmapFont>
|
||||
{
|
||||
private LiCommandBuffer commandBuffer;
|
||||
|
||||
public BitmapTextShaper setCommandBuffer(LiCommandBuffer commandBuffer)
|
||||
{
|
||||
this.commandBuffer = commandBuffer;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiTextInfo shape(EnumSet<TextShaper.EnumFeature> features, BitmapFont font, String text, TextStyleOptions style)
|
||||
{
|
||||
var commandBuf = Objects.requireNonNullElseGet(this.commandBuffer, LiCommandBuffer::uncleared);
|
||||
|
||||
var atlas = font.getGlyphAtlas();
|
||||
var atlasTexture = atlas.getGlyphAtlasTexture();
|
||||
var texSwitch = new PlutoCommandSwitchTexture(atlasTexture);
|
||||
commandBuf.push(texSwitch);
|
||||
|
||||
var shader = PlutoGUIMod.bitmapFontShader;
|
||||
var shaderSwitch = new PlutoCommandSwitchShader(shader);
|
||||
commandBuf.push(shaderSwitch);
|
||||
|
||||
commandBuf.push(new LiCommandSetPaint(style.getPaint()));
|
||||
|
||||
var cpCount = (int) text.codePoints().count();
|
||||
|
||||
var mesh = new PlutoCommandDrawMeshDirectBuffer();
|
||||
|
||||
final var quadVerts = 4;
|
||||
final var twoTriVerts = 6;
|
||||
|
||||
var vertDim = 2;
|
||||
var vertexBuf = MemoryUtil.memAllocFloat(vertDim * quadVerts * cpCount);
|
||||
|
||||
var uvDim = 2;
|
||||
var uvBuf = MemoryUtil.memAllocFloat(uvDim * quadVerts * cpCount);
|
||||
|
||||
var paintUVBuf = MemoryUtil.memAllocFloat(uvDim * quadVerts * cpCount);
|
||||
|
||||
var indexBuf = MemoryUtil.memAllocInt(twoTriVerts * cpCount);
|
||||
|
||||
var cpIt = text.codePoints().iterator();
|
||||
|
||||
var indices = new int[] {
|
||||
0, 1, 2,
|
||||
0, 2, 3
|
||||
};
|
||||
|
||||
float[] vertices = new float[vertDim * quadVerts];
|
||||
float[] uvs = new float[uvDim * quadVerts];
|
||||
|
||||
float scale = font.getScale();
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
int padding = font.getPadding();
|
||||
|
||||
GlyphInfo<?, ?> info;
|
||||
BitmapFont.PlutoGlyphMetrics metrics = null;
|
||||
int cp;
|
||||
float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY, minY = Float.POSITIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
|
||||
|
||||
while (cpIt.hasNext())
|
||||
{
|
||||
cp = cpIt.next();
|
||||
|
||||
switch (cp)
|
||||
{
|
||||
case '\n' -> {
|
||||
x = 0;
|
||||
y += font.getLineAdvance() * scale;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics != null && features.contains(TextShaper.EnumFeature.KERNING))
|
||||
x += metrics.getKerning(cp) * scale;
|
||||
|
||||
metrics = font.getGlyphMetrics(cp);
|
||||
info = atlas.getGlyph(cp);
|
||||
|
||||
if (metrics == null)
|
||||
continue;
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
float gx = x + metrics.getXOrigin();
|
||||
float gy = y + metrics.getYOrigin() + font.getAscent() * scale;
|
||||
|
||||
float xLow = gx - padding;
|
||||
float xHigh = gx + metrics.getCX1() * scale - metrics.getCX0() * scale + padding;
|
||||
float yLow = gy - padding;
|
||||
float yHigh = gy + metrics.getCY1() * scale - metrics.getCY0() * scale + padding;
|
||||
|
||||
minX = Math.min(minX, xLow);
|
||||
minY = Math.min(minY, yLow);
|
||||
maxX = Math.max(maxX, xHigh);
|
||||
maxY = Math.max(maxY, yHigh);
|
||||
|
||||
vertices[6] = vertices[0] = xLow;
|
||||
vertices[3] = vertices[1] = yHigh;
|
||||
vertices[4] = vertices[2] = xHigh;
|
||||
vertices[7] = vertices[5] = yLow;
|
||||
|
||||
var uvRect = info.getRect();
|
||||
uvs[6] = uvs[0] = uvRect.minX;
|
||||
uvs[3] = uvs[1] = atlasTexture.getHeight() - uvRect.maxY;
|
||||
uvs[4] = uvs[2] = uvRect.maxX;
|
||||
uvs[7] = uvs[5] = atlasTexture.getHeight() - uvRect.minY;
|
||||
|
||||
vertexBuf.put(vertices);
|
||||
uvBuf.put(uvs);
|
||||
|
||||
indexBuf.put(indices);
|
||||
|
||||
indices[0] += quadVerts;
|
||||
indices[1] += quadVerts;
|
||||
indices[2] += quadVerts;
|
||||
indices[3] += quadVerts;
|
||||
indices[4] += quadVerts;
|
||||
indices[5] += quadVerts;
|
||||
}
|
||||
|
||||
x += metrics.getAdvanceX() * scale;
|
||||
}
|
||||
|
||||
vertexBuf.flip();
|
||||
|
||||
while (vertexBuf.hasRemaining())
|
||||
{
|
||||
paintUVBuf.put((vertexBuf.get() - minX) / (maxX - minX));
|
||||
paintUVBuf.put((vertexBuf.get() - minY) / (maxY - minY));
|
||||
}
|
||||
|
||||
mesh.addAttribute(shader.position, vertexBuf.rewind(), vertDim);
|
||||
mesh.addAttribute(shader.uvCoords, uvBuf.flip(), uvDim);
|
||||
mesh.addAttribute(shader.paintUVCoords, paintUVBuf.flip(), uvDim);
|
||||
|
||||
mesh.addIndices(indexBuf.flip());
|
||||
|
||||
commandBuf.push(mesh);
|
||||
|
||||
return new LiTextInfo(commandBuf, new Rectanglef(minX, minY, maxX, maxY));
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
package org.plutoengine.graphics.gui.stbttf;
|
||||
package org.plutoengine.graphics.gui.font.stbttf;
|
||||
|
||||
import org.joml.primitives.Rectanglef;
|
||||
import org.lwjgl.stb.*;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.plutoengine.buffer.BufferHelper;
|
||||
import org.plutoengine.graphics.gui.SDFTextureArray;
|
||||
import org.plutoengine.graphics.gui.font.PlutoFont;
|
||||
import org.plutoengine.graphics.texture.MagFilter;
|
||||
import org.plutoengine.graphics.texture.MinFilter;
|
||||
import org.plutoengine.graphics.texture.WrapMode;
|
||||
import org.plutoengine.libra.text.font.GlyphInfo;
|
||||
import org.plutoengine.libra.text.font.GlyphMetrics;
|
||||
import org.plutoengine.libra.text.font.LiFont;
|
||||
import org.plutoengine.libra.text.shaping.IShapingStrategy;
|
||||
import org.plutoengine.logger.Logger;
|
||||
import org.plutoengine.logger.SmartSeverity;
|
||||
|
||||
|
@ -24,157 +24,22 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class STBTTFont extends LiFont<STBTTFont.STBTTGlyphAtlas, STBTTFont.STBTTGlyphMetrics> implements AutoCloseable
|
||||
public class STBTTFont extends PlutoFont<STBTTFont>
|
||||
{
|
||||
public static final int PIXEL_HEIGHT = 64;
|
||||
public static final int SDF_PADDING = 8;
|
||||
public static final int SHEET_SIZE = 1024;
|
||||
|
||||
private int descent;
|
||||
private int ascent;
|
||||
private int lineGap;
|
||||
private int lineAdvance;
|
||||
|
||||
private float scale;
|
||||
|
||||
private Map<Integer, Integer> glyphIndexLookup;
|
||||
|
||||
private Map<KerningPair, Integer> kerningTable;
|
||||
|
||||
private record KerningPair(int left, int right)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private STBTTFont(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
public float getScale()
|
||||
{
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
public int getAscent()
|
||||
{
|
||||
return this.ascent;
|
||||
}
|
||||
|
||||
public int getDescent()
|
||||
{
|
||||
return this.descent;
|
||||
}
|
||||
|
||||
public int getLineGap()
|
||||
{
|
||||
return this.lineGap;
|
||||
}
|
||||
|
||||
public int getLineAdvance()
|
||||
{
|
||||
return this.lineAdvance;
|
||||
}
|
||||
|
||||
public int getKerningOffset(int left, int right)
|
||||
{
|
||||
var sk = new KerningPair(glyphIndexLookup.getOrDefault(left, -1), glyphIndexLookup.getOrDefault(right, -1));
|
||||
return this.kerningTable.getOrDefault(sk, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
public IShapingStrategy<STBTTFont.PlutoGlyphMetrics, STBTTFont.PlutoGlyphAtlas, STBTTFont> getDefaultShaper()
|
||||
{
|
||||
var tex = this.getGlyphAtlas().getGlyphAtlasTexture();
|
||||
tex.close();
|
||||
}
|
||||
|
||||
public class STBTTGlyphAtlas extends LiFont<STBTTGlyphAtlas, STBTTGlyphMetrics>.GlyphAtlas
|
||||
{
|
||||
private SDFTextureArray glyphAtlasTexture;
|
||||
|
||||
public void setGlyphAtlasTexture(SDFTextureArray glyphAtlasTexture)
|
||||
{
|
||||
this.glyphAtlasTexture = glyphAtlasTexture;
|
||||
}
|
||||
|
||||
public SDFTextureArray getGlyphAtlasTexture()
|
||||
{
|
||||
return this.glyphAtlasTexture;
|
||||
}
|
||||
}
|
||||
|
||||
public class STBTTGlyphMetrics extends GlyphMetrics
|
||||
{
|
||||
private final int codepoint;
|
||||
private int advanceX;
|
||||
private int leftSideBearing;
|
||||
|
||||
private int cx0;
|
||||
private int cy0;
|
||||
private int cx1;
|
||||
private int cy1;
|
||||
|
||||
private int xOrigin;
|
||||
private int yOrigin;
|
||||
|
||||
private STBTTGlyphMetrics(int codepoint)
|
||||
{
|
||||
this.codepoint = codepoint;
|
||||
}
|
||||
|
||||
public int getAdvanceX()
|
||||
{
|
||||
return this.advanceX;
|
||||
}
|
||||
|
||||
public int getLeftSideBearing()
|
||||
{
|
||||
return this.leftSideBearing;
|
||||
}
|
||||
|
||||
public int getCodepoint()
|
||||
{
|
||||
return this.codepoint;
|
||||
}
|
||||
|
||||
public int getKerning(int cp)
|
||||
{
|
||||
return STBTTFont.this.getKerningOffset(this.codepoint, cp);
|
||||
}
|
||||
|
||||
public int getCX0()
|
||||
{
|
||||
return this.cx0;
|
||||
}
|
||||
|
||||
public int getCY0()
|
||||
{
|
||||
return this.cy0;
|
||||
}
|
||||
|
||||
public int getCX1()
|
||||
{
|
||||
return this.cx1;
|
||||
}
|
||||
|
||||
public int getCY1()
|
||||
{
|
||||
return this.cy1;
|
||||
}
|
||||
|
||||
public int getXOrigin()
|
||||
{
|
||||
return this.xOrigin;
|
||||
}
|
||||
|
||||
public int getYOrigin()
|
||||
{
|
||||
return this.yOrigin;
|
||||
}
|
||||
return new STBTTTextShaper();
|
||||
}
|
||||
|
||||
public static STBTTFont load(Path path)
|
||||
|
@ -210,7 +75,7 @@ public class STBTTFont extends LiFont<STBTTFont.STBTTGlyphAtlas, STBTTFont.STBTT
|
|||
Logger.logf(SmartSeverity.ADDED, "Loading font: %s%n", name);
|
||||
|
||||
var font = new STBTTFont(name);
|
||||
font.scale = STBTruetype.stbtt_ScaleForPixelHeight(fontInfo, PIXEL_HEIGHT);
|
||||
font.scale = STBTruetype.stbtt_ScaleForPixelHeight(fontInfo, NORMALIZED_PIXEL_HEIGHT);
|
||||
|
||||
var ascentBuf = stack.callocInt(1);
|
||||
var descentBuf = stack.callocInt(1);
|
||||
|
@ -238,16 +103,16 @@ public class STBTTFont extends LiFont<STBTTFont.STBTTGlyphAtlas, STBTTFont.STBTT
|
|||
var colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
var colorModel = new ComponentColorModel(colorSpace, new int[] { 8 }, false,false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
|
||||
font.atlas = font.new STBTTGlyphAtlas();
|
||||
font.atlas = font.new PlutoGlyphAtlas();
|
||||
font.glyphIndexLookup = new HashMap<>();
|
||||
|
||||
var advanceWidth = stack.mallocInt(1);
|
||||
var leftSideBearing = stack.mallocInt(1);
|
||||
var leftSideBearingBuf = stack.mallocInt(1);
|
||||
|
||||
var cx0 = stack.mallocInt(1);
|
||||
var cy0 = stack.mallocInt(1);
|
||||
var cx1 = stack.mallocInt(1);
|
||||
var cy1 = stack.mallocInt(1);
|
||||
var cx0Buf = stack.mallocInt(1);
|
||||
var cy0Buf = stack.mallocInt(1);
|
||||
var cx1Buf = stack.mallocInt(1);
|
||||
var cy1Buf = stack.mallocInt(1);
|
||||
|
||||
var onedgeValue = 128;
|
||||
var pixelDistScale = onedgeValue / (float) SDF_PADDING;
|
||||
|
@ -268,7 +133,7 @@ public class STBTTFont extends LiFont<STBTTFont.STBTTGlyphAtlas, STBTTFont.STBTT
|
|||
var width = sdfWidthBuf.get(0);
|
||||
var height = sdfHeightBuf.get(0);
|
||||
|
||||
var glyphInfo = (GlyphInfo<STBTTGlyphAtlas, STBTTGlyphMetrics>) null;
|
||||
var glyphInfo = (GlyphInfo<STBTTFont.PlutoGlyphAtlas, STBTTFont.PlutoGlyphMetrics>) null;
|
||||
|
||||
if (buf != null)
|
||||
{
|
||||
|
@ -319,20 +184,21 @@ public class STBTTFont extends LiFont<STBTTFont.STBTTGlyphAtlas, STBTTFont.STBTT
|
|||
STBTruetype.stbtt_FreeSDF(buf);
|
||||
}
|
||||
|
||||
STBTruetype.stbtt_GetCodepointHMetrics(fontInfo, cp, advanceWidth, leftSideBearing);
|
||||
STBTruetype.stbtt_GetCodepointHMetrics(fontInfo, cp, advanceWidth, leftSideBearingBuf);
|
||||
|
||||
var glyphMetrics = font.new STBTTGlyphMetrics(cp);
|
||||
glyphMetrics.advanceX = advanceWidth.get(0);
|
||||
glyphMetrics.leftSideBearing = leftSideBearing.get(0);
|
||||
var glyphMetrics = font.new PlutoGlyphMetrics(cp) {{
|
||||
this.advanceX = advanceWidth.get(0);
|
||||
this.leftSideBearing = leftSideBearingBuf.get(0);
|
||||
|
||||
glyphMetrics.xOrigin = xOffsBuf.get(0);
|
||||
glyphMetrics.yOrigin = yOffsBuf.get(0);
|
||||
this.xOrigin = xOffsBuf.get(0);
|
||||
this.yOrigin = yOffsBuf.get(0);
|
||||
|
||||
STBTruetype.stbtt_GetCodepointBox(fontInfo, cp, cx0, cy0, cx1, cy1);
|
||||
glyphMetrics.cx0 = cx0.get(0);
|
||||
glyphMetrics.cy0 = cy0.get(0);
|
||||
glyphMetrics.cx1 = cx1.get(0);
|
||||
glyphMetrics.cy1 = cy1.get(0);
|
||||
STBTruetype.stbtt_GetCodepointBox(fontInfo, cp, cx0Buf, cy0Buf, cx1Buf, cy1Buf);
|
||||
this.cx0 = cx0Buf.get(0);
|
||||
this.cy0 = cy0Buf.get(0);
|
||||
this.cx1 = cx1Buf.get(0);
|
||||
this.cy1 = cy1Buf.get(0);
|
||||
}};
|
||||
|
||||
font.addGlyph(cp, glyphMetrics, glyphInfo);
|
||||
|
||||
|
@ -349,12 +215,12 @@ public class STBTTFont extends LiFont<STBTTFont.STBTTGlyphAtlas, STBTTFont.STBTT
|
|||
{
|
||||
STBTruetype.stbtt_GetKerningTable(fontInfo, kerningTable);
|
||||
font.kerningTable = new HashMap<>();
|
||||
kerningTable.forEach(e -> font.kerningTable.put(new KerningPair(e.glyph1(), e.glyph2()), e.advance()));
|
||||
kerningTable.forEach(e -> font.kerningTable.put(new PlutoFont.KerningPair(e.glyph1(), e.glyph2()), e.advance()));
|
||||
}
|
||||
|
||||
font.ascent = ascentBuf.get();
|
||||
font.descent = descentBuf.get();
|
||||
font.lineGap = lineGapBuf.get();
|
||||
font.ascent = ascentBuf.get(0);
|
||||
font.descent = descentBuf.get(0);
|
||||
font.lineGap = lineGapBuf.get(0);
|
||||
font.lineAdvance = font.ascent - font.descent + font.lineGap;
|
||||
var tex = new SDFTextureArray();
|
||||
tex.loadImg(sheets, SHEET_SIZE, SHEET_SIZE, sheets.size(), MagFilter.LINEAR, MinFilter.LINEAR, WrapMode.MIRROR_CLAMP_TO_EDGE, WrapMode.MIRROR_CLAMP_TO_EDGE);
|
|
@ -1,4 +1,4 @@
|
|||
package org.plutoengine.graphics.gui.stbttf;
|
||||
package org.plutoengine.graphics.gui.font.stbttf;
|
||||
|
||||
import org.joml.primitives.Rectanglef;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
@ -11,7 +11,6 @@ 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;
|
||||
|
@ -20,11 +19,11 @@ import java.util.Arrays;
|
|||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
||||
public class STBTTBasicTextShaper implements IShapingStrategy<STBTTFont.STBTTGlyphMetrics, STBTTFont.STBTTGlyphAtlas, STBTTFont>
|
||||
public class STBTTTextShaper implements IShapingStrategy<STBTTFont.PlutoGlyphMetrics, STBTTFont.PlutoGlyphAtlas, STBTTFont>
|
||||
{
|
||||
private LiCommandBuffer commandBuffer;
|
||||
|
||||
public STBTTBasicTextShaper setCommandBuffer(LiCommandBuffer commandBuffer)
|
||||
public STBTTTextShaper setCommandBuffer(LiCommandBuffer commandBuffer)
|
||||
{
|
||||
this.commandBuffer = commandBuffer;
|
||||
|
||||
|
@ -32,12 +31,10 @@ public class STBTTBasicTextShaper implements IShapingStrategy<STBTTFont.STBTTGly
|
|||
}
|
||||
|
||||
@Override
|
||||
public LiTextInfo shape(EnumSet<TextShaper.EnumFeature> features, LiFontFamily<STBTTFont> fontFamily, String text, TextStyleOptions style)
|
||||
public LiTextInfo shape(EnumSet<TextShaper.EnumFeature> features, STBTTFont font, String text, TextStyleOptions style)
|
||||
{
|
||||
var commandBuf = Objects.requireNonNullElseGet(this.commandBuffer, LiCommandBuffer::uncleared);
|
||||
|
||||
var font = style.pickFont(fontFamily);
|
||||
|
||||
var atlas = font.getGlyphAtlas();
|
||||
var atlasTexture = atlas.getGlyphAtlasTexture();
|
||||
var texSwitch = new PlutoCommandSwitchTexture(atlasTexture);
|
||||
|
@ -88,7 +85,7 @@ public class STBTTBasicTextShaper implements IShapingStrategy<STBTTFont.STBTTGly
|
|||
float y = 0;
|
||||
|
||||
GlyphInfo<?, ?> info;
|
||||
STBTTFont.STBTTGlyphMetrics metrics = null;
|
||||
STBTTFont.PlutoGlyphMetrics metrics = null;
|
||||
int cp;
|
||||
float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY, minY = Float.POSITIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package org.plutoengine.math;
|
||||
|
||||
import org.joml.Math;
|
||||
|
||||
public class BasicInterpolation
|
||||
{
|
||||
public static int roundedLerp(float value, int min, int max)
|
||||
{
|
||||
return min + Math.round(value * (max - min));
|
||||
}
|
||||
|
||||
public static int roundedLerpWrap(float value, int min, int max)
|
||||
{
|
||||
var range = max - min;
|
||||
return min + (roundedLerp(value, 0, range) % range + range) % range;
|
||||
}
|
||||
|
||||
public static int roundedLerp(double value, int min, int max)
|
||||
{
|
||||
return (int) (min + Math.round(value * (max - min)));
|
||||
}
|
||||
|
||||
public static int roundedLerpWrap(double value, int min, int max)
|
||||
{
|
||||
var range = max - min;
|
||||
return min + (roundedLerp(value, 0, range) % range + range) % range;
|
||||
}
|
||||
|
||||
public static int floorLerp(float value, int min, int max)
|
||||
{
|
||||
return (int) (min + Math.floor(value * (max - min)));
|
||||
}
|
||||
|
||||
public static int floorLerpWrap(float value, int min, int max)
|
||||
{
|
||||
var range = max - min;
|
||||
return min + (floorLerp(value, 0, range) % range + range) % range;
|
||||
}
|
||||
|
||||
public static int floorLerp(double value, int min, int max)
|
||||
{
|
||||
return (int) (min + Math.floor(value * (max - min)));
|
||||
}
|
||||
|
||||
public static int floorLerpWrap(double value, int min, int max)
|
||||
{
|
||||
var range = max - min;
|
||||
return min + (floorLerp(value, 0, range) % range + range) % range;
|
||||
}
|
||||
}
|
|
@ -57,7 +57,7 @@ public class HSB
|
|||
* @since 20.2.0.0-alpha.3
|
||||
* @author 493msi
|
||||
*/
|
||||
public RGB toRGBA()
|
||||
public RGBA toRGBA()
|
||||
{
|
||||
return this.toRGBA(1.0f);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class HSBA extends HSB
|
|||
* @author 493msi
|
||||
*/
|
||||
@Override
|
||||
public RGB toRGBA()
|
||||
public RGBA toRGBA()
|
||||
{
|
||||
return this.toRGBA(this.a);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.plutoengine.logger;
|
||||
|
||||
import org.intellij.lang.annotations.PrintFormat;
|
||||
import org.plutoengine.component.ComponentToken;
|
||||
import org.plutoengine.component.PlutoGlobalComponent;
|
||||
import org.plutoengine.resource.filesystem.ResourceManager;
|
||||
|
@ -215,7 +216,7 @@ public class Logger extends PlutoGlobalComponent
|
|||
*
|
||||
* @since pre-alpha
|
||||
* */
|
||||
public static synchronized void logf(ISeverity s, String formatSpec, Object... o)
|
||||
public static synchronized void logf(ISeverity s, @PrintFormat String formatSpec, Object... o)
|
||||
{
|
||||
(s.isStdErr() ? System.err : System.out).printf(s.getDisplayName() + formatSpec, o);
|
||||
}
|
||||
|
|
|
@ -110,6 +110,9 @@ public class ResourceFileSystemProvider extends FileSystemProvider
|
|||
|
||||
var mod = modLoader.getModByID(urp.modID());
|
||||
|
||||
if (urp.relative())
|
||||
return new ResourcePath(null, urp.pathAddress(), urp.extension(), null);
|
||||
|
||||
if (mod.isEmpty())
|
||||
throw new IllegalArgumentException("No such mod exists!");
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.plutoengine.graphics.gl.vao.QuadPresets;
|
|||
import org.plutoengine.graphics.gl.vao.VertexArray;
|
||||
import org.plutoengine.graphics.sprite.Sprite;
|
||||
import org.plutoengine.graphics.texture.texture2d.RectangleTexture;
|
||||
import org.plutoengine.util.color.IRGBA;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
|
@ -234,6 +235,13 @@ public class RectangleRenderer2D
|
|||
return this;
|
||||
}
|
||||
|
||||
public RectangleRenderer2D recolor(IRGBA rgba)
|
||||
{
|
||||
this.customShader.loadRecolor(rgba.red(), rgba.green(), rgba.blue(), rgba.alpha());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RectangleRenderer2D recolor(Vector4f recolor)
|
||||
{
|
||||
this.customShader.loadRecolor(recolor);
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.plutoengine.graphics.gl.DrawMode;
|
|||
import org.plutoengine.graphics.gl.vao.QuadPresets;
|
||||
import org.plutoengine.graphics.gl.vao.VertexArray;
|
||||
import org.plutoengine.graphics.texture.texture2d.Texture2D;
|
||||
import org.plutoengine.util.color.IRGBA;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
|
@ -216,6 +217,13 @@ public class Renderer2D
|
|||
return this;
|
||||
}
|
||||
|
||||
public Renderer2D recolor(IRGBA rgba)
|
||||
{
|
||||
this.customShader.loadRecolor(rgba.red(), rgba.green(), rgba.blue(), rgba.alpha());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Renderer2D recolor(Vector4f recolor)
|
||||
{
|
||||
this.customShader.loadRecolor(recolor);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package org.plutoengine.graphics.sprite;
|
||||
|
||||
import org.plutoengine.math.BasicInterpolation;
|
||||
|
||||
public class OrientedSprite
|
||||
{
|
||||
protected PartialTextureSprite[] sides;
|
||||
|
||||
public OrientedSprite(int sideCount)
|
||||
{
|
||||
this.sides = new PartialTextureSprite[sideCount];
|
||||
}
|
||||
|
||||
public OrientedSprite(PartialTextureSprite[] sides)
|
||||
{
|
||||
this.sides = sides;
|
||||
}
|
||||
|
||||
public void setSide(int side, PartialTextureSprite sprite)
|
||||
{
|
||||
this.sides[side] = sprite;
|
||||
}
|
||||
|
||||
public int getSideCount()
|
||||
{
|
||||
return this.sides.length;
|
||||
}
|
||||
|
||||
public PartialTextureSprite getSideFromAngle(float angle)
|
||||
{
|
||||
var side = BasicInterpolation.roundedLerpWrap(angle / (Math.PI * 2), 0, this.sides.length);
|
||||
return this.sides[side];
|
||||
}
|
||||
|
||||
public PartialTextureSprite getSide(int i)
|
||||
{
|
||||
return this.sides[i];
|
||||
}
|
||||
|
||||
public PartialTextureSprite[] getSides()
|
||||
{
|
||||
return this.sides;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package org.plutoengine.graphics.sprite;
|
||||
|
||||
import org.plutoengine.display.Framerate;
|
||||
import org.plutoengine.graphics.texture.texture2d.RectangleTexture;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TemporalSprite implements Sprite<RectangleTexture>
|
||||
{
|
||||
protected PartialTextureSprite[] frames;
|
||||
protected float[] durations;
|
||||
|
||||
protected float cached = 0;
|
||||
protected int cacheIndex = 0;
|
||||
|
||||
protected transient float[] stops;
|
||||
|
||||
public TemporalSprite(int frameCount)
|
||||
{
|
||||
this.frames = new PartialTextureSprite[frameCount];
|
||||
this.durations = new float[frameCount];
|
||||
this.stops = new float[frameCount];
|
||||
}
|
||||
|
||||
public TemporalSprite(PartialTextureSprite[] frames)
|
||||
{
|
||||
this.frames = frames;
|
||||
this.durations = new float[frames.length];
|
||||
this.stops = new float[frames.length];
|
||||
}
|
||||
|
||||
public TemporalSprite(PartialTextureSprite[] frames, float duration)
|
||||
{
|
||||
this.frames = frames;
|
||||
this.durations = new float[frames.length];
|
||||
this.stops = new float[frames.length];
|
||||
|
||||
Arrays.fill(this.durations, duration);
|
||||
this.recomputeFromIndex(0);
|
||||
}
|
||||
|
||||
public TemporalSprite(PartialTextureSprite[] frames, float[] durations)
|
||||
{
|
||||
assert frames.length == durations.length;
|
||||
|
||||
this.frames = frames;
|
||||
this.durations = durations;
|
||||
this.stops = new float[durations.length];
|
||||
|
||||
this.recomputeFromIndex(0);
|
||||
}
|
||||
|
||||
protected void recomputeFromIndex(int index)
|
||||
{
|
||||
for (int i = index + 1; i < this.durations.length; i++)
|
||||
this.stops[i] = this.stops[i - 1] + this.durations[i];
|
||||
}
|
||||
|
||||
public void setFrame(int index, PartialTextureSprite sprite)
|
||||
{
|
||||
this.frames[index] = sprite;
|
||||
this.recomputeFromIndex(index);
|
||||
}
|
||||
|
||||
public int getSideCount()
|
||||
{
|
||||
return this.frames.length;
|
||||
}
|
||||
|
||||
public PartialTextureSprite getFrameAt(float time)
|
||||
{
|
||||
if (time == this.cached)
|
||||
return this.frames[this.cacheIndex];
|
||||
|
||||
var totalDuration = this.stops[this.stops.length - 1] + durations[this.durations.length - 1];
|
||||
time = (time % totalDuration + totalDuration) % totalDuration;
|
||||
var i = Math.abs(Arrays.binarySearch(this.stops, time));
|
||||
this.cacheIndex = i % this.durations.length;
|
||||
this.cached = time;
|
||||
return this.frames[this.cacheIndex];
|
||||
}
|
||||
|
||||
public PartialTextureSprite getFrame()
|
||||
{
|
||||
return this.getFrameAt(Framerate.getAnimationTimer());
|
||||
}
|
||||
|
||||
public PartialTextureSprite getFrameNr(int i)
|
||||
{
|
||||
return this.frames[i];
|
||||
}
|
||||
|
||||
public PartialTextureSprite[] getFrames()
|
||||
{
|
||||
return this.frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX()
|
||||
{
|
||||
return this.getFrame().getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY()
|
||||
{
|
||||
return this.getFrame().getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth()
|
||||
{
|
||||
return this.getFrame().getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return this.getFrame().getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RectangleTexture getSheet()
|
||||
{
|
||||
return this.getFrame().getSheet();
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
|
@ -10,6 +10,10 @@
|
|||
"plutofonts": {
|
||||
"path": "plutofonts",
|
||||
"type": "open"
|
||||
},
|
||||
"default": {
|
||||
"path": "default",
|
||||
"type": "open"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,240 @@
|
|||
name: SRClone
|
||||
meta:
|
||||
scale: 8
|
||||
ascent: 8
|
||||
descent: 0
|
||||
lineGap: 1
|
||||
atlas: "pluto+asl://!font#png"
|
||||
filtering: NEAREST
|
||||
kern:
|
||||
-
|
||||
left: 0
|
||||
right: 0
|
||||
offset: 0
|
||||
|
||||
glyphs:
|
||||
-
|
||||
cp: 48 # 0
|
||||
sprite:
|
||||
x: 0
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 49 # 1
|
||||
sprite:
|
||||
x: 8
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 50 # 2
|
||||
sprite:
|
||||
x: 16
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 51 # 3
|
||||
sprite:
|
||||
x: 24
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 52 # 4
|
||||
sprite:
|
||||
x: 32
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 53 # 5
|
||||
sprite:
|
||||
x: 40
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 54 # 6
|
||||
sprite:
|
||||
x: 48
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 55 # 7
|
||||
sprite:
|
||||
x: 56
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 56 # 8
|
||||
sprite:
|
||||
x: 64
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 57 # 9
|
||||
sprite:
|
||||
x: 72
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 57 # 9
|
||||
sprite:
|
||||
x: 72
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 43 # +
|
||||
sprite:
|
||||
x: 80
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 45 # +
|
||||
sprite:
|
||||
x: 88
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 46 # .
|
||||
sprite:
|
||||
x: 96
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 120 # x
|
||||
sprite:
|
||||
x: 104
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 128150 # 💖 - sparkling heart because the default red one is two codepoints :(
|
||||
sprite:
|
||||
x: 112
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 105 # i
|
||||
sprite:
|
||||
x: 120
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 83 # S
|
||||
sprite:
|
||||
x: 0
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 127776 # 🌠 - shooting star
|
||||
sprite:
|
||||
x: 8
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 128994 # 🟢 - large green circle
|
||||
sprite:
|
||||
x: 16
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 9728 # ☀ - sun
|
||||
sprite:
|
||||
x: 24
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 128314 # 🔺 - red up triangle
|
||||
sprite:
|
||||
x: 32
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 121171 # 𝥓 - spiral arrow thingy
|
||||
sprite:
|
||||
x: 40
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 128160 # 💠 - diamond
|
||||
sprite:
|
||||
x: 48
|
||||
y: 8
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
||||
-
|
||||
cp: 8734 # ∞ - infinity
|
||||
sprite:
|
||||
x: 112
|
||||
y: 0
|
||||
w: 8
|
||||
h: 8
|
||||
leftBearing: 0
|
||||
advance: 8
|
|
@ -1,100 +0,0 @@
|
|||
//FONT DEFINITION, DO NOT CHANGE UNLESS YOU KNOW WHAT ARE YOU DOING.
|
||||
//Use double slash to comment one row.
|
||||
//First uncommented row must contain name of the font texture and its size.
|
||||
//Width of one character is 16px, height 24px. Different resolutions are WIP.
|
||||
default,256x144
|
||||
A 0;0
|
||||
B 0;0
|
||||
C 0;0
|
||||
D 0;0
|
||||
E 0;0
|
||||
F 0;0
|
||||
G 0;0
|
||||
H 0;0
|
||||
I 4;5
|
||||
J 1;0
|
||||
K 1;0
|
||||
L 0;0
|
||||
M 0;0
|
||||
N 0;0
|
||||
O 0;0
|
||||
P 0;2
|
||||
Q 0;0
|
||||
R 0;1
|
||||
S 0;0
|
||||
T 0;0
|
||||
U 0;0
|
||||
V 0;1
|
||||
W 0;0
|
||||
X 0;1
|
||||
Y 1;0
|
||||
Z 0;0
|
||||
a 3;3
|
||||
b 2;2
|
||||
c 2;3
|
||||
d 2;2
|
||||
e 2;3
|
||||
f 3;4
|
||||
g 2;3
|
||||
h 2;2
|
||||
i 4;7
|
||||
j 4;4
|
||||
k 2;3
|
||||
l 4;8
|
||||
m 1;0
|
||||
n 2;3
|
||||
o 3;2
|
||||
p 3;2
|
||||
q 3;4
|
||||
r 3;2
|
||||
s 3;4
|
||||
t 1;5
|
||||
u 3;3
|
||||
v 2;4
|
||||
w 0;0
|
||||
x 3;4
|
||||
y 3;2
|
||||
z 2;2
|
||||
1 5;1
|
||||
2 1;1
|
||||
3 2;3
|
||||
4 2;2
|
||||
5 1;3
|
||||
6 1;1
|
||||
7 1;1
|
||||
8 1;1
|
||||
9 1;1
|
||||
0 1;1
|
||||
- 3;3
|
||||
+ 2;3
|
||||
/ 1;2
|
||||
* 6;2
|
||||
) 7;4
|
||||
( 6;5
|
||||
[ 6;5
|
||||
] 6;5
|
||||
\ 1;3
|
||||
< 3;5
|
||||
> 3;6
|
||||
ˇ 3;2
|
||||
´ 5;6
|
||||
= 2;2
|
||||
^ 3;2
|
||||
. 5;7
|
||||
! 5;8
|
||||
? 1;2
|
||||
: 5;7
|
||||
@ 1;0
|
||||
# 0;2
|
||||
~ 1;3
|
||||
& 2;0
|
||||
, 6;5
|
||||
; 6;4
|
||||
% 0;0
|
||||
| 5;8
|
||||
° 4;7
|
||||
" 4;5
|
||||
} 0;9
|
||||
{ 0;9
|
||||
' 5;6
|
||||
_ 2;2
|
|
@ -1,2 +0,0 @@
|
|||
Feel free to create and send me a better font, I'll be glad.
|
||||
Everything you need to know is in the definitions.txt file.
|
Binary file not shown.
Before Width: | Height: | Size: 5.0 KiB |
|
@ -0,0 +1,75 @@
|
|||
#version 330 core
|
||||
|
||||
in vec2 uvCoordinates;
|
||||
in vec2 paintUVCoordinates;
|
||||
|
||||
uniform sampler2DRect textureSampler;
|
||||
|
||||
uniform int paintType;
|
||||
uniform vec4 paintColor;
|
||||
|
||||
uniform int paintGradientStopCount;
|
||||
uniform vec4[16] paintGradientColors;
|
||||
uniform float[16] paintGradientPositions;
|
||||
uniform vec2[2] paintGradientEnds;
|
||||
|
||||
out vec4 out_Color;
|
||||
|
||||
vec4 solidColor(void)
|
||||
{
|
||||
return paintColor;
|
||||
}
|
||||
|
||||
vec4 gammaMix(vec4 lCol, vec4 rCol, float ratio)
|
||||
{
|
||||
float gamma = 2.2;
|
||||
float one_over_gamma = 1 / gamma;
|
||||
|
||||
vec4 ilCol = vec4(pow(lCol.r, gamma), pow(lCol.g, gamma), pow(lCol.b, gamma), lCol.a);
|
||||
vec4 irCol = vec4(pow(rCol.r, gamma), pow(rCol.g, gamma), pow(rCol.b, gamma), rCol.a);
|
||||
|
||||
vec4 fCol = mix(ilCol, irCol, ratio);
|
||||
|
||||
return vec4(pow(fCol.r, one_over_gamma), pow(fCol.g, one_over_gamma), pow(fCol.b, one_over_gamma), fCol.a);
|
||||
}
|
||||
|
||||
vec4 gradientColor(void)
|
||||
{
|
||||
float angle = atan(-paintGradientEnds[1].y + paintGradientEnds[0].y, paintGradientEnds[1].x - paintGradientEnds[0].x);
|
||||
float rotatedStartX = paintGradientEnds[0].x * cos(angle) - paintGradientEnds[0].y * sin(angle);
|
||||
float rotatedEndX = paintGradientEnds[1].x * cos(angle) - paintGradientEnds[1].y * sin(angle);
|
||||
float d = rotatedEndX - rotatedStartX;
|
||||
|
||||
float pX = paintUVCoordinates.x * cos(angle) - paintUVCoordinates.y * sin(angle);
|
||||
|
||||
float mr = smoothstep(rotatedStartX + paintGradientPositions[0] * d, rotatedStartX + paintGradientPositions[1] * d, pX);
|
||||
vec4 col = gammaMix(paintGradientColors[0], paintGradientColors[1], mr);
|
||||
|
||||
for (int i = 1; i < paintGradientStopCount - 1; i++)
|
||||
{
|
||||
mr = smoothstep(rotatedStartX + paintGradientPositions[i] * d, rotatedStartX + paintGradientPositions[i + 1] * d, pX);
|
||||
col = gammaMix(col, paintGradientColors[i + 1], mr);
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 col;
|
||||
|
||||
switch (paintType)
|
||||
{
|
||||
case 0:
|
||||
col = solidColor();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
col = gradientColor();
|
||||
break;
|
||||
}
|
||||
|
||||
col.rgba *= texture(textureSampler, uvCoordinates);
|
||||
|
||||
out_Color = col;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#version 330 core
|
||||
|
||||
in vec2 position;
|
||||
in vec2 uvCoords;
|
||||
in vec2 paintUVCoords;
|
||||
|
||||
out vec2 uvCoordinates;
|
||||
out vec2 paintUVCoordinates;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat3 transformation;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
uvCoordinates = uvCoords;
|
||||
paintUVCoordinates = paintUVCoords;
|
||||
vec3 transformed = vec3((transformation * vec3(position, 1.0)).xy, 0.0);
|
||||
gl_Position = projection * vec4(transformed, 1.0);
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package org.plutoengine.demo;
|
||||
|
||||
import org.plutoengine.graphics.PlutoGUIMod;
|
||||
import org.plutoengine.graphics.gui.stbttf.STBTTFont;
|
||||
import org.plutoengine.graphics.gui.font.bitmap.BitmapFont;
|
||||
import org.plutoengine.graphics.gui.font.stbttf.STBTTFont;
|
||||
import org.plutoengine.graphics.sprite.PartialTextureSprite;
|
||||
import org.plutoengine.graphics.sprite.TemporalSprite;
|
||||
import org.plutoengine.graphics.texture.MagFilter;
|
||||
import org.plutoengine.graphics.texture.MinFilter;
|
||||
import org.plutoengine.graphics.texture.WrapMode;
|
||||
|
@ -21,23 +24,44 @@ public class BasicApplicationDemoMod implements IModEntryPoint
|
|||
{
|
||||
public static LiFontFamily<STBTTFont> font;
|
||||
|
||||
public static LiFontFamily<BitmapFont> srCloneFont;
|
||||
|
||||
public static RectangleTexture plutoLogo;
|
||||
|
||||
public static RectangleTexture srCloneBoxTex;
|
||||
public static TemporalSprite srCloneBox;
|
||||
|
||||
@Override
|
||||
public void onLoad(Mod mod)
|
||||
{
|
||||
font = new LiFontFamily<>();
|
||||
font.add(TextStyleOptions.STYLE_REGULAR, STBTTFont.load(mod.getResource("plutofonts$plutostardust#ttf")));
|
||||
|
||||
srCloneFont = new LiFontFamily<>();
|
||||
srCloneFont.add(TextStyleOptions.STYLE_REGULAR, BitmapFont.load(mod.getResource("plutofonts$srclone.info#yaml")));
|
||||
|
||||
plutoLogo = new RectangleTexture();
|
||||
plutoLogo.load(mod.getResource("icons$icon128#png"), MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE);
|
||||
|
||||
srCloneBoxTex = new RectangleTexture();
|
||||
srCloneBoxTex.load(mod.getResource("box#png"));
|
||||
|
||||
var frames = new PartialTextureSprite[16];
|
||||
for (int i = 0; i < frames.length; i++)
|
||||
frames[i] = new PartialTextureSprite(srCloneBoxTex, 64 * i, 0, 64, 64);
|
||||
|
||||
srCloneBox = new TemporalSprite(frames, 0.04f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnload()
|
||||
{
|
||||
srCloneBoxTex.close();
|
||||
|
||||
plutoLogo.close();
|
||||
|
||||
srCloneFont.close();
|
||||
|
||||
font.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class Main extends PlutoApplication
|
|||
.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;
|
||||
float gPos = Framerate.getAnimationTimer() * 50.0f;
|
||||
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()));
|
||||
|
@ -92,6 +92,26 @@ public class Main extends PlutoApplication
|
|||
welcomeStyle.setPaint(LiPaint.horizontaLinearGradient(stops));
|
||||
ImmediateFontRenderer.drawString(0, 100, "Welcome to PlutoEngine v. %s!".formatted(Pluto.VERSION), BasicApplicationDemoMod.font, welcomeStyle);
|
||||
|
||||
var srCloneStyle = new TextStyleOptions(32);
|
||||
srCloneStyle.setHorizontalAlign(TextStyleOptions.TextAlign.CENTER);
|
||||
srCloneStyle.setVerticalAlign(TextStyleOptions.TextAlign.START);
|
||||
srCloneStyle.setPaint(LiPaint.solidColor(Color.WHITE));
|
||||
ImmediateFontRenderer.drawString(this.display.getWidth() / 2.0f, this.display.getHeight() - 5,
|
||||
"\uD83C\uDF20\uD83D\uDFE2☀\uD83D\uDD3A\uD836\uDD53\uD83D\uDCA0", BasicApplicationDemoMod.srCloneFont, srCloneStyle);
|
||||
|
||||
var boxRender = RectangleRenderer2D.draw();
|
||||
|
||||
var cnt = 20;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
var hsb = new HSB(Framerate.getAnimationTimer() * 20.0f + i * 10.0f, 1.0f, 1.0f);
|
||||
|
||||
boxRender.at(this.display.getWidth() / 2.0f - cnt / 2.0f * 64.0f + i * 64.0f, this.display.getHeight() - 128, 64, 64)
|
||||
.sprite(BasicApplicationDemoMod.srCloneBox.getFrameAt(Framerate.getAnimationTimer() + i * 0.05f))
|
||||
.recolor(hsb.toRGBA())
|
||||
.flush();
|
||||
}
|
||||
|
||||
if (PlutoLocal.components().getComponent(Keyboard.class).pressed(GLFW.GLFW_KEY_R))
|
||||
{
|
||||
var shader = PlutoGUIMod.fontShader;
|
||||
|
|
2
libra
2
libra
|
@ -1 +1 @@
|
|||
Subproject commit dc5bbae9d11aaf483c8e95c7da305f926065ce20
|
||||
Subproject commit a8d8f1184f4c1663f1a600ad65cd16b398ae671a
|
|
@ -13,6 +13,10 @@ file("engine-core").listFiles().forEach {
|
|||
if (!it.isDirectory)
|
||||
return@forEach
|
||||
|
||||
// Skip hidden files
|
||||
if (it.name.startsWith("."))
|
||||
return@forEach
|
||||
|
||||
include("plutoengine:${it.name}")
|
||||
}
|
||||
|
||||
|
@ -20,6 +24,10 @@ file("engine-ext").listFiles().forEach {
|
|||
if (!it.isDirectory)
|
||||
return@forEach
|
||||
|
||||
// Skip hidden files
|
||||
if (it.name.startsWith("."))
|
||||
return@forEach
|
||||
|
||||
include("plutoengine-ext:${it.name}")
|
||||
}
|
||||
|
||||
|
@ -27,5 +35,9 @@ file("engine-demo").listFiles().forEach {
|
|||
if (!it.isDirectory)
|
||||
return@forEach
|
||||
|
||||
// Skip hidden files
|
||||
if (it.name.startsWith("."))
|
||||
return@forEach
|
||||
|
||||
include("plutoengine-demos:${it.name}")
|
||||
}
|
Loading…
Reference in New Issue