diff --git a/src/main/resources/assets/opencomputers/textures/model/drone_item.png b/src/main/resources/assets/opencomputers/textures/model/drone_item.png new file mode 100644 index 000000000..b5fd7c606 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/model/drone_item.png differ diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 421b7cfb0..86eaff6d7 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -9,7 +9,6 @@ import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.util.ResourceLocation import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import org.lwjgl.opengl.GL11 import scala.collection.mutable @@ -74,6 +73,7 @@ object Textures { val UpgradeInventory = L("inventory_upgrade") val HologramEffect = L("hologram_effect") val Drone = L("drone") + val DroneItem = L("drone_item") val Robot = L("robot") override protected def basePath = "textures/model/%s.png" diff --git a/src/main/scala/li/cil/oc/client/renderer/block/DroneModel.scala b/src/main/scala/li/cil/oc/client/renderer/block/DroneModel.scala new file mode 100644 index 000000000..d967495d3 --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/block/DroneModel.scala @@ -0,0 +1,42 @@ +package li.cil.oc.client.renderer.block + +import li.cil.oc.client.Textures +import net.minecraft.block.state.IBlockState +import net.minecraft.client.renderer.block.model.BakedQuad +import net.minecraft.item.ItemStack +import net.minecraft.util.Vec3 +import net.minecraftforge.client.model.ISmartItemModel + +import scala.collection.convert.WrapAsJava.bufferAsJavaList +import scala.collection.mutable + +object DroneModel extends SmartBlockModelBase with ISmartItemModel { + override def handleBlockState(state: IBlockState) = new NullModel.Model() + + override def handleItemState(stack: ItemStack) = new ItemModel(stack) + + protected def droneTexture = Textures.getSprite(Textures.Model.DroneItem) + + protected def Boxes = Array( + makeBox(new Vec3(1f / 16f, 7f / 16f, 1f / 16f), new Vec3(7f / 16f, 8f / 16f, 7f / 16f)), + makeBox(new Vec3(1f / 16f, 7f / 16f, 9f / 16f), new Vec3(7f / 16f, 8f / 16f, 15f / 16f)), + makeBox(new Vec3(9f / 16f, 7f / 16f, 1f / 16f), new Vec3(15f / 16f, 8f / 16f, 7f / 16f)), + makeBox(new Vec3(9f / 16f, 7f / 16f, 9f / 16f), new Vec3(15f / 16f, 8f / 16f, 15f / 16f)), + rotateBox(makeBox(new Vec3(6f / 16f, 6f / 16f, 6f / 16f), new Vec3(10f / 16f, 9f / 16f, 10f / 16f)), 45) + ) + + class ItemModel(val stack: ItemStack) extends SmartBlockModelBase { + override protected def textureScale = 32f + + override def getGeneralQuads = { + val faces = mutable.ArrayBuffer.empty[BakedQuad] + + faces ++= Boxes.flatMap(box => bakeQuads(box, Array.fill(6)(droneTexture), None)) + + Textures.bind(Textures.Model.DroneItem) + + bufferAsJavaList(faces) + } + } + +} diff --git a/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala b/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala index 57667f580..f6d875b8a 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/ModelInitialization.scala @@ -5,6 +5,7 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.common.item.CustomModel import li.cil.oc.common.item.Delegate +import li.cil.oc.common.item.Delegator import net.minecraft.block.Block import net.minecraft.block.state.IBlockState import net.minecraft.client.Minecraft @@ -47,9 +48,9 @@ object ModelInitialization { } def init(): Unit = { - registerItems(meshableItems) - registerSubItems(itemDelegates) - registerSubItemsCustom(itemDelegatesCustom) + registerItems() + registerSubItems() + registerSubItemsCustom() } // ----------------------------------------------------------------------- // @@ -83,7 +84,7 @@ object ModelInitialization { }) } - private def registerItems(items: mutable.Buffer[Item]): Unit = { + private def registerItems(): Unit = { val meshDefinition = new ItemMeshDefinition { override def getModelLocation(stack: ItemStack) = { Option(api.Items.get(stack)) match { @@ -96,31 +97,33 @@ object ModelInitialization { } val modelMeshes = Minecraft.getMinecraft.getRenderItem.getItemModelMesher - for (item <- items) { + for (item <- meshableItems) { modelMeshes.register(item, meshDefinition) } - items.clear() + meshableItems.clear() } - private def registerSubItems(items: mutable.Buffer[(String, Delegate)]): Unit = { + private def registerSubItems(): Unit = { val modelMeshes = Minecraft.getMinecraft.getRenderItem.getItemModelMesher - for ((id, item) <- items) { + for ((id, item) <- itemDelegates) { val location = Settings.resourceDomain + ":" + id modelMeshes.register(item.parent, item.itemId, new ModelResourceLocation(location, "inventory")) ModelBakery.addVariantName(item.parent, location) } - items.clear() + itemDelegates.clear() } - private def registerSubItemsCustom(items: mutable.Buffer[Delegate with CustomModel]): Unit = { + private def registerSubItemsCustom(): Unit = { val modelMeshes = Minecraft.getMinecraft.getRenderItem.getItemModelMesher - for (item <- items) { + for (item <- itemDelegatesCustom) { modelMeshes.register(item.parent, new ItemMeshDefinition { - override def getModelLocation(stack: ItemStack): ModelResourceLocation = item.getModelLocation(stack) + override def getModelLocation(stack: ItemStack): ModelResourceLocation = Delegator.subItem(stack) match { + case Some(subItem: CustomModel) => subItem.getModelLocation(stack) + case _ => null + } }) item.registerModelLocations() } - items.clear() } // ----------------------------------------------------------------------- // @@ -136,6 +139,10 @@ object ModelInitialization { registry.putObject(RobotAfterimageBlockLocation, NullModel) registry.putObject(RobotAfterimageItemLocation, NullModel) + for (item <- itemDelegatesCustom) { + item.bakeModels(e) + } + val modelOverrides = Map[String, IFlexibleBakedModel => ISmartBlockModel]( Constants.BlockName.ScreenTier1 -> (_ => ScreenModel), Constants.BlockName.ScreenTier2 -> (_ => ScreenModel), diff --git a/src/main/scala/li/cil/oc/client/renderer/block/SmartBlockModelBase.scala b/src/main/scala/li/cil/oc/client/renderer/block/SmartBlockModelBase.scala index b593fa7e8..ffbf03140 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/SmartBlockModelBase.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/SmartBlockModelBase.scala @@ -78,6 +78,8 @@ trait SmartBlockModelBase extends ISmartBlockModel with ISmartItemModel { protected final val NoTint = -1 + protected def textureScale = 1f + /** * Generates a list of arrays, each containing the four vertices making up a * face of the box with the specified size. @@ -95,6 +97,24 @@ trait SmartBlockModelBase extends ISmartBlockModel with ISmartItemModel { math.max(minZ, math.min(maxZ, vertex.zCoord))))) } + protected def rotateVector(v: Vec3, angle: Double, axis: Vec3) = { + // vrot = v * cos(angle) + (axis x v) * sin(angle) + axis * (axis dot v)(1 - cos(angle)) + def scale(v: Vec3, s: Double) = new Vec3(v.xCoord * s, v.yCoord * s, v.zCoord * s) + val cosAngle = math.cos(angle) + val sinAngle = math.sin(angle) + scale(v, cosAngle). + add(scale(axis.crossProduct(v), sinAngle)). + add(scale(axis, axis.dotProduct(v) * (1 - cosAngle))) + } + + protected def rotateFace(face: Array[Vec3], angle: Double, axis: Vec3, around: Vec3 = new Vec3(0.5, 0.5, 0.5)) = { + face.map(v => rotateVector(v.subtract(around), angle, axis).add(around)) + } + + protected def rotateBox(box: Array[Array[Vec3]], angle: Double, axis: Vec3 = new Vec3(0, 1, 0), around: Vec3 = new Vec3(0.5, 0.5, 0.5)) = { + box.map(face => rotateFace(face, angle, axis, around)) + } + /** * Create the BakedQuads for a set of quads defined by the specified vertices. *
@@ -147,8 +167,8 @@ trait SmartBlockModelBase extends ISmartBlockModel with ISmartItemModel { java.lang.Float.floatToRawIntBits(y.toFloat), java.lang.Float.floatToRawIntBits(z.toFloat), getFaceShadeColor(face), - java.lang.Float.floatToRawIntBits(u), - java.lang.Float.floatToRawIntBits(v), + java.lang.Float.floatToRawIntBits(u * textureScale), + java.lang.Float.floatToRawIntBits(v * textureScale), 0 ) } diff --git a/src/main/scala/li/cil/oc/common/item/CustomModel.scala b/src/main/scala/li/cil/oc/common/item/CustomModel.scala index 6173d08a4..d0b9e0be5 100644 --- a/src/main/scala/li/cil/oc/common/item/CustomModel.scala +++ b/src/main/scala/li/cil/oc/common/item/CustomModel.scala @@ -2,6 +2,7 @@ package li.cil.oc.common.item import net.minecraft.client.resources.model.ModelResourceLocation import net.minecraft.item.ItemStack +import net.minecraftforge.client.event.ModelBakeEvent import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly @@ -10,5 +11,8 @@ trait CustomModel { def getModelLocation(stack: ItemStack): ModelResourceLocation @SideOnly(Side.CLIENT) - def registerModelLocations(): Unit + def registerModelLocations(): Unit = {} + + @SideOnly(Side.CLIENT) + def bakeModels(bakeEvent: ModelBakeEvent): Unit = {} } diff --git a/src/main/scala/li/cil/oc/common/item/Drone.scala b/src/main/scala/li/cil/oc/common/item/Drone.scala index d88d6e234..27f6ec454 100644 --- a/src/main/scala/li/cil/oc/common/item/Drone.scala +++ b/src/main/scala/li/cil/oc/common/item/Drone.scala @@ -2,22 +2,37 @@ package li.cil.oc.common.item import java.util +import li.cil.oc.Constants +import li.cil.oc.Settings import li.cil.oc.client.KeyBindings +import li.cil.oc.client.renderer.block.DroneModel import li.cil.oc.common.entity import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.integration.util.NEI import li.cil.oc.server.agent import li.cil.oc.util.BlockPosition import li.cil.oc.util.Rarity +import net.minecraft.client.resources.model.ModelResourceLocation import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing +import net.minecraftforge.client.event.ModelBakeEvent +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly -class Drone(val parent: Delegator) extends Delegate { +class Drone(val parent: Delegator) extends Delegate with CustomModel { NEI.hide(this) showInItemList = false + @SideOnly(Side.CLIENT) + override def getModelLocation(stack: ItemStack) = new ModelResourceLocation(Settings.resourceDomain + ":" + Constants.ItemName.Drone, "inventory") + + @SideOnly(Side.CLIENT) + override def bakeModels(bakeEvent: ModelBakeEvent): Unit = { + bakeEvent.modelRegistry.putObject(getModelLocation(createItemStack()), DroneModel) + } + override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = { if (KeyBindings.showExtendedTooltips) { val info = new MicrocontrollerData(stack)