transfered from codeberg

This commit is contained in:
2026-03-26 14:46:39 -05:00
parent 630f28bb7e
commit 5ed2173793
136 changed files with 14932 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
#include "light_table.h"
const float light_table[16] = {
0.05f, 0.06f, 0.08f, 0.12f, 0.17f, 0.22f, 0.30f, 0.40f,
0.50f, 0.60f, 0.72f, 0.82f, 0.90f, 0.95f, 0.98f, 1.0f
};

View File

@@ -0,0 +1,6 @@
#ifndef light_table_h
#define light_table_h
extern const float light_table[16];
#endif

View File

@@ -0,0 +1,94 @@
#include "private_sunlight.h"
#include "chunk.h"
#include "world.h"
#include "world_querier.h"
/**
* Processes the light queue to propagate light levels across the chunk.
* This function uses a breadth-first search to decay light intensity as it
* travels through air blocks, ensuring neighbors are updated to current - 1.
*/
void _propagate_light_level_flood_fill(struct chunk_struct* chunk,
_light_node_struct* light_queue,
uint16_t* head_index,
uint16_t* tail_index)
{
const int8_t adjacency_directions[6][3] = {
{ 1, 0, 0}, {-1, 0, 0},
{ 0, 1, 0}, { 0,-1, 0},
{ 0, 0, 1}, { 0, 0,-1}
};
while (*head_index < *tail_index && *tail_index < 8192)
{
_light_node_struct current_node = light_queue[(*head_index)++];
const uint32_t current_index = index_chunk(
current_node.x,
current_node.y,
current_node.z
);
uint8_t current_light_level = chunk->light_data[current_index];
/* Light below level 2 cannot propagate further. (decay to 0) */
if (current_light_level <= 1)
{
continue;
}
for (uint8_t i = 0; i < 6; i++)
{
int32_t neighbor_x = (int32_t)current_node.x +
adjacency_directions[i][0];
int32_t neighbor_y = (int32_t)current_node.y +
adjacency_directions[i][1];
int32_t neighbor_z = (int32_t)current_node.z +
adjacency_directions[i][2];
const bool is_inside_chunk =
(neighbor_x >= 0 && neighbor_x < chunk_size) &&
(neighbor_y >= 0 && neighbor_y < chunk_size) &&
(neighbor_z >= 0 && neighbor_z < chunk_size);
if (is_inside_chunk)
{
uint32_t neighbor_index = index_chunk(
(uint8_t)neighbor_x,
(uint8_t)neighbor_y,
(uint8_t)neighbor_z
);
/* Only propagate into air blocks
* that have a lower light level.
*/
if (chunk->block_data[neighbor_index] == 0 &&
chunk->light_data[neighbor_index] <
current_light_level - 1)
{
chunk->light_data[neighbor_index] =
current_light_level - 1;
if (*tail_index < 8192)
{
light_queue[(*tail_index)++] =
(_light_node_struct){
(uint8_t)neighbor_x,
(uint8_t)neighbor_y,
(uint8_t)neighbor_z
};
}
}
}
}
}
}
/**
* Evaluates a specific coordinate to determine if it should act as a starting point
* for light propagation. It checks for internal sunlight or light bleeding in
* from neighboring chunks.
*/

View File

@@ -0,0 +1,37 @@
#ifndef private_sunlight_h
#define private_sunlight_h
#include "stdint.h"
struct world_struct;
struct chunk_struct;
typedef struct _light_node_struct {
uint8_t x, y, z;
} _light_node_struct;
/**
* Evaluates a specific coordinate to determine if it should act as a starting point
* for light propagation. It checks for internal sunlight or light bleeding in
* from neighboring chunks.
*/
void _seed_light_source_at_coordinate(struct world_struct* world,
struct chunk_struct* chunk,
uint8_t local_x,
uint8_t local_y,
uint8_t local_z,
_light_node_struct* light_queue,
uint16_t* tail_index);
/**
* Processes the light queue to propagate light levels across the chunk.
* This function uses a breadth-first search to decay light intensity as it
* travels through air blocks, ensuring neighbors are updated to current - 1.
*/
void _propagate_light_level_flood_fill(struct chunk_struct* chunk,
_light_node_struct* light_queue,
uint16_t* head_index,
uint16_t* tail_index);
#endif

