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( "", 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, "", 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( "%s", 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(); }