aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/makamys/neodymium/Neodymium.java21
-rw-r--r--src/main/java/makamys/neodymium/renderer/ChunkMesh.java12
-rw-r--r--src/main/java/makamys/neodymium/renderer/MeshQuad.java392
-rw-r--r--src/main/java/makamys/neodymium/renderer/NeoRenderer.java64
-rw-r--r--src/main/java/makamys/neodymium/renderer/compat/RenderUtil.java18
-rw-r--r--src/main/java/makamys/neodymium/renderer/compat/RenderUtilRPLE.java109
-rw-r--r--src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaderRPLE.java156
-rw-r--r--src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaders.java126
-rw-r--r--src/main/java/makamys/neodymium/renderer/compat/RenderUtilVanilla.java96
9 files changed, 536 insertions, 458 deletions
diff --git a/src/main/java/makamys/neodymium/Neodymium.java b/src/main/java/makamys/neodymium/Neodymium.java
index 3750ddd..320e46a 100644
--- a/src/main/java/makamys/neodymium/Neodymium.java
+++ b/src/main/java/makamys/neodymium/Neodymium.java
@@ -7,9 +7,12 @@ import static makamys.neodymium.Constants.VERSION;
import java.util.ArrayList;
import java.util.List;
+import makamys.neodymium.renderer.compat.RenderUtil;
+import makamys.neodymium.renderer.compat.RenderUtilRPLE;
+import makamys.neodymium.renderer.compat.RenderUtilShaderRPLE;
+import makamys.neodymium.renderer.compat.RenderUtilShaders;
+import makamys.neodymium.renderer.compat.RenderUtilVanilla;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import cpw.mods.fml.client.event.ConfigChangedEvent;
import cpw.mods.fml.common.FMLCommonHandler;
@@ -18,7 +21,6 @@ import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
-import cpw.mods.fml.common.event.FMLServerAboutToStartEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
@@ -49,6 +51,8 @@ public class Neodymium
private boolean renderDebugText = false;
public static NeoRenderer renderer;
+
+ public static RenderUtil util;
private static World rendererWorld;
@@ -97,6 +101,17 @@ public class Neodymium
List<Warning> criticalWarns = warnsAndCriticalWarns.getRight();
if(criticalWarns.isEmpty()) {
+ boolean rple = Compat.isRPLEModPresent();
+ boolean optiFineShaders = Compat.isOptiFineShadersEnabled();
+ if (rple && optiFineShaders) {
+ util = RenderUtilShaderRPLE.INSTANCE;
+ } else if (optiFineShaders) {
+ util = RenderUtilShaders.INSTANCE;
+ } else if (rple) {
+ util = RenderUtilRPLE.INSTANCE;
+ } else {
+ util = RenderUtilVanilla.INSTANCE;
+ }
renderer = new NeoRenderer(newWorld);
renderer.hasIncompatibilities = !warns.isEmpty() || !criticalWarns.isEmpty();
}
diff --git a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
index 9d98bd3..9f1e8fc 100644
--- a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
+++ b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java
@@ -197,7 +197,7 @@ public class ChunkMesh extends Mesh {
if(subMeshStart[subMeshStartIdx] == -1) {
subMeshStart[subMeshStartIdx] = i;
}
- quad.writeToBuffer(out, stride);
+ Neodymium.util.writeMeshQuadToBuffer(quad, out, stride);
i++;
} else if(sortByNormals){
break;
@@ -301,12 +301,12 @@ public class ChunkMesh extends Mesh {
public static void setCaptureTarget(ChunkMesh cm) {
meshCaptureTarget = cm;
}
-
+
public static class Flags {
- boolean hasTexture;
- boolean hasBrightness;
- boolean hasColor;
- boolean hasNormals;
+ public boolean hasTexture;
+ public boolean hasBrightness;
+ public boolean hasColor;
+ public boolean hasNormals;
public Flags(byte flags) {
hasTexture = (flags & 1) != 0;
diff --git a/src/main/java/makamys/neodymium/renderer/MeshQuad.java b/src/main/java/makamys/neodymium/renderer/MeshQuad.java
index 2a9fe2d..cfae0b3 100644
--- a/src/main/java/makamys/neodymium/renderer/MeshQuad.java
+++ b/src/main/java/makamys/neodymium/renderer/MeshQuad.java
@@ -1,6 +1,7 @@
package makamys.neodymium.renderer;
import makamys.neodymium.Compat;
+import makamys.neodymium.Neodymium;
import makamys.neodymium.config.Config;
import makamys.neodymium.util.BufferWriter;
import makamys.neodymium.util.Util;
@@ -10,8 +11,8 @@ import org.lwjgl.util.vector.Vector3f;
import java.util.Locale;
public class MeshQuad {
- private final static int DEFAULT_BRIGHTNESS = Util.createBrightness(15, 15);
- private final static int DEFAULT_COLOR = 0xFFFFFFFF;
+ public final static int DEFAULT_BRIGHTNESS = Util.createBrightness(15, 15);
+ public final static int DEFAULT_COLOR = 0xFFFFFFFF;
//region common
@@ -68,250 +69,11 @@ public class MeshQuad {
private static Vector3f vectorB = new Vector3f();
private static Vector3f vectorC = new Vector3f();
-
- private void read(int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
- boolean rple = Compat.isRPLEModPresent();
- boolean optiFineShaders = Compat.isOptiFineShadersEnabled();
-
- if (rple && optiFineShaders) {
- readRPLEAndShaders(rawBuffer, tessellatorVertexSize, offset, offsetX, offsetY, offsetZ, drawMode, flags);
- } else if (optiFineShaders) {
- readShaders(rawBuffer, tessellatorVertexSize, offset, offsetX, offsetY, offsetZ, drawMode, flags);
- } else if (rple) {
- readRPLE(rawBuffer, tessellatorVertexSize, offset, offsetX, offsetY, offsetZ, drawMode, flags);
- } else {
- readVanilla(rawBuffer, tessellatorVertexSize, offset, offsetX, offsetY, offsetZ, drawMode, flags);
- }
- }
-
- //region read implementations
-
- private void readRPLEAndShaders(int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
- //RPLE and Shaders
- int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
- for(int vi = 0; vi < vertices; vi++) {
- int i = offset + vi * tessellatorVertexSize;
-
- xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
- ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
- zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
-
- us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
- vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
-
- cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
-
- bs[vi] = flags.hasBrightness ? rawBuffer[i + 6] : DEFAULT_BRIGHTNESS;
-
- e1[vi] = rawBuffer[i + 7];
- e2[vi] = rawBuffer[i + 8];
-
- xn[vi] = Float.intBitsToFloat(rawBuffer[i + 9]);
- yn[vi] = Float.intBitsToFloat(rawBuffer[i + 10]);
- zn[vi] = Float.intBitsToFloat(rawBuffer[i + 11]);
-
- xt[vi] = Float.intBitsToFloat(rawBuffer[i + 12]);
- yt[vi] = Float.intBitsToFloat(rawBuffer[i + 13]);
- zt[vi] = Float.intBitsToFloat(rawBuffer[i + 14]);
- wt[vi] = Float.intBitsToFloat(rawBuffer[i + 15]);
-
- um[vi] = Float.intBitsToFloat(rawBuffer[i + 16]);
- vm[vi] = Float.intBitsToFloat(rawBuffer[i + 17]);
-
- if (flags.hasBrightness) {
- bsG[vi] = rawBuffer[i + 18];
- bsB[vi] = rawBuffer[i + 19];
- } else {
- bsG[vi] = DEFAULT_BRIGHTNESS;
- bsB[vi] = DEFAULT_BRIGHTNESS;
- }
-
- ue[vi] = Float.intBitsToFloat(rawBuffer[i + 20]);
- ve[vi] = Float.intBitsToFloat(rawBuffer[i + 21]);
- }
-
- if(vertices == 3) {
- // Quadrangulate!
- xs[3] = xs[2];
- ys[3] = ys[2];
- zs[3] = zs[2];
-
- us[3] = us[2];
- vs[3] = vs[2];
-
- cs[3] = cs[2];
-
- bs[3] = bs[2];
-
- e1[3] = e1[2];
- e2[3] = e2[2];
-
- xn[3] = xn[2];
- yn[3] = yn[2];
- zn[3] = zn[2];
-
- xt[3] = xt[2];
- yt[3] = yt[2];
- zt[3] = zt[2];
- wt[3] = wt[2];
-
- um[3] = um[2];
- vm[3] = vm[2];
-
- bsG[3] = bsG[2];
- bsB[3] = bsB[2];
-
- ue[3] = ue[2];
- ve[3] = ve[2];
- }
- }
-
- private void readShaders(int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
- //Only shaders
- int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
- for (int vi = 0; vi < vertices; vi++) {
- int i = offset + vi * tessellatorVertexSize;
-
- xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
- ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
- zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
-
- us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
- vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
-
- cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
-
- bs[vi] = flags.hasBrightness ? rawBuffer[i + 6] : DEFAULT_BRIGHTNESS;
- e1[vi] = rawBuffer[i + 7];
- e2[vi] = rawBuffer[i + 8];
- xn[vi] = Float.intBitsToFloat(rawBuffer[i + 9]);
- yn[vi] = Float.intBitsToFloat(rawBuffer[i + 10]);
- zn[vi] = Float.intBitsToFloat(rawBuffer[i + 11]);
- xt[vi] = Float.intBitsToFloat(rawBuffer[i + 12]);
- yt[vi] = Float.intBitsToFloat(rawBuffer[i + 13]);
- zt[vi] = Float.intBitsToFloat(rawBuffer[i + 14]);
- wt[vi] = Float.intBitsToFloat(rawBuffer[i + 15]);
- um[vi] = Float.intBitsToFloat(rawBuffer[i + 16]);
- vm[vi] = Float.intBitsToFloat(rawBuffer[i + 17]);
- }
-
- if (vertices == 3) {
- // Quadrangulate!
- xs[3] = xs[2];
- ys[3] = ys[2];
- zs[3] = zs[2];
-
- us[3] = us[2];
- vs[3] = vs[2];
-
- cs[3] = cs[2];
-
- bs[3] = bs[2];
-
- e1[3] = e1[2];
- e2[3] = e2[2];
-
- xn[3] = xn[2];
- yn[3] = yn[2];
- zn[3] = zn[2];
-
- xt[3] = xt[2];
- yt[3] = yt[2];
- zt[3] = zt[2];
- wt[3] = wt[2];
-
- um[3] = um[2];
- vm[3] = vm[2];
- }
- }
-
- private void readRPLE(int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
- //Only RPLE
- int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
- for(int vi = 0; vi < vertices; vi++) {
- int i = offset + vi * tessellatorVertexSize;
-
- xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
- ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
- zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
-
- us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
- vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
-
- cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
-
- // TODO normals?
-
- if (flags.hasBrightness) {
- bs[vi] = rawBuffer[i + 7];
- bsG[vi] = rawBuffer[i + 8];
- bsB[vi] = rawBuffer[i + 9];
- } else {
- bs[vi] = DEFAULT_BRIGHTNESS;
- bsG[vi] = DEFAULT_BRIGHTNESS;
- bsB[vi] = DEFAULT_BRIGHTNESS;
- }
- }
-
- if(vertices == 3) {
- // Quadrangulate!
- xs[3] = xs[2];
- ys[3] = ys[2];
- zs[3] = zs[2];
-
- us[3] = us[2];
- vs[3] = vs[2];
-
- cs[3] = cs[2];
-
- bs[3] = bs[2];
- bsG[3] = bsG[2];
- bsB[3] = bsB[2];
- }
- }
-
- private void readVanilla(int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
- //No RPLE or Shaders
- int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
- for(int vi = 0; vi < vertices; vi++) {
- int i = offset + vi * tessellatorVertexSize;
-
- xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
- ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
- zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
-
- us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
- vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
-
- cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
-
- // TODO normals?
-
- bs[vi] = flags.hasBrightness ? rawBuffer[i + 7] : DEFAULT_BRIGHTNESS;
- }
-
- if(vertices == 3) {
- // Quadrangulate!
- xs[3] = xs[2];
- ys[3] = ys[2];
- zs[3] = zs[2];
-
- us[3] = us[2];
- vs[3] = vs[2];
-
- cs[3] = cs[2];
-
- bs[3] = bs[2];
- }
- }
-
- //endregion read implementations
-
public void setState(int[] rawBuffer, int tessellatorVertexSize, int offset, ChunkMesh.Flags flags, int drawMode, float offsetX, float offsetY, float offsetZ) {
deleted = false;
- read(rawBuffer, tessellatorVertexSize, offset, offsetX, offsetY, offsetZ, drawMode, flags);
-
+ Neodymium.util.readMeshQuad(this, rawBuffer, tessellatorVertexSize, offset, offsetX, offsetY, offsetZ, drawMode, flags);
+
if(xs[0] == xs[1] && xs[1] == xs[2] && xs[2] == xs[3] && ys[0] == ys[1] && ys[1] == ys[2] && ys[2] == ys[3]) {
// ignore empty quads (e.g. alpha pass of EnderIO item conduits)
deleted = true;
@@ -325,150 +87,6 @@ public class MeshQuad {
normal = QuadNormal.fromVector(vectorC);
}
- /**
- * @implSpec These needs to be kept in sync with the attributes in {@link NeoRenderer#init()}
- */
- public void writeToBuffer(BufferWriter out, int expectedStride) {
- boolean rple = Compat.isRPLEModPresent();
- boolean shaders = Compat.isOptiFineShadersEnabled();
-
- if (rple && shaders) {
- writeToBufferRPLEAndShaders(out, expectedStride);
- } else if (shaders) {
- writeToBufferShaders(out, expectedStride);
- } else if (rple) {
- writeToBufferRPLE(out, expectedStride);
- } else {
- writeToBufferVanilla(out, expectedStride);
- }
- }
-
- //region writeToBuffer implementations
-
- public void writeToBufferRPLEAndShaders(BufferWriter out, int expectedStride) {
- for(int vi = 0; vi < 4; vi++) {
- out.writeFloat(xs[vi]);
- out.writeFloat(ys[vi]);
- out.writeFloat(zs[vi]);
-
- out.writeFloat(us[vi]);
- out.writeFloat(vs[vi]);
-
- out.writeInt(cs[vi]);
-
- out.writeInt(bs[vi]);
-
- out.writeInt(e1[vi]);
- out.writeInt(e2[vi]);
-
- out.writeFloat(xn[vi]);
- out.writeFloat(yn[vi]);
- out.writeFloat(zn[vi]);
-
- out.writeFloat(xt[vi]);
- out.writeFloat(yt[vi]);
- out.writeFloat(zt[vi]);
- out.writeFloat(wt[vi]);
-
- out.writeFloat(um[vi]);
- out.writeFloat(vm[vi]);
-
- out.writeInt(bsG[vi]);
- out.writeInt(bsB[vi]);
-
- out.writeFloat(ue[vi]);
- out.writeFloat(ve[vi]);
-
- assert out.position() % expectedStride == 0;
- }
- }
-
- public void writeToBufferShaders(BufferWriter out, int expectedStride) {
- for(int vi = 0; vi < 4; vi++) {
- out.writeFloat(xs[vi]);
- out.writeFloat(ys[vi]);
- out.writeFloat(zs[vi]);
-
- out.writeFloat(us[vi]);
- out.writeFloat(vs[vi]);
-
- out.writeInt( cs[vi]);
-
- out.writeInt(bs[vi]);
-
- out.writeInt(e1[vi]);
- out.writeInt(e2[vi]);
-
- out.writeFloat(xn[vi]);
- out.writeFloat(yn[vi]);
- out.writeFloat(zn[vi]);
-
- out.writeFloat(xt[vi]);
- out.writeFloat(yt[vi]);
- out.writeFloat(zt[vi]);
- out.writeFloat(wt[vi]);
-
- out.writeFloat(um[vi]);
- out.writeFloat(vm[vi]);
-
- assert out.position() % expectedStride == 0;
- }
- }
-
- public void writeToBufferRPLE(BufferWriter out, int expectedStride) {
- for(int vi = 0; vi < 4; vi++) {
- out.writeFloat(xs[vi]);
- out.writeFloat(ys[vi]);
- out.writeFloat(zs[vi]);
-
- float u = us[vi];
- float v = vs[vi];
-
- if(Config.shortUV) {
- out.writeShort((short)(Math.round(u * 32768f)));
- out.writeShort((short)(Math.round(v * 32768f)));
- } else {
- out.writeFloat(u);
- out.writeFloat(v);
- }
-
- out.writeInt(cs[vi]);
-
- out.writeInt(bs[vi]);
- out.writeInt(bsG[vi]);
- out.writeInt(bsB[vi]);
-
- assert out.position() % expectedStride == 0;
- }
- }
-
- public void writeToBufferVanilla(BufferWriter out, int expectedStride) {
- for(int vi = 0; vi < 4; vi++) {
- out.writeFloat(xs[vi]);
- out.writeFloat(ys[vi]);
- out.writeFloat(zs[vi]);
-
- float u = us[vi];
- float v = vs[vi];
-
- if(Config.shortUV) {
- out.writeShort((short)(Math.round(u * 32768f)));
- out.writeShort((short)(Math.round(v * 32768f)));
- } else {
- out.writeFloat(u);
- out.writeFloat(v);
- }
-
- out.writeInt(cs[vi]);
-
- out.writeInt(bs[vi]);
-
- assert out.position() % expectedStride == 0;
- }
- }
-
- //endregion
-
@Override
public String toString() {
return String.format(Locale.ENGLISH, "%s[(%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f)]", deleted ? "XXX " : "", xs[0], ys[0], zs[0], xs[1], ys[1], zs[1], xs[2], ys[2], zs[2], xs[3], ys[3], zs[3]);
diff --git a/src/main/java/makamys/neodymium/renderer/NeoRenderer.java b/src/main/java/makamys/neodymium/renderer/NeoRenderer.java
index 79b6117..d6becc8 100644
--- a/src/main/java/makamys/neodymium/renderer/NeoRenderer.java
+++ b/src/main/java/makamys/neodymium/renderer/NeoRenderer.java
@@ -432,56 +432,6 @@ public class NeoRenderer {
fogStartEnd.position(0);
}
- private void initAttributesRPLEAndShaders() {
- attributes.addAttribute("POS", 3, 4, GL_FLOAT);
- attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
- attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
- attributes.addAttribute("BRIGHTNESS_RED", 2, 2, GL_SHORT);
- attributes.addAttribute("ENTITY_DATA_1", 1, 4, GL_UNSIGNED_INT);
- attributes.addAttribute("ENTITY_DATA_2", 1, 4, GL_UNSIGNED_INT);
- attributes.addAttribute("NORMAL", 3, 4, GL_FLOAT);
- attributes.addAttribute("TANGENT", 4, 4, GL_FLOAT);
- attributes.addAttribute("MIDTEXTURE", 2, 4, GL_FLOAT);
- attributes.addAttribute("BRIGHTNESS_GREEN", 2, 2, GL_SHORT);
- attributes.addAttribute("BRIGHTNESS_BLUE", 2, 2, GL_SHORT);
- attributes.addAttribute("EDGE_TEX", 2, 4, GL_FLOAT);
- }
-
- private void initAttributesShaders() {
- attributes.addAttribute("POS", 3, 4, GL_FLOAT);
- attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
- attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
- attributes.addAttribute("BRIGHTNESS", 2, 2, GL_SHORT);
- attributes.addAttribute("ENTITY_DATA_1", 1, 4, GL_UNSIGNED_INT);
- attributes.addAttribute("ENTITY_DATA_2", 1, 4, GL_UNSIGNED_INT);
- attributes.addAttribute("NORMAL", 3, 4, GL_FLOAT);
- attributes.addAttribute("TANGENT", 4, 4, GL_FLOAT);
- attributes.addAttribute("MIDTEXTURE", 2, 4, GL_FLOAT);
- }
-
- private void initAttributesRPLE() {
- attributes.addAttribute("POS", 3, 4, GL_FLOAT);
- if (Config.shortUV) {
- attributes.addAttribute("TEXTURE", 2, 2, GL_UNSIGNED_SHORT);
- } else {
- attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
- }
- attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
- attributes.addAttribute("BRIGHTNESS_RED", 2, 2, GL_SHORT);
- attributes.addAttribute("BRIGHTNESS_GREEN", 2, 2, GL_SHORT);
- attributes.addAttribute("BRIGHTNESS_BLUE", 2, 2, GL_SHORT);
- }
-
- private void initAttributesVanilla() {
- attributes.addAttribute("POS", 3, 4, GL_FLOAT);
- if (Config.shortUV) {
- attributes.addAttribute("TEXTURE", 2, 2, GL_UNSIGNED_SHORT);
- } else {
- attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
- }
- attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
- attributes.addAttribute("BRIGHTNESS", 2, 2, GL_SHORT);
- }
/**
* @implSpec The attributes here need to be kept in sync with {@link MeshQuad#writeToBuffer(BufferWriter, int)}
*/
@@ -494,17 +444,7 @@ public class NeoRenderer {
attributes = new AttributeSet();
- boolean rple = Compat.isRPLEModPresent();
- boolean optiFineShaders = Compat.isOptiFineShadersEnabled();
- if (rple && optiFineShaders) {
- initAttributesRPLEAndShaders();
- } else if (optiFineShaders) {
- initAttributesShaders();
- } else if (rple) {
- initAttributesRPLE();
- } else {
- initAttributesVanilla();
- }
+ Neodymium.util.initVertexAttributes(attributes);
reloadShader();
@@ -515,7 +455,7 @@ public class NeoRenderer {
glBindBuffer(GL_ARRAY_BUFFER, mem.VBO);
-
+ boolean optiFineShaders = Compat.isOptiFineShadersEnabled();
if (optiFineShaders) {
initOptiFineShadersVertexPointers();
} else {
diff --git a/src/main/java/makamys/neodymium/renderer/compat/RenderUtil.java b/src/main/java/makamys/neodymium/renderer/compat/RenderUtil.java
new file mode 100644
index 0000000..70996eb
--- /dev/null
+++ b/src/main/java/makamys/neodymium/renderer/compat/RenderUtil.java
@@ -0,0 +1,18 @@
+package makamys.neodymium.renderer.compat;
+
+import makamys.neodymium.renderer.ChunkMesh;
+import makamys.neodymium.renderer.MeshQuad;
+import makamys.neodymium.renderer.NeoRenderer;
+import makamys.neodymium.renderer.attribs.AttributeSet;
+import makamys.neodymium.util.BufferWriter;
+
+public interface RenderUtil {
+ void readMeshQuad(MeshQuad meshQuad, int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags);
+
+ /**
+ * @implSpec These needs to be kept in sync with the attributes in {@link NeoRenderer#init()}
+ */
+ void writeMeshQuadToBuffer(MeshQuad meshQuad, BufferWriter out, int expectedStride);
+
+ void initVertexAttributes(AttributeSet attributes);
+}
diff --git a/src/main/java/makamys/neodymium/renderer/compat/RenderUtilRPLE.java b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilRPLE.java
new file mode 100644
index 0000000..fb27fee
--- /dev/null
+++ b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilRPLE.java
@@ -0,0 +1,109 @@
+package makamys.neodymium.renderer.compat;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import makamys.neodymium.config.Config;
+import makamys.neodymium.renderer.ChunkMesh;
+import makamys.neodymium.renderer.MeshQuad;
+import makamys.neodymium.renderer.attribs.AttributeSet;
+import makamys.neodymium.util.BufferWriter;
+import org.lwjgl.opengl.GL11;
+
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_BRIGHTNESS;
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_COLOR;
+import static org.lwjgl.opengl.GL11.GL_FLOAT;
+import static org.lwjgl.opengl.GL11.GL_SHORT;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class RenderUtilRPLE implements RenderUtil {
+ public static final RenderUtilRPLE INSTANCE = new RenderUtilRPLE();
+
+ @Override
+ public void readMeshQuad(MeshQuad meshQuad, int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
+ int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
+ for(int vi = 0; vi < vertices; vi++) {
+ int i = offset + vi * tessellatorVertexSize;
+
+ meshQuad.xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
+ meshQuad.ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
+ meshQuad.zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
+
+ meshQuad.us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
+ meshQuad.vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
+
+ meshQuad.cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
+
+ // TODO normals?
+
+ if (flags.hasBrightness) {
+ meshQuad.bs[vi] = rawBuffer[i + 7];
+ meshQuad.bsG[vi] = rawBuffer[i + 8];
+ meshQuad.bsB[vi] = rawBuffer[i + 9];
+ } else {
+ meshQuad.bs[vi] = DEFAULT_BRIGHTNESS;
+ meshQuad.bsG[vi] = DEFAULT_BRIGHTNESS;
+ meshQuad.bsB[vi] = DEFAULT_BRIGHTNESS;
+ }
+ }
+
+ if(vertices == 3) {
+ // Quadrangulate!
+ meshQuad.xs[3] = meshQuad.xs[2];
+ meshQuad.ys[3] = meshQuad.ys[2];
+ meshQuad.zs[3] = meshQuad.zs[2];
+
+ meshQuad.us[3] = meshQuad.us[2];
+ meshQuad.vs[3] = meshQuad.vs[2];
+
+ meshQuad.cs[3] = meshQuad.cs[2];
+
+ meshQuad.bs[3] = meshQuad.bs[2];
+ meshQuad.bsG[3] = meshQuad.bsG[2];
+ meshQuad.bsB[3] = meshQuad.bsB[2];
+ }
+ }
+
+ @Override
+ public void writeMeshQuadToBuffer(MeshQuad meshQuad, BufferWriter out, int expectedStride) {
+ for(int vi = 0; vi < 4; vi++) {
+ out.writeFloat(meshQuad.xs[vi]);
+ out.writeFloat(meshQuad.ys[vi]);
+ out.writeFloat(meshQuad.zs[vi]);
+
+ float u = meshQuad.us[vi];
+ float v = meshQuad.vs[vi];
+
+ if(Config.shortUV) {
+ out.writeShort((short)(Math.round(u * 32768f)));
+ out.writeShort((short)(Math.round(v * 32768f)));
+ } else {
+ out.writeFloat(u);
+ out.writeFloat(v);
+ }
+
+ out.writeInt(meshQuad.cs[vi]);
+
+ out.writeInt(meshQuad.bs[vi]);
+ out.writeInt(meshQuad.bsG[vi]);
+ out.writeInt(meshQuad.bsB[vi]);
+
+ assert out.position() % expectedStride == 0;
+ }
+ }
+
+ @Override
+ public void initVertexAttributes(AttributeSet attributes) {
+ attributes.addAttribute("POS", 3, 4, GL_FLOAT);
+ if (Config.shortUV) {
+ attributes.addAttribute("TEXTURE", 2, 2, GL_UNSIGNED_SHORT);
+ } else {
+ attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
+ }
+ attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
+ attributes.addAttribute("BRIGHTNESS_RED", 2, 2, GL_SHORT);
+ attributes.addAttribute("BRIGHTNESS_GREEN", 2, 2, GL_SHORT);
+ attributes.addAttribute("BRIGHTNESS_BLUE", 2, 2, GL_SHORT);
+ }
+}
diff --git a/src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaderRPLE.java b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaderRPLE.java
new file mode 100644
index 0000000..731bfd6
--- /dev/null
+++ b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaderRPLE.java
@@ -0,0 +1,156 @@
+package makamys.neodymium.renderer.compat;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import makamys.neodymium.renderer.ChunkMesh;
+import makamys.neodymium.renderer.MeshQuad;
+import makamys.neodymium.renderer.attribs.AttributeSet;
+import makamys.neodymium.util.BufferWriter;
+import org.lwjgl.opengl.GL11;
+
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_BRIGHTNESS;
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_COLOR;
+import static org.lwjgl.opengl.GL11.GL_FLOAT;
+import static org.lwjgl.opengl.GL11.GL_SHORT;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class RenderUtilShaderRPLE implements RenderUtil {
+ public static final RenderUtilShaderRPLE INSTANCE = new RenderUtilShaderRPLE();
+
+ @Override
+ public void readMeshQuad(MeshQuad meshQuad, int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
+ int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
+ for(int vi = 0; vi < vertices; vi++) {
+ int i = offset + vi * tessellatorVertexSize;
+
+ meshQuad.xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
+ meshQuad.ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
+ meshQuad.zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
+
+ meshQuad.us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
+ meshQuad.vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
+
+ meshQuad.cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
+
+ meshQuad.bs[vi] = flags.hasBrightness ? rawBuffer[i + 6] : DEFAULT_BRIGHTNESS;
+
+ meshQuad.e1[vi] = rawBuffer[i + 7];
+ meshQuad.e2[vi] = rawBuffer[i + 8];
+
+ meshQuad.xn[vi] = Float.intBitsToFloat(rawBuffer[i + 9]);
+ meshQuad.yn[vi] = Float.intBitsToFloat(rawBuffer[i + 10]);
+ meshQuad.zn[vi] = Float.intBitsToFloat(rawBuffer[i + 11]);
+
+ meshQuad.xt[vi] = Float.intBitsToFloat(rawBuffer[i + 12]);
+ meshQuad.yt[vi] = Float.intBitsToFloat(rawBuffer[i + 13]);
+ meshQuad.zt[vi] = Float.intBitsToFloat(rawBuffer[i + 14]);
+ meshQuad.wt[vi] = Float.intBitsToFloat(rawBuffer[i + 15]);
+
+ meshQuad.um[vi] = Float.intBitsToFloat(rawBuffer[i + 16]);
+ meshQuad.vm[vi] = Float.intBitsToFloat(rawBuffer[i + 17]);
+
+ if (flags.hasBrightness) {
+ meshQuad.bsG[vi] = rawBuffer[i + 18];
+ meshQuad.bsB[vi] = rawBuffer[i + 19];
+ } else {
+ meshQuad.bsG[vi] = DEFAULT_BRIGHTNESS;
+ meshQuad.bsB[vi] = DEFAULT_BRIGHTNESS;
+ }
+
+ meshQuad.ue[vi] = Float.intBitsToFloat(rawBuffer[i + 20]);
+ meshQuad.ve[vi] = Float.intBitsToFloat(rawBuffer[i + 21]);
+ }
+
+ if(vertices == 3) {
+ // Quadrangulate!
+ meshQuad.xs[3] = meshQuad.xs[2];
+ meshQuad.ys[3] = meshQuad.ys[2];
+ meshQuad.zs[3] = meshQuad.zs[2];
+
+ meshQuad.us[3] = meshQuad.us[2];
+ meshQuad.vs[3] = meshQuad.vs[2];
+
+ meshQuad.cs[3] = meshQuad.cs[2];
+
+ meshQuad.bs[3] = meshQuad.bs[2];
+
+ meshQuad.e1[3] = meshQuad.e1[2];
+ meshQuad.e2[3] = meshQuad.e2[2];
+
+ meshQuad.xn[3] = meshQuad.xn[2];
+ meshQuad.yn[3] = meshQuad.yn[2];
+ meshQuad.zn[3] = meshQuad.zn[2];
+
+ meshQuad.xt[3] = meshQuad.xt[2];
+ meshQuad.yt[3] = meshQuad.yt[2];
+ meshQuad.zt[3] = meshQuad.zt[2];
+ meshQuad.wt[3] = meshQuad.wt[2];
+
+ meshQuad.um[3] = meshQuad.um[2];
+ meshQuad.vm[3] = meshQuad.vm[2];
+
+ meshQuad.bsG[3] = meshQuad.bsG[2];
+ meshQuad.bsB[3] = meshQuad.bsB[2];
+
+ meshQuad.ue[3] = meshQuad.ue[2];
+ meshQuad.ve[3] = meshQuad.ve[2];
+ }
+ }
+
+ @Override
+ public void writeMeshQuadToBuffer(MeshQuad meshQuad, BufferWriter out, int expectedStride) {
+ for(int vi = 0; vi < 4; vi++) {
+ out.writeFloat(meshQuad.xs[vi]);
+ out.writeFloat(meshQuad.ys[vi]);
+ out.writeFloat(meshQuad.zs[vi]);
+
+ out.writeFloat(meshQuad.us[vi]);
+ out.writeFloat(meshQuad.vs[vi]);
+
+ out.writeInt(meshQuad.cs[vi]);
+
+ out.writeInt(meshQuad.bs[vi]);
+
+ out.writeInt(meshQuad.e1[vi]);
+ out.writeInt(meshQuad.e2[vi]);
+
+ out.writeFloat(meshQuad.xn[vi]);
+ out.writeFloat(meshQuad.yn[vi]);
+ out.writeFloat(meshQuad.zn[vi]);
+
+ out.writeFloat(meshQuad.xt[vi]);
+ out.writeFloat(meshQuad.yt[vi]);
+ out.writeFloat(meshQuad.zt[vi]);
+ out.writeFloat(meshQuad.wt[vi]);
+
+ out.writeFloat(meshQuad.um[vi]);
+ out.writeFloat(meshQuad.vm[vi]);
+
+ out.writeInt(meshQuad.bsG[vi]);
+ out.writeInt(meshQuad.bsB[vi]);
+
+ out.writeFloat(meshQuad.ue[vi]);
+ out.writeFloat(meshQuad.ve[vi]);
+
+ assert out.position() % expectedStride == 0;
+ }
+ }
+
+ @Override
+ public void initVertexAttributes(AttributeSet attributes) {
+ attributes.addAttribute("POS", 3, 4, GL_FLOAT);
+ attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
+ attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
+ attributes.addAttribute("BRIGHTNESS_RED", 2, 2, GL_SHORT);
+ attributes.addAttribute("ENTITY_DATA_1", 1, 4, GL_UNSIGNED_INT);
+ attributes.addAttribute("ENTITY_DATA_2", 1, 4, GL_UNSIGNED_INT);
+ attributes.addAttribute("NORMAL", 3, 4, GL_FLOAT);
+ attributes.addAttribute("TANGENT", 4, 4, GL_FLOAT);
+ attributes.addAttribute("MIDTEXTURE", 2, 4, GL_FLOAT);
+ attributes.addAttribute("BRIGHTNESS_GREEN", 2, 2, GL_SHORT);
+ attributes.addAttribute("BRIGHTNESS_BLUE", 2, 2, GL_SHORT);
+ attributes.addAttribute("EDGE_TEX", 2, 4, GL_FLOAT);
+ }
+}
diff --git a/src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaders.java b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaders.java
new file mode 100644
index 0000000..b621e2c
--- /dev/null
+++ b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilShaders.java
@@ -0,0 +1,126 @@
+package makamys.neodymium.renderer.compat;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import makamys.neodymium.renderer.ChunkMesh;
+import makamys.neodymium.renderer.MeshQuad;
+import makamys.neodymium.renderer.attribs.AttributeSet;
+import makamys.neodymium.util.BufferWriter;
+import org.lwjgl.opengl.GL11;
+
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_BRIGHTNESS;
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_COLOR;
+import static org.lwjgl.opengl.GL11.GL_FLOAT;
+import static org.lwjgl.opengl.GL11.GL_SHORT;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class RenderUtilShaders implements RenderUtil {
+ public static final RenderUtilShaders INSTANCE = new RenderUtilShaders();
+
+ @Override
+ public void readMeshQuad(MeshQuad meshQuad, int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
+ int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
+ for (int vi = 0; vi < vertices; vi++) {
+ int i = offset + vi * tessellatorVertexSize;
+
+ meshQuad.xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
+ meshQuad.ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
+ meshQuad.zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
+
+ meshQuad.us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
+ meshQuad.vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
+
+ meshQuad.cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
+
+ meshQuad.bs[vi] = flags.hasBrightness ? rawBuffer[i + 6] : DEFAULT_BRIGHTNESS;
+ meshQuad.e1[vi] = rawBuffer[i + 7];
+ meshQuad.e2[vi] = rawBuffer[i + 8];
+ meshQuad.xn[vi] = Float.intBitsToFloat(rawBuffer[i + 9]);
+ meshQuad.yn[vi] = Float.intBitsToFloat(rawBuffer[i + 10]);
+ meshQuad.zn[vi] = Float.intBitsToFloat(rawBuffer[i + 11]);
+ meshQuad.xt[vi] = Float.intBitsToFloat(rawBuffer[i + 12]);
+ meshQuad.yt[vi] = Float.intBitsToFloat(rawBuffer[i + 13]);
+ meshQuad.zt[vi] = Float.intBitsToFloat(rawBuffer[i + 14]);
+ meshQuad.wt[vi] = Float.intBitsToFloat(rawBuffer[i + 15]);
+ meshQuad.um[vi] = Float.intBitsToFloat(rawBuffer[i + 16]);
+ meshQuad.vm[vi] = Float.intBitsToFloat(rawBuffer[i + 17]);
+ }
+
+ if (vertices == 3) {
+ // Quadrangulate!
+ meshQuad.xs[3] = meshQuad.xs[2];
+ meshQuad.ys[3] = meshQuad.ys[2];
+ meshQuad.zs[3] = meshQuad.zs[2];
+
+ meshQuad.us[3] = meshQuad.us[2];
+ meshQuad.vs[3] = meshQuad.vs[2];
+
+ meshQuad.cs[3] = meshQuad.cs[2];
+
+ meshQuad.bs[3] = meshQuad.bs[2];
+
+ meshQuad.e1[3] = meshQuad.e1[2];
+ meshQuad.e2[3] = meshQuad.e2[2];
+
+ meshQuad.xn[3] = meshQuad.xn[2];
+ meshQuad.yn[3] = meshQuad.yn[2];
+ meshQuad.zn[3] = meshQuad.zn[2];
+
+ meshQuad.xt[3] = meshQuad.xt[2];
+ meshQuad.yt[3] = meshQuad.yt[2];
+ meshQuad.zt[3] = meshQuad.zt[2];
+ meshQuad.wt[3] = meshQuad.wt[2];
+
+ meshQuad.um[3] = meshQuad.um[2];
+ meshQuad.vm[3] = meshQuad.vm[2];
+ }
+ }
+
+ @Override
+ public void writeMeshQuadToBuffer(MeshQuad meshQuad, BufferWriter out, int expectedStride) {
+ for(int vi = 0; vi < 4; vi++) {
+ out.writeFloat(meshQuad.xs[vi]);
+ out.writeFloat(meshQuad.ys[vi]);
+ out.writeFloat(meshQuad.zs[vi]);
+
+ out.writeFloat(meshQuad.us[vi]);
+ out.writeFloat(meshQuad.vs[vi]);
+
+ out.writeInt(meshQuad.cs[vi]);
+
+ out.writeInt(meshQuad.bs[vi]);
+
+ out.writeInt(meshQuad.e1[vi]);
+ out.writeInt(meshQuad.e2[vi]);
+
+ out.writeFloat(meshQuad.xn[vi]);
+ out.writeFloat(meshQuad.yn[vi]);
+ out.writeFloat(meshQuad.zn[vi]);
+
+ out.writeFloat(meshQuad.xt[vi]);
+ out.writeFloat(meshQuad.yt[vi]);
+ out.writeFloat(meshQuad.zt[vi]);
+ out.writeFloat(meshQuad.wt[vi]);
+
+ out.writeFloat(meshQuad.um[vi]);
+ out.writeFloat(meshQuad.vm[vi]);
+
+ assert out.position() % expectedStride == 0;
+ }
+ }
+
+ @Override
+ public void initVertexAttributes(AttributeSet attributes) {
+ attributes.addAttribute("POS", 3, 4, GL_FLOAT);
+ attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
+ attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
+ attributes.addAttribute("BRIGHTNESS", 2, 2, GL_SHORT);
+ attributes.addAttribute("ENTITY_DATA_1", 1, 4, GL_UNSIGNED_INT);
+ attributes.addAttribute("ENTITY_DATA_2", 1, 4, GL_UNSIGNED_INT);
+ attributes.addAttribute("NORMAL", 3, 4, GL_FLOAT);
+ attributes.addAttribute("TANGENT", 4, 4, GL_FLOAT);
+ attributes.addAttribute("MIDTEXTURE", 2, 4, GL_FLOAT);
+ }
+}
diff --git a/src/main/java/makamys/neodymium/renderer/compat/RenderUtilVanilla.java b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilVanilla.java
new file mode 100644
index 0000000..46f5a2a
--- /dev/null
+++ b/src/main/java/makamys/neodymium/renderer/compat/RenderUtilVanilla.java
@@ -0,0 +1,96 @@
+package makamys.neodymium.renderer.compat;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import makamys.neodymium.config.Config;
+import makamys.neodymium.renderer.ChunkMesh;
+import makamys.neodymium.renderer.MeshQuad;
+import makamys.neodymium.renderer.attribs.AttributeSet;
+import makamys.neodymium.util.BufferWriter;
+import org.lwjgl.opengl.GL11;
+
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_BRIGHTNESS;
+import static makamys.neodymium.renderer.MeshQuad.DEFAULT_COLOR;
+import static org.lwjgl.opengl.GL11.GL_FLOAT;
+import static org.lwjgl.opengl.GL11.GL_SHORT;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class RenderUtilVanilla implements RenderUtil {
+ public static final RenderUtilVanilla INSTANCE = new RenderUtilVanilla();
+
+ @Override
+ public void readMeshQuad(MeshQuad meshQuad, int[] rawBuffer, int tessellatorVertexSize, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, ChunkMesh.Flags flags) {
+ //No RPLE or Shaders
+ int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4;
+ for(int vi = 0; vi < vertices; vi++) {
+ int i = offset + vi * tessellatorVertexSize;
+
+ meshQuad.xs[vi] = Float.intBitsToFloat(rawBuffer[i]) + offsetX;
+ meshQuad.ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY;
+ meshQuad.zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ;
+
+ meshQuad.us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]);
+ meshQuad.vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]);
+
+ meshQuad.cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR;
+
+ // TODO normals?
+
+ meshQuad.bs[vi] = flags.hasBrightness ? rawBuffer[i + 7] : DEFAULT_BRIGHTNESS;
+ }
+
+ if(vertices == 3) {
+ // Quadrangulate!
+ meshQuad.xs[3] = meshQuad.xs[2];
+ meshQuad.ys[3] = meshQuad.ys[2];
+ meshQuad.zs[3] = meshQuad.zs[2];
+
+ meshQuad.us[3] = meshQuad.us[2];
+ meshQuad.vs[3] = meshQuad.vs[2];
+
+ meshQuad.cs[3] = meshQuad.cs[2];
+
+ meshQuad.bs[3] = meshQuad.bs[2];
+ }
+ }
+
+ @Override
+ public void writeMeshQuadToBuffer(MeshQuad meshQuad, BufferWriter out, int expectedStride) {
+ for(int vi = 0; vi < 4; vi++) {
+ out.writeFloat(meshQuad.xs[vi]);
+ out.writeFloat(meshQuad.ys[vi]);
+ out.writeFloat(meshQuad.zs[vi]);
+
+ float u = meshQuad.us[vi];
+ float v = meshQuad.vs[vi];
+
+ if(Config.shortUV) {
+ out.writeShort((short)(Math.round(u * 32768f)));
+ out.writeShort((short)(Math.round(v * 32768f)));
+ } else {
+ out.writeFloat(u);
+ out.writeFloat(v);
+ }
+
+ out.writeInt(meshQuad.cs[vi]);
+
+ out.writeInt(meshQuad.bs[vi]);
+
+ assert out.position() % expectedStride == 0;
+ }
+ }
+
+ @Override
+ public void initVertexAttributes(AttributeSet attributes) {
+ attributes.addAttribute("POS", 3, 4, GL_FLOAT);
+ if (Config.shortUV) {
+ attributes.addAttribute("TEXTURE", 2, 2, GL_UNSIGNED_SHORT);
+ } else {
+ attributes.addAttribute("TEXTURE", 2, 4, GL_FLOAT);
+ }
+ attributes.addAttribute("COLOR", 4, 1, GL_UNSIGNED_BYTE);
+ attributes.addAttribute("BRIGHTNESS", 2, 2, GL_SHORT);
+ }
+}