diff --git a/build.gradle b/build.gradle index 8fd354ad3..a5fa99fdd 100644 --- a/build.gradle +++ b/build.gradle @@ -121,6 +121,12 @@ jar { jar.finalizedBy('reobfJar') +javadoc { + source = [sourceSets.main.allJava] + // prevent java 8's strict doclint for javadocs from failing builds + options.addStringOption('Xdoclint:none', '-quiet') +} + task sourcesJar(type: Jar) { from sourceSets.main.allSource archiveBaseName.set(project.archivesBaseName) @@ -128,8 +134,13 @@ task sourcesJar(type: Jar) { archiveClassifier.set('sources') } +task javadocJar(type: Jar, dependsOn: javadoc) { + from javadoc.destinationDir + archiveClassifier.set('javadoc') +} + artifacts { - archives jar, sourcesJar + archives jar, sourcesJar, javadocJar } publishing { @@ -138,6 +149,7 @@ publishing { mavenJava(MavenPublication) { artifact jar artifact sourcesJar + artifact javadocJar } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 0cfb51552..770e0734c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -155,7 +155,7 @@ public class Backend { .enabled() && !OptifineHandler.usingShaders(); } - public boolean canUseInstancing(World world) { + public boolean canUseInstancing(@Nullable World world) { return canUseInstancing() && isFlywheelWorld(world); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/attrib/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/gl/attrib/package-info.java new file mode 100644 index 000000000..4d3485865 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/attrib/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.gl.attrib; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/package-info.java new file mode 100644 index 000000000..fb593bf7c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.gl.buffer; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/gl/package-info.java new file mode 100644 index 000000000..8abd8a8a9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.gl; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/package-info.java new file mode 100644 index 000000000..5c4bed0b3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.gl.shader; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/IDynamicInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/IDynamicInstance.java index fd17da753..e801d16f8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/IDynamicInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/IDynamicInstance.java @@ -14,6 +14,10 @@ import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance; public interface IDynamicInstance extends IInstance { /** * Called every frame. + *
+ * DISPATCHED IN PARALLEL, don't attempt to mutate anything outside of this instance. + *
+ * {@link Instancer}/{@link InstanceData} creation/acquisition is safe here. */ void beginFrame(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ITickableInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/ITickableInstance.java index 4c3265d0c..041f62ff1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/ITickableInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/ITickableInstance.java @@ -22,6 +22,10 @@ public interface ITickableInstance extends IInstance { /** * Called every tick. + *
+ * DISPATCHED IN PARALLEL, don't attempt to mutate anything outside of this instance. + *
+ * {@link Instancer}/{@link InstanceData} creation/acquisition is safe here. */ void tick(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java new file mode 100644 index 000000000..26ddbbb67 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -0,0 +1,104 @@ +package com.jozufozu.flywheel.backend.instancing; + +import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager; +import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager; +import com.jozufozu.flywheel.backend.material.MaterialManager; +import com.jozufozu.flywheel.backend.state.RenderLayer; +import com.jozufozu.flywheel.core.Contexts; +import com.jozufozu.flywheel.core.shader.WorldProgram; +import com.jozufozu.flywheel.event.BeginFrameEvent; +import com.jozufozu.flywheel.event.RenderLayerEvent; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IWorld; +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. + */ +public class InstanceWorld { + protected final MaterialManager materialManager; + protected final InstanceManager entityInstanceManager; + protected final InstanceManager tileEntityInstanceManager; + + public InstanceWorld() { + + materialManager = MaterialManager.builder(Contexts.WORLD) + .build(); + entityInstanceManager = new EntityInstanceManager(materialManager); + tileEntityInstanceManager = new TileInstanceManager(materialManager); + } + + public MaterialManager getMaterialManager() { + return materialManager; + } + + public InstanceManager getEntityInstanceManager() { + return entityInstanceManager; + } + + public InstanceManager getTileEntityInstanceManager() { + return tileEntityInstanceManager; + } + + /** + * Free all acquired resources and invalidate this instance world. + */ + public void delete() { + materialManager.delete(); + } + + /** + * Instantiate all the necessary instances to render the given world. + */ + public void loadAll(ClientWorld world) { + world.blockEntityList.forEach(tileEntityInstanceManager::add); + world.entitiesForRendering() + .forEach(entityInstanceManager::add); + } + + /** + * 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()); + + tileEntityInstanceManager.beginFrame(event.getInfo()); + entityInstanceManager.beginFrame(event.getInfo()); + } + + /** + * Tick the renderers after the game has ticked: + *
+ * Call {@link ITickableInstance#tick()} on all instances in this world. + */ + public void tick() { + Minecraft mc = Minecraft.getInstance(); + Entity renderViewEntity = mc.cameraEntity != null ? mc.cameraEntity : mc.player; + + if (renderViewEntity == null) return; + + tileEntityInstanceManager.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ()); + entityInstanceManager.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ()); + } + + /** + * Draw the given layer. + */ + public void renderLayer(RenderLayerEvent event) { + event.type.setupRenderState(); + + materialManager.render(event.layer, event.viewProjection, event.camX, event.camY, event.camZ); + + event.type.clearRenderState(); + } +} 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 95958d162..1db796450 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -3,12 +3,7 @@ package com.jozufozu.flywheel.backend.instancing; import javax.annotation.Nonnull; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager; -import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager; -import com.jozufozu.flywheel.backend.material.MaterialManager; import com.jozufozu.flywheel.backend.state.RenderLayer; -import com.jozufozu.flywheel.core.Contexts; -import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.RenderLayerEvent; @@ -30,19 +25,18 @@ import net.minecraftforge.fml.common.Mod; @Mod.EventBusSubscriber(Dist.CLIENT) public class InstancedRenderDispatcher { - private static final WorldAttached> materialManagers = new WorldAttached<>($ -> MaterialManager.builder(Contexts.WORLD).build()); - - private static final WorldAttached> entityInstanceManager = new WorldAttached<>(world -> new EntityInstanceManager(materialManagers.get(world))); - private static final WorldAttached> tileInstanceManager = new WorldAttached<>(world -> new TileInstanceManager(materialManagers.get(world))); + private static final WorldAttached instanceWorlds = new WorldAttached<>($ -> new InstanceWorld()); @Nonnull public static InstanceManager getTiles(IWorld world) { - return tileInstanceManager.get(world); + return instanceWorlds.get(world) + .getTileEntityInstanceManager(); } @Nonnull public static InstanceManager getEntities(IWorld world) { - return entityInstanceManager.get(world); + return instanceWorlds.get(world) + .getEntityInstanceManager(); } @SubscribeEvent @@ -55,12 +49,7 @@ public class InstancedRenderDispatcher { ClientWorld world = mc.level; AnimationTickHolder.tick(); - Entity renderViewEntity = mc.cameraEntity != null ? mc.cameraEntity : mc.player; - - if (renderViewEntity == null) return; - - getTiles(world).tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ()); - getEntities(world).tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ()); + instanceWorlds.get(world).tick(); } public static void enqueueUpdate(TileEntity te) { @@ -73,29 +62,18 @@ public class InstancedRenderDispatcher { @SubscribeEvent public static void onBeginFrame(BeginFrameEvent event) { - materialManagers.get(event.getWorld()) - .checkAndShiftOrigin(event.getInfo()); - - getTiles(event.getWorld()).beginFrame(event.getInfo()); - getEntities(event.getWorld()).beginFrame(event.getInfo()); + instanceWorlds.get(event.getWorld()).beginFrame(event); } @SubscribeEvent public static void renderLayer(RenderLayerEvent event) { + if (event.layer == null) return; + ClientWorld world = event.getWorld(); if (!Backend.getInstance() .canUseInstancing(world)) return; - RenderLayer renderLayer = RenderLayer.fromRenderType(event.type); - - if (renderLayer == null) return; - - event.type.setupRenderState(); - - materialManagers.get(world) - .render(renderLayer, event.viewProjection, event.camX, event.camY, event.camZ); - - event.type.clearRenderState(); + instanceWorlds.get(world).renderLayer(event); } @SubscribeEvent @@ -108,13 +86,8 @@ public class InstancedRenderDispatcher { } public static void loadAllInWorld(ClientWorld world) { - materialManagers.replace(world, MaterialManager::delete); - - InstanceManager tiles = tileInstanceManager.replace(world); - world.blockEntityList.forEach(tiles::add); - - InstanceManager entities = entityInstanceManager.replace(world); - world.entitiesForRendering() - .forEach(entities::add); + instanceWorlds.replace(world, InstanceWorld::delete) + .loadAll(world); } + } 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 babec0d6e..61bd13723 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.backend.instancing; - import java.util.ArrayList; import java.util.BitSet; import java.util.function.Supplier; @@ -17,12 +16,26 @@ import com.jozufozu.flywheel.core.model.IModel; import com.jozufozu.flywheel.core.model.ModelUtil; import com.jozufozu.flywheel.util.AttribUtil; -import net.minecraft.util.math.vector.Vector3i; - +/** + * An instancer is how you interact with an instanced model. + *

+ * Instanced models can have many copies, and on most systems it's very fast to draw all of the copies at once. + * There is no limit to how many copies an instanced model can have. + * Each copy is represented by an InstanceData object. + *

+ *

+ * When you call {@link #createInstance()} you are given an InstanceData object that you can manipulate however + * you want. The changes you make to the InstanceData object are automatically made visible, and persistent. + * Changing the position of your InstanceData object every frame means that that copy of the model will be in a + * different position in the world each frame. Setting the position of your InstanceData once and not touching it + * again means that your model will be in the same position in the world every frame. This persistence is useful + * because it means the properties of your model don't have to be re-evaluated every frame. + *

+ * + * @param the data that represents a copy of the instanced model. + */ public class Instancer { - public final Supplier originCoordinate; - protected final Supplier gen; protected BufferedModel model; @@ -40,11 +53,30 @@ public class Instancer { boolean anyToRemove; boolean anyToUpdate; - public Instancer(Supplier model, Supplier originCoordinate, MaterialSpec spec) { + public Instancer(Supplier model, MaterialSpec spec) { this.gen = model; this.factory = spec.getInstanceFactory(); this.instanceFormat = spec.getInstanceFormat(); - this.originCoordinate = originCoordinate; + } + + /** + * @return a handle to a new copy of this model. + */ + public D createInstance() { + return _add(factory.create(this)); + } + + /** + * Copy a data from another Instancer to this. + * + * This has the effect of swapping out one model for another. + * @param inOther the data associated with a different model. + */ + public void stealInstance(D inOther) { + if (inOther.owner == this) return; + + inOther.owner.anyToRemove = true; + _add(inOther); } public void render() { @@ -59,17 +91,6 @@ public class Instancer { vao.unbind(); } - public D createInstance() { - return _add(factory.create(this)); - } - - public void stealInstance(D inOther) { - if (inOther.owner == this) return; - - inOther.owner.anyToRemove = true; - _add(inOther); - } - private void init() { model = ModelUtil.getIndexedModel(gen.get()); initialized = true; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/package-info.java new file mode 100644 index 000000000..4ce85a9f8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.instancing.entity; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/package-info.java new file mode 100644 index 000000000..6e52353b7 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.instancing.tile; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/loading/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/loading/package-info.java new file mode 100644 index 000000000..21e83243b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/loading/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.loading; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java index 2f55c4c9a..a8c46059c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java @@ -4,36 +4,31 @@ import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.function.Supplier; -import org.apache.commons.lang3.tuple.Pair; - import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.jozufozu.flywheel.backend.RenderWork; -import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; import com.jozufozu.flywheel.backend.instancing.InstanceData; import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.model.BlockModel; import com.jozufozu.flywheel.core.model.IModel; +import com.jozufozu.flywheel.util.Pair; import com.jozufozu.flywheel.util.RenderUtil; import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.block.BlockState; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BlockRendererDispatcher; -import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.util.Direction; -import net.minecraft.util.math.vector.Vector3i; +/** + * A collection of Instancers that all have the same format. + * @param + */ public class InstanceMaterial { - protected final Supplier originCoordinate; protected final Cache> models; protected final MaterialSpec spec; - private final VertexFormat modelFormat; - public InstanceMaterial(Supplier renderer, MaterialSpec spec) { - this.originCoordinate = renderer; + public InstanceMaterial(MaterialSpec spec) { this.spec = spec; this.models = CacheBuilder.newBuilder() @@ -42,7 +37,37 @@ public class InstanceMaterial { RenderWork.enqueue(instancer::delete); }) .build(); - modelFormat = this.spec.getModelFormat(); + } + + /** + * Get an instancer for the given model. Calling this method twice with the same key will return the same instancer. + * + * @param key An object that uniquely identifies the model. + * @param modelSupplier A factory that creates the IModel that you want to render. + * @return An instancer for the given model, capable of rendering many copies for little cost. + */ + public Instancer model(Object key, Supplier modelSupplier) { + try { + return models.get(key, () -> new Instancer<>(modelSupplier, spec)); + } catch (ExecutionException e) { + throw new RuntimeException("error creating instancer", e); + } + } + + public Instancer getModel(PartialModel partial, BlockState referenceState) { + return model(partial, () -> new BlockModel(spec.getModelFormat(), partial.get(), referenceState)); + } + + public Instancer getModel(PartialModel partial, BlockState referenceState, Direction dir) { + return getModel(partial, referenceState, dir, RenderUtil.rotateToFace(dir)); + } + + public Instancer getModel(PartialModel partial, BlockState referenceState, Direction dir, Supplier modelTransform) { + return model(Pair.of(dir, partial), () -> new BlockModel(spec.getModelFormat(), partial.get(), referenceState, modelTransform.get())); + } + + public Instancer getModel(BlockState toRender) { + return model(toRender, () -> new BlockModel(spec.getModelFormat(), toRender)); } public boolean nothingToRender() { @@ -72,43 +97,4 @@ public class InstanceMaterial { } } - public Instancer getModel(PartialModel partial, BlockState referenceState) { - return model(partial, () -> buildModel(partial.get(), referenceState)); - } - - public Instancer getModel(PartialModel partial, BlockState referenceState, Direction dir) { - return getModel(partial, referenceState, dir, RenderUtil.rotateToFace(dir)); - } - - public Instancer getModel(PartialModel partial, BlockState referenceState, Direction dir, Supplier modelTransform) { - return model(Pair.of(dir, partial), () -> buildModel(partial.get(), referenceState, modelTransform.get())); - } - - public Instancer getModel(BlockState toRender) { - return model(toRender, () -> buildModel(toRender)); - } - - public Instancer model(Object key, Supplier supplier) { - try { - return models.get(key, () -> new Instancer<>(supplier, originCoordinate, spec)); - } catch (ExecutionException e) { - e.printStackTrace(); - return null; - } - } - - private IModel buildModel(BlockState renderedState) { - BlockRendererDispatcher dispatcher = Minecraft.getInstance() - .getBlockRenderer(); - return buildModel(dispatcher.getBlockModel(renderedState), renderedState); - } - - private IModel buildModel(IBakedModel model, BlockState renderedState) { - return buildModel(model, renderedState, new MatrixStack()); - } - - private IModel buildModel(IBakedModel model, BlockState referenceState, MatrixStack ms) { - - return new BlockModel(modelFormat, model, referenceState, ms); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java index d9d84e5af..9dacda4c6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java @@ -10,6 +10,12 @@ import com.jozufozu.flywheel.core.shader.WorldProgram; import net.minecraft.util.math.vector.Matrix4f; +/** + * A group of materials all rendered with the same GL state. + * + * The children of a material group will all be rendered at the same time. + * No guarantees are made about the order of draw calls. + */ public class MaterialGroup

{ protected final MaterialManager

owner; @@ -24,6 +30,17 @@ public class MaterialGroup

{ this.state = state; } + /** + * Get the material as defined by the given {@link MaterialSpec spec}. + * @param spec The material you want to create instances with. + * @param The type representing the per instance data. + * @return A + */ + @SuppressWarnings("unchecked") + public InstanceMaterial material(MaterialSpec spec) { + return (InstanceMaterial) materials.computeIfAbsent(spec, this::createInstanceMaterial); + } + public void render(Matrix4f viewProjection, double camX, double camY, double camZ) { for (MaterialRenderer

renderer : renderers) { renderer.render(viewProjection, camX, camY, camZ); @@ -34,19 +51,6 @@ public class MaterialGroup

{ } - @SuppressWarnings("unchecked") - public InstanceMaterial material(MaterialSpec spec) { - return (InstanceMaterial) materials.computeIfAbsent(spec, this::createInstanceMaterial); - } - - private InstanceMaterial createInstanceMaterial(MaterialSpec type) { - InstanceMaterial material = new InstanceMaterial<>(owner::getOriginCoordinate, type); - - this.renderers.add(new MaterialRenderer<>(owner.getProgram(type.getProgramName()), material, this::setup)); - - return material; - } - public void clear() { materials.values().forEach(InstanceMaterial::clear); } @@ -58,4 +62,12 @@ public class MaterialGroup

{ materials.clear(); renderers.clear(); } + + private InstanceMaterial createInstanceMaterial(MaterialSpec type) { + InstanceMaterial material = new InstanceMaterial<>(type); + + this.renderers.add(new MaterialRenderer<>(owner.getProgram(type.getProgramName()), material, this::setup)); + + return material; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialManager.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialManager.java index d9436c117..869be4cff 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialManager.java @@ -60,9 +60,44 @@ public class MaterialManager

{ } } + /** + * Get a material group that will render in the given layer with the given state. + * + * @param layer The {@link RenderLayer} you want to draw in. + * @param state The {@link IRenderState} you need to draw with. + * @return A material group whose children will + */ + public MaterialGroup

state(RenderLayer layer, IRenderState state) { + return layers.get(layer).computeIfAbsent(state, this::createGroup); + } + + public MaterialGroup

solid(IRenderState state) { + return layers.get(RenderLayer.SOLID).computeIfAbsent(state, this::createGroup); + } + + public MaterialGroup

cutout(IRenderState state) { + return layers.get(RenderLayer.CUTOUT).computeIfAbsent(state, this::createGroup); + } + + public MaterialGroup

transparent(IRenderState state) { + return layers.get(RenderLayer.TRANSPARENT).computeIfAbsent(state, this::createGroup); + } + + public MaterialGroup

defaultSolid() { + return solid(TextureRenderState.get(PlayerContainer.BLOCK_ATLAS)); + } + + public MaterialGroup

defaultCutout() { + return cutout(TextureRenderState.get(PlayerContainer.BLOCK_ATLAS)); + } + + public MaterialGroup

defaultTransparent() { + return transparent(TextureRenderState.get(PlayerContainer.BLOCK_ATLAS)); + } + /** * Render every model for every material. - * @param layer Which vanilla {@link RenderType} is being drawn? + * @param layer Which of the 3 {@link RenderLayer render layers} is being drawn? * @param viewProjection How do we get from camera space to clip space? */ public void render(RenderLayer layer, Matrix4f viewProjection, double camX, double camY, double camZ) { @@ -95,34 +130,6 @@ public class MaterialManager

{ } } - public MaterialGroup

state(RenderLayer layer, IRenderState state) { - return layers.get(layer).computeIfAbsent(state, this::createGroup); - } - - public MaterialGroup

solid(IRenderState state) { - return layers.get(RenderLayer.SOLID).computeIfAbsent(state, this::createGroup); - } - - public MaterialGroup

cutout(IRenderState state) { - return layers.get(RenderLayer.CUTOUT).computeIfAbsent(state, this::createGroup); - } - - public MaterialGroup

transparent(IRenderState state) { - return layers.get(RenderLayer.TRANSPARENT).computeIfAbsent(state, this::createGroup); - } - - public MaterialGroup

defaultSolid() { - return solid(TextureRenderState.get(PlayerContainer.BLOCK_ATLAS)); - } - - public MaterialGroup

defaultCutout() { - return cutout(TextureRenderState.get(PlayerContainer.BLOCK_ATLAS)); - } - - public MaterialGroup

defaultTransparent() { - return transparent(TextureRenderState.get(PlayerContainer.BLOCK_ATLAS)); - } - @Deprecated public InstanceMaterial getMaterial(MaterialSpec materialType) { return defaultCutout().material(materialType); @@ -155,6 +162,11 @@ public class MaterialManager

{ listeners.add(listener); } + /** + * Maintain the integer origin coordinate to be within a certain distance from the camera in all directions. + * + * This prevents floating point precision issues at high coordinates. + */ public void checkAndShiftOrigin(ActiveRenderInfo info) { int cX = MathHelper.floor(info.getPosition().x); int cY = MathHelper.floor(info.getPosition().y); diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialSpec.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialSpec.java index 8946fcbff..9b3a87b5a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialSpec.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialSpec.java @@ -4,7 +4,6 @@ import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; import com.jozufozu.flywheel.backend.instancing.IInstanceFactory; import com.jozufozu.flywheel.backend.instancing.InstanceData; -import net.minecraft.inventory.container.PlayerContainer; import net.minecraft.util.ResourceLocation; public class MaterialSpec { @@ -15,19 +14,13 @@ public class MaterialSpec { private final VertexFormat modelFormat; private final VertexFormat instanceFormat; private final IInstanceFactory instanceFactory; - private final ResourceLocation texture; public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, VertexFormat instanceFormat, IInstanceFactory instanceFactory) { - this(name, programSpec, modelFormat, instanceFormat, PlayerContainer.BLOCK_ATLAS, instanceFactory); - } - - public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, VertexFormat instanceFormat, ResourceLocation texture, IInstanceFactory instanceFactory) { this.name = name; this.programSpec = programSpec; this.modelFormat = modelFormat; this.instanceFormat = instanceFormat; this.instanceFactory = instanceFactory; - this.texture = texture; } public ResourceLocation getProgramName() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/material/package-info.java new file mode 100644 index 000000000..da6906de5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/material/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.material; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/state/RenderLayer.java b/src/main/java/com/jozufozu/flywheel/backend/state/RenderLayer.java index 231e5cead..8594f1f00 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/state/RenderLayer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/state/RenderLayer.java @@ -4,9 +4,36 @@ import javax.annotation.Nullable; import net.minecraft.client.renderer.RenderType; +/** + * The 3 discrete stages the world is rendered in. + */ public enum RenderLayer { + /** + * Solid layer:
+ * + * All polygons will entirely occlude everything behind them. + * + *

+ * e.g. stone, dirt, solid blocks + */ SOLID, + /** + * Cutout layer:
+ * + * Fragments will either occlude or not occlude depending on the texture/material. + * + *

+ * e.g. leaves, cobwebs, tall grass, saplings, glass + */ CUTOUT, + /** + * Transparent layer:
+ * + * Nothing is guaranteed to occlude and fragments blend their color with what's behind them. + * + *

+ * e.g. stained glass, water + */ TRANSPARENT, ; diff --git a/src/main/java/com/jozufozu/flywheel/backend/state/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/state/package-info.java new file mode 100644 index 000000000..0fb20311b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/state/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.state; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/package-info.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/package-info.java new file mode 100644 index 000000000..00190daac --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.core.crumbling; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java b/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java index 3a30847c6..631c87da1 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/BlockModel.java @@ -30,6 +30,12 @@ public class BlockModel implements IModel { private final VertexFormat modelFormat; + public BlockModel(VertexFormat modelFormat, BlockState state) { + this(modelFormat, Minecraft.getInstance() + .getBlockRenderer() + .getBlockModel(state), state); + } + public BlockModel(VertexFormat modelFormat, IBakedModel model, BlockState referenceState) { this(modelFormat, model, referenceState, IDENTITY); } diff --git a/src/main/java/com/jozufozu/flywheel/event/ReloadRenderersEvent.java b/src/main/java/com/jozufozu/flywheel/event/ReloadRenderersEvent.java index dc7bac5fb..aad67e6fd 100644 --- a/src/main/java/com/jozufozu/flywheel/event/ReloadRenderersEvent.java +++ b/src/main/java/com/jozufozu/flywheel/event/ReloadRenderersEvent.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.event; +import javax.annotation.Nullable; + import net.minecraft.client.world.ClientWorld; import net.minecraftforge.eventbus.api.Event; @@ -10,6 +12,7 @@ public class ReloadRenderersEvent extends Event { this.world = world; } + @Nullable public ClientWorld getWorld() { return world; } diff --git a/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java b/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java index a22816f71..fafcfbf75 100644 --- a/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java +++ b/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java @@ -1,5 +1,9 @@ package com.jozufozu.flywheel.event; +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.backend.state.RenderLayer; + import net.minecraft.client.renderer.RenderType; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.math.vector.Matrix4f; @@ -12,6 +16,7 @@ public class RenderLayerEvent extends Event { public final double camX; public final double camY; public final double camZ; + public final RenderLayer layer; public RenderLayerEvent(ClientWorld world, RenderType type, Matrix4f viewProjection, double camX, double camY, double camZ) { this.world = world; @@ -20,6 +25,13 @@ public class RenderLayerEvent extends Event { this.camX = camX; this.camY = camY; this.camZ = camZ; + + this.layer = RenderLayer.fromRenderType(type); + } + + @Nullable + public RenderLayer getLayer() { + return layer; } public ClientWorld getWorld() { diff --git a/src/main/java/com/jozufozu/flywheel/event/package-info.java b/src/main/java/com/jozufozu/flywheel/event/package-info.java new file mode 100644 index 000000000..b2b0463bf --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/event/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.event; + +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault;