mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-12 06:54:27 -04:00
Improve Indigo and FRAPI Test Mod (#3208)
* Improve flat shade - Use AO mode to make flat shade calculation consistent with shade applied by smooth lighting - Use face normal to calculate shade if necessary - Use normal shade even if no custom normals are set * Improve FRAPI test mod - Add octagonal column to test irregular face lighting - Use obsidian sprite instead of missing sprite for frame mesh - Simplify and organize registration - Inline `simple` package * Fix crumbling on 45 degree faces - Fix checkstyle - Give octagonal column a non-zero hardness * Fix checkstyle * Improve PillarBakedModel to fully support custom block appearance * Explain OverlayVertexConsumer fix
This commit is contained in:
parent
8536527b69
commit
6bdb2ed00f
22 changed files with 861 additions and 361 deletions
fabric-renderer-api-v1/src
client
java/net/fabricmc/fabric/mixin/renderer/client
resources
testmod
java/net/fabricmc/fabric/test/renderer
resources
testmodClient
java/net/fabricmc/fabric/test/renderer
client
FrameBakedModel.javaFrameUnbakedModel.javaModelResolverImpl.javaOctagonalColumnUnbakedModel.javaPillarBakedModel.javaPillarUnbakedModel.javaRendererClientTest.javaSingleMeshBakedModel.java
simple/client
resources/assets/fabric-renderer-api-v1-testmod/blockstates
fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.renderer.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import net.minecraft.client.render.OverlayVertexConsumer;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathConstants;
|
||||
|
||||
@Mixin(OverlayVertexConsumer.class)
|
||||
public class OverlayVertexConsumerMixin {
|
||||
@Unique
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
|
||||
/*
|
||||
The original method call is used to get the closest axis-aligned direction of the world-space
|
||||
normal vector for a certain face. The world-space normal vector is computed using matrices
|
||||
that change when the camera values change. Due to precision errors during matrix
|
||||
multiplication, the computed world-space normal of a face will not remain constant, so the
|
||||
closest axis-aligned direction may flicker. This issue only affects faces that are directly
|
||||
between two axis-aligned directions (45 degree faces) or three axis-aligned directions.
|
||||
|
||||
The fix involves requiring the dot product of each axis-aligned direction to be a small
|
||||
amount greater than the previous maximum dot product to be set as the new maximum.
|
||||
*/
|
||||
@Redirect(method = "next()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/Direction;getFacing(FFF)Lnet/minecraft/util/math/Direction;"))
|
||||
private Direction redirectGetFacing(float x, float y, float z) {
|
||||
Direction closestDir = Direction.NORTH;
|
||||
float maxDot = 1.4E-45F;
|
||||
|
||||
for (Direction direction : DIRECTIONS) {
|
||||
float dot = x * direction.getOffsetX() + y * direction.getOffsetY() + z * direction.getOffsetZ();
|
||||
|
||||
if (dot > maxDot + MathConstants.EPSILON) {
|
||||
maxDot = dot;
|
||||
closestDir = direction;
|
||||
}
|
||||
}
|
||||
|
||||
return closestDir;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@
|
|||
"client.BakedModelMixin",
|
||||
"client.MultipartBakedModelMixin",
|
||||
"client.WeightedBakedModelMixin",
|
||||
"client.SpriteAtlasTextureMixin"
|
||||
"client.SpriteAtlasTextureMixin",
|
||||
"client.OverlayVertexConsumerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer.simple;
|
||||
package net.fabricmc.fabric.test.renderer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -27,7 +27,6 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
@ -35,16 +34,12 @@ import net.minecraft.world.BlockRenderView;
|
|||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.block.v1.FabricBlock;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
|
||||
|
||||
// Need to implement FabricBlock manually because this is a testmod for another Fabric module, otherwise it would be injected.
|
||||
public final class FrameBlock extends Block implements BlockEntityProvider, FabricBlock {
|
||||
public final Identifier id;
|
||||
|
||||
public FrameBlock(Identifier id) {
|
||||
super(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());
|
||||
this.id = id;
|
||||
public class FrameBlock extends Block implements BlockEntityProvider, FabricBlock {
|
||||
public FrameBlock(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer.simple;
|
||||
package net.fabricmc.fabric.test.renderer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -31,12 +31,12 @@ import net.minecraft.util.math.BlockPos;
|
|||
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
|
||||
|
||||
public final class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlockEntity {
|
||||
public class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlockEntity {
|
||||
@Nullable
|
||||
private Block block = null;
|
||||
|
||||
public FrameBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||
super(RendererTest.FRAME_BLOCK_ENTITY, blockPos, blockState);
|
||||
super(Registration.FRAME_BLOCK_ENTITY_TYPE, blockPos, blockState);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.Blocks;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
|
||||
public final class Registration {
|
||||
public static final FrameBlock FRAME_BLOCK = register("frame", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()));
|
||||
public static final FrameBlock FRAME_MULTIPART_BLOCK = register("frame_multipart", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()));
|
||||
public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()));
|
||||
public static final Block PILLAR_BLOCK = register("pillar", new Block(FabricBlockSettings.create()));
|
||||
public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(FabricBlockSettings.create().nonOpaque().strength(1.8F)));
|
||||
|
||||
public static final FrameBlock[] FRAME_BLOCKS = new FrameBlock[] {
|
||||
FRAME_BLOCK,
|
||||
FRAME_MULTIPART_BLOCK,
|
||||
FRAME_VARIANT_BLOCK,
|
||||
};
|
||||
|
||||
public static final Item FRAME_ITEM = register("frame", new BlockItem(FRAME_BLOCK, new Item.Settings()));
|
||||
public static final Item FRAME_MULTIPART_ITEM = register("frame_multipart", new BlockItem(FRAME_MULTIPART_BLOCK, new Item.Settings()));
|
||||
public static final Item FRAME_VARIANT_ITEM = register("frame_variant", new BlockItem(FRAME_VARIANT_BLOCK, new Item.Settings()));
|
||||
public static final Item PILLAR_ITEM = register("pillar", new BlockItem(PILLAR_BLOCK, new Item.Settings()));
|
||||
public static final Item OCTAGONAL_COLUMN_ITEM = register("octagonal_column", new BlockItem(OCTAGONAL_COLUMN_BLOCK, new Item.Settings()));
|
||||
|
||||
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY_TYPE = register("frame", FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME_BLOCKS).build(null));
|
||||
|
||||
private static <T extends Block> T register(String path, T block) {
|
||||
return Registry.register(Registries.BLOCK, RendererTest.id(path), block);
|
||||
}
|
||||
|
||||
private static <T extends Item> T register(String path, T item) {
|
||||
return Registry.register(Registries.ITEM, RendererTest.id(path), item);
|
||||
}
|
||||
|
||||
private static <T extends BlockEntityType<?>> T register(String path, T blockEntityType) {
|
||||
return Registry.register(Registries.BLOCK_ENTITY_TYPE, RendererTest.id(path), blockEntityType);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
/**
|
||||
* The testmod for the Fabric Renderer API. These tests are used to validate that
|
||||
* Indigo's implementation is correct, but they may also be useful for other
|
||||
* implementations of the Fabric Renderer API.
|
||||
*
|
||||
* <h3>Tests</h3>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Frame blocks display another block inside, scaled down and made translucent.
|
||||
* Blocks that provide a block entity cannot be placed inside frames.
|
||||
*
|
||||
* <li>Pillars connect vertically with each other by changing textures. They also
|
||||
* connect vertically to frame blocks containing a pillar, and vice versa.
|
||||
*
|
||||
* <li>Octagonal columns have irregular faces to test enhanced AO and normal shade. The
|
||||
* octagonal item column has glint force enabled on all faces except the top and bottom
|
||||
* faces.
|
||||
* </ul>
|
||||
*/
|
||||
public final class RendererTest implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
Registration.init();
|
||||
}
|
||||
|
||||
public static Identifier id(String path) {
|
||||
return new Identifier("fabric-renderer-api-v1-testmod", path);
|
||||
}
|
||||
}
|
|
@ -1,26 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The testmod for the Fabric Renderer API.
|
||||
* Right now there is only one test here, but more tests may come to exist in the future.
|
||||
* These tests are used to validate Indigo's implementation is correct, but these tests may also be useful for other implementations of the Fabric Renderer API.
|
||||
*
|
||||
* <p>Right now there is a simple test in the {@code simple} package which validates that simple meshes and quad emitters function.
|
||||
* Future tests may look into testing things such as render materials or creating more advanced models.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer;
|
|
@ -1,68 +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.test.renderer.simple;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
|
||||
/**
|
||||
* A simple testmod that renders a simple block rendered using the fabric renderer api.
|
||||
* The block that is rendered is a simple frame that another block is rendered in.
|
||||
* Blocks that provide a block entity cannot be placed inside the frame.
|
||||
*
|
||||
* <p>There are no fancy shaders or glow that is provided by this renderer test.
|
||||
*/
|
||||
public final class RendererTest implements ModInitializer {
|
||||
public static final FrameBlock[] FRAMES = new FrameBlock[]{
|
||||
new FrameBlock(id("frame")),
|
||||
new FrameBlock(id("frame_multipart")),
|
||||
new FrameBlock(id("frame_weighted")),
|
||||
};
|
||||
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAMES).build(null);
|
||||
|
||||
public static final Identifier PILLAR_ID = id("pillar");
|
||||
public static final Block PILLAR = new Block(FabricBlockSettings.create());
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
for (FrameBlock frameBlock : FRAMES) {
|
||||
Registry.register(Registries.BLOCK, frameBlock.id, frameBlock);
|
||||
Registry.register(Registries.ITEM, frameBlock.id, new BlockItem(frameBlock, new Item.Settings()));
|
||||
}
|
||||
|
||||
// To anyone testing this: pillars are supposed to connect vertically with each other.
|
||||
// Additionally, they should also connect vertically to frame blocks containing a pillar.
|
||||
// (The frame block will not change, but adjacent pillars should adjust their textures).
|
||||
Registry.register(Registries.BLOCK, PILLAR_ID, PILLAR);
|
||||
Registry.register(Registries.ITEM, PILLAR_ID, new BlockItem(PILLAR, new Item.Settings()));
|
||||
|
||||
Registry.register(Registries.BLOCK_ENTITY_TYPE, id("frame"), FRAME_BLOCK_ENTITY);
|
||||
}
|
||||
|
||||
public static Identifier id(String path) {
|
||||
return new Identifier("fabric-renderer-api-v1-testmod", path);
|
||||
}
|
||||
}
|
|
@ -7,14 +7,15 @@
|
|||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-renderer-api-v1":"*",
|
||||
"fabric-model-loading-api-v1":"*",
|
||||
"fabric-resource-loader-v0": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.renderer.simple.RendererTest"
|
||||
"net.fabricmc.fabric.test.renderer.RendererTest"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.renderer.simple.client.RendererClientTest"
|
||||
"net.fabricmc.fabric.test.renderer.client.RendererClientTest"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer.simple.client;
|
||||
package net.fabricmc.fabric.test.renderer.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -46,13 +46,13 @@ import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
|||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
|
||||
|
||||
final class FrameBakedModel implements BakedModel {
|
||||
public class FrameBakedModel implements BakedModel {
|
||||
private final Mesh frameMesh;
|
||||
private final Sprite frameSprite;
|
||||
private final RenderMaterial translucentMaterial;
|
||||
private final RenderMaterial translucentEmissiveMaterial;
|
||||
|
||||
FrameBakedModel(Mesh frameMesh, Sprite frameSprite) {
|
||||
public FrameBakedModel(Mesh frameMesh, Sprite frameSprite) {
|
||||
this.frameMesh = frameMesh;
|
||||
this.frameSprite = frameSprite;
|
||||
|
||||
|
@ -62,46 +62,6 @@ final class FrameBakedModel implements BakedModel {
|
|||
this.translucentEmissiveMaterial = finder.blendMode(BlendMode.TRANSLUCENT).emissive(true).find();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
return Collections.emptyList(); // Renderer API makes this obsolete, so return no quads
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return true; // we want the block to have a shadow depending on the adjacent blocks
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return true; // we want the block to be lit from the side when rendered as an item
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return this.frameSprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return ModelHelper.MODEL_TRANSFORM_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
|
@ -142,7 +102,7 @@ final class FrameBakedModel implements BakedModel {
|
|||
// Emit a scaled-down fence for testing, trying both materials again.
|
||||
RenderMaterial material = stack.hasCustomName() ? translucentEmissiveMaterial : translucentMaterial;
|
||||
|
||||
ItemStack innerItem = Items.OAK_FENCE.getDefaultStack();
|
||||
ItemStack innerItem = Items.CRAFTING_TABLE.getDefaultStack();
|
||||
BakedModel innerModel = MinecraftClient.getInstance().getItemRenderer().getModel(innerItem, null, null, 0);
|
||||
|
||||
emitInnerQuads(context, material, () -> {
|
||||
|
@ -187,4 +147,44 @@ final class FrameBakedModel implements BakedModel {
|
|||
// Let's not forget to pop the transform!
|
||||
context.popTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
return Collections.emptyList(); // Renderer API makes this obsolete, so return no quads
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return true; // we want the block to have a shadow depending on the adjacent blocks
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return true; // we want the block to be lit from the side when rendered as an item
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return this.frameSprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return ModelHelper.MODEL_TRANSFORM_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.Baker;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||
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;
|
||||
|
||||
public class FrameUnbakedModel implements UnbakedModel {
|
||||
private static final SpriteIdentifier OBSIDIAN_SPRITE_ID = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier("block/obsidian"));
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParents(Function<Identifier, UnbakedModel> modelLoader) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Bake the model.
|
||||
* In this case we can prebake the frame into a mesh, but will render the contained block when we draw the quads.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
// The renderer API may not have an implementation, so we should check if it exists.
|
||||
if (!RendererAccess.INSTANCE.hasRenderer()) {
|
||||
// No renderer implementation is present.
|
||||
return null;
|
||||
}
|
||||
|
||||
Sprite obsidianSprite = textureGetter.apply(OBSIDIAN_SPRITE_ID);
|
||||
|
||||
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
MeshBuilder builder = renderer.meshBuilder();
|
||||
QuadEmitter emitter = builder.getEmitter();
|
||||
|
||||
for (Direction direction : Direction.values()) {
|
||||
// Draw outer frame
|
||||
emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.0F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.0F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.0F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.0F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
// Draw inner frame - inset by 0.9 so the frame looks like an actual mesh
|
||||
emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.9F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.9F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.9F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.9F)
|
||||
.spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
}
|
||||
|
||||
return new FrameBakedModel(builder.build(), obsidianSprite);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.client;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.test.renderer.RendererTest;
|
||||
|
||||
public class ModelResolverImpl implements ModelResolver {
|
||||
private static final Set<Identifier> FRAME_MODEL_LOCATIONS = Set.of(
|
||||
RendererTest.id("block/frame"),
|
||||
RendererTest.id("item/frame"),
|
||||
RendererTest.id("item/frame_multipart"),
|
||||
RendererTest.id("item/frame_variant")
|
||||
);
|
||||
|
||||
private static final Set<Identifier> PILLAR_MODEL_LOCATIONS = Set.of(
|
||||
RendererTest.id("block/pillar"),
|
||||
RendererTest.id("item/pillar")
|
||||
);
|
||||
|
||||
private static final Set<Identifier> OCTAGONAL_COLUMN_MODEL_LOCATIONS = Set.of(
|
||||
RendererTest.id("block/octagonal_column"),
|
||||
RendererTest.id("item/octagonal_column")
|
||||
);
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public UnbakedModel resolveModel(Context context) {
|
||||
Identifier id = context.id();
|
||||
|
||||
if (FRAME_MODEL_LOCATIONS.contains(id)) {
|
||||
return new FrameUnbakedModel();
|
||||
}
|
||||
|
||||
if (PILLAR_MODEL_LOCATIONS.contains(id)) {
|
||||
return new PillarUnbakedModel();
|
||||
}
|
||||
|
||||
if (OCTAGONAL_COLUMN_MODEL_LOCATIONS.contains(id)) {
|
||||
return new OctagonalColumnUnbakedModel();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.Baker;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
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.mesh.MeshBuilder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.util.TriState;
|
||||
|
||||
public class OctagonalColumnUnbakedModel implements UnbakedModel {
|
||||
private static final SpriteIdentifier WHITE_CONCRETE_SPRITE_ID = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier("block/white_concrete"));
|
||||
|
||||
// (B - A) is the side length of a regular octagon that fits in a unit square.
|
||||
// The line from A to B is centered on the line from 0 to 1.
|
||||
private static final float A = (float) (1 - Math.sqrt(2) / 2);
|
||||
private static final float B = (float) (Math.sqrt(2) / 2);
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParents(Function<Identifier, UnbakedModel> modelLoader) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
if (!RendererAccess.INSTANCE.hasRenderer()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Sprite whiteConcreteSprite = textureGetter.apply(WHITE_CONCRETE_SPRITE_ID);
|
||||
|
||||
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
MaterialFinder finder = renderer.materialFinder();
|
||||
RenderMaterial glintMaterial = finder.glint(TriState.TRUE).find();
|
||||
|
||||
MeshBuilder builder = renderer.meshBuilder();
|
||||
QuadEmitter emitter = builder.getEmitter();
|
||||
|
||||
// up
|
||||
|
||||
emitter.pos(0, A, 1, 0);
|
||||
emitter.pos(1, 0.5f, 1, 0.5f);
|
||||
emitter.pos(2, 1, 1, A);
|
||||
emitter.pos(3, B, 1, 0);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
emitter.pos(0, 0, 1, A);
|
||||
emitter.pos(1, 0, 1, B);
|
||||
emitter.pos(2, 0.5f, 1, 0.5f);
|
||||
emitter.pos(3, A, 1, 0);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
emitter.pos(0, 0, 1, B);
|
||||
emitter.pos(1, A, 1, 1);
|
||||
emitter.pos(2, B, 1, 1);
|
||||
emitter.pos(3, 0.5f, 1, 0.5f);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
emitter.pos(0, 0.5f, 1, 0.5f);
|
||||
emitter.pos(1, B, 1, 1);
|
||||
emitter.pos(2, 1, 1, B);
|
||||
emitter.pos(3, 1, 1, A);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// down
|
||||
|
||||
emitter.pos(0, A, 0, 1);
|
||||
emitter.pos(1, 0.5f, 0, 0.5f);
|
||||
emitter.pos(2, 1, 0, B);
|
||||
emitter.pos(3, B, 0, 1);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
emitter.pos(0, 0, 0, B);
|
||||
emitter.pos(1, 0, 0, A);
|
||||
emitter.pos(2, 0.5f, 0, 0.5f);
|
||||
emitter.pos(3, A, 0, 1);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
emitter.pos(0, 0, 0, A);
|
||||
emitter.pos(1, A, 0, 0);
|
||||
emitter.pos(2, B, 0, 0);
|
||||
emitter.pos(3, 0.5f, 0, 0.5f);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
emitter.pos(0, 0.5f, 0, 0.5f);
|
||||
emitter.pos(1, B, 0, 0);
|
||||
emitter.pos(2, 1, 0, A);
|
||||
emitter.pos(3, 1, 0, B);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// north
|
||||
emitter.pos(0, B, 1, 0);
|
||||
emitter.pos(1, B, 0, 0);
|
||||
emitter.pos(2, A, 0, 0);
|
||||
emitter.pos(3, A, 1, 0);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// northwest
|
||||
emitter.pos(0, A, 1, 0);
|
||||
emitter.pos(1, A, 0, 0);
|
||||
emitter.pos(2, 0, 0, A);
|
||||
emitter.pos(3, 0, 1, A);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// west
|
||||
emitter.pos(0, 0, 1, A);
|
||||
emitter.pos(1, 0, 0, A);
|
||||
emitter.pos(2, 0, 0, B);
|
||||
emitter.pos(3, 0, 1, B);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// southwest
|
||||
emitter.pos(0, 0, 1, B);
|
||||
emitter.pos(1, 0, 0, B);
|
||||
emitter.pos(2, A, 0, 1);
|
||||
emitter.pos(3, A, 1, 1);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// south
|
||||
emitter.pos(0, A, 1, 1);
|
||||
emitter.pos(1, A, 0, 1);
|
||||
emitter.pos(2, B, 0, 1);
|
||||
emitter.pos(3, B, 1, 1);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// southeast
|
||||
emitter.pos(0, B, 1, 1);
|
||||
emitter.pos(1, B, 0, 1);
|
||||
emitter.pos(2, 1, 0, B);
|
||||
emitter.pos(3, 1, 1, B);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// east
|
||||
emitter.pos(0, 1, 1, B);
|
||||
emitter.pos(1, 1, 0, B);
|
||||
emitter.pos(2, 1, 0, A);
|
||||
emitter.pos(3, 1, 1, A);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
// northeast
|
||||
emitter.pos(0, 1, 1, A);
|
||||
emitter.pos(1, 1, 0, A);
|
||||
emitter.pos(2, B, 0, 0);
|
||||
emitter.pos(3, B, 1, 0);
|
||||
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.material(glintMaterial);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
|
||||
return new SingleMeshBakedModel(builder.build(), whiteConcreteSprite);
|
||||
}
|
||||
}
|
|
@ -14,8 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer.simple.client;
|
||||
package net.fabricmc.fabric.test.renderer.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -34,15 +35,11 @@ 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.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;
|
||||
import net.fabricmc.fabric.test.renderer.Registration;
|
||||
|
||||
/**
|
||||
* Very crude implementation of a pillar block model that connects with pillars above and below.
|
||||
|
@ -54,16 +51,9 @@ public class PillarBakedModel implements BakedModel {
|
|||
|
||||
// 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
|
||||
|
@ -73,52 +63,67 @@ public class PillarBakedModel implements BakedModel {
|
|||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
emitQuads(context.getEmitter(), blockView, state, pos);
|
||||
}
|
||||
QuadEmitter emitter = context.getEmitter();
|
||||
// Do not use the passed state to ensure that this model connects
|
||||
// to and from blocks with a custom appearance correctly.
|
||||
BlockState worldState = blockView.getBlockState(pos);
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
emitQuads(context.getEmitter(), null, null, null);
|
||||
}
|
||||
|
||||
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()) {
|
||||
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);
|
||||
boolean connectAbove = canConnect(blockView, worldState, pos, pos.offset(Direction.UP), side);
|
||||
boolean connectBelow = canConnect(blockView, worldState, pos, pos.offset(Direction.DOWN), side);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canConnect(BlockRenderView blockView, BlockPos pos, Direction side, BlockState sourceState, BlockPos sourcePos) {
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
QuadEmitter emitter = context.getEmitter();
|
||||
|
||||
for (Direction side : Direction.values()) {
|
||||
emitter.square(side, 0, 0, 1, 1, 0);
|
||||
emitter.spriteBake(sprites[ConnectedTexture.ALONE.ordinal()], MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canConnect(BlockRenderView blockView, BlockState originState, BlockPos originPos, BlockPos otherPos, Direction side) {
|
||||
BlockState otherState = blockView.getBlockState(otherPos);
|
||||
// In this testmod we can't rely on injected interfaces - in normal mods the (FabricBlockState) cast will be unnecessary
|
||||
return ((FabricBlockState) blockView.getBlockState(pos)).getAppearance(blockView, pos, side, sourceState, sourcePos).isOf(RendererTest.PILLAR);
|
||||
BlockState originAppearance = ((FabricBlockState) originState).getAppearance(blockView, originPos, side, otherState, otherPos);
|
||||
|
||||
if (!originAppearance.isOf(Registration.PILLAR_BLOCK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockState otherAppearance = ((FabricBlockState) otherState).getAppearance(blockView, otherPos, side, originState, originPos);
|
||||
|
||||
if (!otherAppearance.isOf(Registration.PILLAR_BLOCK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
return List.of();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
|
@ -14,9 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer.simple.client;
|
||||
package net.fabricmc.fabric.test.renderer.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -32,7 +33,7 @@ import net.minecraft.client.util.SpriteIdentifier;
|
|||
import net.minecraft.screen.PlayerScreenHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
|
||||
import net.fabricmc.fabric.test.renderer.RendererTest;
|
||||
|
||||
public class PillarUnbakedModel implements UnbakedModel {
|
||||
private static final List<SpriteIdentifier> SPRITES = Stream.of("alone", "bottom", "middle", "top")
|
||||
|
@ -41,7 +42,7 @@ public class PillarUnbakedModel implements UnbakedModel {
|
|||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return List.of();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
|
@ -14,51 +14,27 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.renderer.simple.client;
|
||||
|
||||
import static net.fabricmc.fabric.test.renderer.simple.RendererTest.id;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
package net.fabricmc.fabric.test.renderer.client;
|
||||
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
|
||||
import net.fabricmc.fabric.test.renderer.simple.FrameBlock;
|
||||
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
|
||||
import net.fabricmc.fabric.test.renderer.FrameBlock;
|
||||
import net.fabricmc.fabric.test.renderer.Registration;
|
||||
|
||||
public final class RendererClientTest implements ClientModInitializer {
|
||||
private static final Set<Identifier> FRAME_MODELS = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
for (FrameBlock frameBlock : RendererTest.FRAMES) {
|
||||
ModelLoadingPlugin.register(pluginContext -> {
|
||||
pluginContext.resolveModel().register(new ModelResolverImpl());
|
||||
});
|
||||
|
||||
for (FrameBlock frameBlock : Registration.FRAME_BLOCKS) {
|
||||
// We don't specify a material for the frame mesh,
|
||||
// so it will use the default material, i.e. the one from BlockRenderLayerMap.
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(frameBlock, RenderLayer.getCutoutMipped());
|
||||
|
||||
String itemPath = Registries.ITEM.getId(frameBlock.asItem()).getPath();
|
||||
FRAME_MODELS.add(id("item/" + itemPath));
|
||||
}
|
||||
|
||||
FRAME_MODELS.add(id("block/frame"));
|
||||
|
||||
ModelLoadingPlugin.register(pluginContext -> {
|
||||
pluginContext.resolveModel().register(context -> {
|
||||
if (FRAME_MODELS.contains(context.id())) {
|
||||
return new FrameUnbakedModel();
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
pluginContext.registerBlockStateResolver(RendererTest.PILLAR, context -> {
|
||||
context.setModel(context.block().getDefaultState(), new PillarUnbakedModel());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
|
||||
public class SingleMeshBakedModel implements BakedModel {
|
||||
private final Mesh mesh;
|
||||
private final Sprite particleSprite;
|
||||
|
||||
public SingleMeshBakedModel(Mesh mesh, Sprite particleSprite) {
|
||||
this.mesh = mesh;
|
||||
this.particleSprite = particleSprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
mesh.outputTo(context.getEmitter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
mesh.outputTo(context.getEmitter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return particleSprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return ModelHelper.MODEL_TRANSFORM_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
}
|
|
@ -1,120 +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.test.renderer.simple.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.Baker;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||
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;
|
||||
|
||||
final class FrameUnbakedModel implements UnbakedModel {
|
||||
FrameUnbakedModel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParents(Function<Identifier, UnbakedModel> function) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Bake the model.
|
||||
* In this case we can prebake the frame into a mesh, but will render the contained block when we draw the quads.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
// The renderer api may not have an implementation.
|
||||
// For this reason we will just null check the renderer impl
|
||||
if (RendererAccess.INSTANCE.hasRenderer()) {
|
||||
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
||||
MeshBuilder builder = renderer.meshBuilder();
|
||||
QuadEmitter emitter = builder.getEmitter();
|
||||
// TODO: Just some random texture to get a missing texture, we should get a proper texture soon
|
||||
Sprite frameSprite = textureGetter.apply(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier("foo:foo")));
|
||||
|
||||
for (Direction direction : Direction.values()) {
|
||||
// Draw outer frame
|
||||
emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.0F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.0F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.0F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.0F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
// Draw inner frame - inset by 0.9 so the frame looks like an actual mesh
|
||||
emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.9F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.9F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.9F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
|
||||
emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.9F)
|
||||
.spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV)
|
||||
.color(-1, -1, -1, -1)
|
||||
.emit();
|
||||
}
|
||||
|
||||
return new FrameBakedModel(builder.build(), frameSprite);
|
||||
}
|
||||
|
||||
// No renderer implementation is present.
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-renderer-api-v1-testmod:block/octagonal_column" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-renderer-api-v1-testmod:block/pillar" }
|
||||
}
|
||||
}
|
|
@ -173,6 +173,11 @@ public class QuadViewImpl implements QuadView {
|
|||
return normalFlags() != 0;
|
||||
}
|
||||
|
||||
/** True if all vertex normals have been set. */
|
||||
public boolean hasAllVertexNormals() {
|
||||
return (normalFlags() & 0b1111) == 0b1111;
|
||||
}
|
||||
|
||||
protected final int normalIndex(int vertexIndex) {
|
||||
return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHel
|
|||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
|
@ -37,8 +38,10 @@ 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.util.TriState;
|
||||
import net.fabricmc.fabric.impl.client.indigo.Indigo;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoConfig;
|
||||
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.MutableQuadViewImpl;
|
||||
|
@ -131,7 +134,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
shadeFlatQuad(quad);
|
||||
shadeFlatQuad(quad, isVanilla);
|
||||
|
||||
if (emissive) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -151,30 +154,57 @@ 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) {
|
||||
if (quad.hasVertexNormals()) {
|
||||
// Quads that have vertex normals need to be shaded using interpolation - vanilla can't
|
||||
// handle them. Generally only applies to modded models.
|
||||
final float faceShade = blockInfo.blockView.getBrightness(quad.lightFace(), quad.hasShade());
|
||||
private void shadeFlatQuad(MutableQuadViewImpl quad, boolean isVanilla) {
|
||||
final boolean hasShade = quad.hasShade();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad.color(i, ColorHelper.multiplyRGB(quad.color(i), vertexShade(quad, i, faceShade)));
|
||||
// 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 (quad.hasAllVertexNormals()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float shade = normalShade(quad.normalX(i), quad.normalY(i), quad.normalZ(i), hasShade);
|
||||
quad.color(i, ColorHelper.multiplyRGB(quad.color(i), shade));
|
||||
}
|
||||
} else {
|
||||
final float faceShade;
|
||||
|
||||
if ((quad.geometryFlags() & AXIS_ALIGNED_FLAG) != 0) {
|
||||
faceShade = blockInfo.blockView.getBrightness(quad.lightFace(), hasShade);
|
||||
} else {
|
||||
Vector3f faceNormal = quad.faceNormal();
|
||||
faceShade = normalShade(faceNormal.x, faceNormal.y, faceNormal.z, hasShade);
|
||||
}
|
||||
|
||||
if (quad.hasVertexNormals()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float shade;
|
||||
|
||||
if (quad.hasNormal(i)) {
|
||||
shade = normalShade(quad.normalX(i), quad.normalY(i), quad.normalZ(i), hasShade);
|
||||
} else {
|
||||
shade = faceShade;
|
||||
}
|
||||
|
||||
quad.color(i, ColorHelper.multiplyRGB(quad.color(i), shade));
|
||||
}
|
||||
} else {
|
||||
if (faceShade != 1.0f) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad.color(i, ColorHelper.multiplyRGB(quad.color(i), faceShade));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final float diffuseShade = blockInfo.blockView.getBrightness(quad.lightFace(), quad.hasShade());
|
||||
final float faceShade = blockInfo.blockView.getBrightness(quad.lightFace(), hasShade);
|
||||
|
||||
if (diffuseShade != 1.0f) {
|
||||
if (faceShade != 1.0f) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad.color(i, ColorHelper.multiplyRGB(quad.color(i), diffuseShade));
|
||||
quad.color(i, ColorHelper.multiplyRGB(quad.color(i), faceShade));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float vertexShade(MutableQuadViewImpl quad, int vertexIndex, float faceShade) {
|
||||
return quad.hasNormal(vertexIndex) ? normalShade(quad.normalX(vertexIndex), quad.normalY(vertexIndex), quad.normalZ(vertexIndex), quad.hasShade()) : faceShade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds mean of per-face shading factors weighted by normal components.
|
||||
* Not how light actually works but the vanilla diffuse shading model is a hack to start with
|
||||
|
|
Loading…
Add table
Reference in a new issue