diff --git a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/block/forward/FWBlock.java b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/block/forward/FWBlock.java index 123d2e4f9..2f42a76ca 100644 --- a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/block/forward/FWBlock.java +++ b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/block/forward/FWBlock.java @@ -45,7 +45,8 @@ import nova.core.block.component.LightEmitter; import nova.core.component.Updater; import nova.core.component.misc.Collider; -import nova.core.component.renderer.ItemRenderer; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.component.renderer.Renderer; import nova.core.component.renderer.StaticRenderer; import nova.core.retention.Storable; import nova.core.util.Direction; @@ -376,14 +377,21 @@ public int getRenderBlockPass() { @SideOnly(Side.CLIENT) @Override public void renderInventoryBlock(net.minecraft.block.Block block, int metadata, int modelId, RenderBlocks renderer) { - Optional opRenderer = this.dummy.components.getOp(ItemRenderer.class); - if (opRenderer.isPresent()) { + if (this.dummy.components.has(Renderer.class)) { GL11.glPushAttrib(GL_TEXTURE_BIT); GL11.glEnable(GL12.GL_RESCALE_NORMAL); GL11.glPushMatrix(); Tessellator.instance.startDrawingQuads(); BWModel model = new BWModel(); - opRenderer.get().onRender.accept(model); + + if (this.dummy.components.has(StaticRenderer.class)) { + StaticRenderer staticRenderer = this.dummy.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); + } else if (this.dummy.components.has(DynamicRenderer.class)) { + DynamicRenderer dynamicRenderer = this.dummy.components.get(DynamicRenderer.class); + dynamicRenderer.onRender.accept(model); + } + model.render(); Tessellator.instance.draw(); GL11.glPopMatrix(); diff --git a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/BWItem.java b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/BWItem.java index 9bb8b6925..df0eccf39 100644 --- a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/BWItem.java +++ b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/BWItem.java @@ -24,7 +24,7 @@ import net.minecraft.entity.item.EntityItem; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import nova.core.component.renderer.ItemRenderer; +import nova.core.component.renderer.StaticRenderer; import nova.core.item.Item; import nova.core.render.model.CustomModel; import nova.core.retention.Storable; @@ -55,7 +55,7 @@ public BWItem(net.minecraft.item.Item item, int meta, NBTTagCompound tag) { this.meta = meta; this.tag = tag; - components.add(new ItemRenderer()) + components.add(new StaticRenderer()) .onRender(model -> { model.addChild(new CustomModel(self -> { Tessellator.instance.draw(); diff --git a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/ItemWrapperMethods.java b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/ItemWrapperMethods.java index e9bd29306..4f0b1ef80 100644 --- a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/ItemWrapperMethods.java +++ b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/wrapper/item/ItemWrapperMethods.java @@ -25,7 +25,9 @@ import net.minecraft.util.IIcon; import net.minecraft.world.World; import net.minecraftforge.client.IItemRenderer; -import nova.core.component.renderer.ItemRenderer; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.component.renderer.Renderer; +import nova.core.component.renderer.StaticRenderer; import nova.core.item.Item; import nova.core.item.ItemFactory; import nova.core.util.Direction; @@ -67,37 +69,39 @@ default ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlaye } default IIcon getIconFromDamage(int p_77617_1_) { - //TODO: Can we prevent building new items? - Item item = getItemFactory().build(); - if (item.components.has(ItemRenderer.class) && item.components.get(ItemRenderer.class).texture.isPresent()) { - return RenderUtility.instance.getIcon(item.components.get(ItemRenderer.class).texture.get()); - } return null; } default IIcon getIcon(ItemStack itemStack, int pass) { - Item item = Game.natives().toNova(itemStack); - if (item.components.has(ItemRenderer.class) && item.components.get(ItemRenderer.class).texture.isPresent()) { - return RenderUtility.instance.getIcon(item.components.get(ItemRenderer.class).texture.get()); - } return null; } + @Override default boolean handleRenderType(ItemStack item, IItemRenderer.ItemRenderType type) { return item.getItem() == this && getIcon(item, 0) == null; } + @Override default boolean shouldUseRenderHelper(IItemRenderer.ItemRenderType type, ItemStack item, IItemRenderer.ItemRendererHelper helper) { return true; } + @Override default void renderItem(IItemRenderer.ItemRenderType type, ItemStack itemStack, Object... data) { Item item = Game.natives().toNova(itemStack); - if (item.components.has(ItemRenderer.class)) { - BWModel model = new BWModel(); - item.components.get(ItemRenderer.class).onRender.accept(model); - model.render(); + BWModel model = new BWModel(); + + if (item.components.has(StaticRenderer.class)) { + StaticRenderer staticRenderer = item.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); + } else if (item.components.has(DynamicRenderer.class)) { + DynamicRenderer dynamicRenderer = item.components.get(DynamicRenderer.class); + dynamicRenderer.onRender.accept(model); } + + // For some reason calling model.faces.size() returns 0. + // Yet staticRenderer.onRender.accept(model) still gets executed. + model.render(); } default int getColorFromItemStack(ItemStack itemStack, int p_82790_2_) { diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/render/RenderUtility.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/render/RenderUtility.java index 236f9cbb8..1dfb5d0be 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/render/RenderUtility.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/render/RenderUtility.java @@ -23,35 +23,28 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.BlockPart; -import net.minecraft.client.renderer.block.model.BlockPartFace; import net.minecraft.client.renderer.block.model.FaceBakery; import net.minecraft.client.renderer.block.model.ItemModelGenerator; import net.minecraft.client.renderer.block.model.ModelBlock; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.client.resources.model.ModelRotation; -import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.client.model.TRSRTransformation; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -import nova.core.component.renderer.ItemRenderer; +import nova.core.component.renderer.Renderer; import nova.core.component.renderer.StaticRenderer; import nova.core.render.texture.BlockTexture; import nova.core.render.texture.ItemTexture; import nova.core.render.texture.Texture; import nova.core.wrapper.mc.forge.v18.wrapper.block.forward.FWBlock; import nova.core.wrapper.mc.forge.v18.wrapper.item.FWItem; +import nova.core.wrapper.mc.forge.v18.wrapper.item.FWItemBlock; import nova.core.wrapper.mc.forge.v18.wrapper.render.FWEmptyModel; import nova.core.wrapper.mc.forge.v18.wrapper.render.FWSmartBlockModel; import nova.core.wrapper.mc.forge.v18.wrapper.render.FWSmartItemModel; @@ -60,7 +53,6 @@ import java.io.IOException; import java.util.HashMap; -import java.util.Optional; import static org.lwjgl.opengl.GL11.GL_BLEND; import static org.lwjgl.opengl.GL11.GL_FLAT; @@ -214,35 +206,8 @@ public void onModelBakeEvent(ModelBakeEvent event) { nova.core.item.Item dummy = item.getItemFactory().build(); - if (dummy.components.has(ItemRenderer.class)) { - Optional texture = dummy.components.get(ItemRenderer.class).texture; - - if (texture.isPresent()) { - MODEL_GENERATED.textures.put("layer0", texture.get().getResource()); - MODEL_GENERATED.name = itemLocation.toString(); - - // This is the key part, it takes the texture and makes the "3d" one wide voxel model - ModelBlock itemModel = ITEM_MODEL_GENERATOR.makeItemModel(new FakeTextureMap(dummy), MODEL_GENERATED); - - // This was taken from ModelBakery and simplified for the generation of our Items - SimpleBakedModel.Builder builder = new SimpleBakedModel.Builder(itemModel).setTexture(getTexture(texture.get())); - for (BlockPart blockpart : (Iterable) itemModel.getElements()) { - for (EnumFacing enumfacing : (Iterable) blockpart.mapFaces.keySet()) { - BlockPartFace blockpartface = (BlockPartFace) blockpart.mapFaces.get(enumfacing); - BakedQuad bakedQuad = FACE_BAKERY.makeBakedQuad(blockpart.positionFrom, blockpart.positionTo, blockpartface, getTexture(texture.get()), enumfacing, ModelRotation.X0_Y0, blockpart.partRotation, false, blockpart.shade); - - if (blockpartface.cullFace == null || !TRSRTransformation.isInteger(ModelRotation.X0_Y0.getMatrix())) { - builder.addGeneralQuad(bakedQuad); - } else { - - builder.addFaceQuad(ModelRotation.X0_Y0.rotate(blockpartface.cullFace), bakedQuad); - } - } - } - event.modelRegistry.putObject(itemLocation, builder.makeBakedModel()); - } else { - event.modelRegistry.putObject(itemLocation, new FWSmartItemModel(dummy)); - } + if (dummy.components.has(Renderer.class)) { + event.modelRegistry.putObject(itemLocation, new FWSmartItemModel(dummy)); } } } @@ -261,24 +226,4 @@ public void preInit() { } }); } - - private class FakeTextureMap extends TextureMap { - private final nova.core.item.Item item; - - public FakeTextureMap(nova.core.item.Item item) { - super(""); - this.item = item; - } - - @Override - public TextureAtlasSprite getAtlasSprite(String iconName) { - if (item.components.has(ItemRenderer.class)) { - ItemRenderer itemRenderer = item.components.get(ItemRenderer.class); - if (itemRenderer.texture.isPresent()) { - return RenderUtility.instance.getTexture(itemRenderer.texture.get()); - } - } - return Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite(); - } - } } diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartBlockModel.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartBlockModel.java index 5f7835809..a090db09d 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartBlockModel.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartBlockModel.java @@ -24,21 +24,21 @@ import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.ItemCameraTransforms; import net.minecraft.client.renderer.block.model.ItemTransformVec3f; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.item.ItemStack; import net.minecraftforge.client.model.IFlexibleBakedModel; import net.minecraftforge.client.model.ISmartBlockModel; import net.minecraftforge.client.model.ISmartItemModel; import nova.core.block.Block; -import nova.core.component.renderer.ItemRenderer; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.component.renderer.Renderer; import nova.core.component.renderer.StaticRenderer; import nova.core.item.ItemBlock; -import nova.core.wrapper.mc.forge.v18.render.RenderUtility; import nova.core.wrapper.mc.forge.v18.wrapper.block.forward.FWBlock; import nova.internal.core.Game; import javax.vecmath.Vector3f; + import java.util.List; /** @@ -50,10 +50,10 @@ public class FWSmartBlockModel extends FWSmartModel implements ISmartBlockModel, private final Block block; private final boolean isItem; - public FWSmartBlockModel(Block block, boolean isDummy) { + public FWSmartBlockModel(Block block, boolean isItem) { super(); this.block = block; - this.isItem = isDummy; + this.isItem = isItem; // Change the default transforms to the default full Block transforms this.itemCameraTransforms = new ItemCameraTransforms( new ItemTransformVec3f(new Vector3f(10, -45, 170), new Vector3f(0, 0.09375f, -0.171875f), new Vector3f(0.375f, 0.375f, 0.375f)), // Third Person @@ -78,10 +78,8 @@ public IBakedModel handleBlockState(IBlockState state) { @Override public IBakedModel handleItemState(ItemStack stack) { ItemBlock item = Game.natives().toNova(stack); - ItemRenderer renderer = - item.components.has(ItemRenderer.class) ? item.components.get(ItemRenderer.class) : block.components.has(ItemRenderer.class) ? block.components.get(ItemRenderer.class) : null; - if (renderer != null) { + if (item.components.has(Renderer.class) || block.components.has(Renderer.class)) { return new FWSmartBlockModel(block, true); } @@ -90,37 +88,22 @@ public IBakedModel handleItemState(ItemStack stack) { @Override public List getGeneralQuads() { - BWModel blockModel = new BWModel(); - blockModel.matrix.translate(0.5, 0.5, 0.5); + BWModel model = new BWModel(); + model.matrix.translate(0.5, 0.5, 0.5); if (isItem) { - ItemRenderer renderer = block.components.get(ItemRenderer.class); - renderer.onRender.accept(blockModel); - } else { - StaticRenderer renderer = block.components.get(StaticRenderer.class); - renderer.onRender.accept(blockModel); - } - - return modelToQuads(blockModel); - } - - @Override - public TextureAtlasSprite getTexture() { - /* - if (block.components.has(StaticRenderer.class)) { - Optional apply = block.components.get(StaticRenderer.class).texture.apply(Direction.UNKNOWN); - if (apply.isPresent()) { - return RenderUtility.instance.getTexture(apply.components.get()); - } - }*/ - - if (block.components.has(ItemRenderer.class)) { - ItemRenderer itemRenderer = block.components.get(ItemRenderer.class); - if (itemRenderer.texture.isPresent()) { - return RenderUtility.instance.getTexture(itemRenderer.texture.get()); + if (block.components.has(StaticRenderer.class)) { + StaticRenderer staticRenderer = block.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); + } else if (block.components.has(DynamicRenderer.class)) { + DynamicRenderer dynamicRenderer = block.components.get(DynamicRenderer.class); + dynamicRenderer.onRender.accept(model); } + } else { + StaticRenderer staticRenderer = block.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); } - return null; + return modelToQuads(model); } } diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartItemModel.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartItemModel.java index a230eb96e..7d00b4991 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartItemModel.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartItemModel.java @@ -23,19 +23,19 @@ import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.ItemCameraTransforms; import net.minecraft.client.renderer.block.model.ItemTransformVec3f; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.item.ItemStack; import net.minecraftforge.client.model.IFlexibleBakedModel; import net.minecraftforge.client.model.ISmartItemModel; -import nova.core.component.renderer.ItemRenderer; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.component.renderer.Renderer; +import nova.core.component.renderer.StaticRenderer; import nova.core.item.Item; -import nova.core.wrapper.mc.forge.v18.render.RenderUtility; import nova.internal.core.Game; import javax.vecmath.Vector3f; -import java.util.Collections; import java.util.List; +import java.util.Optional; /** * Generates a smart model based on a NOVA Model @@ -50,49 +50,41 @@ public FWSmartItemModel(Item item) { this.item = item; // Change the default transforms to the default Item transforms this.itemCameraTransforms = new ItemCameraTransforms( - new ItemTransformVec3f(new Vector3f(-90, 0, 0), new Vector3f(0, 1, -3), new Vector3f(0.55f, 0.55f, 0.55f)), // Third Person - new ItemTransformVec3f(new Vector3f(0, -135, 25), new Vector3f(0, 4, 2), new Vector3f(1.7f, 1.7f, 1.7f)), // First Person - ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT); + new ItemTransformVec3f(new Vector3f(0, -90, 130), new Vector3f(0, 1f / 24f, -2.75f / 16f), new Vector3f(0.9f, 0.9f, 0.9f)), // Third Person + new ItemTransformVec3f(new Vector3f(0, -135, 25/*-135/*-25*/), new Vector3f(0, 0.25f, 0.125f/*0.5f, 0.25f*/), new Vector3f(1.7f, 1.7f, 1.7f)), // First Person + ItemTransformVec3f.DEFAULT, // Head + new ItemTransformVec3f(new Vector3f(-30, 135, 0), new Vector3f(), new Vector3f(1.6F, 1.6F, 1.6F))); // GUI } @Override public IBakedModel handleItemState(ItemStack stack) { Item item = Game.natives().toNova(stack); - if (item.components.has(ItemRenderer.class)) { + if (item.components.has(Renderer.class)) { return new FWSmartItemModel(item); } - return this; + return new FWEmptyModel(); } @Override public List getGeneralQuads() { - if (item.components.has(ItemRenderer.class)) { - BWModel model = new BWModel(); - ItemRenderer renderer = item.components.get(ItemRenderer.class); - model.matrix.translate(0.5, 0.5, 0.5); - renderer.onRender.accept(model); - return modelToQuads(model); - } - - return Collections.emptyList(); - } + BWModel model = new BWModel(); + model.matrix.translate(0.5, 0.5, 0.5); - @Override - public TextureAtlasSprite getTexture() { - if (item.components.has(ItemRenderer.class)) { - ItemRenderer itemRenderer = item.components.get(ItemRenderer.class); - if (itemRenderer.texture.isPresent()) { - return RenderUtility.instance.getTexture(itemRenderer.texture.get()); - } + if (item.components.has(StaticRenderer.class)) { + StaticRenderer staticRenderer = item.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); + } else if (item.components.has(DynamicRenderer.class)) { + DynamicRenderer dynamicRenderer = item.components.get(DynamicRenderer.class); + dynamicRenderer.onRender.accept(model); } - return null; + return modelToQuads(model); } @Override public boolean isGui3d() { - return item.components.has(ItemRenderer.class); + return item.components.has(Renderer.class); } } diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartModel.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartModel.java index 1010a33ea..b5a85e9b8 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartModel.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/wrapper/render/FWSmartModel.java @@ -21,6 +21,7 @@ package nova.core.wrapper.mc.forge.v18.wrapper.render; import com.google.common.primitives.Ints; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.ItemCameraTransforms; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -76,9 +77,11 @@ protected List modelToQuads(Model modelIn) { .stream() .map( face -> { + TextureAtlasSprite texture = face.texture.map(RenderUtility.instance::getTexture) + .orElse(Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite()); List vertexData = face.vertices .stream() - .map(v -> vertexToInts(v, RenderUtility.instance.getTexture(face.texture.get()))) + .map(v -> vertexToInts(v, texture)) .collect(Collectors.toList()); int[] data = Ints.concat(vertexData.toArray(new int[][] {})); @@ -100,7 +103,7 @@ public VertexFormat getFormat() { } @Override - public List getFaceQuads(EnumFacing p_177551_1_) { + public List getFaceQuads(EnumFacing facing) { return Collections.emptyList(); } @@ -119,6 +122,11 @@ public boolean isBuiltInRenderer() { return false; } + @Override + public TextureAtlasSprite getTexture() { + return null; + } + @Override public ItemCameraTransforms getItemCameraTransforms() { return itemCameraTransforms; diff --git a/src/main/java/nova/core/component/renderer/DynamicRenderer.java b/src/main/java/nova/core/component/renderer/DynamicRenderer.java index e4d4573db..d1ab70332 100644 --- a/src/main/java/nova/core/component/renderer/DynamicRenderer.java +++ b/src/main/java/nova/core/component/renderer/DynamicRenderer.java @@ -20,8 +20,15 @@ package nova.core.component.renderer; +import nova.core.component.ComponentProvider; +import nova.core.render.pipeline.RenderPipeline; + /** - * This interface signals that a block needs dynamic rendering. + * This Component specifies that a {@link ComponentProvider} requires custom dynamic rendering. + * This type of rendering updates its render state every frame. As such it should be reserved only for models + * which truly need it. See {@link RenderPipeline} to easily pipeline models to prepare it for rendering. + * + * @see StaticRenderer */ public class DynamicRenderer extends Renderer { diff --git a/src/main/java/nova/core/component/renderer/ItemRenderer.java b/src/main/java/nova/core/component/renderer/ItemRenderer.java deleted file mode 100644 index 638c08e45..000000000 --- a/src/main/java/nova/core/component/renderer/ItemRenderer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2015 NOVA, All rights reserved. - * This library is free software, licensed under GNU Lesser General Public License version 3 - * - * This file is part of NOVA. - * - * NOVA is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * NOVA is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NOVA. If not, see . - */ - -package nova.core.component.renderer; - -import nova.core.component.ComponentProvider; -import nova.core.render.texture.ItemTexture; -import nova.core.render.texture.Texture; - -import java.util.Optional; - -/** - * This interface specifies that a block requires custom static item rendering. - * (That is, called upon item render or network synchronization.) - */ -//Item renderer should not exist. Instead, blocks should just edit the default ItemBlock renderer... -@Deprecated -public class ItemRenderer extends Renderer { - - /** - * If there is no texture provided, it will not render any and default to onRender() method for custom item rendering. - *

- * return - {@link ItemTexture} instance - */ - public Optional texture = Optional.empty(); - - public ItemRenderer() { - - } - - public ItemRenderer(ComponentProvider provider) { - onRender = model -> { - Optional opComponent = provider.components.getOp(StaticRenderer.class); - if (opComponent.isPresent()) { - opComponent.get().onRender.accept(model); - } else { - provider.components.getOp(DynamicRenderer.class).ifPresent(c -> c.onRender.accept(model)); - } - }; - } - - public ItemRenderer setTexture(Texture texture) { - this.texture = Optional.of(texture); - return this; - } -} diff --git a/src/main/java/nova/core/component/renderer/StaticRenderer.java b/src/main/java/nova/core/component/renderer/StaticRenderer.java index 1e252ad54..30fa6d400 100644 --- a/src/main/java/nova/core/component/renderer/StaticRenderer.java +++ b/src/main/java/nova/core/component/renderer/StaticRenderer.java @@ -20,12 +20,15 @@ package nova.core.component.renderer; +import nova.core.component.ComponentProvider; import nova.core.render.pipeline.RenderPipeline; /** - * This interface specifies that a block requires custom static rendering. + * This Component specifies that a {@link ComponentProvider} requires custom static rendering. * This type of rendering only updates its render state every time the world changes (block change) - * See {@link RenderPipeline} to easily pipeline models to prepare it for rendering + * See {@link RenderPipeline} to easily pipeline models to prepare it for rendering. + * + * @see DynamicRenderer */ public class StaticRenderer extends Renderer { diff --git a/src/main/java/nova/core/recipes/crafting/ItemIngredient.java b/src/main/java/nova/core/recipes/crafting/ItemIngredient.java index 5aa41d22e..d9a580bc8 100755 --- a/src/main/java/nova/core/recipes/crafting/ItemIngredient.java +++ b/src/main/java/nova/core/recipes/crafting/ItemIngredient.java @@ -20,7 +20,9 @@ package nova.core.recipes.crafting; +import nova.core.block.BlockFactory; import nova.core.item.Item; +import nova.core.item.ItemFactory; import java.util.Collection; import java.util.Optional; @@ -32,6 +34,27 @@ * @author Stan Hebben */ public interface ItemIngredient { + + /** + * Retrieves an ingredient to represent a specific block. + * + * @param block The block + * @return ingredient + */ + static ItemIngredient forBlock(BlockFactory block) { + return forItem(block.getID()); + } + + /** + * Retrieves an ingredient to represent a specific item. + * + * @param item The item + * @return ingredient + */ + static ItemIngredient forItem(ItemFactory item) { + return forItem(item.getID()); + } + /** * Retrieves an ingredient to represent a specific item. * diff --git a/src/main/java/nova/core/recipes/crafting/OreItemIngredient.java b/src/main/java/nova/core/recipes/crafting/OreItemIngredient.java index 6a4661d8e..648455ec2 100644 --- a/src/main/java/nova/core/recipes/crafting/OreItemIngredient.java +++ b/src/main/java/nova/core/recipes/crafting/OreItemIngredient.java @@ -74,6 +74,6 @@ public Optional getTag() { @Override public Item consumeOnCrafting(Item original, CraftingGrid craftingGrid) { - return null; + return original.withAmount(original.count() - 1); } } diff --git a/src/main/java/nova/core/recipes/crafting/ShapedCraftingRecipe.java b/src/main/java/nova/core/recipes/crafting/ShapedCraftingRecipe.java index dfd095fc8..b79e4ea65 100755 --- a/src/main/java/nova/core/recipes/crafting/ShapedCraftingRecipe.java +++ b/src/main/java/nova/core/recipes/crafting/ShapedCraftingRecipe.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -256,6 +257,7 @@ public void consumeItems(CraftingGrid craftingGrid) { for (int i = 0; i < ingredients.length; i++) { Item original = mapping.Items[i]; Item consumed = ingredients[i].consumeOnCrafting(original, craftingGrid); + Objects.requireNonNull(consumed, "The result of 'ItemIngredient.consumeOnCrafting' can't be null"); // -- only works if Item is immutable //if (original == consumed) diff --git a/src/main/java/nova/core/recipes/crafting/ShapelessCraftingRecipe.java b/src/main/java/nova/core/recipes/crafting/ShapelessCraftingRecipe.java index e45bebe70..e19f8d5ed 100755 --- a/src/main/java/nova/core/recipes/crafting/ShapelessCraftingRecipe.java +++ b/src/main/java/nova/core/recipes/crafting/ShapelessCraftingRecipe.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; /** @@ -119,8 +120,9 @@ public void consumeItems(CraftingGrid craftingGrid) { for (int i = 0; i < ingredients.length; i++) { ItemIngredient ingredient = ingredients[i]; - Item transformed = ingredient.consumeOnCrafting(matching.inputs[i], craftingGrid); - craftingGrid.setStack(matching.indices[i], Optional.ofNullable(transformed)); + Item consumed = ingredient.consumeOnCrafting(matching.inputs[i], craftingGrid); + Objects.requireNonNull(consumed, "The result of 'ItemIngredient.consumeOnCrafting' can't be null"); + craftingGrid.setStack(matching.indices[i], Optional.ofNullable(consumed)); } } diff --git a/src/main/java/nova/core/recipes/crafting/SpecificItemIngredient.java b/src/main/java/nova/core/recipes/crafting/SpecificItemIngredient.java index d3b2330ca..074928720 100644 --- a/src/main/java/nova/core/recipes/crafting/SpecificItemIngredient.java +++ b/src/main/java/nova/core/recipes/crafting/SpecificItemIngredient.java @@ -69,7 +69,7 @@ public Optional getTag() { @Override public Item consumeOnCrafting(Item original, CraftingGrid craftingGrid) { - return original; + return original.withAmount(original.count() - 1); } @Override diff --git a/src/main/java/nova/core/render/pipeline/BlockRenderPipeline.java b/src/main/java/nova/core/render/pipeline/BlockRenderPipeline.java index cf092927a..c67bef89b 100644 --- a/src/main/java/nova/core/render/pipeline/BlockRenderPipeline.java +++ b/src/main/java/nova/core/render/pipeline/BlockRenderPipeline.java @@ -20,9 +20,7 @@ package nova.core.render.pipeline; - - -import nova.core.block.Block; +import nova.core.component.ComponentProvider; import nova.core.component.misc.Collider; import nova.core.render.Color; import nova.core.render.RenderException; @@ -37,14 +35,16 @@ import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier;/** +import java.util.function.Supplier; + +/** * A block rendering builder that generates a function that renders a block model. * * @author Calclavia */ public class BlockRenderPipeline extends RenderPipeline { - public final Block block; + public final ComponentProvider componentProvider; /** * Called to get the texture of this block for a certain side. @@ -75,9 +75,9 @@ public class BlockRenderPipeline extends RenderPipeline { */ public Function colorMultiplier = (dir) -> Color.white; - public BlockRenderPipeline(Block block) { - this.block = block; - bounds = () -> block.components.getOp(Collider.class).map(c -> c.boundingBox.get()).orElse(Cuboid.ONE); + public BlockRenderPipeline(ComponentProvider componentProvider) { + this.componentProvider = componentProvider; + bounds = () -> componentProvider.components.getOp(Collider.class).map(c -> c.boundingBox.get()).orElse(Cuboid.ONE); consumer = model -> model.addChild(draw(new MeshModel())); } diff --git a/src/main/java/nova/core/render/pipeline/ConnectedTextureRenderPipeline.java b/src/main/java/nova/core/render/pipeline/ConnectedTextureRenderPipeline.java index 8f902f0cd..62eb9c91f 100644 --- a/src/main/java/nova/core/render/pipeline/ConnectedTextureRenderPipeline.java +++ b/src/main/java/nova/core/render/pipeline/ConnectedTextureRenderPipeline.java @@ -35,6 +35,8 @@ import java.util.function.Supplier; public class ConnectedTextureRenderPipeline extends BlockRenderPipeline { + + public final Block block; public final Texture edgeTexture; /** @@ -52,6 +54,7 @@ public class ConnectedTextureRenderPipeline extends BlockRenderPipeline { public ConnectedTextureRenderPipeline(Block block, Texture edgeTexture) { super(block); + this.block = block; this.edgeTexture = edgeTexture; connectMask = () -> { diff --git a/src/main/java/nova/core/render/pipeline/ItemRenderPipeline.java b/src/main/java/nova/core/render/pipeline/ItemRenderPipeline.java new file mode 100644 index 000000000..7f5202054 --- /dev/null +++ b/src/main/java/nova/core/render/pipeline/ItemRenderPipeline.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2017 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.render.pipeline; + +import nova.core.component.ComponentProvider; +import nova.core.render.Color; +import nova.core.render.model.Face; +import nova.core.render.model.MeshModel; +import nova.core.render.model.Vertex; +import nova.core.render.texture.Texture; +import nova.core.util.Direction; +import nova.core.util.math.Vector2DUtil; +import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +/** + * An item rendering builder that generates a function that renders an item model. + * + * @author ExE Boss + */ +public class ItemRenderPipeline extends RenderPipeline { + + public final ComponentProvider componentProvider; + + /** + * Called to get the texture of this item. + * Returns - An optional of the texture. + */ + public Supplier> texture = () -> Optional.empty(); + + /** + * Called to get the size of this item to be rendered. + * Defaults to (1, 1). + */ + public Supplier size; + + /** + * Gets the color of the item. This is called by the default item renderer. + * + * Returns the color + */ + public Supplier colorMultiplier = () -> Color.white; + + public ItemRenderPipeline(ComponentProvider componentProvider) { + this.componentProvider = componentProvider; + size = () -> new Vector2D(1, 1); + consumer = model -> model.addChild(draw(new MeshModel())); + } + + public ItemRenderPipeline withTexture(Supplier> texture) { + this.texture = texture; + return this; + } + + public ItemRenderPipeline withTexture(Texture t) { + Objects.requireNonNull(t, "Texture is null, please initiate the texture before the item"); + this.texture = () -> Optional.of(t); + return this; + } + + public ItemRenderPipeline withSize(Supplier size) { + this.size = size; + return this; + } + + public ItemRenderPipeline withSize(Vector2D size) { + this.size = () -> size; + return this; + } + + public ItemRenderPipeline withColor(Supplier colorMultiplier) { + this.colorMultiplier = colorMultiplier; + return this; + } + + public ItemRenderPipeline withColor(Color colorMultiplier) { + this.colorMultiplier = () -> colorMultiplier; + return this; + } + + public MeshModel draw(MeshModel model) { + Vector2D size = this.size.get(); + double minX = -size.getX() / 2; + double minY = -size.getY() / 2; + double minZ = -0.5 / 16; + double maxX = size.getX() / 2; + double maxY = size.getY() / 2; + double maxZ = 0.5 / 16; + + Color color = colorMultiplier.get(); + Optional texture = this.texture.get(); + Face face; + Set faces; + + face = drawFront(model, minX, minY, minZ, maxX, maxY, maxZ, texture); + face.vertices.forEach(v -> v.color = color); + face = drawBack(model, minX, minY, minZ, maxX, maxY, maxZ, texture); + face.vertices.forEach(v -> v.color = color); + faces = drawUpAndDown(model, minX, minY, minZ, maxX, maxY, maxZ, texture); + faces.stream().flatMap(f -> f.vertices.stream()).forEach(v -> v.color = color); + faces = drawLeftAndRight(model, minX, minY, minZ, maxX, maxY, maxZ, texture); + faces.stream().flatMap(f -> f.vertices.stream()).forEach(v -> v.color = color); + + return model; + } + + public static Face drawBack( + MeshModel model, + double minX, double minY, double minZ, + double maxX, double maxY, double maxZ, + Optional texture) { + + Vector2D minUV; + Vector2D maxUV; + + if (texture.isPresent()) { + minUV = texture.get().minUV(); + maxUV = texture.get().maxUV(); + } else { + minUV = Vector2D.ZERO; + maxUV = Vector2DUtil.ONE; + } + + Face back = new Face(); + back.texture = texture; + back.normal = Direction.NORTH.toVector(); + //Top-left corner + back.drawVertex(new Vertex(minX, maxY, minZ, maxUV.getX(), maxUV.getY())); + //Top-right corner + back.drawVertex(new Vertex(maxX, maxY, minZ, minUV.getX(), maxUV.getY())); + //Bottom-right corner + back.drawVertex(new Vertex(maxX, minY, minZ, minUV.getX(), minUV.getY())); + //Bottom-left corner + back.drawVertex(new Vertex(minX, minY, minZ, maxUV.getX(), minUV.getY())); + model.drawFace(back); + + return back; + } + + public static Face drawFront( + MeshModel model, + double minX, double minY, double minZ, + double maxX, double maxY, double maxZ, + Optional texture) { + + Vector2D minUV; + Vector2D maxUV; + + if (texture.isPresent()) { + minUV = texture.get().minUV(); + maxUV = texture.get().maxUV(); + } else { + minUV = Vector2D.ZERO; + maxUV = Vector2DUtil.ONE; + } + + Face front = new Face(); + front.texture = texture; + front.normal = Direction.SOUTH.toVector(); + //Bottom-left corner + front.drawVertex(new Vertex(minX, minY, maxZ, maxUV.getX(), minUV.getY())); + //Bottom-right corner + front.drawVertex(new Vertex(maxX, minY, maxZ, minUV.getX(), minUV.getY())); + //Top-right corner + front.drawVertex(new Vertex(maxX, maxY, maxZ, minUV.getX(), maxUV.getY())); + //Top-left corner + front.drawVertex(new Vertex(minX, maxY, maxZ, maxUV.getX(), maxUV.getY())); + model.drawFace(front); + + return front; + } + + public static Set drawUpAndDown( + MeshModel model, + double minX, double minY, double minZ, + double maxX, double maxY, double maxZ, + Optional texture) { + + Vector2D minUV; + Vector2D maxUV; + Vector2D dimensions; + + if (texture.isPresent()) { + minUV = texture.get().minUV(); + maxUV = texture.get().maxUV(); + dimensions = texture.get().dimension; + } else { + minUV = Vector2D.ZERO; + maxUV = Vector2DUtil.ONE; + dimensions = new Vector2D(1, 1); + } + + Set faces = new HashSet<>(); + + double pixelHeight = (maxUV.getY() - minUV.getY()) / dimensions.getY(); + double voxelHeight = Math.abs(maxY - minY) / dimensions.getY(); + + for (int i = 0; i < dimensions.getY(); i++) { + Face up = new Face(); + up.texture = texture; + up.normal = Direction.UP.toVector(); + //Bottom-left corner + up.drawVertex(new Vertex(maxX, interpolate(minY, maxY, i + 1, voxelHeight), minZ, minUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i - 1, pixelHeight))); + //Bottom-right corner + up.drawVertex(new Vertex(minX, interpolate(minY, maxY, i + 1, voxelHeight), minZ, maxUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i - 1, pixelHeight))); + //Top-right corner + up.drawVertex(new Vertex(minX, interpolate(minY, maxY, i + 1, voxelHeight), maxZ, maxUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i, pixelHeight))); + //Top-left corner + up.drawVertex(new Vertex(maxX, interpolate(minY, maxY, i + 1, voxelHeight), maxZ, minUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i, pixelHeight))); + model.drawFace(up); + faces.add(up); + + Face down = new Face(); + down.texture = texture; + down.normal = Direction.DOWN.toVector(); + //Top-left corner + down.drawVertex(new Vertex(maxX, interpolate(minY, maxY, i, voxelHeight), maxZ, minUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i, pixelHeight))); + //Top-right corner + down.drawVertex(new Vertex(minX, interpolate(minY, maxY, i, voxelHeight), maxZ, maxUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i, pixelHeight))); + //Bottom-right corner + down.drawVertex(new Vertex(minX, interpolate(minY, maxY, i, voxelHeight), minZ, maxUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i - 1, pixelHeight))); + //Bottom-left corner + down.drawVertex(new Vertex(maxX, interpolate(minY, maxY, i, voxelHeight), minZ, minUV.getX(), interpolate(minUV.getY(), maxUV.getY(), ((int)dimensions.getY()) - i - 1, pixelHeight))); + model.drawFace(down); + faces.add(down); + } + + return faces; + } + + public static Set drawLeftAndRight( + MeshModel model, + double minX, double minY, double minZ, + double maxX, double maxY, double maxZ, + Optional texture) { + + Vector2D minUV; + Vector2D maxUV; + Vector2D dimensions; + + if (texture.isPresent()) { + minUV = texture.get().minUV(); + maxUV = texture.get().maxUV(); + dimensions = texture.get().dimension; + } else { + minUV = Vector2D.ZERO; + maxUV = Vector2DUtil.ONE; + dimensions = new Vector2D(1, 1); + } + + Set faces = new HashSet<>(); + + double pixelWidth = (maxUV.getX() - minUV.getX()) / dimensions.getX(); + double voxelWidth = Math.abs(maxX - minX) / dimensions.getX(); + + + for (int i = 0; i < dimensions.getX(); i++) { + Face left = new Face(); + left.texture = texture; + left.normal = Direction.WEST.toVector(); + //Bottom-left corner + left.drawVertex(new Vertex(interpolate(minX, maxX, i, voxelWidth), minY, minZ, interpolate(minUV.getX(), maxUV.getX(), i, pixelWidth), minUV.getY())); + //Bottom-right corner + left.drawVertex(new Vertex(interpolate(minX, maxX, i, voxelWidth), minY, maxZ, interpolate(minUV.getX(), maxUV.getX(), i + 1, pixelWidth), minUV.getY())); + //Top-right corner + left.drawVertex(new Vertex(interpolate(minX, maxX, i, voxelWidth), maxY, maxZ, interpolate(minUV.getX(), maxUV.getX(), i + 1, pixelWidth), maxUV.getY())); + //Top-left corner + left.drawVertex(new Vertex(interpolate(minX, maxX, i, voxelWidth), maxY, minZ, interpolate(minUV.getX(), maxUV.getX(), i, pixelWidth), maxUV.getY())); + model.drawFace(left); + faces.add(left); + + Face right = new Face(); + right.texture = texture; + right.normal = Direction.EAST.toVector(); + //Top-left corner + right.drawVertex(new Vertex(interpolate(minX, maxX, i + 1, voxelWidth), maxY, minZ, interpolate(minUV.getX(), maxUV.getX(), i, pixelWidth), maxUV.getY())); + //Top-right corner + right.drawVertex(new Vertex(interpolate(minX, maxX, i + 1, voxelWidth), maxY, maxZ, interpolate(minUV.getX(), maxUV.getX(), i + 1, pixelWidth), maxUV.getY())); + //Bottom-right corner + right.drawVertex(new Vertex(interpolate(minX, maxX, i + 1, voxelWidth), minY, maxZ, interpolate(minUV.getX(), maxUV.getX(), i + 1, pixelWidth), minUV.getY())); + //Bottom-left corner + right.drawVertex(new Vertex(interpolate(minX, maxX, i + 1, voxelWidth), minY, minZ, interpolate(minUV.getX(), maxUV.getX(), i, pixelWidth), minUV.getY())); + model.drawFace(right); + faces.add(right); + } + + return faces; + } + + private static double interpolate(double min, double max, int index, double indexSize) { + if (indexSize > 0) { + if (max > min) { + return min + indexSize * index; + } else if (max < min) { + return max + indexSize * index; + } + } else if (indexSize < 0) { + if (max > min) { + return min - indexSize * index; + } else if (max < min) { + return max - indexSize * index; + } + } + + return min == max ? min : max; + } +}