using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Security.AccessControl; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using VoxelIsometricRenderer.Properties; namespace VoxelIsometricRenderer { public enum LightDirection { North, NorthEast, NorthWest, East, West, SouthEast, SouthWest, South } public static class LightingManager { public static float[] AmbientColouring = new float[] { 1.0f, 1.0f, 1.0f }; public static float[] AmbientMinimums = new float[] { 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f }; public static float[] DefaultValues = new float[] { 0.6f, 0.6f, 0.6f, 0.6f, 1.0f, 0.4f }; public static float[] SunModifiedValues = new float[] { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; public static float[] sunAngles = new float[] { 180, 0 }; public static LightDirection SunAngle = LightDirection.North; 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; 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 < SunModifiedValues.Length - 2; i++) { SunModifiedValues[i] = (float)((1 + Math.Cos(Math.PI * (sunAngles[0] + AngleOffsets[i]) / 180)/ 2.0) * (float)( 1 + Math.Sin(Math.PI * (sunAngles[1] + 45) / 180))/ 2.0); } for (int i = SunModifiedValues.Length - 2; i < SunModifiedValues.Length; i++) { SunModifiedValues[i] = (float)Math.Max((1 + Math.Cos(Math.PI * (sunAngles[1]) / 180)) / 2.0, 0.3f); } } private static float Square(float ValueIn) { return ValueIn * ValueIn; } } public static class TextureManager { public static List textures = new List() {Resources._16xDefaultTile}; public static List PreCompiledModels = new List(); 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); voxel.SetPreCompiledModel(PreCompiledModels.Count); PreCompiledModels.Add(GeneratedModel); GeneratedModel.Save("Model" + voxel.GetModelNum() + ".png"); } public static float GetSunlightValue(int face) { return LightingManager.SunModifiedValues[face] * LightingManager.DefaultValues[face]; } public static float GetShadingValue(float LightValue, int RGBIndex, int FaceIndex) { return (float)Math.Max(LightValue * LightingManager.AmbientColouring[RGBIndex], LightingManager.AmbientMinimums[FaceIndex]); } public static ImageAttributes GetShadow(int face) { ImageAttributes imageAttributes; float[][] colorMatrixElements; ColorMatrix colorMatrix; switch (face) { case 0: colorMatrixElements = new float[][]{ new float[] { GetShadingValue(GetSunlightValue(face), 0,face), 0, 0, 0, 0}, // red new float[] {0, GetShadingValue(GetSunlightValue(face), 1, face), 0, 0, 0}, // green new float[] {0, 0, GetShadingValue(GetSunlightValue(face), 2, face), 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), 0,face), 0, 0, 0, 0}, // red new float[] {0, GetShadingValue(GetSunlightValue(face), 1, face), 0, 0, 0}, // green new float[] {0, 0, GetShadingValue(GetSunlightValue(face), 2, face), 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), 0,face), 0, 0, 0, 0}, // red new float[] {0, GetShadingValue(GetSunlightValue(face), 1, face), 0, 0, 0}, // green new float[] {0, 0, GetShadingValue(GetSunlightValue(face), 2, face), 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), 0,face), 0, 0, 0, 0}, // red new float[] {0, GetShadingValue(GetSunlightValue(face), 1, face), 0, 0, 0}, // green new float[] {0, 0, GetShadingValue(GetSunlightValue(face), 2, face), 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), 0,face), 0, 0, 0, 0}, // red new float[] {0, GetShadingValue(GetSunlightValue(face), 1, face), 0, 0, 0}, // green new float[] {0, 0, GetShadingValue(GetSunlightValue(face), 2, face), 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), 0,face), 0, 0, 0, 0}, // red new float[] {0, GetShadingValue(GetSunlightValue(face), 1, face), 0, 0, 0}, // green new float[] {0, 0, GetShadingValue(GetSunlightValue(face), 2, face), 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; 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) { this.ModelType = ModelType; faces = new int[] { NorthFace, SouthFace, EastFace, WestFace, UpFace, DownFace }; VoxelNum = TextureManager.VoxelCount; TextureManager.VoxelCount++; } 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) { for (int i = 0; i < DrawOrder.Length; i++) { if (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])); 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)); 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)); 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)); 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)); 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])); 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; } } }