mirror of
https://github.com/FabricMC/fabric
synced 2026-08-19 06:26:07 -04:00
Finalize 1.21.5 FRAPI port and other improvements (#4650)
* Allow using sprite finder during model baking - Allow retrieving sprite finders from ErrorCollectingSpriteGetter, SpriteLoader.StitchResult, and SpriteAtlasManager.AtlasPreparation via new interface injections - Deprecate SpriteFinder.get in favor of interface injected method for consistency with other methods - Ensure lazily initialization of sprite finders is completely thread safe - Provide a default implementation for MutableQuadView/QuadEmitter.spriteBake - Improve some documentation * Add ModelBakeSettingsHelper - Respect passed ModelBakeSettings in testmod custom Geometry implementations - Add axis block state property to testmod octagonal column block and rotate model to test ModelBakeSettings application * Make AoCalculator.vanillaFullFace work regardless of vertex order - Use vertex map for cubic faces during enhanced light as well now that it works regardless of vertex order and is faster than using weights - Fix typos in AoFaceData * Finalization - Remove Experimental annotations - Deprecate Renderer.emitBlockModelPartQuads for removal - Fix GeometryBakedModel.emitQuads not applying instance AO boolean - Add RenderLayerHelper.movingDelegate/entityDelegate and use them where appropriate - Clarify some javadoc
This commit is contained in:
parent
39f4686e1f
commit
5281b90756
46 changed files with 952 additions and 189 deletions
|
|
@ -53,7 +53,7 @@ public class BakedModelFeatureRenderer<S extends LivingEntityRenderState, M exte
|
|||
matrices.scale(-0.75F, -0.75F, 0.75F);
|
||||
float aboveHead = (float) (Math.sin(state.age * 0.08F)) * 0.5F + 0.5F;
|
||||
matrices.translate(-0.5F, 0.75F + aboveHead, -0.5F);
|
||||
FabricBlockModelRenderer.render(matrices.peek(), layer -> vertexConsumers.getBuffer(RenderLayerHelper.getEntityBlockLayer(layer)), model, 1, 1, 1, light, OverlayTexture.DEFAULT_UV, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, Blocks.AIR.getDefaultState());
|
||||
FabricBlockModelRenderer.render(matrices.peek(), RenderLayerHelper.entityDelegate(vertexConsumers), model, 1, 1, 1, light, OverlayTexture.DEFAULT_UV, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, Blocks.AIR.getDefaultState());
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public interface Renderer {
|
|||
/**
|
||||
* @see FabricBlockModelPart#emitQuads(QuadEmitter, Predicate)
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@Deprecated(forRemoval = true)
|
||||
@ApiStatus.OverrideOnly
|
||||
default void emitBlockModelPartQuads(BlockModelPart modelPart, QuadEmitter emitter, Predicate<@Nullable Direction> cullTest) {
|
||||
VanillaBlockModelPartEncoder.emitQuads(modelPart, emitter, cullTest);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import net.minecraft.util.math.Direction;
|
|||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
import net.fabricmc.fabric.impl.renderer.QuadSpriteBaker;
|
||||
|
||||
/**
|
||||
* A mutable {@link QuadView} instance. The base interface for
|
||||
|
|
@ -41,46 +42,47 @@ import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
|||
*/
|
||||
public interface MutableQuadView extends QuadView {
|
||||
/**
|
||||
* Causes texture to appear with no rotation.
|
||||
* When enabled, causes texture to appear with no rotation. This is the default and does not have to be specified
|
||||
* explicitly. Can be overridden by other rotation flags.
|
||||
* Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}.
|
||||
*/
|
||||
int BAKE_ROTATE_NONE = 0;
|
||||
|
||||
/**
|
||||
* Causes texture to appear rotated 90 deg. clockwise relative to nominal face.
|
||||
* When enabled, causes texture to appear rotated 90 degrees clockwise.
|
||||
* Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}.
|
||||
*/
|
||||
int BAKE_ROTATE_90 = 1;
|
||||
|
||||
/**
|
||||
* Causes texture to appear rotated 180 deg. relative to nominal face.
|
||||
* When enabled, causes texture to appear rotated 180 degrees.
|
||||
* Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}.
|
||||
*/
|
||||
int BAKE_ROTATE_180 = 2;
|
||||
|
||||
/**
|
||||
* Causes texture to appear rotated 270 deg. clockwise relative to nominal face.
|
||||
* When enabled, causes texture to appear rotated 270 degrees clockwise.
|
||||
* Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}.
|
||||
*/
|
||||
int BAKE_ROTATE_270 = 3;
|
||||
|
||||
/**
|
||||
* When enabled, texture coordinate are assigned based on vertex position.
|
||||
* Any existing UV coordinates will be replaced.
|
||||
* When enabled, texture coordinates are assigned based on vertex positions and the
|
||||
* {@linkplain #nominalFace() nominal face}.
|
||||
* Any existing UV coordinates will be replaced and the {@link #BAKE_NORMALIZED} flag will be ignored.
|
||||
* Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}.
|
||||
*
|
||||
* <p>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.
|
||||
* <p>UV lock derives texture coordinates based on {@linkplain #nominalFace() nominal face} by projecting the quad
|
||||
* onto it, even when the quad is not co-planar with it. This flag is ignored if the normal face is {@code null}.
|
||||
*/
|
||||
int BAKE_LOCK_UV = 4;
|
||||
|
||||
/**
|
||||
* When set, U texture coordinates for the given sprite are
|
||||
* When enabled, 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 from what
|
||||
* can be obtained via rotation and both can be applied.
|
||||
* can be obtained via rotation and both can be applied. Any
|
||||
* rotation is applied before this flag.
|
||||
* Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}.
|
||||
*/
|
||||
int BAKE_FLIP_U = 8;
|
||||
|
|
@ -168,7 +170,10 @@ public interface MutableQuadView extends QuadView {
|
|||
* Can handle UV locking, rotation, interpolation, etc. Control this behavior
|
||||
* by passing additive combinations of the BAKE_ flags defined in this interface.
|
||||
*/
|
||||
MutableQuadView spriteBake(Sprite sprite, int bakeFlags);
|
||||
default MutableQuadView spriteBake(Sprite sprite, int bakeFlags) {
|
||||
QuadSpriteBaker.bakeSprite(this, sprite, bakeFlags);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept vanilla lightmap values. Input values will override lightmap values
|
||||
|
|
|
|||
|
|
@ -78,7 +78,10 @@ public interface QuadEmitter extends MutableQuadView {
|
|||
}
|
||||
|
||||
@Override
|
||||
QuadEmitter spriteBake(Sprite sprite, int bakeFlags);
|
||||
default QuadEmitter spriteBake(Sprite sprite, int bakeFlags) {
|
||||
MutableQuadView.super.spriteBake(sprite, bakeFlags);
|
||||
return this;
|
||||
}
|
||||
|
||||
default QuadEmitter uvUnitSquare() {
|
||||
uv(0, 0, 0);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package net.fabricmc.fabric.api.renderer.v1.model;
|
|||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
|
@ -32,15 +31,15 @@ import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on all block model parts via Mixin and interface injection.
|
||||
* Note: This interface is automatically implemented on {@link BlockModelPart} via Mixin and interface injection.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface FabricBlockModelPart {
|
||||
/**
|
||||
* Produces this model part's geometry. <b>This method must be called instead of
|
||||
* {@link BlockModelPart#getQuads(Direction)}; the vanilla method should be considered deprecated as it may not
|
||||
* produce accurate results.</b> However, it is acceptable for a custom model part to only implement the vanilla
|
||||
* method as the default implementation of this method will delegate to the vanilla method.
|
||||
* {@link BlockModelPart#getQuads(Direction)} and {@link BlockModelPart#useAmbientOcclusion()}; the vanilla methods
|
||||
* should be considered deprecated as they may not produce accurate results.</b> However, it is acceptable for a
|
||||
* custom model part to only implement the vanilla methods as the default implementation of this method will
|
||||
* delegate to the vanilla methods.
|
||||
*
|
||||
* <p>This method mainly exists for convenience when interacting with parts implemented and produced by vanilla
|
||||
* code. Custom models should generally override
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
|||
*
|
||||
* <p>Implementors should have a look at {@link ModelHelper} as it contains many useful functions.
|
||||
*
|
||||
* <p>Note: This interface is automatically implemented on all block state models via Mixin and interface injection.
|
||||
* <p>Note: This interface is automatically implemented on {@link BlockStateModel} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricBlockStateModel {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,21 +18,24 @@ package net.fabricmc.fabric.api.renderer.v1.model;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.client.render.model.BakedGeometry;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.Baker;
|
||||
import net.minecraft.client.render.model.Geometry;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.ModelTextures;
|
||||
import net.minecraft.client.render.model.SimpleModel;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||
|
||||
/**
|
||||
* A special {@link BakedGeometry} which hides a {@link Mesh} instead of using {@link BakedQuad}s. Instances of this
|
||||
* class always return empty lists from inherited methods.
|
||||
* A special {@link BakedGeometry} which hides a {@link Mesh} instead of using {@link BakedQuad}s. Useful for custom
|
||||
* implementations of {@link Geometry#bake(ModelTextures, Baker, ModelBakeSettings, SimpleModel)} that want to return a
|
||||
* mesh. Instances of this class always return empty lists from inherited methods.
|
||||
*
|
||||
* <p>Any code that interacts with {@link BakedGeometry} should first check {@code instanceof MeshBakedGeometry} and use
|
||||
* {@link #getMesh()} if {@code true} or the vanilla methods otherwise.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public final class MeshBakedGeometry extends BakedGeometry {
|
||||
private final Mesh mesh;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* 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.api.renderer.v1.model;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import net.minecraft.client.render.model.Geometry;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.ModelRotation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.AffineTransformation;
|
||||
import net.minecraft.util.math.AffineTransformations;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MatrixUtil;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadTransform;
|
||||
|
||||
/**
|
||||
* Utilities to make it easier to work with {@link ModelBakeSettings}.
|
||||
*/
|
||||
public final class ModelBakeSettingsHelper {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
|
||||
private ModelBakeSettingsHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ModelBakeSettings} using the given transformation and enables UV lock if specified. Works
|
||||
* exactly like {@link ModelRotation}, but allows an arbitrary transformation. Instances should be retained and
|
||||
* reused, especially if UV lock is enabled, to avoid redoing costly computations.
|
||||
*/
|
||||
public static ModelBakeSettings of(AffineTransformation transformation, boolean uvLock) {
|
||||
Matrix4fc matrix = transformation.getMatrix();
|
||||
|
||||
if (MatrixUtil.isIdentity(matrix)) {
|
||||
return ModelRotation.X0_Y0;
|
||||
}
|
||||
|
||||
if (!uvLock) {
|
||||
return new ModelBakeSettings() {
|
||||
@Override
|
||||
public AffineTransformation getRotation() {
|
||||
return transformation;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Map<Direction, Matrix4fc> faceTransformations = new EnumMap<>(Direction.class);
|
||||
Map<Direction, Matrix4fc> inverseFaceTransformations = new EnumMap<>(Direction.class);
|
||||
|
||||
for (Direction face : DIRECTIONS) {
|
||||
Matrix4fc faceTransformation = AffineTransformations.getTransformed(transformation, face).getMatrix();
|
||||
faceTransformations.put(face, faceTransformation);
|
||||
inverseFaceTransformations.put(face, faceTransformation.invert(new Matrix4f()));
|
||||
}
|
||||
|
||||
return new ModelBakeSettings() {
|
||||
@Override
|
||||
public AffineTransformation getRotation() {
|
||||
return transformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4fc forward(Direction face) {
|
||||
return faceTransformations.get(face);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4fc reverse(Direction face) {
|
||||
return inverseFaceTransformations.get(face);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ModelBakeSettings} that is the product of the two given settings. Settings are represented
|
||||
* by matrices, so this method follows the rules of matrix multiplication, namely that applying the resulting
|
||||
* settings is (mostly) equivalent to applying the right settings and then the left settings. The only exception
|
||||
* during standard application is cull face transformation, as the result must be clamped. Thus, applying a single
|
||||
* premultiplied transformation generally yields better results than multiple applications.
|
||||
*/
|
||||
public static ModelBakeSettings multiply(ModelBakeSettings left, ModelBakeSettings right) {
|
||||
// Assumes face transformations are identity if main transformation is identity
|
||||
if (MatrixUtil.isIdentity(left.getRotation().getMatrix())) {
|
||||
return right;
|
||||
} else if (MatrixUtil.isIdentity(right.getRotation().getMatrix())) {
|
||||
return left;
|
||||
}
|
||||
|
||||
AffineTransformation transformation = left.getRotation().multiply(right.getRotation());
|
||||
|
||||
boolean leftHasFaceTransformations = false;
|
||||
boolean rightHasFaceTransformations = false;
|
||||
|
||||
// Assumes inverse face transformations are exactly inverse of regular face transformations
|
||||
for (Direction face : DIRECTIONS) {
|
||||
if (!leftHasFaceTransformations && !MatrixUtil.isIdentity(left.forward(face))) {
|
||||
leftHasFaceTransformations = true;
|
||||
}
|
||||
|
||||
if (!rightHasFaceTransformations && !MatrixUtil.isIdentity(right.forward(face))) {
|
||||
rightHasFaceTransformations = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (leftHasFaceTransformations & rightHasFaceTransformations) {
|
||||
Map<Direction, Matrix4fc> faceTransformations = new EnumMap<>(Direction.class);
|
||||
Map<Direction, Matrix4fc> inverseFaceTransformations = new EnumMap<>(Direction.class);
|
||||
|
||||
for (Direction face : DIRECTIONS) {
|
||||
faceTransformations.put(face, left.forward(face).mul(right.forward(face), new Matrix4f()));
|
||||
inverseFaceTransformations.put(face, right.reverse(face).mul(left.reverse(face), new Matrix4f()));
|
||||
}
|
||||
|
||||
return new ModelBakeSettings() {
|
||||
@Override
|
||||
public AffineTransformation getRotation() {
|
||||
return transformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4fc forward(Direction face) {
|
||||
return faceTransformations.get(face);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4fc reverse(Direction face) {
|
||||
return inverseFaceTransformations.get(face);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ModelBakeSettings faceTransformDelegate = leftHasFaceTransformations ? left : right;
|
||||
|
||||
return new ModelBakeSettings() {
|
||||
@Override
|
||||
public AffineTransformation getRotation() {
|
||||
return transformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4fc forward(Direction face) {
|
||||
return faceTransformDelegate.forward(face);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4fc reverse(Direction face) {
|
||||
return faceTransformDelegate.reverse(face);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link QuadTransform} that applies the given transformation. The sprite finder is used to look up
|
||||
* the current sprite to correctly apply UV lock, if present in the transformation.
|
||||
*
|
||||
* <p>This method is most useful when creating custom implementations of {@link Geometry}, which receive a
|
||||
* {@link ModelBakeSettings}.
|
||||
*/
|
||||
public static QuadTransform asQuadTransform(ModelBakeSettings settings, SpriteFinder spriteFinder) {
|
||||
Matrix4fc matrix = settings.getRotation().getMatrix();
|
||||
|
||||
// Assumes face transformations are identity if main transformation is identity
|
||||
if (MatrixUtil.isIdentity(matrix)) {
|
||||
return q -> true;
|
||||
}
|
||||
|
||||
Matrix3f normalMatrix = matrix.normal(new Matrix3f());
|
||||
|
||||
Vector4f vec4 = new Vector4f();
|
||||
Vector3f vec3 = new Vector3f();
|
||||
|
||||
return quad -> {
|
||||
Direction lightFace = quad.lightFace();
|
||||
Matrix4fc reverseMatrix = settings.reverse(lightFace);
|
||||
|
||||
if (!MatrixUtil.isIdentity(reverseMatrix)) {
|
||||
Sprite sprite = spriteFinder.find(quad);
|
||||
|
||||
for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++) {
|
||||
float frameU = sprite.getFrameFromU(quad.u(vertexIndex));
|
||||
float frameV = sprite.getFrameFromV(quad.v(vertexIndex));
|
||||
vec3.set(frameU - 0.5f, frameV - 0.5f, 0.0f);
|
||||
reverseMatrix.transformPosition(vec3);
|
||||
frameU = vec3.x + 0.5f;
|
||||
frameV = vec3.y + 0.5f;
|
||||
quad.uv(vertexIndex, sprite.getFrameU(frameU), sprite.getFrameV(frameV));
|
||||
}
|
||||
}
|
||||
|
||||
for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++) {
|
||||
vec4.set(quad.x(vertexIndex) - 0.5f, quad.y(vertexIndex) - 0.5f, quad.z(vertexIndex) - 0.5f, 1.0f);
|
||||
vec4.mul(matrix);
|
||||
quad.pos(vertexIndex, vec4.x + 0.5f, vec4.y + 0.5f, vec4.z + 0.5f);
|
||||
|
||||
if (quad.hasNormal(vertexIndex)) {
|
||||
quad.copyNormal(vertexIndex, vec3);
|
||||
vec3.mul(normalMatrix);
|
||||
vec3.normalize();
|
||||
quad.normal(vertexIndex, vec3);
|
||||
}
|
||||
}
|
||||
|
||||
Direction cullFace = quad.cullFace();
|
||||
|
||||
if (cullFace != null) {
|
||||
quad.cullFace(Direction.transform(matrix, cullFace));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ public final class ModelHelper {
|
|||
* <p>Retrieves sprites from the block texture atlas via {@link SpriteFinder}.
|
||||
*/
|
||||
public static List<BakedQuad>[] toQuadLists(Mesh mesh) {
|
||||
SpriteFinder finder = SpriteFinder.get(MinecraftClient.getInstance().getBakedModelManager().getAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE));
|
||||
SpriteFinder finder = MinecraftClient.getInstance().getBakedModelManager().getAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).spriteFinder();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final ImmutableList.Builder<BakedQuad>[] builders = new ImmutableList.Builder[7];
|
||||
|
|
@ -80,12 +80,10 @@ public final class ModelHelper {
|
|||
builders[i] = ImmutableList.builder();
|
||||
}
|
||||
|
||||
if (mesh != null) {
|
||||
mesh.forEach(q -> {
|
||||
Direction cullFace = q.cullFace();
|
||||
builders[cullFace == null ? NULL_FACE_ID : cullFace.getIndex()].add(q.toBakedQuad(finder.find(q)));
|
||||
});
|
||||
}
|
||||
mesh.forEach(q -> {
|
||||
Direction cullFace = q.cullFace();
|
||||
builders[cullFace == null ? NULL_FACE_ID : cullFace.getIndex()].add(q.toBakedQuad(finder.find(q)));
|
||||
});
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<BakedQuad>[] result = new List[7];
|
||||
|
|
|
|||
|
|
@ -16,35 +16,42 @@
|
|||
|
||||
package net.fabricmc.fabric.api.renderer.v1.model;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.ErrorCollectingSpriteGetter;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||
import net.fabricmc.fabric.impl.renderer.SpriteFinderImpl;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricAtlasPreparation;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricErrorCollectingSpriteGetter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricSpriteAtlasTexture;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricStitchResult;
|
||||
|
||||
/**
|
||||
* Indexes a texture atlas to allow fast lookup of Sprites from
|
||||
* baked vertex coordinates. Main use is for {@link Mesh}-based models
|
||||
* to generate vanilla quads on demand without tracking and retaining
|
||||
* the sprites that were baked into the mesh. In other words, this class
|
||||
* supplies the sprite parameter for {@link QuadView#toBakedQuad(Sprite)}.
|
||||
* Indexes a texture atlas to allow fast lookup of {@link Sprite}s from baked texture coordinates.
|
||||
*
|
||||
* <p>Example use cases include interpolating the textures of a submodel's quads in
|
||||
* {@link FabricBlockStateModel#emitQuads(QuadEmitter, BlockRenderView, BlockPos, BlockState, Random, Predicate)} or
|
||||
* finding the sprite for use in {@link QuadView#toBakedQuad(Sprite)}.
|
||||
*
|
||||
* <p>A sprite finder can be retrieved from various vanilla objects. Always use
|
||||
* {@link FabricErrorCollectingSpriteGetter#spriteFinder(Identifier)}, {@link FabricStitchResult#spriteFinder()}, or
|
||||
* {@link FabricAtlasPreparation#spriteFinder()} whenever an applicable instance is available. For example, model
|
||||
* baking is supplied with a {@link ErrorCollectingSpriteGetter}, so it should be used to retrieve the sprite finder.
|
||||
* In most other cases, it is safe to use {@link FabricSpriteAtlasTexture#spriteFinder()}.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
public interface SpriteFinder {
|
||||
/**
|
||||
* Retrieves or creates the finder for the given atlas.
|
||||
* Instances should not be retained as fields, or they must be
|
||||
* refreshed whenever there is a resource reload or other event
|
||||
* that causes atlas textures to be re-stitched.
|
||||
*/
|
||||
static SpriteFinder get(SpriteAtlasTexture atlas) {
|
||||
return SpriteFinderImpl.get(atlas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the atlas sprite containing the vertex centroid of the quad.
|
||||
* Vertex centroid is essentially the mean u,v coordinate - the intent being
|
||||
|
|
@ -69,6 +76,14 @@ public interface SpriteFinder {
|
|||
*/
|
||||
Sprite find(float u, float v);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FabricSpriteAtlasTexture#spriteFinder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
static SpriteFinder get(SpriteAtlasTexture atlas) {
|
||||
return atlas.spriteFinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #find(QuadView)} instead.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on all block model renderers via Mixin and interface injection.
|
||||
* Note: This interface is automatically implemented on {@link BlockModelRenderer} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricBlockModelRenderer {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on all block render managers via Mixin and interface injection.
|
||||
* Note: This interface is automatically implemented on {@link BlockRenderManager} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricBlockRenderManager {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on all layer render states via Mixin and interface injection.
|
||||
* Note: This interface is automatically implemented on {@link ItemRenderState.LayerRenderState} via Mixin and interface
|
||||
* injection.
|
||||
*/
|
||||
public interface FabricLayerRenderState {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import net.minecraft.block.BlockState;
|
|||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.RenderLayers;
|
||||
import net.minecraft.client.render.TexturedRenderLayers;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
|
||||
public final class RenderLayerHelper {
|
||||
private RenderLayerHelper() {
|
||||
|
|
@ -40,4 +41,20 @@ public final class RenderLayerHelper {
|
|||
public static RenderLayer getEntityBlockLayer(RenderLayer chunkRenderLayer) {
|
||||
return chunkRenderLayer == RenderLayer.getTranslucent() ? TexturedRenderLayers.getItemEntityTranslucentCull() : TexturedRenderLayers.getEntityCutout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given provider, converting {@linkplain RenderLayer#getBlockLayers() block layers} to render layers
|
||||
* using {@link #getMovingBlockLayer(RenderLayer)}.
|
||||
*/
|
||||
public static VertexConsumerProvider movingDelegate(VertexConsumerProvider vertexConsumers) {
|
||||
return chunkRenderLayer -> vertexConsumers.getBuffer(RenderLayerHelper.getMovingBlockLayer(chunkRenderLayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given provider, converting {@linkplain RenderLayer#getBlockLayers() block layers} to render layers
|
||||
* using {@link #getEntityBlockLayer(RenderLayer)}.
|
||||
*/
|
||||
public static VertexConsumerProvider entityDelegate(VertexConsumerProvider vertexConsumers) {
|
||||
return chunkRenderLayer -> vertexConsumers.getBuffer(RenderLayerHelper.getEntityBlockLayer(chunkRenderLayer));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.api.renderer.v1.sprite;
|
||||
|
||||
import net.minecraft.client.render.model.SpriteAtlasManager;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on {@link SpriteAtlasManager.AtlasPreparation} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricAtlasPreparation {
|
||||
/**
|
||||
* {@return the sprite finder for this atlas preparation}
|
||||
*/
|
||||
default SpriteFinder spriteFinder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.api.renderer.v1.sprite;
|
||||
|
||||
import net.minecraft.client.render.model.ErrorCollectingSpriteGetter;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on {@link ErrorCollectingSpriteGetter} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricErrorCollectingSpriteGetter {
|
||||
/**
|
||||
* {@return the sprite finder for the given atlas ID}
|
||||
*/
|
||||
default SpriteFinder spriteFinder(Identifier atlasId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.api.renderer.v1.sprite;
|
||||
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.texture.SpriteLoader;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on {@link SpriteAtlasTexture} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricSpriteAtlasTexture {
|
||||
/**
|
||||
* Retrieves the sprite finder for this atlas. The returned instance is only valid until the next call to
|
||||
* {@link SpriteAtlasTexture#upload(SpriteLoader.StitchResult)}, and thus should not be persisted across resource
|
||||
* reloads.
|
||||
*
|
||||
* <p><b>This method should not be used during a resource reload</b> as this atlas will only be populated with new
|
||||
* sprites towards the end of the resource reload. In this case, use
|
||||
* {@link FabricErrorCollectingSpriteGetter#spriteFinder(Identifier)}, {@link FabricStitchResult#spriteFinder()},
|
||||
* or {@link FabricAtlasPreparation#spriteFinder()} instead.
|
||||
*
|
||||
* @return the sprite finder for this atlas
|
||||
*/
|
||||
default SpriteFinder spriteFinder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.api.renderer.v1.sprite;
|
||||
|
||||
import net.minecraft.client.texture.SpriteLoader;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
|
||||
/**
|
||||
* Note: This interface is automatically implemented on {@link SpriteLoader.StitchResult} via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricStitchResult {
|
||||
/**
|
||||
* {@return the sprite finder for this stitch result}
|
||||
*/
|
||||
default SpriteFinder spriteFinder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.indigo.renderer.helper;
|
||||
package net.fabricmc.fabric.impl.renderer;
|
||||
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
|
@ -23,11 +23,10 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
|||
|
||||
/**
|
||||
* Handles most texture-baking use cases for model loaders and model libraries
|
||||
* via {@link #bakeSprite(MutableQuadView, Sprite, int)}. Also used by the API
|
||||
* itself to implement automatic block-breaking models for enhanced models.
|
||||
* via {@link #bakeSprite(MutableQuadView, Sprite, int)}.
|
||||
*/
|
||||
public final class TextureHelper {
|
||||
private TextureHelper() { }
|
||||
public final class QuadSpriteBaker {
|
||||
private QuadSpriteBaker() { }
|
||||
|
||||
private static final float NORMALIZER = 1f / 16f;
|
||||
|
||||
|
|
@ -101,11 +100,11 @@ public final class TextureHelper {
|
|||
private static final VertexModifier[] UVLOCKERS = new VertexModifier[6];
|
||||
|
||||
static {
|
||||
UVLOCKERS[Direction.EAST.getIndex()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.WEST.getIndex()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.NORTH.getIndex()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.SOUTH.getIndex()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.DOWN.getIndex()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i));
|
||||
UVLOCKERS[Direction.UP.getIndex()] = (q, i) -> q.uv(i, q.x(i), q.z(i));
|
||||
UVLOCKERS[Direction.NORTH.getIndex()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.SOUTH.getIndex()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.WEST.getIndex()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i));
|
||||
UVLOCKERS[Direction.EAST.getIndex()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i));
|
||||
}
|
||||
}
|
||||
|
|
@ -17,14 +17,12 @@
|
|||
package net.fabricmc.fabric.impl.renderer;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.client.texture.MissingSprite;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||
|
|
@ -43,12 +41,12 @@ public class SpriteFinderImpl implements SpriteFinder {
|
|||
private static final Logger LOGGER = LoggerFactory.getLogger(SpriteFinderImpl.class);
|
||||
|
||||
private final Node root;
|
||||
private final SpriteAtlasTexture spriteAtlasTexture;
|
||||
private final Sprite missingSprite;
|
||||
private int badSpriteCount = 0;
|
||||
|
||||
public SpriteFinderImpl(Map<Identifier, Sprite> sprites, SpriteAtlasTexture spriteAtlasTexture) {
|
||||
public SpriteFinderImpl(Map<Identifier, Sprite> sprites, Sprite missingSprite) {
|
||||
root = new Node(0.5f, 0.5f, 0.25f);
|
||||
this.spriteAtlasTexture = spriteAtlasTexture;
|
||||
this.missingSprite = missingSprite;
|
||||
sprites.values().forEach(root::add);
|
||||
}
|
||||
|
||||
|
|
@ -74,9 +72,14 @@ public class SpriteFinderImpl implements SpriteFinder {
|
|||
final float midU;
|
||||
final float midV;
|
||||
final float cellRadius;
|
||||
|
||||
@Nullable
|
||||
Object lowLow = null;
|
||||
@Nullable
|
||||
Object lowHigh = null;
|
||||
@Nullable
|
||||
Object highLow = null;
|
||||
@Nullable
|
||||
Object highHigh = null;
|
||||
|
||||
Node(float midU, float midV, float radius) {
|
||||
|
|
@ -105,36 +108,37 @@ public class SpriteFinderImpl implements SpriteFinder {
|
|||
final boolean highV = sprite.getMaxV() > midV + EPS;
|
||||
|
||||
if (lowU && lowV) {
|
||||
addInner(sprite, lowLow, -1, -1, q -> lowLow = q);
|
||||
lowLow = addInner(sprite, lowLow, -1, -1);
|
||||
}
|
||||
|
||||
if (lowU && highV) {
|
||||
addInner(sprite, lowHigh, -1, 1, q -> lowHigh = q);
|
||||
lowHigh = addInner(sprite, lowHigh, -1, 1);
|
||||
}
|
||||
|
||||
if (highU && lowV) {
|
||||
addInner(sprite, highLow, 1, -1, q -> highLow = q);
|
||||
highLow = addInner(sprite, highLow, 1, -1);
|
||||
}
|
||||
|
||||
if (highU && highV) {
|
||||
addInner(sprite, highHigh, 1, 1, q -> highHigh = q);
|
||||
highHigh = addInner(sprite, highHigh, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void addInner(Sprite sprite, Object quadrant, int uStep, int vStep, Consumer<Object> setter) {
|
||||
private Object addInner(Sprite sprite, @Nullable Object quadrant, int uStep, int vStep) {
|
||||
if (quadrant == null) {
|
||||
setter.accept(sprite);
|
||||
} else if (quadrant instanceof Node) {
|
||||
((Node) quadrant).add(sprite);
|
||||
return sprite;
|
||||
} else if (quadrant instanceof Node node) {
|
||||
node.add(sprite);
|
||||
return quadrant;
|
||||
} else {
|
||||
Node n = new Node(midU + cellRadius * uStep, midV + cellRadius * vStep, cellRadius * 0.5f);
|
||||
|
||||
if (quadrant instanceof Sprite) {
|
||||
n.add((Sprite) quadrant);
|
||||
if (quadrant instanceof Sprite prevSprite) {
|
||||
n.add(prevSprite);
|
||||
}
|
||||
|
||||
n.add(sprite);
|
||||
setter.accept(n);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,22 +150,14 @@ public class SpriteFinderImpl implements SpriteFinder {
|
|||
}
|
||||
}
|
||||
|
||||
private Sprite findInner(Object quadrant, float u, float v) {
|
||||
if (quadrant instanceof Sprite) {
|
||||
return (Sprite) quadrant;
|
||||
} else if (quadrant instanceof Node) {
|
||||
return ((Node) quadrant).find(u, v);
|
||||
private Sprite findInner(@Nullable Object quadrant, float u, float v) {
|
||||
if (quadrant instanceof Node node) {
|
||||
return node.find(u, v);
|
||||
} else if (quadrant instanceof Sprite sprite) {
|
||||
return sprite;
|
||||
} else {
|
||||
return spriteAtlasTexture.getSprite(MissingSprite.getMissingSpriteId());
|
||||
return missingSprite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SpriteFinderImpl get(SpriteAtlasTexture atlas) {
|
||||
return ((SpriteFinderAccess) atlas).fabric_spriteFinder();
|
||||
}
|
||||
|
||||
public interface SpriteFinderAccess {
|
||||
SpriteFinderImpl fabric_spriteFinder();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.impl.renderer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
|
||||
public interface StitchResultExtension {
|
||||
@Nullable
|
||||
SpriteFinder fabric_spriteFinderNullable();
|
||||
}
|
||||
|
|
@ -28,19 +28,43 @@ import net.minecraft.client.render.model.BlockModelPart;
|
|||
import net.minecraft.client.render.model.GeometryBakedModel;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.MeshBakedGeometry;
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
|
||||
@Mixin(GeometryBakedModel.class)
|
||||
abstract class GeometryBakedModelMixin implements BlockModelPart {
|
||||
@Shadow
|
||||
@Final
|
||||
private BakedGeometry quads;
|
||||
@Shadow
|
||||
@Final
|
||||
private boolean useAmbientOcclusion;
|
||||
|
||||
@Override
|
||||
public void emitQuads(QuadEmitter emitter, Predicate<@Nullable Direction> cullTest) {
|
||||
if (quads instanceof MeshBakedGeometry meshBakedGeometry) {
|
||||
meshBakedGeometry.getMesh().outputTo(emitter);
|
||||
if (useAmbientOcclusion) {
|
||||
meshBakedGeometry.getMesh().outputTo(emitter);
|
||||
} else {
|
||||
MaterialFinder materialFinder = Renderer.get().materialFinder();
|
||||
emitter.pushTransform(quad -> {
|
||||
RenderMaterial material = quad.material();
|
||||
|
||||
if (material.ambientOcclusion() == TriState.DEFAULT) {
|
||||
materialFinder.copyFrom(quad.material());
|
||||
materialFinder.ambientOcclusion(TriState.FALSE);
|
||||
quad.material(materialFinder.find());
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
meshBakedGeometry.getMesh().outputTo(emitter);
|
||||
emitter.popTransform();
|
||||
}
|
||||
} else {
|
||||
BlockModelPart.super.emitQuads(emitter, cullTest);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ abstract class FallingBlockEntityRendererMixin extends EntityRenderer<FallingBlo
|
|||
|
||||
BlockStateModel model = blockRenderManager.getModel(blockState);
|
||||
long seed = blockState.getRenderingSeed(renderState.fallingBlockPos);
|
||||
blockRenderManager.getModelRenderer().render(renderState, model, blockState, renderState.currentPos, matrixStack, layer -> vertexConsumers.getBuffer(RenderLayerHelper.getMovingBlockLayer(layer)), false, seed, OverlayTexture.DEFAULT_UV);
|
||||
blockRenderManager.getModelRenderer().render(renderState, model, blockState, renderState.currentPos, matrixStack, RenderLayerHelper.movingDelegate(vertexConsumers), false, seed, OverlayTexture.DEFAULT_UV);
|
||||
|
||||
matrixStack.pop();
|
||||
super.render(renderState, matrixStack, vertexConsumers, light);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,6 @@ abstract class PistonBlockEntityRendererMixin {
|
|||
// Support multi-render layer models.
|
||||
@Overwrite
|
||||
private void renderModel(BlockPos pos, BlockState state, MatrixStack matrices, VertexConsumerProvider vertexConsumers, World world, boolean cull, int overlay) {
|
||||
manager.getModelRenderer().render(world, manager.getModel(state), state, pos, matrices, layer -> vertexConsumers.getBuffer(RenderLayerHelper.getMovingBlockLayer(layer)), cull, state.getRenderingSeed(pos), overlay);
|
||||
manager.getModelRenderer().render(world, manager.getModel(state), state, pos, matrices, RenderLayerHelper.movingDelegate(vertexConsumers), cull, state.getRenderingSeed(pos), overlay);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ abstract class SnowGolemPumpkinFeatureRendererMixin {
|
|||
FabricBlockModelRenderer.render(entry, layer -> vertexConsumer, model, 1, 1, 1, light, overlay, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, blockState);
|
||||
} else {
|
||||
// Support multi-render layer models, fix tinted quads being rendered completely black, and provide the BlockState as context.
|
||||
FabricBlockModelRenderer.render(entry, layer -> vertexConsumers.getBuffer(RenderLayerHelper.getEntityBlockLayer(layer)), model, 1, 1, 1, light, overlay, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, blockState);
|
||||
FabricBlockModelRenderer.render(entry, RenderLayerHelper.entityDelegate(vertexConsumers), model, 1, 1, 1, light, overlay, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, blockState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import net.minecraft.client.render.item.model.BasicItemModel;
|
|||
import net.minecraft.client.render.item.model.ItemModel;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.FabricLayerRenderState;
|
||||
import net.fabricmc.fabric.impl.renderer.BasicItemModelExtension;
|
||||
|
||||
@Mixin(BasicItemModel.class)
|
||||
|
|
@ -41,7 +40,7 @@ abstract class BasicItemModelMixin implements ItemModel, BasicItemModelExtension
|
|||
@Inject(method = "update", at = @At("RETURN"))
|
||||
private void onReturnUpdate(CallbackInfo ci, @Local ItemRenderState.LayerRenderState layer) {
|
||||
if (mesh != null) {
|
||||
mesh.outputTo(((FabricLayerRenderState) layer).emitter());
|
||||
mesh.outputTo(layer.emitter());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.mixin.renderer.client.sprite;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import net.minecraft.client.render.model.ErrorCollectingSpriteGetter;
|
||||
import net.minecraft.client.render.model.SpriteAtlasManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
|
||||
@Mixin(targets = "net/minecraft/client/render/model/BakedModelManager$1")
|
||||
abstract class BakedModelManager1Mixin implements ErrorCollectingSpriteGetter {
|
||||
@Shadow
|
||||
@Final
|
||||
Map<Identifier, SpriteAtlasManager.AtlasPreparation> field_55477;
|
||||
|
||||
@Override
|
||||
public SpriteFinder spriteFinder(Identifier atlasId) {
|
||||
return field_55477.get(atlasId).spriteFinder();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.mixin.renderer.client.sprite;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import net.minecraft.client.render.model.ErrorCollectingSpriteGetter;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricErrorCollectingSpriteGetter;
|
||||
|
||||
@Mixin(ErrorCollectingSpriteGetter.class)
|
||||
interface ErrorCollectingSpriteGetterMixin extends FabricErrorCollectingSpriteGetter {
|
||||
}
|
||||
|
|
@ -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.mixin.renderer.client.sprite;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import net.minecraft.client.render.model.SpriteAtlasManager;
|
||||
import net.minecraft.client.texture.SpriteLoader;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricAtlasPreparation;
|
||||
|
||||
@Mixin(SpriteAtlasManager.AtlasPreparation.class)
|
||||
abstract class SpriteAtlasManagerAtlasPreparationMixin implements FabricAtlasPreparation {
|
||||
@Shadow
|
||||
@Final
|
||||
private SpriteLoader.StitchResult stitchResult;
|
||||
|
||||
@Override
|
||||
public SpriteFinder spriteFinder() {
|
||||
return stitchResult.spriteFinder();
|
||||
}
|
||||
}
|
||||
|
|
@ -14,13 +14,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.renderer.client;
|
||||
package net.fabricmc.fabric.mixin.renderer.client.sprite;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
|
@ -30,28 +32,48 @@ import net.minecraft.client.texture.SpriteAtlasTexture;
|
|||
import net.minecraft.client.texture.SpriteLoader;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricSpriteAtlasTexture;
|
||||
import net.fabricmc.fabric.impl.renderer.SpriteFinderImpl;
|
||||
import net.fabricmc.fabric.impl.renderer.StitchResultExtension;
|
||||
|
||||
@Mixin(SpriteAtlasTexture.class)
|
||||
public class SpriteAtlasTextureMixin implements SpriteFinderImpl.SpriteFinderAccess {
|
||||
@Final
|
||||
abstract class SpriteAtlasTextureMixin implements FabricSpriteAtlasTexture {
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<Identifier, Sprite> sprites;
|
||||
@Shadow
|
||||
@Final
|
||||
@Nullable
|
||||
private Sprite missingSprite;
|
||||
|
||||
private SpriteFinderImpl fabric_spriteFinder = null;
|
||||
@Unique
|
||||
@Nullable
|
||||
private volatile SpriteFinder spriteFinder;
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "upload")
|
||||
private void uploadHook(SpriteLoader.StitchResult arg, CallbackInfo ci) {
|
||||
fabric_spriteFinder = null;
|
||||
private void uploadHook(SpriteLoader.StitchResult stitchResult, CallbackInfo ci) {
|
||||
// Clear this atlas' old finder. If the finder was already initialized in the stitch result, reuse it for this
|
||||
// atlas.
|
||||
spriteFinder = ((StitchResultExtension) (Object) stitchResult).fabric_spriteFinderNullable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpriteFinderImpl fabric_spriteFinder() {
|
||||
SpriteFinderImpl result = fabric_spriteFinder;
|
||||
public SpriteFinder spriteFinder() {
|
||||
SpriteFinder result = spriteFinder;
|
||||
|
||||
if (result == null) {
|
||||
result = new SpriteFinderImpl(sprites, (SpriteAtlasTexture) (Object) this);
|
||||
fabric_spriteFinder = result;
|
||||
synchronized (this) {
|
||||
result = spriteFinder;
|
||||
|
||||
if (result == null) {
|
||||
if (missingSprite == null) {
|
||||
throw new IllegalStateException("Tried to create sprite finder, but atlas is not initialized");
|
||||
}
|
||||
|
||||
spriteFinder = result = new SpriteFinderImpl(sprites, missingSprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -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.mixin.renderer.client.sprite;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteLoader;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.sprite.FabricStitchResult;
|
||||
import net.fabricmc.fabric.impl.renderer.SpriteFinderImpl;
|
||||
import net.fabricmc.fabric.impl.renderer.StitchResultExtension;
|
||||
|
||||
@Mixin(SpriteLoader.StitchResult.class)
|
||||
abstract class SpriteLoaderStitchResultMixin implements FabricStitchResult, StitchResultExtension {
|
||||
@Shadow
|
||||
@Final
|
||||
private Sprite missing;
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<Identifier, Sprite> regions;
|
||||
|
||||
@Unique
|
||||
@Nullable
|
||||
private volatile SpriteFinder spriteFinder;
|
||||
|
||||
@Override
|
||||
public SpriteFinder spriteFinder() {
|
||||
SpriteFinder result = spriteFinder;
|
||||
|
||||
if (result == null) {
|
||||
synchronized (this) {
|
||||
result = spriteFinder;
|
||||
|
||||
if (result == null) {
|
||||
spriteFinder = result = new SpriteFinderImpl(regions, missing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SpriteFinder fabric_spriteFinderNullable() {
|
||||
return spriteFinder;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
"package": "net.fabricmc.fabric.mixin.renderer",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"client.SpriteAtlasTextureMixin",
|
||||
"client.block.model.BlockModelPartMixin",
|
||||
"client.block.model.BlockStateModelMixin",
|
||||
"client.block.model.GeometryBakedModelMixin",
|
||||
|
|
@ -24,7 +23,12 @@
|
|||
"client.block.render.SnowGolemPumpkinFeatureRendererMixin",
|
||||
"client.item.BasicItemModelMixin",
|
||||
"client.item.BasicItemModelUnbakedMixin",
|
||||
"client.item.ItemRenderStateLayerRenderStateMixin"
|
||||
"client.item.ItemRenderStateLayerRenderStateMixin",
|
||||
"client.sprite.BakedModelManager1Mixin",
|
||||
"client.sprite.ErrorCollectingSpriteGetterMixin",
|
||||
"client.sprite.SpriteAtlasManagerAtlasPreparationMixin",
|
||||
"client.sprite.SpriteAtlasTextureMixin",
|
||||
"client.sprite.SpriteLoaderStitchResultMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
|||
|
|
@ -37,7 +37,11 @@
|
|||
"net/minecraft/class_1087": ["net/fabricmc/fabric/api/renderer/v1/model/FabricBlockStateModel"],
|
||||
"net/minecraft/class_778": ["net/fabricmc/fabric/api/renderer/v1/render/FabricBlockModelRenderer"],
|
||||
"net/minecraft/class_776": ["net/fabricmc/fabric/api/renderer/v1/render/FabricBlockRenderManager"],
|
||||
"net/minecraft/class_10444\u0024class_10446": ["net/fabricmc/fabric/api/renderer/v1/render/FabricLayerRenderState"]
|
||||
"net/minecraft/class_10444\u0024class_10446": ["net/fabricmc/fabric/api/renderer/v1/render/FabricLayerRenderState"],
|
||||
"net/minecraft/class_4724\u0024class_7774": ["net/fabricmc/fabric/api/renderer/v1/sprite/FabricAtlasPreparation"],
|
||||
"net/minecraft/class_9826": ["net/fabricmc/fabric/api/renderer/v1/sprite/FabricErrorCollectingSpriteGetter"],
|
||||
"net/minecraft/class_1059": ["net/fabricmc/fabric/api/renderer/v1/sprite/FabricSpriteAtlasTexture"],
|
||||
"net/minecraft/class_7766\u0024class_7767": ["net/fabricmc/fabric/api/renderer/v1/sprite/FabricStitchResult"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@ package net.fabricmc.fabric.test.renderer;
|
|||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.PillarBlock;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.BooleanProperty;
|
||||
|
||||
public class OctagonalColumnBlock extends Block {
|
||||
public class OctagonalColumnBlock extends PillarBlock {
|
||||
public static final BooleanProperty VANILLA_SHADE_MODE = BooleanProperty.of("vanilla_shade_mode");
|
||||
|
||||
public OctagonalColumnBlock(Settings settings) {
|
||||
|
|
@ -31,6 +32,7 @@ public class OctagonalColumnBlock extends Block {
|
|||
|
||||
@Override
|
||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||
super.appendProperties(builder);
|
||||
builder.add(VANILLA_SHADE_MODE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import net.minecraft.client.render.model.ModelBakeSettings;
|
|||
import net.minecraft.client.render.model.ModelTextures;
|
||||
import net.minecraft.client.render.model.SimpleModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
|
|
@ -32,12 +33,14 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.MutableMesh;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.MeshBakedGeometry;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelBakeSettingsHelper;
|
||||
|
||||
public record FrameGeometry(boolean emissive) implements Geometry {
|
||||
@Override
|
||||
public BakedGeometry bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, SimpleModel model) {
|
||||
MutableMesh builder = Renderer.get().mutableMesh();
|
||||
QuadEmitter emitter = builder.emitter();
|
||||
emitter.pushTransform(ModelBakeSettingsHelper.asQuadTransform(settings, baker.getSpriteGetter().spriteFinder(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)));
|
||||
|
||||
MaterialFinder finder = Renderer.get().materialFinder();
|
||||
RenderMaterial material = finder.emissive(emissive).find();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import net.minecraft.client.render.model.ModelBakeSettings;
|
|||
import net.minecraft.client.render.model.ModelTextures;
|
||||
import net.minecraft.client.render.model.SimpleModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
|
|
@ -34,6 +35,7 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.MutableMesh;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.MeshBakedGeometry;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelBakeSettingsHelper;
|
||||
|
||||
public record OctagonalColumnGeometry(ShadeMode shadeMode) implements Geometry {
|
||||
// (B - A) is the side length of a regular octagon that fits in a unit square.
|
||||
|
|
@ -45,6 +47,7 @@ public record OctagonalColumnGeometry(ShadeMode shadeMode) implements Geometry {
|
|||
public BakedGeometry bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, SimpleModel model) {
|
||||
MutableMesh builder = Renderer.get().mutableMesh();
|
||||
QuadEmitter emitter = builder.emitter();
|
||||
emitter.pushTransform(ModelBakeSettingsHelper.asQuadTransform(settings, baker.getSpriteGetter().spriteFinder(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)));
|
||||
|
||||
MaterialFinder finder = Renderer.get().materialFinder();
|
||||
RenderMaterial glintMaterial = finder.glintMode(GlintMode.STANDARD).shadeMode(shadeMode).find();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import net.minecraft.client.render.model.ModelBakeSettings;
|
|||
import net.minecraft.client.render.model.ModelTextures;
|
||||
import net.minecraft.client.render.model.SimpleModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
|
|
@ -30,12 +31,14 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.MutableMesh;
|
|||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.MeshBakedGeometry;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelBakeSettingsHelper;
|
||||
|
||||
public record PillarGeometry() implements Geometry {
|
||||
@Override
|
||||
public BakedGeometry bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, SimpleModel model) {
|
||||
MutableMesh builder = Renderer.get().mutableMesh();
|
||||
QuadEmitter emitter = builder.emitter();
|
||||
emitter.pushTransform(ModelBakeSettingsHelper.asQuadTransform(settings, baker.getSpriteGetter().spriteFinder(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)));
|
||||
|
||||
Sprite sprite = baker.getSpriteGetter().get(textures.get("pillar"), model);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,28 @@
|
|||
{
|
||||
"variants": {
|
||||
"vanilla_shade_mode=false": { "model": "fabric-renderer-api-v1-testmod:octagonal_column_enhanced" },
|
||||
"vanilla_shade_mode=true": { "model": "fabric-renderer-api-v1-testmod:octagonal_column_vanilla" }
|
||||
"axis=x,vanilla_shade_mode=false": {
|
||||
"model": "fabric-renderer-api-v1-testmod:octagonal_column_enhanced",
|
||||
"x": 90,
|
||||
"y": 90
|
||||
},
|
||||
"axis=x,vanilla_shade_mode=true": {
|
||||
"model": "fabric-renderer-api-v1-testmod:octagonal_column_vanilla",
|
||||
"x": 90,
|
||||
"y": 90
|
||||
},
|
||||
"axis=y,vanilla_shade_mode=false": {
|
||||
"model": "fabric-renderer-api-v1-testmod:octagonal_column_enhanced"
|
||||
},
|
||||
"axis=y,vanilla_shade_mode=true": {
|
||||
"model": "fabric-renderer-api-v1-testmod:octagonal_column_vanilla"
|
||||
},
|
||||
"axis=z,vanilla_shade_mode=false": {
|
||||
"model": "fabric-renderer-api-v1-testmod:octagonal_column_enhanced",
|
||||
"x": 90
|
||||
},
|
||||
"axis=z,vanilla_shade_mode=true": {
|
||||
"model": "fabric-renderer-api-v1-testmod:octagonal_column_vanilla",
|
||||
"x": 90
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ public class IndigoRenderer implements Renderer {
|
|||
float red = (tint >> 16 & 255) / 255.0F;
|
||||
float green = (tint >> 8 & 255) / 255.0F;
|
||||
float blue = (tint & 255) / 255.0F;
|
||||
FabricBlockModelRenderer.render(matrices.peek(), layer -> vertexConsumers.getBuffer(RenderLayerHelper.getEntityBlockLayer(layer)), model, red, green, blue, light, overlay, blockView, pos, state);
|
||||
FabricBlockModelRenderer.render(matrices.peek(), RenderLayerHelper.entityDelegate(vertexConsumers), model, red, green, blue, light, overlay, blockView, pos, state);
|
||||
((BlockRenderManagerAccessor) renderManager).getBlockEntityModelsGetter().get().render(state.getBlock(), ItemDisplayContext.NONE, matrices, vertexConsumers, light, overlay);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import net.minecraft.util.math.MathHelper;
|
|||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.impl.client.indigo.Indigo;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.QuadViewImpl;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
||||
|
|
@ -151,12 +152,18 @@ public class AoCalculator {
|
|||
|
||||
private void calcEnhanced(QuadViewImpl quad) {
|
||||
switch (quad.geometryFlags()) {
|
||||
case AXIS_ALIGNED_FLAG | CUBIC_FLAG | LIGHT_FACE_FLAG:
|
||||
case AXIS_ALIGNED_FLAG | LIGHT_FACE_FLAG:
|
||||
case LIGHT_FACE_FLAG | AXIS_ALIGNED_FLAG | CUBIC_FLAG:
|
||||
vanillaFullFace(quad, quad.lightFace(), true, quad.hasShade());
|
||||
break;
|
||||
|
||||
case LIGHT_FACE_FLAG | AXIS_ALIGNED_FLAG:
|
||||
vanillaPartialFace(quad, quad.lightFace(), true, quad.hasShade());
|
||||
break;
|
||||
|
||||
case AXIS_ALIGNED_FLAG | CUBIC_FLAG:
|
||||
blendedFullFace(quad, quad.lightFace(), quad.hasShade());
|
||||
break;
|
||||
|
||||
case AXIS_ALIGNED_FLAG:
|
||||
blendedPartialFace(quad, quad.lightFace(), quad.hasShade());
|
||||
break;
|
||||
|
|
@ -167,24 +174,31 @@ public class AoCalculator {
|
|||
}
|
||||
}
|
||||
|
||||
private void vanillaFullFace(QuadViewImpl quad, Direction lightFace, boolean isOnLightFace, boolean shade) {
|
||||
computeFace(lightFace, isOnLightFace, shade).toArray(ao, light, AoFace.get(lightFace).vertexMap);
|
||||
private void fullFace(QuadViewImpl quad, Direction lightFace, AoFaceData faceData) {
|
||||
faceData.toArrays(ao, light, AoFace.get(lightFace).vertexMap, GeometryHelper.firstCubicVertex(quad));
|
||||
}
|
||||
|
||||
private void vanillaPartialFace(QuadViewImpl quad, Direction lightFace, boolean isOnLightFace, boolean shade) {
|
||||
AoFaceData faceData = computeFace(lightFace, isOnLightFace, shade);
|
||||
private void partialFace(QuadViewImpl quad, Direction lightFace, AoFaceData faceData) {
|
||||
final AoFace aoFace = AoFace.get(lightFace);
|
||||
final float[] w = this.w;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
aoFace.computeCornerWeights(quad, i, w);
|
||||
light[i] = faceData.weightedCombinedLight(w);
|
||||
ao[i] = faceData.weigtedAo(w);
|
||||
ao[i] = faceData.weightedAo(w);
|
||||
}
|
||||
}
|
||||
|
||||
/** used in {@link #blendedInsetFace(QuadViewImpl quad, int vertexIndex, Direction lightFace, boolean shade)} as return variable to avoid new allocation. */
|
||||
AoFaceData tmpFace = new AoFaceData();
|
||||
private void vanillaFullFace(QuadViewImpl quad, Direction lightFace, boolean isOnLightFace, boolean shade) {
|
||||
fullFace(quad, lightFace, computeFace(lightFace, isOnLightFace, shade));
|
||||
}
|
||||
|
||||
private void vanillaPartialFace(QuadViewImpl quad, Direction lightFace, boolean isOnLightFace, boolean shade) {
|
||||
partialFace(quad, lightFace, computeFace(lightFace, isOnLightFace, shade));
|
||||
}
|
||||
|
||||
/** Used in {@link #blendedInsetFace(QuadViewImpl, int, Direction, boolean)} as return variable to avoid new allocation. */
|
||||
private final AoFaceData tmpFace = new AoFaceData();
|
||||
|
||||
/** Returns linearly interpolated blend of outer and inner face based on depth of vertex in face. */
|
||||
private AoFaceData blendedInsetFace(QuadViewImpl quad, int vertexIndex, Direction lightFace, boolean shade) {
|
||||
|
|
@ -194,7 +208,7 @@ public class AoCalculator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Like {@link #blendedInsetFace(QuadViewImpl quad, int vertexIndex, Direction lightFace, boolean shade)} but optimizes if depth is 0 or 1.
|
||||
* Like {@link #blendedInsetFace(QuadViewImpl, int, Direction, boolean)} but optimizes if depth is 0 or 1.
|
||||
* Used for irregular faces when depth varies by vertex to avoid unneeded interpolation.
|
||||
*/
|
||||
private AoFaceData gatherInsetFace(QuadViewImpl quad, int vertexIndex, Direction lightFace, boolean shade) {
|
||||
|
|
@ -210,15 +224,12 @@ public class AoCalculator {
|
|||
}
|
||||
}
|
||||
|
||||
private void blendedPartialFace(QuadViewImpl quad, Direction lightFace, boolean shade) {
|
||||
AoFaceData faceData = blendedInsetFace(quad, 0, lightFace, shade);
|
||||
final AoFace aoFace = AoFace.get(lightFace);
|
||||
private void blendedFullFace(QuadViewImpl quad, Direction lightFace, boolean shade) {
|
||||
fullFace(quad, lightFace, blendedInsetFace(quad, 0, lightFace, shade));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
aoFace.computeCornerWeights(quad, i, w);
|
||||
light[i] = faceData.weightedCombinedLight(w);
|
||||
ao[i] = faceData.weigtedAo(w);
|
||||
}
|
||||
private void blendedPartialFace(QuadViewImpl quad, Direction lightFace, boolean shade) {
|
||||
partialFace(quad, lightFace, blendedInsetFace(quad, 0, lightFace, shade));
|
||||
}
|
||||
|
||||
/** used exclusively in irregular face to avoid new heap allocations each call. */
|
||||
|
|
@ -243,9 +254,9 @@ public class AoCalculator {
|
|||
final AoFaceData fd = gatherInsetFace(quad, i, face, shade);
|
||||
AoFace.get(face).computeCornerWeights(quad, i, w);
|
||||
final float n = x * x;
|
||||
final float a = fd.weigtedAo(w);
|
||||
final int s = fd.weigtedSkyLight(w);
|
||||
final int b = fd.weigtedBlockLight(w);
|
||||
final float a = fd.weightedAo(w);
|
||||
final int s = fd.weightedSkyLight(w);
|
||||
final int b = fd.weightedBlockLight(w);
|
||||
ao += n * a;
|
||||
sky += n * s;
|
||||
block += n * b;
|
||||
|
|
@ -261,9 +272,9 @@ public class AoCalculator {
|
|||
final AoFaceData fd = gatherInsetFace(quad, i, face, shade);
|
||||
AoFace.get(face).computeCornerWeights(quad, i, w);
|
||||
final float n = y * y;
|
||||
final float a = fd.weigtedAo(w);
|
||||
final int s = fd.weigtedSkyLight(w);
|
||||
final int b = fd.weigtedBlockLight(w);
|
||||
final float a = fd.weightedAo(w);
|
||||
final int s = fd.weightedSkyLight(w);
|
||||
final int b = fd.weightedBlockLight(w);
|
||||
ao += n * a;
|
||||
sky += n * s;
|
||||
block += n * b;
|
||||
|
|
@ -279,9 +290,9 @@ public class AoCalculator {
|
|||
final AoFaceData fd = gatherInsetFace(quad, i, face, shade);
|
||||
AoFace.get(face).computeCornerWeights(quad, i, w);
|
||||
final float n = z * z;
|
||||
final float a = fd.weigtedAo(w);
|
||||
final int s = fd.weigtedSkyLight(w);
|
||||
final int b = fd.weigtedBlockLight(w);
|
||||
final float a = fd.weightedAo(w);
|
||||
final int s = fd.weightedSkyLight(w);
|
||||
final int b = fd.weightedBlockLight(w);
|
||||
ao += n * a;
|
||||
sky += n * s;
|
||||
block += n * b;
|
||||
|
|
|
|||
|
|
@ -127,8 +127,9 @@ enum AoFace {
|
|||
|
||||
final Direction[] neighbors;
|
||||
/**
|
||||
* Vanilla models with cubic quads have vertices in a certain order, which allows
|
||||
* us to map them using a lookup.
|
||||
* Cubic quads have a vertex in each corner, which allows us to skip computing
|
||||
* weights and map values to vertices directly. Note that vanilla assumes a
|
||||
* certain vertex order, but we detect it and offset the map accordingly.
|
||||
*/
|
||||
final int[] vertexMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,31 +54,37 @@ class AoFaceData {
|
|||
this.s3 = (l3 >>> 16) & 0xFFFF;
|
||||
}
|
||||
|
||||
int weigtedBlockLight(float[] w) {
|
||||
int weightedBlockLight(float[] w) {
|
||||
return (int) (b0 * w[0] + b1 * w[1] + b2 * w[2] + b3 * w[3]) & 0xFF;
|
||||
}
|
||||
|
||||
int weigtedSkyLight(float[] w) {
|
||||
int weightedSkyLight(float[] w) {
|
||||
return (int) (s0 * w[0] + s1 * w[1] + s2 * w[2] + s3 * w[3]) & 0xFF;
|
||||
}
|
||||
|
||||
int weightedCombinedLight(float[] w) {
|
||||
return weigtedSkyLight(w) << 16 | weigtedBlockLight(w);
|
||||
return weightedSkyLight(w) << 16 | weightedBlockLight(w);
|
||||
}
|
||||
|
||||
float weigtedAo(float[] w) {
|
||||
float weightedAo(float[] w) {
|
||||
return a0 * w[0] + a1 * w[1] + a2 * w[2] + a3 * w[3];
|
||||
}
|
||||
|
||||
void toArray(float[] aOut, int[] bOut, int[] vertexMap) {
|
||||
aOut[vertexMap[0]] = a0;
|
||||
aOut[vertexMap[1]] = a1;
|
||||
aOut[vertexMap[2]] = a2;
|
||||
aOut[vertexMap[3]] = a3;
|
||||
bOut[vertexMap[0]] = s0 << 16 | b0;
|
||||
bOut[vertexMap[1]] = s1 << 16 | b1;
|
||||
bOut[vertexMap[2]] = s2 << 16 | b2;
|
||||
bOut[vertexMap[3]] = s3 << 16 | b3;
|
||||
void toArrays(float[] aoOut, int[] lightOut, int[] vertexMap, int vertexOffset) {
|
||||
int i0 = vertexMap[vertexOffset];
|
||||
int i1 = vertexMap[(vertexOffset + 1) % 4];
|
||||
int i2 = vertexMap[(vertexOffset + 2) % 4];
|
||||
int i3 = vertexMap[(vertexOffset + 3) % 4];
|
||||
|
||||
aoOut[i0] = a0;
|
||||
aoOut[i1] = a1;
|
||||
aoOut[i2] = a2;
|
||||
aoOut[i3] = a3;
|
||||
|
||||
lightOut[i0] = s0 << 16 | b0;
|
||||
lightOut[i1] = s1 << 16 | b1;
|
||||
lightOut[i2] = s2 << 16 | b2;
|
||||
lightOut[i3] = s3 << 16 | b3;
|
||||
}
|
||||
|
||||
static AoFaceData weightedMean(AoFaceData in0, float w0, AoFaceData in1, float w1, AoFaceData out) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import static net.minecraft.util.math.MathHelper.approximatelyEquals;
|
|||
import org.joml.Vector3fc;
|
||||
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.CubeFace;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Direction.Axis;
|
||||
import net.minecraft.util.math.Direction.AxisDirection;
|
||||
|
|
@ -197,24 +198,6 @@ public final class GeometryHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple 4-way compare, doesn't handle NaN values.
|
||||
*/
|
||||
public static float min(float a, float b, float c, float d) {
|
||||
final float x = a < b ? a : b;
|
||||
final float y = c < d ? c : d;
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple 4-way compare, doesn't handle NaN values.
|
||||
*/
|
||||
public static float max(float a, float b, float c, float d) {
|
||||
final float x = a > b ? a : b;
|
||||
final float y = c > d ? c : d;
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #longestAxis(float, float, float)
|
||||
*/
|
||||
|
|
@ -238,4 +221,71 @@ public final class GeometryHelper {
|
|||
return Math.abs(normalZ) > longest
|
||||
? Axis.Z : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the vertex which is in the first cubic corner for the given quad's light face, according to
|
||||
* the directions specified in {@link CubeFace}. Assumes that the given quad is
|
||||
* {@linkplain #isQuadCubic(Direction, QuadView) cubic}. Used to make smooth lighting for cubic quads work correctly
|
||||
* regardless of vertex order.
|
||||
*
|
||||
* <p>Because cubic quads have all vertices in different corners, the implementation only has to find which corner
|
||||
* the first vertex is in based on the same criteria as {@link #isQuadCubic(Direction, QuadView)}. Then, since
|
||||
* the vertex winding order is always counterclockwise, it can know which vertex is in the first corner.
|
||||
*/
|
||||
public static int firstCubicVertex(QuadView quad) {
|
||||
final float x = quad.x(0);
|
||||
final float y = quad.y(0);
|
||||
final float z = quad.z(0);
|
||||
|
||||
/*
|
||||
!a & !b -> vertex 0 is in corner 0 -> vertex 0 is in corner 0
|
||||
!a & b -> vertex 0 is in corner 1 -> vertex 3 is in corner 0
|
||||
a & b -> vertex 0 is in corner 2 -> vertex 2 is in corner 0
|
||||
a & !b -> vertex 0 is in corner 3 -> vertex 1 is in corner 0
|
||||
*/
|
||||
final boolean a;
|
||||
final boolean b;
|
||||
|
||||
switch (quad.lightFace()) {
|
||||
case DOWN -> {
|
||||
a = x > EPS_MIN;
|
||||
b = z < EPS_MAX;
|
||||
}
|
||||
case UP -> {
|
||||
a = x > EPS_MIN;
|
||||
b = z > EPS_MIN;
|
||||
}
|
||||
case NORTH -> {
|
||||
a = x < EPS_MAX;
|
||||
b = y < EPS_MAX;
|
||||
}
|
||||
case SOUTH -> {
|
||||
a = x > EPS_MIN;
|
||||
b = y < EPS_MAX;
|
||||
}
|
||||
case WEST -> {
|
||||
a = z > EPS_MIN;
|
||||
b = y < EPS_MAX;
|
||||
}
|
||||
case EAST -> {
|
||||
a = z < EPS_MAX;
|
||||
b = y < EPS_MAX;
|
||||
}
|
||||
default -> {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (a) {
|
||||
result ^= 1;
|
||||
}
|
||||
|
||||
if (b) {
|
||||
result ^= 3;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
|
|
@ -42,7 +41,6 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
|||
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.NormalHelper;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.TextureHelper;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.material.RenderMaterialImpl;
|
||||
|
||||
/**
|
||||
|
|
@ -121,12 +119,6 @@ public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEm
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final MutableQuadViewImpl spriteBake(Sprite sprite, int bakeFlags) {
|
||||
TextureHelper.bakeSprite(this, sprite, bakeFlags);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final MutableQuadViewImpl lightmap(int vertexIndex, int lightmap) {
|
||||
data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap;
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ public class ItemRenderContext extends AbstractRenderContext {
|
|||
|
||||
final int vanillaQuadCount = vanillaQuads.size();
|
||||
|
||||
for (int j = 0; j < vanillaQuadCount; j++) {
|
||||
final BakedQuad q = vanillaQuads.get(j);
|
||||
for (int i = 0; i < vanillaQuadCount; i++) {
|
||||
final BakedQuad q = vanillaQuads.get(i);
|
||||
emitter.fromVanilla(q, IndigoRenderer.STANDARD_MATERIAL, null);
|
||||
emitter.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,6 @@ abstract class BlockRenderManagerMixin {
|
|||
|
||||
@Redirect(method = "renderBlockAsEntity(Lnet/minecraft/block/BlockState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;II)V", at = @At(value = "INVOKE", target = "net/minecraft/client/render/block/BlockModelRenderer.render(Lnet/minecraft/client/util/math/MatrixStack$Entry;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/client/render/model/BlockStateModel;FFFII)V"))
|
||||
private void renderProxy(MatrixStack.Entry entry, VertexConsumer vertexConsumer, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockState state, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light1, int overlay1) {
|
||||
FabricBlockModelRenderer.render(entry, layer -> vertexConsumers.getBuffer(RenderLayerHelper.getEntityBlockLayer(layer)), model, red, green, blue, light, overlay, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, state);
|
||||
FabricBlockModelRenderer.render(entry, RenderLayerHelper.entityDelegate(vertexConsumers), model, red, green, blue, light, overlay, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, state);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue