Added connected textures renderer

This commit is contained in:
bdew committed 2014-08-11 16:51:18 +03:00
1 parent 490433a7f4
commit 9fdc6bd880
4 files changed
+279

No files matched your search

@@ -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]
}
@@ -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
}
}
@@ -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
}
@@ -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
}