diff --git a/src/net/bdew/lib/render/connected/BlockAdditionalRender.scala b/src/net/bdew/lib/render/connected/BlockAdditionalRender.scala new file mode 100644 index 0000000..b38c862 --- /dev/null +++ b/src/net/bdew/lib/render/connected/BlockAdditionalRender.scala @@ -0,0 +1,23 @@ +/* + * Copyright (c) bdew, 2013 - 2014 + * https://github.com/bdew/bdlib + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt + */ + +package net.bdew.lib.render.connected + +import net.bdew.lib.gui.Color +import net.minecraft.util.IIcon +import net.minecraft.world.IBlockAccess +import net.minecraftforge.common.util.ForgeDirection + +case class FaceOverlay(icon: IIcon, color: Color) { + def this(icon: IIcon, color: (Float, Float, Float)) = this(icon, new Color(color._1, color._2, color._3)) +} + +trait BlockAdditionalRender { + def getFaceOverlays(world: IBlockAccess, x: Int, y: Int, z: Int, face: ForgeDirection): List[FaceOverlay] +} diff --git a/src/net/bdew/lib/render/connected/ConnectedHelper.scala b/src/net/bdew/lib/render/connected/ConnectedHelper.scala new file mode 100644 index 0000000..aaf224d --- /dev/null +++ b/src/net/bdew/lib/render/connected/ConnectedHelper.scala @@ -0,0 +1,121 @@ +/* + * Copyright (c) bdew, 2013 - 2014 + * https://github.com/bdew/bdlib + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt + */ + +package net.bdew.lib.render.connected + +import net.bdew.lib.block.BlockRef +import net.minecraft.client.renderer.Tessellator +import net.minecraft.util.IIcon +import net.minecraftforge.common.util.ForgeDirection + +object ConnectedHelper { + val edgeWidth = 1 / 16F + + // Represents the rectangles of all edges/corners on a 2d pane + // 701 + // 6 2 + // 543 + // 8 is a special case for the full face + val faceEdges = Array( + RectF(0, 1 - edgeWidth, 1, 1), + RectF(1 - edgeWidth, 1 - edgeWidth, 1, 1), + RectF(1 - edgeWidth, 0, 1, 1), + RectF(1 - edgeWidth, 0, 1, edgeWidth), + RectF(0, 0, 1, edgeWidth), + RectF(0, 0, edgeWidth, edgeWidth), + RectF(0, 0, edgeWidth, 1), + RectF(0, 1 - edgeWidth, edgeWidth, 1), + RectF(0, 0, 1, 1) + ) + + val faceAdjanced = (for (x <- ForgeDirection.VALID_DIRECTIONS) yield x -> new FaceAdjanced(x)).toMap + + // Maps edge number + face to 3d vertices + val draw = + (for ((rect, n) <- faceEdges.zipWithIndex; face <- ForgeDirection.VALID_DIRECTIONS) + yield (face, n) -> new EdgeDraw(rect, face)).toMap + + val brightnessMultiplier = Map( + ForgeDirection.UP -> 1F, + ForgeDirection.DOWN -> 0.5F, + ForgeDirection.NORTH -> 0.8F, + ForgeDirection.SOUTH -> 0.8F, + ForgeDirection.WEST -> 0.6F, + ForgeDirection.EAST -> 0.6F + ) + + case class Vec3F(x: Float, y: Float, z: Float) { + def *(m: Float) = Vec3F(x * m, y * m, z * m) + def +(m: Vec3F) = Vec3F(x + m.x, y + m.y, z + m.z) + def -(m: Vec3F) = Vec3F(x - m.x, y - m.y, z - m.z) + def +(d: ForgeDirection) = Vec3F(x + d.offsetX, y + d.offsetY, z + d.offsetZ) + def toInts = (x.toInt, y.toInt, z.toInt) + def asBlockRef = BlockRef(x.toInt, y.toInt, z.toInt) + } + + case class RectF(x1: Float, y1: Float, x2: Float, y2: Float) { + def corners = Seq(Vec2F(x1, y1), Vec2F(x2, y1), Vec2F(x2, y2), Vec2F(x1, y2)) + } + + case class Vec2F(u: Float, v: Float) + + case class VecPair(pos: Vec3F, tex: Vec2F) + + class EdgeDraw(rect: RectF, face: ForgeDirection) { + val vertices = rect.corners map { d => + val v = face match { + case ForgeDirection.UP => Vec3F(d.u, 1, 1 - d.v) + case ForgeDirection.DOWN => Vec3F(d.u, 0, d.v) + case ForgeDirection.NORTH => Vec3F(1 - d.u, d.v, 0) + case ForgeDirection.SOUTH => Vec3F(d.u, d.v, 1) + case ForgeDirection.EAST => Vec3F(1, d.v, 1 - d.u) + case ForgeDirection.WEST => Vec3F(0, d.v, d.u) + case _ => sys.error("Invalid face") + } + VecPair(extend(v, 0.001F), d) + } + + def doDraw(pos: Vec3F, icon: IIcon) { + for (v <- vertices) + addVertextWithUV(v.pos + pos, mapToIcon(v.tex, icon)) + } + } + + def extend(v: Vec3F, o: Float) = Vec3F( + if (v.x == 0F) -o else if (v.x == 1F) 1 + o else v.x, + if (v.y == 0F) -o else if (v.y == 1F) 1 + o else v.y, + if (v.z == 0F) -o else if (v.z == 1F) 1 + o else v.z + ) + + def mapToIcon(v: Vec2F, i: IIcon) = Vec2F(i.getInterpolatedU(v.u * 16), i.getInterpolatedV((1 - v.v) * 16)) + + def addVertextWithUV(p: Vec3F, t: Vec2F) = + Tessellator.instance.addVertexWithUV(p.x, p.y, p.z, t.u, t.v) + + class FaceAdjanced(d: ForgeDirection) { + val top = d match { + case ForgeDirection.UP => ForgeDirection.NORTH + case ForgeDirection.DOWN => ForgeDirection.SOUTH + case _ => ForgeDirection.UP + } + + val right = d match { + case ForgeDirection.UP => ForgeDirection.EAST + case ForgeDirection.DOWN => ForgeDirection.EAST + case ForgeDirection.NORTH => ForgeDirection.WEST + case ForgeDirection.WEST => ForgeDirection.SOUTH + case ForgeDirection.SOUTH => ForgeDirection.EAST + case ForgeDirection.EAST => ForgeDirection.NORTH + case _ => ForgeDirection.UNKNOWN + } + val bottom = top.getOpposite + val left = right.getOpposite + } + +} diff --git a/src/net/bdew/lib/render/connected/ConnectedRenderer.scala b/src/net/bdew/lib/render/connected/ConnectedRenderer.scala new file mode 100644 index 0000000..119abf2 --- /dev/null +++ b/src/net/bdew/lib/render/connected/ConnectedRenderer.scala @@ -0,0 +1,113 @@ +/* + * Copyright (c) bdew, 2013 - 2014 + * https://github.com/bdew/bdlib + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt + */ + +package net.bdew.lib.render.connected + +import cpw.mods.fml.client.registry.{ISimpleBlockRenderingHandler, RenderingRegistry} +import net.bdew.lib.block.BlockRef +import net.minecraft.block.Block +import net.minecraft.client.renderer.{RenderBlocks, Tessellator} +import net.minecraft.world.IBlockAccess +import net.minecraftforge.common.util.ForgeDirection +import org.lwjgl.opengl.GL11 + +object ConnectedRenderer extends ISimpleBlockRenderingHandler { + val id = RenderingRegistry.getNextAvailableRenderId + RenderingRegistry.registerBlockHandler(this) + + def doRenderItemSide(d: ForgeDirection, r: RenderBlocks, block: Block, meta: Int) = { + val icon = r.getBlockIconFromSideAndMetadata(block, d.ordinal(), meta) + Tessellator.instance.setNormal(d.offsetX, d.offsetY, d.offsetZ) + d match { + case ForgeDirection.DOWN => r.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, icon) + case ForgeDirection.UP => r.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, icon) + case ForgeDirection.NORTH => r.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, icon) + case ForgeDirection.SOUTH => r.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, icon) + case ForgeDirection.WEST => r.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, icon) + case ForgeDirection.EAST => r.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, icon) + case _ => sys.error("Invalid side") + } + } + + override def renderInventoryBlock(block: Block, metadata: Int, modelID: Int, renderer: RenderBlocks) { + val tessellator = Tessellator.instance + GL11.glTranslatef(-0.5F, -0.5F, -0.5F) + + val edge = block.asInstanceOf[ConnectedTextureBlock].edgeIcon + + for (side <- ForgeDirection.VALID_DIRECTIONS) { + tessellator.startDrawingQuads() + doRenderItemSide(side, renderer, block, metadata) + val m = ConnectedHelper.brightnessMultiplier(side) + ConnectedHelper.draw(side, 8).doDraw(ConnectedHelper.Vec3F(0, 0, 0), edge) + tessellator.draw() + } + + GL11.glTranslatef(0.5F, 0.5F, 0.5F) + } + + override def renderWorldBlock(world: IBlockAccess, x: Int, y: Int, z: Int, block: Block, modelId: Int, renderer: RenderBlocks): Boolean = { + renderer.renderStandardBlock(block, x, y, z) + + val pos = ConnectedHelper.Vec3F(x, y, z) + for (face <- ForgeDirection.VALID_DIRECTIONS) + if (block.shouldSideBeRendered(world, x + face.offsetX, y + face.offsetY, z + face.offsetZ, face.ordinal())) + drawFaceEdges(world, pos, face, block.asInstanceOf[ConnectedTextureBlock]) + + return true + } + + def drawFaceEdges(world: IBlockAccess, pos: ConnectedHelper.Vec3F, face: ForgeDirection, block: ConnectedTextureBlock) { + val edge = block.edgeIcon + val canConnect = block.canConnect(world, pos.asBlockRef, _: BlockRef) + val sides = ConnectedHelper.faceAdjanced(face) + + val m = ConnectedHelper.brightnessMultiplier(face) + Tessellator.instance.setColorOpaque_F(m, m, m) + + val fo = pos + face + val b = block.getMixedBrightnessForBlock(world, fo.x.toInt, fo.y.toInt, fo.z.toInt) + Tessellator.instance.setBrightness(b) + + val U = !canConnect((pos + sides.top).asBlockRef) + val D = !canConnect((pos + sides.bottom).asBlockRef) + val L = !canConnect((pos + sides.left).asBlockRef) + val R = !canConnect((pos + sides.right).asBlockRef) + + if (!U && !R && !canConnect((pos + sides.top + sides.right).asBlockRef)) + ConnectedHelper.draw(face, 1).doDraw(pos, edge) + + if (!U && !L && !canConnect((pos + sides.top + sides.left).asBlockRef)) + ConnectedHelper.draw(face, 7).doDraw(pos, edge) + + if (!D && !R && !canConnect((pos + sides.bottom + sides.right).asBlockRef)) + ConnectedHelper.draw(face, 3).doDraw(pos, edge) + + if (!D && !L && !canConnect((pos + sides.bottom + sides.left).asBlockRef)) + ConnectedHelper.draw(face, 5).doDraw(pos, edge) + + if (U) ConnectedHelper.draw(face, 0).doDraw(pos, edge) + if (D) ConnectedHelper.draw(face, 4).doDraw(pos, edge) + if (R) ConnectedHelper.draw(face, 2).doDraw(pos, edge) + if (L) ConnectedHelper.draw(face, 6).doDraw(pos, edge) + + if (block.isInstanceOf[BlockAdditionalRender]) { + val overlays = block.asInstanceOf[BlockAdditionalRender].getFaceOverlays(world, pos.x.toInt, pos.y.toInt, pos.z.toInt, face) + for (overlay <- overlays) { + Tessellator.instance.setColorOpaque_F(overlay.color.r, overlay.color.g, overlay.color.b) + ConnectedHelper.draw(face, 8).doDraw(pos, overlay.icon) + } + } + } + + override def shouldRender3DInInventory(modelId: Int) = true + override def getRenderId = id +} + + diff --git a/src/net/bdew/lib/render/connected/ConnectedTextureBlock.scala b/src/net/bdew/lib/render/connected/ConnectedTextureBlock.scala new file mode 100644 index 0000000..b59b133 --- /dev/null +++ b/src/net/bdew/lib/render/connected/ConnectedTextureBlock.scala @@ -0,0 +1,22 @@ +/* + * Copyright (c) bdew, 2013 - 2014 + * https://github.com/bdew/bdlib + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * https://raw.github.com/bdew/bdlib/master/MMPL-1.0.txt + */ + +package net.bdew.lib.render.connected + +import net.bdew.lib.block.BlockRef +import net.minecraft.block.Block +import net.minecraft.util.IIcon +import net.minecraft.world.IBlockAccess + +trait ConnectedTextureBlock extends Block { + def edgeIcon: IIcon + def canConnect(world: IBlockAccess, origin: BlockRef, target: BlockRef): Boolean + + override def getRenderType = ConnectedRenderer.id +}