1249 lines
58 KiB
C#
1249 lines
58 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Remoting.Messaging;
|
|
using System.Security.AccessControl;
|
|
using System.Security.Policy;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Forms.VisualStyles;
|
|
using VoxelIsometricRenderer.Properties;
|
|
|
|
namespace VoxelIsometricRenderer
|
|
{
|
|
public enum LightDirection
|
|
{
|
|
North,
|
|
NorthEast,
|
|
NorthWest,
|
|
East,
|
|
West,
|
|
SouthEast,
|
|
SouthWest,
|
|
South
|
|
}
|
|
public enum LightShape
|
|
{
|
|
Cylinder,
|
|
Sphere,
|
|
Cube,
|
|
Cuboid
|
|
}
|
|
public class LightSource
|
|
{
|
|
int RangeX;
|
|
int RangeY;
|
|
int RangeZ;
|
|
int XWorldPos;
|
|
int YWorldPos;
|
|
int ZWorldPos;
|
|
LightShape Shape;
|
|
byte[,,] LightLevels;
|
|
float[] LightLevelModifier = new float[] { 1.0f, 1.0f, 1.0f };
|
|
int Brightness = 64;
|
|
public void SetPosition(int[] pos)
|
|
{
|
|
XWorldPos = pos[0];
|
|
YWorldPos = pos[1];
|
|
ZWorldPos = pos[2];
|
|
}
|
|
public int[] GetPosition()
|
|
{
|
|
return new int[] { XWorldPos, YWorldPos, ZWorldPos };
|
|
}
|
|
public int[] GetRadius()
|
|
{
|
|
return new int[] {RangeX,RangeY, RangeZ };
|
|
}
|
|
public int GetAverageRadius()
|
|
{
|
|
return (RangeX + RangeY + RangeZ) / 3;
|
|
}
|
|
public float[] GetRGBLightLevels(int level)
|
|
{
|
|
float Multiplier = (float)level / 255.0f;
|
|
return new float[] { LightLevelModifier[0] * Multiplier, LightLevelModifier[1] * Multiplier, LightLevelModifier[2] * Multiplier };
|
|
}
|
|
public int GetLightLevel(int RelativeBlockX, int RelativeBlockY, int RelativeBlockZ, int face, bool BlocksLight)
|
|
{
|
|
int CentreX = LightLevels.GetLength(0) / 2;
|
|
int CentreY = LightLevels.GetLength(1) / 2;
|
|
int CentreZ = LightLevels.GetLength(2) / 2;
|
|
int LightLevel = 0;
|
|
|
|
if(RelativeBlockX >= 0 && RelativeBlockX < LightLevels.GetLength(0) &&
|
|
RelativeBlockY >= 0 && RelativeBlockY < LightLevels.GetLength(1) &&
|
|
RelativeBlockZ >= 0 && RelativeBlockZ < LightLevels.GetLength(2))
|
|
{
|
|
LightLevel = LightLevels[RelativeBlockX,RelativeBlockY,RelativeBlockZ];
|
|
int DirectionX = 0;
|
|
if (BlocksLight)
|
|
{
|
|
switch (face)
|
|
{
|
|
case 0:
|
|
if (CentreZ < RelativeBlockZ)
|
|
{
|
|
DirectionX = 180;
|
|
}
|
|
if (CentreZ == RelativeBlockZ)
|
|
{
|
|
DirectionX = 90;
|
|
}
|
|
if (CentreZ > RelativeBlockZ)
|
|
{
|
|
DirectionX = 0;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (CentreZ > RelativeBlockZ)
|
|
{
|
|
DirectionX = 180;
|
|
}
|
|
if (CentreZ == RelativeBlockZ)
|
|
{
|
|
DirectionX = 90;
|
|
}
|
|
if (CentreZ < RelativeBlockZ)
|
|
{
|
|
DirectionX = 0;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (CentreX < RelativeBlockX)
|
|
{
|
|
DirectionX = 180;
|
|
}
|
|
if (CentreX == RelativeBlockX)
|
|
{
|
|
DirectionX = 90;
|
|
}
|
|
if (CentreX > RelativeBlockX)
|
|
{
|
|
DirectionX = 0;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (CentreX > RelativeBlockX)
|
|
{
|
|
DirectionX = 180;
|
|
}
|
|
if (CentreX == RelativeBlockX)
|
|
{
|
|
DirectionX = 90;
|
|
}
|
|
if (CentreX < RelativeBlockX)
|
|
{
|
|
DirectionX = 0;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (CentreY < RelativeBlockY)
|
|
{
|
|
DirectionX = 180;
|
|
}
|
|
if(CentreY == RelativeBlockY)
|
|
{
|
|
DirectionX = 90;
|
|
}
|
|
if(CentreY > RelativeBlockY)
|
|
{
|
|
DirectionX = 0;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (CentreY > RelativeBlockY)
|
|
{
|
|
DirectionX = 180;
|
|
}
|
|
if (CentreY == RelativeBlockY)
|
|
{
|
|
DirectionX = 90;
|
|
}
|
|
if (CentreY < RelativeBlockY)
|
|
{
|
|
DirectionX = 0;
|
|
}
|
|
break;
|
|
}
|
|
/* if (CentreZ < RelativeBlockZ && RelativeBlockZ > RelativeBlockX)
|
|
{
|
|
for (int i = RelativeBlockZ; i < LightLevels.GetLength(2); i++)
|
|
{
|
|
LightLevels[RelativeBlockX, RelativeBlockY, i] = 0;
|
|
}
|
|
} else if (CentreZ > RelativeBlockZ && RelativeBlockZ < RelativeBlockX)
|
|
{
|
|
for (int i = RelativeBlockZ; i >= 0; i--)
|
|
{
|
|
LightLevels[RelativeBlockX, RelativeBlockY, i] = 0;
|
|
}
|
|
} else
|
|
{
|
|
if (CentreX < RelativeBlockX && RelativeBlockX > RelativeBlockZ)
|
|
{
|
|
for (int i = RelativeBlockX; i < LightLevels.GetLength(0); i++)
|
|
{
|
|
LightLevels[i, RelativeBlockY, RelativeBlockZ] = 0;
|
|
}
|
|
}
|
|
else if (CentreX > RelativeBlockX && RelativeBlockX < RelativeBlockZ)
|
|
{
|
|
for (int i = RelativeBlockZ; i >= 0; i--)
|
|
{
|
|
LightLevels[i, RelativeBlockY, RelativeBlockZ] = 0;
|
|
}
|
|
}
|
|
}*/
|
|
LightLevel = (int)(LightLevel * ((1 + Math.Cos(Math.PI * DirectionX / 180)) / 2));
|
|
// MessageBox.Show(LightLevel + "");
|
|
}
|
|
}
|
|
return LightLevel;
|
|
}
|
|
public static bool IsWithinCircle(int Radius, int CentreX, int CentreY, int posX, int PosY)
|
|
{
|
|
return LightingManager.Square(posX - CentreX) + LightingManager.Square(PosY - CentreY) < LightingManager.Square(Radius);
|
|
}
|
|
public static bool IsWithinSphere(int Radius, int CentreX, int CentreY, int CentreZ, int posX, int PosY, int PosZ)
|
|
{
|
|
return LightingManager.Square(posX - CentreX) + LightingManager.Square(PosY - CentreY) + LightingManager.Square(PosZ - CentreZ) < LightingManager.Square(Radius);
|
|
}
|
|
public LightSource(LightShape shape, int RangeX, int RangeY, int RangeZ, int XWorldPos, int YWorldPos, int ZWorldPos,int Brightness)
|
|
{
|
|
this.Shape = shape;
|
|
this.RangeX = RangeX;
|
|
this.RangeY = RangeY;
|
|
this.RangeZ = RangeZ;
|
|
this.XWorldPos = XWorldPos;
|
|
this.YWorldPos = YWorldPos;
|
|
this.ZWorldPos = ZWorldPos;
|
|
this.Brightness = Brightness;
|
|
SetUpLightLevels();
|
|
}
|
|
public byte CalculateLightLevel(int CentreX, int CentreY, int CentreZ, int PosX, int PosY, int PosZ, int RangeX, int RangeY, int RangeZ, int MaxLevel)
|
|
{
|
|
int[] Distances = new int[] { CentreX - PosX, CentreY - PosY, CentreZ - PosZ};
|
|
int[] Centres = new int[] { CentreX, CentreY, CentreZ };
|
|
float[] LightLevel = new float[] {255.0f/ RangeX * (MaxLevel / 255.0f), 255.0f/ RangeY * (MaxLevel / 255.0f), 255.0f/ RangeZ * (MaxLevel / 255.0f) };
|
|
float TotalLightLevel = 0;
|
|
int Dimensions = 0;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
Distances[i] = Distances[i] > 0 ? Distances[i] : -Distances[i];
|
|
}
|
|
LightLevel = new float[] { LightLevel[0] * (float)Distances[0], LightLevel[1] * (float)Distances[1], LightLevel[2] * (float)Distances[2] };
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (Centres[i] >= 0)
|
|
{
|
|
Dimensions++;
|
|
TotalLightLevel += LightLevel[i];
|
|
}
|
|
}
|
|
TotalLightLevel /= Dimensions;
|
|
return (byte)Math.Min(Math.Max(TotalLightLevel,0),255);
|
|
}
|
|
private void SetUpLightLevels()
|
|
{
|
|
LightLevels = new byte[RangeX*2, RangeY*2, RangeZ*2];
|
|
int CentreX = LightLevels.GetLength(0) / 2;
|
|
int CentreY = LightLevels.GetLength(1) / 2;
|
|
int CentreZ = LightLevels.GetLength(2) / 2;
|
|
for (int x = 0; x < LightLevels.GetLength(0); x++)
|
|
{
|
|
for (int y = 0; y < LightLevels.GetLength(1); y++)
|
|
{
|
|
for (int z = 0; z < LightLevels.GetLength(2); z++)
|
|
{
|
|
switch (Shape)
|
|
{
|
|
case LightShape.Sphere:
|
|
if (IsWithinSphere((RangeX + RangeY + RangeZ)/3, CentreX, CentreY, CentreZ, x, y, z)){
|
|
LightLevels[x, y, z] = CalculateLightLevel(CentreX, CentreY, CentreZ, x, y, z, RangeX, RangeY, RangeZ,Brightness);
|
|
}
|
|
break;
|
|
case LightShape.Cylinder:
|
|
if (IsWithinCircle((RangeX + RangeY) / 2, CentreX, CentreZ, x, z))
|
|
{
|
|
LightLevels[x, y, z] = CalculateLightLevel(CentreX, -1, CentreZ, x, y, z, RangeX, RangeY, RangeZ, Brightness);
|
|
}
|
|
break;
|
|
default:
|
|
LightLevels[x, y, z] = CalculateLightLevel(CentreX, CentreY, CentreZ, x, y, z, RangeX, RangeY, RangeZ, Brightness);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
public LightSource(LightShape shape, int Range, int XWorldPos, int YWorldPos, int ZWorldPos,int Brightness)
|
|
{
|
|
this.Shape = shape;
|
|
this.RangeX = Range;
|
|
this.RangeY = Range;
|
|
this.RangeZ = Range;
|
|
this.XWorldPos = XWorldPos;
|
|
this.YWorldPos = YWorldPos;
|
|
this.ZWorldPos = ZWorldPos;
|
|
this.Brightness = Brightness;
|
|
SetUpLightLevels();
|
|
}
|
|
public LightSource(LightShape shape, int Range, int XWorldPos, int YWorldPos, int ZWorldPos, float[] RGBLightLevels, int Brightness)
|
|
{
|
|
this.Shape = shape;
|
|
this.RangeX = Range;
|
|
this.RangeY = Range;
|
|
this.RangeZ = Range;
|
|
this.XWorldPos = XWorldPos;
|
|
this.YWorldPos = YWorldPos;
|
|
this.ZWorldPos = ZWorldPos;
|
|
this.LightLevelModifier = RGBLightLevels;
|
|
this.Brightness = Brightness;
|
|
SetUpLightLevels();
|
|
}
|
|
public LightSource( LightShape shape, int RangeX, int RangeY, int RangeZ, int XWorldPos, int YWorldPos, int ZWorldPos, float[] RGBLightLevels, int Brightness)
|
|
{
|
|
this.Shape = shape;
|
|
this.RangeX = RangeX;
|
|
this.RangeY = RangeY;
|
|
this.RangeZ = RangeZ;
|
|
this.XWorldPos = XWorldPos;
|
|
this.YWorldPos = YWorldPos;
|
|
this.ZWorldPos = ZWorldPos;
|
|
this.LightLevelModifier = RGBLightLevels;
|
|
this.Brightness = Brightness;
|
|
SetUpLightLevels();
|
|
}
|
|
}
|
|
public static class LightingManager
|
|
{
|
|
public static float[] AmbientColouring = new float[] { 1.0f, 1.0f, 1.0f };
|
|
public static float[] AmbientMinimums = new float[] { 0.05f, 0.05f, 0.05f, 0.05f, 0.05f, 0.05f };
|
|
public static float[] DefaultValues = new float[] { 0.6f, 0.6f, 0.6f, 0.6f, 1.0f, 0.4f };
|
|
public static float[] SkyLightModifiedValues = new float[] { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
|
public static float[] SunLightColourModifier = new float[] { 1.1f, 1.0f, 0.8f };
|
|
public static float[] MoonLightColourModifier = new float[] { 0.5f, 0.6f, 0.85f };
|
|
public static float[] sunAngles = new float[] { 135, 0 };
|
|
public static float[] SkyLightMetrics = new float[] { 0, 0, 0, 0,0,0 };
|
|
public static List<LightSource> Lights = new List<LightSource>();
|
|
public static LightDirection SunAngle = LightDirection.North;
|
|
public static float MaxBloom = 1.05f;
|
|
public static float[] GetLightsOnCube(int WorldX, int WorldY, int WorldZ, int face, bool BlocksLight)
|
|
{
|
|
float[] RGBLevels = new float[] { 0, 0, 0 };
|
|
int LightCount = 0;
|
|
Lights.ForEach(Light =>
|
|
{
|
|
int DistX = WorldX - (Light.GetPosition()[0] - Light.GetRadius()[0]);
|
|
int DistY = WorldY - (Light.GetPosition()[1] - Light.GetRadius()[1]);
|
|
int DistZ = WorldZ - (Light.GetPosition()[2] - Light.GetRadius()[2]);
|
|
if (DistX > 0 && DistY > 0 && DistZ > 0 && DistX - Light.GetRadius()[0] < 0 && DistY - Light.GetRadius()[1] < 0 && DistZ - Light.GetRadius()[2] < 0)
|
|
{
|
|
//MessageBox.Show("X: " + DistX + " Y: " + DistY + " Z: " + DistZ);
|
|
float[] LightRGB = new float[3];
|
|
LightCount++;
|
|
int LightLevel = Light.GetLightLevel(DistX, DistY, DistZ, face, BlocksLight);
|
|
LightRGB = Light.GetRGBLightLevels(LightLevel);
|
|
RGBLevels[0] += LightRGB[0];
|
|
RGBLevels[1] += LightRGB[1];
|
|
RGBLevels[2] += LightRGB[2];
|
|
|
|
}
|
|
});
|
|
//return RGBLevels;
|
|
return new float[] { RGBLevels[0] != 0 ? RGBLevels[0]/LightCount : 0, RGBLevels[1] != 0 ? RGBLevels[1]/LightCount : 0, RGBLevels[2] != 0 ? RGBLevels[2]/LightCount : 0 };
|
|
}
|
|
public static void UpdateLighting()
|
|
{
|
|
float[] AngleRanges = new float[] { 0, 45, 90, 135, 180, 225, 270, 315 };
|
|
float[] AngleOffsets = new float[] { 0, 180, 90, 270, -1, -1 };
|
|
LightDirection[] directions = new LightDirection[] { LightDirection.North, LightDirection.NorthEast, LightDirection.East, LightDirection.SouthEast, LightDirection.South, LightDirection.SouthWest, LightDirection.West, LightDirection.NorthWest };
|
|
if (sunAngles[0] > 360) sunAngles[0] -= 360;
|
|
if (sunAngles[1] > 360) sunAngles[1] -= 360;
|
|
if (sunAngles[0] <= -360) sunAngles[0] += 360;
|
|
if (sunAngles[1] <= -360) sunAngles[1] += 360;
|
|
float CurrentAngle = 0;
|
|
int AngleIndex = 0;
|
|
float MoonAngle = (float)((1 + Math.Sin(Math.PI * (sunAngles[1] - 60) / 180)) / 2.0);
|
|
float SunLightAngle = (float)((1 + Math.Cos(Math.PI * sunAngles[1] / 180)) / 1.8);
|
|
for (int i = 0; i < AngleRanges.Length; i++)
|
|
{
|
|
if (sunAngles[0] < AngleRanges[i])
|
|
{
|
|
CurrentAngle = AngleRanges[i];
|
|
AngleIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (Square(CurrentAngle - sunAngles[0]) > Square(sunAngles[0] - AngleRanges[AngleIndex - 1 >= 0 ? AngleIndex - 1 : AngleRanges.Length - 1]))
|
|
{
|
|
AngleIndex = AngleIndex - 1 >= 0 ? AngleIndex - 1 : AngleRanges.Length - 1;
|
|
}
|
|
SunAngle = directions[AngleIndex];
|
|
for (int i = 0; i < SkyLightModifiedValues.Length - 2; i++)
|
|
{
|
|
SkyLightModifiedValues[i] = (float)((1 + Math.Cos(Math.PI * (sunAngles[0] + AngleOffsets[i]) / 180) / 2.0) * (float)Math.Min(Math.Max((1 + Math.Cos(Math.PI * (sunAngles[1] + 45) / 180)) / 2.0, MoonAngle/2),0.9));
|
|
}
|
|
for (int i = SkyLightModifiedValues.Length - 2; i < SkyLightModifiedValues.Length; i++)
|
|
{
|
|
SkyLightModifiedValues[i] = (float)Math.Min(Math.Max(SunLightAngle, MoonAngle/2) + (MoonAngle/ 4),MaxBloom);
|
|
}
|
|
for (int i = 0; i < AmbientColouring.Length; i++)
|
|
{
|
|
AmbientColouring[i] = SunLightColourModifier[i] * SunLightAngle + MoonLightColourModifier[i] * MoonAngle;
|
|
SkyLightMetrics[3 + i] = AmbientColouring[i];
|
|
}
|
|
AmbientColouring[2] -= sunAngles[1] > 180 || sunAngles[1] < 90 ? Square(Square((float)(Math.Max(Math.Cos(Math.PI * (sunAngles[1] + 45) / 180), 0)))) / 2.0f : 0;//(float)(Math.Max(Math.Cos(Math.PI * (sunAngles[1] + 45) / 180),0));
|
|
AmbientColouring[1] -= sunAngles[1] > 180 || sunAngles[1] < 90 ? Square(Square((float)(Math.Max(Math.Cos(Math.PI * (sunAngles[1] + 45) / 180), 0))) / 3.0f) : 0;// (float)(Math.Max(Math.Cos(Math.PI * (sunAngles[1] + 45) / 180),0))/2.0f;
|
|
SkyLightMetrics[0] = (float)Math.Max(SunLightAngle, 0.1f) + (float)(MoonAngle / 5);
|
|
SkyLightMetrics[2] = MoonAngle;
|
|
}
|
|
public static float Square(float ValueIn)
|
|
{
|
|
return ValueIn * ValueIn;
|
|
}
|
|
}
|
|
public static class TextureManager
|
|
{
|
|
public static List<Bitmap> textures = new List<Bitmap>() {Resources._16xDefaultTile};
|
|
public static List<Bitmap> PreCompiledModels = new List<Bitmap>();
|
|
public static Bitmap[,] GeneratedFaceTextures = new Bitmap[0,0];
|
|
public static int VoxelCount = 0;
|
|
public static Bitmap GetModel(int modelNum)
|
|
{
|
|
return PreCompiledModels[modelNum];
|
|
}
|
|
public static void CreateModel(Voxel voxel)
|
|
{
|
|
if (GeneratedFaceTextures.GetLength(1) < 6) GenerateVoxelFaces();
|
|
int ImageWidth = 0;
|
|
int ImageHeight = 0;
|
|
int[] faces = voxel.getFaces();
|
|
int[] DrawOrder = voxel.GetDrawOrder();
|
|
for(int i = 0; i < faces.Length; i++)
|
|
{
|
|
if (faces[i] >= 0 && GeneratedFaceTextures[faces[i], i].Width > ImageWidth) ImageWidth = GeneratedFaceTextures[faces[i], i].Width;
|
|
if (faces[i] >= 0 && GeneratedFaceTextures[faces[i], i].Height > ImageHeight) ImageHeight = GeneratedFaceTextures[faces[i], i].Height;
|
|
}
|
|
Bitmap GeneratedModel = new Bitmap(ImageWidth, ImageHeight);
|
|
voxel.Draw(Graphics.FromImage(GeneratedModel),0,0,0,0,0,0,false);
|
|
voxel.SetPreCompiledModel(PreCompiledModels.Count);
|
|
PreCompiledModels.Add(GeneratedModel);
|
|
GeneratedModel.Save("Model" + voxel.GetModelNum() + ".png");
|
|
}
|
|
public static float GetSunlightValue(int face, int ShadowLevel)
|
|
{
|
|
return (LightingManager.SkyLightModifiedValues[face] * LightingManager.DefaultValues[face]) / (float)ShadowLevel;
|
|
}
|
|
public static float GetShadingValue(float LightValue, int RGBIndex, int FaceIndex)
|
|
{
|
|
return GetShadingValue(LightValue, RGBIndex, FaceIndex, new float[] { 0, 0, 0 });
|
|
}
|
|
public static float GetShadingValue(float LightValue, int RGBIndex, int FaceIndex, float[] Lights)
|
|
{
|
|
//if (Lights[RGBIndex] > 0) MessageBox.Show(Lights[RGBIndex] + "");
|
|
return ((float)Math.Max(LightValue * LightingManager.AmbientColouring[RGBIndex], LightingManager.AmbientMinimums[FaceIndex])) + Lights[RGBIndex] * 10;
|
|
}
|
|
public static ImageAttributes GetShadow(int face) { return GetShadow(face, 0, 0,0,0, false); }
|
|
public static ImageAttributes GetShadow(int face, int WorldX, int WorldY, int WorldZ, int ShadowLevel, bool BlocksLight)
|
|
{
|
|
ImageAttributes imageAttributes;
|
|
float[][] colorMatrixElements;
|
|
float[] Lights = LightingManager.GetLightsOnCube(WorldX, WorldY, WorldZ, face, BlocksLight);
|
|
ColorMatrix colorMatrix;
|
|
switch (face) {
|
|
case 0:
|
|
colorMatrixElements = new float[][]{
|
|
new float[] { GetShadingValue(GetSunlightValue(face,ShadowLevel), 0,face,Lights), 0, 0, 0, 0}, // red
|
|
new float[] {0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 1, face, Lights), 0, 0, 0}, // green
|
|
new float[] {0, 0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 2, face, Lights), 0, 0}, // blue
|
|
new float[] {0, 0, 0, 1, 0}, // alpha
|
|
new float[] {0, 0, 0, 0, 1}}; // three translations of 0.2
|
|
|
|
colorMatrix = new ColorMatrix(colorMatrixElements);
|
|
imageAttributes = new ImageAttributes();
|
|
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
|
return imageAttributes;
|
|
case 1:
|
|
colorMatrixElements = new float[][]{
|
|
new float[] { GetShadingValue(GetSunlightValue(face,ShadowLevel), 0,face, Lights), 0, 0, 0, 0}, // red
|
|
new float[] {0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 1, face, Lights), 0, 0, 0}, // green
|
|
new float[] {0, 0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 2, face, Lights), 0, 0}, // blue
|
|
new float[] {0, 0, 0, 1, 0}, // alpha
|
|
new float[] {0, 0, 0, 0, 1}}; // three translations of 0.2
|
|
|
|
colorMatrix = new ColorMatrix(colorMatrixElements);
|
|
imageAttributes = new ImageAttributes();
|
|
imageAttributes.SetColorMatrix( colorMatrix,ColorMatrixFlag.Default,ColorAdjustType.Bitmap);
|
|
return imageAttributes;
|
|
case 2:
|
|
colorMatrixElements = new float[][]{
|
|
new float[] { GetShadingValue(GetSunlightValue(face,ShadowLevel), 0,face, Lights), 0, 0, 0, 0}, // red
|
|
new float[] {0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 1, face, Lights), 0, 0, 0}, // green
|
|
new float[] {0, 0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 2, face, Lights), 0, 0}, // blue
|
|
new float[] {0, 0, 0, 1, 0}, // alpha
|
|
new float[] {0, 0, 0, 0, 1}}; // three translations of 0.2
|
|
|
|
colorMatrix = new ColorMatrix(colorMatrixElements);
|
|
imageAttributes = new ImageAttributes();
|
|
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
|
return imageAttributes;
|
|
case 3:
|
|
colorMatrixElements = new float[][]{
|
|
new float[] { GetShadingValue(GetSunlightValue(face,ShadowLevel), 0,face, Lights), 0, 0, 0, 0}, // red
|
|
new float[] {0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 1, face, Lights), 0, 0, 0}, // green
|
|
new float[] {0, 0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 2, face, Lights), 0, 0}, // blue
|
|
new float[] {0, 0, 0, 1, 0}, // alpha
|
|
new float[] {0, 0, 0, 0, 1}}; // three translations of 0.2
|
|
|
|
colorMatrix = new ColorMatrix(colorMatrixElements);
|
|
imageAttributes = new ImageAttributes();
|
|
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
|
return imageAttributes;
|
|
case 4:
|
|
colorMatrixElements = new float[][]{
|
|
new float[] { GetShadingValue(GetSunlightValue(face,ShadowLevel), 0,face, Lights), 0, 0, 0, 0}, // red
|
|
new float[] {0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 1, face, Lights), 0, 0, 0}, // green
|
|
new float[] {0, 0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 2, face, Lights), 0, 0}, // blue
|
|
new float[] {0, 0, 0, 1, 0}, // alpha
|
|
new float[] {0, 0, 0, 0, 1}}; // three translations of 0.2
|
|
|
|
colorMatrix = new ColorMatrix(colorMatrixElements);
|
|
imageAttributes = new ImageAttributes();
|
|
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
|
return imageAttributes;
|
|
case 5:
|
|
colorMatrixElements = new float[][]{
|
|
new float[] { GetShadingValue(GetSunlightValue(face,ShadowLevel), 0,face, Lights), 0, 0, 0, 0}, // red
|
|
new float[] {0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 1, face, Lights), 0, 0, 0}, // green
|
|
new float[] {0, 0, GetShadingValue(GetSunlightValue(face,ShadowLevel), 2, face, Lights), 0, 0}, // blue
|
|
new float[] {0, 0, 0, 1, 0}, // alpha
|
|
new float[] {0, 0, -0, 0, 1}}; // three translations of 0.2
|
|
|
|
colorMatrix = new ColorMatrix(colorMatrixElements);
|
|
imageAttributes = new ImageAttributes();
|
|
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
|
|
return imageAttributes;
|
|
default:
|
|
imageAttributes = new ImageAttributes();
|
|
return imageAttributes;
|
|
|
|
}
|
|
}
|
|
public static Point IntegerCalculateIsometricProjection(int width, int height, int X, int Y, int Z, int Corner)
|
|
{
|
|
switch (Corner)
|
|
{
|
|
case 0:
|
|
return new Point(width / 2 + (int)((X * 1) + (Z * -1)),
|
|
height / 2 + (int)Math.Ceiling((X * 0.5f) + (Z * 0.5f) - (Y / 3) * 2));
|
|
case 1:
|
|
return new Point(width / 2 + (int)((X * 1) + (Z * -1)),
|
|
height / 2 + (int)Math.Floor((X * 0.5f) + (Z * 0.5f) - (Y / 3) * 2));
|
|
case 2:
|
|
return new Point(-1 + width / 2 + (int)((X * 1) + (Z * -1)),
|
|
height / 2 + (int)Math.Floor((X * 0.5f) + (Z * 0.5f) - (Y / 3) * 2));
|
|
default:
|
|
return new Point(-1 + width / 2 + (int)((X * 1) + (Z * -1)),
|
|
height / 2 + (int)Math.Ceiling((X * 0.5f) + (Z * 0.5f) - (Y / 3) * 2));
|
|
}
|
|
}
|
|
public static Point IntegerCalculateIsometricProjection(int width, int height, int X, int Y, int Z)
|
|
{
|
|
return new Point(width / 2 + (int)((X * 1) + (Z * -1)),
|
|
height / 2 + (int)((X * 0.5f) + (Z * 0.5f) - (Y / 3) * 2));
|
|
}
|
|
public static PointF CalculateIsometricProjection(double[] Position, int width, int height, int X, int Y, int Z)
|
|
{
|
|
return new PointF(width / 2 + (float)(((/*Globals.CameraX*/ +X + Position[0]) * 0.5) + ((/*Globals.CameraZ +*/ Z + Position[1]) * -0.5)),
|
|
height / 2 + (float)(((/*Globals.CameraX*/ +X + Position[0]) * 0.25f) + ((/*Globals.CameraZ*/ +Z + Position[1]) * 0.25f) - (((/*Globals.CameraY*/ +Position[2]) + (Y / 3) * 2))));
|
|
}
|
|
public static Bitmap GetVoxelFaceBitmap(int index, int face)
|
|
{
|
|
if (GeneratedFaceTextures.GetLength(1) < 6) GenerateVoxelFaces();
|
|
return GeneratedFaceTextures[index,face];
|
|
}
|
|
public static Bitmap GetBitmap(int index)
|
|
{
|
|
return textures[index];
|
|
}
|
|
public static void AddBitmap(Bitmap texture)
|
|
{
|
|
textures.Add(texture);
|
|
}
|
|
public static void GenerateVoxelFaces()
|
|
{
|
|
GeneratedFaceTextures = new Bitmap[textures.Count, 6];
|
|
for (int i = 0; i < textures.Count; i++)
|
|
{
|
|
for (int face = 0; face < 6; face++)
|
|
{
|
|
Bitmap SkewedTexture = new Bitmap(textures[i].Width * 2, textures[i].Height * 2);
|
|
int y = 0;// textures[i].Height;
|
|
switch (face)
|
|
{
|
|
case 0:
|
|
y = 1;
|
|
for(int x = 0; x < textures[i].Width; x++)
|
|
{
|
|
for(int ypx = 0; ypx < textures[i].Height; ypx++)
|
|
{
|
|
SkewedTexture.SetPixel(textures[i].Width+ x, y + ypx, textures[i].GetPixel(x, ypx));
|
|
}
|
|
if (x % 2 != 0) y++;
|
|
}
|
|
y = 0;
|
|
break;
|
|
case 1:
|
|
for (int x = textures[i].Width - 1; x >= 0 ; x--)
|
|
{
|
|
for (int ypx = 0; ypx < textures[i].Height; ypx++)
|
|
{
|
|
SkewedTexture.SetPixel(x, SkewedTexture.Height - (y + ypx + 1), textures[i].GetPixel(x, textures[i].Height - 1 - ypx));
|
|
}
|
|
if (x % 2 == 0) y++;
|
|
}
|
|
y = 0;
|
|
break;
|
|
case 2:
|
|
for (int x = 0; x < textures[i].Width; x++)
|
|
{
|
|
for (int ypx = 0; ypx < textures[i].Height; ypx++)
|
|
{
|
|
SkewedTexture.SetPixel(textures[i].Width + x, SkewedTexture.Height - (y + ypx + 1), textures[i].GetPixel(x, textures[i].Height - 1 - ypx));
|
|
}
|
|
if (x % 2 != 0) y++;
|
|
}
|
|
y = 0;
|
|
break;
|
|
case 3:
|
|
y = 1;
|
|
for (int x = textures[i].Width - 1; x >= 0; x--)
|
|
{
|
|
for (int ypx = 0; ypx < textures[i].Height; ypx++)
|
|
{
|
|
SkewedTexture.SetPixel(x, y + ypx, textures[i].GetPixel(x, ypx));
|
|
}
|
|
if (x % 2 == 0) y++;
|
|
}
|
|
y = 0;
|
|
break;
|
|
case 4:
|
|
Bitmap[] Textures = new Bitmap[4];
|
|
Bitmap MergedTextures = new Bitmap(SkewedTexture.Width, SkewedTexture.Height);
|
|
for (int l = 0; l < 4; l++)
|
|
{
|
|
Textures[l] = new Bitmap(SkewedTexture.Width, SkewedTexture.Height);
|
|
}
|
|
for(int l = 0; l < 4; l++)
|
|
{
|
|
for (int x = 0; x < textures[i].Width; x++)
|
|
{
|
|
for (int ypx = 0; ypx < textures[i].Height; ypx++)
|
|
{
|
|
Point PixelLocation = IntegerCalculateIsometricProjection(textures[i].Width * 2, 0, x, 0, ypx,l);
|
|
PixelLocation.X = Math.Max(Math.Min(PixelLocation.X, SkewedTexture.Width - 1), 0);
|
|
PixelLocation.Y = Math.Max(Math.Min(PixelLocation.Y, SkewedTexture.Height - 1), 0);
|
|
Textures[l].SetPixel(PixelLocation.X, PixelLocation.Y, textures[i].GetPixel(x, ypx));
|
|
}
|
|
}
|
|
}
|
|
for (int l = 0; l < 4; l++)
|
|
{
|
|
int Startx = 0;
|
|
int Starty = 0;
|
|
int endX = Textures[l].Width;
|
|
int endY = Textures[l].Height;
|
|
switch (l)
|
|
{
|
|
case 1:
|
|
Startx = Textures[l].Width / 2;
|
|
Starty = 0;
|
|
endX = Textures[l].Width;
|
|
endY = Textures[l].Height/4;
|
|
break;
|
|
case 0:
|
|
Startx = Textures[l].Width / 2;
|
|
Starty = Textures[l].Height / 4;
|
|
endX = Textures[l].Width;
|
|
endY = Textures[l].Height/2;
|
|
break;
|
|
case 2:
|
|
Startx = 0;
|
|
Starty = 0;
|
|
endX = Textures[l].Width/2;
|
|
endY = Textures[l].Height / 4 ;
|
|
break;
|
|
case 3:
|
|
Startx = 0;
|
|
Starty = Textures[l].Height / 4;
|
|
endX = Textures[l].Width/2;
|
|
endY = Textures[l].Height/2;
|
|
break;
|
|
}
|
|
for(int x = Startx; x < endX; x++)
|
|
{
|
|
for (int ypx = Starty; ypx < endY;ypx++)
|
|
{
|
|
MergedTextures.SetPixel(x, ypx, Textures[l].GetPixel(x, ypx));
|
|
}
|
|
}
|
|
}
|
|
SkewedTexture = MergedTextures;
|
|
y = 0;
|
|
break;
|
|
case 5:
|
|
Textures = new Bitmap[4];
|
|
MergedTextures = new Bitmap(SkewedTexture.Width, SkewedTexture.Height);
|
|
for (int l = 0; l < 4; l++)
|
|
{
|
|
Textures[l] = new Bitmap(SkewedTexture.Width, SkewedTexture.Height);
|
|
}
|
|
for (int l = 0; l < 4; l++)
|
|
{
|
|
for (int x = 0; x < textures[i].Width; x++)
|
|
{
|
|
for (int ypx = 0; ypx < textures[i].Height; ypx++)
|
|
{
|
|
Point PixelLocation = IntegerCalculateIsometricProjection(textures[i].Width * 2, 0, x, 0, ypx, l);
|
|
PixelLocation.X = Math.Max(Math.Min(PixelLocation.X, SkewedTexture.Width - 1), 0);
|
|
PixelLocation.Y = Math.Max(Math.Min(textures[i].Height + PixelLocation.Y, SkewedTexture.Height - 1), 0);
|
|
Textures[l].SetPixel(PixelLocation.X, PixelLocation.Y, textures[i].GetPixel(x, ypx));
|
|
}
|
|
}
|
|
}
|
|
for (int l = 0; l < 4; l++)
|
|
{
|
|
int Startx = 0;
|
|
int Starty = 0;
|
|
int endX = Textures[l].Width;
|
|
int endY = Textures[l].Height;
|
|
switch (l)
|
|
{
|
|
case 1:
|
|
Startx = Textures[l].Width / 2;
|
|
Starty = Textures[l].Height / 2;
|
|
endX = Textures[l].Width;
|
|
endY = (Textures[l].Height / 4) * 3;
|
|
break;
|
|
case 0:
|
|
Startx = Textures[l].Width / 2;
|
|
Starty = (Textures[l].Height / 4) * 3;
|
|
endX = Textures[l].Width;
|
|
endY = Textures[l].Height;
|
|
break;
|
|
case 2:
|
|
Startx = 0;
|
|
Starty = Textures[l].Height / 2;
|
|
endX = Textures[l].Width / 2;
|
|
endY = (Textures[l].Height / 4) * 3;
|
|
break;
|
|
case 3:
|
|
Startx = 0;
|
|
Starty = (Textures[l].Height / 4)*3;
|
|
endX = Textures[l].Width / 2;
|
|
endY = Textures[l].Height;
|
|
break;
|
|
}
|
|
for (int x = Startx; x < endX; x++)
|
|
{
|
|
for (int ypx = Starty; ypx < endY; ypx++)
|
|
{
|
|
MergedTextures.SetPixel(x, ypx, Textures[l].GetPixel(x, ypx));
|
|
}
|
|
}
|
|
}
|
|
SkewedTexture = MergedTextures;
|
|
y = 0;
|
|
break;
|
|
|
|
}
|
|
GeneratedFaceTextures[i, face] = SkewedTexture;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public class Voxel
|
|
{
|
|
int VoxelNum;
|
|
int[] faces = new int[6];
|
|
int[] DrawOrder = new int[] { 5, 0, 3, 1, 2, 4 };
|
|
int ModelType = 0;
|
|
int ModelNum = -1;
|
|
bool Cull = false;
|
|
public int[] getFaces()
|
|
{
|
|
return faces;
|
|
}
|
|
public int[] GetDrawOrder()
|
|
{
|
|
return DrawOrder;
|
|
}
|
|
public int GetModelNum()
|
|
{
|
|
return ModelNum;
|
|
}
|
|
public int GetModelType()
|
|
{
|
|
return ModelType;
|
|
}
|
|
public int GetVoxelNum()
|
|
{
|
|
return VoxelNum;
|
|
}
|
|
public Voxel(int ModelType,int NorthFace, int SouthFace, int EastFace, int WestFace, int UpFace, int DownFace, bool cull)
|
|
{
|
|
this.ModelType = ModelType;
|
|
faces = new int[] { NorthFace, SouthFace, EastFace, WestFace, UpFace, DownFace };
|
|
VoxelNum = TextureManager.VoxelCount;
|
|
TextureManager.VoxelCount++;
|
|
if (cull) SetCullFaces(false,true,false,false, false, false);
|
|
Cull = cull;
|
|
}
|
|
public void SetCullFaces(bool up, bool down, bool West, bool East,bool north, bool south)
|
|
{
|
|
DrawOrder = new int[] { down?-1:5, north?-1:0, West?-1:3, south?-1:1, East?-1:2, up?-1:4 };
|
|
}
|
|
public void SetPreCompiledModel(int ModelNum)
|
|
{
|
|
this.ModelNum = ModelNum;
|
|
}
|
|
public Voxel(int NorthFace, int SouthFace, int EastFace, int WestFace, int UpFace, int DownFace)
|
|
{
|
|
faces = new int[] {NorthFace, SouthFace, EastFace, WestFace, UpFace, DownFace};
|
|
VoxelNum = TextureManager.VoxelCount;
|
|
TextureManager.VoxelCount++;
|
|
}
|
|
virtual public void Draw(Graphics g, int x, int y, int WorldX, int WorldY, int WorldZ, int ShadowLevel, bool BlocksLight)
|
|
{
|
|
for (int i = 0; i < DrawOrder.Length; i++) {
|
|
if (DrawOrder[i] > 0 && DrawOrder[i] < 6 && faces[DrawOrder[i]] >= 0)
|
|
{
|
|
if (ModelNum == -1)
|
|
{
|
|
Bitmap Side;
|
|
switch (ModelType)
|
|
{
|
|
case 0:
|
|
Side = GetRenderedSide(DrawOrder[i]);
|
|
g.DrawImage(Side, new Rectangle(x, y, Side.Width, Side.Height), 0, 0, Side.Width, Side.Height, GraphicsUnit.Pixel, TextureManager.GetShadow(DrawOrder[i], WorldX, WorldY,WorldZ, ShadowLevel, BlocksLight));
|
|
break;
|
|
default:
|
|
|
|
switch (DrawOrder[i])
|
|
{
|
|
case 0:
|
|
Side = GetRenderedSide(0);
|
|
g.DrawImage(Side, new Rectangle(x - (Side.Width / 4), y, Side.Width, Side.Height),0,0,Side.Width,Side.Height, GraphicsUnit.Pixel, TextureManager.GetShadow(0, WorldX, WorldY, WorldZ, ShadowLevel, BlocksLight));
|
|
break;
|
|
case 1:
|
|
Side = GetRenderedSide(1);
|
|
g.DrawImage(Side, new Rectangle(x + (Side.Width / 4), y - (Side.Height / 4), Side.Width, Side.Height),0,0,Side.Width,Side.Height, GraphicsUnit.Pixel, TextureManager.GetShadow(1, WorldX, WorldY, WorldZ, ShadowLevel, BlocksLight));
|
|
break;
|
|
case 2:
|
|
Side = GetRenderedSide(2);
|
|
g.DrawImage(Side, new Rectangle(x - (Side.Width / 4), y - (Side.Height / 4), Side.Width, Side.Height),0,0,Side.Width,Side.Height, GraphicsUnit.Pixel, TextureManager.GetShadow(2, WorldX, WorldY, WorldZ, ShadowLevel, BlocksLight));
|
|
break;
|
|
case 3:
|
|
Side = GetRenderedSide(3);
|
|
g.DrawImage(Side, new Rectangle( x + (Side.Width / 4),y,Side.Width,Side.Height),0,0,Side.Width,Side.Height, GraphicsUnit.Pixel, TextureManager.GetShadow(3, WorldX, WorldY, WorldZ, ShadowLevel, BlocksLight));
|
|
break;
|
|
default:
|
|
Side = GetRenderedSide(DrawOrder[i]);
|
|
g.DrawImage(Side, new Rectangle(x, y, Side.Width, Side.Height), 0, 0, Side.Width, Side.Height, GraphicsUnit.Pixel, TextureManager.GetShadow(DrawOrder[i], WorldX, WorldY, WorldZ, ShadowLevel, BlocksLight));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g.DrawImage(TextureManager.GetModel(ModelNum), x, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public Bitmap GetRenderedSide(int FaceIndex)
|
|
{
|
|
return TextureManager.GetVoxelFaceBitmap(faces[FaceIndex], FaceIndex);
|
|
}
|
|
public int GetFace(int index)
|
|
{
|
|
return faces[index];
|
|
}
|
|
public int GetNorthFace()
|
|
{
|
|
return faces[0];
|
|
}
|
|
public int GetSouthFace()
|
|
{
|
|
return faces[1];
|
|
}
|
|
public int GetEastFace()
|
|
{
|
|
return faces[2];
|
|
}
|
|
public int GetWestFace()
|
|
{
|
|
return faces[3];
|
|
}
|
|
public int GetUpFace()
|
|
{
|
|
return faces[4];
|
|
}
|
|
public int GetDownFace()
|
|
{
|
|
return faces[5];
|
|
}
|
|
public void SetFace(int face, int Texture)
|
|
{
|
|
faces[face] = Texture;
|
|
}
|
|
public void SetNorthFace(int Texture)
|
|
{
|
|
faces[0] = Texture;
|
|
}
|
|
public void SetSouthFace(int Texture)
|
|
{
|
|
faces[1] = Texture;
|
|
}
|
|
public void SetEastFace(int Texture)
|
|
{
|
|
faces[2] = Texture;
|
|
}
|
|
public void SetWestFace(int Texture)
|
|
{
|
|
faces[3] = Texture;
|
|
}
|
|
public void SetUpFace(int Texture)
|
|
{
|
|
faces[4] = Texture;
|
|
}
|
|
public void SetDownFace(int Texture)
|
|
{
|
|
faces[5] = Texture;
|
|
}
|
|
}
|
|
public static class VoxelRegistry
|
|
{
|
|
public static List<Voxel> Voxels = new List<Voxel>();
|
|
public static int IndexVoxel(Voxel voxel)
|
|
{
|
|
if(Voxels.Contains(voxel)) return Voxels.IndexOf(voxel);
|
|
Voxels.Add(voxel);
|
|
return Voxels.IndexOf(Voxels.Last());
|
|
}
|
|
public static int VoxelExists(Voxel voxel)
|
|
{
|
|
return Voxels.Contains(voxel) ? Voxels.IndexOf(voxel) : -1;
|
|
}
|
|
public static Voxel FetchVoxel(int VoxelIndex)
|
|
{
|
|
return Voxels[VoxelIndex];
|
|
}
|
|
}
|
|
public enum BlockType
|
|
{
|
|
Plant,
|
|
Ground,
|
|
Wood,
|
|
Metal,
|
|
BuildMaterial,
|
|
Gas,
|
|
Fluid
|
|
}
|
|
public class BlockState
|
|
{
|
|
bool TickUpdate = false;
|
|
BlockType BlockType;
|
|
bool BlocksLight = false;
|
|
|
|
public BlockState(bool TickUpdate, BlockType blocktype, bool blocksLight)
|
|
{
|
|
this.TickUpdate = TickUpdate;
|
|
this.BlockType = blocktype;
|
|
BlocksLight = blocksLight;
|
|
}
|
|
public bool hasBlocksLight() { return BlocksLight; }
|
|
public BlockType GetBlockType() { return BlockType; }
|
|
public bool Ticks() { return TickUpdate; }
|
|
}
|
|
public static class BlockstateRegistry
|
|
{
|
|
public static List<BlockState> Blockstates = new List<BlockState>();
|
|
public static int GetBlockstateIndex(BlockState blockstate)
|
|
{
|
|
if (!Blockstates.Contains(blockstate)) Blockstates.Add(blockstate);
|
|
return Blockstates.IndexOf(blockstate);
|
|
}
|
|
public static BlockState GetBlockstate(int index)
|
|
{
|
|
return Blockstates[index];
|
|
}
|
|
public static void SetBlockstate(int index, BlockState blockstate)
|
|
{
|
|
Blockstates[index] = blockstate;
|
|
}
|
|
}
|
|
public class Chunk
|
|
{
|
|
public List<int>DrawList = new List<int>();
|
|
public List<int[]>DrawPositions = new List<int[]>();
|
|
public int[,,] BlockReg;
|
|
public bool[,,] Culled;
|
|
public int[] ChunkPos;
|
|
public int ChunkID;
|
|
public int[,,] SkyLightHeightMap;
|
|
public Chunk(int X, int Y, int Z, int Width, int Height, int Length, int ChunkID)
|
|
{
|
|
this.ChunkID = ChunkID;
|
|
BlockReg = new int[Width,Height,Length];
|
|
Culled = new bool[Width,Height,Length];
|
|
SkyLightHeightMap = new int[Width,Height,Length];
|
|
ChunkPos = new int[] { X, Y, Z };
|
|
}
|
|
public void CalculateCull()
|
|
{
|
|
DrawList = new List<int>();
|
|
int CulledCount = 0;
|
|
for (int x = 0; x < Culled.GetLength(0); x++)
|
|
{
|
|
for (int y = 0; y < Culled.GetLength(1); y++)
|
|
{
|
|
for (int z = 0; z < Culled.GetLength(2); z++)
|
|
{
|
|
if (!(x == Culled.GetLength(0) - 1 || x < Culled.GetLength(0) - 1 && (BlockReg[x + 1, y, z] != -1 && !BlockRegistry.FetchBlockState(BlockReg[x + 1, y, z]).hasBlocksLight() || BlockReg[x + 1, y, z] == -1))
|
|
&& !(x > 0 && (BlockReg[x - 1, y, z] != -1 && !BlockRegistry.FetchBlockState(BlockReg[x - 1, y, z]).hasBlocksLight() || BlockReg[x - 1, y, z] == -1))
|
|
&& !(y == Culled.GetLength(1) - 1 || y < Culled.GetLength(1) - 1 && (BlockReg[x, y + 1, z] != -1 && !BlockRegistry.FetchBlockState(BlockReg[x, y + 1, z]).hasBlocksLight() || BlockReg[x, y + 1, z] == -1))
|
|
&& !(y > 0 && (BlockReg[x, y - 1, z] != -1 && !BlockRegistry.FetchBlockState(BlockReg[x, y - 1, z]).hasBlocksLight() || BlockReg[x, y - 1, z] == -1))
|
|
&& !(z == Culled.GetLength(2) - 1 || z < Culled.GetLength(2) - 1 && (BlockReg[x, y, z + 1] != -1 && !BlockRegistry.FetchBlockState(BlockReg[x, y, z + 1]).hasBlocksLight() || BlockReg[x, y, z + 1] == -1))
|
|
&& !(z > 0 && (BlockReg[x, y, z - 1] != -1 && !BlockRegistry.FetchBlockState(BlockReg[x, y, z - 1]).hasBlocksLight() || BlockReg[x, y, z - 1] == -1)))
|
|
{
|
|
Culled[x, y, z] = true;
|
|
CulledCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int x = 0; x < BlockReg.GetLength(0); x++)
|
|
{
|
|
for (int y = 0; y < BlockReg.GetLength(1); y++)
|
|
{
|
|
for (int z = 0; z < BlockReg.GetLength(1); z++)
|
|
{
|
|
if (Culled[x,y,z] == false && BlockReg[x, y, z] != -1)
|
|
{
|
|
DrawList.Add(BlockReg[x,y,z]);
|
|
DrawPositions.Add(new int[] { x, y, z });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
public void GenerateLightMap()
|
|
{
|
|
for (int x = 0;x < SkyLightHeightMap.GetLength(0); x++)
|
|
{
|
|
for(int z = 0; z < SkyLightHeightMap.GetLength(1); z++)
|
|
{
|
|
int Y = 1;
|
|
for (int y = SkyLightHeightMap.GetLength(1) - 1; y > 0; y--)
|
|
{
|
|
SkyLightHeightMap[x, y, z] = Y;
|
|
if (BlockReg[x,y,z] != -1 && BlockRegistry.FetchBlockState(BlockReg[x, y, z]).hasBlocksLight())
|
|
{
|
|
Y++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public void RenderBlocks(Graphics g)
|
|
{
|
|
if (DrawList.Count == 0)
|
|
{
|
|
for (int x = 0; x < BlockReg.GetLength(0); x++)
|
|
{
|
|
for (int y = 0; y < BlockReg.GetLength(1); y++)
|
|
{
|
|
for (int z = 0; z < BlockReg.GetLength(1); z++)
|
|
{
|
|
if (BlockReg[x, y, z] != -1 && Culled[x, y, z] == false)
|
|
{
|
|
BlockRegistry.RenderBlock(g, BlockReg[x, y, z], x + ChunkPos[0] * ChunkRegistry.FetchDimensions()[0], y + ChunkPos[1] * ChunkRegistry.FetchDimensions()[1], z + ChunkPos[1] * ChunkRegistry.FetchDimensions()[1], SkyLightHeightMap[x, y, z]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < DrawList.Count; i++)
|
|
{
|
|
BlockRegistry.RenderBlock(g, DrawList[i], DrawPositions[i][0] + ChunkPos[0] * ChunkRegistry.FetchDimensions()[0], DrawPositions[i][1] + ChunkPos[1] * ChunkRegistry.FetchDimensions()[1], DrawPositions[i][2] + ChunkPos[1] * ChunkRegistry.FetchDimensions()[1], SkyLightHeightMap[DrawPositions[i][0], DrawPositions[i][1], DrawPositions[i][2]]);
|
|
}
|
|
}
|
|
}
|
|
public void CreateAir(int X, int Y, int Z)
|
|
{
|
|
BlockReg[X, Y, Z] = -1;
|
|
}
|
|
public void CreateBlock(int[] Faces, int RenderType, BlockState blockState, int X, int Y, int Z)
|
|
{
|
|
Voxel voxel = new Voxel(RenderType, Faces[0], Faces[1], Faces[2], Faces[3], Faces[4], Faces[5],blockState.hasBlocksLight());
|
|
int index = VoxelRegistry.VoxelExists(voxel);
|
|
if (index == -1)
|
|
{
|
|
index = VoxelRegistry.IndexVoxel(voxel);
|
|
}
|
|
Block newBlock = new Block(index, BlockstateRegistry.GetBlockstateIndex(blockState), ChunkID);
|
|
int x = X + ChunkPos[0] * ChunkRegistry.FetchDimensions()[0];
|
|
int y = Y + ChunkPos[1] * ChunkRegistry.FetchDimensions()[1];
|
|
int z = Z + ChunkPos[2] * ChunkRegistry.FetchDimensions()[2];
|
|
int BlockID = BlockRegistry.CheckInBlock(newBlock, x, y, z);
|
|
BlockReg[X, Y, Z] = BlockID;
|
|
}
|
|
public Block FetchBlock(int x, int y, int z)
|
|
{
|
|
return BlockRegistry.FetchBlock(BlockReg[x,y,z]);
|
|
}
|
|
public void IndexBlock(int BlockIndex, int x, int y, int z)
|
|
{
|
|
BlockReg[x,y,z] = BlockIndex;
|
|
}
|
|
public string FetchPosString()
|
|
{
|
|
return String.Format("x={0};y={1};z={2}", ChunkPos[0], ChunkPos[1], ChunkPos[2]);
|
|
}
|
|
public int[] FetchPos()
|
|
{
|
|
return ChunkPos;
|
|
}
|
|
public int[,,] FetchAllBlocks()
|
|
{
|
|
return BlockReg;
|
|
}
|
|
public int FetchBlockReg(int x, int y, int z)
|
|
{
|
|
return BlockReg[x, y, z];
|
|
}
|
|
}
|
|
|
|
public static class ChunkRegistry
|
|
{
|
|
static int ChunkWidth = 16;
|
|
static int ChunkHeight = 16;
|
|
static int ChunkLength = 16;
|
|
static List<Chunk> Chunks = new List<Chunk>();
|
|
static List<string> Chunk_Pos_Lookup = new List<string>();
|
|
public static Chunk IndexChunk(int x, int y, int z)
|
|
{
|
|
Chunk newChunk = new Chunk(x, y, z, ChunkWidth, ChunkHeight, ChunkLength, Chunks.Count);
|
|
Chunks.Add(newChunk);
|
|
Chunk_Pos_Lookup.Add(String.Format("x={0};y={1};z={2}", x, y, z));
|
|
return newChunk;
|
|
}
|
|
public static Chunk FetchChunk(string pos_lookup)
|
|
{
|
|
if (!Chunk_Pos_Lookup.Contains(pos_lookup)) return null;
|
|
return Chunks[Chunk_Pos_Lookup.IndexOf(pos_lookup)];
|
|
}
|
|
public static Chunk FetchChunk(int index)
|
|
{
|
|
return Chunks[index];
|
|
}
|
|
public static void RenderChunk(Graphics g,int chunkIndex)
|
|
{
|
|
Chunks[chunkIndex].RenderBlocks(g);
|
|
}
|
|
public static int FetchChunkID(string pos_lookup)
|
|
{
|
|
if (!Chunk_Pos_Lookup.Contains(pos_lookup)) return -1;
|
|
return Chunk_Pos_Lookup.IndexOf(pos_lookup);
|
|
}
|
|
public static int[] FetchDimensions()
|
|
{
|
|
return new int[] {ChunkWidth, ChunkHeight, ChunkLength};
|
|
}
|
|
}
|
|
public static class BlockRegistry
|
|
{
|
|
static List<Block> blocks = new List<Block>();
|
|
static List<string> block_pos_lookup = new List<string>();
|
|
static int BlockSize = 32;
|
|
public static BlockState FetchBlockState(int BlockID)
|
|
{
|
|
return BlockstateRegistry.GetBlockstate(blocks[BlockID].FetchBlockState());
|
|
}
|
|
public static Block FetchBlock(int BlockID)
|
|
{
|
|
return blocks[BlockID];
|
|
}
|
|
public static int FetchBlockIDFromPos(string pos_lookup)
|
|
{
|
|
if (!block_pos_lookup.Contains(pos_lookup)) return -1;
|
|
return block_pos_lookup.IndexOf(pos_lookup);
|
|
}
|
|
public static int[] GetDrawLocation(int x, int y, int z, int offsetX, int offsetY, int offsetZ)
|
|
{
|
|
return new int[]{(int)((((double)(x + offsetX) * 0.5) + ((double)(z + offsetZ) * -0.5))*(double)BlockSize),
|
|
(int)((((double)(x + offsetX) * 0.5) + ((double)(z + offsetZ) * 0.5) - (-offsetY + (y)))*((double)BlockSize/2.0)) };
|
|
}
|
|
public static void RenderBlock(Graphics g, int BlockID,int WorldX, int WorldY, int WorldZ, int ShadowLevel)
|
|
{
|
|
int[] location = GetDrawLocation(WorldX, WorldY, WorldZ, PlayerObject.GetPos()[0], PlayerObject.GetPos()[1], PlayerObject.GetPos()[2]);
|
|
VoxelRegistry.FetchVoxel(blocks[BlockID].FetchVoxelID()).Draw(g, location[0] + (Terrain4.width/4) , location[1] + (Terrain4.height/2), WorldX, WorldY, WorldZ, ShadowLevel, FetchBlockState(BlockID).hasBlocksLight());
|
|
}
|
|
public static int CheckInBlock(Block block,int x, int y, int z)
|
|
{
|
|
blocks.Add(block);
|
|
block_pos_lookup.Add(String.Format("x={0};y={1};z={2}",x,y,z));
|
|
return blocks.IndexOf(blocks.Last());
|
|
}
|
|
public static string FetchBlockString(int x, int y, int z)
|
|
{
|
|
return String.Format("x={0};y={1};z={2}", x, y, z);
|
|
}
|
|
}
|
|
public class Block
|
|
{
|
|
int VoxelID;
|
|
int BlockstateID;
|
|
int ChunkID;
|
|
bool render;
|
|
public Block(int voxelID, int blockstateID, int chunkID)
|
|
{
|
|
VoxelID = voxelID;
|
|
BlockstateID = blockstateID;
|
|
ChunkID = chunkID;
|
|
}
|
|
public int FetchVoxelID()
|
|
{
|
|
return VoxelID;
|
|
}
|
|
public int FetchChunkID()
|
|
{
|
|
return ChunkID;
|
|
}
|
|
public int FetchBlockState()
|
|
{
|
|
return BlockstateID;
|
|
}
|
|
public void SetRender(bool render)
|
|
{
|
|
this.render = render;
|
|
}
|
|
public bool Renders()
|
|
{
|
|
return render;
|
|
}
|
|
}
|
|
}
|