Files
common/src/main/java/org/saturnclient/ui/RenderScope.java
T
2026-09-28 21:55:47 +02:00

199 lines
7.4 KiB
Java

package org.saturnclient.ui;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import org.saturnclient.common.ref.asset.IdentifierRef;
import org.saturnclient.common.ref.asset.SpriteRef;
import org.saturnclient.common.ref.game.ItemStackRef;
import org.saturnclient.common.ref.render.MatrixStackRef;
import org.saturnclient.ui.resources.SvgTexture;
public interface RenderScope {
// ----------------------------
// Matrix & Transform
// ----------------------------
MatrixStackRef getMatrixStack();
// ----------------------------
// Color & Opacity
// ----------------------------
void setOpacity(float alpha);
int getColor(int color);
// ----------------------------
// Shapes
// ----------------------------
void drawRectangle(int x, int y, int width, int height, int color);
default void drawRoundedRectangle(int x, int y, int width, int height, int radius, int color) {
if (color == 0)
return;
drawTexture(getRoundedRectangle(width, height, radius), x, y, 0, 0, width, height, color);
}
/**
* The white rounded rectangle that {@link #drawRoundedRectangle} tints, as a
* cached texture.
*/
default IdentifierRef getRoundedRectangle(int width, int height, int radius) {
radius = Math.min(radius, width / 2);
radius = Math.min(radius, height / 2);
String rect = String.format(
"<rect width='%d' height='%d' rx='%d' ry='%d' fill='white'/>",
width, height,
radius, radius);
return getSvgShape(rect, "rounded_" + width + "_" + height + "_" + radius, width, height);
}
/**
* Frosts a rounded rectangle for a translucent background to be drawn over:
* the game behind the screen, blurred by {@code blur}, cut to exactly the
* shape {@link #drawRoundedRectangle} draws. Render scopes without glass
* draw nothing.
*/
default void drawGlass(int x, int y, int width, int height, int radius, int blur) {
drawGlass(getRoundedRectangle(width, height, radius), x, y, width, height, blur);
}
/**
* Draws the game behind the screen, blurred by {@code blur}, where
* {@code mask}, stretched over the area, is opaque.
*/
default void drawGlass(IdentifierRef mask, int x, int y, int width, int height, int blur) {
}
/**
* A {@link #drawRoundedRectangle} with a border, frosted with glass blurred
* by {@code blur} when the background isn't solid. A blur of 0 leaves it
* plain, showing the screen's own background blur.
*/
default void drawGlassRectangle(int x, int y, int width, int height, int radius, int blur, int thickness,
int background, int border) {
if (blur > 0 && background >>> 24 < 0xFF) {
drawGlass(x, y, width, height, radius, blur);
}
drawRoundedRectangle(x, y, width, height, radius, thickness, background, border);
}
/**
* Draws a rounded outline that stays inside the given bounds, so it lines up
* with a {@link #drawRoundedRectangle} of the same size and radius.
*/
default void drawRoundedBorder(int x, int y, int width, int height, int radius, int thickness, int color) {
if (color == 0 || thickness <= 0)
return;
radius = Math.min(radius, width / 2);
radius = Math.min(radius, height / 2);
thickness = Math.min(thickness, Math.min(width, height) / 2);
// The stroke is centered on the path, so inset it by half its width.
float inset = thickness / 2f;
float innerRadius = Math.max(0, radius - inset);
String rect = String.format(Locale.ROOT,
"<rect x='%.1f' y='%.1f' width='%.1f' height='%.1f' rx='%.1f' ry='%.1f' " +
"fill='none' stroke='white' stroke-width='%d'/>",
inset, inset,
width - (float) thickness, height - (float) thickness,
innerRadius, innerRadius,
thickness);
drawSvgShape(rect, "rounded_border_" + width + "_" + height + "_" + radius + "_" + thickness,
x, y, width, height, color);
}
/**
* Draws a rounded rectangle filled with {@code background} and outlined with
* {@code border}. Either color can be 0 to skip that part.
*/
default void drawRoundedRectangle(int x, int y, int width, int height, int radius, int thickness,
int background, int border) {
drawRoundedRectangle(x, y, width, height, radius, background);
drawRoundedBorder(x, y, width, height, radius, thickness, border);
}
/**
* Renders {@code shape} (SVG elements in a {@code width} x {@code height}
* canvas, drawn in white) to a cached texture and draws it tinted with
* {@code color}.
*/
private void drawSvgShape(String shape, String cacheKey, int x, int y, int width, int height, int color) {
drawTexture(getSvgShape(shape, cacheKey, width, height), x, y, 0, 0, width, height, color);
}
/**
* {@code shape} (SVG elements in a {@code width} x {@code height} canvas,
* drawn in white) rendered to a cached texture.
*/
private IdentifierRef getSvgShape(String shape, String cacheKey, int width, int height) {
String svg = String.format(
"<svg xmlns='http://www.w3.org/2000/svg' width='%d' height='%d'>%s</svg>",
width, height, shape);
InputStream svgStream = new ByteArrayInputStream(svg.getBytes(StandardCharsets.UTF_8));
return SvgTexture.getSvg(svgStream, IdentifierRef.ofSaturn("textures/gui/tmp_rect/" + cacheKey),
width * 4, height * 4);
}
void drawBorder(int x, int y, int width, int height, int color);
void fill(int x1, int y1, int x2, int y2, int color);
// ----------------------------
// Text
// ----------------------------
void drawText(String text, int x, int y, int font, int color);
void drawText(float scale, String text, int x, int y, int font, int color);
// ----------------------------
// Textures & Sprites
// ----------------------------
void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height);
void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height, int color);
void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
int regionWidth, int regionHeight, int textureWidth, int textureHeight);
void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color);
void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height);
void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height, int color);
// ----------------------------
// Items
// ----------------------------
void drawItem(ItemStackRef item, int x, int y);
// ----------------------------
// Scissor / Clipping
// ----------------------------
void enableScissor(int x1, int y1, int x2, int y2);
void disableScissor();
boolean scissorContains(int x, int y);
// ----------------------------
// Window Info / Draw
// ----------------------------
int getScaledWindowWidth();
int getScaledWindowHeight();
void draw();
}