mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-23 16:18:29 -05:00
Add ShadeMode
to FRAPI (#3937)
* Add ShadeMode to the API - Update material documentation - Use ShadeMode in VanillaModelEncoder * Add ShadeMode support to Indigo - Rewrite header packing constants in EncodingFormat to match material packing constants - Pass buffer Function to TerrainRenderContext instead of allocators and buffer map - Restore functionality of ChunkRenderInfo#release - Set captured terrain context to null after releasing it - Bump mixin compatibility level to Java 21 - Remove unused AWs * Add test for ShadeMode - Fix RiverstoneUnbakedModel not calling setParents on models that it will bake * Clarify documentation of inverted material properties
This commit is contained in:
parent
6c1df360ce
commit
c705a49cc5
26 changed files with 288 additions and 217 deletions
|
@ -17,13 +17,15 @@
|
|||
package net.fabricmc.fabric.api.renderer.v1.material;
|
||||
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.RenderLayers;
|
||||
|
||||
/**
|
||||
* Defines how sprite pixels will be blended with the scene.
|
||||
* Controls how sprite pixels will be blended with the scene.
|
||||
*/
|
||||
public enum BlendMode {
|
||||
/**
|
||||
* Emulate blending behavior of {@code BlockRenderLayer} associated with the block.
|
||||
* Emulate blending behavior of the {@link RenderLayer} associated with the block state through
|
||||
* {@link RenderLayers}.
|
||||
*/
|
||||
DEFAULT(null),
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package net.fabricmc.fabric.api.renderer.v1.material;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
@ -34,33 +35,42 @@ import net.fabricmc.fabric.api.util.TriState;
|
|||
*/
|
||||
public interface MaterialFinder extends MaterialView {
|
||||
/**
|
||||
* Defines how sprite pixels will be blended with the scene.
|
||||
* Controls how sprite pixels should be blended with the scene.
|
||||
*
|
||||
* <p>See {@link BlendMode} for more information.
|
||||
* <p>The default value is {@link BlendMode#DEFAULT}.
|
||||
*
|
||||
* @see BlendMode
|
||||
*/
|
||||
MaterialFinder blendMode(BlendMode blendMode);
|
||||
|
||||
/**
|
||||
* Vertex color(s) will be modified for quad color index unless disabled.
|
||||
* Controls whether vertex colors should be modified for quad coloring. This property
|
||||
* is inverted, so a value of {@code false} means that quad coloring will be applied.
|
||||
*
|
||||
* <p>The default value is {@code false}.
|
||||
*/
|
||||
MaterialFinder disableColorIndex(boolean disable);
|
||||
|
||||
/**
|
||||
* When true, sprite texture and color will be rendered at full brightness.
|
||||
* Lightmap values provided via {@link QuadEmitter#lightmap(int)} will be ignored.
|
||||
* False by default
|
||||
*
|
||||
* <p>This is the preferred method for emissive lighting effects. Some renderers
|
||||
* with advanced lighting models may not use block lightmaps and this method will
|
||||
* with advanced lighting pipelines may not use block lightmaps and this method will
|
||||
* allow per-sprite emissive lighting in future extensions that support overlay sprites.
|
||||
*
|
||||
* <p>Note that color will still be modified by diffuse shading and ambient occlusion,
|
||||
* unless disabled via {@link #disableDiffuse(boolean)} and {@link #ambientOcclusion(TriState)}.
|
||||
*
|
||||
* <p>The default value is {@code false}.
|
||||
*/
|
||||
MaterialFinder emissive(boolean isEmissive);
|
||||
|
||||
/**
|
||||
* Vertex color(s) will be modified for diffuse shading unless disabled.
|
||||
* Controls whether vertex colors should be modified for diffuse shading. This property
|
||||
* is inverted, so a value of {@code false} means that diffuse shading will be applied.
|
||||
*
|
||||
* <p>The default value is {@code false}.
|
||||
*
|
||||
* <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.
|
||||
|
@ -68,11 +78,15 @@ public interface MaterialFinder extends MaterialView {
|
|||
MaterialFinder disableDiffuse(boolean disable);
|
||||
|
||||
/**
|
||||
* Controls whether vertex color(s) will be modified for ambient occlusion.
|
||||
* Controls whether vertex colors should be modified for ambient occlusion.
|
||||
*
|
||||
* <p>By default, ambient occlusion will be used if {@link BakedModel#useAmbientOcclusion() the model uses ambient occlusion}
|
||||
* 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>If set to {@link TriState#DEFAULT}, ambient occlusion will be used if
|
||||
* {@linkplain BakedModel#useAmbientOcclusion() the model uses ambient occlusion} and the block state has
|
||||
* {@linkplain BlockState#getLuminance() a luminance} of 0. Set to {@link TriState#TRUE} or {@link TriState#FALSE}
|
||||
* to override this behavior. {@link TriState#TRUE} will not have an effect if
|
||||
* {@linkplain MinecraftClient#isAmbientOcclusionEnabled() ambient occlusion is disabled globally}.
|
||||
*
|
||||
* <p>The default value is {@link TriState#DEFAULT}.
|
||||
*
|
||||
* <p>This property is respected only in block contexts. It will not have an effect in other contexts.
|
||||
*/
|
||||
|
@ -81,14 +95,33 @@ public interface MaterialFinder extends MaterialView {
|
|||
/**
|
||||
* 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>If set to {@link TriState#DEFAULT}, glint will be applied in item contexts if
|
||||
* {@linkplain ItemStack#hasGlint() the item stack has glint}. Set to {@link TriState#TRUE} or
|
||||
* {@link TriState#FALSE} to override this behavior.
|
||||
*
|
||||
* <p>The default value is {@link TriState#DEFAULT}.
|
||||
*
|
||||
* <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.
|
||||
*/
|
||||
MaterialFinder glint(TriState mode);
|
||||
|
||||
/**
|
||||
* A hint to the renderer about how the quad is intended to be shaded, for example through ambient occlusion and
|
||||
* diffuse shading. The renderer is free to ignore this hint.
|
||||
*
|
||||
* <p>The default value is {@link ShadeMode#ENHANCED}.
|
||||
*
|
||||
* <p>This property is respected only in block contexts. It will not have an effect in other contexts.
|
||||
*
|
||||
* @see ShadeMode
|
||||
*
|
||||
* @apiNote The default implementation will be removed in the next breaking release.
|
||||
*/
|
||||
default MaterialFinder shadeMode(ShadeMode mode) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all properties from the given {@link MaterialView} to this material finder.
|
||||
*/
|
||||
|
|
|
@ -54,4 +54,13 @@ public interface MaterialView {
|
|||
* @see MaterialFinder#glint(TriState)
|
||||
*/
|
||||
TriState glint();
|
||||
|
||||
/**
|
||||
* @see MaterialFinder#shadeMode(ShadeMode)
|
||||
*
|
||||
* @apiNote The default implementation will be removed in the next breaking release.
|
||||
*/
|
||||
default ShadeMode shadeMode() {
|
||||
return ShadeMode.ENHANCED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A hint to the renderer about how the quad is intended to be shaded, for example through ambient occlusion and
|
||||
* diffuse shading. The renderer is free to ignore this hint.
|
||||
*/
|
||||
public enum ShadeMode {
|
||||
/**
|
||||
* Conveys the intent that shading should be generally consistent, lack edge cases, and produce visually pleasing
|
||||
* results, even for quads that are not used by vanilla or are not possible to create through resource packs in
|
||||
* vanilla.
|
||||
*/
|
||||
ENHANCED,
|
||||
|
||||
/**
|
||||
* Conveys the intent that shading should mimic vanilla results, potentially to preserve certain visuals produced
|
||||
* by resource packs that modify models.
|
||||
*/
|
||||
VANILLA;
|
||||
}
|
|
@ -94,7 +94,7 @@ public interface FabricBakedModel {
|
|||
* @param context Accepts model output.
|
||||
*/
|
||||
default void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
VanillaModelEncoder.emitBlockQuads((BakedModel) this, state, randomSupplier, context, context.getEmitter());
|
||||
VanillaModelEncoder.emitBlockQuads((BakedModel) this, state, randomSupplier, context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
@ -46,7 +47,7 @@ public final class ModelHelper {
|
|||
* Null is returned as {@link #NULL_FACE_ID}.
|
||||
* Use {@link #faceFromIndex(int)} to retrieve encoded face.
|
||||
*/
|
||||
public static int toFaceIndex(Direction face) {
|
||||
public static int toFaceIndex(@Nullable Direction face) {
|
||||
return face == null ? NULL_FACE_ID : face.getId();
|
||||
}
|
||||
|
||||
|
@ -57,6 +58,7 @@ public final class ModelHelper {
|
|||
* optionally including the null face. (Use < or <= {@link #NULL_FACE_ID}
|
||||
* to exclude or include the null value, respectively.)
|
||||
*/
|
||||
@Nullable
|
||||
public static Direction faceFromIndex(int faceIndex) {
|
||||
return FACES[faceIndex];
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import net.minecraft.util.math.random.Random;
|
|||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
|
||||
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;
|
||||
|
@ -41,12 +42,12 @@ import net.fabricmc.fabric.api.util.TriState;
|
|||
*/
|
||||
public class VanillaModelEncoder {
|
||||
private static final Renderer RENDERER = RendererAccess.INSTANCE.getRenderer();
|
||||
private static final RenderMaterial MATERIAL_STANDARD = RENDERER.materialFinder().find();
|
||||
private static final RenderMaterial MATERIAL_NO_AO = RENDERER.materialFinder().ambientOcclusion(TriState.FALSE).find();
|
||||
private static final RenderMaterial STANDARD_MATERIAL = RENDERER.materialFinder().shadeMode(ShadeMode.VANILLA).find();
|
||||
private static final RenderMaterial NO_AO_MATERIAL = RENDERER.materialFinder().shadeMode(ShadeMode.VANILLA).ambientOcclusion(TriState.FALSE).find();
|
||||
|
||||
// Separate QuadEmitter parameter so that Indigo can pass its own emitter that handles vanilla quads differently.
|
||||
public static void emitBlockQuads(BakedModel model, @Nullable BlockState state, Supplier<Random> randomSupplier, RenderContext context, QuadEmitter emitter) {
|
||||
final RenderMaterial defaultMaterial = model.useAmbientOcclusion() ? MATERIAL_STANDARD : MATERIAL_NO_AO;
|
||||
public static void emitBlockQuads(BakedModel model, @Nullable BlockState state, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
QuadEmitter emitter = context.getEmitter();
|
||||
final RenderMaterial defaultMaterial = model.useAmbientOcclusion() ? STANDARD_MATERIAL : NO_AO_MATERIAL;
|
||||
|
||||
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
|
||||
final Direction cullFace = ModelHelper.faceFromIndex(i);
|
||||
|
@ -77,7 +78,7 @@ public class VanillaModelEncoder {
|
|||
|
||||
for (int j = 0; j < count; j++) {
|
||||
final BakedQuad q = quads.get(j);
|
||||
emitter.fromVanilla(q, MATERIAL_STANDARD, cullFace);
|
||||
emitter.fromVanilla(q, STANDARD_MATERIAL, cullFace);
|
||||
emitter.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.renderer",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"client.BakedModelMixin",
|
||||
"client.MultipartBakedModelMixin",
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.test.renderer;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.BooleanProperty;
|
||||
|
||||
public class OctagonalColumnBlock extends Block {
|
||||
public static final BooleanProperty VANILLA_SHADE_MODE = BooleanProperty.of("vanilla_shade_mode");
|
||||
|
||||
public OctagonalColumnBlock(Settings settings) {
|
||||
super(settings);
|
||||
setDefaultState(getDefaultState().with(VANILLA_SHADE_MODE, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||
builder.add(VANILLA_SHADE_MODE);
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ public final class Registration {
|
|||
public static final FrameBlock FRAME_MULTIPART_BLOCK = register("frame_multipart", new FrameBlock(AbstractBlock.Settings.copy(Blocks.IRON_BLOCK).nonOpaque()));
|
||||
public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(AbstractBlock.Settings.copy(Blocks.IRON_BLOCK).nonOpaque()));
|
||||
public static final Block PILLAR_BLOCK = register("pillar", new Block(AbstractBlock.Settings.create()));
|
||||
public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(AbstractBlock.Settings.create().nonOpaque().strength(1.8F)));
|
||||
public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new OctagonalColumnBlock(AbstractBlock.Settings.create().nonOpaque().strength(1.8F)));
|
||||
public static final Block RIVERSTONE_BLOCK = register("riverstone", new Block(AbstractBlock.Settings.copy(Blocks.STONE)));
|
||||
|
||||
public static final FrameBlock[] FRAME_BLOCKS = new FrameBlock[] {
|
||||
|
|
|
@ -24,6 +24,7 @@ import net.minecraft.client.render.model.UnbakedModel;
|
|||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ModelResolver;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
|
||||
import net.fabricmc.fabric.test.renderer.RendererTest;
|
||||
|
||||
public class ModelResolverImpl implements ModelResolver {
|
||||
|
@ -44,6 +45,10 @@ public class ModelResolverImpl implements ModelResolver {
|
|||
RendererTest.id("item/octagonal_column")
|
||||
);
|
||||
|
||||
private static final Set<Identifier> OCTAGONAL_COLUMN_VANILLA_MODEL_LOCATIONS = Set.of(
|
||||
RendererTest.id("block/octagonal_column_vanilla")
|
||||
);
|
||||
|
||||
private static final Set<Identifier> RIVERSTONE_MODEL_LOCATIONS = Set.of(
|
||||
RendererTest.id("block/riverstone"),
|
||||
RendererTest.id("item/riverstone")
|
||||
|
@ -63,7 +68,11 @@ public class ModelResolverImpl implements ModelResolver {
|
|||
}
|
||||
|
||||
if (OCTAGONAL_COLUMN_MODEL_LOCATIONS.contains(id)) {
|
||||
return new OctagonalColumnUnbakedModel();
|
||||
return new OctagonalColumnUnbakedModel(ShadeMode.ENHANCED);
|
||||
}
|
||||
|
||||
if (OCTAGONAL_COLUMN_VANILLA_MODEL_LOCATIONS.contains(id)) {
|
||||
return new OctagonalColumnUnbakedModel(ShadeMode.VANILLA);
|
||||
}
|
||||
|
||||
if (RIVERSTONE_MODEL_LOCATIONS.contains(id)) {
|
||||
|
|
|
@ -36,6 +36,7 @@ import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
|||
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.material.ShadeMode;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
|
@ -49,6 +50,12 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
|
|||
private static final float A = (float) (1 - Math.sqrt(2) / 2);
|
||||
private static final float B = (float) (Math.sqrt(2) / 2);
|
||||
|
||||
private final ShadeMode shadeMode;
|
||||
|
||||
public OctagonalColumnUnbakedModel(ShadeMode shadeMode) {
|
||||
this.shadeMode = shadeMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return Collections.emptySet();
|
||||
|
@ -58,8 +65,8 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
|
|||
public void setParents(Function<Identifier, UnbakedModel> modelLoader) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@Nullable
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer) {
|
||||
if (!RendererAccess.INSTANCE.hasRenderer()) {
|
||||
return null;
|
||||
|
@ -69,7 +76,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
|
|||
|
||||
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
MaterialFinder finder = renderer.materialFinder();
|
||||
RenderMaterial glintMaterial = finder.glint(TriState.TRUE).find();
|
||||
RenderMaterial glintMaterial = finder.glint(TriState.TRUE).shadeMode(shadeMode).find();
|
||||
|
||||
MeshBuilder builder = renderer.meshBuilder();
|
||||
QuadEmitter emitter = builder.getEmitter();
|
||||
|
|
|
@ -41,6 +41,8 @@ public class RiverstoneUnbakedModel implements UnbakedModel {
|
|||
|
||||
@Override
|
||||
public void setParents(Function<Identifier, UnbakedModel> modelLoader) {
|
||||
modelLoader.apply(STONE_MODEL_ID).setParents(modelLoader);
|
||||
modelLoader.apply(GOLD_BLOCK_MODEL_ID).setParents(modelLoader);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-renderer-api-v1-testmod:block/octagonal_column" }
|
||||
"vanilla_shade_mode=false": { "model": "fabric-renderer-api-v1-testmod:block/octagonal_column" },
|
||||
"vanilla_shade_mode=true": { "model": "fabric-renderer-api-v1-testmod:block/octagonal_column_vanilla" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ 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.material.MaterialFinderImpl;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.material.RenderMaterialImpl;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MeshBuilderImpl;
|
||||
|
||||
/**
|
||||
|
@ -64,7 +65,7 @@ public class IndigoRenderer implements Renderer {
|
|||
if (materialMap.containsKey(id)) return false;
|
||||
|
||||
// cast to prevent acceptance of impostor implementations
|
||||
materialMap.put(id, material);
|
||||
materialMap.put(id, (RenderMaterialImpl) material);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ import net.minecraft.world.LightType;
|
|||
import net.fabricmc.fabric.impl.client.indigo.Indigo;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoFace.WeightFunction;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.QuadViewImpl;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
||||
|
||||
|
@ -105,41 +104,23 @@ public abstract class AoCalculator {
|
|||
completionFlags = 0;
|
||||
}
|
||||
|
||||
public void compute(MutableQuadViewImpl quad, boolean isVanilla) {
|
||||
public void compute(QuadViewImpl quad, boolean vanillaShade) {
|
||||
final AoConfig config = Indigo.AMBIENT_OCCLUSION_MODE;
|
||||
final boolean shouldCompare;
|
||||
|
||||
switch (config) {
|
||||
case VANILLA:
|
||||
calcVanilla(quad);
|
||||
|
||||
// no point in comparing vanilla with itself
|
||||
shouldCompare = false;
|
||||
break;
|
||||
|
||||
case EMULATE:
|
||||
calcFastVanilla(quad);
|
||||
shouldCompare = Indigo.DEBUG_COMPARE_LIGHTING && isVanilla;
|
||||
break;
|
||||
|
||||
case HYBRID:
|
||||
default:
|
||||
if (isVanilla) {
|
||||
shouldCompare = Indigo.DEBUG_COMPARE_LIGHTING;
|
||||
case VANILLA -> calcVanilla(quad);
|
||||
case EMULATE -> calcFastVanilla(quad);
|
||||
case HYBRID -> {
|
||||
if (vanillaShade) {
|
||||
calcFastVanilla(quad);
|
||||
} else {
|
||||
shouldCompare = false;
|
||||
calcEnhanced(quad);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ENHANCED:
|
||||
shouldCompare = false;
|
||||
calcEnhanced(quad);
|
||||
}
|
||||
case ENHANCED -> calcEnhanced(quad);
|
||||
}
|
||||
|
||||
if (shouldCompare) {
|
||||
if (Indigo.DEBUG_COMPARE_LIGHTING && vanillaShade && (config == AoConfig.EMULATE || config == AoConfig.HYBRID)) {
|
||||
float[] vanillaAo = new float[4];
|
||||
int[] vanillaLight = new int[4];
|
||||
calcVanilla(quad, vanillaAo, vanillaLight);
|
||||
|
@ -158,7 +139,7 @@ public abstract class AoCalculator {
|
|||
}
|
||||
}
|
||||
|
||||
private void calcVanilla(MutableQuadViewImpl quad) {
|
||||
private void calcVanilla(QuadViewImpl quad) {
|
||||
calcVanilla(quad, ao, light);
|
||||
}
|
||||
|
||||
|
@ -169,7 +150,7 @@ public abstract class AoCalculator {
|
|||
private final BitSet vanillaAoControlBits = new BitSet(3);
|
||||
private final int[] vertexData = new int[EncodingFormat.QUAD_STRIDE];
|
||||
|
||||
private void calcVanilla(MutableQuadViewImpl quad, float[] aoDest, int[] lightDest) {
|
||||
private void calcVanilla(QuadViewImpl quad, float[] aoDest, int[] lightDest) {
|
||||
vanillaAoControlBits.clear();
|
||||
final Direction lightFace = quad.lightFace();
|
||||
quad.toVanilla(vertexData, 0);
|
||||
|
@ -181,7 +162,7 @@ public abstract class AoCalculator {
|
|||
System.arraycopy(vanillaCalc.light, 0, lightDest, 0, 4);
|
||||
}
|
||||
|
||||
private void calcFastVanilla(MutableQuadViewImpl quad) {
|
||||
private void calcFastVanilla(QuadViewImpl quad) {
|
||||
int flags = quad.geometryFlags();
|
||||
|
||||
// force to block face if shape is full cube - matches vanilla logic
|
||||
|
@ -196,7 +177,7 @@ public abstract class AoCalculator {
|
|||
}
|
||||
}
|
||||
|
||||
private void calcEnhanced(MutableQuadViewImpl quad) {
|
||||
private void calcEnhanced(QuadViewImpl quad) {
|
||||
switch (quad.geometryFlags()) {
|
||||
case AXIS_ALIGNED_FLAG | CUBIC_FLAG | LIGHT_FACE_FLAG:
|
||||
case AXIS_ALIGNED_FLAG | LIGHT_FACE_FLAG:
|
||||
|
@ -271,7 +252,7 @@ public abstract class AoCalculator {
|
|||
/** used exclusively in irregular face to avoid new heap allocations each call. */
|
||||
private final Vector3f vertexNormal = new Vector3f();
|
||||
|
||||
private void irregularFace(MutableQuadViewImpl quad, boolean shade) {
|
||||
private void irregularFace(QuadViewImpl quad, boolean shade) {
|
||||
final Vector3f faceNorm = quad.faceNormal();
|
||||
Vector3f normal;
|
||||
final float[] w = this.w;
|
||||
|
|
|
@ -22,6 +22,7 @@ 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.renderer.v1.material.ShadeMode;
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
|
||||
public class MaterialFinderImpl extends MaterialViewImpl implements MaterialFinder {
|
||||
|
@ -84,6 +85,14 @@ public class MaterialFinderImpl extends MaterialViewImpl implements MaterialFind
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialFinder shadeMode(ShadeMode mode) {
|
||||
Objects.requireNonNull(mode, "ShadeMode may not be null");
|
||||
|
||||
bits = (bits & ~SHADE_MODE_MASK) | (mode.ordinal() << SHADE_MODE_BIT_OFFSET);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialFinder copyFrom(MaterialView material) {
|
||||
bits = ((MaterialViewImpl) material).bits;
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.client.indigo.renderer.material;
|
||||
|
||||
import static net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat.bitMask;
|
||||
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.MaterialView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
|
||||
/**
|
||||
|
@ -33,6 +36,8 @@ public class MaterialViewImpl implements MaterialView {
|
|||
private static final int BLEND_MODE_COUNT = BLEND_MODES.length;
|
||||
private static final TriState[] TRI_STATES = TriState.values();
|
||||
private static final int TRI_STATE_COUNT = TRI_STATES.length;
|
||||
private static final ShadeMode[] SHADE_MODES = ShadeMode.values();
|
||||
private static final int SHADE_MODE_COUNT = SHADE_MODES.length;
|
||||
|
||||
protected static final int BLEND_MODE_BIT_LENGTH = MathHelper.ceilLog2(BLEND_MODE_COUNT);
|
||||
protected static final int COLOR_DISABLE_BIT_LENGTH = 1;
|
||||
|
@ -40,6 +45,7 @@ public class MaterialViewImpl implements MaterialView {
|
|||
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 SHADE_MODE_BIT_LENGTH = MathHelper.ceilLog2(SHADE_MODE_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;
|
||||
|
@ -47,7 +53,8 @@ public class MaterialViewImpl implements MaterialView {
|
|||
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 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 SHADE_MODE_BIT_OFFSET = GLINT_BIT_OFFSET + GLINT_BIT_LENGTH;
|
||||
public static final int TOTAL_BIT_LENGTH = SHADE_MODE_BIT_OFFSET + SHADE_MODE_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);
|
||||
|
@ -55,19 +62,18 @@ public class MaterialViewImpl implements MaterialView {
|
|||
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);
|
||||
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;
|
||||
}
|
||||
protected static final int SHADE_MODE_MASK = bitMask(SHADE_MODE_BIT_LENGTH, SHADE_MODE_BIT_OFFSET);
|
||||
|
||||
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;
|
||||
int shadeMode = (bits & SHADE_MODE_MASK) >>> SHADE_MODE_BIT_OFFSET;
|
||||
|
||||
return blendMode < BLEND_MODE_COUNT
|
||||
&& ao < TRI_STATE_COUNT
|
||||
&& glint < TRI_STATE_COUNT;
|
||||
&& glint < TRI_STATE_COUNT
|
||||
&& shadeMode < SHADE_MODE_COUNT;
|
||||
}
|
||||
|
||||
protected int bits;
|
||||
|
@ -105,4 +111,9 @@ public class MaterialViewImpl implements MaterialView {
|
|||
public TriState glint() {
|
||||
return TRI_STATES[(bits & GLINT_MASK) >>> GLINT_BIT_OFFSET];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShadeMode shadeMode() {
|
||||
return SHADE_MODES[(bits & SHADE_MODE_MASK) >>> SHADE_MODE_BIT_OFFSET];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package net.fabricmc.fabric.impl.client.indigo.renderer.mesh;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
|
@ -26,6 +27,7 @@ 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.helper.GeometryHelper;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.material.MaterialViewImpl;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.material.RenderMaterialImpl;
|
||||
|
||||
/**
|
||||
|
@ -78,66 +80,75 @@ public abstract class EncodingFormat {
|
|||
/** used for quick clearing of quad buffers. */
|
||||
static final int[] EMPTY = new int[TOTAL_STRIDE];
|
||||
|
||||
private static final int DIRECTION_MASK = MathHelper.smallestEncompassingPowerOfTwo(ModelHelper.NULL_FACE_ID) - 1;
|
||||
private static final int DIRECTION_BIT_COUNT = Integer.bitCount(DIRECTION_MASK);
|
||||
private static final int CULL_SHIFT = 0;
|
||||
private static final int CULL_INVERSE_MASK = ~(DIRECTION_MASK << CULL_SHIFT);
|
||||
private static final int LIGHT_SHIFT = CULL_SHIFT + DIRECTION_BIT_COUNT;
|
||||
private static final int LIGHT_INVERSE_MASK = ~(DIRECTION_MASK << LIGHT_SHIFT);
|
||||
private static final int NORMALS_SHIFT = LIGHT_SHIFT + DIRECTION_BIT_COUNT;
|
||||
private static final int NORMALS_COUNT = 4;
|
||||
private static final int NORMALS_MASK = (1 << NORMALS_COUNT) - 1;
|
||||
private static final int NORMALS_INVERSE_MASK = ~(NORMALS_MASK << NORMALS_SHIFT);
|
||||
private static final int GEOMETRY_SHIFT = NORMALS_SHIFT + NORMALS_COUNT;
|
||||
private static final int GEOMETRY_MASK = (1 << GeometryHelper.FLAG_BIT_COUNT) - 1;
|
||||
private static final int GEOMETRY_INVERSE_MASK = ~(GEOMETRY_MASK << GEOMETRY_SHIFT);
|
||||
private static final int MATERIAL_SHIFT = GEOMETRY_SHIFT + GeometryHelper.FLAG_BIT_COUNT;
|
||||
private static final int MATERIAL_MASK = MathHelper.smallestEncompassingPowerOfTwo(RenderMaterialImpl.VALUE_COUNT) - 1;
|
||||
private static final int MATERIAL_BIT_COUNT = Integer.bitCount(MATERIAL_MASK);
|
||||
private static final int MATERIAL_INVERSE_MASK = ~(MATERIAL_MASK << MATERIAL_SHIFT);
|
||||
private static final int DIRECTION_COUNT = Direction.values().length;
|
||||
private static final int NULLABLE_DIRECTION_COUNT = DIRECTION_COUNT + 1;
|
||||
|
||||
private static final int CULL_BIT_LENGTH = MathHelper.ceilLog2(NULLABLE_DIRECTION_COUNT);
|
||||
private static final int LIGHT_BIT_LENGTH = MathHelper.ceilLog2(DIRECTION_COUNT);
|
||||
private static final int NORMALS_BIT_LENGTH = 4;
|
||||
private static final int GEOMETRY_BIT_LENGTH = GeometryHelper.FLAG_BIT_COUNT;
|
||||
private static final int MATERIAL_BIT_LENGTH = MaterialViewImpl.TOTAL_BIT_LENGTH;
|
||||
|
||||
private static final int CULL_BIT_OFFSET = 0;
|
||||
private static final int LIGHT_BIT_OFFSET = CULL_BIT_OFFSET + CULL_BIT_LENGTH;
|
||||
private static final int NORMALS_BIT_OFFSET = LIGHT_BIT_OFFSET + LIGHT_BIT_LENGTH;
|
||||
private static final int GEOMETRY_BIT_OFFSET = NORMALS_BIT_OFFSET + NORMALS_BIT_LENGTH;
|
||||
private static final int MATERIAL_BIT_OFFSET = GEOMETRY_BIT_OFFSET + GEOMETRY_BIT_LENGTH;
|
||||
private static final int TOTAL_BIT_LENGTH = MATERIAL_BIT_OFFSET + MATERIAL_BIT_LENGTH;
|
||||
|
||||
private static final int CULL_MASK = bitMask(CULL_BIT_LENGTH, CULL_BIT_OFFSET);
|
||||
private static final int LIGHT_MASK = bitMask(LIGHT_BIT_LENGTH, LIGHT_BIT_OFFSET);
|
||||
private static final int NORMALS_MASK = bitMask(NORMALS_BIT_LENGTH, NORMALS_BIT_OFFSET);
|
||||
private static final int GEOMETRY_MASK = bitMask(GEOMETRY_BIT_LENGTH, GEOMETRY_BIT_OFFSET);
|
||||
private static final int MATERIAL_MASK = bitMask(MATERIAL_BIT_LENGTH, MATERIAL_BIT_OFFSET);
|
||||
|
||||
static {
|
||||
Preconditions.checkArgument(MATERIAL_SHIFT + MATERIAL_BIT_COUNT <= 32, "Indigo header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE);
|
||||
Preconditions.checkArgument(TOTAL_BIT_LENGTH <= 32, "Indigo header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE);
|
||||
}
|
||||
|
||||
public static int bitMask(int bitLength, int bitOffset) {
|
||||
return ((1 << bitLength) - 1) << bitOffset;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Direction cullFace(int bits) {
|
||||
return ModelHelper.faceFromIndex((bits >>> CULL_SHIFT) & DIRECTION_MASK);
|
||||
return ModelHelper.faceFromIndex((bits & CULL_MASK) >>> CULL_BIT_OFFSET);
|
||||
}
|
||||
|
||||
static int cullFace(int bits, Direction face) {
|
||||
return (bits & CULL_INVERSE_MASK) | (ModelHelper.toFaceIndex(face) << CULL_SHIFT);
|
||||
static int cullFace(int bits, @Nullable Direction face) {
|
||||
return (bits & ~CULL_MASK) | (ModelHelper.toFaceIndex(face) << CULL_BIT_OFFSET);
|
||||
}
|
||||
|
||||
static Direction lightFace(int bits) {
|
||||
return ModelHelper.faceFromIndex((bits >>> LIGHT_SHIFT) & DIRECTION_MASK);
|
||||
return ModelHelper.faceFromIndex((bits & LIGHT_MASK) >>> LIGHT_BIT_OFFSET);
|
||||
}
|
||||
|
||||
static int lightFace(int bits, Direction face) {
|
||||
return (bits & LIGHT_INVERSE_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_SHIFT);
|
||||
return (bits & ~LIGHT_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_BIT_OFFSET);
|
||||
}
|
||||
|
||||
/** indicate if vertex normal has been set - bits correspond to vertex ordinals. */
|
||||
static int normalFlags(int bits) {
|
||||
return (bits >>> NORMALS_SHIFT) & NORMALS_MASK;
|
||||
return (bits & NORMALS_MASK) >>> NORMALS_BIT_OFFSET;
|
||||
}
|
||||
|
||||
static int normalFlags(int bits, int normalFlags) {
|
||||
return (bits & NORMALS_INVERSE_MASK) | ((normalFlags & NORMALS_MASK) << NORMALS_SHIFT);
|
||||
return (bits & ~NORMALS_MASK) | ((normalFlags << NORMALS_BIT_OFFSET) & NORMALS_MASK);
|
||||
}
|
||||
|
||||
static int geometryFlags(int bits) {
|
||||
return (bits >>> GEOMETRY_SHIFT) & GEOMETRY_MASK;
|
||||
return (bits & GEOMETRY_MASK) >>> GEOMETRY_BIT_OFFSET;
|
||||
}
|
||||
|
||||
static int geometryFlags(int bits, int geometryFlags) {
|
||||
return (bits & GEOMETRY_INVERSE_MASK) | ((geometryFlags & GEOMETRY_MASK) << GEOMETRY_SHIFT);
|
||||
return (bits & ~GEOMETRY_MASK) | ((geometryFlags << GEOMETRY_BIT_OFFSET) & GEOMETRY_MASK);
|
||||
}
|
||||
|
||||
static RenderMaterialImpl material(int bits) {
|
||||
return RenderMaterialImpl.byIndex((bits >>> MATERIAL_SHIFT) & MATERIAL_MASK);
|
||||
return RenderMaterialImpl.byIndex((bits & MATERIAL_MASK) >>> MATERIAL_BIT_OFFSET);
|
||||
}
|
||||
|
||||
static int material(int bits, RenderMaterialImpl material) {
|
||||
return (bits & MATERIAL_INVERSE_MASK) | (material.index() << MATERIAL_SHIFT);
|
||||
return (bits & ~MATERIAL_MASK) | (material.index() << MATERIAL_BIT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.material.ShadeMode;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
import net.fabricmc.fabric.impl.client.indigo.Indigo;
|
||||
|
@ -55,18 +56,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
|
||||
@Override
|
||||
public void emitDirectly() {
|
||||
renderQuad(this, false);
|
||||
}
|
||||
};
|
||||
private final MutableQuadViewImpl vanillaModelEditorQuad = new MutableQuadViewImpl() {
|
||||
{
|
||||
data = new int[EncodingFormat.TOTAL_STRIDE];
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitDirectly() {
|
||||
renderQuad(this, true);
|
||||
renderQuad(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -88,11 +78,6 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
return editorQuad;
|
||||
}
|
||||
|
||||
public QuadEmitter getVanillaModelEmitter() {
|
||||
// Do not clear the editorQuad since it is not accessible to API users.
|
||||
return vanillaModelEditorQuad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFaceCulled(@Nullable Direction face) {
|
||||
return !blockInfo.shouldDrawFace(face);
|
||||
|
@ -108,7 +93,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
return vanillaModelConsumer;
|
||||
}
|
||||
|
||||
private void renderQuad(MutableQuadViewImpl quad, boolean isVanilla) {
|
||||
private void renderQuad(MutableQuadViewImpl quad) {
|
||||
if (!transform(quad)) {
|
||||
return;
|
||||
}
|
||||
|
@ -122,10 +107,11 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
final TriState aoMode = mat.ambientOcclusion();
|
||||
final boolean ao = blockInfo.useAo && (aoMode == TriState.TRUE || (aoMode == TriState.DEFAULT && blockInfo.defaultAo));
|
||||
final boolean emissive = mat.emissive();
|
||||
final boolean vanillaShade = mat.shadeMode() == ShadeMode.VANILLA;
|
||||
final VertexConsumer vertexConsumer = getVertexConsumer(blockInfo.effectiveRenderLayer(mat.blendMode()));
|
||||
|
||||
colorizeQuad(quad, colorIndex);
|
||||
shadeQuad(quad, isVanilla, ao, emissive);
|
||||
shadeQuad(quad, ao, emissive, vanillaShade);
|
||||
bufferQuad(quad, vertexConsumer);
|
||||
}
|
||||
|
||||
|
@ -140,10 +126,10 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
}
|
||||
}
|
||||
|
||||
private void shadeQuad(MutableQuadViewImpl quad, boolean isVanilla, boolean ao, boolean emissive) {
|
||||
private void shadeQuad(MutableQuadViewImpl quad, boolean ao, boolean emissive, boolean vanillaShade) {
|
||||
// routines below have a bit of copy-paste code reuse to avoid conditional execution inside a hot loop
|
||||
if (ao) {
|
||||
aoCalc.compute(quad, isVanilla);
|
||||
aoCalc.compute(quad, vanillaShade);
|
||||
|
||||
if (emissive) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -157,7 +143,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
shadeFlatQuad(quad, isVanilla);
|
||||
shadeFlatQuad(quad, vanillaShade);
|
||||
|
||||
if (emissive) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -177,11 +163,11 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
* Starting in 1.16 flat shading uses dimension-specific diffuse factors that can be < 1.0
|
||||
* even for un-shaded quads. These are also applied with AO shading but that is done in AO calculator.
|
||||
*/
|
||||
private void shadeFlatQuad(MutableQuadViewImpl quad, boolean isVanilla) {
|
||||
private void shadeFlatQuad(MutableQuadViewImpl quad, boolean vanillaShade) {
|
||||
final boolean hasShade = quad.hasShade();
|
||||
|
||||
// Check the AO mode to match how shade is applied during smooth lighting
|
||||
if ((Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.HYBRID && !isVanilla) || Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.ENHANCED) {
|
||||
if ((Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.HYBRID && !vanillaShade) || Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.ENHANCED) {
|
||||
if (quad.hasAllVertexNormals()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float shade = normalShade(quad.normalX(i), quad.normalY(i), quad.normalZ(i), hasShade);
|
||||
|
@ -305,7 +291,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
|
||||
@Override
|
||||
public void accept(BakedModel model, @Nullable BlockState state) {
|
||||
VanillaModelEncoder.emitBlockQuads(model, state, blockInfo.randomSupplier, AbstractBlockRenderContext.this, vanillaModelEditorQuad);
|
||||
VanillaModelEncoder.emitBlockQuads(model, state, blockInfo.randomSupplier, AbstractBlockRenderContext.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
|
@ -24,12 +24,8 @@ import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.render.chunk.BlockBufferAllocatorStorage;
|
||||
import net.minecraft.client.render.chunk.ChunkRendererRegion;
|
||||
import net.minecraft.client.util.BufferAllocator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
|
@ -69,9 +65,7 @@ public class ChunkRenderInfo {
|
|||
private final Long2IntOpenHashMap brightnessCache;
|
||||
private final Long2FloatOpenHashMap aoLevelCache;
|
||||
|
||||
private final BlockPos.Mutable chunkOrigin = new BlockPos.Mutable();
|
||||
BlockBufferAllocatorStorage builders;
|
||||
Map<RenderLayer, BufferBuilder> buffers;
|
||||
private Function<RenderLayer, BufferBuilder> bufferFunc;
|
||||
BlockRenderView blockView;
|
||||
|
||||
ChunkRenderInfo() {
|
||||
|
@ -81,31 +75,21 @@ public class ChunkRenderInfo {
|
|||
aoLevelCache.defaultReturnValue(Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
void prepare(ChunkRendererRegion blockView, BlockPos chunkOrigin, BlockBufferAllocatorStorage builders, Map<RenderLayer, BufferBuilder> buffers) {
|
||||
void prepare(ChunkRendererRegion blockView, Function<RenderLayer, BufferBuilder> bufferFunc) {
|
||||
this.blockView = blockView;
|
||||
this.chunkOrigin.set(chunkOrigin);
|
||||
this.builders = builders;
|
||||
this.buffers = buffers;
|
||||
this.bufferFunc = bufferFunc;
|
||||
|
||||
brightnessCache.clear();
|
||||
aoLevelCache.clear();
|
||||
}
|
||||
|
||||
void release() {
|
||||
blockView = null;
|
||||
bufferFunc = null;
|
||||
}
|
||||
|
||||
/** Lazily retrieves output buffer for given layer, initializing as needed. */
|
||||
public BufferBuilder getInitializedBuffer(RenderLayer renderLayer) {
|
||||
// TODO 24w21b - possibly AW class_9810#method_60903 which does the same thing?
|
||||
BufferBuilder builder = buffers.get(renderLayer);
|
||||
|
||||
if (builder == null) {
|
||||
BufferAllocator byteBuilder = builders.get(renderLayer);
|
||||
builder = new BufferBuilder(byteBuilder, VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
|
||||
|
||||
buffers.put(renderLayer, builder);
|
||||
}
|
||||
|
||||
return builder;
|
||||
BufferBuilder getBuffer(RenderLayer layer) {
|
||||
return bufferFunc.apply(layer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,14 +16,13 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.OverlayTexture;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.chunk.BlockBufferAllocatorStorage;
|
||||
import net.minecraft.client.render.chunk.ChunkRendererRegion;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
@ -69,12 +68,12 @@ public class TerrainRenderContext extends AbstractBlockRenderContext {
|
|||
|
||||
@Override
|
||||
protected VertexConsumer getVertexConsumer(RenderLayer layer) {
|
||||
return chunkInfo.getInitializedBuffer(layer);
|
||||
return chunkInfo.getBuffer(layer);
|
||||
}
|
||||
|
||||
public void prepare(ChunkRendererRegion blockView, BlockPos chunkOrigin, BlockBufferAllocatorStorage builders, Map<RenderLayer, BufferBuilder> builderMap) {
|
||||
public void prepare(ChunkRendererRegion blockView, Function<RenderLayer, BufferBuilder> bufferFunc) {
|
||||
chunkInfo.prepare(blockView, bufferFunc);
|
||||
blockInfo.prepareForWorld(blockView, true);
|
||||
chunkInfo.prepare(blockView, chunkOrigin, builders, builderMap);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* 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.client.indigo.renderer;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
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.model.FabricBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
|
||||
import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
|
||||
|
||||
@Mixin(BakedModel.class)
|
||||
public interface BakedModelMixin extends FabricBakedModel {
|
||||
/**
|
||||
* Override the fallback path to shade vanilla quads differently.
|
||||
*/
|
||||
@Override
|
||||
default void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
VanillaModelEncoder.emitBlockQuads((BakedModel) this, state, randomSupplier, context, ((AbstractBlockRenderContext) context).getVanillaModelEmitter());
|
||||
}
|
||||
}
|
|
@ -17,11 +17,11 @@
|
|||
package net.fabricmc.fabric.mixin.client.indigo.renderer;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.systems.VertexSorter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
@ -30,7 +30,6 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
|||
|
||||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
|
@ -67,17 +66,19 @@ import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderConte
|
|||
*/
|
||||
@Mixin(SectionBuilder.class)
|
||||
public abstract class SectionBuilderMixin {
|
||||
@Shadow
|
||||
abstract BufferBuilder beginBufferBuilding(Map<RenderLayer, BufferBuilder> builders, BlockBufferAllocatorStorage allocatorStorage, RenderLayer layer);
|
||||
|
||||
@Inject(method = "build",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/BlockPos;iterate(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/BlockPos;)Ljava/lang/Iterable;"),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void hookChunkBuild(ChunkSectionPos sectionPos, ChunkRendererRegion region, VertexSorter sorter,
|
||||
BlockBufferAllocatorStorage builder,
|
||||
CallbackInfoReturnable<SectionBuilder.RenderData> ci,
|
||||
private void hookBuild(ChunkSectionPos sectionPos, ChunkRendererRegion region, VertexSorter sorter,
|
||||
BlockBufferAllocatorStorage allocators,
|
||||
CallbackInfoReturnable<SectionBuilder.RenderData> cir,
|
||||
@Local(ordinal = 0) Map<RenderLayer, BufferBuilder> builderMap) {
|
||||
// hook just before iterating over the render chunk's chunks blocks, captures the buffer builder map
|
||||
|
||||
// hook just before iterating over the render chunk's blocks to capture the buffer builder map
|
||||
TerrainRenderContext renderer = TerrainRenderContext.POOL.get();
|
||||
renderer.prepare(region, sectionPos.getMinPos(), builder, builderMap);
|
||||
renderer.prepare(region, layer -> beginBufferBuilding(builderMap, allocators, layer));
|
||||
((AccessChunkRendererRegion) region).fabric_setRenderer(renderer);
|
||||
}
|
||||
|
||||
|
@ -99,7 +100,7 @@ public abstract class SectionBuilderMixin {
|
|||
*/
|
||||
@Redirect(method = "build", require = 1, at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/render/block/BlockRenderManager;renderBlock(Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;ZLnet/minecraft/util/math/random/Random;)V"))
|
||||
private void hookChunkBuildTessellate(BlockRenderManager renderManager, BlockState blockState, BlockPos blockPos, BlockRenderView blockView, MatrixStack matrix, VertexConsumer bufferBuilder, boolean checkSides, Random random) {
|
||||
private void hookBuildRenderBlock(BlockRenderManager renderManager, BlockState blockState, BlockPos blockPos, BlockRenderView blockView, MatrixStack matrix, VertexConsumer bufferBuilder, boolean checkSides, Random random) {
|
||||
if (blockState.getRenderType() == BlockRenderType.MODEL) {
|
||||
final BakedModel model = renderManager.getModel(blockState);
|
||||
|
||||
|
@ -115,11 +116,9 @@ public abstract class SectionBuilderMixin {
|
|||
/**
|
||||
* Release all references. Probably not necessary but would be $#%! to debug if it is.
|
||||
*/
|
||||
@Inject(method = "build",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModelRenderer;disableBrightnessCache()V"))
|
||||
private void hookRebuildChunkReturn(CallbackInfoReturnable<Set<BlockEntity>> ci) {
|
||||
// hook after iterating over the render chunk's chunks blocks, must be called if and only if hookChunkBuild happened
|
||||
|
||||
TerrainRenderContext.POOL.get().release();
|
||||
@Inject(method = "build", at = @At(value = "RETURN"))
|
||||
private void hookBuildReturn(ChunkSectionPos sectionPos, ChunkRendererRegion renderRegion, VertexSorter vertexSorter, BlockBufferAllocatorStorage allocatorStorage, CallbackInfoReturnable<SectionBuilder.RenderData> cir) {
|
||||
((AccessChunkRendererRegion) renderRegion).fabric_getRenderer().release();
|
||||
((AccessChunkRendererRegion) renderRegion).fabric_setRenderer(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
accessWidener v2 named
|
||||
|
||||
accessible class net/minecraft/client/render/chunk/ChunkBuilder$BuiltChunk$RebuildTask
|
||||
|
||||
accessible class net/minecraft/client/render/block/BlockModelRenderer$AmbientOcclusionCalculator
|
||||
accessible field net/minecraft/client/render/block/BlockModelRenderer$AmbientOcclusionCalculator brightness [F
|
||||
accessible field net/minecraft/client/render/block/BlockModelRenderer$AmbientOcclusionCalculator light [I
|
||||
|
||||
accessible method net/minecraft/client/render/block/BlockModelRenderer getQuadDimensions (Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;[ILnet/minecraft/util/math/Direction;[FLjava/util/BitSet;)V
|
||||
|
||||
accessible method net/minecraft/client/render/item/ItemRenderer renderBakedItemModel (Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/item/ItemStack;IILnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;)V
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.client.indigo.renderer",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"plugin": "net.fabricmc.fabric.impl.client.indigo.IndigoMixinConfigPlugin",
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"BakedModelMixin",
|
||||
"BlockModelRendererMixin",
|
||||
"ChunkRendererRegionMixin",
|
||||
"ItemRendererAccessor",
|
||||
|
|
Loading…
Reference in a new issue