View File

@@ -0,0 +1,50 @@
#include "sunlight.h"
#include "_internal/private_sunlight.h"
#include "chunk.h"
#include "world.h"
#include "world_querier.h"
#include <stdint.h>
/**
* Calculates initial vertical illumination for a specific chunk.
* * This function performs a top-down scan of the chunk's columns. It
* determines where sunlight is obstructed by solid blocks and where it
* can pass through to the chunk below. This serves as the primary data
* source for the light propagation phase.
*/
void apply_sunlight(struct chunk_struct *neighbors[3][3][3], struct chunk_struct *chunk)
{
for (uint8_t local_x = 0; local_x < chunk_size; local_x++)
{
for (uint8_t local_z = 0; local_z < chunk_size; local_z++)
{
/* Check the light level at the bottom of the chunk
* above this one by looking at the neighbor array.
*/
uint8_t column_light = get_light_at_neighbor(neighbors,
chunk,
(int32_t)local_x,
(int32_t)chunk_size,
(int32_t)local_z);
for (int8_t local_y = (int8_t)chunk_size - 1; local_y >= 0; local_y--)
{
uint32_t block_index = index_chunk(local_x,
(uint8_t)local_y,
local_z);
/* If we hit any non-air block,
* the column below it enters shadow
*/
if (chunk->block_data[block_index] != 0)
{
column_light = 0;
}
chunk->light_data[block_index] = column_light;
}
}
}
}

View File

@@ -0,0 +1,25 @@
#ifndef sunlight_h
#define sunlight_h
struct world_struct;
struct chunk_struct;
/**
* Calculates initial vertical illumination for a specific chunk.
* * This function performs a top-down scan of the chunk's columns. It
* determines where sunlight is obstructed by solid blocks and where it
* can pass through to the chunk below. This serves as the primary data
* source for the light propagation phase.
*/
void apply_sunlight(struct chunk_struct *neighbors[3][3][3], struct chunk_struct *chunk);
/**
* Expands light levels from sources into adjacent empty spaces.
* * This function handles the "flood fill" or "diffusion" of light. It
* takes the initial values from sunlight and light-emitting blocks
* and spreads them horizontally and vertically, decreasing intensity
* with distance to create natural-looking gradients and shadows.
*/
void light_propagate(struct world_struct* world, struct chunk_struct* chunk);
#endif

View File

