diff --git a/fabric-renderer-api-v1/build.gradle b/fabric-renderer-api-v1/build.gradle index bff12890a..35e957d9f 100644 --- a/fabric-renderer-api-v1/build.gradle +++ b/fabric-renderer-api-v1/build.gradle @@ -4,3 +4,11 @@ version = getSubprojectVersion(project, "0.4.1") moduleDependencies(project, [ 'fabric-api-base' ]) + +dependencies { + testmodCompile project(path: ':fabric-blockrenderlayer-v1', configuration: 'dev') + testmodCompile project(path: ':fabric-models-v0', configuration: 'dev') + testmodCompile project(path: ':fabric-networking-blockentity-v0', configuration: 'dev') + testmodCompile project(path: ':fabric-object-builder-api-v1', configuration: 'dev') + testmodCompile project(path: ':fabric-rendering-data-attachment-v1', configuration: 'dev') +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/WorldRenderExtensions.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/WorldRenderExtensions.java new file mode 100644 index 000000000..a104747b7 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/WorldRenderExtensions.java @@ -0,0 +1,31 @@ +/* + * 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.math.BlockPos; +import net.minecraft.world.World; + +/** + * Extension interface for a world to notify the world that a block needs to be re-rendered. + */ +public interface WorldRenderExtensions { + static void scheduleBlockRerender(World world, BlockPos pos) { + ((WorldRenderExtensions) world).scheduleBlockRerender(pos); + } + + void scheduleBlockRerender(BlockPos pos); +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/mixin/ClientWorldMixin.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/mixin/ClientWorldMixin.java new file mode 100644 index 000000000..6d8c5febf --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/mixin/ClientWorldMixin.java @@ -0,0 +1,38 @@ +/* + * 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.mixin; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.BlockPos; + +@Mixin(ClientWorld.class) +abstract class ClientWorldMixin extends WorldMixin { + @Shadow + @Final + private WorldRenderer worldRenderer; + + @Override + public void scheduleBlockRerender(BlockPos pos) { + // Update the block at the position to trigger chunk re-render. + this.worldRenderer.updateBlock(null, pos, null, null, 0); + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/mixin/WorldMixin.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/mixin/WorldMixin.java new file mode 100644 index 000000000..03903b9fb --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/mixin/WorldMixin.java @@ -0,0 +1,32 @@ +/* + * 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.mixin; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import net.fabricmc.fabric.test.renderer.WorldRenderExtensions; + +@Mixin(World.class) +abstract class WorldMixin implements WorldRenderExtensions { + @Override + public void scheduleBlockRerender(BlockPos pos) { + // Do nothing, the client world will do things here + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.java new file mode 100644 index 000000000..0af08e4ff --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * 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. + * + *

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; diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlock.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlock.java new file mode 100644 index 000000000..91c3b625f --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlock.java @@ -0,0 +1,92 @@ +/* + * 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 org.jetbrains.annotations.Nullable; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; +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.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; + +public final class FrameBlock extends Block implements BlockEntityProvider { + public FrameBlock(Settings settings) { + super(settings); + } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + if (world.isClient()) { + return ActionResult.PASS; + } + + BlockEntity blockEntity = world.getBlockEntity(pos); + + if (blockEntity instanceof FrameBlockEntity) { + ItemStack stack = player.getStackInHand(hand); + Block handBlock = Block.getBlockFromItem(stack.getItem()); + + @Nullable + Block currentBlock = ((FrameBlockEntity) blockEntity).getBlock(); + + if (stack.isEmpty()) { + // Try to remove if the stack in hand is empty + if (currentBlock != null) { + player.inventory.offerOrDrop(world, new ItemStack(currentBlock)); + ((FrameBlockEntity) blockEntity).setBlock(null); + return ActionResult.SUCCESS; + } + + return ActionResult.PASS; + } + + // getBlockFromItem will return air if we do not have a block item in hand + if (handBlock.is(Blocks.AIR)) { + return ActionResult.FAIL; + } + + // Do not allow blocks that may have a block entity + if (handBlock.hasBlockEntity()) { + return ActionResult.FAIL; + } + + if (currentBlock != null) { + player.inventory.offerOrDrop(world, new ItemStack(currentBlock)); + } + + ((FrameBlockEntity) blockEntity).setBlock(handBlock); + return ActionResult.SUCCESS; + } + + return ActionResult.FAIL; + } + + @Nullable + @Override + public BlockEntity createBlockEntity(BlockView world) { + return new FrameBlockEntity(); + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlockEntity.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlockEntity.java new file mode 100644 index 000000000..e9a01cd77 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlockEntity.java @@ -0,0 +1,107 @@ +/* + * 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 org.jetbrains.annotations.Nullable; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable; +import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity; +import net.fabricmc.fabric.api.util.NbtType; +import net.fabricmc.fabric.test.renderer.WorldRenderExtensions; + +public final class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlockEntity, BlockEntityClientSerializable { + @Nullable + private Block block = null; + + public FrameBlockEntity() { + super(RendererTest.FRAME_BLOCK_ENTITY); + } + + @Override + public void fromTag(BlockState state, CompoundTag tag) { + super.fromTag(state, tag); + + if (tag.contains("block", NbtType.STRING)) { + this.block = Registry.BLOCK.get(new Identifier(tag.getString("block"))); + } + } + + @Override + public CompoundTag toTag(CompoundTag tag) { + if (this.block != null) { + tag.putString("block", Registry.BLOCK.getId(this.block).toString()); + } + + return super.toTag(tag); + } + + @Override + public void markDirty() { + super.markDirty(); + + if (this.hasWorld() && !this.getWorld().isClient()) { + this.sync(); + } + } + + @Nullable + public Block getBlock() { + return this.block; + } + + public void setBlock(@Nullable Block block) { + this.block = block; + this.markDirty(); + } + + @Nullable + @Override + public Block getRenderAttachmentData() { + return this.block; + } + + @Override + public void fromClientTag(CompoundTag tag) { + System.out.println("Recieved sync packet"); + + if (tag.contains("block", NbtType.STRING)) { + this.block = Registry.BLOCK.get(new Identifier(tag.getString("block"))); + } else { + this.block = null; + } + + if (this.getWorld() != null) { + WorldRenderExtensions.scheduleBlockRerender(this.getWorld(), this.getPos()); + } + } + + @Override + public CompoundTag toClientTag(CompoundTag tag) { + if (this.block != null) { + tag.putString("block", Registry.BLOCK.getId(this.block).toString()); + } + + return tag; + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java new file mode 100644 index 000000000..36b0a4449 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.renderer.simple; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; + +/** + * 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. + * + *

There are no fancy shaders or glow that is provided by this renderer test. + */ +public final class RendererTest implements ModInitializer { + public static final Block FRAME = new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); + public static final BlockEntityType FRAME_BLOCK_ENTITY = BlockEntityType.Builder.create(FrameBlockEntity::new, FRAME).build(null); + + @Override + public void onInitialize() { + Registry.register(Registry.BLOCK, new Identifier("fabric-renderer-api-v1-testmod", "frame"), FRAME); + Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier("fabric-renderer-api-v1-testmod", "frame"), FRAME_BLOCK_ENTITY); + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameBakedModel.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameBakedModel.java new file mode 100644 index 000000000..cd7ca0b78 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameBakedModel.java @@ -0,0 +1,138 @@ +/* + * 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.Collections; +import java.util.List; +import java.util.Random; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +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.world.BlockRenderView; + +import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; +import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView; + +final class FrameBakedModel implements BakedModel, FabricBakedModel { + private final Mesh frameMesh; + private final Sprite frameSprite; + + FrameBakedModel(Mesh frameMesh, Sprite frameSprite) { + this.frameMesh = frameMesh; + this.frameSprite = frameSprite; + } + + @Override + public List 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 false; + } + + @Override + public boolean isBuiltin() { + return false; + } + + @Override + public Sprite getSprite() { + return this.frameSprite; + } + + @Override + public ModelTransformation getTransformation() { + return ModelTransformation.NONE; + } + + @Override + public ModelOverrideList getOverrides() { + return ModelOverrideList.EMPTY; + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + // Emit our frame mesh + context.meshConsumer().accept(this.frameMesh); + + RenderAttachedBlockView renderAttachedBlockView = (RenderAttachedBlockView) blockView; + + // We cannot access the block entity from here. We should instead use the immutable render attachments provided by the block entity. + @Nullable + Block data = (Block) renderAttachedBlockView.getBlockEntityRenderAttachment(pos); + + if (data == null) { + return; // No inner block to render + } + + Sprite sprite = MinecraftClient.getInstance().getBlockRenderManager().getModels().getModelManager().getBlockModels().getSprite(data.getDefaultState()); + QuadEmitter emitter = context.getEmitter(); + + // We can emit our quads outside of the mesh as the block being put in the frame is very much dynamic. + // Emit the quads for each face of the block inside the frame + for (Direction direction : Direction.values()) { + // Add a face, with an inset to give the appearance of the block being in a frame. + emitter.square(direction, 0.1F, 0.1F, 0.9F, 0.9F, 0.1F) + // Set the sprite of the fact, use whole texture via BAKE_LOCK_UV + .spriteBake(0, sprite, MutableQuadView.BAKE_LOCK_UV) + // Allow textures + // TODO: the magic values here are not documented at all and probably should be + .spriteColor(0, -1, -1, -1, -1) + // Emit the quad + .emit(); + } + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + // TODO: Implement an item test. + // For now we will just leave this as I have not added a block item yet + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameModelResourceProvider.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameModelResourceProvider.java new file mode 100644 index 000000000..6e7003b8e --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameModelResourceProvider.java @@ -0,0 +1,43 @@ +/* + * 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 org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.client.model.ModelProviderContext; +import net.fabricmc.fabric.api.client.model.ModelProviderException; +import net.fabricmc.fabric.api.client.model.ModelResourceProvider; + +/** + * Provides the unbaked model for use with the frame block. + */ +final class FrameModelResourceProvider implements ModelResourceProvider { + private static final Identifier FRAME_MODEL_ID = new Identifier("fabric-renderer-api-v1-testmod", "block/frame"); + + @Nullable + @Override + public UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) throws ModelProviderException { + if (resourceId.equals(FRAME_MODEL_ID)) { + return new FrameUnbakedModel(); + } + + return null; + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java new file mode 100644 index 000000000..8656bbf64 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java @@ -0,0 +1,123 @@ +/* + * 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.Set; +import java.util.function.Function; + +import com.mojang.datafixers.util.Pair; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.ModelLoader; +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 getModelDependencies() { + return Collections.emptySet(); + } + + @Override + public Collection getTextureDependencies(Function unbakedModelGetter, Set> unresolvedTextureReferences) { + return Collections.emptySet(); // TODO: Also set the return value when we set a proper texture. + } + + /* + * 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(ModelLoader loader, Function 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(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.0F) + .spriteBake(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.0F) + .spriteBake(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.0F) + .spriteBake(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -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(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.9F) + .spriteBake(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.9F) + .spriteBake(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.9F) + .spriteBake(0, frameSprite, MutableQuadView.BAKE_LOCK_UV) + .spriteColor(0, -1, -1, -1, -1) + .emit(); + } + + return new FrameBakedModel(builder.build(), frameSprite); + } + + // No renderer implementation is present. + return null; + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/RendererClientTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/RendererClientTest.java new file mode 100644 index 000000000..6995503fd --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/client/RendererClientTest.java @@ -0,0 +1,32 @@ +/* + * 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 net.minecraft.client.render.RenderLayer; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; +import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; +import net.fabricmc.fabric.test.renderer.simple.RendererTest; + +public final class RendererClientTest implements ClientModInitializer { + @Override + public void onInitializeClient() { + ModelLoadingRegistry.INSTANCE.registerResourceProvider(manager -> new FrameModelResourceProvider()); + BlockRenderLayerMap.INSTANCE.putBlock(RendererTest.FRAME, RenderLayer.getCutoutMipped()); + } +} diff --git a/fabric-renderer-api-v1/src/testmod/resources/assets/fabric-renderer-api-v1-testmod/blockstates/frame.json b/fabric-renderer-api-v1/src/testmod/resources/assets/fabric-renderer-api-v1-testmod/blockstates/frame.json new file mode 100644 index 000000000..cb52a6f0c --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/resources/assets/fabric-renderer-api-v1-testmod/blockstates/frame.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "fabric-renderer-api-v1-testmod:block/frame" } + } +} diff --git a/fabric-renderer-api-v1/src/testmod/resources/fabric-renderer-api-v1-testmod.mixins.json b/fabric-renderer-api-v1/src/testmod/resources/fabric-renderer-api-v1-testmod.mixins.json new file mode 100644 index 000000000..fa6f2b25c --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/resources/fabric-renderer-api-v1-testmod.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.test.renderer.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "WorldMixin" + ], + "client": [ + "ClientWorldMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json b/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json new file mode 100644 index 000000000..45037a1a9 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "id": "fabric-renderer-api-v1-testmod", + "name": "Fabric Renderer API (v1) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-renderer-api-v1":"*", + "fabric-resource-loader-v0": "*" + }, + "entrypoints": { + "main": [ + "net.fabricmc.fabric.test.renderer.simple.RendererTest" + ], + "client": [ + "net.fabricmc.fabric.test.renderer.simple.client.RendererClientTest" + ] + }, + "mixins": [ + "fabric-renderer-api-v1-testmod.mixins.json" + ] +}