diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 15efd3bcb..de617646e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -44,6 +44,8 @@ public class Loader implements ISelectiveResourceReloadListener { private final Backend backend; private boolean shouldCrash; + private boolean firstLoad = true; + public Loader(Backend backend) { this.backend = backend; @@ -72,7 +74,7 @@ public class Loader implements ISelectiveResourceReloadListener { Resolver.INSTANCE.invalidate(); ModLoader.get() - .postEvent(new GatherContextEvent(backend)); + .postEvent(new GatherContextEvent(backend, firstLoad)); ShaderSources sources = new ShaderSources(manager); @@ -97,6 +99,8 @@ public class Loader implements ISelectiveResourceReloadListener { CrumblingRenderer.reset(); } } + + firstLoad = false; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java b/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java index 37ac4451c..0cca30b39 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java @@ -4,6 +4,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; +import java.io.IOException; import java.util.Optional; import net.minecraft.client.Minecraft; @@ -55,13 +56,18 @@ public class OptifineHandler { public static void refresh() { if (optifine == null) return; + boolean shadersOff = areShadersDisabledInOptifineConfigFile(); + + handler = new OptifineHandler(!shadersOff); + } + + private static boolean areShadersDisabledInOptifineConfigFile() { File dir = Minecraft.getInstance().gameDirectory; File shaderOptions = new File(dir, "optionsshaders.txt"); boolean shadersOff = true; - try { - BufferedReader reader = new BufferedReader(new FileReader(shaderOptions)); + try (BufferedReader reader = new BufferedReader(new FileReader(shaderOptions))) { shadersOff = reader.lines() .anyMatch(it -> { @@ -73,11 +79,10 @@ public class OptifineHandler { } return false; }); - } catch (FileNotFoundException e) { + } catch (IOException e) { Backend.log.info("No shader config found."); } - - handler = new OptifineHandler(!shadersOff); + return shadersOff; } public boolean isUsingShaders() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 26ddbbb67..e2c54a561 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -18,8 +18,9 @@ import net.minecraftforge.event.TickEvent; /** * A manager class for a single world where instancing is supported. - *
- * The material manager is shared between the different instance managers. + *

+ * The material manager is shared between the different instance managers. + *

*/ public class InstanceWorld { protected final MaterialManager materialManager; @@ -63,11 +64,12 @@ public class InstanceWorld { } /** - * Get ready to render a frame: - *
- * Check and shift the origin coordinate. - *
- * Call {@link IDynamicInstance#beginFrame()} on all instances in this world. + * Get ready to render a frame. + *

+ * Check and shift the origin coordinate. + *
+ * Call {@link IDynamicInstance#beginFrame()} on all instances in this world. + *

*/ public void beginFrame(BeginFrameEvent event) { materialManager.checkAndShiftOrigin(event.getInfo()); @@ -78,8 +80,9 @@ public class InstanceWorld { /** * Tick the renderers after the game has ticked: - *
- * Call {@link ITickableInstance#tick()} on all instances in this world. + *

+ * Call {@link ITickableInstance#tick()} on all instances in this world. + *

*/ public void tick() { Minecraft mc = Minecraft.getInstance(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index 1186d7ea3..708582ae5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -28,13 +28,17 @@ public class InstancedRenderDispatcher { private static final WorldAttached instanceWorlds = new WorldAttached<>($ -> new InstanceWorld()); /** - * Call this when you want to invoke - * @param te + * Call this when you want to manually run {@link IInstance#update()}. + * @param te The tile whose instance you want to update. */ public static void enqueueUpdate(TileEntity te) { getTiles(te.getLevel()).queueUpdate(te); } + /** + * Call this when you want to manually run {@link IInstance#update()}. + * @param entity The entity whose instance you want to update. + */ public static void enqueueUpdate(Entity entity) { getEntities(entity.level).queueUpdate(entity); } @@ -66,7 +70,10 @@ public class InstancedRenderDispatcher { @SubscribeEvent public static void onBeginFrame(BeginFrameEvent event) { - instanceWorlds.get(event.getWorld()).beginFrame(event); + if (Backend.isGameActive()) { + instanceWorlds.get(event.getWorld()) + .beginFrame(event); + } } @SubscribeEvent diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java index 132cbd9f2..c2b3dd720 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java @@ -37,10 +37,10 @@ import com.jozufozu.flywheel.util.AttribUtil; public class Instancer { protected final Supplier gen; - protected IBufferedModel model; - protected final VertexFormat instanceFormat; protected final IInstanceFactory factory; + + protected IBufferedModel model; protected GlVertexArray vao; protected GlBuffer instanceVBO; protected int glBufferSize = -1; @@ -81,7 +81,7 @@ public class Instancer { public void render() { if (!isInitialized()) init(); - if (deleted) return; + if (invalid()) return; vao.bind(); renderSetup(); @@ -91,13 +91,19 @@ public class Instancer { vao.unbind(); } + private boolean invalid() { + return deleted || model == null; + } + private void init() { - model = new IndexedModel(gen.get()); initialized = true; + IModel iModel = gen.get(); - if (model.getVertexCount() <= 0) - throw new IllegalArgumentException("Refusing to instance a model with no vertices."); + if (iModel.empty()) { + return; + } + model = new IndexedModel(iModel); vao = new GlVertexArray(); instanceVBO = new GlBuffer(GlBufferType.ARRAY_BUFFER); @@ -133,16 +139,14 @@ public class Instancer { * Free acquired resources. All other Instancer methods are undefined behavior after calling delete. */ public void delete() { - if (deleted) return; + if (invalid()) return; deleted = true; - if (isInitialized()) { - model.delete(); + model.delete(); - instanceVBO.delete(); - vao.delete(); - } + instanceVBO.delete(); + vao.delete(); } private D _add(D instanceData) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java index c3e93fcdb..d3370626e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java @@ -17,6 +17,7 @@ import com.jozufozu.flywheel.core.materials.OrientedData; import net.minecraft.entity.Entity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.math.vector.Vector3i; @@ -89,8 +90,7 @@ public abstract class EntityInstance implements IInstance { * {@link TileInstanceManager}s are allowed to arbitrarily adjust the origin, and * shift the world matrix provided as a shader uniform accordingly. * - * @return The {@link BlockPos position} of the {@link Entity} this instance - * represents should be rendered at to appear in the correct location. + * @return The position this instance should be rendered at to appear in the correct location. */ public Vector3f getInstancePosition() { Vector3d pos = entity.position(); @@ -98,6 +98,23 @@ public abstract class EntityInstance implements IInstance { return new Vector3f((float) (pos.x - origin.getX()), (float) (pos.y - origin.getY()), (float) (pos.z - origin.getZ())); } + /** + * In order to accommodate for floating point precision errors at high coordinates, + * {@link TileInstanceManager}s are allowed to arbitrarily adjust the origin, and + * shift the world matrix provided as a shader uniform accordingly. + * + * @return The position this instance should be rendered at to appear in the correct location. + */ + public Vector3f getInstancePosition(float partialTicks) { + Vector3d pos = entity.position(); + Vector3i origin = materialManager.getOriginCoordinate(); + return new Vector3f( + (float) (MathHelper.lerp(partialTicks, entity.xOld, pos.x) - origin.getX()), + (float) (MathHelper.lerp(partialTicks, entity.yOld, pos.y) - origin.getY()), + (float) (MathHelper.lerp(partialTicks, entity.zOld, pos.z) - origin.getZ()) + ); + } + @Override public BlockPos getWorldPosition() { return entity.blockPosition(); diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java b/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java index f7c99122a..9c15d99cd 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java @@ -20,6 +20,19 @@ public class ModelData extends BasicData { return this; } + /** + * Sets the transform matrices to be all zeros. + * + *

+ * This will allow the gpu to quickly discard all geometry for this instance, effectively "turning it off". + *

+ */ + public ModelData setEmptyTransform() { + matrices = empty; + markDirty(); + return this; + } + @Override public void write(MappedBuffer buf) { super.write(buf); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java new file mode 100644 index 000000000..f5eead908 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java @@ -0,0 +1,139 @@ +package com.jozufozu.flywheel.core.model; + +import static com.jozufozu.flywheel.util.RenderMath.nb; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.lwjgl.system.MemoryStack; + +import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; +import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; +import com.jozufozu.flywheel.core.Formats; +import com.jozufozu.flywheel.util.VirtualEmptyModelData; +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.color.ItemColors; +import net.minecraft.client.renderer.model.BakedQuad; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ItemCameraTransforms; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Vector3f; +import net.minecraft.util.math.vector.Vector3i; +import net.minecraftforge.client.ForgeHooksClient; + +public class BakedModelModel implements IModel { + // DOWN, UP, NORTH, SOUTH, WEST, EAST, null + private static final Direction[] dirs; + + static { + Direction[] directions = Direction.values(); + + dirs = Arrays.copyOf(directions, directions.length + 1); + } + + + public final IBakedModel model; + private final int numQuads; + + public BakedModelModel(IBakedModel model) { + this.model = model; + + Random random = new Random(); + + int numQuads = 0; + + for (Direction dir : dirs) { + random.setSeed(42); + List quads = model.getQuads(null, dir, random, VirtualEmptyModelData.INSTANCE); + + numQuads += quads.size(); + } + + this.numQuads = numQuads; + } + + @Override + public void buffer(VecBuffer buffer) { + + Minecraft mc = Minecraft.getInstance(); + + ItemColors itemColors = mc.getItemColors(); + + Random random = new Random(); + + for (Direction dir : dirs) { + random.setSeed(42); + List quads = model.getQuads(null, dir, random, VirtualEmptyModelData.INSTANCE); + + for (BakedQuad bakedQuad : quads) { +// int i = -1; +// if (!itemStack.isEmpty() && bakedQuad.isTinted()) { +// i = itemColors.getColor(itemStack, bakedQuad.getTintIndex()); +// } +// +// byte red = (byte)(i >> 16 & 255); +// byte green = (byte)(i >> 8 & 255); +// byte blue = (byte)(i & 255); + + int[] aint = bakedQuad.getVertices(); + Vector3i faceNormal = bakedQuad.getDirection().getNormal(); + Vector3f normal = new Vector3f((float)faceNormal.getX(), (float)faceNormal.getY(), (float)faceNormal.getZ()); + int intSize = DefaultVertexFormats.BLOCK.getIntegerSize(); + int vertexCount = aint.length / intSize; + + try (MemoryStack memorystack = MemoryStack.stackPush()) { + ByteBuffer bytebuffer = memorystack.malloc(DefaultVertexFormats.BLOCK.getVertexSize()); + IntBuffer intbuffer = bytebuffer.asIntBuffer(); + + for(int j = 0; j < vertexCount; ++j) { + ((Buffer)intbuffer).clear(); + intbuffer.put(aint, j * 8, 8); + float f = bytebuffer.getFloat(0); + float f1 = bytebuffer.getFloat(4); + float f2 = bytebuffer.getFloat(8); +// float cr; +// float cg; +// float cb; +// float ca; +// { +// float r = (float)(bytebuffer.get(12) & 255) / 255.0F; +// float g = (float)(bytebuffer.get(13) & 255) / 255.0F; +// float b = (float)(bytebuffer.get(14) & 255) / 255.0F; +// float a = (float)(bytebuffer.get(15) & 255) / 255.0F; +// cr = r * red; +// cg = g * green; +// cb = b * blue; +// ca = a; +// } + + float u = bytebuffer.getFloat(16); + float v = bytebuffer.getFloat(20); + + buffer.putVec3(f, f1, f2); + buffer.putVec3(nb(normal.x()), nb(normal.y()), nb(normal.z())); + buffer.putVec2(u, v); + } + } + } + } + } + + @Override + public int vertexCount() { + return numQuads * 4; + } + + @Override + public VertexFormat format() { + return Formats.UNLIT_MODEL; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java b/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java index a409d4363..c7891abfb 100644 --- a/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java +++ b/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java @@ -8,12 +8,21 @@ import net.minecraftforge.fml.event.lifecycle.IModBusEvent; public class GatherContextEvent extends Event implements IModBusEvent { private final Backend backend; + private final boolean firstLoad; - public GatherContextEvent(Backend backend) { + public GatherContextEvent(Backend backend, boolean firstLoad) { this.backend = backend; + this.firstLoad = firstLoad; } public Backend getBackend() { return backend; } + + /** + * @return true iff it is the first time the event is fired. + */ + public boolean isFirstLoad() { + return firstLoad; + } } diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java index ed08b5dc7..52cbdb5ab 100644 --- a/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java +++ b/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java @@ -24,6 +24,22 @@ public class MatrixTransformStack implements TransformStack { return internal; } + public MatrixTransformStack setIdentity() { + if (internal.clear()) { + MatrixStack.Entry last = internal.last(); + + last.normal() + .setIdentity(); + last.pose() + .setIdentity(); + } else { + internal.popPose(); + internal.pushPose(); + } + + return this; + } + @Override public TransformStack translate(double x, double y, double z) { internal.translate(x, y, z); diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java index 1962bcf26..1066446cd 100644 --- a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java +++ b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java @@ -44,6 +44,18 @@ public interface TransformStack { return multiply(Vector3f.ZP, angle); } + default TransformStack rotateXRadians(double angle) { + return multiplyRadians(Vector3f.XP, angle); + } + + default TransformStack rotateYRadians(double angle) { + return multiplyRadians(Vector3f.YP, angle); + } + + default TransformStack rotateZRadians(double angle) { + return multiplyRadians(Vector3f.ZP, angle); + } + default TransformStack centre() { return translateAll(0.5); } @@ -76,6 +88,10 @@ public interface TransformStack { return translate(vec.x, vec.y, vec.z); } + default TransformStack translate(Vector3f vec) { + return translate(vec.x(), vec.y(), vec.z()); + } + default TransformStack translateBack(Vector3d vec) { return translate(-vec.x, -vec.y, -vec.z); } @@ -94,4 +110,34 @@ public interface TransformStack { return this; return multiply(axis.rotationDegrees((float) angle)); } + + default TransformStack multiplyRadians(Vector3f axis, double angle) { + if (angle == 0) + return this; + return multiply(axis.rotation((float) angle)); + } + + default TransformStack rotateToFace(Direction facing) { + switch (facing) { + case SOUTH: + multiply(Vector3f.YP.rotationDegrees(180)); + break; + case WEST: + multiply(Vector3f.YP.rotationDegrees(90)); + break; + case NORTH: + multiply(Vector3f.YP.rotationDegrees(0)); + break; + case EAST: + multiply(Vector3f.YP.rotationDegrees(270)); + break; + case UP: + multiply(Vector3f.XP.rotationDegrees(90)); + break; + case DOWN: + multiply(Vector3f.XN.rotationDegrees(90)); + break; + } + return this; + } }