@@ -0,0 +1,132 @@
#include "test_sunlight.h"
#include "unity.h"
#include "chunk.h"
#include "sunlight.h"
#include "_internal/private_sunlight.h"
#include <string.h>
/* Verify that vertical sunlight is blocked by a solid ceiling, casting shadow */
void test_apply_sunlight_obstructed_by_solid_block(void)
{
chunk_position_struct initial_position = { 0.0f, 0.0f, 0.0f };
chunk_struct *test_chunk = initialize_chunk(initial_position);
/* Ensure the chunk arrays are completely cleared */
memset(test_chunk->block_data, 0, sizeof(test_chunk->block_data));
memset(test_chunk->light_data, 0, sizeof(test_chunk->light_data));
/* Place a single solid block at the top-middle of the chunk */
uint32_t block_index = index_chunk(8, 15, 8);
test_chunk->block_data[block_index] = 1;
/* Process the vertical sunlight pass.
* The guard you added will now prevent a crash when passing NULL.
*/
apply_sunlight(NULL, test_chunk);
/* The block at (8, 14, 8) is directly beneath the solid block.
* It must have a light level of zero.
*/
uint32_t shadowed_index = index_chunk(8, 14, 8);
TEST_ASSERT_EQUAL_UINT8_MESSAGE(0,
test_chunk->light_data[shadowed_index],
"The block directly beneath an obstruction must be in shadow");
/* The block at (0, 15, 0) has nothing above it.
* Depending on your get_light_at_neighbor logic, it should either
* be 0 (if NULL returns 0) or 15 (if NULL returns max light).
*/
destroy_chunk(test_chunk);
}
/* Verify that light intensity decreases by exactly one per meter of travel */
void test_light_propagation_decay_intensity_over_distance(void)
{
chunk_position_struct initial_position = { 0.0f, 0.0f, 0.0f };
chunk_struct *test_chunk = initialize_chunk(initial_position);
memset(test_chunk->block_data, 0, sizeof(test_chunk->block_data));
memset(test_chunk->light_data, 0, sizeof(test_chunk->light_data));
/* Manually set a high light intensity in the center of the chunk */
uint32_t source_index = index_chunk(8, 8, 8);
test_chunk->light_data[source_index] = 15;
/* Manually prepare the BFS queue for the internal flood fill function */
_light_node_struct light_queue[8192];
uint16_t head_index = 0;
uint16_t tail_index = 0;
light_queue[tail_index++] = (_light_node_struct){ 8, 8, 8 };
/* Execute the propagation logic directly to isolate the test */
_propagate_light_level_flood_fill(test_chunk,
light_queue,
&head_index,
&tail_index);
/* Check the light gradient along the X axis */
/* Distance 1: 15 - 1 = 14 */
TEST_ASSERT_EQUAL_UINT8(14, test_chunk->light_data[index_chunk(9, 8, 8)]);
/* Distance 2: 15 - 2 = 13 */
TEST_ASSERT_EQUAL_UINT8(13, test_chunk->light_data[index_chunk(10, 8, 8)]);
/* Distance 5: 15 - 5 = 10 */
TEST_ASSERT_EQUAL_UINT8(10, test_chunk->light_data[index_chunk(13, 8, 8)]);
destroy_chunk(test_chunk);
}
/* Verify that light cannot pass through a solid wall of blocks */
void test_light_propagation_is_blocked_by_solid_wall(void)
{
chunk_position_struct initial_position = { 0.0f, 0.0f, 0.0f };
chunk_struct *test_chunk = initialize_chunk(initial_position);
memset(test_chunk->block_data, 0, sizeof(test_chunk->block_data));
memset(test_chunk->light_data, 0, sizeof(test_chunk->light_data));
/* Create a solid 1-block thick wall at X = 5 */
for (uint8_t y = 0; y < chunk_size; y++)
{
for (uint8_t z = 0; z < chunk_size; z++)
{
test_chunk->block_data[index_chunk(5, y, z)] = 1;
}
}
/* Seed light at X = 4 (directly in front of the wall) */
uint32_t source_index = index_chunk(4, 8, 8);
test_chunk->light_data[source_index] = 10;
_light_node_struct light_queue[8192];
uint16_t head_index = 0;
uint16_t tail_index = 0;
light_queue[tail_index++] = (_light_node_struct){ 4, 8, 8 };
_propagate_light_level_flood_fill(test_chunk,
light_queue,
&head_index,
&tail_index);
/* Verify that light exists on the source side of the wall */
TEST_ASSERT_EQUAL_UINT8(9, test_chunk->light_data[index_chunk(4, 9, 8)]);
/* Verify that light did not penetrate the wall to reach X = 6 */
uint32_t destination_index = index_chunk(6, 8, 8);
TEST_ASSERT_EQUAL_UINT8_MESSAGE(0,
test_chunk->light_data[destination_index],
"Light should not pass through a solid wall of blocks");
destroy_chunk(test_chunk);
}
void run_sunlight_tests(void)
{
RUN_TEST(test_apply_sunlight_obstructed_by_solid_block);
RUN_TEST(test_light_propagation_decay_intensity_over_distance);
RUN_TEST(test_light_propagation_is_blocked_by_solid_wall);
}

View File

@@ -0,0 +1,13 @@
#ifndef test_sunglight_h
#define test_sunglight_h
void test_apply_sunlight_obstructed_by_solid_block(void);
void test_light_propagation_decay_intensity_over_distance(void);
void test_light_propagation_is_blocked_by_solid_wall(void);
void run_sunlight_tests(void);
#endif