diff options
Diffstat (limited to 'src/main/java/cc/polyfrost/oneconfig/renderer/image')
3 files changed, 261 insertions, 0 deletions
diff --git a/src/main/java/cc/polyfrost/oneconfig/renderer/image/ImageLoader.java b/src/main/java/cc/polyfrost/oneconfig/renderer/image/ImageLoader.java new file mode 100644 index 0000000..e8861eb --- /dev/null +++ b/src/main/java/cc/polyfrost/oneconfig/renderer/image/ImageLoader.java @@ -0,0 +1,190 @@ +package cc.polyfrost.oneconfig.renderer.image; + +import cc.polyfrost.oneconfig.utils.IOUtils; +import org.lwjgl.nanovg.NSVGImage; +import org.lwjgl.nanovg.NanoSVG; +import org.lwjgl.nanovg.NanoVG; +import org.lwjgl.stb.STBImage; +import org.lwjgl.system.MemoryUtil; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.util.HashMap; + +/** + * Loads images and SVGs from resources into NanoVG. + * + * @see cc.polyfrost.oneconfig.renderer.RenderManager + * @see Images + * @see SVGs + */ +public final class ImageLoader { + private ImageLoader() { + + } + + private final HashMap<String, Integer> imageHashMap = new HashMap<>(); + private final HashMap<String, Integer> svgHashMap = new HashMap<>(); + public static ImageLoader INSTANCE = new ImageLoader(); + + /** + * Loads an image from resources. + * + * @param vg The NanoVG context. + * @param fileName The name of the file to load. + * @return Whether the image was loaded successfully. + */ + public boolean loadImage(long vg, String fileName) { + if (!imageHashMap.containsKey(fileName)) { + int[] width = {0}; + int[] height = {0}; + int[] channels = {0}; + + ByteBuffer image = IOUtils.resourceToByteBufferNullable(fileName); + if (image == null) { + return false; + } + + ByteBuffer buffer = STBImage.stbi_load_from_memory(image, width, height, channels, 4); + if (buffer == null) { + return false; + } + + imageHashMap.put(fileName, NanoVG.nvgCreateImageRGBA(vg, width[0], height[0], NanoVG.NVG_IMAGE_REPEATX | NanoVG.NVG_IMAGE_REPEATY | NanoVG.NVG_IMAGE_GENERATE_MIPMAPS, buffer)); + return true; + } + return true; + } + + /** + * Loads an SVG from resources. + * + * @param vg The NanoVG context. + * @param fileName The name of the file to load. + * @param width The width of the SVG. + * @param height The height of the SVG. + * @return Whether the SVG was loaded successfully. + */ + public boolean loadSVG(long vg, String fileName, float width, float height) { + String name = fileName + "-" + width + "-" + height; + if (!svgHashMap.containsKey(name)) { + try { + InputStream inputStream = this.getClass().getResourceAsStream(fileName); + if (inputStream == null) return false; + StringBuilder resultStringBuilder = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = br.readLine()) != null) { + resultStringBuilder.append(line); + } + } + CharSequence s = resultStringBuilder.toString(); + NSVGImage svg = NanoSVG.nsvgParse(s, "px", 96f); + if (svg == null) return false; + long rasterizer = NanoSVG.nsvgCreateRasterizer(); + + int w = (int) svg.width(); + int h = (int) svg.height(); + float scale = Math.max(width / w, height / h); + w = (int) (w * scale); + h = (int) (h * scale); + + ByteBuffer image = MemoryUtil.memAlloc(w * h * 4); + NanoSVG.nsvgRasterize(rasterizer, svg, 0, 0, scale, image, w, h, w * 4); + + NanoSVG.nsvgDeleteRasterizer(rasterizer); + NanoSVG.nsvgDelete(svg); + + svgHashMap.put(name, NanoVG.nvgCreateImageRGBA(vg, w, h, NanoVG.NVG_IMAGE_REPEATX | NanoVG.NVG_IMAGE_REPEATY | NanoVG.NVG_IMAGE_GENERATE_MIPMAPS, image)); + return true; + } catch (Exception e) { + System.err.println("Failed to parse SVG file"); + e.printStackTrace(); + return false; + } + } + return true; + } + + /** + * Get a loaded image from the cache. + * <p><b>Requires the image to have been loaded first.</b></p> + * + * @param fileName The name of the file to load. + * @return The image + * @see ImageLoader#loadImage(long, String) + */ + public int getImage(String fileName) { + return imageHashMap.get(fileName); + } + + /** + * Remove an image from the cache, allowing the image to be garbage collected. + * Should be used when the GUI rendering the image is closed. + * + * @param vg The NanoVG context. + * @param fileName The name of the file to remove. + * @see ImageLoader#loadImage(long, String) + */ + public void removeImage(long vg, String fileName) { + NanoVG.nvgDeleteImage(vg, imageHashMap.get(fileName)); + imageHashMap.remove(fileName); + } + + /** + * Clears all images from the cache, allowing the images cleared to be garbage collected. + * Should be used when the GUI rendering loaded images are closed. + * + * @param vg The NanoVG context. + */ + public void clearImages(long vg) { + HashMap<String, Integer> temp = new HashMap<>(imageHashMap); + for (String image : temp.keySet()) { + NanoVG.nvgDeleteImage(vg, imageHashMap.get(image)); + imageHashMap.remove(image); + } + } + + /** + * Get a loaded SVG from the cache. + * <p><b>Requires the SVG to have been loaded first.</b></p> + * + * @param fileName The name of the file to load. + * @return The SVG + * @see ImageLoader#loadSVG(long, String, float, float) + */ + public int getSVG(String fileName, float width, float height) { + String name = fileName + "-" + width + "-" + height; + return svgHashMap.get(name); + } + + /** + * Remove a SVG from the cache, allowing the SVG to be garbage collected. + * Should be used when the GUI rendering the SVG is closed. + * + * @param vg The NanoVG context. + * @param fileName The name of the file to remove. + * @see ImageLoader#loadSVG(long, String, float, float) + */ + public void removeSVG(long vg, String fileName, float width, float height) { + String name = fileName + "-" + width + "-" + height; + NanoVG.nvgDeleteImage(vg, imageHashMap.get(name)); + svgHashMap.remove(name); + } + + /** + * Clears all SVGs from the cache, allowing the SVGs cleared to be garbage collected. + * Should be used when the GUI rendering loaded SVGs are closed. + * + * @param vg The NanoVG context. + */ + public void clearSVGs(long vg) { + HashMap<String, Integer> temp = new HashMap<>(svgHashMap); + for (String image : temp.keySet()) { + NanoVG.nvgDeleteImage(vg, svgHashMap.get(image)); + svgHashMap.remove(image); + } + } +} diff --git a/src/main/java/cc/polyfrost/oneconfig/renderer/image/Images.java b/src/main/java/cc/polyfrost/oneconfig/renderer/image/Images.java new file mode 100644 index 0000000..ad1941e --- /dev/null +++ b/src/main/java/cc/polyfrost/oneconfig/renderer/image/Images.java @@ -0,0 +1,19 @@ +package cc.polyfrost.oneconfig.renderer.image; + +/** + * An enum of images used in OneConfig. + * + * @see cc.polyfrost.oneconfig.renderer.RenderManager#drawImage(long, String, float, float, float, float, int) + * @see ImageLoader + */ +public enum Images { + HUE_GRADIENT("/assets/oneconfig/options/HueGradient.png"), + COLOR_WHEEL("/assets/oneconfig/options/ColorWheel.png"), + ALPHA_GRID("/assets/oneconfig/options/AlphaGrid.png"); + + public final String filePath; + + Images(String filePath) { + this.filePath = filePath; + } +}
\ No newline at end of file diff --git a/src/main/java/cc/polyfrost/oneconfig/renderer/image/SVGs.java b/src/main/java/cc/polyfrost/oneconfig/renderer/image/SVGs.java new file mode 100644 index 0000000..5ba3fcd --- /dev/null +++ b/src/main/java/cc/polyfrost/oneconfig/renderer/image/SVGs.java @@ -0,0 +1,52 @@ +package cc.polyfrost.oneconfig.renderer.image; + +/** + * An enum of SVGs used in OneConfig. + * + * @see cc.polyfrost.oneconfig.renderer.RenderManager#drawSvg(long, String, float, float, float, float, int) + * @see ImageLoader + */ +public enum SVGs { + ONECONFIG("/assets/oneconfig/icons/OneConfig.svg"), + ONECONFIG_OFF("/assets/oneconfig/icons/OneConfigOff.svg"), + COPYRIGHT_FILL("/assets/oneconfig/icons/CopyrightFill.svg"), + APERTURE_FILL("/assets/oneconfig/icons/ApertureFill.svg"), + ARROWS_CLOCKWISE_BOLD("/assets/oneconfig/icons/ArrowsClockwiseBold.svg"), + FADERS_HORIZONTAL_BOLD("/assets/oneconfig/icons/FadersHorizontalBold.svg"), + GAUGE_FILL("/assets/oneconfig/icons/GaugeFill.svg"), + GEAR_SIX_FILL("/assets/oneconfig/icons/GearSixFill.svg"), + MAGNIFYING_GLASS_BOLD("/assets/oneconfig/icons/MagnifyingGlassBold.svg"), + NOTE_PENCIL_BOLD("/assets/oneconfig/icons/NotePencilBold.svg"), + PAINT_BRUSH_BROAD_FILL("/assets/oneconfig/icons/PaintBrushBroadFill.svg"), + USER_SWITCH_FILL("/assets/oneconfig/icons/UserSwitchFill.svg"), + X_CIRCLE_BOLD("/assets/oneconfig/icons/XCircleBold.svg"), + CARET_LEFT("/assets/oneconfig/icons/CaretLeftBold.svg"), + CARET_RIGHT("/assets/oneconfig/icons/CaretRightBold.svg"), + + // OLD ICONS + BOX("/assets/oneconfig/old-icons/Box.svg"), + CHECKBOX_TICK("/assets/oneconfig/old-icons/CheckboxTick.svg"), + CHECK_CIRCLE("/assets/oneconfig/old-icons/CheckCircle.svg"), + CHEVRON_DOWN("/assets/oneconfig/old-icons/ChevronDown.svg"), + CHEVRON_UP("/assets/oneconfig/old-icons/ChevronUp.svg"), + COPY("/assets/oneconfig/old-icons/Copy.svg"), + DROPDOWN_LIST("/assets/oneconfig/old-icons/DropdownList.svg"), + ERROR("/assets/oneconfig/old-icons/Error.svg"), + EYE("/assets/oneconfig/old-icons/Eye.svg"), + EYE_OFF("/assets/oneconfig/old-icons/EyeOff.svg"), + HEART_FILL("/assets/oneconfig/old-icons/HeartFill.svg"), + HEART_OUTLINE("/assets/oneconfig/old-icons/HeartOutline.svg"), + HELP_CIRCLE("/assets/oneconfig/old-icons/HelpCircle.svg"), + HISTORY("/assets/oneconfig/old-icons/History.svg"), + INFO_CIRCLE("/assets/oneconfig/old-icons/InfoCircle.svg"), + KEYSTROKE("/assets/oneconfig/old-icons/Keystroke.svg"), + PASTE("/assets/oneconfig/old-icons/Paste.svg"), + POP_OUT("/assets/oneconfig/old-icons/PopOut.svg"), + WARNING("/assets/oneconfig/old-icons/Warning.svg"); + + public final String filePath; + + SVGs(String filePath) { + this.filePath = filePath; + } +} |