From 7ab2d5a0837b7758d7c3de888331a516ea19df94 Mon Sep 17 00:00:00 2001 From: milkwx3 Date: Sat, 4 Jul 2026 01:48:50 +0300 Subject: [PATCH] Huge skylight optimizations. Also fixed the submodules. --- .gitmodules | 2 +- src/helpers/chunks.cpp | 85 +++++++++++++++++++++++++-------------- src/helpers/common.hpp | 3 +- src/helpers/entities.cpp | 2 +- src/helpers/inventory.cpp | 14 +++---- src/helpers/mesher.cpp | 9 ++--- src/rcraft.cpp | 18 ++++++--- 7 files changed, 81 insertions(+), 52 deletions(-) diff --git a/.gitmodules b/.gitmodules index a04f925..f4d558e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "src/libraries/enet"] path = src/libraries/enet - url = https://github.com/zpl-c/enet + url = https://github.com/lsalzman/enet [submodule "src/libraries/Lua"] path = src/libraries/Lua url = https://github.com/walterschell/Lua diff --git a/src/helpers/chunks.cpp b/src/helpers/chunks.cpp index 079f53d..65083a3 100644 --- a/src/helpers/chunks.cpp +++ b/src/helpers/chunks.cpp @@ -23,7 +23,7 @@ static const siv::PerlinNoise perlin; static int world_type = 0; -const BlockDef BLOCKS[] = { +std::vector BLOCKS = { BlockDef{ "air", R_Translucent, B_Stone, 0, 0, 0}, BlockDef{ "stone", R_Normal, B_Stone, 7, 0, 3}, BlockDef{ "grass", R_TriSide, B_Grass, 1, 0, 0, 1, 2}, @@ -40,8 +40,8 @@ const BlockDef BLOCKS[] = { BlockDef{ "spruce_planks", R_Normal, B_Wood, 3, 0, 13}, BlockDef{ "spruce_log", R_TriSide, B_Wood, 5, 0, 21, 20, 21}, BlockDef{ "workbench", R_TranslucentAllSides, B_Stone, 3, 0, 23, 22, 23}, - BlockDef{ "blue_block", R_Normal, B_Stone, 5, 0, 22}, - BlockDef{ "yellow_block", R_Normal, B_Stone, 5, 0, 23}, + BlockDef{ "undefined", R_Normal, B_Stone, 5, 0, 22}, + BlockDef{ "undefined", R_Normal, B_Stone, 5, 0, 23}, BlockDef{ "red_block", R_Normal, B_Stone, 5, 0, 24}, BlockDef{ "green_block", R_Normal, B_Stone, 5, 0, 25}, BlockDef{ "blue_block", R_Normal, B_Stone, 5, 0, 26}, @@ -53,9 +53,14 @@ const BlockDef BLOCKS[] = { BlockDef{ "coal_ore", R_Normal, B_Stone, 7, 0, 8}, BlockDef{ "unobtainium", R_Normal, B_Stone, 7, 999, 3}, // Bedrock? }; +BlockDef &GetBlockDefinition(int id) { + return BLOCKS[id]; +} +void LoadBlocks() { + +} int GetNumericIDFromString(std::string s) { - int count = sizeof(BLOCKS) / sizeof(BLOCKS[0]); - for (int i = 0; i < count; ++i) { + for (int i = 0; i < BLOCKS.size(); ++i) { if (BLOCKS[i].name == s) return i; } return -1; @@ -118,7 +123,7 @@ int GetHighestBlock(World &world, int x, int z) { 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; + if(CheckOOBWorld(x, y, z)) return 15; int locX = x % CHUNK_SIZE; int locZ = z % CHUNK_SIZE; int cx = x / CHUNK_SIZE; @@ -164,18 +169,14 @@ Color GetLight(World &world, int x, int y, int z) { 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; - Color sky = {skyLight, skyLight, skyLight, 255}; - Color r = {((light >> 8) & 0xF) * 16 + skyLight, 0, 0, 255}; - Color g = {0, ((light >> 4) & 0xF) * 16 + skyLight, 0, 255}; - Color b = {0, 0, ((light >> 0) & 0xF) * 16 + skyLight, 255}; - Color f = ColorTint(sky, r); - f = ColorTint(f, g); - f = ColorTint(f, b); + int skyLight = powf(((light >> 12) & 0xF) / 15.0f, 1) * 255; + Color r = {((light >> 8) & 0xF) * 16, 0, 0, 255}; + Color g = {0, ((light >> 4) & 0xF) * 16, 0, 255}; + Color b = {0, 0, ((light >> 0) & 0xF) * 16, 255}; return { - fmin((int)sky.r + (int)r.r, 255), - fmin((int)sky.g + (int)g.g, 255), - fmin((int)sky.b + (int)b.b, 255), + fmin((int)skyLight + (int)r.r, 255), + fmin((int)skyLight + (int)g.g, 255), + fmin((int)skyLight + (int)b.b, 255), 255 }; } @@ -310,12 +311,12 @@ void SetLight(World &world, int x, int y, int z, uint8_t sky, uint8_t r, uint8_t } void InitWorldgen(int worldType) { - const siv::PerlinNoise::seed_type seed = 123456u; + const siv::PerlinNoise::seed_type seed = 0u; const siv::PerlinNoise perlin{ seed }; constexpr size_t MAX = 128; // allowed range: 0..MAX-1 - for (int i = 0; i < sizeof(BLOCKS) / sizeof(BlockDef); i++) + for (int i = 0; i < BLOCKS.size(); i++) { - BlockDef def = BLOCKS[i]; + BlockDef def = GetBlockDefinition(i); if(def.render == R_Translucent || def.render == R_TranslucentAllSides || def.render == R_TranslucentTriSide) { marked.set(i); } @@ -619,28 +620,52 @@ void RebuildLighting(World &world, int startX, int startZ) { 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; + int highest = chunk.highestBlock[GetIndexChunk2D(x, z)]; + const int neighbors[4] = { + chunk.highestBlock[GetIndexChunk2D(x-1, z)], + chunk.highestBlock[GetIndexChunk2D(x+1, z)], + chunk.highestBlock[GetIndexChunk2D(x, z-1)], + chunk.highestBlock[GetIndexChunk2D(x, z+1)] + }; + int highestNeighbor = fmax(neighbors[0], fmax(neighbors[1], fmax(neighbors[2], neighbors[3]))); + + Vector3I pos = { x + chunk.x * CHUNK_SIZE, highest + 1, z + chunk.z * CHUNK_SIZE }; - for (int _y = WORLD_HEIGHT; _y >= y; _y--) + for (int y = highest + 1; y <= WORLD_HEIGHT; ++y) { - SetLight(world, pos.x, _y, pos.z, 15, 0, 0, 0); + SetLightChunk(&chunk, x, y, z, 15, 0, 0, 0); } - LightNode node{pos, 15}; - nodes.push(node); + if (highest == highestNeighbor) continue; + + + for (int y = highest+1; y < highestNeighbor+1; y++) + { + if ( + GetSkyLight(world, pos.x-1, y, pos.z) < 15 && !TestOpaqueMaskWorld(world, pos.x-1, y, pos.z) + ) nodes.push({(Vector3I){pos.x-1, y, pos.z}, 15}); + if ( + GetSkyLight(world, pos.x+1, y, pos.z) < 15 && !TestOpaqueMaskWorld(world, pos.x+1, y, pos.z) + ) nodes.push({(Vector3I){pos.x+1, y, pos.z}, 15}); + if ( + GetSkyLight(world, pos.x, y, pos.z-1) < 15 && !TestOpaqueMaskWorld(world, pos.x, y, pos.z-1) + ) nodes.push({(Vector3I){pos.x, y, pos.z-1}, 15}); + if ( + GetSkyLight(world, pos.x, y, pos.z+1) < 15 && !TestOpaqueMaskWorld(world, pos.x, y, pos.z+1) + ) nodes.push({(Vector3I){pos.x, y, pos.z+1}, 15}); + } } } } } - + std::cout << nodes.size() << std::endl; while (!nodes.empty()) { LightNode node = nodes.front(); nodes.pop(); for (int i = 0; i < 6; i++) { + int newValue = node.value - 1; + if (newValue <= 0) continue; Vector3I newPos = { node.position.x + dirs[i].x, node.position.y + dirs[i].y, @@ -649,8 +674,6 @@ void RebuildLighting(World &world, int startX, int startZ) { if (CheckOOBWorld(newPos.x, newPos.y, newPos.z)) continue; if (TestOpaqueMaskWorld(world, newPos.x, newPos.y, newPos.z)) continue; - int newValue = node.value - 1; - if (newValue <= 0) continue; if (GetSkyLight(world, newPos.x, newPos.y, newPos.z) >= newValue) continue; diff --git a/src/helpers/common.hpp b/src/helpers/common.hpp index 41aa1fa..1e7f66a 100644 --- a/src/helpers/common.hpp +++ b/src/helpers/common.hpp @@ -303,7 +303,8 @@ typedef struct World World; struct World { Chunk chunks[MAX_WORLD_AREA]; }; -extern const BlockDef BLOCKS[]; +BlockDef&GetBlockDefinition(int id); +void LoadBlocks(); 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); diff --git a/src/helpers/entities.cpp b/src/helpers/entities.cpp index 2f44e12..74fe434 100644 --- a/src/helpers/entities.cpp +++ b/src/helpers/entities.cpp @@ -363,7 +363,7 @@ void DrawEntities(float dt) { DrawCube(pos_lerped, 1, 1, 1, RED); } if(ent.type == 4) { - DrawCubeBlock(terrain, pos_lerped, 1,1,1, BLOCKS[ent.data[1]]); + DrawCubeBlock(terrain, pos_lerped, 1,1,1, GetBlockDefinition(ent.data[1])); } } } diff --git a/src/helpers/inventory.cpp b/src/helpers/inventory.cpp index ec2ea33..30a5525 100644 --- a/src/helpers/inventory.cpp +++ b/src/helpers/inventory.cpp @@ -40,7 +40,7 @@ void DrawItem(InventoryItem item, int x, int y) { if(item.item->type == IType_Block) { atlas = terrain; atl_size = ATLAS_SIZE_W; - tex = BLOCKS[item.damage].textureTop; + tex = GetBlockDefinition(item.damage).textureTop; } DrawTexturePro(atlas, { @@ -198,9 +198,9 @@ static bool GetTaggedItem(std::string tag, InventoryItem* item) { bool isBlock; bool found; for(int blk = 0; blk < MAX_BLOCK_ID; blk++) { - if(IDTagMatch(tag, BLOCKS[blk].name)) { + if(IDTagMatch(tag, GetBlockDefinition(blk).name)) { isBlock = true; - id = GetNumericIDFromString(BLOCKS[blk].name); + id = GetNumericIDFromString(GetBlockDefinition(blk).name); found = true; break; }; @@ -307,7 +307,7 @@ void DrawHotbar() { if(item.item != nullptr) { bool blockCond = item.item->type == IType_Block && ingredient.type == IType_Block && item.damage == GetNumericIDFromString(ingredient.id); bool genericCond = item.item->type != IType_Block && ingredient.type == IType_Generic && item.item->id == ingredient.id; - bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, BLOCKS[item.damage].name); + bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, GetBlockDefinition(item.damage).name); bool tagItemCond = item.item->type != IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, item.item->id); if(blockCond || genericCond || tagBlockCond || tagItemCond) { items.push_back(i); @@ -366,7 +366,7 @@ void DrawHotbar() { if(item.item != nullptr) { bool blockCond = item.item->type == IType_Block && ingredient.type == IType_Block && item.damage == GetNumericIDFromString(ingredient.id); bool genericCond = item.item->type != IType_Block && ingredient.type == IType_Generic && item.item->id == ingredient.id; - bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, BLOCKS[item.damage].name); + bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, GetBlockDefinition(item.damage).name); bool tagItemCond = item.item->type != IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, item.item->id); if(blockCond || genericCond || tagBlockCond || tagItemCond) { items[i] = ingredient.quantity; @@ -432,7 +432,7 @@ void DrawHotbar() { DrawItem(*movingItem, GetMouseX(), GetMouseY()); std::string name = "item."+movingItem->item->id; if(movingItem->item->type == IType_Block) { - name = "item."+BLOCKS[movingItem->damage].name; + name = "item."+GetBlockDefinition(movingItem->damage).name; } DrawTextB(LocaleGet(name).c_str(), GetMouseX()-16, GetMouseY()+56, 16, WHITE); } @@ -461,7 +461,7 @@ void DrawSelectedItem() { DrawCubeTexture(playerTex, {0, -12*PIXUNIT/2, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4); if(item.item != nullptr) { if(item.item->type == IType_Block) { - DrawCubeBlock(terrain, {0, -12*PIXUNIT - 0.25f, 0}, 0.5f, 0.5f, 0.5f, BLOCKS[item.damage]); + DrawCubeBlock(terrain, {0, -12*PIXUNIT - 0.25f, 0}, 0.5f, 0.5f, 0.5f, GetBlockDefinition(item.damage)); } else { UVCorners left = GetUVTex(item.item->texture); diff --git a/src/helpers/mesher.cpp b/src/helpers/mesher.cpp index 8a4e49f..b4a163c 100644 --- a/src/helpers/mesher.cpp +++ b/src/helpers/mesher.cpp @@ -23,21 +23,20 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk std::vector indices; int face = 0; - for (int x = 0; x < CHUNK_SIZE; ++x) - for (int y = 0; y < WORLD_HEIGHT; ++y) - for (int z = 0; z < CHUNK_SIZE; ++z) + for (int index = 0; index < CHUNK_DATA_SIZE; index++) { - int index = GetIndexChunk(x,y,z); uint8_t crdata = chunkRenderData.sides[index]; if (crdata == 0) continue; + int x, y, z; + GetXYZFromIndex(index, &x, &y, &z); 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]; + BlockDef definition = GetBlockDefinition(this_block); UVCorners UVside = GetUVTex(definition.textureSide); UVCorners UVtop = GetUVTex(definition.textureTop); diff --git a/src/rcraft.cpp b/src/rcraft.cpp index a276631..b6d736d 100644 --- a/src/rcraft.cpp +++ b/src/rcraft.cpp @@ -409,11 +409,11 @@ void SetBlockNetwork(World &world, int bx, int by, int bz, int t) { tickedBlocks.push({bx, by, bz-1}); tickedBlocks.push({bx, by, bz+1}); if(t != 0) { - sound = BLOCKS[t].type; + sound = GetBlockDefinition(t).type; } else { int id = GetBlock(world, bx, by, bz); - BlockDef block = BLOCKS[id]; + BlockDef block = GetBlockDefinition(id); if(id != 0) { sound = block.type; for (int x = 0; x < 4; x++) @@ -730,7 +730,7 @@ static void GameUpdate(Camera camera, float &time) { tier = selected_item->tier; } } - BlockDef block = BLOCKS[GetBlock(world, bx, by, bz)]; + BlockDef block = GetBlockDefinition(GetBlock(world, bx, by, bz)); float hardnessMultiplier = block.hardness / 4.0f; if(player_break_parts_time >= 0.05f) { Vector3 v = {0, 1, 0}; @@ -1053,7 +1053,7 @@ static void GameUpdate(Camera camera, float &time) { oxygen += dt * 20.0f; oxygen = Clamp(oxygen, 0, MAX_HP); } - if(!hide_ui && !taking_panorama) { + if(!hide_ui && !taking_panorama) { // DEBUG MENU!!!! char text[128]; sprintf(text, "%s %s", GAME_NAME, GAME_VERSION); DrawTextB(text, 20, 20, DEFAULT_FONT_SIZE, WHITE); @@ -1068,8 +1068,14 @@ static void GameUpdate(Camera camera, float &time) { float virtualmem = m.virtualSize / 1024.0f / 1024.0f; sprintf(text, "Mem %.2fMiB/%.2fMiB", residentmem, virtualmem); DrawTextB(text, 20, 80, DEFAULT_FONT_SIZE, WHITE); - sprintf(text, "Drawing %d verts", debug_verts_opaque+debug_verts_transparent); - DrawTextB(text, 120, 40, DEFAULT_FONT_SIZE, WHITE); + Vector3I ppos = {floorf(player_position.x), floorf(player_position.y), floorf(player_position.z)}; + sprintf(text, "skylight %d | blocklight: r %d g %d b %d", + GetSkyLight(world, ppos.x, ppos.y, ppos.z), + GetRLight(world, ppos.x, ppos.y, ppos.z), + GetGLight(world, ppos.x, ppos.y, ppos.z), + GetBLight(world, ppos.x, ppos.y, ppos.z) + ); + DrawTextB(text, 20, 100, DEFAULT_FONT_SIZE, WHITE); DrawRectangle(GetScreenWidth()/2-3, GetScreenHeight()/2-3, 6, 6, BLACK); DrawRectangle(GetScreenWidth()/2-2, GetScreenHeight()/2-2, 4, 4, WHITE);