diff --git a/.gitea/workflows/autobuild.yaml b/.gitea/workflows/autobuild.yaml index 999c99e..7cb7028 100644 --- a/.gitea/workflows/autobuild.yaml +++ b/.gitea/workflows/autobuild.yaml @@ -11,13 +11,15 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Install build tools run: | # echo "deb [signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] http://archive.ubuntu.com/ubuntu noble main" | sudo tee /tmp/only.list # sudo apt-get update -o Dir::Etc::sourcelist=/tmp/only.list -o Dir::Etc::sourceparts="-" -qq sudo apt update - sudo apt install -y build-essential cmake zip unzip make libxrandr-dev g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 libxinerama-dev libxcursor-dev libxi-dev libgl-dev + sudo apt install -y build-essential cmake zip unzip make libxrandr-dev g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 g++-mingw-i686-x86-64 gcc-mingw-i686-x86-64 libxinerama-dev libxcursor-dev libxi-dev libgl-dev - name: Build makeheaders run: | diff --git a/src/helpers/chunks.cpp b/src/helpers/chunks.cpp index 08c431d..ee9dd79 100644 --- a/src/helpers/chunks.cpp +++ b/src/helpers/chunks.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "common.hpp" @@ -6,6 +7,7 @@ #include #include #include +#include #define HUMIDITY_OFFSET 12.3f #define CAVE_OFFSET 45.6f @@ -107,6 +109,35 @@ int GetBlock(World &world, int x, int y, int z) { int cz = z / CHUNK_SIZE; return fetch_block(world.chunks[GetIndexWorld(cx, cz)], locX, y, locZ); } +int GetHighestBlock(World &world, int x, int z) { + if(CheckOOBWorld(x, 0, z)) return 0; + int locX = x % CHUNK_SIZE; + int locZ = z % CHUNK_SIZE; + int cx = x / CHUNK_SIZE; + int cz = z / CHUNK_SIZE; + return world.chunks[GetIndexWorld(cx, cz)].highestBlock[GetIndexChunk2D(locX, locZ)]; +} +int GetSkyLight(World &world, int x, int y, int z) { + if(CheckOOBWorld(x, y, z)) return 0; + int locX = x % CHUNK_SIZE; + int locZ = z % CHUNK_SIZE; + int cx = x / CHUNK_SIZE; + int cz = z / CHUNK_SIZE; + uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)]; + int skyLight = (light >> 12) & 0xF; + return skyLight; +} +Color GetLight(World &world, int x, int y, int z) { + if(CheckOOBWorld(x, y, z)) return {0, 0, 0, 0}; + int locX = x % CHUNK_SIZE; + int locZ = z % CHUNK_SIZE; + int cx = x / CHUNK_SIZE; + int cz = z / CHUNK_SIZE; + uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)]; + int skyLight = ((light >> 12) & 0xF) * 16; + //return {((light >> 8) & 0xF) * 16 + skyLight, (light >> 4) * 16 + skyLight, (light & 0xF) * 16 + skyLight, 255}; + return {skyLight, skyLight, skyLight, 255}; +} bool CanTick(int blockType) { // TODO: make smarter in case other blocks can tick too! return blockType == BLOCK_SAND; } @@ -211,6 +242,19 @@ void SetBlock(World &world, int x, int y, int z, int t) { int cz = z / CHUNK_SIZE; SetBlockChunk(&world.chunks[GetIndexWorld(cx, cz)], locX, y, locZ, t); } + +void SetLightChunk(Chunk *c, int x, int y, int z, uint8_t sky, uint8_t r, uint8_t g, uint8_t b) { + c->light[GetIndexChunk(x,y,z)] = sky << 12 | r << 8 | g << 4 | b; +} +void SetLight(World &world, int x, int y, int z, uint8_t sky, uint8_t r, uint8_t g, uint8_t b) { + if(CheckOOBWorld(x, y, z)) { return; } + int locX = x % CHUNK_SIZE; + int locZ = z % CHUNK_SIZE; + int cx = x / CHUNK_SIZE; + int cz = z / CHUNK_SIZE; + SetLightChunk(&world.chunks[GetIndexWorld(cx, cz)], locX, y, locZ, sky, r, g, b); +} + void InitWorldgen(int worldType) { const siv::PerlinNoise::seed_type seed = 123456u; const siv::PerlinNoise perlin{ seed }; @@ -232,7 +276,7 @@ Chunk GenerateChunk(int _x, int _y) { Chunk new_chunk = { 0 }; new_chunk.x = _x; new_chunk.z = _y; - + memset(&new_chunk.light, 0, sizeof(new_chunk.light)); for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < WORLD_HEIGHT; y++) @@ -480,6 +524,10 @@ void TickChunk(Chunk *chunk, World &world, int wx, int wz) { } } } +struct LightNode { + Vector3I position; + int value; +}; void RebuildOpaqueMask(Chunk &chunk) { const int GROUP = 16; const int GROUPS = CHUNK_DATA_SIZE / GROUP; @@ -504,6 +552,60 @@ void RebuildOpaqueMask(Chunk &chunk) { memcpy(chunk.airMask, aMask, sizeof(aMask)); } +void RebuildLighting(World &world, int startX, int startZ) { + std::queue nodes; + + for (int cx = -1; cx <= 1; cx++) + { + for (int cz = -1; cz <= 1; cz++) { + Chunk &chunk = world.chunks[GetIndexWorld(startX+cx, startZ+cz)]; + memset(&chunk.light, 0, sizeof(chunk.light)); + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { + int y = chunk.highestBlock[GetIndexChunk2D(x, z)]; + if (y < 0) continue; + Vector3I pos = { x + chunk.x * CHUNK_SIZE, y + 1, z + chunk.z * CHUNK_SIZE }; + if (CheckOOBWorld(pos.x, pos.y, pos.z)) continue; + for (int _y = WORLD_HEIGHT; _y >= y; _y--) + { + SetLight(world, pos.x, _y, pos.z, 15, 0, 0, 0); + } + + LightNode node{pos, 15}; + SetLight(world, pos.x, pos.y, pos.z, 15, 0, 0, 0); + nodes.push(node); + } + } + } + } + + + const Vector3I dirs[6] = { (Vector3I){ 1, 0, 0 }, (Vector3I){ -1, 0, 0 }, (Vector3I){ 0, 1, 0 }, (Vector3I){ 0,-1, 0 }, (Vector3I){ 0, 0, 1 }, (Vector3I){ 0, 0,-1 } }; + + while (!nodes.empty()) { + std::cout << nodes.size() << std::endl; + LightNode node = nodes.front(); + nodes.pop(); + + for (int i = 0; i < 6; i++) { + Vector3I newPos = { + node.position.x + dirs[i].x, + node.position.y + dirs[i].y, + node.position.z + dirs[i].z + }; + + if (CheckOOBWorld(newPos.x, newPos.y, newPos.z)) continue; + if (GetBlock(world, newPos.x, newPos.y, newPos.z) != BLOCK_AIR) continue; + int newValue = node.value - 1; + if (newValue <= 0) continue; + + if (GetSkyLight(world, newPos.x, newPos.y, newPos.z) >= newValue) continue; + + SetLight(world, newPos.x, newPos.y, newPos.z, newValue, 0, 0, 0); + nodes.push({ newPos, newValue }); + } + } +} #ifndef SERVER //Generates an opaque CRD (ChunkRenderData). Outputs the CRD. ChunkRenderData GenerateCRDOpaque(Chunk &chunk, World &world) { diff --git a/src/helpers/common.hpp b/src/helpers/common.hpp index 055bba7..96a7f61 100644 --- a/src/helpers/common.hpp +++ b/src/helpers/common.hpp @@ -9,6 +9,7 @@ #undef PlaySound #undef Sound #endif +#include #include "glfw_keycodes_to_string.h" #include "../PerlinNoise.hpp" #include "raylib.h" @@ -77,7 +78,7 @@ #define DEFAULT_FONT_SIZE 16 #define TPS 30.0 #define TPS_DIV 1.0 / TPS -#define RENDER_DISTANCE 128 +#define RENDER_DISTANCE 2 #define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE #define MAX_HP 100 #define PATH_APPEND "resources/" @@ -152,7 +153,7 @@ struct Chunk { uint16_t opaqueMask[CHUNK_DATA_SIZE/16]; uint16_t airMask[CHUNK_DATA_SIZE/16]; uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE]; - uint8_t lights[CHUNK_DATA_SIZE]; + uint16_t light[CHUNK_DATA_SIZE]; }; #if !defined(SERVER) typedef struct ChunkRenderData ChunkRenderData; @@ -195,9 +196,19 @@ struct Quad2D { #endif typedef struct Vector3I Vector3I; struct Vector3I { - int x; - int y; - int z; + int x, y, z; + bool operator==(const Vector3I& other) const { + return (x == other.x && y == other.y && z == other.z); + }; +}; +typedef struct Vector3IHash Vector3IHash; +struct Vector3IHash { + size_t operator()(const Vector3I& p) const noexcept { + size_t h1 = std::hash{}(p.x); + size_t h2 = std::hash{}(p.y); + size_t h3 = std::hash{}(p.z); + return h1 ^ (h2 << 1) ^ (h3 << 2); + } }; typedef struct Entity Entity; struct Entity { @@ -294,6 +305,9 @@ struct World { }; extern const BlockDef BLOCKS[]; int GetBlock(World&world,int x,int y,int z); +int GetHighestBlock(World&world,int x,int z); +int GetSkyLight(World&world,int x,int y,int z); +Color GetLight(World&world,int x,int y,int z); bool CanTick(int blockType); bool GetCloud(int x,int z); bool IsTranslucent(int blockType); @@ -302,6 +316,8 @@ void RebuildHeightmap(Chunk&c); int GetBiome(int sx,int sy); void SetBlockChunkFast(Chunk *c,int i,int t); void SetBlock(World&world,int x,int y,int z,int t); +void SetLightChunk(Chunk *c,int x,int y,int z,uint8_t sky,uint8_t r,uint8_t g,uint8_t b); +void SetLight(World&world,int x,int y,int z,uint8_t sky,uint8_t r,uint8_t g,uint8_t b); void InitWorldgen(int worldType); Vector3 WorldPosition(int cx,int cz,int localX,int y,int localZ); Chunk GenerateChunk(int _x,int _y); @@ -309,6 +325,7 @@ void GenerateWorldAdditional(World&world); void TickBlock(World&world,int wx,int wy,int wz); void TickChunk(Chunk *chunk,World&world,int wx,int wz); void RebuildOpaqueMask(Chunk&chunk); +void RebuildLighting(World&world,int startX,int startZ); #if !defined(SERVER) ChunkRenderData GenerateCRDOpaque(Chunk&chunk,World&world); ChunkRenderData GenerateCRDTranslucent(Chunk chunk,World&world); @@ -406,7 +423,7 @@ char *DrawChat(); void DrawLogoCenter(); #endif #if !defined(LEGACY_GL) && !defined(SERVER) -MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData,Chunk chunk,int chunkWorldX,int chunkWorldY,uint8_t sideMask); +MeshData GenerateChunkMesh(World&world,ChunkRenderData chunkRenderData,Chunk chunk,int chunkWorldX,int chunkWorldY,uint8_t sideMask); MeshData MergeMeshData(const MeshData&a,const MeshData&b); MeshData CreateCubeMeshData(const BlockDef&def,float cx,float cy,float cz); Mesh GenChunkMesh(MeshData meshData); @@ -462,6 +479,9 @@ inline int GetIndexChunk2D(int x,int z){ inline bool CheckOOBWorld(int x,int y,int z){ return (x < 0 || y < 0 || z < 0 || x >= WORLD_SIZE_BLOCKS || y >= WORLD_HEIGHT || z >= WORLD_SIZE_BLOCKS); }; +inline bool CheckOOBWorldChunk(int x,int z){ + return (x < 0 || z < 0 || x >= MAX_WORLD_SIZE || z >= MAX_WORLD_SIZE); +}; inline int GetIndexWorld(int x,int z){ if(CheckOOBWorld(x << 4, 0, z << 4)) return 0; return x + MAX_WORLD_SIZE * z; diff --git a/src/helpers/inlines.hpp b/src/helpers/inlines.hpp index 67567cb..87a7a9c 100644 --- a/src/helpers/inlines.hpp +++ b/src/helpers/inlines.hpp @@ -39,6 +39,9 @@ inline int GetIndexChunk2D(int x, int z) { inline bool CheckOOBWorld(int x, int y, int z) { return (x < 0 || y < 0 || z < 0 || x >= WORLD_SIZE_BLOCKS || y >= WORLD_HEIGHT || z >= WORLD_SIZE_BLOCKS); } +inline bool CheckOOBWorldChunk(int x, int z) { + return (x < 0 || z < 0 || x >= MAX_WORLD_SIZE || z >= MAX_WORLD_SIZE); +} inline int GetIndexWorld(int x, int z) { if(CheckOOBWorld(x << 4, 0, z << 4)) return 0; return x + MAX_WORLD_SIZE * z; diff --git a/src/helpers/mesher.cpp b/src/helpers/mesher.cpp index d7002da..8a4e49f 100644 --- a/src/helpers/mesher.cpp +++ b/src/helpers/mesher.cpp @@ -10,7 +10,7 @@ #ifndef SERVER #ifndef LEGACY_GL -MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask) +MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask) { MeshData out = {0}; @@ -31,6 +31,10 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu uint8_t crdata = chunkRenderData.sides[index]; if (crdata == 0) continue; + int wx = (chunkWorldX * CHUNK_SIZE + x); + int wy = (y); + int wz = (chunkWorldY * CHUNK_SIZE + z); + int this_block = fetch_block(chunk, x,y,z); BlockDef definition = BLOCKS[this_block]; @@ -45,10 +49,7 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu bool shaded = chunk.highestBlock[GetIndexChunk2D(x, z)] != y; Color color = {255, 255, 255, 255}; Color colorShaded = {128, 128, 172, 255}; - - float wx = (float)(chunkWorldX * CHUNK_SIZE + x); - float wy = (float)(y); - float wz = (float)(chunkWorldY * CHUNK_SIZE + z); + /*if(GetCloud(wx, wz)) { color = ColorLerp(color, colorShaded, 0.5f); }*/ @@ -72,7 +73,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu positions.push_back(verts[3]); normals.push_back(normal); - colors.push_back(colorShaded); + Color clr = GetLight(world, wx-1, wy, wz); + colors.push_back(clr); uvs.push_back(corners[0]); uvs.push_back(corners[1]); @@ -111,7 +113,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu positions.push_back(verts[3]); normals.push_back(normal); - colors.push_back(colorShaded); + Color clr = GetLight(world, wx+1, wy, wz); + colors.push_back(clr); uvs.push_back(corners[0]); uvs.push_back(corners[1]); @@ -150,7 +153,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu positions.push_back(verts[3]); normals.push_back(normal); - colors.push_back(colorShaded); + Color clr = GetLight(world, wx, wy-1, wz); + colors.push_back(clr); uvs.push_back(corners[0]); uvs.push_back(corners[1]); @@ -189,12 +193,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu positions.push_back(verts[3]); normals.push_back(normal); - if(shaded) { - colors.push_back(colorShaded); - } - else { - colors.push_back(color); - } + Color clr = GetLight(world, wx, wy+1, wz); + colors.push_back(clr); uvs.push_back(corners[0]); uvs.push_back(corners[1]); @@ -233,7 +233,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu positions.push_back(verts[3]); normals.push_back(normal); - colors.push_back(colorShaded); + Color clr = GetLight(world, wx, wy, wz+1); + colors.push_back(clr); uvs.push_back(corners[0]); uvs.push_back(corners[1]); @@ -272,7 +273,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu positions.push_back(verts[3]); normals.push_back(normal); - colors.push_back(colorShaded); + Color clr = GetLight(world, wx, wy, wz-1); + colors.push_back(clr); uvs.push_back(corners[0]); uvs.push_back(corners[1]); diff --git a/src/helpers/particles.cpp b/src/helpers/particles.cpp index 045fbeb..fe9a358 100644 --- a/src/helpers/particles.cpp +++ b/src/helpers/particles.cpp @@ -66,10 +66,11 @@ static void DrawParticle(Particle particle, Color color) rlSetTexture(0); } void ParticlesUpdate(float dt, World &world) { - particles.remove_if([](Particle x) { return x.lifetime > 200; }); - for (Particle &part : particles) + //particles.remove_if([](Particle x) { return x.lifetime > 0; }); + particles.remove_if([](Particle x) { return true; }); + /*for (Particle &part : particles) { - part.lifetime++; + art.lifetime++;p if(part.physicsType == Phys_Falling) { Vector3 velocityTgt = Vector3Clamp(Vector3Add(part.velocity, {0, -dt * 9.8f, 0}), {-30.0f, -30.0f, 0-30.0f}, {30.0f, 30.0f, 30.0f}); @@ -99,7 +100,7 @@ void ParticlesUpdate(float dt, World &world) { part.position = final; part.velocity = velocityTgt; } - } + }*/ } void ParticlesDraw() { for (Particle part : particles) diff --git a/src/helpers/vars.hpp b/src/helpers/vars.hpp index 680687f..f3bd8e8 100644 --- a/src/helpers/vars.hpp +++ b/src/helpers/vars.hpp @@ -1,3 +1,4 @@ +#include #if INTERFACE #ifdef Escape @@ -101,7 +102,7 @@ #define TPS 30.0 #define TPS_DIV 1.0 / TPS //Rendering -#define RENDER_DISTANCE 128 +#define RENDER_DISTANCE 2 #define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE //Game stuff @@ -179,7 +180,7 @@ struct Chunk { uint16_t opaqueMask[CHUNK_DATA_SIZE/16]; uint16_t airMask[CHUNK_DATA_SIZE/16]; uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE]; - uint8_t lights[CHUNK_DATA_SIZE]; + uint16_t light[CHUNK_DATA_SIZE]; }; #ifndef SERVER struct ChunkRenderData { @@ -220,10 +221,20 @@ struct Quad2D { }; #endif struct Vector3I { - int x; - int y; - int z; + int x, y, z; + bool operator==(const Vector3I& other) const { + return (x == other.x && y == other.y && z == other.z); + }; }; +struct Vector3IHash { + size_t operator()(const Vector3I& p) const noexcept { + size_t h1 = std::hash{}(p.x); + size_t h2 = std::hash{}(p.y); + size_t h3 = std::hash{}(p.z); + return h1 ^ (h2 << 1) ^ (h3 << 2); + } +}; + struct Entity { uint8_t type; uint8_t id; diff --git a/src/rcraft.cpp b/src/rcraft.cpp index 4bdd083..a276631 100644 --- a/src/rcraft.cpp +++ b/src/rcraft.cpp @@ -263,7 +263,12 @@ static void ResolveCollisions(float dt) bool loadedChunks[MAX_WORLD_AREA] = { false }; bool dirtyChunks[MAX_WORLD_AREA] = { false }; - +const Vector3I dirs2d[4] = { + (Vector3I){ 1, 0, 0}, + (Vector3I){ 0, 0, 1}, + (Vector3I){-1, 0, 0}, + (Vector3I){ 0, 0, -1}, +}; void Debug_EndMeasure(const std::string &stuff); void Debug_EndMeasureLoops(const std::string &stuff, int loops); static void RemeshChunk(int x, int y) { @@ -274,9 +279,17 @@ static void RemeshChunk(int x, int y) { } Chunk &chunk = world.chunks[idx]; RebuildOpaqueMask(chunk); + /*for (int i = 0; i < 4; i++) + { + Vector3I dir = dirs2d[i]; + if(!CheckOOBWorldChunk(x+dir.x, y+dir.z)) { + RebuildLighting(world, world.chunks[GetIndexWorld(x+dir.x, y+dir.z)]); + } + }*/ - MeshData renderDataOpq = GenerateChunkMesh(GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF); - MeshData renderDataTsl = GenerateChunkMesh(GenerateCRDTranslucent(chunk, world), chunk, x, y, 0xFF); + RebuildLighting(world, chunk.x, chunk.z); + MeshData renderDataOpq = GenerateChunkMesh(world, GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF); + MeshData renderDataTsl = GenerateChunkMesh(world, GenerateCRDTranslucent(chunk, world), chunk, x, y, 0xFF); Model model = LoadModelFromMesh(GenChunkMesh(renderDataOpq)); model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;