ClassiCube/ClassicalSharp/2D/IsometricBlockDrawer.cs
2016-12-21 14:27:24 +11:00

249 lines
9.2 KiB
C#

// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Model;
using ClassicalSharp.Textures;
using OpenTK;
namespace ClassicalSharp {
public sealed class IsometricBlockDrawer {
Game game;
TerrainAtlas1D atlas;
int index;
float scale;
Vector3 minBB, maxBB;
const float invElemSize = TerrainAtlas2D.invElementSize;
bool fullBright;
VertexP3fT2fC4b[] vertices;
int vb;
public void BeginBatch(Game game, VertexP3fT2fC4b[] vertices, int vb) {
this.game = game;
lastIndex = -1;
index = 0;
this.vertices = vertices;
this.vb = vb;
}
static int colNormal = FastColour.WhitePacked, colXSide, colZSide, colYBottom;
static float cosX, sinX, cosY, sinY;
static IsometricBlockDrawer() {
FastColour.GetShaded(FastColour.White, out colXSide, out colZSide, out colYBottom);
cosX = (float)Math.Cos(26.565f * Utils.Deg2Rad);
sinX = (float)Math.Sin(26.565f * Utils.Deg2Rad);
cosY = (float)Math.Cos(-45f * Utils.Deg2Rad);
sinY = (float)Math.Sin(-45f * Utils.Deg2Rad);
}
public void DrawBatch(byte block, float size, float x, float y) {
BlockInfo info = game.BlockInfo;
atlas = game.TerrainAtlas1D;
minBB = info.MinBB[block];
maxBB = info.MaxBB[block];
fullBright = info.FullBright[block];
if (info.Draw[block] == DrawType.Sprite) {
minBB = Vector3.Zero; maxBB = Vector3.One;
}
if (info.Draw[block] == DrawType.Gas) return;
// isometric coords size: cosY * -scale - sinY * scale
// we need to divide by (2 * cosY), as the calling function expects size to be in pixels.
scale = size / (2 * cosY);
// screen to isometric coords (cos(-x) = cos(x), sin(-x) = -sin(x))
pos.X = x; pos.Y = y; pos.Z = 0;
Utils.RotateX(ref pos.Y, ref pos.Z, cosX, -sinX);
Utils.RotateY(ref pos.X, ref pos.Z, cosY, -sinY);
if (info.Draw[block] == DrawType.Sprite) {
SpriteXQuad(block, true);
SpriteZQuad(block, true);
SpriteZQuad(block, false);
SpriteXQuad(block, false);
} else {
XQuad(block, maxBB.X, Side.Left);
ZQuad(block, minBB.Z, Side.Back);
YQuad(block, maxBB.Y, Side.Top);
}
}
public void EndBatch() {
if (index == 0) return;
if (texIndex != lastIndex)
game.Graphics.BindTexture(atlas.TexIds[texIndex]);
game.Graphics.UpdateDynamicIndexedVb(DrawMode.Triangles,
vb, vertices, index);
index = 0;
lastIndex = -1;
}
static Vector3 pos = Vector3.Zero;
void YQuad(byte block, float y, int side) {
int texLoc = game.BlockInfo.GetTextureLoc(block, side);
texIndex = texLoc / atlas.elementsPerAtlas1D;
if (lastIndex != texIndex) Flush();
VertexP3fT2fC4b v = default(VertexP3fT2fC4b);
v.Colour = colNormal;
if (game.BlockInfo.Tinted[block]) {
FastColour fogCol = game.BlockInfo.FogColour[block];
FastColour newCol = FastColour.Unpack(v.Colour);
newCol *= fogCol;
v.Colour = newCol.Pack();
}
TextureRec rec;
float vOrigin = (texLoc % atlas.elementsPerAtlas1D) * atlas.invElementSize;
rec.U1 = minBB.X; rec.U2 = maxBB.X;
rec.V1 = vOrigin + minBB.Z * atlas.invElementSize;
rec.V2 = vOrigin + maxBB.Z * atlas.invElementSize * (15.99f/16f);
y = scale * (1 - y * 2);
float minX = scale * (1 - minBB.X * 2), maxX = scale * (1 - maxBB.X * 2);
float minZ = scale * (1 - minBB.Z * 2), maxZ = scale * (1 - maxBB.Z * 2);
v.X = minX; v.Y = y; v.Z = minZ; v.U = rec.U2; v.V = rec.V2; Transform(ref v);
v.X = maxX; v.Y = y; v.Z = minZ; v.U = rec.U1; v.V = rec.V2; Transform(ref v);
v.X = maxX; v.Y = y; v.Z = maxZ; v.U = rec.U1; v.V = rec.V1; Transform(ref v);
v.X = minX; v.Y = y; v.Z = maxZ; v.U = rec.U2; v.V = rec.V1; Transform(ref v);
}
void ZQuad(byte block, float z, int side) {
int texLoc = game.BlockInfo.GetTextureLoc(block, side);
texIndex = texLoc / atlas.elementsPerAtlas1D;
if (lastIndex != texIndex) Flush();
VertexP3fT2fC4b v = default(VertexP3fT2fC4b);
v.Colour = fullBright ? colNormal : colZSide;
if (game.BlockInfo.Tinted[block]) {
FastColour fogCol = game.BlockInfo.FogColour[block];
FastColour newCol = FastColour.Unpack(v.Colour);
newCol *= fogCol;
v.Colour = newCol.Pack();
}
TextureRec rec;
float vOrigin = (texLoc % atlas.elementsPerAtlas1D) * atlas.invElementSize;
rec.U1 = minBB.X; rec.U2 = maxBB.X;
rec.V1 = vOrigin + (1 - minBB.Y) * atlas.invElementSize;
rec.V2 = vOrigin + (1 - maxBB.Y) * atlas.invElementSize * (15.99f/16f);
z = scale * (1 - z * 2);
float minX = scale * (1 - minBB.X * 2), maxX = scale * (1 - maxBB.X * 2);
float minY = scale * (1 - minBB.Y * 2), maxY = scale * (1 - maxBB.Y * 2);
v.X = minX; v.Y = maxY; v.Z = z; v.U = rec.U2; v.V = rec.V2; Transform(ref v);
v.X = minX; v.Y = minY; v.Z = z; v.U = rec.U2; v.V = rec.V1; Transform(ref v);
v.X = maxX; v.Y = minY; v.Z = z; v.U = rec.U1; v.V = rec.V1; Transform(ref v);
v.X = maxX; v.Y = maxY; v.Z = z; v.U = rec.U1; v.V = rec.V2; Transform(ref v);
}
void XQuad(byte block, float x, int side) {
int texLoc = game.BlockInfo.GetTextureLoc(block, side);
texIndex = texLoc / atlas.elementsPerAtlas1D;
if (lastIndex != texIndex) Flush();
VertexP3fT2fC4b v = default(VertexP3fT2fC4b);
v.Colour = fullBright ? colNormal : colXSide;
if (game.BlockInfo.Tinted[block]) {
FastColour fogCol = game.BlockInfo.FogColour[block];
FastColour newCol = FastColour.Unpack(v.Colour);
newCol *= fogCol;
v.Colour = newCol.Pack();
}
TextureRec rec;
float vOrigin = (texLoc % atlas.elementsPerAtlas1D) * atlas.invElementSize;
rec.U1 = minBB.Z; rec.U2 = maxBB.Z;
rec.V1 = vOrigin + (1 - minBB.Y) * atlas.invElementSize;
rec.V2 = vOrigin + (1 - maxBB.Y) * atlas.invElementSize * (15.99f/16f);
x = scale * (1 - x * 2);
float minY = scale * (1 - minBB.Y * 2), maxY = scale * (1 - maxBB.Y * 2);
float minZ = scale * (1 - minBB.Z * 2), maxZ = scale * (1 - maxBB.Z * 2);
v.X = x; v.Y = maxY; v.Z = minZ; v.U = rec.U2; v.V = rec.V2; Transform(ref v);
v.X = x; v.Y = minY; v.Z = minZ; v.U = rec.U2; v.V = rec.V1; Transform(ref v);
v.X = x; v.Y = minY; v.Z = maxZ; v.U = rec.U1; v.V = rec.V1; Transform(ref v);
v.X = x; v.Y = maxY; v.Z = maxZ; v.U = rec.U1; v.V = rec.V2; Transform(ref v);
}
void SpriteZQuad(byte block, bool firstPart) {
int texLoc = game.BlockInfo.GetTextureLoc(block, Side.Right);
TextureRec rec = atlas.GetTexRec(texLoc, 1, out texIndex);
if (lastIndex != texIndex) Flush();
VertexP3fT2fC4b v = default(VertexP3fT2fC4b);
v.Colour = colNormal;
if (game.BlockInfo.Tinted[block]) {
FastColour fogCol = game.BlockInfo.FogColour[block];
FastColour newCol = FastColour.Unpack(v.Colour);
newCol *= fogCol;
v.Colour = newCol.Pack();
}
float x1 = firstPart ? 0.5f : -0.1f, x2 = firstPart ? 1.1f : 0.5f;
rec.U1 = firstPart ? 0.0f : 0.5f; rec.U2 = (firstPart ? 0.5f : 1.0f) * (15.99f/16f);
float minX = scale * (1 - x1 * 2), maxX = scale * (1 - x2 * 2);
float minY = scale * (1 - 0 * 2), maxY = scale * (1 - 1.1f * 2);
v.X = minX; v.Y = minY; v.Z = 0; v.U = rec.U2; v.V = rec.V2; Transform(ref v);
v.X = minX; v.Y = maxY; v.Z = 0; v.U = rec.U2; v.V = rec.V1; Transform(ref v);
v.X = maxX; v.Y = maxY; v.Z = 0; v.U = rec.U1; v.V = rec.V1; Transform(ref v);
v.X = maxX; v.Y = minY; v.Z = 0; v.U = rec.U1; v.V = rec.V2; Transform(ref v);
}
void SpriteXQuad(byte block, bool firstPart) {
int texLoc = game.BlockInfo.GetTextureLoc(block, Side.Right);
TextureRec rec = atlas.GetTexRec(texLoc, 1, out texIndex);
if (lastIndex != texIndex) Flush();
VertexP3fT2fC4b v = default(VertexP3fT2fC4b);
v.Colour = colNormal;
if (game.BlockInfo.Tinted[block]) {
FastColour fogCol = game.BlockInfo.FogColour[block];
FastColour newCol = FastColour.Unpack(v.Colour);
newCol *= fogCol;
v.Colour = newCol.Pack();
}
float z1 = firstPart ? 0.5f : -0.1f, z2 = firstPart ? 1.1f : 0.5f;
rec.U1 = firstPart ? 0.0f : 0.5f; rec.U2 = (firstPart ? 0.5f : 1.0f) * (15.99f/16f);
float minY = scale * (1 - 0 * 2), maxY = scale * (1 - 1.1f * 2);
float minZ = scale * (1 - z1 * 2), maxZ = scale * (1 - z2 * 2);
v.X = 0; v.Y = minY; v.Z = minZ; v.U = rec.U2; v.V = rec.V2; Transform(ref v);
v.X = 0; v.Y = maxY; v.Z = minZ; v.U = rec.U2; v.V = rec.V1; Transform(ref v);
v.X = 0; v.Y = maxY; v.Z = maxZ; v.U = rec.U1; v.V = rec.V1; Transform(ref v);
v.X = 0; v.Y = minY; v.Z = maxZ; v.U = rec.U1; v.V = rec.V2; Transform(ref v);
}
int lastIndex, texIndex;
void Flush() {
if (lastIndex != -1) {
game.Graphics.UpdateDynamicIndexedVb(DrawMode.Triangles, vb, vertices, index);
index = 0;
}
lastIndex = texIndex;
game.Graphics.BindTexture(atlas.TexIds[texIndex]);
}
void Transform(ref VertexP3fT2fC4b v) {
v.X += pos.X; v.Y += pos.Y; v.Z += pos.Z;
//Vector3 p = new Vector3(v.X, v.Y, v.Z) + pos;
//p = Utils.RotateY(p - pos, time) + pos;
//v coords = p
// See comment in IGraphicsApi.Draw2DTexture()
v.X -= 0.5f; v.Y -= 0.5f;
float t = cosY * v.X - sinY * v.Z; v.Z = sinY * v.X + cosY * v.Z; v.X = t; // Inlined RotY
t = cosX * v.Y + sinX * v.Z; v.Z = -sinX * v.Y + cosX * v.Z; v.Y = t; // Inlined RotX
vertices[index++] = v;
}
}
}