Material inspection (#3066)

* Material inspection

- Add MaterialView to get material properties from RenderMaterial and MaterialFinder
- Add MaterialFinder#copyFrom to copy properties from another MaterialView
- Finish todo in QuadView#toBakedQuad
- Move material impl classes to material package

* Add glint material property

- Allow force enabling or force disabling glint on items
- Force enable glint on horizontal sides of pillar item model in test mod

* Fix imports

* Add documentation

* Do not create invalid materials

- Ensure material bits are valid before creating material
- Assert that default MaterialFinder bits are valid
- Remove ordinal checks in MaterialViewImpl since bits are now guaranteed to be valid
- Set default glint mode to default instead of false
- Remove getter overrides in RenderMaterialImpl

* Add MutableQuadView#copyFrom

- Deprecate QuadView#copyTo

* Add missing nullability annotations
This commit is contained in:
PepperCode1 2023-05-24 08:30:12 -07:00 committed by GitHub
parent 2198ff13ff
commit 52cca24e15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 474 additions and 212 deletions

View file

@ -19,6 +19,7 @@ package net.fabricmc.fabric.api.renderer.v1.material;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.item.ItemStack;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
@ -31,7 +32,7 @@ import net.fabricmc.fabric.api.util.TriState;
*
* <p>Must be obtained via {@link Renderer#materialFinder()}.
*/
public interface MaterialFinder {
public interface MaterialFinder extends MaterialView {
/**
* Defines how sprite pixels will be blended with the scene.
*
@ -73,6 +74,9 @@ public interface MaterialFinder {
/**
* Vertex color(s) will be modified for diffuse shading unless disabled.
*
* <p>This property is guaranteed to be respected in block contexts. Some renderers may also respect it in item
* contexts, but this is not guaranteed.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default MaterialFinder disableDiffuse(boolean disable) {
@ -86,12 +90,44 @@ public interface MaterialFinder {
* and the block state has {@link BlockState#getLuminance() a luminance} of 0.
* Set to {@link TriState#TRUE} or {@link TriState#FALSE} to override this behavior.
*
* <p>This property is respected only in block contexts. It will not have an effect in other contexts.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default MaterialFinder ambientOcclusion(TriState mode) {
return disableAo(0, mode == TriState.FALSE);
}
/**
* Controls whether glint should be applied.
*
* <p>By default, glint will be applied in item contexts if {@link ItemStack#hasGlint() the item stack has glint}.
* Set to {@link TriState#TRUE} or {@link TriState#FALSE} to override this behavior.
*
* <p>This property is guaranteed to be respected in item contexts. Some renderers may also respect it in block
* contexts, but this is not guaranteed.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default MaterialFinder glint(TriState mode) {
return this;
}
/**
* Copies all properties from the given {@link MaterialView} to this material finder.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default MaterialFinder copyFrom(MaterialView material) {
blendMode(material.blendMode());
disableColorIndex(material.disableColorIndex());
emissive(material.emissive());
disableDiffuse(material.disableDiffuse());
ambientOcclusion(material.ambientOcclusion());
glint(material.glint());
return this;
}
/**
* Resets this instance to default values. Values will match those
* in effect when an instance is newly obtained via {@link Renderer#materialFinder()}.

View file

@ -0,0 +1,81 @@
/*
* 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.material;
import net.fabricmc.fabric.api.util.TriState;
/**
* Getter methods for {@link RenderMaterial} (immutable) and {@link MaterialFinder} (mutable).
*
* <p>Values returned by the getters may not necessarily be identical to those requested in the {@link MaterialFinder}.
* The renderer may choose different values that are sufficiently representative for its own processing.
*/
public interface MaterialView {
/**
* @see MaterialFinder#blendMode(BlendMode)
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default BlendMode blendMode() {
return BlendMode.DEFAULT;
}
/**
* @see MaterialFinder#disableColorIndex(boolean)
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default boolean disableColorIndex() {
return false;
}
/**
* @see MaterialFinder#emissive(boolean)
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default boolean emissive() {
return false;
}
/**
* @see MaterialFinder#disableDiffuse(boolean)
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default boolean disableDiffuse() {
return false;
}
/**
* @see MaterialFinder#ambientOcclusion(TriState)
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default TriState ambientOcclusion() {
return TriState.DEFAULT;
}
/**
* @see MaterialFinder#glint(TriState)
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default TriState glint() {
return TriState.DEFAULT;
}
}

View file

@ -62,7 +62,7 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
* special materials could be implemented by multiple renderers, however there is
* no requirement that special materials be cross-compatible.
*/
public interface RenderMaterial {
public interface RenderMaterial extends MaterialView {
/**
* 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.

View file

@ -256,6 +256,19 @@ public interface MutableQuadView extends QuadView {
*/
MutableQuadView tag(int tag);
/**
* Copies all quad properties from the given {@link QuadView} to this quad.
*
* <p>Calling this method does not emit the quad.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default MutableQuadView copyFrom(QuadView quad) {
quad.copyTo(this);
material(quad.material());
return this;
}
/**
* Enables bulk vertex data transfer using the standard Minecraft vertex formats.
* Only the {@link BakedQuad#getVertexData() quad vertex data} is copied.

View file

@ -16,6 +16,7 @@
package net.fabricmc.fabric.api.renderer.v1.mesh;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector2f;
import org.joml.Vector3f;
@ -115,10 +116,10 @@ public interface QuadEmitter extends MutableQuadView {
}
@Override
QuadEmitter cullFace(Direction face);
QuadEmitter cullFace(@Nullable Direction face);
@Override
QuadEmitter nominalFace(Direction face);
QuadEmitter nominalFace(@Nullable Direction face);
@Override
QuadEmitter material(RenderMaterial material);
@ -129,6 +130,14 @@ public interface QuadEmitter extends MutableQuadView {
@Override
QuadEmitter tag(int tag);
/**
* @apiNote The default implementation will be removed in the next breaking release.
*/
default QuadEmitter copyFrom(QuadView quad) {
MutableQuadView.super.copyFrom(quad);
return this;
}
/**
* @apiNote The default implementation will be removed in the next breaking release.
*/

View file

@ -163,6 +163,7 @@ public interface QuadView {
/**
* See {@link MutableQuadView#nominalFace(Direction)}.
*/
@Nullable
Direction nominalFace();
/**
@ -191,13 +192,6 @@ public interface QuadView {
*/
int tag();
/**
* Extracts all quad properties except material to the given {@link MutableQuadView} instance.
* Must be used before calling {link QuadEmitter#emit()} on the target instance.
* Meant for re-texturing, analysis and static transformation use cases.
*/
void copyTo(MutableQuadView target);
/**
* Reads baked vertex data and outputs standard {@link BakedQuad#getVertexData() baked quad vertex data}
* in the given array and location.
@ -227,9 +221,11 @@ public interface QuadView {
default BakedQuad toBakedQuad(Sprite sprite) {
int[] vertexData = new int[VANILLA_QUAD_STRIDE];
toVanilla(vertexData, 0);
// TODO material inspection: set shade as !disableDiffuse
// TODO material inspection: set color index to -1 if the material disables it
return new BakedQuad(vertexData, colorIndex(), lightFace(), sprite, true);
// Mimic material properties to the largest possible extent
int outputColorIndex = material().disableColorIndex() ? -1 : colorIndex();
boolean outputShade = !material().disableDiffuse();
return new BakedQuad(vertexData, outputColorIndex, lightFace(), sprite, outputShade);
}
/**
@ -256,6 +252,17 @@ public interface QuadView {
return v(vertexIndex);
}
/**
* @deprecated Use {@link MutableQuadView#copyFrom(QuadView)} instead.
* <b>Unlike {@link MutableQuadView#copyFrom(QuadView) copyFrom}, this method will not copy the material.</b>
*/
@Deprecated
default void copyTo(MutableQuadView target) {
RenderMaterial material = target.material();
target.copyFrom(this);
target.material(material);
}
/**
* @deprecated Use {@link #toVanilla(int[], int)} instead.
*/

View file

@ -34,11 +34,15 @@ import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.block.v1.FabricBlockState;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
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.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
/**
@ -51,9 +55,16 @@ public class PillarBakedModel implements BakedModel, FabricBakedModel {
// alone, bottom, middle, top
private final Sprite[] sprites;
private final RenderMaterial defaultMaterial;
private final RenderMaterial glintMaterial;
public PillarBakedModel(Sprite[] sprites) {
this.sprites = sprites;
MaterialFinder finder = RendererAccess.INSTANCE.getRenderer().materialFinder();
defaultMaterial = finder.find();
finder.clear();
glintMaterial = finder.glint(TriState.TRUE).find();
}
@Override
@ -74,23 +85,29 @@ public class PillarBakedModel implements BakedModel, FabricBakedModel {
private void emitQuads(QuadEmitter emitter, @Nullable BlockRenderView blockView, @Nullable BlockState state, @Nullable BlockPos pos) {
for (Direction side : Direction.values()) {
ConnectedTexture texture = ConnectedTexture.ALONE;
RenderMaterial material = defaultMaterial;
if (side.getAxis().isHorizontal() && blockView != null && state != null && pos != null) {
boolean connectAbove = canConnect(blockView, pos.offset(Direction.UP), side, state, pos);
boolean connectBelow = canConnect(blockView, pos.offset(Direction.DOWN), side, state, pos);
if (side.getAxis().isHorizontal()) {
if (blockView != null && state != null && pos != null) {
boolean connectAbove = canConnect(blockView, pos.offset(Direction.UP), side, state, pos);
boolean connectBelow = canConnect(blockView, pos.offset(Direction.DOWN), side, state, pos);
if (connectAbove && connectBelow) {
texture = ConnectedTexture.MIDDLE;
} else if (connectAbove) {
texture = ConnectedTexture.BOTTOM;
} else if (connectBelow) {
texture = ConnectedTexture.TOP;
if (connectAbove && connectBelow) {
texture = ConnectedTexture.MIDDLE;
} else if (connectAbove) {
texture = ConnectedTexture.BOTTOM;
} else if (connectBelow) {
texture = ConnectedTexture.TOP;
}
}
material = glintMaterial;
}
emitter.square(side, 0, 0, 1, 1, 0);
emitter.spriteBake(sprites[texture.ordinal()], MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.material(material);
emitter.emit();
}
}

View file

@ -24,7 +24,7 @@ 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.MeshBuilder;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl.Value;
import net.fabricmc.fabric.impl.client.indigo.renderer.material.MaterialFinderImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MeshBuilderImpl;
/**
@ -34,7 +34,7 @@ import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MeshBuilderImpl;
public class IndigoRenderer implements Renderer {
public static final IndigoRenderer INSTANCE = new IndigoRenderer();
public static final RenderMaterialImpl.Value MATERIAL_STANDARD = (Value) INSTANCE.materialFinder().find();
public static final RenderMaterial MATERIAL_STANDARD = INSTANCE.materialFinder().find();
static {
INSTANCE.registerMaterial(RenderMaterial.MATERIAL_STANDARD, MATERIAL_STANDARD);
@ -51,7 +51,7 @@ public class IndigoRenderer implements Renderer {
@Override
public MaterialFinder materialFinder() {
return new RenderMaterialImpl.Finder();
return new MaterialFinderImpl();
}
@Override

View file

@ -19,6 +19,7 @@ package net.fabricmc.fabric.impl.client.indigo.renderer.helper;
import static net.minecraft.util.math.MathHelper.approximatelyEquals;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import net.minecraft.client.render.model.BakedQuad;
@ -81,7 +82,7 @@ public abstract class GeometryHelper {
* Does not validate quad winding order.
* Expects convex quads with all points co-planar.
*/
public static boolean isQuadParallelToFace(Direction face, QuadView quad) {
public static boolean isQuadParallelToFace(@Nullable Direction face, QuadView quad) {
if (face == null) {
return false;
}

View file

@ -0,0 +1,103 @@
/*
* 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.client.indigo.renderer.material;
import java.util.Objects;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
import net.fabricmc.fabric.api.renderer.v1.material.MaterialView;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.util.TriState;
public class MaterialFinderImpl extends MaterialViewImpl implements MaterialFinder {
private static int defaultBits = 0;
static {
MaterialFinderImpl finder = new MaterialFinderImpl();
finder.ambientOcclusion(TriState.DEFAULT);
finder.glint(TriState.DEFAULT);
defaultBits = finder.bits;
if (!areBitsValid(defaultBits)) {
throw new AssertionError("Default MaterialFinder bits are not valid!");
}
}
public MaterialFinderImpl() {
super(defaultBits);
}
@Override
public MaterialFinder blendMode(BlendMode blendMode) {
Objects.requireNonNull(blendMode, "BlendMode may not be null");
bits = (bits & ~BLEND_MODE_MASK) | (blendMode.ordinal() << BLEND_MODE_BIT_OFFSET);
return this;
}
@Override
public MaterialFinder disableColorIndex(boolean disable) {
bits = disable ? (bits | COLOR_DISABLE_FLAG) : (bits & ~COLOR_DISABLE_FLAG);
return this;
}
@Override
public MaterialFinder emissive(boolean isEmissive) {
bits = isEmissive ? (bits | EMISSIVE_FLAG) : (bits & ~EMISSIVE_FLAG);
return this;
}
@Override
public MaterialFinder disableDiffuse(boolean disable) {
bits = disable ? (bits | DIFFUSE_FLAG) : (bits & ~DIFFUSE_FLAG);
return this;
}
@Override
public MaterialFinder ambientOcclusion(TriState mode) {
Objects.requireNonNull(mode, "ambient occlusion TriState may not be null");
bits = (bits & ~AO_MASK) | (mode.ordinal() << AO_BIT_OFFSET);
return this;
}
@Override
public MaterialFinder glint(TriState mode) {
Objects.requireNonNull(mode, "glint TriState may not be null");
bits = (bits & ~GLINT_MASK) | (mode.ordinal() << GLINT_BIT_OFFSET);
return this;
}
@Override
public MaterialFinder copyFrom(MaterialView material) {
bits = ((MaterialViewImpl) material).bits;
return this;
}
@Override
public MaterialFinder clear() {
bits = defaultBits;
return this;
}
@Override
public RenderMaterial find() {
return RenderMaterialImpl.byIndex(bits);
}
}

View file

@ -14,15 +14,12 @@
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.indigo.renderer;
import java.util.Objects;
package net.fabricmc.fabric.impl.client.indigo.renderer.material;
import net.minecraft.util.math.MathHelper;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
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.material.MaterialView;
import net.fabricmc.fabric.api.util.TriState;
/**
@ -31,7 +28,7 @@ import net.fabricmc.fabric.api.util.TriState;
* packing of the various material properties. This offers
* easy/fast interning via int/object hashmap.
*/
public abstract class RenderMaterialImpl {
public class MaterialViewImpl implements MaterialView {
private static final BlendMode[] BLEND_MODES = BlendMode.values();
private static final int BLEND_MODE_COUNT = BLEND_MODES.length;
private static final TriState[] TRI_STATES = TriState.values();
@ -42,150 +39,70 @@ public abstract class RenderMaterialImpl {
protected static final int EMISSIVE_BIT_LENGTH = 1;
protected static final int DIFFUSE_BIT_LENGTH = 1;
protected static final int AO_BIT_LENGTH = MathHelper.ceilLog2(TRI_STATE_COUNT);
protected static final int GLINT_BIT_LENGTH = MathHelper.ceilLog2(TRI_STATE_COUNT);
protected static final int BLEND_MODE_BIT_OFFSET = 0;
protected static final int COLOR_DISABLE_BIT_OFFSET = BLEND_MODE_BIT_OFFSET + BLEND_MODE_BIT_LENGTH;
protected static final int EMISSIVE_BIT_OFFSET = COLOR_DISABLE_BIT_OFFSET + COLOR_DISABLE_BIT_LENGTH;
protected static final int DIFFUSE_BIT_OFFSET = EMISSIVE_BIT_OFFSET + EMISSIVE_BIT_LENGTH;
protected static final int AO_BIT_OFFSET = DIFFUSE_BIT_OFFSET + DIFFUSE_BIT_LENGTH;
protected static final int TOTAL_BIT_LENGTH = AO_BIT_OFFSET + AO_BIT_LENGTH;
protected static final int GLINT_BIT_OFFSET = AO_BIT_OFFSET + AO_BIT_LENGTH;
protected static final int TOTAL_BIT_LENGTH = GLINT_BIT_OFFSET + GLINT_BIT_LENGTH;
protected static final int BLEND_MODE_MASK = bitMask(BLEND_MODE_BIT_LENGTH, BLEND_MODE_BIT_OFFSET);
protected static final int COLOR_DISABLE_FLAG = bitMask(COLOR_DISABLE_BIT_LENGTH, COLOR_DISABLE_BIT_OFFSET);
protected static final int EMISSIVE_FLAG = bitMask(EMISSIVE_BIT_LENGTH, EMISSIVE_BIT_OFFSET);
protected static final int DIFFUSE_FLAG = bitMask(DIFFUSE_BIT_LENGTH, DIFFUSE_BIT_OFFSET);
protected static final int AO_MASK = bitMask(AO_BIT_LENGTH, AO_BIT_OFFSET);
public static final int VALUE_COUNT = 1 << TOTAL_BIT_LENGTH;
protected static final int GLINT_MASK = bitMask(GLINT_BIT_LENGTH, GLINT_BIT_OFFSET);
protected static int bitMask(int bitLength, int bitOffset) {
return ((1 << bitLength) - 1) << bitOffset;
}
private static final Value[] VALUES = new Value[VALUE_COUNT];
protected static boolean areBitsValid(int bits) {
int blendMode = (bits & BLEND_MODE_MASK) >> BLEND_MODE_BIT_OFFSET;
int ao = (bits & AO_MASK) >> AO_BIT_OFFSET;
int glint = (bits & GLINT_MASK) >> GLINT_BIT_OFFSET;
static {
for (int i = 0; i < VALUE_COUNT; i++) {
VALUES[i] = new Value(i);
}
}
public static RenderMaterialImpl.Value byIndex(int index) {
return VALUES[index];
}
public static Value setDisableDiffuse(Value material, boolean disable) {
if (material.disableDiffuse() != disable) {
return byIndex(disable ? (material.bits | DIFFUSE_FLAG) : (material.bits & ~DIFFUSE_FLAG));
}
return material;
return blendMode < BLEND_MODE_COUNT
&& ao < TRI_STATE_COUNT
&& glint < TRI_STATE_COUNT;
}
protected int bits;
protected RenderMaterialImpl(int bits) {
protected MaterialViewImpl(int bits) {
this.bits = bits;
}
@Override
public BlendMode blendMode() {
int ordinal = (bits & BLEND_MODE_MASK) >> BLEND_MODE_BIT_OFFSET;
if (ordinal >= BLEND_MODE_COUNT) {
return BlendMode.DEFAULT;
}
return BLEND_MODES[ordinal];
return BLEND_MODES[(bits & BLEND_MODE_MASK) >> BLEND_MODE_BIT_OFFSET];
}
@Override
public boolean disableColorIndex() {
return (bits & COLOR_DISABLE_FLAG) != 0;
}
@Override
public boolean emissive() {
return (bits & EMISSIVE_FLAG) != 0;
}
@Override
public boolean disableDiffuse() {
return (bits & DIFFUSE_FLAG) != 0;
}
@Override
public TriState ambientOcclusion() {
int ordinal = (bits & AO_MASK) >> AO_BIT_OFFSET;
if (ordinal >= TRI_STATE_COUNT) {
return TriState.DEFAULT;
}
return TRI_STATES[ordinal];
return TRI_STATES[(bits & AO_MASK) >> AO_BIT_OFFSET];
}
public static class Value extends RenderMaterialImpl implements RenderMaterial {
private Value(int bits) {
super(bits);
}
public int index() {
return bits;
}
}
public static class Finder extends RenderMaterialImpl implements MaterialFinder {
private static int defaultBits = 0;
static {
Finder finder = new Finder();
finder.ambientOcclusion(TriState.DEFAULT);
defaultBits = finder.bits;
}
public Finder() {
super(defaultBits);
}
@Override
public MaterialFinder blendMode(BlendMode blendMode) {
Objects.requireNonNull(blendMode, "BlendMode may not be null");
bits = (bits & ~BLEND_MODE_MASK) | (blendMode.ordinal() << BLEND_MODE_BIT_OFFSET);
return this;
}
@Override
public MaterialFinder disableColorIndex(boolean disable) {
bits = disable ? (bits | COLOR_DISABLE_FLAG) : (bits & ~COLOR_DISABLE_FLAG);
return this;
}
@Override
public MaterialFinder emissive(boolean isEmissive) {
bits = isEmissive ? (bits | EMISSIVE_FLAG) : (bits & ~EMISSIVE_FLAG);
return this;
}
@Override
public MaterialFinder disableDiffuse(boolean disable) {
bits = disable ? (bits | DIFFUSE_FLAG) : (bits & ~DIFFUSE_FLAG);
return this;
}
@Override
public MaterialFinder ambientOcclusion(TriState mode) {
Objects.requireNonNull(mode, "ambient occlusion TriState may not be null");
bits = (bits & ~AO_MASK) | (mode.ordinal() << AO_BIT_OFFSET);
return this;
}
@Override
public MaterialFinder clear() {
bits = defaultBits;
return this;
}
@Override
public RenderMaterial find() {
return VALUES[bits];
}
@Override
public TriState glint() {
return TRI_STATES[(bits & GLINT_MASK) >> GLINT_BIT_OFFSET];
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.client.indigo.renderer.material;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
public class RenderMaterialImpl extends MaterialViewImpl implements RenderMaterial {
public static final int VALUE_COUNT = 1 << TOTAL_BIT_LENGTH;
private static final RenderMaterialImpl[] BY_INDEX = new RenderMaterialImpl[VALUE_COUNT];
static {
for (int i = 0; i < VALUE_COUNT; i++) {
if (areBitsValid(i)) {
BY_INDEX[i] = new RenderMaterialImpl(i);
}
}
}
private RenderMaterialImpl(int bits) {
super(bits);
}
public int index() {
return bits;
}
public static RenderMaterialImpl byIndex(int index) {
return BY_INDEX[index];
}
public static RenderMaterialImpl setDisableDiffuse(RenderMaterialImpl material, boolean disable) {
if (material.disableDiffuse() != disable) {
return byIndex(disable ? (material.bits | DIFFUSE_FLAG) : (material.bits & ~DIFFUSE_FLAG));
}
return material;
}
}

View file

@ -25,8 +25,8 @@ import net.minecraft.util.math.MathHelper;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.material.RenderMaterialImpl;
/**
* Holds all the array offsets and bit-wise encoders/decoders for
@ -132,11 +132,11 @@ public abstract class EncodingFormat {
return (bits & GEOMETRY_INVERSE_MASK) | ((geometryFlags & GEOMETRY_MASK) << GEOMETRY_SHIFT);
}
static RenderMaterialImpl.Value material(int bits) {
static RenderMaterialImpl material(int bits) {
return RenderMaterialImpl.byIndex((bits >> MATERIAL_SHIFT) & MATERIAL_MASK);
}
static int material(int bits, RenderMaterialImpl.Value material) {
static int material(int bits, RenderMaterialImpl material) {
return (bits & MATERIAL_INVERSE_MASK) | (material.index() << MATERIAL_SHIFT);
}
}

View file

@ -37,11 +37,11 @@ import net.minecraft.util.math.Direction;
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.mesh.QuadView;
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl.Value;
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;
/**
* Almost-concrete implementation of a mutable quad. The only missing part is {@link #emit()},
@ -150,7 +150,7 @@ public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEm
material = IndigoRenderer.MATERIAL_STANDARD;
}
data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], (Value) material);
data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], (RenderMaterialImpl) material);
return this;
}
@ -166,6 +166,18 @@ public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEm
return this;
}
@Override
public MutableQuadViewImpl copyFrom(QuadView quad) {
final QuadViewImpl q = (QuadViewImpl) quad;
q.computeGeometry();
System.arraycopy(q.data, q.baseIndex, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
faceNormal.set(q.faceNormal);
nominalFace = q.nominalFace;
isGeometryInvalid = false;
return this;
}
@Override
public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) {
System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, QUAD_STRIDE);
@ -181,7 +193,7 @@ public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEm
colorIndex(quad.getColorIndex());
if (!quad.hasShade()) {
material = RenderMaterialImpl.setDisableDiffuse((Value) material, true);
material = RenderMaterialImpl.setDisableDiffuse((RenderMaterialImpl) material, true);
}
material(material);

View file

@ -35,22 +35,19 @@ import org.jetbrains.annotations.Nullable;
import org.joml.Vector2f;
import org.joml.Vector3f;
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;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.NormalHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.material.RenderMaterialImpl;
/**
* Base class for all quads / quad makers. Handles the ugly bits
* of maintaining and encoding the quad state.
*/
public class QuadViewImpl implements QuadView {
@Nullable
protected Direction nominalFace;
/** True when geometry flags or light face may not match geometry. */
protected boolean isGeometryInvalid = true;
@ -238,6 +235,7 @@ public class QuadViewImpl implements QuadView {
}
@Override
@Nullable
public final Direction nominalFace() {
return nominalFace;
}
@ -249,7 +247,7 @@ public class QuadViewImpl implements QuadView {
}
@Override
public final RenderMaterialImpl.Value material() {
public final RenderMaterialImpl material() {
return EncodingFormat.material(data[baseIndex + HEADER_BITS]);
}
@ -263,34 +261,8 @@ public class QuadViewImpl implements QuadView {
return data[baseIndex + HEADER_TAG];
}
@Override
public void copyTo(MutableQuadView target) {
computeGeometry();
final MutableQuadViewImpl quad = (MutableQuadViewImpl) target;
// copy everything except the material
RenderMaterial material = quad.material();
System.arraycopy(data, baseIndex, quad.data, quad.baseIndex, EncodingFormat.TOTAL_STRIDE);
quad.material(material);
quad.faceNormal.set(faceNormal);
quad.nominalFace = this.nominalFace;
quad.isGeometryInvalid = false;
}
@Override
public final void toVanilla(int[] target, int targetIndex) {
System.arraycopy(data, baseIndex + VERTEX_X, target, targetIndex, QUAD_STRIDE);
}
// TODO material inspection: remove
@Override
public final BakedQuad toBakedQuad(Sprite sprite) {
int[] vertexData = new int[VANILLA_QUAD_STRIDE];
toVanilla(vertexData, 0);
// Mimic material properties to the largest possible extent
int outputColorIndex = material().disableColorIndex() ? -1 : colorIndex();
boolean outputShade = !material().disableDiffuse();
return new BakedQuad(vertexData, outputColorIndex, lightFace(), sprite, outputShade);
}
}

View file

@ -33,9 +33,9 @@ import net.minecraft.client.render.WorldRenderer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext.QuadTransform;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
@ -81,7 +81,7 @@ public abstract class AbstractQuadRenderer {
* tessellate routine based on material properties.
*/
private void tessellateQuad(MutableQuadViewImpl quad, boolean isVanilla) {
final RenderMaterialImpl.Value mat = quad.material();
final RenderMaterial mat = quad.material();
final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
final RenderLayer renderLayer = blockInfo.effectiveRenderLayer(mat.blendMode());
final TriState ao = mat.ambientOcclusion();

View file

@ -44,12 +44,13 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MeshImpl;
@ -90,9 +91,13 @@ public class ItemRenderContext extends AbstractRenderContext {
private boolean isDefaultTranslucent;
private boolean isTranslucentDirect;
private boolean isDefaultGlint;
private VertexConsumer translucentVertexConsumer;
private VertexConsumer cutoutVertexConsumer;
private VertexConsumer modelVertexConsumer;
private VertexConsumer translucentGlintVertexConsumer;
private VertexConsumer cutoutGlintVertexConsumer;
private VertexConsumer defaultVertexConsumer;
public ItemRenderContext(ItemColors colorMap) {
this.colorMap = colorMap;
@ -116,9 +121,12 @@ public class ItemRenderContext extends AbstractRenderContext {
this.itemStack = null;
this.matrixStack = null;
this.vanillaHandler = null;
translucentVertexConsumer = null;
cutoutVertexConsumer = null;
modelVertexConsumer = null;
translucentGlintVertexConsumer = null;
cutoutGlintVertexConsumer = null;
defaultVertexConsumer = null;
}
private void computeOutputInfo() {
@ -140,7 +148,23 @@ public class ItemRenderContext extends AbstractRenderContext {
}
}
modelVertexConsumer = quadVertexConsumer(BlendMode.DEFAULT);
isDefaultGlint = itemStack.hasGlint();
defaultVertexConsumer = quadVertexConsumer(BlendMode.DEFAULT, TriState.DEFAULT);
}
private VertexConsumer createTranslucentVertexConsumer(boolean glint) {
if (isTranslucentDirect) {
return ItemRenderer.getDirectItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getEntityTranslucentCull(), true, glint);
} else if (MinecraftClient.isFabulousGraphicsOrBetter()) {
return ItemRenderer.getItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getItemEntityTranslucentCull(), true, glint);
} else {
return ItemRenderer.getItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getEntityTranslucentCull(), true, glint);
}
}
private VertexConsumer createCutoutVertexConsumer(boolean glint) {
return ItemRenderer.getDirectItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getEntityCutout(), true, glint);
}
/**
@ -148,8 +172,9 @@ public class ItemRenderContext extends AbstractRenderContext {
* in {@code RenderLayers.getEntityBlockLayer}. Layers other than
* translucent are mapped to cutout.
*/
private VertexConsumer quadVertexConsumer(BlendMode blendMode) {
private VertexConsumer quadVertexConsumer(BlendMode blendMode, TriState glintMode) {
boolean translucent;
boolean glint;
if (blendMode == BlendMode.DEFAULT) {
translucent = isDefaultTranslucent;
@ -157,29 +182,45 @@ public class ItemRenderContext extends AbstractRenderContext {
translucent = blendMode == BlendMode.TRANSLUCENT;
}
if (translucent) {
if (translucentVertexConsumer == null) {
if (isTranslucentDirect) {
translucentVertexConsumer = ItemRenderer.getDirectItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getEntityTranslucentCull(), true, itemStack.hasGlint());
} else if (MinecraftClient.isFabulousGraphicsOrBetter()) {
translucentVertexConsumer = ItemRenderer.getItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getItemEntityTranslucentCull(), true, itemStack.hasGlint());
} else {
translucentVertexConsumer = ItemRenderer.getItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getEntityTranslucentCull(), true, itemStack.hasGlint());
}
}
return translucentVertexConsumer;
if (glintMode == TriState.DEFAULT) {
glint = isDefaultGlint;
} else {
if (cutoutVertexConsumer == null) {
cutoutVertexConsumer = ItemRenderer.getDirectItemGlintConsumer(vertexConsumerProvider, TexturedRenderLayers.getEntityCutout(), true, itemStack.hasGlint());
}
glint = glintMode == TriState.TRUE;
}
return cutoutVertexConsumer;
if (translucent) {
if (glint) {
if (translucentGlintVertexConsumer == null) {
translucentGlintVertexConsumer = createTranslucentVertexConsumer(true);
}
return translucentGlintVertexConsumer;
} else {
if (translucentVertexConsumer == null) {
translucentVertexConsumer = createTranslucentVertexConsumer(false);
}
return translucentVertexConsumer;
}
} else {
if (glint) {
if (cutoutGlintVertexConsumer == null) {
cutoutGlintVertexConsumer = createCutoutVertexConsumer(true);
}
return cutoutGlintVertexConsumer;
} else {
if (cutoutVertexConsumer == null) {
cutoutVertexConsumer = createCutoutVertexConsumer(false);
}
return cutoutVertexConsumer;
}
}
}
private void bufferQuad(MutableQuadViewImpl quad, BlendMode blendMode) {
AbstractQuadRenderer.bufferQuad(quadVertexConsumer(blendMode), quad, matrix, overlay, normalMatrix, normalVec);
private void bufferQuad(MutableQuadViewImpl quad, BlendMode blendMode, TriState glint) {
AbstractQuadRenderer.bufferQuad(quadVertexConsumer(blendMode, glint), quad, matrix, overlay, normalMatrix, normalVec);
}
private void colorizeQuad(MutableQuadViewImpl q, int colorIndex) {
@ -196,7 +237,7 @@ public class ItemRenderContext extends AbstractRenderContext {
}
}
private void renderQuad(MutableQuadViewImpl quad, BlendMode blendMode, int colorIndex) {
private void renderQuad(MutableQuadViewImpl quad, BlendMode blendMode, TriState glint, int colorIndex) {
colorizeQuad(quad, colorIndex);
final int lightmap = this.lightmap;
@ -205,17 +246,17 @@ public class ItemRenderContext extends AbstractRenderContext {
quad.lightmap(i, ColorHelper.maxBrightness(quad.lightmap(i), lightmap));
}
bufferQuad(quad, blendMode);
bufferQuad(quad, blendMode, glint);
}
private void renderQuadEmissive(MutableQuadViewImpl quad, BlendMode blendMode, int colorIndex) {
private void renderQuadEmissive(MutableQuadViewImpl quad, BlendMode blendMode, TriState glint, int colorIndex) {
colorizeQuad(quad, colorIndex);
for (int i = 0; i < 4; i++) {
quad.lightmap(i, LightmapTextureManager.MAX_LIGHT_COORDINATE);
}
bufferQuad(quad, blendMode);
bufferQuad(quad, blendMode, glint);
}
private void renderMeshQuad(MutableQuadViewImpl quad) {
@ -223,15 +264,16 @@ public class ItemRenderContext extends AbstractRenderContext {
return;
}
final RenderMaterialImpl.Value mat = quad.material();
final RenderMaterial mat = quad.material();
final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
final BlendMode blendMode = mat.blendMode();
final TriState glint = mat.glint();
if (mat.emissive()) {
renderQuadEmissive(quad, blendMode, colorIndex);
renderQuadEmissive(quad, blendMode, glint, colorIndex);
} else {
renderQuad(quad, blendMode, colorIndex);
renderQuad(quad, blendMode, glint, colorIndex);
}
}
@ -292,7 +334,7 @@ public class ItemRenderContext extends AbstractRenderContext {
}
}
} else {
vanillaHandler.accept(model, itemStack, lightmap, overlay, matrixStack, modelVertexConsumer);
vanillaHandler.accept(model, itemStack, lightmap, overlay, matrixStack, defaultVertexConsumer);
}
}
}

View file

@ -30,13 +30,13 @@ import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
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.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext.QuadTransform;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl.Value;
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
@ -61,8 +61,8 @@ import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
* manipulating the data via NIO.
*/
public abstract class TerrainFallbackConsumer extends AbstractQuadRenderer implements RenderContext.BakedModelConsumer {
private static final Value MATERIAL_FLAT = (Value) IndigoRenderer.INSTANCE.materialFinder().ambientOcclusion(TriState.FALSE).find();
private static final Value MATERIAL_SHADED = (Value) IndigoRenderer.INSTANCE.materialFinder().find();
private static final RenderMaterial MATERIAL_FLAT = IndigoRenderer.INSTANCE.materialFinder().ambientOcclusion(TriState.FALSE).find();
private static final RenderMaterial MATERIAL_SHADED = IndigoRenderer.INSTANCE.materialFinder().find();
TerrainFallbackConsumer(BlockRenderInfo blockInfo, Function<RenderLayer, VertexConsumer> bufferFunc, AoCalculator aoCalc, QuadTransform transform) {
super(blockInfo, bufferFunc, aoCalc, transform);
@ -89,7 +89,7 @@ public abstract class TerrainFallbackConsumer extends AbstractQuadRenderer imple
@Override
public void accept(BakedModel model, @Nullable BlockState blockState) {
final Supplier<Random> random = blockInfo.randomSupplier;
final Value defaultMaterial = model.useAmbientOcclusion() ? MATERIAL_SHADED : MATERIAL_FLAT;
final RenderMaterial defaultMaterial = model.useAmbientOcclusion() ? MATERIAL_SHADED : MATERIAL_FLAT;
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
final Direction cullFace = ModelHelper.faceFromIndex(i);
@ -105,7 +105,7 @@ public abstract class TerrainFallbackConsumer extends AbstractQuadRenderer imple
}
}
private void renderQuad(BakedQuad quad, Direction cullFace, Value defaultMaterial) {
private void renderQuad(BakedQuad quad, Direction cullFace, RenderMaterial defaultMaterial) {
final MutableQuadViewImpl editorQuad = this.editorQuad;
editorQuad.fromVanilla(quad, defaultMaterial, cullFace);