Compare commits
2 Commits
0641d22c9b
...
01d86cd2aa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01d86cd2aa | ||
|
|
f532eddfbb |
20
Chunk.cs
20
Chunk.cs
@@ -40,7 +40,7 @@ namespace Voxel
|
||||
Y = y;
|
||||
|
||||
_blockData = new Dictionary<ushort, BlockData>();
|
||||
_blocks = new Blocks[Size * Size * Height];
|
||||
_blocks = new Blocks[TotalBlocks];
|
||||
_chunkMesh = new ChunkMesh(X, Y);
|
||||
|
||||
Initialize();
|
||||
@@ -219,14 +219,16 @@ namespace Voxel
|
||||
|
||||
private void AddFace(int x, int y, int z, int face, Textures texture, List<FaceData> faces)
|
||||
{
|
||||
faces.Add(new FaceData
|
||||
{
|
||||
Facing = (Orientation)face,
|
||||
Texture = texture,
|
||||
X = (byte)x,
|
||||
Y = (byte)y,
|
||||
Z = (byte)z
|
||||
});
|
||||
byte lightLevel = 15;
|
||||
|
||||
faces.Add(new FaceData(
|
||||
(byte)x,
|
||||
(byte)y,
|
||||
(byte)z,
|
||||
(Orientation)face,
|
||||
texture,
|
||||
lightLevel
|
||||
));
|
||||
}
|
||||
|
||||
public ChunkMesh GetChunkMesh()
|
||||
|
||||
41
ChunkMesh.cs
41
ChunkMesh.cs
@@ -1,25 +1,15 @@
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Voxel
|
||||
namespace Voxel
|
||||
{
|
||||
public class ChunkMesh
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
private byte[] _packedData;
|
||||
public bool NeedsUpdate = false;
|
||||
public int Size = 0;
|
||||
private List<FaceData> _faces;
|
||||
|
||||
public ChunkMesh(int x, int y)
|
||||
{
|
||||
_packedData = new byte[0];
|
||||
_packedData = Array.Empty<byte>();
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
@@ -27,18 +17,31 @@ namespace Voxel
|
||||
public void SetFaces(List<FaceData> faces)
|
||||
{
|
||||
Size = faces.Count;
|
||||
_faces = faces;
|
||||
NeedsUpdate = true;
|
||||
_packedData = PackFaces(faces);
|
||||
}
|
||||
|
||||
public byte[] GetPackedData()
|
||||
private static byte[] PackFaces(List<FaceData> faces)
|
||||
{
|
||||
if (NeedsUpdate)
|
||||
const int BYTES_PER_FACE = 4;
|
||||
int totalFaces = faces.Count;
|
||||
var result = new byte[faces.Count * BYTES_PER_FACE];
|
||||
|
||||
for (int i = 0; i < totalFaces; i++)
|
||||
{
|
||||
_packedData = _faces.SelectMany(f => f.Pack()).ToArray();
|
||||
var face = faces[i];
|
||||
uint packed = face._data;
|
||||
int offset = i * 4;
|
||||
|
||||
// Write little-endian (important!)
|
||||
result[offset] = (byte)(packed);
|
||||
result[offset + 1] = (byte)(packed >> 8);
|
||||
result[offset + 2] = (byte)(packed >> 16);
|
||||
result[offset + 3] = (byte)(packed >> 24);
|
||||
}
|
||||
|
||||
return _packedData;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] GetPackedData() => _packedData;
|
||||
}
|
||||
}
|
||||
|
||||
45
FaceData.cs
45
FaceData.cs
@@ -2,25 +2,42 @@
|
||||
|
||||
namespace Voxel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct FaceData
|
||||
{
|
||||
public Orientation Facing;
|
||||
public byte X, Y, Z;
|
||||
public Textures Texture;
|
||||
public byte LightLevel;
|
||||
public uint _data;
|
||||
|
||||
// Bit layout:
|
||||
// [31-24]: Y (8 bits) 0-255
|
||||
// [23-20]: Z (4 bits) 0-15
|
||||
// [19-16]: X (4 bits) 0-15
|
||||
// [15-10]: Texture (6 bits) 0-63
|
||||
// [9-7]: Facing (3 bits) 0-7
|
||||
// [6-3]: Light (4 bits) 0-15
|
||||
// [2-0]: unused (3 bits)
|
||||
|
||||
public FaceData(byte x, byte y, byte z, Orientation facing, Textures texture, byte lightLevel)
|
||||
{
|
||||
_data = (uint)(
|
||||
((y & 0xFF) << 24) | // 8 bits
|
||||
((z & 0x0F) << 20) | // 4 bits
|
||||
((x & 0x0F) << 16) | // 4 bits
|
||||
(((byte)texture & 0x3F) << 10) | // 6 bits (0-63)
|
||||
(((byte)facing & 0x07) << 7) | // 3 bits
|
||||
((lightLevel & 0x0F) << 3) // 4 bits
|
||||
);
|
||||
}
|
||||
|
||||
public byte X => (byte)((_data >> 16) & 0x0F);
|
||||
public byte Y => (byte)((_data >> 24) & 0xFF);
|
||||
public byte Z => (byte)((_data >> 20) & 0x0F);
|
||||
public Orientation Facing => (Orientation)((_data >> 7) & 0x07);
|
||||
public Textures Texture => (Textures)((_data >> 10) & 0x3F);
|
||||
public byte LightLevel => (byte)((_data >> 3) & 0x0F);
|
||||
|
||||
public byte[] Pack()
|
||||
{
|
||||
return new byte[]
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
(byte)Facing,
|
||||
(byte)Texture,
|
||||
LightLevel,
|
||||
0,0 // two bits empty
|
||||
};
|
||||
return BitConverter.GetBytes(_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Voxel
|
||||
{
|
||||
@@ -66,7 +60,6 @@ namespace Voxel
|
||||
|
||||
if (Input.GetKey(Keys.Space) && OnGround)
|
||||
{
|
||||
Console.WriteLine("Jump");
|
||||
Velocity = new Vector3(Velocity.X, 0.42f, Velocity.Z);
|
||||
OnGround = false;
|
||||
}
|
||||
|
||||
28
Program.cs
28
Program.cs
@@ -12,34 +12,6 @@ internal class Program
|
||||
World world = new World();
|
||||
Window window = new Window(sizeX, sizeY, title);
|
||||
|
||||
Console.WriteLine("Generating map...");
|
||||
|
||||
int worldSizeX = 2;
|
||||
int worldSizeY = 2;
|
||||
|
||||
float maxI = worldSizeX * worldSizeY;
|
||||
int i = 0;
|
||||
int lastPercentage = 0;
|
||||
|
||||
for (int x = 0; x < worldSizeX; x++)
|
||||
{
|
||||
for (int y = 0; y < worldSizeY; y++)
|
||||
{
|
||||
i++;
|
||||
Chunk chunk = new Chunk(x, y);
|
||||
world.AddChunk(chunk);
|
||||
|
||||
int percentage = (int)((i / maxI) * 100);
|
||||
if (percentage > lastPercentage)
|
||||
{
|
||||
lastPercentage = percentage;
|
||||
Console.WriteLine((percentage).ToString() + "%");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Generated " + maxI.ToString() + " chunks");
|
||||
|
||||
Renderer.SetWorld(world);
|
||||
|
||||
Vector3 startPos = new Vector3(15, 64, 15);
|
||||
|
||||
25
Renderer.cs
25
Renderer.cs
@@ -72,8 +72,8 @@ namespace Voxel
|
||||
byte[] data = chunkMesh.GetPackedData();
|
||||
|
||||
GL.BufferSubData(BufferTarget.ShaderStorageBuffer,
|
||||
(IntPtr)(faceOffset * 8), // faceOffset * 8 = byte offset
|
||||
chunkMesh.Size * 8,
|
||||
(IntPtr)(faceOffset * 4), // faceOffset * 4 = byte offset
|
||||
chunkMesh.Size * 4,
|
||||
data
|
||||
);
|
||||
|
||||
@@ -83,28 +83,7 @@ namespace Voxel
|
||||
|
||||
private static void RenderUi()
|
||||
{
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
//_uiShader.Use();
|
||||
|
||||
//Matrix4 projection = Matrix4.CreateOrthographicOffCenter(
|
||||
// 0, screenWidth, screenHeight, 0, -1, 1);
|
||||
//_uiShader.SetMatrix4("projection", projection);
|
||||
|
||||
// Bind UI texture atlas
|
||||
//_uiTexture.Bind();
|
||||
|
||||
// Draw all UI sprites (batch by texture for efficiency)
|
||||
//foreach (var sprite in _uiSprites)
|
||||
//{
|
||||
// sprite.Draw();
|
||||
//}
|
||||
|
||||
// Restore 3D settings
|
||||
GL.Disable(EnableCap.Blend);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
}
|
||||
|
||||
private static void RenderWorld()
|
||||
|
||||
@@ -21,6 +21,7 @@ void main()
|
||||
|
||||
float fogFactor = (fogEndSq - distSq) * fogRangeInv;
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
fogFactor = 1;
|
||||
|
||||
// Texture and lighting
|
||||
vec4 texColor = texture(uTexture, fragUV);
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
#version 430 core
|
||||
|
||||
struct FaceData {
|
||||
uint x;
|
||||
uint y;
|
||||
uint z;
|
||||
uint facing; // 0=+X,1=-X,2=+Y,3=-Y,4=+Z,5=-Z
|
||||
uint texture;
|
||||
uint lightLevel;
|
||||
uint pack; // All data in 4 bytes
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer FaceBuffer {
|
||||
@@ -77,23 +72,35 @@ const vec3 offsets[6][6] = vec3[6][6](
|
||||
|
||||
const vec2 uvs[6] = vec2[6](vec2(0,0), vec2(1,1), vec2(1,0), vec2(1,1), vec2(0,0), vec2(0,1));
|
||||
|
||||
// Function to unpack the 4-byte face data
|
||||
// Bit layout from C# (little-endian, but we read as uint):
|
||||
// Bits 31-24: Y (8 bits) 0-255
|
||||
// Bits 23-20: Z (4 bits) 0-15
|
||||
// Bits 19-16: X (4 bits) 0-15
|
||||
// Bits 15-10: Texture (6 bits) 0-63
|
||||
// Bits 9-7: Facing (3 bits) 0-7
|
||||
// Bits 6-3: Light (4 bits) 0-15
|
||||
// Bits 2-0: unused (3 bits)
|
||||
void unpackFace(uint pack, out uint x, out uint y, out uint z,
|
||||
out uint facing, out uint texture, out uint lightLevel)
|
||||
{
|
||||
y = (pack >> 24) & 0xFFu; // Y: bits 24-31 (8 bits)
|
||||
z = (pack >> 20) & 0x0Fu; // Z: bits 20-23 (4 bits)
|
||||
x = (pack >> 16) & 0x0Fu; // X: bits 16-19 (4 bits)
|
||||
texture = (pack >> 10) & 0x3Fu; // Texture: bits 10-15 (6 bits)
|
||||
facing = (pack >> 7) & 0x07u; // Facing: bits 7-9 (3 bits)
|
||||
lightLevel = (pack >> 3) & 0x0Fu;// Light: bits 3-6 (4 bits)
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
uint faceIndex = gl_VertexID / 6u;
|
||||
uint vertIndex = gl_VertexID % 6u;
|
||||
|
||||
uint start = faceIndex * 2u; // 2 uint per face
|
||||
uint pack = faces[faceIndex];
|
||||
|
||||
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;
|
||||
uint x, y, z, facing, texture, lightLevel;
|
||||
unpackFace(pack, x, y, z, facing, texture, lightLevel);
|
||||
|
||||
vec3 basePos = vec3(x, y, z) + vec3(chunkX, 0, chunkY) * 16.0;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Voxel
|
||||
{
|
||||
public enum Textures : uint
|
||||
public enum Textures : byte
|
||||
{
|
||||
GrassTop,
|
||||
Stone,
|
||||
|
||||
7
UIElement.cs
Normal file
7
UIElement.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using OpenTK.Mathematics;
|
||||
using System.Drawing;
|
||||
|
||||
public class UIElement
|
||||
{
|
||||
|
||||
}
|
||||
17
UISprite.cs
17
UISprite.cs
@@ -1,17 +0,0 @@
|
||||
using OpenTK.Mathematics;
|
||||
using System.Drawing;
|
||||
|
||||
public class UISprite
|
||||
{
|
||||
public Vector2 Position; // Screen pixels (not normalized)
|
||||
public Vector2 Size; // Size in pixels
|
||||
public Rectangle TextureRegion; // Which part of atlas to use
|
||||
public Color Tint = Color.White;
|
||||
public float Rotation = 0f;
|
||||
public Vector2 Origin = Vector2.Zero; // Rotation/scale origin
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
// Draw textured quad using TextureRegion coordinates
|
||||
}
|
||||
}
|
||||
7
World.cs
7
World.cs
@@ -9,7 +9,8 @@ namespace Voxel
|
||||
private Dictionary<(int, int), Chunk> _chunks;
|
||||
|
||||
private (int x, int z) _lastCenter = (0, 0);
|
||||
private int _loadDistance = 4;
|
||||
private int _loadDistance = 32;
|
||||
bool chunkLoadingInitialized = false;
|
||||
|
||||
private static readonly Dictionary<Orientation, (int x, int y)> _neighborOffsets = new()
|
||||
{
|
||||
@@ -62,7 +63,7 @@ namespace Voxel
|
||||
int centerZ = (int)Math.Floor(playerPosition.Z / Chunk.Size);
|
||||
|
||||
// Quick check - skip if still in same chunk
|
||||
if (centerX == _lastCenter.x && centerZ == _lastCenter.z)
|
||||
if ((centerX == _lastCenter.x && centerZ == _lastCenter.z) && chunkLoadingInitialized)
|
||||
return;
|
||||
|
||||
_lastCenter = (centerX, centerZ);
|
||||
@@ -78,6 +79,8 @@ namespace Voxel
|
||||
|
||||
// Load chunks inside range
|
||||
LoadChunksInRange(minX, maxX, minZ, maxZ);
|
||||
|
||||
chunkLoadingInitialized = true;
|
||||
}
|
||||
|
||||
private void UnloadDistantChunks(int minX, int maxX, int minZ, int maxZ)
|
||||
|
||||
Reference in New Issue
Block a user