Culling, rendering improvements and optimizations, block removing test.
This commit is contained in:
61
Blocks.cs
61
Blocks.cs
@@ -2,8 +2,11 @@
|
||||
{
|
||||
public enum Blocks : byte
|
||||
{
|
||||
Air = 0,
|
||||
Stone = 1,
|
||||
Air,
|
||||
Stone,
|
||||
Dirt,
|
||||
OakPlanks,
|
||||
Grass
|
||||
}
|
||||
|
||||
public enum Orientation : uint
|
||||
@@ -16,8 +19,58 @@
|
||||
South = 5, // - Z
|
||||
}
|
||||
|
||||
public enum Texture : uint
|
||||
public class BlockDefinition
|
||||
{
|
||||
Stone = 1
|
||||
public Blocks BlockType;
|
||||
public Textures[] FaceTextures;
|
||||
|
||||
public BlockDefinition(Blocks type, Textures singleTexture)
|
||||
{
|
||||
BlockType = type;
|
||||
FaceTextures = new Voxel.Textures[6];
|
||||
for (int i = 0; i < 6; i++) FaceTextures[i] = singleTexture;
|
||||
}
|
||||
|
||||
public BlockDefinition(
|
||||
Blocks type,
|
||||
Textures west,
|
||||
Textures east,
|
||||
Textures top,
|
||||
Textures bottom,
|
||||
Textures north,
|
||||
Textures south
|
||||
)
|
||||
{
|
||||
BlockType = type;
|
||||
FaceTextures = new Textures[]
|
||||
{
|
||||
west, east, top, bottom, north, south
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockDefinitions
|
||||
{
|
||||
public static readonly Dictionary<Blocks, BlockDefinition> Blocks;
|
||||
|
||||
static BlockDefinitions()
|
||||
{
|
||||
Blocks = new Dictionary<Blocks, BlockDefinition>
|
||||
{
|
||||
{ Voxel.Blocks.Stone, new BlockDefinition(Voxel.Blocks.Stone, Voxel.Textures.Stone) },
|
||||
{ Voxel.Blocks.Dirt, new BlockDefinition(Voxel.Blocks.Dirt, Voxel.Textures.Dirt) },
|
||||
{ Voxel.Blocks.OakPlanks, new BlockDefinition(Voxel.Blocks.OakPlanks, Voxel.Textures.OakPlanks) },
|
||||
|
||||
{ Voxel.Blocks.Grass, new BlockDefinition(
|
||||
Voxel.Blocks.Grass,
|
||||
Voxel.Textures.GrassSide, // West
|
||||
Voxel.Textures.GrassSide, // East
|
||||
Voxel.Textures.GrassTop, // Top
|
||||
Voxel.Textures.Dirt, // Bottom
|
||||
Voxel.Textures.GrassSide, // North
|
||||
Voxel.Textures.GrassSide // South
|
||||
)},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
Camera.cs
25
Camera.cs
@@ -4,11 +4,11 @@ namespace Voxel
|
||||
{
|
||||
static class Camera
|
||||
{
|
||||
public static Vector3 Position;
|
||||
public static Vector3 Position = new Vector3(-8, 16, -8);
|
||||
|
||||
public static float Pitch = 0f;
|
||||
public static float Yaw = -90f;
|
||||
public static float FOV = 70f;
|
||||
public static float Pitch = -22.5f;
|
||||
public static float Yaw = 45f;
|
||||
public static float FOV = 60f;
|
||||
public static float Speed = 5f;
|
||||
public static float ShiftSpeed = 20f;
|
||||
|
||||
@@ -56,18 +56,21 @@ namespace Voxel
|
||||
|
||||
public static void UpdateMouse(Vector2 delta)
|
||||
{
|
||||
float fov = MathHelper.DegreesToRadians(60f);
|
||||
float aspectRatio = 800f / 600f;
|
||||
float near = 0.1f;
|
||||
float far = 100f;
|
||||
|
||||
projection = Matrix4.CreatePerspectiveFieldOfView(fov, aspectRatio, near, far);
|
||||
|
||||
float sensitivity = 0.1f;
|
||||
Yaw += delta.X * sensitivity;
|
||||
Pitch -= delta.Y * sensitivity;
|
||||
|
||||
Pitch = MathHelper.Clamp(Pitch, -89f, 89f);
|
||||
}
|
||||
|
||||
public static void UpdateProjection(int width, int height)
|
||||
{
|
||||
float fov = MathHelper.DegreesToRadians(FOV);
|
||||
float aspectRatio = width / (float)height;
|
||||
float near = 0.1f;
|
||||
float far = 1000f;
|
||||
|
||||
projection = Matrix4.CreatePerspectiveFieldOfView(fov, aspectRatio, near, far);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
121
Chunk.cs
121
Chunk.cs
@@ -8,7 +8,7 @@
|
||||
public readonly int PositionY;
|
||||
|
||||
private Dictionary<ushort, BlockData> _blockData;
|
||||
private byte[] _blocks;
|
||||
private Blocks[] _blocks;
|
||||
|
||||
public Chunk(int positionX, int positionY)
|
||||
{
|
||||
@@ -16,18 +16,23 @@
|
||||
PositionY = positionY;
|
||||
|
||||
_blockData = new Dictionary<ushort, BlockData>();
|
||||
_blocks = new byte[Size * Size * Height];
|
||||
_blocks = new Blocks[Size * Size * Height];
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void SetBlock(int x, int y, int z, byte blockId)
|
||||
public void SetBlock(int x, int y, int z, Blocks block)
|
||||
{
|
||||
int i = GetBlockIndex(x, y, z);
|
||||
_blocks[i] = blockId;
|
||||
_blocks[i] = block;
|
||||
}
|
||||
|
||||
public byte GetBlock(int x, int y, int z)
|
||||
public void SetBlockIndex(int i, Blocks block)
|
||||
{
|
||||
_blocks[i] = block;
|
||||
}
|
||||
|
||||
public Blocks GetBlock(int x, int y, int z)
|
||||
{
|
||||
int i = GetBlockIndex(x, y, z);
|
||||
return _blocks[i];
|
||||
@@ -40,23 +45,9 @@
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
for (int x = 0; x < Size; x++)
|
||||
{
|
||||
for (int z = 0; z < Size; z++)
|
||||
{
|
||||
for (int y = 0; y < Size; y++)
|
||||
{
|
||||
byte blockId = 1;
|
||||
SetBlock(x, y, z, blockId);
|
||||
Console.WriteLine(
|
||||
"Set block "
|
||||
+ x.ToString() + ", "
|
||||
+ y.ToString() + ", "
|
||||
+ z.ToString() + " "
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Random rng = new Random();
|
||||
for (int i = 0; i < Size * Size * 16; i++)
|
||||
_blocks[i] = (Blocks)rng.Next(5);
|
||||
}
|
||||
|
||||
// todo
|
||||
@@ -71,60 +62,25 @@
|
||||
|
||||
private int GetBlockIndex(int x, int y, int z)
|
||||
{
|
||||
return x + y * Size + z * Size * Size;
|
||||
return x + z * Size + y * Size * Size;
|
||||
}
|
||||
|
||||
public List<FaceData> GetFaces()
|
||||
private static readonly (int dx, int dy, int dz)[] Offsets = new (int, int, int)[6]
|
||||
{
|
||||
List<FaceData> list = new List<FaceData>();
|
||||
( 1, 0, 0), // +X
|
||||
(-1, 0, 0), // -X
|
||||
( 0, 1, 0), // +Y
|
||||
( 0, -1, 0), // -Y
|
||||
( 0, 0, 1), // +Z
|
||||
( 0, 0, -1) // -Z
|
||||
};
|
||||
|
||||
for (byte i = 0; i < 6; i++)
|
||||
|
||||
public ChunkMesh GetChunkMesh()
|
||||
{
|
||||
FaceData faceData = new FaceData();
|
||||
ChunkMesh chunkMesh = new ChunkMesh(Size * Size * Height / 2);
|
||||
|
||||
faceData.Facing = (Orientation)i;
|
||||
|
||||
list.Add(faceData);
|
||||
}
|
||||
|
||||
for (byte i = 0; i < 6; i++)
|
||||
{
|
||||
FaceData faceData = new FaceData();
|
||||
|
||||
faceData.Facing = (Orientation)i;
|
||||
|
||||
faceData.X = 1;
|
||||
|
||||
list.Add(faceData);
|
||||
}
|
||||
|
||||
for (byte i = 0; i < 6; i++)
|
||||
{
|
||||
FaceData faceData = new FaceData();
|
||||
|
||||
faceData.Facing = (Orientation)i;
|
||||
|
||||
|
||||
faceData.X = 1;
|
||||
faceData.Y = 1;
|
||||
faceData.Z = 1;
|
||||
|
||||
list.Add(faceData);
|
||||
}
|
||||
|
||||
for (byte i = 0; i < 6; i++)
|
||||
{
|
||||
FaceData faceData = new FaceData();
|
||||
|
||||
faceData.Facing = (Orientation)i;
|
||||
|
||||
|
||||
faceData.X = 1;
|
||||
faceData.Y = 2;
|
||||
faceData.Z = 1;
|
||||
|
||||
list.Add(faceData);
|
||||
}
|
||||
// offsets table
|
||||
|
||||
for (int x = 0; x < Size; x++)
|
||||
{
|
||||
@@ -132,23 +88,40 @@
|
||||
{
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
for (byte i = 0; i < 6; i++)
|
||||
for (byte face = 0; face < 6; face++)
|
||||
{
|
||||
int indexBase = y * Size * Size + z * Size + x;
|
||||
Blocks block = _blocks[indexBase];
|
||||
|
||||
if (block == Blocks.Air) continue; // ignore if air
|
||||
|
||||
int nx = x + Offsets[face].dx;
|
||||
int ny = y + Offsets[face].dy;
|
||||
int nz = z + Offsets[face].dz;
|
||||
|
||||
// check neighbor, ignore if at chunk edge
|
||||
if (nx >= 0 && nx < Size &&
|
||||
ny >= 0 && ny < Height &&
|
||||
nz >= 0 && nz < Size &&
|
||||
_blocks[GetBlockIndex(nx, ny, nz)] != 0)
|
||||
continue;
|
||||
|
||||
FaceData faceData = new FaceData();
|
||||
|
||||
faceData.Facing = (Orientation)i;
|
||||
faceData.Facing = (Orientation)face;
|
||||
faceData.Texture = BlockDefinitions.Blocks[block].FaceTextures[face];
|
||||
|
||||
faceData.X = (byte)x;
|
||||
faceData.Y = (byte)y;
|
||||
faceData.Z = (byte)z;
|
||||
|
||||
//list.Add(faceData);
|
||||
chunkMesh.Faces.Add(faceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
return chunkMesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
ChunkMesh.cs
19
ChunkMesh.cs
@@ -1,17 +1,18 @@
|
||||
namespace Voxel
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Voxel
|
||||
{
|
||||
public class ChunkMesh
|
||||
{
|
||||
private List<FaceData> _faces;
|
||||
public List<FaceData> Faces;
|
||||
|
||||
public ChunkMesh(Chunk chunk)
|
||||
public ChunkMesh(int maxBlocks)
|
||||
{
|
||||
_faces = new List<FaceData>();
|
||||
}
|
||||
|
||||
private void MeshBlock(int i)
|
||||
{
|
||||
|
||||
Faces = new List<FaceData>(maxBlocks * 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace Voxel
|
||||
{
|
||||
static class ChunkMesher
|
||||
{
|
||||
static ChunkMesh MeshChunk(Chunk chunk)
|
||||
{
|
||||
ChunkMesh chunkMesh = new ChunkMesh(chunk);
|
||||
|
||||
return chunkMesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
FaceData.cs
16
FaceData.cs
@@ -2,22 +2,24 @@
|
||||
|
||||
namespace Voxel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct FaceData
|
||||
{
|
||||
public Orientation Facing;
|
||||
public uint X, Y, Z;
|
||||
public Texture Texture;
|
||||
public byte X, Y, Z;
|
||||
public Textures Texture;
|
||||
public byte LightLevel;
|
||||
|
||||
public uint[] Pack()
|
||||
public byte[] Pack()
|
||||
{
|
||||
return new uint[]
|
||||
return new byte[]
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
(uint)Facing,
|
||||
(uint)Texture
|
||||
(byte)Facing,
|
||||
(byte)Texture,
|
||||
LightLevel,
|
||||
0,0 // two bits empty
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,15 @@ internal class Program
|
||||
int sizeY = 600;
|
||||
string title = "Game";
|
||||
|
||||
Window window = new Window(sizeX, sizeY, title);
|
||||
|
||||
Chunk chunk = new Chunk(0, 0);
|
||||
|
||||
var faces = chunk.GetFaces();
|
||||
Renderer.AddFaces(faces);
|
||||
ChunkMesh chunkMesh = chunk.GetChunkMesh();
|
||||
Renderer.AddFaces(chunkMesh.Faces);
|
||||
|
||||
window.Chunk = chunk;
|
||||
|
||||
Window window = new Window(sizeX, sizeY, title);
|
||||
window.Run();
|
||||
}
|
||||
}
|
||||
18
Renderer.cs
18
Renderer.cs
@@ -8,13 +8,19 @@ namespace Voxel
|
||||
private static int _vao;
|
||||
private static List<FaceData> _faces = new List<FaceData>();
|
||||
private static Shader _shader;
|
||||
private static Texture _texture;
|
||||
private static bool _needsUpdate = false;
|
||||
|
||||
public static void OnLoad()
|
||||
static Renderer()
|
||||
{
|
||||
string vertexPath = "Shaders/shader.vert";
|
||||
string fragmentPath = "Shaders/shader.frag";
|
||||
string texturePath = "atlas.png";
|
||||
|
||||
_shader = new Shader(vertexPath, fragmentPath);
|
||||
_texture = new Texture(texturePath);
|
||||
|
||||
_shader.SetInt("uTexture", 0);
|
||||
|
||||
_ssbo = GL.GenBuffer();
|
||||
_vao = GL.GenVertexArray();
|
||||
@@ -32,9 +38,8 @@ namespace Voxel
|
||||
if (_needsUpdate)
|
||||
{
|
||||
_needsUpdate = false;
|
||||
Console.WriteLine("Update buffer");
|
||||
uint[] data = _faces.SelectMany(f => f.Pack()).ToArray();
|
||||
GL.BufferData(BufferTarget.ShaderStorageBuffer, data.Length * sizeof(uint), data, BufferUsageHint.StaticRead);
|
||||
byte[] data = _faces.SelectMany(f => f.Pack()).ToArray();
|
||||
GL.BufferData(BufferTarget.ShaderStorageBuffer, data.Length, data, BufferUsageHint.StaticRead);
|
||||
}
|
||||
|
||||
_shader.Use();
|
||||
@@ -51,5 +56,10 @@ namespace Voxel
|
||||
_faces.AddRange(faces);
|
||||
_needsUpdate = true;
|
||||
}
|
||||
|
||||
public static void ClearFaces()
|
||||
{
|
||||
_faces.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Shader.cs
11
Shader.cs
@@ -67,6 +67,17 @@ namespace Voxel
|
||||
GL.UniformMatrix4(location, false, ref matrix);
|
||||
}
|
||||
|
||||
public void SetInt(string name, int value)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
Console.WriteLine($"Uniform '{name}' not found in shader.");
|
||||
return;
|
||||
}
|
||||
GL.Uniform1(location, value);
|
||||
}
|
||||
|
||||
public void Use()
|
||||
{
|
||||
GL.UseProgram(_handle);
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#version 430 core
|
||||
|
||||
out vec4 FragColor;
|
||||
in vec3 fragColor;
|
||||
in vec2 fragUV;
|
||||
in float lighting;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(fragColor, 1.0);
|
||||
vec4 texColor = texture(uTexture, fragUV);
|
||||
FragColor = vec4(texColor.rgb * lighting, texColor.a);
|
||||
}
|
||||
@@ -6,101 +6,108 @@ struct FaceData {
|
||||
uint z;
|
||||
uint facing; // 0=+X,1=-X,2=+Y,3=-Y,4=+Z,5=-Z
|
||||
uint texture;
|
||||
uint lightLevel;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer FaceBuffer {
|
||||
FaceData faces[];
|
||||
uint faces[];
|
||||
};
|
||||
|
||||
out vec3 fragColor;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
vec3 getVertexOffset(uint facing, uint vertIndex) {
|
||||
if (facing == 0u) { // +X
|
||||
vec3 offsets[6] = vec3[6](
|
||||
out vec2 fragUV;
|
||||
out float lighting;
|
||||
|
||||
const float lightMult[6] = float[6](0.6, 0.6, 1.0, 0.5, 0.8, 0.8);
|
||||
|
||||
const vec3 offsets[6][6] = vec3[6][6](
|
||||
vec3[6]( // +X
|
||||
vec3(0.5, -0.5, -0.5),
|
||||
vec3(0.5, 0.5, 0.5),
|
||||
vec3(0.5, -0.5, 0.5),
|
||||
vec3(0.5, 0.5, 0.5),
|
||||
vec3(0.5, -0.5, -0.5),
|
||||
vec3(0.5, 0.5, -0.5)
|
||||
);
|
||||
return offsets[vertIndex];
|
||||
} else if (facing == 1u) { // -X
|
||||
vec3 offsets[6] = vec3[6](
|
||||
),
|
||||
vec3[6]( // -X
|
||||
vec3(-0.5, -0.5, 0.5),
|
||||
vec3(-0.5, 0.5, -0.5),
|
||||
vec3(-0.5, -0.5, -0.5),
|
||||
vec3(-0.5, 0.5, -0.5),
|
||||
vec3(-0.5, -0.5, 0.5),
|
||||
vec3(-0.5, 0.5, 0.5)
|
||||
);
|
||||
return offsets[vertIndex];
|
||||
} else if (facing == 2u) { // +Y (top)
|
||||
vec3 offsets[6] = vec3[6](
|
||||
),
|
||||
vec3[6]( // +Y
|
||||
vec3(-0.5, 0.5, -0.5),
|
||||
vec3( 0.5, 0.5, 0.5),
|
||||
vec3( 0.5, 0.5, -0.5),
|
||||
vec3( 0.5, 0.5, 0.5),
|
||||
vec3(-0.5, 0.5, -0.5),
|
||||
vec3(-0.5, 0.5, 0.5)
|
||||
);
|
||||
return offsets[vertIndex];
|
||||
} else if (facing == 3u) { // -Y (bottom)
|
||||
vec3 offsets[6] = vec3[6](
|
||||
),
|
||||
vec3[6](
|
||||
vec3(-0.5, -0.5, 0.5),
|
||||
vec3( 0.5, -0.5, -0.5),
|
||||
vec3( 0.5, -0.5, 0.5),
|
||||
vec3( 0.5, -0.5, -0.5),
|
||||
vec3(-0.5, -0.5, 0.5),
|
||||
vec3(-0.5, -0.5, -0.5)
|
||||
);
|
||||
return offsets[vertIndex];
|
||||
} else if (facing == 4u) { // +Z (front)
|
||||
vec3 offsets[6] = vec3[6](
|
||||
vec3(-0.5, -0.5, 0.5),
|
||||
),
|
||||
vec3[6]( // +Z
|
||||
vec3( 0.5, -0.5, 0.5),
|
||||
vec3( 0.5, 0.5, 0.5),
|
||||
vec3( 0.5, 0.5, 0.5),
|
||||
vec3(-0.5, 0.5, 0.5),
|
||||
vec3(-0.5, -0.5, 0.5)
|
||||
);
|
||||
return offsets[vertIndex];
|
||||
} else if (facing == 5u) { // -Z (back)
|
||||
vec3 offsets[6] = vec3[6](
|
||||
vec3( 0.5, -0.5, -0.5),
|
||||
vec3(-0.5, -0.5, 0.5),
|
||||
vec3(-0.5, 0.5, 0.5),
|
||||
vec3( 0.5, -0.5, 0.5),
|
||||
vec3( 0.5, 0.5, 0.5)
|
||||
),
|
||||
vec3[6]( // -Z
|
||||
vec3(-0.5, -0.5, -0.5),
|
||||
vec3(-0.5, 0.5, -0.5),
|
||||
vec3(-0.5, 0.5, -0.5),
|
||||
vec3( 0.5, 0.5, -0.5),
|
||||
vec3( 0.5, -0.5, -0.5)
|
||||
vec3( 0.5, -0.5, -0.5),
|
||||
vec3( 0.5, 0.5, -0.5),
|
||||
vec3(-0.5, -0.5, -0.5),
|
||||
vec3(-0.5, 0.5, -0.5)
|
||||
)
|
||||
);
|
||||
return offsets[vertIndex];
|
||||
}
|
||||
}
|
||||
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
const vec2 uvs[6] = vec2[6](vec2(0,0), vec2(1,1), vec2(1,0), vec2(1,1), vec2(0,0), vec2(0,1));
|
||||
|
||||
void main()
|
||||
{
|
||||
float[6] lightMult = float[6](
|
||||
0.6,
|
||||
0.6,
|
||||
1.0,
|
||||
0.5,
|
||||
0.8,
|
||||
0.8
|
||||
);
|
||||
uint faceIndex = gl_VertexID / 6u;
|
||||
uint vertIndex = gl_VertexID % 6u;
|
||||
|
||||
uint faceIndex = gl_VertexID / 6;
|
||||
uint vertIndex = gl_VertexID % 6;
|
||||
uint start = faceIndex * 2u; // 2 byte per face
|
||||
|
||||
FaceData f = faces[faceIndex];
|
||||
vec3 basePos = vec3(f.x, f.y, f.z);
|
||||
vec4 worldPos = vec4(basePos + getVertexOffset(f.facing, vertIndex), 1.0);
|
||||
uint u0 = faces[start]; // data in uint 0
|
||||
uint u1 = faces[start + 1]; // data in uint 1
|
||||
|
||||
// extract values from bits
|
||||
uint x = u0 & 0xFFu;
|
||||
uint y = (u0 >> 8) & 0xFFu;
|
||||
uint z = (u0 >> 16) & 0xFFu;
|
||||
uint facing = (u0 >> 24) & 0xFFu;
|
||||
uint texture = u1 & 0xFFu;
|
||||
uint lightLevel = (u1 >> 8) & 0xFFu;
|
||||
|
||||
fragColor = vec3(1.0, 1.0, 1.0) * lightMult[f.facing];
|
||||
vec3 basePos = vec3(x, y, z);
|
||||
vec4 worldPos = vec4(basePos + offsets[facing][vertIndex], 1.0);
|
||||
float light = float(lightLevel) / 255.0; // use later for caves and stuff
|
||||
|
||||
// UV mapping
|
||||
uint col = texture & 15u; // texture % 16
|
||||
uint row = texture >> 4; // texture / 16
|
||||
row = 15u - row; // invert row so 0 is top
|
||||
|
||||
// convert to float after int math, divide by 16
|
||||
vec2 uv = uvs[vertIndex] * 0.0625;
|
||||
uv.x += float(col) * 0.0625;
|
||||
uv.y += float(row) * 0.0625;
|
||||
|
||||
fragUV = uv;
|
||||
lighting = lightMult[facing];
|
||||
|
||||
gl_Position = projection * view * worldPos;
|
||||
}
|
||||
43
Texture.cs
Normal file
43
Texture.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using StbImageSharp;
|
||||
|
||||
namespace Voxel
|
||||
{
|
||||
public class Texture
|
||||
{
|
||||
private int _handle;
|
||||
private string _path;
|
||||
|
||||
public Texture(string path)
|
||||
{
|
||||
_handle = GL.GenTexture();
|
||||
_path = path;
|
||||
|
||||
LoadFromFile();
|
||||
}
|
||||
|
||||
private void LoadFromFile()
|
||||
{
|
||||
StbImage.stbi_set_flip_vertically_on_load(1);
|
||||
ImageResult image = ImageResult.FromStream(File.OpenRead(_path), ColorComponents.RedGreenBlueAlpha);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, _handle);
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
|
||||
image.Width, image.Height, 0,
|
||||
PixelFormat.Rgba, PixelType.UnsignedByte, image.Data
|
||||
);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
}
|
||||
|
||||
public void Bind(TextureUnit unit = TextureUnit.Texture0)
|
||||
{
|
||||
GL.ActiveTexture(unit);
|
||||
GL.BindTexture(TextureTarget.Texture2D, _handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Textures.cs
Normal file
44
Textures.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace Voxel
|
||||
{
|
||||
public enum Textures : uint
|
||||
{
|
||||
GrassTop,
|
||||
Stone,
|
||||
Dirt,
|
||||
GrassSide,
|
||||
OakPlanks,
|
||||
SmoothStoneSlab,
|
||||
SmoothStone,
|
||||
Bricks,
|
||||
TntSide,
|
||||
TntTop,
|
||||
TntBottom,
|
||||
Cobweb,
|
||||
Rose,
|
||||
Dandelion,
|
||||
Water,
|
||||
OakSapling,
|
||||
Cobblestone,
|
||||
Bedrock,
|
||||
Sand,
|
||||
Gravel,
|
||||
OakSide,
|
||||
OakTop,
|
||||
IronBlock,
|
||||
GoldBlock,
|
||||
DiamondBlock,
|
||||
EmeraldBlock,
|
||||
RedstoneBlock,
|
||||
none0,
|
||||
RedMushroom,
|
||||
BrownMushroom,
|
||||
JungleSapling,
|
||||
none1,
|
||||
GoldOre,
|
||||
IronOre,
|
||||
CoalOre,
|
||||
Bookshelf,
|
||||
MossyCobblestone,
|
||||
Obsidian,
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,13 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK" Version="4.9.4" />
|
||||
<PackageReference Include="StbImageSharp" Version="2.30.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="atlas.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Shaders\shader.frag">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
38
Window.cs
38
Window.cs
@@ -11,6 +11,11 @@ namespace Voxel
|
||||
public uint frames = 0;
|
||||
public double timeElapsed = 0;
|
||||
|
||||
// testing
|
||||
public Chunk Chunk;
|
||||
private Dictionary<int, bool> _cache = new Dictionary<int, bool>();
|
||||
private bool chunkEmpty = false;
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnUpdateFrame(e);
|
||||
@@ -19,6 +24,31 @@ namespace Voxel
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
RemoveRandomBlocks();
|
||||
}
|
||||
|
||||
private void RemoveRandomBlocks()
|
||||
{
|
||||
if (Chunk != null && !chunkEmpty)
|
||||
{
|
||||
Random rng = new Random();
|
||||
|
||||
int GetNum()
|
||||
{
|
||||
int max = 4096;
|
||||
int num = rng.Next(max);
|
||||
if (_cache.ContainsKey(num)) return GetNum();
|
||||
_cache[num] = true;
|
||||
if (_cache.Count == max) chunkEmpty = true;
|
||||
return num;
|
||||
}
|
||||
|
||||
Chunk.SetBlockIndex(GetNum(), Blocks.Air);
|
||||
}
|
||||
|
||||
Renderer.ClearFaces();
|
||||
Renderer.AddFaces(Chunk.GetChunkMesh().Faces);
|
||||
}
|
||||
|
||||
protected override void OnRenderFrame(FrameEventArgs e)
|
||||
@@ -46,6 +76,8 @@ namespace Voxel
|
||||
{
|
||||
base.OnFramebufferResize(e);
|
||||
|
||||
Camera.UpdateProjection(e.Width, e.Height);
|
||||
|
||||
GL.Viewport(0, 0, e.Width, e.Height);
|
||||
}
|
||||
|
||||
@@ -53,15 +85,17 @@ namespace Voxel
|
||||
{
|
||||
base.OnLoad();
|
||||
|
||||
Renderer.OnLoad();
|
||||
|
||||
GL.ClearColor(0.72f, 0.88f, 0.97f, 1f);
|
||||
|
||||
GL.Enable(EnableCap.CullFace);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
|
||||
CursorState = CursorState.Grabbed;
|
||||
VSync = VSyncMode.On;
|
||||
|
||||
Camera.UpdateProjection(Width, Height);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user