Added handle system and improve resource management.

This commit is contained in:
2025-12-31 23:50:22 +09:00
parent 5c988108ef
commit acaaa2a86e
33 changed files with 998 additions and 915 deletions

View File

@@ -1,15 +1,15 @@
#include "Rendering/Debug.h"
#include "Algorithm/RayIntersection.h"
static void ray_intersect_bvh_count(ray_t ray, bvh_tree_t bvh_tree, uint64_t node_index, uint32_t* count_out)
static void ray_intersect_tlas_count(ray_t ray, const tlas_tree_t* tlas_tree, uint32_t node_index, uint32_t* count_out)
{
const float _MAX_DIST = 1e6f;
if (bvh_tree.nodes == NULL || bvh_tree.primitive_indices == NULL || count_out == NULL)
if (tlas_tree->nodes == NULL || tlas_tree->primitive_indices == NULL || count_out == NULL)
{
return;
}
const bvh_node_t* node = &bvh_tree.nodes[node_index];
const bvh_node_t* node = &tlas_tree->nodes[node_index];
float enter, exit;
if (!ray_intersect_aabb(&ray, node->bounds, &enter, &exit))
@@ -26,8 +26,8 @@ static void ray_intersect_bvh_count(ray_t ray, bvh_tree_t bvh_tree, uint64_t nod
if (node->primitive_count == 0)
{
// Internal node
ray_intersect_bvh_count(ray, bvh_tree, node->left_child_offset, count_out);
ray_intersect_bvh_count(ray, bvh_tree, node->right_child_offset, count_out);
ray_intersect_tlas_count(ray, tlas_tree, node->left_child_offset, count_out);
ray_intersect_tlas_count(ray, tlas_tree, node->right_child_offset, count_out);
}
}
@@ -42,7 +42,7 @@ vec4s render_debug(scene_t* scene, ray_t ray, uint16_t sample_index, int flag)
{
case DEBUG_BVH:
uint32_t count = 0;
ray_intersect_bvh_count(ray, scene->bvh_tree, 0, &count);
ray_intersect_tlas_count(ray, &scene->tlas, 0, &count);
vec4s result = glms_vec4_zero();
for (uint32_t i = 0; i < count; i++)

View File

@@ -20,7 +20,7 @@ static inline void create_target_if_required(aov_flags_t aov_flags, aov_flags_t
*render_target = temp;
}
bool renderer_aov_target_init(render_job_t* job, aov_flags_t aov_flags)
bool renderer_aov_target_init(render_job_t* job)
{
job->aov_target = (render_target_t**)malloc(sizeof(render_target_t*) * MAX_AOV_TARGET);
if (job->aov_target == NULL)
@@ -28,14 +28,14 @@ bool renderer_aov_target_init(render_job_t* job, aov_flags_t aov_flags)
return false;
}
create_target_if_required(aov_flags, AOV_BEAUTY, &job->aov_target[AOV_BEAUTY_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_AlBEDO, &job->aov_target[AOV_AlBEDO_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_NORMAL, &job->aov_target[AOV_NORMAL_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_DEPTH, &job->aov_target[AOV_DEPTH_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_POSITION, &job->aov_target[AOV_POSITION_INDEX], job->config->width, job->config->height);
create_target_if_required(job->config.aov_flags, AOV_BEAUTY, &job->aov_target[AOV_BEAUTY_INDEX], job->config.width, job->config.height);
create_target_if_required(job->config.aov_flags, AOV_AlBEDO, &job->aov_target[AOV_AlBEDO_INDEX], job->config.width, job->config.height);
create_target_if_required(job->config.aov_flags, AOV_NORMAL, &job->aov_target[AOV_NORMAL_INDEX], job->config.width, job->config.height);
create_target_if_required(job->config.aov_flags, AOV_DEPTH, &job->aov_target[AOV_DEPTH_INDEX], job->config.width, job->config.height);
create_target_if_required(job->config.aov_flags, AOV_POSITION, &job->aov_target[AOV_POSITION_INDEX], job->config.width, job->config.height);
create_target_if_required(aov_flags, AOV_DIRECT, &job->aov_target[AOV_DIRECT_INDEX], job->config->width, job->config->height);
create_target_if_required(aov_flags, AOV_INDIRECT, &job->aov_target[AOV_INDIRECT_INDEX], job->config->width, job->config->height);
create_target_if_required(job->config.aov_flags, AOV_DIRECT, &job->aov_target[AOV_DIRECT_INDEX], job->config.width, job->config.height);
create_target_if_required(job->config.aov_flags, AOV_INDIRECT, &job->aov_target[AOV_INDIRECT_INDEX], job->config.width, job->config.height);
return true;
}
@@ -67,17 +67,34 @@ static inline bool aov_needs_lighting_samples(aov_flags_t flags)
return has_flag(flags, AOV_BEAUTY) || has_flag(flags, AOV_DIRECT) || has_flag(flags, AOV_INDIRECT);
}
static inline uint32_t get_minimal_sample_count(render_job_t* job)
{
if (aov_needs_lighting_samples(job->config.aov_flags))
{
if (job->config.aov_flags == AOV_DIRECT)
{
return 1;
}
return job->config.sample_count;
}
else
{
return 1;
}
}
static inline vec4s running_average_vec4(vec4s prev_avg, vec4s sample, uint32_t prev_count)
{
float n = (float)prev_count;
float inv = 1.0f / (n + 1.0f);
vec4s out;
out.x = (prev_avg.x * n + sample.x) * inv;
out.y = (prev_avg.y * n + sample.y) * inv;
out.z = (prev_avg.z * n + sample.z) * inv;
out.w = 1.0f;
return out;
return (vec4s){
.x = (prev_avg.x * n + sample.x) * inv,
.y = (prev_avg.y * n + sample.y) * inv,
.z = (prev_avg.z * n + sample.z) * inv,
.w = 1.0f
};
}
static inline void clear_render_target(render_target_t* target)
@@ -108,7 +125,13 @@ static inline void clear_aov_targets(render_job_t* job)
}
}
static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s coord, uint32_t x, uint32_t y, aov_flags_t aov_flags, aov_output_t* pixel_output)
static void render_pixel(const rendering_config_t* config,
const scene_t* scene,
vec3s coord,
uint32_t x,
uint32_t y,
aov_flags_t aov_flags,
aov_output_t* pixel_output)
{
aov_output_t accumulated_color = {0};
@@ -155,12 +178,11 @@ static void render_pixel(const rendering_config_t* config, scene_t* scene, vec3s
}
static void render_pixel_one_sample(const rendering_config_t* config,
scene_t* scene,
const scene_t* scene,
vec3s coord,
uint32_t x,
uint32_t y,
uint32_t sample_index,
aov_flags_t aov_flags,
aov_output_t* pixel_output)
{
uint32_t pixel_id = y * config->width + x;
@@ -192,7 +214,7 @@ static void render_pixel_one_sample(const rendering_config_t* config,
spread_angle);
aov_output_t out = {0};
path_trace_aov(scene, ray, sobol_idx, config->max_depth, aov_flags, &out);
path_trace_aov(scene, ray, sobol_idx, config->max_depth, config->aov_flags, &out);
*pixel_output = out;
}
@@ -220,23 +242,24 @@ static inline void update_aov(render_target_t** target, const aov_output_t* aov,
void renderer_start(render_job_t* job)
{
ensure_camera_aspect_ratio(&job->scene->camera, job->config);
ensure_camera_aspect_ratio(&job->scene->camera, &job->config);
job->config.sample_count = get_minimal_sample_count(job);
// Reset progressive state whenever we (re)start.
job->progressive_sample_index = 0;
vec3s coord = glms_vec3_add(job->scene->camera.position, glms_vec3_scale(quat_get_forward(job->scene->camera.rotation), job->scene->camera.focal_length));
if (job->rendering_mode == RENDER_PROGRESSIVE)
if (job->config.rendering_mode == RENDER_PROGRESSIVE)
{
// Progressive mode: accumulate 1 spp per pass until sample_count or stop requested.
clear_aov_targets(job);
job->is_done = false;
uint32_t width = job->config->width;
uint32_t height = job->config->height;
uint32_t width = job->config.width;
uint32_t height = job->config.height;
for (uint32_t s = 0; s < job->config->sample_count; ++s)
for (uint32_t s = 0; s < job->config.sample_count; ++s)
{
if (job->is_done)
{
@@ -257,10 +280,10 @@ void renderer_start(render_job_t* job)
}
aov_output_t pixel = {0};
render_pixel_one_sample(job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, s, job->aov_flags, &pixel);
render_pixel_one_sample(&job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, s, &pixel);
// Accumulate lighting AOVs; write non-stochastic AOVs once.
if (has_flag(job->aov_flags, AOV_BEAUTY))
if (has_flag(job->config.aov_flags, AOV_BEAUTY))
{
vec4s prev = render_target_get_pixel(job->aov_target[AOV_BEAUTY_INDEX], (uint32_t)x, (uint32_t)y);
vec4s avg = running_average_vec4(prev, pixel.beauty, s);
@@ -275,14 +298,14 @@ void renderer_start(render_job_t* job)
update_aov_pixel_if_exist(&job->aov_target[AOV_POSITION_INDEX], pixel.position, (uint32_t)x, (uint32_t)y);
}
if (has_flag(job->aov_flags, AOV_DIRECT))
if (has_flag(job->config.aov_flags, AOV_DIRECT))
{
vec4s prev = render_target_get_pixel(job->aov_target[AOV_DIRECT_INDEX], (uint32_t)x, (uint32_t)y);
vec4s avg = running_average_vec4(prev, pixel.direct, s);
render_target_set_pixel(job->aov_target[AOV_DIRECT_INDEX], (uint32_t)x, (uint32_t)y, avg);
}
if (has_flag(job->aov_flags, AOV_INDIRECT))
if (has_flag(job->config.aov_flags, AOV_INDIRECT))
{
vec4s prev = render_target_get_pixel(job->aov_target[AOV_INDIRECT_INDEX], (uint32_t)x, (uint32_t)y);
vec4s avg = running_average_vec4(prev, pixel.indirect, s);
@@ -299,20 +322,20 @@ void renderer_start(render_job_t* job)
}
else
{
uint32_t tile_count_x = (job->config->width + job->config->bucket_size - 1) / job->config->bucket_size;
uint32_t tile_count_y = (job->config->height + job->config->bucket_size - 1) / job->config->bucket_size;
uint32_t tile_count_x = (job->config.width + job->config.bucket_size - 1) / job->config.bucket_size;
uint32_t tile_count_y = (job->config.height + job->config.bucket_size - 1) / job->config.bucket_size;
uint32_t tile_count = tile_count_x * tile_count_y;
int64_t x, y, tile_index; // OpenMP requires these to be declared outside the parallel region.
#pragma omp parallel for schedule(dynamic, 1) default(none) \
shared(tile_count_x, tile_count_y, tile_count, coord, job) \
private(x, y, tile_index)
#pragma omp parallel for schedule(dynamic, 1) default(none) \
shared(tile_count_x, tile_count_y, tile_count, coord, job) \
private(x, y, tile_index)
for (tile_index = 0; tile_index < tile_count; tile_index++)
{
uint32_t tile_x_0 = (uint32_t)tile_index % tile_count_x * job->config->bucket_size;
uint32_t tile_y_0 = (uint32_t)tile_index / tile_count_x * job->config->bucket_size;
uint32_t tile_x_1 = (uint32_t)fmin(tile_x_0 + job->config->bucket_size, job->config->width);
uint32_t tile_y_1 = (uint32_t)fmin(tile_y_0 + job->config->bucket_size, job->config->height);
uint32_t tile_x_0 = (uint32_t)tile_index % tile_count_x * job->config.bucket_size;
uint32_t tile_y_0 = (uint32_t)tile_index / tile_count_x * job->config.bucket_size;
uint32_t tile_x_1 = (uint32_t)fmin(tile_x_0 + job->config.bucket_size, job->config.width);
uint32_t tile_y_1 = (uint32_t)fmin(tile_y_0 + job->config.bucket_size, job->config.height);
for (y = tile_y_0; y < tile_y_1; y++)
{
@@ -324,7 +347,7 @@ void renderer_start(render_job_t* job)
}
aov_output_t pixel_output = {0};
render_pixel(job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, job->aov_flags, &pixel_output);
render_pixel(&job->config, job->scene, coord, (uint32_t)x, (uint32_t)y, job->config.aov_flags, &pixel_output);
update_aov(job->aov_target, &pixel_output, (uint32_t)x, (uint32_t)y);
}
}

View File

@@ -3,56 +3,6 @@
#include <stdlib.h>
#include <string.h>
static inline void mesh_model_collection_init(mesh_model_collection_t* models, uint32_t capacity)
{
models->count = capacity;
models->capacity = capacity;
models->buffer = (mesh_model_t*)calloc(capacity, sizeof(mesh_model_t));
}
static inline void mesh_instance_collection_init(mesh_instance_collection_t* instances, uint32_t capacity)
{
instances->count = capacity;
instances->capacity = capacity;
instances->buffer = (mesh_instance_t*)calloc(capacity, sizeof(mesh_instance_t));
}
static inline void mesh_model_collection_free(mesh_model_collection_t* models)
{
if (models == NULL || models->buffer == NULL)
{
return;
}
for (uint32_t i = 0; i < models->capacity; ++i)
{
mesh_model_t* m = &models->buffer[i];
if (m->active)
{
bvh_tree_free(&m->blas);
triangle_collection_free(&m->triangles);
}
}
free(models->buffer);
models->buffer = NULL;
models->count = 0;
models->capacity = 0;
}
static inline void mesh_instance_collection_free(mesh_instance_collection_t* instances)
{
if (instances == NULL)
{
return;
}
free(instances->buffer);
instances->buffer = NULL;
instances->count = 0;
instances->capacity = 0;
}
static inline vec3s mat4_mul_point(mat4s m, vec3s p)
{
return glms_mat4_mulv3(m, p, 1.0f);
@@ -101,7 +51,7 @@ static bool scene_rebuild_tlas(scene_t* scene)
uint64_t active_count = 0;
for (uint32_t i = 0; i < scene->mesh_instances.capacity; ++i)
{
if (scene->mesh_instances.buffer[i].active)
if (scene->mesh_instances.occupied[i])
{
active_count++;
}
@@ -123,7 +73,7 @@ static bool scene_rebuild_tlas(scene_t* scene)
uint64_t cursor = 0;
for (uint32_t i = 0; i < scene->mesh_instances.capacity; ++i)
{
if (scene->mesh_instances.buffer[i].active)
if (scene->mesh_instances.occupied[i])
{
indices[cursor++] = i;
}
@@ -165,26 +115,21 @@ static bool scene_rebuild_tlas(scene_t* scene)
return true;
}
bool scene_init(scene_t* scene, uint64_t triangle_count, uint16_t texture_count, uint8_t material_count, uint32_t punctual_light_count)
bool scene_init(scene_t* scene, uint32_t triangle_count, uint32_t texture_count, uint32_t material_count, uint32_t punctual_light_count)
{
scene_t temp = {0};
if (!triangle_collection_init(triangle_count, &temp.triangles))
{
goto triangle_failed;
}
if (!texture_collection_init(texture_count, &temp.textures))
if (texture_slot_map_init(&temp.textures, texture_count) != RESULT_SUCCESS)
{
goto texture_failed;
}
if (!material_collection_init(material_count, &temp.materials))
if (material_slot_map_init(&temp.materials, material_count) != RESULT_SUCCESS)
{
goto material_failed;
}
if (!light_collection_create(punctual_light_count, 16, &temp.lights)) // NOTE: We just fixed the max directional light count to 16.
if (light_collection_create( &temp.lights, punctual_light_count, 16) != RESULT_SUCCESS) // NOTE: We just fixed the max directional light count to 16.
{
goto light_failed;
}
@@ -199,20 +144,20 @@ bool scene_init(scene_t* scene, uint64_t triangle_count, uint16_t texture_count,
// New mesh system: start with small default capacities (simple first).
(void)triangle_count;
mesh_model_collection_init(&temp.mesh_models, 64);
mesh_instance_collection_init(&temp.mesh_instances, 128);
mesh_model_slot_map_init(&temp.mesh_models, 64);
memset(temp.mesh_models.buffer, 0, sizeof(mesh_model_t) * temp.mesh_models.capacity);
mesh_instance_slot_map_init(&temp.mesh_instances, 128);
temp.tlas_dirty = true;
*scene = temp;
return true;
light_failed:
material_collection_free(&temp.materials);
material_slot_map_free(&temp.materials);
material_failed:
texture_collection_free(&temp.textures);
texture_slot_map_free(&temp.textures);
texture_failed:
triangle_collection_free(&temp.triangles);
triangle_failed:
return false;
}
@@ -223,7 +168,6 @@ bool scene_build_bvh(scene_t* scene)
return false;
}
// Prefer TLAS if any mesh instances exist.
if (scene->tlas_dirty)
{
if (!scene_rebuild_tlas(scene))
@@ -232,21 +176,6 @@ bool scene_build_bvh(scene_t* scene)
}
}
// Legacy BVH build if triangles are present.
if (scene->triangles.count > 0)
{
bvh_tree_free(&scene->bvh_tree);
bvh_tree_t bvh_tree = {0};
if (!bvh_tree_init(&bvh_tree, &scene->triangles))
{
return false;
}
bvh_tree_build(&bvh_tree);
scene->bvh_tree = bvh_tree;
}
return true;
}
@@ -257,148 +186,138 @@ void scene_free(scene_t* scene)
return;
}
bvh_tree_free(&scene->bvh_tree);
triangle_collection_free(&scene->triangles);
// Mesh system
tlas_tree_free(&scene->tlas);
free((void*)scene->tlas.instance_bounds);
scene->tlas.instance_bounds = NULL;
mesh_instance_collection_free(&scene->mesh_instances);
mesh_model_collection_free(&scene->mesh_models);
texture_collection_free(&scene->textures);
material_collection_free(&scene->materials);
for (size_t i = 0; i < scene->mesh_models.capacity; ++i)
{
if (scene->mesh_instances.occupied[i])
{
mesh_model_t* m = &scene->mesh_models.buffer[i];
bvh_tree_free(&m->blas);
triangle_list_free(&m->triangles);
}
}
for (uint32_t i = 0; i < scene->textures.capacity; i++)
{
if (scene->textures.occupied[i] != 0)
{
texture_asset_t* asset = &scene->textures.buffer[i];
texture_free(&asset->texture);
if (asset->full_name != NULL)
{
free(asset->full_name);
asset->full_name = NULL;
}
}
}
for (uint32_t i = 0; i < scene->materials.capacity; i++)
{
if (scene->materials.occupied[i] != 0)
{
material_t* material = &scene->materials.buffer[i];
material_free(material);
}
}
mesh_instance_slot_map_free(&scene->mesh_instances);
mesh_model_slot_map_free(&scene->mesh_models);
texture_slot_map_free(&scene->textures);
material_slot_map_free(&scene->materials);
light_collection_free(&scene->lights);
}
static uint32_t find_free_mesh_model_slot(scene_t* scene)
{
for (uint32_t i = 0; i < scene->mesh_models.capacity; ++i)
{
if (!scene->mesh_models.buffer[i].active)
{
return i;
}
}
uint32_t old_capacity = scene->mesh_models.capacity;
uint32_t new_capacity = old_capacity == 0 ? 64 : old_capacity * 2;
mesh_model_t* resized = (mesh_model_t*)realloc(scene->mesh_models.buffer, sizeof(mesh_model_t) * new_capacity);
if (resized == NULL)
{
return UINT32_MAX;
}
memset(resized + old_capacity, 0, sizeof(mesh_model_t) * (new_capacity - old_capacity));
scene->mesh_models.buffer = resized;
scene->mesh_models.capacity = new_capacity;
scene->mesh_models.count = new_capacity;
return old_capacity;
}
static uint32_t find_free_mesh_instance_slot(scene_t* scene)
{
for (uint32_t i = 0; i < scene->mesh_instances.capacity; ++i)
{
if (!scene->mesh_instances.buffer[i].active)
{
return i;
}
}
uint32_t old_capacity = scene->mesh_instances.capacity;
uint32_t new_capacity = old_capacity == 0 ? 128 : old_capacity * 2;
mesh_instance_t* resized = (mesh_instance_t*)realloc(scene->mesh_instances.buffer, sizeof(mesh_instance_t) * new_capacity);
if (resized == NULL)
{
return UINT32_MAX;
}
memset(resized + old_capacity, 0, sizeof(mesh_instance_t) * (new_capacity - old_capacity));
scene->mesh_instances.buffer = resized;
scene->mesh_instances.capacity = new_capacity;
scene->mesh_instances.count = new_capacity;
return old_capacity;
}
uint32_t scene_add_mesh_model(scene_t* scene, uint64_t triangle_reserve)
mesh_model_handle_t scene_add_mesh_model(scene_t* scene, uint64_t triangle_reserve)
{
if (scene == NULL)
{
return UINT32_MAX;
return INVALID_HANDLE(mesh_model_handle_t);
}
uint32_t slot = find_free_mesh_model_slot(scene);
if (slot == UINT32_MAX)
mesh_model_t model =
{
return UINT32_MAX;
}
.local_bounds = invalid_aabb()
};
mesh_model_t* model = &scene->mesh_models.buffer[slot];
*model = (mesh_model_t){0};
model->active = true;
model->local_bounds = invalid_aabb();
if (!triangle_collection_init((size_t)(triangle_reserve > 0 ? triangle_reserve : 1), &model->triangles))
if (triangle_list_init(&model.triangles, triangle_reserve) != RESULT_SUCCESS)
{
model->active = false;
return UINT32_MAX;
return INVALID_HANDLE(mesh_model_handle_t);
}
return slot;
mesh_model_handle_t handle;
if (mesh_model_slot_map_add(&scene->mesh_models, model, &handle.id, &handle.generation) != RESULT_SUCCESS)
{
return INVALID_HANDLE(mesh_model_handle_t);
}
return handle;
}
uint32_t scene_add_mesh_instance(scene_t* scene, uint32_t model_id, mat4s local_to_world)
mesh_instance_handle_t scene_add_mesh_instance(scene_t* scene, mesh_model_handle_t model, mat4s local_to_world)
{
if (scene == NULL || model_id >= scene->mesh_models.capacity || !scene->mesh_models.buffer[model_id].active)
if (scene == NULL)
{
return UINT32_MAX;
return INVALID_HANDLE(mesh_instance_handle_t);
}
uint32_t slot = find_free_mesh_instance_slot(scene);
if (slot == UINT32_MAX)
mesh_model_t* mesh_model = mesh_model_slot_map_get(&scene->mesh_models, model.id, model.generation);
if (mesh_model == NULL)
{
return UINT32_MAX;
return INVALID_HANDLE(mesh_instance_handle_t);
}
mesh_instance_t* inst = &scene->mesh_instances.buffer[slot];
*inst = (mesh_instance_t){0};
inst->active = true;
inst->model_id = model_id;
inst->local_to_world = local_to_world;
inst->world_to_local = glms_mat4_inv(local_to_world);
inst->normal_matrix = compute_normal_matrix(local_to_world);
inst->world_bounds = aabb_transform(local_to_world, scene->mesh_models.buffer[model_id].local_bounds);
mesh_instance_t instance =
{
.model = model,
.local_to_world = local_to_world,
.world_to_local = glms_mat4_inv(local_to_world),
.normal_matrix = compute_normal_matrix(local_to_world),
.world_bounds = aabb_transform(local_to_world, mesh_model->local_bounds)
};
mesh_instance_handle_t handle;
if (mesh_instance_slot_map_add(&scene->mesh_instances, instance, &handle.id, &handle.generation) != RESULT_SUCCESS)
{
return INVALID_HANDLE(mesh_instance_handle_t);
}
scene->tlas_dirty = true;
return slot;
return handle;
}
void scene_remove_mesh_instance(scene_t* scene, uint32_t instance_id)
void scene_remove_mesh_instance(scene_t* scene, mesh_instance_handle_t instance)
{
if (scene == NULL || instance_id >= scene->mesh_instances.capacity)
if (scene == NULL)
{
return;
}
if (!scene->mesh_instances.buffer[instance_id].active)
if (mesh_instance_slot_map_remove(&scene->mesh_instances, instance.id, instance.generation) == RESULT_SUCCESS)
{
return;
scene->tlas_dirty = true;
}
scene->mesh_instances.buffer[instance_id].active = false;
scene->tlas_dirty = true;
}
void scene_set_mesh_instance_transform(scene_t* scene, uint32_t instance_id, mat4s local_to_world)
void scene_set_mesh_instance_transform(scene_t* scene, mesh_instance_handle_t instance, mat4s local_to_world)
{
if (scene == NULL || instance_id >= scene->mesh_instances.capacity)
if (scene == NULL)
{
return;
}
mesh_instance_t* inst = &scene->mesh_instances.buffer[instance_id];
if (!inst->active)
mesh_instance_t* inst = mesh_instance_slot_map_get(&scene->mesh_instances, instance.id, instance.generation);
if (inst == NULL)
{
return;
}
mesh_model_t* mesh_model = mesh_model_slot_map_get(&scene->mesh_models, inst->model.id, inst->model.generation);
if (mesh_model == NULL)
{
return;
}
@@ -406,10 +325,7 @@ void scene_set_mesh_instance_transform(scene_t* scene, uint32_t instance_id, mat
inst->local_to_world = local_to_world;
inst->world_to_local = glms_mat4_inv(local_to_world);
inst->normal_matrix = compute_normal_matrix(local_to_world);
if (inst->model_id < scene->mesh_models.capacity && scene->mesh_models.buffer[inst->model_id].active)
{
inst->world_bounds = aabb_transform(local_to_world, scene->mesh_models.buffer[inst->model_id].local_bounds);
}
inst->world_bounds = aabb_transform(local_to_world, mesh_model->local_bounds);
scene->tlas_dirty = true;
}

View File

@@ -6,65 +6,6 @@
#define GET_CHANNEL_DATA(pixel, channel, channel_count, default, max) (channel < channel_count ? pixel[channel] : default) / max
bool texture_collection_init(uint16_t size, texture_collection_t* textures)
{
texture_collection_t temp = {0};
temp.buffer = (texture_asset_t*)malloc(size * sizeof(texture_asset_t));
if (temp.buffer == NULL)
{
return false;
}
temp.size = size;
temp.count = 0;
*textures = temp;
return true;
}
void texture_collection_resize(texture_collection_t* textures, uint16_t size)
{
if (size == INVALID_TEXTURE_ID)
{
size = INVALID_TEXTURE_ID - 1;
}
if (size == textures->size)
{
return;
}
texture_asset_t* temp = (texture_asset_t*)realloc(textures->buffer, size * sizeof(texture_asset_t));
if (temp != NULL)
{
textures->buffer = temp;
textures->size = size;
}
}
void texture_collection_free(texture_collection_t* textures)
{
if (textures == NULL)
{
return;
}
for (uint16_t i = 0; i < textures->count; i++)
{
texture_free(&textures->buffer[i].texture);
char* full_name = textures->buffer[i].full_name;
if (full_name != NULL)
{
free(full_name);
}
}
free(textures->buffer);
textures->buffer = NULL;
}
static inline void read_pixel_raw(const char* data, uint32_t x, uint32_t y, uint32_t width, uint8_t channel_count, stride_t stride, char* out_pixel_data)
{
size_t pixel_offset = (size_t)(y * width + x) * channel_count * stride;
@@ -253,7 +194,7 @@ static void generate_mipmap(char* raw_data, mipmap_t* texture_data, uint32_t wid
#endif
}
texture_handle_t texture_load(const char* filename, bool srgb, bool mipmap, stride_t stride, texture_collection_t* textures)
texture_handle_t texture_load(const char* filename, bool srgb, bool mipmap, stride_t stride, texture_slot_map_t* textures)
{
// TODO: This hurts performance, consider using a hash map or similar structure for faster lookups
@@ -284,7 +225,7 @@ texture_handle_t texture_load(const char* filename, bool srgb, bool mipmap, stri
if (raw_data == NULL)
{
return invalid_texture_handle();
return INVALID_HANDLE(texture_handle_t);
}
uint8_t max_mip_level = mipmap ? (uint8_t)log2f(fmaxf((float)width, (float)height)) : 0;
@@ -292,7 +233,7 @@ texture_handle_t texture_load(const char* filename, bool srgb, bool mipmap, stri
if (temp_texture_data == NULL)
{
stbi_image_free(raw_data);
return invalid_texture_handle();
return INVALID_HANDLE(texture_handle_t);
}
generate_mipmap(raw_data, temp_texture_data, (uint32_t)width, (uint32_t)height, (uint8_t)channels, max_mip_level, stride);
@@ -311,17 +252,19 @@ texture_handle_t texture_load(const char* filename, bool srgb, bool mipmap, stri
texture.wrap_mode = WM_REPEAT;
texture.filter_mode = FM_LINEAR;
if (textures->count >= textures->size)
texture_handle_t handle;
texture_asset_t asset = {.full_name = string_copy(filename), .texture = texture};
if (texture_slot_map_add(textures, asset, &handle.id, &handle.generation) != RESULT_SUCCESS)
{
texture_collection_resize(textures, textures->size * 2);
texture_free(&texture);
if (asset.full_name != NULL)
{
free(asset.full_name);
}
return INVALID_HANDLE(texture_handle_t);
}
texture_handle_t entity = {.id = textures->count};
textures->buffer[textures->count] = (texture_asset_t){.full_name = string_copy(filename), .texture = texture};
textures->count++;
return entity;
return handle;
}
static inline void warp_uv(wrap_mode_t mode, vec2s* uv)