VoxelUnity/Assets/Scripts/Chunk.cs

411 lines
13 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chunk : MonoBehaviour {
public enum Direction {x_neg, y_neg, z_neg, x_pos, y_pos, z_pos};
// rawData:
public const int N_CHUNK_SIDELENGTH = 16; // FIXME: bad naming
public const int N_CHUNK_SIDELENGTH_SQRD = 256; //16 * 16
public const int N_CHUNK_BLOCKS=4096; //16*16*16
private int[] data = new int[N_CHUNK_BLOCKS];
protected MeshFilter meshFilter;
protected List<Vector3> vertices;
protected List<int> tris;
protected List<Vector3> normals;
protected List<Color> colors;
protected int[] chunk_position = new int[3] {0,0,0};
protected Vector3Int chunk_position_vec;
public int[] ChunkPosition
{
get
{
return chunk_position;
}
set
{
chunk_position = value;
chunk_position_vec = new Vector3Int(value[0], value[1], value[2]);
}
}
public Vector3Int ChunkPositionVec
{
get
{
return chunk_position_vec;
}
set
{
chunk_position_vec = value;
chunk_position = new int[3] {value.x, value.y, value.z};
}
}
protected Chunk[] neighbor_chunks = new Chunk[6];
public Chunk[] NeighborChunks
{
get
{
return neighbor_chunks;
}
}
public int[] Data
{
get
{
return data;
}
set
{
data = value;
}
}
public void ConnectChunk(Chunk chunk, Direction direction)
{
neighbor_chunks[(int) direction] = chunk;
chunk.neighbor_chunks[((int) direction + 3) % 6] = this;
}
void Awake()
{
meshFilter = this.gameObject.AddComponent<MeshFilter>();
meshFilter.mesh.MarkDynamic();
vertices = new List<Vector3>();
tris = new List<int>();
normals = new List<Vector3>();
colors = new List<Color>();
}
// Use this for initialization
void Start () {
}
public void SetDataFromMessageObject(MessageObject mo)
{
if (mo.data == null)
{
throw new System.Exception("received empty data block");
}
if (mo.data.Length != 4096)
{
throw new System.Exception("bad data received");
}
Data = mo.data;
}
public void Index2Coords(int i, int[] coords)
{
coords[0] = i % N_CHUNK_SIDELENGTH;
coords[1] = (i / N_CHUNK_SIDELENGTH) % N_CHUNK_SIDELENGTH;
coords[2] = i / (N_CHUNK_SIDELENGTH * N_CHUNK_SIDELENGTH);
}
public int Coords2Index(int[] coords)
{
return coords[0] + coords[1] * N_CHUNK_SIDELENGTH + coords[2] * N_CHUNK_SIDELENGTH_SQRD;
}
protected Color CalculateColor(int[] coords)
{
return Color.blue + (((float)coords[1] + chunk_position[1] * N_CHUNK_SIDELENGTH) / (float)WorldManager.Instance.WorldHeight) * (Color.green - Color.blue);
}
protected void AddPlane(Vector3 normal, Vector3 pos, Color color)
{
/*
plane looks like this:
b
/|
/ |
/ |
normal a |
<------|-+---------+pos (center of cube)
| c
| /
| /
|/
d
*/
Vector3 a,b,c,d;
Vector3 normal_flipped = Vector3.one - normal;
float half_normal;
if (normal.x * normal.x > 0)
{
half_normal = .5f * normal.x;
a = new Vector3(half_normal, half_normal, half_normal);
b = new Vector3(half_normal, half_normal, -half_normal);
c = new Vector3(half_normal, -half_normal, -half_normal);
d = new Vector3(half_normal, -half_normal, half_normal);
}
else if (normal.y * normal.y > 0)
{
half_normal = .5f * normal.y;
a = new Vector3( half_normal, half_normal, half_normal);
b = new Vector3(-half_normal, half_normal, half_normal);
c = new Vector3(-half_normal, half_normal, -half_normal);
d = new Vector3( half_normal, half_normal, -half_normal);
}
else
{
half_normal = .5f * normal.z;
a = new Vector3( half_normal, half_normal, half_normal);
b = new Vector3( half_normal, -half_normal, half_normal);
c = new Vector3(-half_normal, -half_normal, half_normal);
d = new Vector3(-half_normal, half_normal, half_normal);
}
a += pos;
b += pos;
c += pos;
d += pos;
int n = vertices.Count;
vertices.Add(a);
vertices.Add(half_normal > 0 ? d : b); // forcing clockwise built triangles
vertices.Add(c);
vertices.Add(half_normal > 0 ? b : d);
tris.Add(n + 0);
tris.Add(n + 1);
tris.Add(n + 2);
tris.Add(n + 2);
tris.Add(n + 3);
tris.Add(n + 0);
normals.Add(normal);
normals.Add(normal);
normals.Add(normal);
normals.Add(normal);
colors.Add(color);
colors.Add(color);
colors.Add(color);
colors.Add(color);
}
// Build the chunk mesh from ground up
public void BuildMesh()
{
vertices.Clear();
tris.Clear();
normals.Clear();
colors.Clear();
int i = 0;
int[] pos = new int[3];
int[] pos_buffer = new int[3];
Index2Coords(i, pos);
// iterate through the raw data:
foreach (int d in Data)
{
int k = 0;
if (d == 0)
{
// since there is air here, the adjacent blocks are visible. So we will draw the adjacent sides
// manually go through 6 neighbors:
pos_buffer[0] = pos[0];
pos_buffer[1] = pos[1];
pos_buffer[2] = pos[2];
// x axis
if (pos[0] > 0)
{
pos_buffer[0] -= 1;
k = Coords2Index(pos_buffer);
if (Data[k] != 0)
{
AddPlane(Vector3.right, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[0] += 1;
}
else if (neighbor_chunks[(int)Direction.x_neg])
{
//wraparound
pos_buffer[0] = N_CHUNK_SIDELENGTH - 1;
k = Coords2Index(pos_buffer);
pos_buffer[0] = -1;
if (neighbor_chunks[(int) Direction.x_neg].Data[k] != 0)
{
AddPlane(Vector3.right, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[0] = 0;
}
if (pos[0] + 1 < N_CHUNK_SIDELENGTH)
{
pos_buffer[0] += 1;
k = Coords2Index(pos_buffer);
if (Data[k] != 0)
{
AddPlane(Vector3.left, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[0] -= 1;
}
else if (neighbor_chunks[(int)Direction.x_pos])
{
//wraparound
pos_buffer[0] = 0;
k = Coords2Index(pos_buffer);
pos_buffer[0] = N_CHUNK_SIDELENGTH;
if (neighbor_chunks[(int) Direction.x_pos].Data[k] != 0)
{
AddPlane(Vector3.left, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[0] = N_CHUNK_SIDELENGTH - 1;
}
// y axis
if (pos[1] > 0)
{
pos_buffer[1] -= 1;
k = Coords2Index(pos_buffer);
if (Data[k] != 0)
{
AddPlane(Vector3.up, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[1] += 1;
}
else if (neighbor_chunks[(int)Direction.y_neg])
{
//wraparound
pos_buffer[1] = N_CHUNK_SIDELENGTH - 1;
k = Coords2Index(pos_buffer);
pos_buffer[1] = -1;
if (neighbor_chunks[(int) Direction.y_neg].Data[k] != 0)
{
AddPlane(Vector3.up, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[1] = 0;
}
if (pos[1] + 1 < N_CHUNK_SIDELENGTH)
{
pos_buffer[1] += 1;
k = Coords2Index(pos_buffer);
if (Data[k] != 0)
{
AddPlane(Vector3.down, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[1] -= 1;
}
else if (neighbor_chunks[(int)Direction.y_pos])
{
//wraparound
pos_buffer[1] = 0;
k = Coords2Index(pos_buffer);
pos_buffer[1] = N_CHUNK_SIDELENGTH;
if (neighbor_chunks[(int) Direction.y_pos].Data[k] != 0)
{
AddPlane(Vector3.down, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[1] = N_CHUNK_SIDELENGTH - 1;
}
// z axis
if (pos[2] > 0)
{
pos_buffer[2] -= 1;
k = Coords2Index(pos_buffer);
if (Data[k] != 0)
{
AddPlane(Vector3.forward, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[2] += 1;
}
else if (neighbor_chunks[(int)Direction.z_neg])
{
//wraparound
pos_buffer[2] = N_CHUNK_SIDELENGTH - 1;
k = Coords2Index(pos_buffer);
pos_buffer[2] = -1;
if (neighbor_chunks[(int) Direction.z_neg].Data[k] != 0)
{
AddPlane(Vector3.forward, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[2] = 0;
}
if (pos[2] + 1 < N_CHUNK_SIDELENGTH)
{
pos_buffer[2] += 1;
k = Coords2Index(pos_buffer);
if (Data[k] != 0)
{
AddPlane(Vector3.back, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[2] -= 1;
}
else if (neighbor_chunks[(int)Direction.z_pos])
{
//wraparound
pos_buffer[2] = 0;
k = Coords2Index(pos_buffer);
pos_buffer[2] = N_CHUNK_SIDELENGTH;
if (neighbor_chunks[(int) Direction.z_pos].Data[k] != 0)
{
AddPlane(Vector3.back, new Vector3(pos_buffer[0], pos_buffer[1], pos_buffer[2]), CalculateColor(pos_buffer));
}
pos_buffer[2] = N_CHUNK_SIDELENGTH - 1;
}
}
i += 1;
Index2Coords(i, pos);
}
}
public void AssignMesh()
{
meshFilter.mesh.Clear();
meshFilter.mesh.vertices = vertices.ToArray();
meshFilter.mesh.triangles = tris.ToArray();
meshFilter.mesh.normals = normals.ToArray();
meshFilter.mesh.colors = colors.ToArray();
}
// Update is called once per frame
void Update () {
//Pulse();
}
}