aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/io/polyfrost/oneconfig/lwjgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/io/polyfrost/oneconfig/lwjgl')
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/IOUtil.java53
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/Lwjgl2FunctionProvider.java39
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/RenderManager.java194
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/font/Font.java39
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/font/FontManager.java34
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/image/Image.java20
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/image/ImageLoader.java39
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/ClassTransformer.java55
-rw-r--r--src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/LoadingPlugin.java52
9 files changed, 525 insertions, 0 deletions
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/IOUtil.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/IOUtil.java
new file mode 100644
index 0000000..f5105fb
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/IOUtil.java
@@ -0,0 +1,53 @@
+package io.polyfrost.oneconfig.lwjgl;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public final class IOUtil {
+
+ private IOUtil() {
+ }
+
+ /**
+ * Taken from legui under MIT License
+ * https://github.com/SpinyOwl/legui/blob/develop/LICENSE
+ */
+ @SuppressWarnings("RedundantCast")
+ public static ByteBuffer resourceToByteBuffer(String path) throws IOException {
+ byte[] bytes;
+ path = path.trim();
+ if (path.startsWith("http")) {
+ bytes = IOUtils.toByteArray(new URL(path));
+ } else {
+ InputStream stream;
+ File file = new File(path);
+ if (file.exists() && file.isFile()) {
+ stream = new FileInputStream(file);
+ } else {
+ stream = IOUtil.class.getResourceAsStream(path);
+ }
+ if (stream == null) {
+ throw new FileNotFoundException(path);
+ }
+ bytes = IOUtils.toByteArray(stream);
+ }
+ ByteBuffer data = ByteBuffer.allocateDirect(bytes.length).order(ByteOrder.nativeOrder())
+ .put(bytes);
+ ((Buffer) data).flip();
+ return data;
+ }
+
+ public static ByteBuffer resourceToByteBufferNullable(String path) {
+ try {
+ return resourceToByteBuffer(path);
+ } catch (Exception ignored) {
+ return null;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/Lwjgl2FunctionProvider.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/Lwjgl2FunctionProvider.java
new file mode 100644
index 0000000..ea1a44b
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/Lwjgl2FunctionProvider.java
@@ -0,0 +1,39 @@
+package io.polyfrost.oneconfig.lwjgl;
+
+import org.lwjgl.opengl.GLContext;
+import org.lwjgl.system.FunctionProvider;
+
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+
+/**
+ * Taken from LWJGLTwoPointFive under The Unlicense
+ * https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/
+ */
+public class Lwjgl2FunctionProvider implements FunctionProvider {
+
+ private final Method m_getFunctionAddress;
+
+ public Lwjgl2FunctionProvider() {
+ try {
+ m_getFunctionAddress = GLContext.class.getDeclaredMethod("getFunctionAddress", String.class);
+ m_getFunctionAddress.setAccessible(true);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public long getFunctionAddress(CharSequence functionName) {
+ try {
+ return (long) m_getFunctionAddress.invoke(null, functionName.toString());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public long getFunctionAddress(ByteBuffer byteBuffer) {
+ throw new UnsupportedOperationException();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/RenderManager.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/RenderManager.java
new file mode 100644
index 0000000..72cb75a
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/RenderManager.java
@@ -0,0 +1,194 @@
+package io.polyfrost.oneconfig.lwjgl;
+
+import io.polyfrost.oneconfig.lwjgl.font.Font;
+import io.polyfrost.oneconfig.lwjgl.font.FontManager;
+import io.polyfrost.oneconfig.lwjgl.image.Image;
+import io.polyfrost.oneconfig.lwjgl.image.ImageLoader;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.shader.Framebuffer;
+import org.lwjgl.nanovg.NVGColor;
+import org.lwjgl.nanovg.NVGPaint;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.util.function.LongConsumer;
+
+import static org.lwjgl.nanovg.NanoVG.*;
+import static org.lwjgl.nanovg.NanoVGGL2.NVG_ANTIALIAS;
+import static org.lwjgl.nanovg.NanoVGGL2.nvgCreate;
+
+public final class RenderManager {
+ private RenderManager() {
+
+ }
+
+ //nanovg
+
+ private static long vg = -1;
+
+ public static void setupAndDraw(LongConsumer consumer) {
+ setupAndDraw(false, consumer);
+ }
+
+ public static void setupAndDraw(boolean mcScaling, LongConsumer consumer) {
+ if (vg == -1) {
+ vg = nvgCreate(NVG_ANTIALIAS);
+ if (vg == -1) {
+ throw new RuntimeException("Failed to create nvg context");
+ }
+ FontManager.INSTANCE.initialize(vg);
+ }
+
+ Framebuffer fb = Minecraft.getMinecraft().getFramebuffer();
+ if (!fb.isStencilEnabled()) {
+ fb.enableStencil();
+ }
+ GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
+
+ if (mcScaling) {
+ ScaledResolution resolution = new ScaledResolution(Minecraft.getMinecraft());
+ nvgBeginFrame(vg, (float) resolution.getScaledWidth_double(), (float) resolution.getScaledHeight_double(), 1);
+ } else {
+ nvgBeginFrame(vg, Display.getWidth(), Display.getHeight(), 1);
+ }
+
+ consumer.accept(vg);
+
+ nvgEndFrame(vg);
+
+ GlStateManager.popAttrib();
+ }
+
+ public static void drawRect(long vg, float x, float y, float width, float height, int color) {
+ nvgBeginPath(vg);
+ nvgRect(vg, x, y, width, height);
+ NVGColor nvgColor = color(vg, color);
+ nvgFill(vg);
+ nvgColor.free();
+ }
+
+ public static void drawRoundedRect(long vg, float x, float y, float width, float height, int color, float radius) {
+ nvgBeginPath(vg);
+ nvgRoundedRect(vg, x, y, width, height, radius);
+ color(vg, color);
+ NVGColor nvgColor = color(vg, color);
+ nvgFill(vg);
+ nvgColor.free();
+ }
+
+ public static void drawCircle(long vg, float x, float y, float radius, int color) {
+ nvgBeginPath(vg);
+ nvgCircle(vg, x, y, radius);
+ NVGColor nvgColor = color(vg, color);
+ nvgFill(vg);
+ nvgColor.free();
+ }
+
+ public static void drawString(long vg, String text, float x, float y, int color, float size, Font font) {
+ drawString(vg, text, x, y, color, size, font.getName());
+ }
+
+ public static void drawString(long vg, String text, float x, float y, int color, float size, String fontName) {
+ nvgBeginPath(vg);
+ nvgFontSize(vg, size);
+ nvgFontFace(vg, fontName);
+ nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
+ NVGColor nvgColor = color(vg, color);
+ nvgText(vg, x, y, text);
+ nvgFill(vg);
+ nvgColor.free();
+ }
+
+ public static void drawWrappedString(long vg, String text, float x, float y, float width, int color, float size, Font font) {
+ drawWrappedString(vg, text, x, y, width, color, size, font.getName());
+ }
+
+ public static void drawWrappedString(long vg, String text, float x, float y, float width, int color, float size, String fontName) {
+ nvgBeginPath(vg);
+ nvgFontSize(vg, size);
+ nvgFontFace(vg, fontName);
+ nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
+ NVGColor nvgColor = color(vg, color);
+ nvgTextBox(vg, x, y, width, text);
+ nvgFill(vg);
+ nvgColor.free();
+ }
+
+ public static void drawImage(long vg, String fileName, float x, float y, float width, float height) {
+ if (ImageLoader.INSTANCE.loadImage(vg, fileName)) {
+ NVGPaint imagePaint = NVGPaint.calloc();
+ Image image = ImageLoader.INSTANCE.getImage(fileName);
+ nvgBeginPath(vg);
+ nvgImagePattern(vg, x, y, width, height, 0, image.getReference(), 1, imagePaint);
+ nvgRect(vg, x, y, width, height);
+ nvgFillPaint(vg, imagePaint);
+ nvgFill(vg);
+ imagePaint.free();
+ }
+ }
+
+ public static void drawLine(long vg, float x, float y, float endX, float endY, float width, int color) {
+ nvgBeginPath(vg);
+ nvgMoveTo(vg, x, y);
+ nvgLineTo(vg, endX, endY);
+ NVGColor nvgColor = color(vg, color);
+ nvgStrokeColor(vg, nvgColor);
+ nvgStrokeWidth(vg, width);
+ nvgStroke(vg);
+ nvgColor.free();
+ }
+
+ public static NVGColor color(long vg, int color) {
+ NVGColor nvgColor = NVGColor.calloc();
+ nvgRGBA((byte) (color >> 16 & 0xFF), (byte) (color >> 8 & 0xFF), (byte) (color & 0xFF), (byte) (color >> 24 & 0xFF), nvgColor);
+ nvgFillColor(vg, nvgColor);
+ return nvgColor;
+ }
+
+ //gl
+
+ public static void drawScaledString(String text, float x, float y, int color, boolean shadow, float scale) {
+ GlStateManager.pushMatrix();
+ GlStateManager.scale(scale, scale, 1);
+ Minecraft.getMinecraft().fontRendererObj.drawString(text, x * (1 / scale), y * (1 / scale), color, shadow);
+ GlStateManager.popMatrix();
+ }
+
+ public static void color(Color color) {
+ color(color.getRGB());
+ }
+
+ public static void color(int color) {
+ float f = (float) (color >> 24 & 255) / 255.0F;
+ float f1 = (float) (color >> 16 & 255) / 255.0F;
+ float f2 = (float) (color >> 8 & 255) / 255.0F;
+ float f3 = (float) (color & 255) / 255.0F;
+ GlStateManager.color(f1, f2, f3, f);
+ }
+
+ public static void drawDottedLine(float sx, float sy, float ex, float ey, int width, int factor, int color) {
+ GlStateManager.pushMatrix();
+ GL11.glLineStipple(factor, (short) 0xAAAA);
+ GL11.glEnable(GL11.GL_LINE_STIPPLE);
+ GlStateManager.pushMatrix();
+ GlStateManager.disableTexture2D();
+ GlStateManager.enableBlend();
+ GlStateManager.disableAlpha();
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+ color(color);
+ GL11.glLineWidth(width);
+ GL11.glBegin(GL11.GL_LINES);
+ GL11.glVertex2d(sx, sy);
+ GL11.glVertex2d(ex, ey);
+ GL11.glEnd();
+ GlStateManager.disableBlend();
+ GlStateManager.enableAlpha();
+ GlStateManager.enableTexture2D();
+ GlStateManager.popMatrix();
+ GL11.glDisable(GL11.GL_LINE_STIPPLE);
+ GlStateManager.popMatrix();
+ }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/font/Font.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/font/Font.java
new file mode 100644
index 0000000..f250a46
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/font/Font.java
@@ -0,0 +1,39 @@
+package io.polyfrost.oneconfig.lwjgl.font;
+
+import java.nio.ByteBuffer;
+
+public class Font {
+ private final String fileName;
+ private final String name;
+ private boolean loaded = false;
+ private ByteBuffer buffer = null;
+
+ public Font(String name, String fileName) {
+ this.name = name;
+ this.fileName = fileName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+ void setLoaded(boolean loaded) {
+ this.loaded = loaded;
+ }
+
+ public ByteBuffer getBuffer() {
+ return buffer;
+ }
+
+ void setBuffer(ByteBuffer buffer) {
+ this.buffer = buffer;
+ }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/font/FontManager.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/font/FontManager.java
new file mode 100644
index 0000000..20a8cc7
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/font/FontManager.java
@@ -0,0 +1,34 @@
+package io.polyfrost.oneconfig.lwjgl.font;
+
+import io.polyfrost.oneconfig.lwjgl.IOUtil;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import static org.lwjgl.nanovg.NanoVG.nvgCreateFontMem;
+
+public class FontManager {
+ public static FontManager INSTANCE = new FontManager();
+ private final ArrayList<Font> fonts = new ArrayList<>();
+
+ public void initialize(long vg) {
+ fonts.add(new Font("inter-bold", "/assets/oneconfig/font/Inter-Bold.ttf"));
+ fonts.add(new Font("mc-regular", "/assets/oneconfig/font/Minecraft-Regular.otf"));
+ for (Font font : fonts) {
+ int loaded = -1;
+ try {
+ ByteBuffer buffer = IOUtil.resourceToByteBuffer(font.getFileName());
+ loaded = nvgCreateFontMem(vg, font.getName(), buffer, 0);
+ font.setBuffer(buffer);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (loaded == -1) {
+ throw new RuntimeException("Failed to initialize font " + font.getName());
+ } else {
+ font.setLoaded(true);
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/image/Image.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/image/Image.java
new file mode 100644
index 0000000..2ed7276
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/image/Image.java
@@ -0,0 +1,20 @@
+package io.polyfrost.oneconfig.lwjgl.image;
+
+import java.nio.ByteBuffer;
+
+public class Image {
+ private final int reference;
+ private final ByteBuffer buffer;
+ public Image(int reference, ByteBuffer buffer) {
+ this.reference = reference;
+ this.buffer = buffer;
+ }
+
+ public ByteBuffer getBuffer() {
+ return buffer;
+ }
+
+ public int getReference() {
+ return reference;
+ }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/image/ImageLoader.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/image/ImageLoader.java
new file mode 100644
index 0000000..b0cb6d4
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/image/ImageLoader.java
@@ -0,0 +1,39 @@
+package io.polyfrost.oneconfig.lwjgl.image;
+
+import io.polyfrost.oneconfig.lwjgl.IOUtil;
+import org.lwjgl.nanovg.NanoVG;
+import org.lwjgl.stb.STBImage;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+public class ImageLoader {
+ private final HashMap<String, Image> imageHashMap = new HashMap<>();
+ public static ImageLoader INSTANCE = new ImageLoader();
+
+ public boolean loadImage(long vg, String fileName) {
+ if (!imageHashMap.containsKey(fileName)) {
+ int[] width = {0};
+ int[] height = {0};
+ int[] channels = {0};
+
+ ByteBuffer image = IOUtil.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, new Image(NanoVG.nvgCreateImageRGBA(vg, width[0], height[0], NanoVG.NVG_IMAGE_REPEATX | NanoVG.NVG_IMAGE_REPEATY | NanoVG.NVG_IMAGE_GENERATE_MIPMAPS, buffer), buffer));
+ return true;
+ }
+ return true;
+ }
+
+ public Image getImage(String fileName) {
+ return imageHashMap.get(fileName);
+ }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/ClassTransformer.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/ClassTransformer.java
new file mode 100644
index 0000000..066677b
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/ClassTransformer.java
@@ -0,0 +1,55 @@
+package io.polyfrost.oneconfig.lwjgl.plugin;
+
+import net.minecraft.launchwrapper.IClassTransformer;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.*;
+
+/**
+ * Taken from LWJGLTwoPointFive under The Unlicense
+ * https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/
+ */
+public class ClassTransformer implements IClassTransformer {
+ @Override
+ public byte[] transform(String name, String transformedName, byte[] basicClass) {
+ if (name.equals("org.lwjgl.nanovg.NanoVGGLConfig")) {
+ ClassReader reader = new ClassReader(basicClass);
+ ClassNode node = new ClassNode();
+ reader.accept(node, ClassReader.EXPAND_FRAMES);
+
+ for (MethodNode method : node.methods) {
+ if (method.name.equals("configGL")) {
+ InsnList list = new InsnList();
+
+ list.add(new VarInsnNode(Opcodes.LLOAD, 0));
+ list.add(new TypeInsnNode(Opcodes.NEW, "io/polyfrost/oneconfig/lwjgl/Lwjgl2FunctionProvider"));
+ list.add(new InsnNode(Opcodes.DUP));
+ list.add(new MethodInsnNode(
+ Opcodes.INVOKESPECIAL,
+ "io/polyfrost/oneconfig/lwjgl/Lwjgl2FunctionProvider",
+ "<init>",
+ "()V",
+ false
+ ));
+ list.add(new MethodInsnNode(
+ Opcodes.INVOKESTATIC,
+ "org/lwjgl/nanovg/NanoVGGLConfig",
+ "config",
+ "(JLorg/lwjgl/system/FunctionProvider;)V",
+ false
+ ));
+ list.add(new InsnNode(Opcodes.RETURN));
+
+ method.instructions.clear();
+ method.instructions.insert(list);
+ }
+ }
+
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+ node.accept(cw);
+ return cw.toByteArray();
+ }
+ return basicClass;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/LoadingPlugin.java b/src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/LoadingPlugin.java
new file mode 100644
index 0000000..1f48135
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/lwjgl/plugin/LoadingPlugin.java
@@ -0,0 +1,52 @@
+package io.polyfrost.oneconfig.lwjgl.plugin;
+
+import net.minecraft.launchwrapper.Launch;
+import net.minecraft.launchwrapper.LaunchClassLoader;
+import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Taken from LWJGLTwoPointFive under The Unlicense
+ * https://github.com/DJtheRedstoner/LWJGLTwoPointFive/blob/master/LICENSE/
+ */
+public class LoadingPlugin implements IFMLLoadingPlugin {
+
+ public LoadingPlugin() {
+ try {
+ Field f_exceptions = LaunchClassLoader.class.getDeclaredField("classLoaderExceptions");
+ f_exceptions.setAccessible(true);
+ Set<String> exceptions = (Set<String>) f_exceptions.get(Launch.classLoader);
+ exceptions.remove("org.lwjgl.");
+ } catch (Exception e) {
+ throw new RuntimeException("e");
+ }
+ }
+
+ @Override
+ public String[] getASMTransformerClass() {
+ return new String[]{"io.polyfrost.oneconfig.lwjgl.plugin.ClassTransformer"};
+ }
+
+ @Override
+ public String getModContainerClass() {
+ return null;
+ }
+
+ @Override
+ public String getSetupClass() {
+ return null;
+ }
+
+ @Override
+ public void injectData(Map<String, Object> data) {
+
+ }
+
+ @Override
+ public String getAccessTransformerClass() {
+ return null;
+ }
+} \ No newline at end of file