diff --git a/fabric-renderer-v0/build.gradle b/fabric-renderer-v0/build.gradle new file mode 100644 index 0000000000..9fed8941c6 --- /dev/null +++ b/fabric-renderer-v0/build.gradle @@ -0,0 +1,6 @@ +archivesBaseName = "fabric-renderer-v0" +version = getSubprojectVersion(project, "0.1.0") + +dependencies { + compile project(path: ':fabric-api-base', configuration: 'dev') +} diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/Renderer.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/Renderer.java new file mode 100644 index 0000000000..8948ce55fb --- /dev/null +++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/Renderer.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.renderer.v1.api; + +import net.fabricmc.fabric.renderer.v1.api.material.MaterialFinder; +import net.fabricmc.fabric.renderer.v1.api.material.RenderMaterial; +import net.fabricmc.fabric.renderer.v1.api.mesh.MeshBuilder; +import net.minecraft.util.Identifier; + +/** + * Interface for rendering plug-ins that provide enhanced capabilities + * for model lighting, buffering and rendering. Such plug-ins implement the + * enhanced model rendering interfaces specified by the Fabric API.
+ */ +public interface Renderer { + /** + * Obtain a new {@link MeshBuilder} instance used to create + * baked models with enhanced features.
+ * + * Renderer does not retain a reference to returned instances and they should be re-used for + * multiple models when possible to avoid memory allocation overhead. + */ + MeshBuilder meshBuilder(); + + /** + * Obtain a new {@link MaterialFinder} instance used to retrieve + * standard {@link RenderMaterial} instances.
+ * + * Renderer does not retain a reference to returned instances and they should be re-used for + * multiple materials when possible to avoid memory allocation overhead. + */ + MaterialFinder materialFinder(); + + /** + * Return a material previously registered via {@link #registerMaterial(Identifier, RenderMaterial)}. + * Will return null if no material was found matching the given identifier. + */ + RenderMaterial materialById(Identifier id); + + /** + * Register a material for re-use by other mods or models within a mod. + * The registry does not persist registrations - mods must create and register + * all materials at game initialization.
+ * + * Returns false if a material with the given identifier is already present, + * leaving the existing material intact. + */ + boolean registerMaterial(Identifier id, RenderMaterial material); +} diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/RendererAccess.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/RendererAccess.java new file mode 100644 index 0000000000..ccd6a390ed --- /dev/null +++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/RendererAccess.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.renderer.v1.api; + +import net.fabricmc.fabric.renderer.v1.impl.RendererAccessImpl; + +/** + * Registration and access for rendering extensions. + */ +public interface RendererAccess { + RendererAccess INSTANCE = RendererAccessImpl.INSTANCE; + + /** + * Rendering extension mods must implement {@link Renderer} and + * call this method during initialization.
+ * + * Only one {@link Renderer} plug-in can be active in any game instance. + * If a second mod attempts to register this method will throw an UnsupportedOperationException. + */ + void registerRenderer(Renderer plugin); + + /** + * Access to the current {@link Renderer} for creating and retrieving model builders + * and materials. Will return null if no render plug in is active. + */ + Renderer getRenderer(); + + /** + * Performant test for {@link #getRenderer()} != null; + */ + boolean hasRenderer(); +} diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/material/MaterialFinder.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/material/MaterialFinder.java new file mode 100644 index 0000000000..9ee9850aa9 --- /dev/null +++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/material/MaterialFinder.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.renderer.v1.api.material; + +import net.fabricmc.fabric.renderer.v1.api.Renderer; +import net.fabricmc.fabric.renderer.v1.api.mesh.QuadEmitter; +import net.fabricmc.fabric.renderer.v1.api.render.RenderContext; +import net.minecraft.block.Block; +import net.minecraft.block.BlockRenderLayer; + +/** + * Finds standard {@link RenderMaterial} instances used to communicate + * quad rendering characteristics to a {@link RenderContext}.
+ * + * Must be obtained via {@link Renderer#materialFinder()}. + */ +public interface MaterialFinder { + /** + * Returns the standard material encoding all + * of the current settings in this finder. The settings in + * this finder are not changed.
+ * + * Resulting instances can and should be re-used to prevent + * needless memory allocation. {@link Renderer} implementations + * may or may not cache standard material instances. + */ + RenderMaterial find(); + + /** + * Resets this instance to default values. Values will match those + * in effect when an instance is newly obtained via {@link Renderer#materialFinder()}. + */ + MaterialFinder clear(); + + /** + * + * Reserved for future use. Behavior for values > 1 is currently undefined. + */ + MaterialFinder spriteDepth(int depth); + + /** + * Defines how sprite pixels will be blended with the scene. + * Accepts {link @BlockRenderLayer} values and blending behavior + * will emulate the way that Minecraft renders each pass. But this does + * NOT mean the sprite will be rendered in a specific render pass - some + * implementations may not use the standard Minecraft render passes.
+ * + * CAN be null and is null by default. A null value means the renderer + * will use {@link Block#getRenderLayer()} for the associate block, or + * {@link BlockRenderLayer#TRANSLUCENT} for item renders. (Normal Minecraft rendering) + */ + MaterialFinder blendMode(int spriteIndex, BlockRenderLayer blendMode); + + /** + * Vertex color(s) will be modified for quad color index unless disabled.
+ */ + MaterialFinder disableColorIndex(int spriteIndex, boolean disable); + + /** + * Vertex color(s) will be modified for diffuse shading unless disabled. + */ + MaterialFinder disableDiffuse(int spriteIndex, boolean disable); + + /** + * Vertex color(s) will be modified for ambient occlusion unless disabled. + */ + MaterialFinder disableAo(int spriteIndex, boolean disable); + + /** + * When true, sprite texture and color will be rendered at full brightness. + * Lightmap values provided via {@link QuadEmitter#lightmap(int)} will be ignored. + * False by default
+ * + * This is the preferred method for emissive lighting effects. Some renderers + * with advanced lighting models may not use block lightmaps and this method will + * allow per-sprite emissive lighting in future extensions that support overlay sprites.
+ * + * Note that color will still be modified by diffuse shading and ambient occlusion, + * unless disabled via {@link #disableAo(int, boolean)} and {@link #disableDiffuse(int, boolean)}. + */ + MaterialFinder emissive(int spriteIndex, boolean isEmissive); +} diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/material/RenderMaterial.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/material/RenderMaterial.java new file mode 100644 index 0000000000..058d91cb4c --- /dev/null +++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/material/RenderMaterial.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.renderer.v1.api.material; + +import net.fabricmc.fabric.renderer.v1.api.Renderer; +import net.fabricmc.fabric.renderer.v1.api.mesh.MeshBuilder; +import net.fabricmc.fabric.renderer.v1.api.mesh.MutableQuadView; +import net.minecraft.block.Block; +import net.minecraft.util.Identifier; + +/** + * All model quads have an associated render material governing + * how the quad will be rendered.
+ * + * A material instance is always immutable and thread-safe. References to a material + * remain valid until the end of the current game session.
+ * + * Materials can be registered and shared between mods using {@link Renderer#registerMaterial(net.minecraft.util.Identifier, RenderMaterial)}. + * The registering mod is responsible for creating each registered material at startup.
+ * + * Materials are not required to know their registration identity, and two materials + * with the same attributes may or may not satisfy equality and identity tests. Model + * implementations should never attempt to analyze materials or implement control logic based on them. + * They are only tokens for communicating quad attributes to the ModelRenderer.
+ * + * There are three classes of materials...
+ * + * STANDARD MATERIALS
+ * + * Standard materials have "normal" rendering with control over lighting, + * color, and texture blending. In the default renderer, "normal" rendering + * emulates unmodified Minecraft. Other renderers may offer a different aesthetic.
+ * + * The number of standard materials is finite, but not necessarily small. + * To find a standard material, use {@link Renderer#materialFinder()}.
+ * + * All renderer implementations should support standard materials.
+ * + * SHADER MATERIALS
+ * + * Shader materials are standard materials with a vertex and fragment shader attached. + * The quad attributes for standard materials have standard vertex attribute bindings + * for cross-compatibility of shaders. Vertex colors will be modified (lit) by the + * renderer before the vertex shader runs, unless lighting (AO and diffuse) has been + * disabled in the standard material.
+ * + * Shader materials do not have to implement any sort of "standard" render, and the quad + * vertex attributes can be re-purposed to fit the needs of the shader author.
+ * + * Shader materials are an optional {@link Renderer} feature. + * {@link Renderer#shaderManager()} will return null if shaders are unsupported.
+ * + * SPECIAL MATERIALS
+ * + * Special materials are implemented directly by the Renderer implementation, typically + * with the aim of providing advanced/extended features. Such materials may offer additional + * vertex attributes via extensions to {@link MeshBuilder} and {@link MutableQuadView}.
+ * + * Special materials can be obtained using {@link Renderer#materialById(Identifier)} + * with a known identifier. Renderers may provide other means of access. Popular + * special materials could be implemented by multiple renderers, however there is + * no requirement that special materials be cross-compatible. + */ +public interface RenderMaterial { + /** + * This will be identical to the material that would be obtained by calling {@link MaterialFinder#find()} + * on a new, unaltered, {@link MaterialFinder} instance. It is defined here for clarity and convenience. + * + * Quads using this material use {@link Block#getRenderLayer()} of the associated block to determine texture blending, + * honor block color index, are non-emissive, and apply both diffuse and ambient occlusion shading to vertex colors.
+ * + * All standard, non-fluid baked models are rendered using this material. + */ + Identifier MATERIAL_STANDARD = new Identifier("fabric", "standard"); + + /** + * How many sprite color/uv coordinates are in the material. + * Behavior for values > 1 is currently undefined. + * See {@link MaterialFinder#spriteDepth(int)} + */ + int spriteDepth(); +} diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/Mesh.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/Mesh.java new file mode 100644 index 0000000000..799beb3dd5 --- /dev/null +++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/Mesh.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.renderer.v1.api.mesh; + +import java.util.function.Consumer; + +import net.fabricmc.fabric.renderer.v1.api.Renderer; + +/** + * A bundle of one or more {@link QuadView} instances encoded by the renderer, + * typically via {@link Renderer#meshBuilder()}.
+ *
+ * Similar in purpose to the List
+ *
+ * Only the renderer should implement or extend this interface.
+ */
+public interface Mesh {
+ /**
+ * Use to access all of the quads encoded in this mesh. The quad instances
+ * sent to the consumer will likely be threadlocal/reused and should never
+ * be retained by the consumer.
+ */
+ public void forEach(Consumer
+ *
+ * Decouples models from the vertex format(s) used by
+ * ModelRenderer to allow compatibility across diverse implementations.
+ */
+public interface MeshBuilder {
+ /**
+ * Returns the {@link QuadEmitter} used to append quad to this mesh.
+ * Calling this method a second time invalidates any prior result.
+ * Do not retain references outside the context of building the mesh.
+ */
+ QuadEmitter getEmitter();
+
+ /**
+ * Returns a new {@link Mesh} instance containing all
+ * quads added to this builder and resets the builder to an empty state
+ */
+ Mesh build();
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/MutableQuadView.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/MutableQuadView.java
new file mode 100644
index 0000000000..44c0698430
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/MutableQuadView.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.mesh;
+
+import net.fabricmc.fabric.renderer.v1.api.Renderer;
+import net.fabricmc.fabric.renderer.v1.api.material.MaterialFinder;
+import net.fabricmc.fabric.renderer.v1.api.material.RenderMaterial;
+import net.minecraft.client.render.model.BakedQuad;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.client.util.math.Vector3f;
+import net.minecraft.util.math.Direction;
+
+/**
+ * A mutable {@link QuadView} instance. The base interface for
+ * {@link QuadEmitter} and for dynamic renders/mesh transforms.
+ *
+ * Instances of {@link MutableQuadView} will practically always be
+ * threadlocal and/or reused - do not retain references.
+ *
+ * Only the renderer should implement or extend this interface.
+ */
+public interface MutableQuadView extends QuadView {
+ /**
+ * Causes texture to appear with no rotation.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ */
+ int BAKE_ROTATE_NONE = 0;
+
+ /**
+ * Causes texture to appear rotated 90 deg. relative to nominal face.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ */
+ int BAKE_ROTATE_90 = 1;
+
+ /**
+ * Causes texture to appear rotated 180 deg. relative to nominal face.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ */
+ int BAKE_ROTATE_180 = 2;
+
+ /**
+ * Causes texture to appear rotated 270 deg. relative to nominal face.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ */
+ int BAKE_ROTATE_270 = 3;
+
+ /**
+ * When enabled, texture coordinate are assigned based on vertex position.
+ * Any existing uv coordinates will be replaced.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ *
+ * UV lock always derives texture coordinates based on nominal face, even
+ * when the quad is not co-planar with that face, and the result is
+ * the same as if the quad were projected onto the nominal face, which
+ * is usually the desired result.
+ */
+ int BAKE_LOCK_UV = 4;
+
+ /**
+ * When set, U texture coordinates for the given sprite are
+ * flipped as part of baking. Can be useful for some randomization
+ * and texture mapping scenarios. Results are different than what
+ * can be obtained via rotation and both can be applied.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ */
+ int BAKE_FLIP_U = 8;
+
+ /**
+ * Same as {@link MutableQuadView#BAKE_FLIP_U} but for V coordinate.
+ */
+ int BAKE_FLIP_V = 16;
+
+ /**
+ * UV coordinates by default are assumed to be 0-16 scale for consistency
+ * with conventional Minecraft model format. This is scaled to 0-1 during
+ * baking before interpolation. Model loaders that already have 0-1 coordinates
+ * can avoid wasteful multiplication/division by passing 0-1 coordinates directly.
+ * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}.
+ */
+ int BAKE_NORMALIZED = 32;
+
+ /**
+ * Assigns a different material to this quad. Useful for transformation of
+ * existing meshes because lighting and texture blending are controlled by material.
+ */
+ MutableQuadView material(RenderMaterial material);
+
+ /**
+ * If non-null, quad is coplanar with a block face which, if known, simplifies
+ * or shortcuts geometric analysis that might otherwise be needed.
+ * Set to null if quad is not coplanar or if this is not known.
+ * Also controls face culling during block rendering.
+ *
+ * Null by default.
+ *
+ * When called with a non-null value, also sets {@link #nominalFace(Direction)}
+ * to the same value.
+ *
+ * This is different than the value reported by {@link BakedQuad#getFace()}. That value
+ * is computed based on face geometry and must be non-null in vanilla quads.
+ * That computed value is returned by {@link #lightFace()}.
+ */
+ MutableQuadView cullFace(Direction face);
+
+ /**
+ * Provides a hint to renderer about the facing of this quad. Not required,
+ * but if provided can shortcut some geometric analysis if the quad is parallel to a block face.
+ * Should be the expected value of {@link #lightFace()}. Value will be confirmed
+ * and if invalid the correct light face will be calculated.
+ *
+ * Null by default, and set automatically by {@link #cullFace()}.
+ *
+ * Models may also find this useful as the face for texture UV locking and rotation semantics.
+ *
+ * NOTE: This value is not persisted independently when the quad is encoded.
+ * When reading encoded quads, this value will always be the same as {@link #lightFace()}.
+ */
+ MutableQuadView nominalFace(Direction face);
+
+ /**
+ * Value functions identically to {@link BakedQuad#getColorIndex()} and is
+ * used by renderer / model builder in same way. Default value is -1.
+ */
+ MutableQuadView colorIndex(int colorIndex);
+
+ /**
+ * Enables bulk vertex data transfer using the standard Minecraft vertex formats.
+ * This method should be performant whenever caller's vertex representation makes it feasible.
+ *
+ * Calling this method does not emit the quad.
+ */
+ MutableQuadView fromVanilla(int[] quadData, int startIndex, boolean isItem);
+
+ /**
+ * Encodes an integer tag with this quad that can later be retrieved via
+ * {@link QuadView#tag()}. Useful for models that want to perform conditional
+ * transformation or filtering on static meshes.
+ */
+ MutableQuadView tag(int tag);
+
+ /**
+ * Sets the geometric vertex position for the given vertex,
+ * relative to block origin. (0,0,0). Minecraft rendering is designed
+ * for models that fit within a single block space and is recommended
+ * that coordinates remain in the 0-1 range, with multi-block meshes
+ * split into multiple per-block models.
+ */
+ MutableQuadView pos(int vertexIndex, float x, float y, float z);
+
+ /**
+ * Same as {@link #pos(float, float, float)} but accepts vector type.
+ */
+ default MutableQuadView pos(int vertexIndex, Vector3f vec) {
+ return pos(vertexIndex, vec.x(), vec.y(), vec.z());
+ }
+
+ /**
+ * Adds a vertex normal. Models that have per-vertex
+ * normals should include them to get correct lighting when it matters.
+ * Computed face normal is used when no vertex normal is provided.
+ *
+ * {@link Renderer} implementations should honor vertex normals for
+ * diffuse lighting - modifying vertex color(s) or packing normals in the vertex
+ * buffer as appropriate for the rendering method/vertex format in effect.
+ */
+ MutableQuadView normal(int vertexIndex, float x, float y, float z);
+
+ /**
+ * Same as {@link #normal(float, float, float, extra)} but accepts vector type.
+ */
+ default MutableQuadView normal(int vertexIndex, Vector3f vec) {
+ return normal(vertexIndex, vec.x(), vec.y(), vec.z());
+ }
+
+ /**
+ * Accept vanilla lightmap values. Input values will override lightmap values
+ * computed from world state if input values are higher. Exposed for completeness
+ * but some rendering implementations with non-standard lighting model may not honor it.
+ *
+ * For emissive rendering, it is better to use {@link MaterialFinder#emissive(int, boolean)}.
+ */
+ MutableQuadView lightmap(int vertexIndex, int lightmap);
+
+ /**
+ * Convenience: set lightmap for all vertices at once.
+ *
+ * For emissive rendering, it is better to use {@link MaterialFinder#emissive(int, boolean)}.
+ * See {@link #lightmap(int, int)}.
+ */
+ default MutableQuadView lightmap(int b0, int b1, int b2, int b3) {
+ lightmap(0, b0);
+ lightmap(1, b1);
+ lightmap(2, b2);
+ lightmap(3, b3);
+ return this;
+ }
+
+ /**
+ * Set sprite color. Behavior for spriteIndex values > 0 is currently undefined.
+ */
+ MutableQuadView spriteColor(int vertexIndex, int spriteIndex, int color);
+
+ /**
+ * Convenience: set sprite color for all vertices at once. Behavior for spriteIndex values > 0 is currently undefined.
+ */
+ default MutableQuadView spriteColor(int spriteIndex, int c0, int c1, int c2, int c3) {
+ spriteColor(0, spriteIndex, c0);
+ spriteColor(1, spriteIndex, c1);
+ spriteColor(2, spriteIndex, c2);
+ spriteColor(3, spriteIndex, c3);
+ return this;
+ }
+
+ /**
+ * Set sprite atlas coordinates. Behavior for spriteIndex values > 0 is currently undefined.
+ */
+ MutableQuadView sprite(int vertexIndex, int spriteIndex, float u, float v);
+
+ /**
+ * Assigns sprite atlas u,v coordinates to this quad for the given sprite.
+ * Can handle UV locking, rotation, interpolation, etc. Control this behavior
+ * by passing additive combinations of the BAKE_ flags defined in this interface.
+ * Behavior for spriteIndex values > 0 is currently undefined.
+ */
+ MutableQuadView spriteBake(int spriteIndex, Sprite sprite, int bakeFlags);
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/QuadEmitter.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/QuadEmitter.java
new file mode 100644
index 0000000000..62ecc458f9
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/QuadEmitter.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.mesh;
+
+import net.fabricmc.fabric.renderer.v1.api.material.RenderMaterial;
+import net.fabricmc.fabric.renderer.v1.api.render.RenderContext;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.client.util.math.Vector3f;
+import net.minecraft.util.math.Direction;
+
+/**
+ * Specialized {@link MutableQuadView} obtained via {@link MeshBuilder#getEmitter()}
+ * to append quads during mesh building.
+ *
+ * Also obtained from {@link RenderContext#getEmitter(RenderMaterial)} to submit
+ * dynamic quads one-by-one at render time.
+ *
+ * Instances of {@link QuadEmitter} will practically always be
+ * threadlocal and/or reused - do not retain references.
+ *
+ * Only the renderer should implement or extend this interface.
+ */
+public interface QuadEmitter extends MutableQuadView {
+ @Override
+ QuadEmitter material(RenderMaterial material);
+
+ @Override
+ QuadEmitter cullFace(Direction face);
+
+ @Override
+ QuadEmitter nominalFace(Direction face);
+
+ @Override
+ QuadEmitter colorIndex(int colorIndex);
+
+ @Override
+ QuadEmitter fromVanilla(int[] quadData, int startIndex, boolean isItem);
+
+ @Override
+ QuadEmitter tag(int tag);
+
+ @Override
+ QuadEmitter pos(int vertexIndex, float x, float y, float z);
+
+ @Override
+ default QuadEmitter pos(int vertexIndex, Vector3f vec) {
+ MutableQuadView.super.pos(vertexIndex, vec);
+ return this;
+ }
+
+ @Override
+ default QuadEmitter normal(int vertexIndex, Vector3f vec) {
+ MutableQuadView.super.normal(vertexIndex, vec);
+ return this;
+ }
+
+ @Override
+ QuadEmitter lightmap(int vertexIndex, int lightmap);
+
+ @Override
+ default QuadEmitter lightmap(int b0, int b1, int b2, int b3) {
+ MutableQuadView.super.lightmap(b0, b1, b2, b3);
+ return this;
+ }
+
+ @Override
+ QuadEmitter spriteColor(int vertexIndex, int spriteIndex, int color);
+
+ @Override
+ default QuadEmitter spriteColor(int spriteIndex, int c0, int c1, int c2, int c3) {
+ MutableQuadView.super.spriteColor(spriteIndex, c0, c1, c2, c3);
+ return this;
+ }
+
+ @Override
+ QuadEmitter sprite(int vertexIndex, int spriteIndex, float u, float v);
+
+ default QuadEmitter spriteUnitSquare(int spriteIndex) {
+ sprite(0, spriteIndex, 0, 0);
+ sprite(1, spriteIndex, 0, 1);
+ sprite(2, spriteIndex, 1, 1);
+ sprite(3, spriteIndex, 1, 0);
+ return this;
+ }
+
+ @Override
+ QuadEmitter spriteBake(int spriteIndex, Sprite sprite, int bakeFlags);
+
+ /**
+ * Helper method to assign vertex coordinates for a square aligned with the given face.
+ * Ensures that vertex order is consistent with vanilla convention. (Incorrect order can
+ * lead to bad AO lighting.)
+ *
+ * Square will be parallel to the given face and coplanar with the face if depth == 0.
+ * All coordinates are normalized (0-1).
+ */
+ default QuadEmitter square(Direction nominalFace, float left, float bottom, float right, float top, float depth) {
+ cullFace(depth == 0 ? nominalFace : null);
+ nominalFace(nominalFace);
+ switch(nominalFace)
+ {
+ case UP:
+ depth = 1 - depth;
+ top = 1 - top;
+ bottom = 1 - bottom;
+
+ case DOWN:
+ pos(0, left, depth, top);
+ pos(1, left, depth, bottom);
+ pos(2, right, depth, bottom);
+ pos(3, right, depth, top);
+ break;
+
+ case EAST:
+ depth = 1 - depth;
+ left = 1 - left;
+ right = 1 - right;
+
+ case WEST:
+ pos(0, depth, top, left);
+ pos(1, depth, bottom, left);
+ pos(2, depth, bottom, right);
+ pos(3, depth, top, right);
+ break;
+
+ case SOUTH:
+ depth = 1 - depth;
+ left = 1 - left;
+ right = 1 - right;
+
+ case NORTH:
+ pos(0, right, top, depth);
+ pos(1, right, bottom, depth);
+ pos(2, left, bottom, depth);
+ pos(3, left, top, depth);
+ break;
+ }
+ return this;
+ }
+
+ /**
+ * In static mesh building, causes quad to be appended to the mesh being built.
+ * In a dynamic render context, create a new quad to be output to rendering.
+ * In both cases, current instance is reset to default values.
+ */
+ QuadEmitter emit();
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/QuadView.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/QuadView.java
new file mode 100644
index 0000000000..3009f8d8c1
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/mesh/QuadView.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.mesh;
+
+import net.fabricmc.fabric.renderer.v1.api.material.RenderMaterial;
+import net.minecraft.client.render.model.BakedQuad;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.client.util.math.Vector3f;
+import net.minecraft.util.math.Direction;
+
+/**
+ * Interface for reading quad data encoded by {@link MeshBuilder}.
+ * Enables models to do analysis, re-texturing or translation without knowing the
+ * renderer's vertex formats and without retaining redundant information.
+ *
+ * Only the renderer should implement or extend this interface.
+ */
+public interface QuadView {
+ /**
+ * Reads baked vertex data and outputs standard baked quad
+ * vertex data in the given array and location.
+ *
+ * @param spriteIndex The sprite to be used for the quad.
+ * Behavior for values > 0 is currently undefined.
+ *
+ * @param target Target array for the baked quad data.
+ *
+ * @param targetIndex Starting position in target array - array must have
+ * at least 28 elements available at this index.
+ *
+ * @param isItem If true, will output vertex normals. Otherwise will output
+ * lightmaps, per Minecraft vertex formats for baked models.
+ */
+ void toVanilla(int spriteIndex, int[] target, int targetIndex, boolean isItem);
+
+ /**
+ * Extracts all quad properties except material to the given {@link MutableQuadView} instance.
+ * Must be used before calling {@link MutableQuadView#emit()} on the target instance.
+ * Meant for re-texturing, analysis and static transformation use cases.
+ */
+ void copyTo(MutableQuadView target);
+
+ /**
+ * Retrieves the material serialized with the quad.
+ */
+ RenderMaterial material();
+
+ /**
+ * Retrieves the quad color index serialized with the quad.
+ */
+ int colorIndex();
+
+ /**
+ * Equivalent to {@link BakedQuad#getFace()}. This is the face used for vanilla lighting
+ * calculations and will be the block face to which the quad is most closely aligned. Always
+ * the same as cull face for quads that are on a block face, but never null.
+ */
+ Direction lightFace();
+
+ /**
+ * If non-null, quad should not be rendered in-world if the
+ * opposite face of a neighbor block occludes it.
+ *
+ * See {@link MutableQuadView#cullFace(Direction)}.
+ */
+ Direction cullFace();
+
+ /**
+ * See {@link MutableQuadView#nominalFace(Direction)}.
+ */
+ Direction nominalFace();
+
+ /**
+ * Normal of the quad as implied by geometry. Will be invalid
+ * if quad vertices are not co-planar. Typically computed lazily
+ * on demand and not encoded.
+ *
+ * Not typically needed by models. Exposed to enable standard lighting
+ * utility functions for use by renderers.
+ */
+ Vector3f faceNormal();
+
+ /**
+ * Generates a new BakedQuad instance with texture
+ * coordinates and colors from the given sprite.
+ *
+ * @param source Data previously packed by {@link MeshBuilder}.
+ *
+ * @param sourceIndex Index where packed data starts.
+ *
+ * @param spriteIndex The sprite to be used for the quad.
+ * Behavior for values > 0 is currently undefined.
+ *
+ * @param sprite {@link MutableQuadView} does not serialize sprites
+ * so the sprite must be provided by the caller.
+ *
+ * @param isItem If true, will output vertex normals. Otherwise will output
+ * lightmaps, per Minecraft vertex formats for baked models.
+ *
+ * @return A new baked quad instance with the closest-available appearance
+ * supported by vanilla features. Will retain emissive light maps, for example,
+ * but the standard Minecraft renderer will not use them.
+ */
+ default BakedQuad toBakedQuad(int spriteIndex, Sprite sprite, boolean isItem) {
+ int vertexData[] = new int[28];
+ toVanilla(spriteIndex, vertexData, 0, isItem);
+ return new BakedQuad(vertexData, colorIndex(), lightFace(), sprite);
+ }
+
+ /**
+ * Retrieves the integer tag encoded with this quad via {@link MutableQuadView#tag(int)}.
+ * Will return zero if no tag was set. For use by models.
+ */
+ int tag();
+
+ /**
+ * Pass a non-null target to avoid allocation - will be returned with values.
+ * Otherwise returns a new instance.
+ * See {@link VertexEditor#pos(float, float, float)}
+ */
+ Vector3f copyPos(int vertexIndex, Vector3f target);
+
+ /**
+ * Convenience: access x, y, z by index 0-2
+ */
+ float posByIndex(int vertexIndex, int coordinateIndex);
+
+ /**
+ * Geometric position, x coordinate.
+ */
+ float x(int vertexIndex);
+
+ /**
+ * Geometric position, y coordinate.
+ */
+ float y(int vertexIndex);
+
+ /**
+ * Geometric position, z coordinate.
+ */
+ float z(int vertexIndex);
+
+ /**
+ * If false, no vertex normal was provided.
+ * Lighting should use face normal in that case.
+ * See {@link VertexEditor#normal(float, float, float, float)}
+ */
+ boolean hasNormal(int vertexIndex);
+
+ /**
+ * Pass a non-null target to avoid allocation - will be returned with values.
+ * Otherwise returns a new instance. Returns null if normal not present.
+ */
+ Vector3f copyNormal(int vertexIndex, Vector3f target);
+
+ /**
+ * Will return {@link Float#NaN} if normal not present.
+ */
+ float normalX(int vertexIndex);
+
+ /**
+ * Will return {@link Float#NaN} if normal not present.
+ */
+ float normalY(int vertexIndex);
+
+ /**
+ * Will return {@link Float#NaN} if normal not present.
+ */
+ float normalZ(int vertexIndex);
+
+ /**
+ * Minimum block brightness. Zero if not set.
+ */
+ int lightmap(int vertexIndex);
+
+ /**
+ * Retrieve vertex color.
+ */
+ int spriteColor(int vertexIndex, int spriteIndex);
+
+ /**
+ * Retrieve horizontal sprite atlas coordinates.
+ */
+ float spriteU(int vertexIndex, int spriteIndex);
+
+ /**
+ * Retrieve vertical sprite atlas coordinates
+ */
+ float spriteV(int vertexIndex, int spriteIndex);
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/model/DynamicModelBlockEntity.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/model/DynamicModelBlockEntity.java
new file mode 100644
index 0000000000..721c485eaf
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/model/DynamicModelBlockEntity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.model;
+
+import net.minecraft.block.entity.BlockEntity;
+
+/**
+ * Interface for {@link BlockEntity}s which provide dynamic model state data.
+ *
+ * Dynamic model state data is separate from BlockState, and will be
+ * cached during render chunk building on the main thread (safely) and accessible
+ * during chunk rendering on non-main threads.
+ *
+ * For this reason, please ensure that all accesses to the passed model data are
+ * thread-safe. This can be achieved by, for example, passing a pre-generated
+ * immutable object, or ensuring all gets performed on the passed object are atomic
+ * and well-checked for unusual states.
+ */
+@FunctionalInterface
+public interface DynamicModelBlockEntity {
+ /**
+ * @return The model state data provided by this block entity. Can be null.
+ */
+ Object getDynamicModelData();
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/model/FabricBakedModel.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/model/FabricBakedModel.java
new file mode 100644
index 0000000000..8759b319d9
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/model/FabricBakedModel.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.model;
+
+import java.util.Random;
+import java.util.function.Supplier;
+
+import net.fabricmc.fabric.renderer.v1.api.Renderer;
+import net.fabricmc.fabric.renderer.v1.api.render.RenderContext;
+import net.fabricmc.fabric.renderer.v1.api.render.TerrainBlockView;
+import net.minecraft.block.BlockState;
+import net.minecraft.client.render.block.BlockModelRenderer;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.ExtendedBlockView;
+
+/**
+ * Interface for baked models that output meshes with enhanced rendering features.
+ * Can also be used to generate or customize outputs based on world state instead of
+ * or in addition to block state when render chunks are rebuilt.
+ *
+ * Note for {@link Renderer} implementors: Fabric causes BakedModel to extend this
+ * interface with {@link #isVanillaAdapter()} == true and to produce standard vertex data.
+ * This means any BakedModel instance can be safely cast to this interface without an instanceof check.
+ */
+public interface FabricBakedModel {
+ /**
+ * When true, signals renderer this producer is implemented through {@link BakedModel#getQuads(BlockState, net.minecraft.util.math.Direction, Random)}.
+ * Also means the model does not rely on any non-vanilla features.
+ * Allows the renderer to optimize or route vanilla models through the unmodified vanilla pipeline if desired.
+
+ * Fabric overrides to true for vanilla baked models.
+ * Enhanced models that use this API should return false,
+ * otherwise the API will not recognize the model.
+ */
+ boolean isVanillaAdapter();
+
+ /**
+ * This method will be called during chunk rebuilds to generate both the static and
+ * dynamic portions of a block model when the model implements this interface and
+ * {@link #isVanillaAdapter()} returns false.
+ *
+ * During chunk rebuild, this method will always be called exactly one time per block
+ * position, irrespective of which or how many faces or block render layers are included
+ * in the model. Models must output all quads/meshes in a single pass.
+ *
+ * Also called to render block models outside of chunk rebuild or block entity rendering.
+ * Typically this happens when the block is being rendered as an entity, not as a block placed in the world.
+ * Currently this happens for falling blocks and blocks being pushed by a piston, but renderers
+ * should invoke this for all calls to {@link BlockModelRenderer#tesselate(ExtendedBlockView, BakedModel, BlockState, BlockPos, net.minecraft.client.render.BufferBuilder, boolean, Random, long)}
+ * that occur outside of chunk rebuilds to allow for features added by mods, unless
+ * {@link #isVanillaAdapter()} returns true.
+ *
+ * Outside of chunk rebuilds, this method will be called every frame. Model implementations should
+ * rely on pre-baked meshes as much as possible and keep transformation to a minimum. The provided
+ * block position may be the nearest block position and not actual. For this reason, neighbor
+ * state lookups are best avoided or will require special handling. Block entity lookups are
+ * likely to fail and/or give meaningless results.
+ *
+ * In all cases, renderer will handle face occlusion and filter quads on faces obscured by
+ * neighboring blocks (if appropriate). Models only need to consider "sides" to the
+ * extent the model is driven by connection with neighbor blocks or other world state.
+ *
+ * Note: with {@link BakedModel#getQuads(BlockState, net.minecraft.util.math.Direction, Random)}, the random
+ * parameter is normally initialized with the same seed prior to each face layer.
+ * Model authors should note this method is called only once per block, and call the provided
+ * Random supplier multiple times if re-seeding is necessary. For wrapped vanilla baked models,
+ * it will probably be easier to use {@link RenderContext#fallbackModelConsumer()} which handles
+ * re-seeding per face automatically.
+ *
+ * @param Access to world state. Using {@link TerrainBlockView#getCachedRenderData(BlockPos)} to
+ * retrieve block entity state unless thread safety can be guaranteed.
+ * @param safeBlockEntityAccessor Thread-safe access to block entity data
+ * @param state Block state for model being rendered.
+ * @param pos Position of block for model being rendered.
+ * @param randomSupplier Random object seeded per vanilla conventions. Call multiple times to re-seed.
+ * Will not be thread-safe. Do not cache or retain a reference.
+ * @param context Accepts model output.
+ */
+ void emitBlockQuads(TerrainBlockView blockView, BlockState state, BlockPos pos, Supplier
+ *
+ * Vanilla item rendering is normally very limited. It ignores lightmaps, vertex colors,
+ * and vertex normals. Renderers are expected to implement enhanced features for item
+ * models. If a feature is impractical due to performance or other concerns, then the
+ * renderer must at least give acceptable visual results without the need for special-
+ * case handling in model implementations.
+ *
+ * Calls to this method will generally happen on the main client thread but nothing
+ * prevents a mod or renderer from calling this method concurrently. Implementations
+ * should not mutate the ItemStack parameter, and best practice will be to make the
+ * method thread-safe.
+ *
+ * Implementing this method does NOT mitigate the need to implement a functional
+ * {@link BakedModel#getItemPropertyOverrides()} method, because this method will be called
+ * on the result of {@link #getItemPropertyOverrides()}. However, that
+ * method can simply return the base model because the output from this method will
+ * be used for rendering.
+ *
+ * Renderer implementations should also use this method to obtain the quads used
+ * for item enchantment glint rendering. This means models can put geometric variation
+ * logic here, instead of returning every possible shape from {@link #getItemPropertyOverrides()}
+ * as vanilla baked models.
+ */
+ void emitItemQuads(ItemStack stack, Supplier
+ *
+ * Retrieves sprites from the block texture atlas via {@link SpriteFinder}.
+ */
+ public static List
+ *
+ * Should be reliable for any convex quad or triangle. May fail for non-convex quads.
+ * Note that all the above refers to u,v coordinates. Geometric vertex does not matter,
+ * except to the extent it was used to determine u,v.
+ */
+ Sprite find(QuadView quad, int textureIndex);
+
+ /**
+ * Alternative to {@link #find(QuadView, int)} when vertex centroid is already
+ * known or unsuitable. Expects normalized (0-1) coordinates on the atlas texture,
+ * which should already be the case for u,v values in vanilla baked quads and in
+ * {@link QuadView} after calling {@link MutableQuadView#spriteBake(int, Sprite, int)}.
+ *
+ * Coordinates must be in the sprite interior for reliable results. Generally will
+ * be easier to use {@link #find(QuadView, int)} unless you know the vertex
+ * centroid will somehow not be in the quad interior. This method will be slightly
+ * faster if you already have the centroid or another appropriate value.
+ */
+ Sprite find(float u, float v);
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/render/RenderContext.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/render/RenderContext.java
new file mode 100644
index 0000000000..c6b3109200
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/render/RenderContext.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.render;
+
+import java.util.function.Consumer;
+
+import net.fabricmc.fabric.renderer.v1.api.mesh.Mesh;
+import net.fabricmc.fabric.renderer.v1.api.mesh.MeshBuilder;
+import net.fabricmc.fabric.renderer.v1.api.mesh.MutableQuadView;
+import net.fabricmc.fabric.renderer.v1.api.mesh.QuadEmitter;
+import net.fabricmc.fabric.renderer.v1.api.model.FabricBakedModel;
+import net.minecraft.client.render.model.BakedModel;
+
+/**
+ * This defines the instance made available to models for buffering vertex data at render time.
+ */
+public interface RenderContext {
+ /**
+ * Used by models to send vertex data previously baked via {@link MeshBuilder}.
+ * The fastest option and preferred whenever feasible.
+ */
+ Consumer
+ *
+ * This method will always be less performant than passing pre-baked meshes
+ * via {@link #meshConsumer()}. It should be used sparingly for model components that
+ * demand it - text, icons, dynamic indicators, or other elements that vary too
+ * much for static baking to be feasible.
+ *
+ * Calling this method invalidates any {@link QuadEmitter} returned earlier.
+ * Will be threadlocal/re-used - do not retain references.
+ */
+ QuadEmitter getEmitter();
+
+ /**
+ * Causes all models/quads/meshes sent to this consumer to be transformed by the provided
+ * {@link QuadTransform} that edits each quad before buffering. Quads in the mesh will
+ * be passed to the {@link QuadTransform} for modification before offsets, face culling or lighting are applied.
+ * Meant for animation and mesh customization.
+ *
+ * You MUST call {@link #popTransform()} after model is done outputting quads.
+ *
+ * More than one transformer can be added to the context. Transformers are applied in reverse order.
+ * (Last pushed is applied first.)
+ *
+ * Meshes are never mutated by the transformer - only buffered quads. This ensures thread-safe
+ * use of meshes/models across multiple chunk builders.
+ *
+ * Only the renderer should implement or extend this interface.
+ */
+ void pushTransform(QuadTransform transform);
+
+ /**
+ * Removes the transformation added by the last call to {@link #pushTransform(Consumer)}.
+ * MUST be called before exiting from {@link FabricBakedModel} .emit... methods.
+ */
+ void popTransform();
+
+ @FunctionalInterface
+ public static interface QuadTransform {
+ /**
+ * Return false to filter out quads from rendering. When more than one transform
+ * is in effect, returning false means unapplied transforms will not receive the quad.
+ */
+ boolean transform(MutableQuadView quad);
+ }
+}
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/render/TerrainBlockView.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/render/TerrainBlockView.java
new file mode 100644
index 0000000000..217639005a
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/api/render/TerrainBlockView.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.api.render;
+
+import net.fabricmc.fabric.renderer.v1.api.model.DynamicModelBlockEntity;
+import net.fabricmc.fabric.renderer.v1.api.model.FabricBakedModel;
+import net.minecraft.block.entity.BlockEntity;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.ExtendedBlockView;
+
+/**
+ * BlockView-extending interface to be used by {@link FabricBakedModel} for dynamic model
+ * customization. It ensures thread safety and exploits data cached in render
+ * chunks for performance and data consistency.
+ *
+ * There are differences from BlockView consumers must understand:
+ *
+ * BlockEntity implementations that provide data for model customization should implement
+ * {@link DynamicModelBlockEntity} which will be queried on the main thread when a render
+ * chunk is enqueued for rebuild. The model should retrieve the results via {@link #getCachedRenderData()}.
+ * While {@link #getBlockEntity(net.minecraft.util.math.BlockPos)} is not disabled, it
+ * is not thread-safe for use on render threads. Models that violate this guidance are
+ * responsible for any necessary synchronization or collision detection.
+ *
+ * {@link #getBlockState(net.minecraft.util.math.BlockPos)} and {@link #getFluidState(net.minecraft.util.math.BlockPos)}
+ * will always reflect the state cached with the render chunk. Block and fluid states
+ * can thus be different from main-thread world state due to lag between block update
+ * application from network packets and render chunk rebuilds. Use of {@link #getCachedRenderData()}
+ * will ensure consistency of model state with the rest of the chunk being rendered.
+ *
+ * Models should avoid using {@link ExtendedBlockView#getBlockEntity(BlockPos)}
+ * to ensure thread safety because this view may be accessed outside the main client thread.
+ * Models that require Block Entity data should implement {@link DynamicModelBlockEntity}
+ * and then use {@link #getCachedRenderData(BlockPos)} to retrieve it. When called from the
+ * main thread, that method will simply retrieve the data directly.
+ *
+ * This interface is only guaranteed to be present in the client environment.
+ */
+public interface TerrainBlockView extends ExtendedBlockView {
+ /**
+ * For models associated with Block Entities that implement {@link DynamicModelBlockEntity}
+ * this will be the most recent value provided by that implementation for the given block position.
+ *
+ * Null in all other cases, or if the result from the implementation was null.
+ *
+ * @param pos Position of the block for the block model.
+ */
+ default Object getCachedRenderData(BlockPos pos) {
+ BlockEntity be = this.getBlockEntity(pos);
+ return be == null ? null : ((DynamicModelBlockEntity)be).getDynamicModelData();
+ }
+}
\ No newline at end of file
diff --git a/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/impl/DamageModel.java b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/impl/DamageModel.java
new file mode 100644
index 0000000000..ee42e1466a
--- /dev/null
+++ b/fabric-renderer-v0/src/main/java/net/fabricmc/fabric/renderer/v1/impl/DamageModel.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.renderer.v1.impl;
+
+import java.util.Random;
+import java.util.function.Supplier;
+
+import net.fabricmc.fabric.renderer.v1.api.RendererAccess;
+import net.fabricmc.fabric.renderer.v1.api.material.RenderMaterial;
+import net.fabricmc.fabric.renderer.v1.api.mesh.MutableQuadView;
+import net.fabricmc.fabric.renderer.v1.api.model.FabricBakedModel;
+import net.fabricmc.fabric.renderer.v1.api.model.ForwardingBakedModel;
+import net.fabricmc.fabric.renderer.v1.api.render.RenderContext;
+import net.fabricmc.fabric.renderer.v1.api.render.TerrainBlockView;
+import net.fabricmc.fabric.renderer.v1.api.render.RenderContext.QuadTransform;
+import net.minecraft.block.BlockState;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.util.math.BlockPos;
+
+/**
+ * Specialized model wrapper that implements a general-purpose
+ * block-breaking render for enhanced models.
+ *
+ * Works by intercepting all model output and redirecting to dynamic
+ * quads that are baked with single-layer, UV-locked damage texture.
+ */
+public class DamageModel extends ForwardingBakedModel {
+ static final RenderMaterial DAMAGE_MATERIAL = RendererAccess.INSTANCE.hasRenderer() ? RendererAccess.INSTANCE.getRenderer().materialFinder().find() : null;
+
+ private DamageTransform damageTransform = new DamageTransform();
+
+ public void prepare(BakedModel wrappedModel, Sprite sprite, BlockState blockState, BlockPos blockPos) {
+ this.damageTransform.damageSprite = sprite;
+ this.wrapped = wrappedModel;
+ }
+
+ @Override
+ public void emitBlockQuads(TerrainBlockView blockView, BlockState state, BlockPos pos, Supplier