diff --git a/base/sources/engine.c b/base/sources/engine.c index 935b22f9..fd16839d 100644 --- a/base/sources/engine.c +++ b/base/sources/engine.c @@ -1,13 +1,32 @@ #include "engine.h" +#include i32 _object_uid_counter = 0; extern any_array_t *scene_empties; extern any_array_t *scene_meshes; extern object_t *_scene_scene_parent; -void mesh_object_remove(void *raw); -void camera_object_remove(void *raw); -_scene_t *data_get_scene_raw(char *name); +scene_t *data_get_scene_raw(char *name); +i32 sys_w(void); +i32 sys_h(void); +void render_path_render_frame(void); + +extern any_array_t *scene_cameras; +extern camera_object_t *scene_camera; +extern world_data_t *scene_world; +extern any_map_t *scene_embedded; +extern i32 render_path_current_w; +extern i32 render_path_current_h; +extern any_map_t *render_path_render_targets; +extern char_ptr_array_t *_render_path_bind_params; + +f32 sys_time(void); +f32 f32_nan(void); +bool f32_isnan(f32 f); + +gpu_pipeline_t *_mesh_object_last_pipeline = NULL; +vec4_t _camera_object_sphere_center = {0}; +i32 camera_object_taa_frames = 1; gpu_buffer_t *gpu_create_vertex_buffer(i32 count, gpu_vertex_structure_t *structure); gpu_buffer_t *gpu_create_index_buffer(i32 count); @@ -252,7 +271,7 @@ float transform_world_z(transform_t *raw) { // ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ camera_data_t *camera_data_parse(char *name, char *id) { - _scene_t *format = data_get_scene_raw(name); + scene_t *format = data_get_scene_raw(name); camera_data_t *raw = camera_data_get_raw_by_name(format->camera_datas, id); if (raw == NULL) { iron_log("Camera data '%s' not found!", id); @@ -283,7 +302,7 @@ camera_data_t *camera_data_get_raw_by_name(any_array_t *datas, char *name) { f32_array_t *_world_data_empty_irr = NULL; world_data_t *world_data_parse(char *name, char *id) { - _scene_t *format = data_get_scene_raw(name); + scene_t *format = data_get_scene_raw(name); world_data_t *raw = world_data_get_raw_by_name(format->world_datas, id); if (raw == NULL) { iron_log("World data '%s' not found!", id); @@ -390,7 +409,7 @@ material_data_t *material_data_create(material_data_t *raw, char *file) { } material_data_t *material_data_parse(char *file, char *name) { - _scene_t *format = data_get_scene_raw(file); + scene_t *format = data_get_scene_raw(file); material_data_t *raw = material_data_get_raw_by_name(format->material_datas, name); if (raw == NULL) { iron_log("Material data '%s' not found!", name); @@ -465,7 +484,7 @@ char *shader_data_ext() { } shader_data_t *shader_data_parse(char *file, char *name) { - _scene_t *format = data_get_scene_raw(file); + scene_t *format = data_get_scene_raw(file); shader_data_t *raw = shader_data_get_raw_by_name(format->shader_datas, name); if (raw == NULL) { iron_log("Shader data '%s' not found!", name); @@ -779,7 +798,7 @@ void shader_context_add_tex(shader_context_t *raw, i32 i) { // ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ mesh_data_t *mesh_data_parse(char *name, char *id) { - _scene_t *format = data_get_scene_raw(name); + scene_t *format = data_get_scene_raw(name); mesh_data_t *raw = mesh_data_get_raw_by_name(format->mesh_datas, id); if (raw == NULL) { iron_log("Mesh data '%s' not found!", id); @@ -917,3 +936,923 @@ void mesh_data_delete(mesh_data_t *raw) { gpu_delete_buffer(raw->_->vertex_buffer); gpu_delete_buffer(raw->_->index_buffer); } + +// ███╗ ███╗███████╗███████╗██╗ ██╗ ██████╗ ██████╗ ██╗███████╗ ██████╗████████╗ +// ████╗ ████║██╔════╝██╔════╝██║ ██║ ██╔═══██╗██╔══██╗ ██║██╔════╝██╔════╝╚══██╔══╝ +// ██╔████╔██║█████╗ ███████╗███████║ ██║ ██║██████╔╝ ██║█████╗ ██║ ██║ +// ██║╚██╔╝██║██╔══╝ ╚════██║██╔══██║ ██║ ██║██╔══██╗██ ██║██╔══╝ ██║ ██║ +// ██║ ╚═╝ ██║███████╗███████║██║ ██║ ╚██████╔╝██████╔╝╚█████╔╝███████╗╚██████╗ ██║ +// ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚════╝ ╚══════╝ ╚═════╝ ╚═╝ + +mesh_object_t *mesh_object_create(mesh_data_t *data, material_data_t *material) { + mesh_object_t *raw = gc_alloc(sizeof(mesh_object_t)); + raw->frustum_culling = true; + raw->base = object_create(false); + raw->base->ext = raw; + raw->base->ext_type = "mesh_object_t"; + raw->material = material; + mesh_object_set_data(raw, data); + any_array_push(scene_meshes, raw); + return raw; +} + +void mesh_object_set_data(mesh_object_t *raw, mesh_data_t *data) { + raw->data = data; + // Scale-up packed (-1,1) mesh coords + raw->base->transform->scale_world = data->scale_pos; +} + +void mesh_object_remove(mesh_object_t *raw) { + array_remove(scene_meshes, raw); + object_remove_super(raw->base); +} + +bool mesh_object_cull_material(mesh_object_t *raw, char *context) { + // Skip render if material does not contain current context + if (!mesh_object_valid_context(raw, raw->material, context)) { + raw->base->culled = true; + return true; + } + if (raw->skip_context != NULL && string_equals(raw->skip_context, context)) { + raw->base->culled = true; + return true; + } + if (raw->force_context != NULL && !string_equals(raw->force_context, context)) { + raw->base->culled = true; + return true; + } + raw->base->culled = false; + return false; +} + +bool mesh_object_cull_mesh(mesh_object_t *raw, char *context, camera_object_t *camera) { + if (camera->data->frustum_culling && raw->frustum_culling) { + f32 radius_scale = 1.0; + if (!camera_object_sphere_in_frustum(&camera->frustum_planes, raw->base->transform, radius_scale, 0.0, 0.0, 0.0)) { + raw->base->culled = true; + return true; + } + } + raw->base->culled = false; + return false; +} + +void mesh_object_render(mesh_object_t *raw, char *context, char_ptr_array_t *bind_params) { + if (!raw->base->visible) { + return; // Skip render if object is hidden + } + if (mesh_object_cull_mesh(raw, context, scene_camera)) { + return; + } + if (mesh_object_cull_material(raw, context)) { + return; + } + + uniforms_pos_unpack = raw->data->scale_pos; + uniforms_tex_unpack = raw->data->scale_tex; + transform_update(raw->base->transform); + + shader_context_t *scontext = NULL; + material_context_t *mcontext = NULL; + material_data_t *mat = raw->material; + for (i32 j = 0; j < (i32)mat->contexts->length; ++j) { + material_context_t *c = (material_context_t *)mat->contexts->buffer[j]; + if (string_equals(c->name, context)) { + scontext = shader_data_get_context(mat->_->shader, context); + mcontext = c; + break; + } + } + + if (scontext->_->pipe != _mesh_object_last_pipeline) { + gpu_set_pipeline(scontext->_->pipe); + gc_unroot(_mesh_object_last_pipeline); + _mesh_object_last_pipeline = scontext->_->pipe; + gc_root(_mesh_object_last_pipeline); + } + uniforms_set_context_consts(scontext, bind_params); + uniforms_set_obj_consts(scontext, raw->base); + uniforms_set_material_consts(scontext, mcontext); + gpu_set_vertex_buffer(raw->data->_->vertex_buffer); + gpu_set_index_buffer(raw->data->_->index_buffer); + gpu_draw(); +} + +bool mesh_object_valid_context(mesh_object_t *raw, material_data_t *mat, char *context) { + return material_data_get_context(mat, context) != NULL; +} + +// ██████╗ ██████╗ ██╗ ██╗███████╗████████╗██╗ ██╗███╗ ███╗ ██████╗ ██╗ █████╗ ███╗ ██╗███████╗ +// ██╔════╝██╔══██╗██║ ██║██╔════╝╚══██╔══╝██║ ██║████╗ ████║ ██╔══██╗██║ ██╔══██╗████╗ ██║██╔════╝ +// ██║ ██████╔╝██║ ██║███████╗ ██║ ██║ ██║██╔████╔██║ ██████╔╝██║ ███████║██╔██╗ ██║█████╗ +// ██║ ██╔══██╗██║ ██║╚════██║ ██║ ██║ ██║██║╚██╔╝██║ ██╔═══╝ ██║ ██╔══██║██║╚██╗██║██╔══╝ +// ╚██████╗██║ ██║╚██████╔╝███████║ ██║ ╚██████╔╝██║ ╚═╝ ██║ ██║ ███████╗██║ ██║██║ ╚████║███████╗ +// ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝ + +camera_object_t *camera_object_create(camera_data_t *data) { + camera_object_t *raw = gc_alloc(sizeof(camera_object_t)); + raw->no_jitter_p = mat4_identity(); + raw->frame = 0; + raw->base = object_create(false); + raw->base->ext = raw; + raw->base->ext_type = "camera_object_t"; + raw->data = data; + + camera_object_build_proj(raw, -1.0); + + raw->v = mat4_identity(); + raw->vp = mat4_identity(); + + if (data->frustum_culling) { + raw->frustum_planes = any_array_create(0); + for (i32 i = 0; i < 6; ++i) { + any_array_push(raw->frustum_planes, frustum_plane_create()); + } + } + + any_array_push(scene_cameras, raw); + return raw; +} + +void camera_object_build_proj(camera_object_t *raw, f32 screen_aspect) { + if (raw->data->ortho != NULL) { + raw->p = mat4_ortho(raw->data->ortho->buffer[0], raw->data->ortho->buffer[1], raw->data->ortho->buffer[2], raw->data->ortho->buffer[3], + -raw->data->far_plane, raw->data->far_plane); + } + else { + if (screen_aspect < 0) { + screen_aspect = (f32)sys_w() / (f32)sys_h(); + } + f32 aspect = raw->data->aspect != 0.0 ? raw->data->aspect : screen_aspect; + raw->p = mat4_persp(raw->data->fov, aspect, raw->data->near_plane, raw->data->far_plane); + } + raw->no_jitter_p = mat4_clone(raw->p); +} + +void camera_object_remove(camera_object_t *raw) { + array_remove(scene_cameras, raw); + object_remove_super(raw->base); +} + +void camera_object_render_frame(camera_object_t *raw) { + camera_object_proj_jitter(raw); + camera_object_build_mat(raw); + render_path_render_frame(); +} + +void camera_object_proj_jitter(camera_object_t *raw) { + i32 w = render_path_current_w; + i32 h = render_path_current_h; + raw->p = mat4_clone(raw->no_jitter_p); + + i32 i = raw->frame % camera_object_taa_frames; + f32 x = 0.0; + f32 y = 0.0; + + if (i == 0) { + x = 0.5; + y = 0.333; + } + else if (i == 1) { + x = -0.5; + y = -0.333; + } + else if (i == 2) { + x = 0.25; + y = 0.111; + } + else if (i == 3) { + x = -0.25; + y = -0.111; + } + else if (i == 4) { + x = 0.375; + y = 0.444; + } + else { + x = -0.375; + y = -0.444; + } + x *= 2; + y *= 2; + + raw->p.m20 += x / w; + raw->p.m21 += y / h; + raw->frame++; +} + +void camera_object_build_mat(camera_object_t *raw) { + transform_build_matrix(raw->base->transform); + + raw->v = mat4_inv(raw->base->transform->world); + raw->vp = mat4_mult_mat(raw->v, raw->p); + + if (raw->data->frustum_culling) { + camera_object_build_view_frustum(raw->vp, raw->frustum_planes); + } +} + +vec4_t camera_object_right(camera_object_t *raw) { + return vec4_norm(vec4_create(raw->base->transform->local.m00, raw->base->transform->local.m01, raw->base->transform->local.m02, 0.0)); +} + +vec4_t camera_object_up(camera_object_t *raw) { + return vec4_norm(vec4_create(raw->base->transform->local.m10, raw->base->transform->local.m11, raw->base->transform->local.m12, 0.0)); +} + +vec4_t camera_object_look(camera_object_t *raw) { + return vec4_norm(vec4_create(-raw->base->transform->local.m20, -raw->base->transform->local.m21, -raw->base->transform->local.m22, 0.0)); +} + +vec4_t camera_object_right_world(camera_object_t *raw) { + return vec4_norm(vec4_create(raw->base->transform->world.m00, raw->base->transform->world.m01, raw->base->transform->world.m02, 0.0)); +} + +vec4_t camera_object_up_world(camera_object_t *raw) { + return vec4_norm(vec4_create(raw->base->transform->world.m10, raw->base->transform->world.m11, raw->base->transform->world.m12, 0.0)); +} + +vec4_t camera_object_look_world(camera_object_t *raw) { + return vec4_norm(vec4_create(-raw->base->transform->world.m20, -raw->base->transform->world.m21, -raw->base->transform->world.m22, 0.0)); +} + +void camera_object_build_view_frustum(mat4_t vp, frustum_plane_array_t *frustum_planes) { + // Left plane + frustum_plane_set_components(frustum_planes->buffer[0], vp.m03 + vp.m00, vp.m13 + vp.m10, vp.m23 + vp.m20, vp.m33 + vp.m30); + // Right plane + frustum_plane_set_components(frustum_planes->buffer[1], vp.m03 - vp.m00, vp.m13 - vp.m10, vp.m23 - vp.m20, vp.m33 - vp.m30); + // Top plane + frustum_plane_set_components(frustum_planes->buffer[2], vp.m03 - vp.m01, vp.m13 - vp.m11, vp.m23 - vp.m21, vp.m33 - vp.m31); + // Bottom plane + frustum_plane_set_components(frustum_planes->buffer[3], vp.m03 + vp.m01, vp.m13 + vp.m11, vp.m23 + vp.m21, vp.m33 + vp.m31); + // Near plane + frustum_plane_set_components(frustum_planes->buffer[4], vp.m02, vp.m12, vp.m22, vp.m32); + // Far plane + frustum_plane_set_components(frustum_planes->buffer[5], vp.m03 - vp.m02, vp.m13 - vp.m12, vp.m23 - vp.m22, vp.m33 - vp.m32); + // Normalize planes + for (i32 i = 0; i < frustum_planes->length; ++i) { + frustum_plane_normalize(frustum_planes->buffer[i]); + } +} + +bool camera_object_sphere_in_frustum(frustum_plane_array_t *frustum_planes, transform_t *t, f32 radius_scale, f32 offset_x, f32 offset_y, f32 offset_z) { + // Use scale when radius is changing + f32 radius = t->radius * radius_scale; + for (i32 i = 0; i < frustum_planes->length; ++i) { + frustum_plane_t *plane = frustum_planes->buffer[i]; + _camera_object_sphere_center = vec4_create(transform_world_x(t) + offset_x, transform_world_y(t) + offset_y, transform_world_z(t) + offset_z, 0.0); + // Outside the frustum + if (frustum_plane_dist_to_sphere(plane, _camera_object_sphere_center, radius) + radius * 2 < 0) { + return false; + } + } + return true; +} + +// ███████╗██████╗ ██╗ ██╗███████╗████████╗██╗ ██╗███╗ ███╗ ██████╗ ██╗ █████╗ ███╗ ██╗███████╗ +// ██╔════╝██╔══██╗██║ ██║██╔════╝╚══██╔══╝██║ ██║████╗ ████║ ██╔══██╗██║ ██╔══██╗████╗ ██║██╔════╝ +// █████╗ ██████╔╝██║ ██║███████╗ ██║ ██║ ██║██╔████╔██║ ██████╔╝██║ ███████║██╔██╗ ██║█████╗ +// ██╔══╝ ██╔══██╗██║ ██║╚════██║ ██║ ██║ ██║██║╚██╔╝██║ ██╔═══╝ ██║ ██╔══██║██║╚██╗██║██╔══╝ +// ██║ ██║ ██║╚██████╔╝███████║ ██║ ╚██████╔╝██║ ╚═╝ ██║ ██║ ███████╗██║ ██║██║ ╚████║███████╗ +// ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝ + +frustum_plane_t *frustum_plane_create() { + frustum_plane_t *raw = gc_alloc(sizeof(frustum_plane_t)); + raw->normal = vec4_create(1.0, 0.0, 0.0, 0.0); + raw->constant = 0.0; + return raw; +} + +void frustum_plane_normalize(frustum_plane_t *raw) { + f32 inv_normal_length = 1.0 / vec4_len(raw->normal); + raw->normal = vec4_mult(raw->normal, inv_normal_length); + raw->constant *= inv_normal_length; +} + +f32 frustum_plane_dist_to_sphere(frustum_plane_t *raw, vec4_t sphere_center, f32 sphere_radius) { + return (vec4_dot(raw->normal, sphere_center) + raw->constant) - sphere_radius; +} + +void frustum_plane_set_components(frustum_plane_t *raw, f32 x, f32 y, f32 z, f32 w) { + raw->normal = vec4_create(x, y, z, 0.0); + raw->constant = w; +} + +// ██╗ ██╗███╗ ██╗██╗███████╗ ██████╗ ██████╗ ███╗ ███╗███████╗ +// ██║ ██║████╗ ██║██║██╔════╝██╔═══██╗██╔══██╗████╗ ████║██╔════╝ +// ██║ ██║██╔██╗ ██║██║█████╗ ██║ ██║██████╔╝██╔████╔██║███████╗ +// ██║ ██║██║╚██╗██║██║██╔══╝ ██║ ██║██╔══██╗██║╚██╔╝██║╚════██║ +// ╚██████╔╝██║ ╚████║██║██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║███████║ +// ╚═════╝ ╚═╝ ╚═══╝╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ + +mat4_t _uniforms_mat = {0}; +mat4_t _uniforms_mat2 = {0}; +mat3_t _uniforms_mat3 = {0}; +vec4_t _uniforms_vec = {0}; +vec4_t _uniforms_vec2 = {0}; +quat_t _uniforms_quat = {0.0, 0.0, 0.0, 1.0}; + +f32 uniforms_pos_unpack = 1.0; +f32 uniforms_tex_unpack = 1.0; + +gpu_texture_t *(*uniforms_tex_links)(object_t *o, material_data_t *md, char *s) = NULL; +mat4_t (*uniforms_mat4_links)(object_t *o, material_data_t *md, char *s) = NULL; +vec4_t (*uniforms_vec4_links)(object_t *o, material_data_t *md, char *s) = NULL; +vec4_t (*uniforms_vec3_links)(object_t *o, material_data_t *md, char *s) = NULL; +vec2_t (*uniforms_vec2_links)(object_t *o, material_data_t *md, char *s) = NULL; +f32 (*uniforms_f32_links)(object_t *o, material_data_t *md, char *s) = NULL; +f32_array_t *(*uniforms_f32_array_links)(object_t *o, material_data_t *md, char *s) = NULL; +i32 (*uniforms_i32_links)(object_t *o, material_data_t *md, char *s) = NULL; + +void uniforms_set_context_consts(shader_context_t *context, char_ptr_array_t *bind_params) { + // On shader compile error, _.constants.length will be 0 + if (context->constants != NULL && context->constants->length == context->_->constants->length) { + for (i32 i = 0; i < context->constants->length; ++i) { + shader_const_t *c = context->constants->buffer[i]; + uniforms_set_context_const(context->_->constants->buffer[i], c); + } + } + + // Texture context constants + if (bind_params != NULL) { // Bind targets + for (i32 i = 0; i < (i32)math_floor(bind_params->length / 2); ++i) { + i32 pos = i * 2; // bind params = [texture, sampler_id] + char *rt_id = bind_params->buffer[pos]; + char *sampler_id = bind_params->buffer[pos + 1]; + render_target_t *rt = any_map_get(render_path_render_targets, rt_id); + uniforms_bind_render_target(rt, context, sampler_id); + } + } + + // Texture links + if (context->texture_units != NULL && context->texture_units->length == context->_->tex_units->length) { + for (i32 j = 0; j < context->texture_units->length; ++j) { + char *tulink = context->texture_units->buffer[j]->link; + if (tulink == NULL) { + continue; + } + + if (tulink[0] == '$') { // Link to embedded data + gpu_set_texture(context->_->tex_units->buffer[j], any_map_get(scene_embedded, substring(tulink, 1, string_length(tulink)))); + } + else if (string_equals(tulink, "_envmap_radiance")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->radiance); + } + } + else if (string_equals(tulink, "_envmap_radiance0")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->radiance_mipmaps->buffer[0]); + } + } + else if (string_equals(tulink, "_envmap_radiance1")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->radiance_mipmaps->buffer[1]); + } + } + else if (string_equals(tulink, "_envmap_radiance2")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->radiance_mipmaps->buffer[2]); + } + } + else if (string_equals(tulink, "_envmap_radiance3")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->radiance_mipmaps->buffer[3]); + } + } + else if (string_equals(tulink, "_envmap_radiance4")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->radiance_mipmaps->buffer[4]); + } + } + else if (string_equals(tulink, "_envmap")) { + world_data_t *w = scene_world; + if (w != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], w->_->envmap); + } + } + } + } +} + +void uniforms_set_obj_consts(shader_context_t *context, object_t *object) { + if (context->constants != NULL && context->constants->length == context->_->constants->length) { + for (i32 i = 0; i < context->constants->length; ++i) { + shader_const_t *c = context->constants->buffer[i]; + uniforms_set_obj_const(object, context->_->constants->buffer[i], c); + } + } + + // Texture object constants + // External + if (uniforms_tex_links != NULL && context->texture_units != NULL && context->texture_units->length == context->_->tex_units->length) { + for (i32 j = 0; j < context->texture_units->length; ++j) { + tex_unit_t *tu = context->texture_units->buffer[j]; + if (tu->link == NULL) { + continue; + } + + gpu_texture_t *image = uniforms_tex_links(object, current_material(object), tu->link); + if (image != NULL) { + gpu_set_texture(context->_->tex_units->buffer[j], image); + } + } + } +} + +void uniforms_bind_render_target(render_target_t *rt, shader_context_t *context, char *sampler_id) { + if (rt == NULL) { + return; + } + + if (context->texture_units != NULL && context->texture_units->length == context->_->tex_units->length) { + for (i32 j = 0; j < context->texture_units->length; ++j) { // Set texture + if (string_equals(sampler_id, context->texture_units->buffer[j]->name)) { + gpu_set_texture(context->_->tex_units->buffer[j], rt->_image); + } + } + } +} + +bool uniforms_set_context_const(i32 location, shader_const_t *c) { + if (c->link == NULL) { + return true; + } + + camera_object_t *camera = scene_camera; + + if (string_equals(c->type, "mat4")) { + mat4_t m = mat4_nan(); + if (string_equals(c->link, "_view_matrix")) { + m = camera->v; + } + else if (string_equals(c->link, "_proj_matrix")) { + m = camera->p; + } + else if (string_equals(c->link, "_inv_proj_matrix")) { + m = mat4_inv(camera->p); + } + else if (string_equals(c->link, "_view_proj_matrix")) { + m = camera->vp; + } + else if (string_equals(c->link, "_inv_view_proj_matrix")) { + m = mat4_mult_mat(camera->v, camera->p); + m = mat4_inv(m); + } + else if (string_equals(c->link, "_skydome_matrix")) { + transform_t *tr = camera->base->transform; + vec4_t v = vec4_create(transform_world_x(tr), transform_world_y(tr), transform_world_z(tr), 0.0); + f32 bounds = camera->data->far_plane * 0.9f; + vec4_t v2 = vec4_create(bounds, bounds, bounds, 0.0); + m = mat4_compose(v, _uniforms_quat, v2); + m = mat4_mult_mat(m, camera->v); + m = mat4_mult_mat(m, camera->p); + } + else { // Unknown uniform + return false; + } + + gpu_set_matrix4(location, m); + return true; + } + else if (string_equals(c->type, "vec4")) { + vec4_t v = vec4_nan(); + if (string_equals(c->link, "_envmap_irradiance0")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[0]; + v.y = fa->buffer[1]; + v.z = fa->buffer[2]; + v.w = fa->buffer[3]; + } + else if (string_equals(c->link, "_envmap_irradiance1")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[4]; + v.y = fa->buffer[5]; + v.z = fa->buffer[6]; + v.w = fa->buffer[7]; + } + else if (string_equals(c->link, "_envmap_irradiance2")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[8]; + v.y = fa->buffer[9]; + v.z = fa->buffer[10]; + v.w = fa->buffer[11]; + } + else if (string_equals(c->link, "_envmap_irradiance3")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[12]; + v.y = fa->buffer[13]; + v.z = fa->buffer[14]; + v.w = fa->buffer[15]; + } + else if (string_equals(c->link, "_envmap_irradiance4")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[16]; + v.y = fa->buffer[17]; + v.z = fa->buffer[18]; + v.w = fa->buffer[19]; + } + else if (string_equals(c->link, "_envmap_irradiance5")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[20]; + v.y = fa->buffer[21]; + v.z = fa->buffer[22]; + v.w = fa->buffer[23]; + } + else if (string_equals(c->link, "_envmap_irradiance6")) { + f32_array_t *fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + v.x = fa->buffer[24]; + v.y = fa->buffer[25]; + v.z = fa->buffer[26]; + v.w = fa->buffer[27]; + } + else { + return false; + } + + if (!vec4_isnan(v)) { + gpu_set_float4(location, v.x, v.y, v.z, v.w); + } + else { + gpu_set_float4(location, 0, 0, 0, 0); + } + return true; + } + else if (string_equals(c->type, "vec3")) { + vec4_t v = vec4_nan(); + + if (string_equals(c->link, "_camera_pos")) { + v = vec4_create(transform_world_x(camera->base->transform), transform_world_y(camera->base->transform), transform_world_z(camera->base->transform), + 0.0); + } + else if (string_equals(c->link, "_camera_look")) { + v = vec4_norm(camera_object_look_world(camera)); + } + else { + return false; + } + + if (!vec4_isnan(v)) { + gpu_set_float3(location, v.x, v.y, v.z); + } + else { + gpu_set_float3(location, 0.0, 0.0, 0.0); + } + return true; + } + else if (string_equals(c->type, "vec2")) { + vec4_t v = vec4_nan(); + + if (string_equals(c->link, "_vec2x")) { + v.x = 1.0; + v.y = 0.0; + } + else if (string_equals(c->link, "_vec2x_inv")) { + v.x = 1.0f / render_path_current_w; + v.y = 0.0; + } + else if (string_equals(c->link, "_vec2x2")) { + v.x = 2.0; + v.y = 0.0; + } + else if (string_equals(c->link, "_vec2x2_inv")) { + v.x = 2.0f / render_path_current_w; + v.y = 0.0; + } + else if (string_equals(c->link, "_vec2y")) { + v.x = 0.0; + v.y = 1.0; + } + else if (string_equals(c->link, "_vec2y_inv")) { + v.x = 0.0; + v.y = 1.0f / render_path_current_h; + } + else if (string_equals(c->link, "_vec2y2")) { + v.x = 0.0; + v.y = 2.0; + } + else if (string_equals(c->link, "_vec2y2_inv")) { + v.x = 0.0; + v.y = 2.0f / render_path_current_h; + } + else if (string_equals(c->link, "_vec2y3")) { + v.x = 0.0; + v.y = 3.0; + } + else if (string_equals(c->link, "_vec2y3_inv")) { + v.x = 0.0; + v.y = 3.0f / render_path_current_h; + } + else if (string_equals(c->link, "_screen_size")) { + v.x = (f32)render_path_current_w; + v.y = (f32)render_path_current_h; + } + else if (string_equals(c->link, "_screen_size_inv")) { + v.x = 1.0f / render_path_current_w; + v.y = 1.0f / render_path_current_h; + } + else if (string_equals(c->link, "_camera_plane_proj")) { + f32 znear = camera->data->near_plane; + f32 zfar = camera->data->far_plane; + v.x = zfar / (zfar - znear); + v.y = (-zfar * znear) / (zfar - znear); + } + else if (starts_with(c->link, "_size(")) { + char *tex = substring(c->link, 6, string_length(c->link) - 1); + gpu_texture_t *image = uniforms_tex_links != NULL ? uniforms_tex_links(NULL, NULL, tex) : NULL; + if (image != NULL) { + v.x = (f32)image->width; + v.y = (f32)image->height; + } + else if (_render_path_bind_params != NULL) { + for (i32 i = 0; i < (i32)math_floor(_render_path_bind_params->length / 2); ++i) { + i32 pos = i * 2; // bind params = [texture, sampler_id] + char *sampler_id = _render_path_bind_params->buffer[pos + 1]; + if (string_equals(sampler_id, tex)) { + char *rt_id = _render_path_bind_params->buffer[pos]; + render_target_t *rt = any_map_get(render_path_render_targets, rt_id); + v.x = (f32)rt->width; + v.y = (f32)rt->height; + } + } + } + } + else { + return false; + } + + if (!vec4_isnan(v)) { + gpu_set_float2(location, v.x, v.y); + } + else { + gpu_set_float2(location, 0.0, 0.0); + } + return true; + } + else if (string_equals(c->type, "float")) { + f32 f = 0.0; + + if (string_equals(c->link, "_time")) { + f = sys_time(); + } + else if (string_equals(c->link, "_aspect_ratio_window")) { + f = (f32)sys_w() / (f32)sys_h(); + } + else { + return false; + } + + gpu_set_float(location, f); + return true; + } + else if (string_equals(c->type, "floats")) { + f32_array_t *fa = NULL; + + if (string_equals(c->link, "_envmap_irradiance")) { + fa = scene_world == NULL ? world_data_get_empty_irradiance() : scene_world->_->irradiance; + } + + if (fa != NULL) { + gpu_set_floats(location, fa); + return true; + } + } + else if (string_equals(c->type, "int")) { + i32 i = 0; + + if (string_equals(c->link, "_envmap_num_mipmaps")) { + world_data_t *w = scene_world; + i = w != NULL ? w->radiance_mipmaps + 1 - 2 : 1; // Include basecolor and exclude 2 scaled mips + } + else { + return false; + } + + gpu_set_int(location, i); + return true; + } + return false; +} + +void uniforms_set_obj_const(object_t *obj, i32 loc, shader_const_t *c) { + if (c->link == NULL) { + return; + } + + camera_object_t *camera = scene_camera; + if (string_equals(c->type, "mat4")) { + mat4_t m = mat4_nan(); + + if (string_equals(c->link, "_world_matrix")) { + m = obj->transform->world_unpack; + } + else if (string_equals(c->link, "_inv_world_matrix")) { + m = mat4_inv(obj->transform->world_unpack); + } + else if (string_equals(c->link, "_world_view_proj_matrix")) { + m = mat4_mult_mat(obj->transform->world_unpack, camera->v); + m = mat4_mult_mat(m, camera->p); + } + else if (string_equals(c->link, "_world_wiew_matrix")) { + m = mat4_mult_mat(obj->transform->world_unpack, camera->v); + } + else if (uniforms_mat4_links != NULL) { + m = uniforms_mat4_links(obj, current_material(obj), c->link); + } + + if (mat4_isnan(m)) { + return; + } + gpu_set_matrix4(loc, m); + } + else if (string_equals(c->type, "mat3")) { + mat3_t m = mat3_nan(); + + if (string_equals(c->link, "_normal_matrix")) { + mat4_t m4 = mat4_inv(obj->transform->world); + m4 = mat4_transpose3x3(m4); + m = mat3_set_from4(m4); + } + else if (string_equals(c->link, "_view_matrix3")) { + m = mat3_set_from4(camera->v); + } + + if (mat3_isnan(m)) { + return; + } + gpu_set_matrix3(loc, m); + } + else if (string_equals(c->type, "vec4")) { + vec4_t v = vec4_nan(); + + if (uniforms_vec4_links != NULL) { + v = uniforms_vec4_links(obj, current_material(obj), c->link); + } + + if (vec4_isnan(v)) { + return; + } + gpu_set_float4(loc, v.x, v.y, v.z, v.w); + } + else if (string_equals(c->type, "vec3")) { + vec4_t v = vec4_nan(); + + if (string_equals(c->link, "_dim")) { // Model space + vec4_t d = obj->transform->dim; + vec4_t s = obj->transform->scale; + v = vec4_create((d.x / s.x), (d.y / s.y), (d.z / s.z), 0.0); + } + else if (string_equals(c->link, "_half_dim")) { // Model space + vec4_t d = obj->transform->dim; + vec4_t s = obj->transform->scale; + v = vec4_create((d.x / s.x) / 2, (d.y / s.y) / 2, (d.z / s.z) / 2, 0.0); + } + else if (uniforms_vec3_links != NULL) { + v = uniforms_vec3_links(obj, current_material(obj), c->link); + } + + if (vec4_isnan(v)) { + return; + } + gpu_set_float3(loc, v.x, v.y, v.z); + } + else if (string_equals(c->type, "vec2")) { + vec2_t v = vec2_nan(); + + if (uniforms_vec2_links != NULL) { + v = uniforms_vec2_links(obj, current_material(obj), c->link); + } + + if (vec2_isnan(v)) { + return; + } + gpu_set_float2(loc, v.x, v.y); + } + else if (string_equals(c->type, "float")) { + f32 f = f32_nan(); + + if (string_equals(c->link, "_object_info_index")) { + f = (f32)obj->uid; + } + else if (string_equals(c->link, "_object_info_material_index")) { + f = current_material(obj)->_->uid; + } + else if (string_equals(c->link, "_object_info_random")) { + f = obj->urandom; + } + else if (string_equals(c->link, "_pos_unpack")) { + f = uniforms_pos_unpack; + } + else if (string_equals(c->link, "_tex_unpack")) { + f = uniforms_tex_unpack; + } + else if (uniforms_f32_links != NULL) { + f = uniforms_f32_links(obj, current_material(obj), c->link); + } + + if (f32_isnan(f)) { + return; + } + gpu_set_float(loc, f); + } + else if (string_equals(c->type, "floats")) { + f32_array_t *fa = NULL; + + if (uniforms_f32_array_links != NULL) { + fa = uniforms_f32_array_links(obj, current_material(obj), c->link); + } + + if (fa == NULL) { + return; + } + gpu_set_floats(loc, fa); + } + else if (string_equals(c->type, "int")) { + i32 i = INT_MAX; + + if (string_equals(c->link, "_uid")) { + i = obj->uid; + } + else if (uniforms_i32_links != NULL) { + i = uniforms_i32_links(obj, current_material(obj), c->link); + } + + if (i == INT_MAX) { + return; + } + + gpu_set_int(loc, i); + } +} + +void uniforms_set_material_consts(shader_context_t *context, material_context_t *material_context) { + if (material_context->bind_constants != NULL) { + for (i32 i = 0; i < material_context->bind_constants->length; ++i) { + bind_const_t *matc = material_context->bind_constants->buffer[i]; + i32 pos = -1; + for (i32 j = 0; j < context->constants->length; ++j) { + char *name = context->constants->buffer[j]->name; + if (string_equals(name, matc->name)) { + pos = j; + break; + } + } + if (pos == -1) { + continue; + } + shader_const_t *c = context->constants->buffer[pos]; + + uniforms_set_material_const(context->_->constants->buffer[pos], c, matc); + } + } + + if (material_context->_->textures != NULL) { + for (i32 i = 0; i < material_context->_->textures->length; ++i) { + char *mname = material_context->bind_textures->buffer[i]->name; + + for (i32 j = 0; j < context->_->tex_units->length; ++j) { + char *sname = context->texture_units->buffer[j]->name; + if (string_equals(mname, sname)) { + gpu_set_texture(context->_->tex_units->buffer[j], material_context->_->textures->buffer[i]); + break; + } + } + } + } +} + +material_data_t *current_material(object_t *object) { + if (object != NULL && object->ext != NULL) { + mesh_object_t *mo = object->ext; + return mo->material; + } + return NULL; +} + +void uniforms_set_material_const(i32 location, shader_const_t *shader_const, bind_const_t *material_const) { + if (string_equals(shader_const->type, "vec4")) { + gpu_set_float4(location, material_const->vec->buffer[0], material_const->vec->buffer[1], material_const->vec->buffer[2], + material_const->vec->buffer[3]); + } + else if (string_equals(shader_const->type, "vec3")) { + gpu_set_float3(location, material_const->vec->buffer[0], material_const->vec->buffer[1], material_const->vec->buffer[2]); + } + else if (string_equals(shader_const->type, "vec2")) { + gpu_set_float2(location, material_const->vec->buffer[0], material_const->vec->buffer[1]); + } + else if (string_equals(shader_const->type, "float")) { + gpu_set_float(location, material_const->vec->buffer[0]); + } + else if (string_equals(shader_const->type, "bool")) { + gpu_set_bool(location, material_const->vec->buffer[0] > 0.0f); + } + else if (string_equals(shader_const->type, "int")) { + gpu_set_int(location, (i32)math_floor(material_const->vec->buffer[0])); + } +} diff --git a/base/sources/engine.h b/base/sources/engine.h index 89745ef3..05ace072 100644 --- a/base/sources/engine.h +++ b/base/sources/engine.h @@ -4,10 +4,12 @@ #include "iron_array.h" #include "iron_gc.h" #include "iron_gpu.h" +#include "iron_mat3.h" #include "iron_mat4.h" #include "iron_quat.h" #include "iron_string.h" #include "iron_system.h" +#include "iron_vec2.h" #include "iron_vec4.h" #include #include @@ -46,18 +48,18 @@ typedef struct _vertex_element_t_array { } _vertex_element_t_array_t; typedef struct _bind_const_t_array { struct bind_const **buffer; - int length; - int capacity; + int length; + int capacity; } _bind_const_t_array_t; typedef struct _bind_tex_t_array { struct bind_tex **buffer; - int length; - int capacity; + int length; + int capacity; } _bind_tex_t_array_t; typedef struct _material_context_t_array { struct material_context **buffer; - int length; - int capacity; + int length; + int capacity; } _material_context_t_array_t; typedef struct obj_runtime { @@ -110,6 +112,28 @@ typedef struct camera_data { f32_array_t *ortho; // Indicates ortho camera, left, right, bottom, top } camera_data_t; +typedef struct frustum_plane { + vec4_t normal; + f32 constant; +} frustum_plane_t; + +typedef struct frustum_plane_array { + frustum_plane_t **buffer; + int length; + int capacity; +} frustum_plane_array_t; + +typedef struct camera_object { + object_t *base; + camera_data_t *data; + mat4_t p; + mat4_t no_jitter_p; + i32 frame; + mat4_t v; + mat4_t vp; + frustum_plane_array_t *frustum_planes; +} camera_object_t; + typedef struct world_data_runtime { gpu_texture_t *envmap; gpu_texture_t *radiance; @@ -132,19 +156,19 @@ typedef struct irradiance { f32_array_t *irradiance; // Spherical harmonics, bands 0,1,2 } irradiance_t; -typedef struct _scene { +typedef struct scene { char *name; - any_array_t *objects; - any_array_t *mesh_datas; - any_array_t *camera_datas; + any_array_t *objects; // obj_t[] + any_array_t *mesh_datas; // mesh_data_t[] + any_array_t *camera_datas; // camera_data_t[] char *camera_ref; - any_array_t *material_datas; - any_array_t *shader_datas; - any_array_t *world_datas; + any_array_t *material_datas; // material_data_t[] + any_array_t *shader_datas; // shader_data_t[] + any_array_t *world_datas; // world_data_t[] char *world_ref; any_array_t *speaker_datas; // TODO: deprecated char_ptr_array_t *embedded_datas; // Preload for this scene, images only for now -} _scene_t; +} scene_t; typedef struct shader_context_runtime { gpu_pipeline_t *pipe; @@ -216,8 +240,8 @@ typedef struct material_context_runtime { typedef struct material_context { char *name; - _bind_const_t_array_t *bind_constants; // bind_const_t[] - _bind_tex_t_array_t *bind_textures; // bind_tex_t[] + _bind_const_t_array_t *bind_constants; // bind_const_t[] + _bind_tex_t_array_t *bind_textures; // bind_tex_t[] material_context_runtime_t *_; } material_context_t; @@ -227,12 +251,33 @@ typedef struct material_data_runtime { } material_data_runtime_t; typedef struct material_data { - char *name; - char *shader; - _material_context_t_array_t *contexts; // material_context_t[] - material_data_runtime_t *_; + char *name; + char *shader; + _material_context_t_array_t *contexts; // material_context_t[] + material_data_runtime_t *_; } material_data_t; +typedef struct render_target { + char *name; + i32 width; + i32 height; + // Optional + char *format; + f32 scale; + // Runtime + gpu_texture_t *_image; +} render_target_t; + +typedef struct mesh_object { + object_t *base; + mesh_data_t *data; + material_data_t *material; + f32 camera_dist; + bool frustum_culling; + char *skip_context; // Do not draw this context + char *force_context; // Draw only this context +} mesh_object_t; + typedef struct transform { mat4_t world; mat4_t local; @@ -290,6 +335,28 @@ float transform_world_z(transform_t *raw); camera_data_t *camera_data_parse(char *name, char *id); camera_data_t *camera_data_get_raw_by_name(any_array_t *datas, char *name); +extern vec4_t _camera_object_sphere_center; +extern i32 camera_object_taa_frames; +camera_object_t *camera_object_create(camera_data_t *data); +void camera_object_build_proj(camera_object_t *raw, f32 screen_aspect); +void camera_object_remove(camera_object_t *raw); +void camera_object_render_frame(camera_object_t *raw); +void camera_object_proj_jitter(camera_object_t *raw); +void camera_object_build_mat(camera_object_t *raw); +vec4_t camera_object_right(camera_object_t *raw); +vec4_t camera_object_up(camera_object_t *raw); +vec4_t camera_object_look(camera_object_t *raw); +vec4_t camera_object_right_world(camera_object_t *raw); +vec4_t camera_object_up_world(camera_object_t *raw); +vec4_t camera_object_look_world(camera_object_t *raw); +void camera_object_build_view_frustum(mat4_t vp, frustum_plane_array_t *frustum_planes); +bool camera_object_sphere_in_frustum(frustum_plane_array_t *frustum_planes, transform_t *t, f32 radius_scale, f32 offset_x, f32 offset_y, f32 offset_z); + +frustum_plane_t *frustum_plane_create(); +void frustum_plane_normalize(frustum_plane_t *raw); +f32 frustum_plane_dist_to_sphere(frustum_plane_t *raw, vec4_t sphere_center, f32 sphere_radius); +void frustum_plane_set_components(frustum_plane_t *raw, f32 x, f32 y, f32 z, f32 w); + extern f32_array_t *_world_data_empty_irr; world_data_t *world_data_parse(char *name, char *id); world_data_t *world_data_get_raw_by_name(any_array_t *datas, char *name); @@ -341,3 +408,38 @@ vertex_array_t *mesh_data_get_vertex_array(mesh_data_t *raw, char *name); void mesh_data_build(mesh_data_t *raw); vec4_t mesh_data_calculate_aabb(mesh_data_t *raw); void mesh_data_delete(mesh_data_t *raw); + +extern gpu_pipeline_t *_mesh_object_last_pipeline; +mesh_object_t *mesh_object_create(mesh_data_t *data, material_data_t *material); +void mesh_object_set_data(mesh_object_t *raw, mesh_data_t *data); +void mesh_object_remove(mesh_object_t *raw); +bool mesh_object_cull_material(mesh_object_t *raw, char *context); +bool mesh_object_cull_mesh(mesh_object_t *raw, char *context, camera_object_t *camera); +void mesh_object_render(mesh_object_t *raw, char *context, char_ptr_array_t *bind_params); +bool mesh_object_valid_context(mesh_object_t *raw, material_data_t *mat, char *context); + +extern mat4_t _uniforms_mat; +extern mat4_t _uniforms_mat2; +extern mat3_t _uniforms_mat3; +extern vec4_t _uniforms_vec; +extern vec4_t _uniforms_vec2; +extern quat_t _uniforms_quat; +extern f32 uniforms_pos_unpack; +extern f32 uniforms_tex_unpack; +extern gpu_texture_t *(*uniforms_tex_links)(object_t *o, material_data_t *md, char *s); +extern mat4_t (*uniforms_mat4_links)(object_t *o, material_data_t *md, char *s); +extern vec4_t (*uniforms_vec4_links)(object_t *o, material_data_t *md, char *s); +extern vec4_t (*uniforms_vec3_links)(object_t *o, material_data_t *md, char *s); +extern vec2_t (*uniforms_vec2_links)(object_t *o, material_data_t *md, char *s); +extern f32 (*uniforms_f32_links)(object_t *o, material_data_t *md, char *s); +extern f32_array_t *(*uniforms_f32_array_links)(object_t *o, material_data_t *md, char *s); +extern i32 (*uniforms_i32_links)(object_t *o, material_data_t *md, char *s); + +void uniforms_set_context_consts(shader_context_t *context, char_ptr_array_t *bind_params); +void uniforms_set_obj_consts(shader_context_t *context, object_t *object); +void uniforms_bind_render_target(render_target_t *rt, shader_context_t *context, char *sampler_id); +bool uniforms_set_context_const(i32 location, shader_const_t *c); +void uniforms_set_obj_const(object_t *obj, i32 loc, shader_const_t *c); +void uniforms_set_material_consts(shader_context_t *context, material_context_t *material_context); +material_data_t *current_material(object_t *object); +void uniforms_set_material_const(i32 location, shader_const_t *shader_const, bind_const_t *material_const); diff --git a/base/sources/engine.ts b/base/sources/engine.ts index 5bd14f28..7cef35c8 100644 --- a/base/sources/engine.ts +++ b/base/sources/engine.ts @@ -103,3 +103,255 @@ declare function material_data_parse(file: string, name: string): material_data_ declare function material_data_get_raw_by_name(datas: material_data_t[], name: string): material_data_t; declare function material_data_get_context(raw: material_data_t, name: string): material_context_t; declare function material_context_load(raw: material_context_t); + +declare type camera_object_t = { + base?: object_t; + data?: camera_data_t; + p?: mat4_t; + no_jitter_p?: mat4_t; + frame?: i32; + v?: mat4_t; + vp?: mat4_t; + frustum_planes?: frustum_plane_t[]; +}; + +declare let _camera_object_sphere_center: vec4_t; +declare let camera_object_taa_frames: i32; + +declare function camera_object_create(data: camera_data_t): camera_object_t; +declare function camera_object_build_proj(raw: camera_object_t, screen_aspect: f32 = -1.0); +declare function camera_object_remove(raw: camera_object_t); +declare function camera_object_render_frame(raw: camera_object_t); +declare function camera_object_proj_jitter(raw: camera_object_t); +declare function camera_object_build_mat(raw: camera_object_t); +declare function camera_object_right(raw: camera_object_t): vec4_t; +declare function camera_object_up(raw: camera_object_t): vec4_t; +declare function camera_object_look(raw: camera_object_t): vec4_t; +declare function camera_object_right_world(raw: camera_object_t): vec4_t; +declare function camera_object_up_world(raw: camera_object_t): vec4_t; +declare function camera_object_look_world(raw: camera_object_t): vec4_t; +declare function camera_object_build_view_frustum(vp: mat4_t, frustum_planes: frustum_plane_t[]); +declare function camera_object_sphere_in_frustum(frustum_planes: frustum_plane_t[], t: transform_t, radius_scale: f32 = 1.0, offset_x: f32 = 0.0, offset_y: f32 = 0.0, offset_z: f32 = 0.0): bool; + +declare type frustum_plane_t = { + normal?: vec4_t; + constant?: f32; +}; + +declare function frustum_plane_create(): frustum_plane_t; +declare function frustum_plane_normalize(raw: frustum_plane_t); +declare function frustum_plane_dist_to_sphere(raw: frustum_plane_t, sphere_center: vec4_t, sphere_radius: f32): f32; +declare function frustum_plane_set_components(raw: frustum_plane_t, x: f32, y: f32, z: f32, w: f32); + +declare type mesh_object_t = { + base?: object_t; + data?: mesh_data_t; + material?: material_data_t; + camera_dist?: f32; + frustum_culling?: bool; + skip_context?: string; // Do not draw this context + force_context?: string; // Draw only this context +}; + +declare let _mesh_object_last_pipeline: gpu_pipeline_t; + +declare function mesh_object_create(data: mesh_data_t, material: material_data_t): mesh_object_t; +declare function mesh_object_set_data(raw: mesh_object_t, data: mesh_data_t); +declare function mesh_object_remove(raw: mesh_object_t); +declare function mesh_object_cull_material(raw: mesh_object_t, context: string): bool; +declare function mesh_object_cull_mesh(raw: mesh_object_t, context: string, camera: camera_object_t): bool; +declare function mesh_object_render(raw: mesh_object_t, context: string, bind_params: string[]); +declare function mesh_object_valid_context(raw: mesh_object_t, mat: material_data_t, context: string): bool; + +declare let uniforms_tex_links: (o: object_t, md: material_data_t, s: string) => gpu_texture_t; +declare let uniforms_mat4_links: (o: object_t, md: material_data_t, s: string) => mat4_t; +declare let uniforms_vec4_links: (o: object_t, md: material_data_t, s: string) => vec4_t; +declare let uniforms_vec3_links: (o: object_t, md: material_data_t, s: string) => vec4_t; +declare let uniforms_vec2_links: (o: object_t, md: material_data_t, s: string) => vec2_t; +declare let uniforms_f32_links: (o: object_t, md: material_data_t, s: string) => f32; +declare let uniforms_f32_array_links: (o: object_t, md: material_data_t, s: string) => f32_array_t; +declare let uniforms_i32_links: (o: object_t, md: material_data_t, s: string) => i32; +declare let uniforms_pos_unpack: f32; +declare let uniforms_tex_unpack: f32; + +declare function uniforms_set_context_consts(context: shader_context_t, bind_params: string[]); +declare function uniforms_set_obj_consts(context: shader_context_t, object: object_t); +declare function uniforms_bind_render_target(rt: render_target_t, context: shader_context_t, sampler_id: string); +declare function uniforms_set_context_const(location: i32, c: shader_const_t): bool; +declare function uniforms_set_obj_const(obj: object_t, loc: i32, c: shader_const_t); +declare function uniforms_set_material_consts(context: shader_context_t, material_context: material_context_t); +declare function current_material(object: object_t): material_data_t; +declare function uniforms_set_material_const(location: i32, shader_const: shader_const_t, material_const: bind_const_t); + +declare type mesh_data_t = { + name?: string; + scale_pos?: f32; // Unpack pos from (-1,1) coords + scale_tex?: f32; // Unpack tex from (-1,1) coords + vertex_arrays?: vertex_array_t[]; + index_array?: u32_array_t; // size = 3 + _?: mesh_data_runtime_t; +}; + +declare type mesh_data_runtime_t = { + handle?: string; // Handle used to retrieve this object in Data + vertex_buffer?: gpu_buffer_t; + index_buffer?: gpu_buffer_t; + structure?: gpu_vertex_structure_t; +}; + +declare type vertex_array_t = { + attrib?: string; + data?: string; // short4norm, short2norm + values?: i16_array_t; +}; + +declare type camera_data_t = { + name?: string; + near_plane?: f32; + far_plane?: f32; + fov?: f32; + aspect?: f32; + frustum_culling?: bool; + ortho?: f32_array_t; // Indicates ortho camera, left, right, bottom, top +}; + +declare type material_data_t = { + name?: string; + shader?: string; + contexts?: material_context_t[]; + _?: material_data_runtime_t; +}; + +declare type material_data_runtime_t = { + uid?: f32; + shader?: shader_data_t; +}; + +declare type material_context_t = { + name?: string; + bind_constants?: bind_const_t[]; + bind_textures?: bind_tex_t[]; + _?: material_context_runtime_t; +}; + +declare type material_context_runtime_t = { + textures?: gpu_texture_t[]; +}; + +declare type bind_const_t = { + name?: string; + vec?: f32_array_t; // bool (vec[0] > 0) | i32 | f32 | vec2 | vec3 | vec4 +}; + +declare type bind_tex_t = { + name?: string; + file?: string; +}; + +declare type shader_data_t = { + name?: string; + contexts?: shader_context_t[]; +}; + +declare type shader_context_t = { + name?: string; + depth_write?: bool; + compare_mode?: string; + cull_mode?: string; + vertex_shader?: string; + fragment_shader?: string; + shader_from_source?: bool; // Build shader at runtime using from_source() + blend_source?: string; + blend_destination?: string; + alpha_blend_source?: string; + alpha_blend_destination?: string; + color_writes_red?: bool[]; // Per target masks + color_writes_green?: bool[]; + color_writes_blue?: bool[]; + color_writes_alpha?: bool[]; + color_attachments?: string[]; // RGBA32, RGBA64, R8 + depth_attachment?: string; // D32 + vertex_elements?: vertex_element_t[]; + constants?: shader_const_t[]; + texture_units?: tex_unit_t[]; + _?: shader_context_runtime_t; +}; + +declare type shader_context_runtime_t = { + pipe?: gpu_pipeline_t; + constants?: i32[]; + tex_units?: i32[]; + structure?: gpu_vertex_structure_t; + vertex_shader_size?: i32; + fragment_shader_size?: i32; +}; + +declare type vertex_element_t = { + name?: string; + data?: string; // "short4norm", "short2norm" +}; + +declare type shader_const_t = { + name?: string; + type?: string; + link?: string; +}; + +declare type tex_unit_t = { + name?: string; + link?: string; +}; + +declare type world_data_t = { + name?: string; + color?: i32; + strength?: f32; + irradiance?: string; // Reference to irradiance_t blob + radiance?: string; + radiance_mipmaps?: i32; + envmap?: string; + _?: world_data_runtime_t; +}; + +declare type world_data_runtime_t = { + envmap?: gpu_texture_t; + radiance?: gpu_texture_t; + radiance_mipmaps?: gpu_texture_t[]; + irradiance?: f32_array_t; +}; + +declare type irradiance_t = { + irradiance?: f32_array_t; // Blob with spherical harmonics, bands 0,1,2 +}; + +declare type obj_t = { + name?: string; + type?: string; // object, mesh_object, camera_object + data_ref?: string; + transform?: f32_array_t; + dimensions?: f32_array_t; // Geometry objects + visible?: bool; + spawn?: bool; // Auto add object when creating scene + anim?: any; // TODO: deprecated + material_ref?: string; + children?: obj_t[]; + _?: obj_runtime_t; +}; + +declare type obj_runtime_t = { + _gc?: scene_t; // Link to armpack_decode result +}; + +declare type scene_t = { + name?: string; + objects?: obj_t[]; + mesh_datas?: mesh_data_t[]; + camera_datas?: camera_data_t[]; + camera_ref?: string; + material_datas?: material_data_t[]; + shader_datas?: shader_data_t[]; + world_datas?: world_data_t[]; + world_ref?: string; + speaker_datas?: any; // TODO: deprecated + embedded_datas?: string[]; // Preload for this scene, images only for now +}; diff --git a/base/sources/iron.h b/base/sources/iron.h index c5112501..5e6fcd62 100644 --- a/base/sources/iron.h +++ b/base/sources/iron.h @@ -209,6 +209,8 @@ string_t *iron_get_arg(i32 index) { #include "iron_tween.h" #include "iron_input.h" #include "iron_tilesheet.h" +#include "iron_raycast.h" +#include "iron_shape.h" #include "iron_sys.h" #include "engine.h" #include "kong/dir.h" diff --git a/base/sources/iron.ts b/base/sources/iron.ts index 18c04eae..b45f4900 100644 --- a/base/sources/iron.ts +++ b/base/sources/iron.ts @@ -1348,3 +1348,77 @@ declare function sys_notify_on_next_frame(f: (data?: any) => void, data: any = n declare function sys_notify_on_end_frame(f: (data?: any) => void, data: any = null); declare function sys_buffer_to_string(b: buffer_t): string; declare function sys_string_to_buffer(str: string): buffer_t; + +declare type ray_t = { + origin?: vec4_t; + dir?: vec4_t; +}; + +declare type plane_t = { + normal?: vec4_t; + constant?: f32; +}; + +declare let _raycast_vp_inv: mat4_t; +declare let _raycast_p_inv: mat4_t; +declare let _raycast_v_inv: mat4_t; + +declare function raycast_get_ray(input_x: f32, input_y: f32, camera: camera_object_t): ray_t; +declare function raycast_box_intersect(transform: transform_t, input_x: f32, input_y: f32, camera: camera_object_t): vec4_t; +declare function raycast_closest_box_intersect(transforms: transform_t[], input_x: f32, input_y: f32, camera: camera_object_t): transform_t; +declare function plane_create(): plane_t; +declare function raycast_plane_intersect(normal: vec4_t, a: vec4_t, input_x: f32, input_y: f32, camera: camera_object_t): vec4_t; +declare function ray_create(origin: vec4_t, dir: vec4_t): ray_t; +declare function ray_at(raw: ray_t, t: f32): vec4_t; +declare function ray_dist_to_point(raw: ray_t, point: vec4_t): f32; +declare function ray_intersects_sphere(raw: ray_t, sphere_center: vec4_t, sphere_radius: f32): bool; +declare function ray_intersects_plane(raw: ray_t, plane: plane_t): bool; +declare function ray_dist_to_plane(raw: ray_t, plane: plane_t): f32; +declare function ray_intersect_plane(raw: ray_t, plane: plane_t): vec4_t; +declare function ray_intersect_box(raw: ray_t, center: vec4_t, dim: vec4_t): vec4_t; +declare function ray_intersect_triangle(raw: ray_t, a: vec4_t, b: vec4_t, c: vec4_t, cull_backface: bool): vec4_t; +declare function plane_dist_to_point(raw: plane_t, point: vec4_t): f32; +declare function plane_set(raw: plane_t, normal: vec4_t, point: vec4_t): plane_t; + +// let line_draw_color: color_t = 0xffff0000; +// let line_draw_strength: f32 = 0.002; +// let line_draw_mat: mat4_t = mat4_nan(); +// let line_draw_dim: vec4_t = vec4_nan(); +// let line_draw_vertex_buffer: gpu_buffer_t; +// let line_draw_index_buffer: gpu_buffer_t; +// let line_draw_pipeline: gpu_pipeline_t = null; +// let line_draw_overlay_pipeline: gpu_pipeline_t = null; +// let line_draw_vp: mat4_t; +// let line_draw_vp_loc: i32; +// let line_draw_color_loc: i32; +// let line_draw_vb_data: buffer_t; +// let line_draw_ib_data: u32_array_t; +// let line_draw_max_lines: i32 = 300; +// let line_draw_max_vertices: i32 = line_draw_max_lines * 4; +// let line_draw_max_indices: i32 = line_draw_max_lines * 6; +// let line_draw_lines: i32 = 0; +// let line_draw_wpos: vec4_t; +// let line_draw_vx: vec4_t = vec4_create(); +// let line_draw_vy: vec4_t = vec4_create(); +// let line_draw_vz: vec4_t = vec4_create(); +// let line_draw_v1: vec4_t = vec4_create(); +// let line_draw_v2: vec4_t = vec4_create(); +// let line_draw_t: vec4_t = vec4_create(); +// let line_draw_mid_point: vec4_t = vec4_create(); +// let line_draw_mid_line: vec4_t = vec4_create(); +// let line_draw_corner1: vec4_t = vec4_create(); +// let line_draw_corner2: vec4_t = vec4_create(); +// let line_draw_corner3: vec4_t = vec4_create(); +// let line_draw_corner4: vec4_t = vec4_create(); +// let line_draw_camera_look: vec4_t = vec4_create(); + +declare function line_draw_init(); +declare function line_draw_render(matrix: mat4_t); +declare function line_draw_bounds(mat: mat4_t, dim: vec4_t); +declare function line_draw_lineb(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32); +declare function line_draw_line(x1: f32, y1: f32, z1: f32, x2: f32, y2: f32, z2: f32); +declare function line_draw_begin(); +declare function line_draw_end(); +// let _shape_draw_sphere_vb: gpu_buffer_t = null; +// let _shape_draw_sphere_ib: gpu_buffer_t = null; +declare function shape_draw_sphere(mat: mat4_t); diff --git a/base/sources/iron_raycast.c b/base/sources/iron_raycast.c index e69de29b..864e0814 100644 --- a/base/sources/iron_raycast.c +++ b/base/sources/iron_raycast.c @@ -0,0 +1,314 @@ +#include "iron_raycast.h" + +#include "iron_gc.h" +#include "iron_mat4.h" +#include "iron_vec4.h" +#include + +i32 sys_w(void); +i32 sys_h(void); + +mat4_t _raycast_vp_inv = {0}; +mat4_t _raycast_p_inv = {0}; +mat4_t _raycast_v_inv = {0}; + +ray_t *raycast_get_ray(f32 input_x, f32 input_y, camera_object_t *camera) { + vec4_t start = vec4_create(0.0, 0.0, 0.0, 0.0); + vec4_t end = vec4_create(0.0, 0.0, 0.0, 0.0); + + // Get 3D point form screen coords + // Set two vectors with opposing z values + start.x = (input_x / sys_w()) * 2.0 - 1.0; + start.y = -((input_y / sys_h()) * 2.0 - 1.0); + start.z = -1.0; + end.x = start.x; + end.y = start.y; + end.z = 1.0; + + _raycast_p_inv = mat4_inv(camera->p); + _raycast_v_inv = mat4_inv(camera->v); + _raycast_vp_inv = mat4_mult_mat(_raycast_p_inv, _raycast_v_inv); + start = vec4_apply_proj(start, _raycast_vp_inv); + end = vec4_apply_proj(end, _raycast_vp_inv); + + // Find direction from start to end + end = vec4_sub(end, start); + end = vec4_norm(end); + end.x *= camera->data->far_plane; + end.y *= camera->data->far_plane; + end.z *= camera->data->far_plane; + + return ray_create(start, end); +} + +vec4_t raycast_box_intersect(transform_t *transform, f32 input_x, f32 input_y, camera_object_t *camera) { + ray_t *ray = raycast_get_ray(input_x, input_y, camera); + vec4_t c = vec4_create(transform_world_x(transform), transform_world_y(transform), transform_world_z(transform), 0.0); + vec4_t s = vec4_create(transform->dim.x, transform->dim.y, transform->dim.z, 0.0); + return ray_intersect_box(ray, c, s); +} + +transform_t *raycast_closest_box_intersect(any_array_t *transforms, f32 input_x, f32 input_y, camera_object_t *camera) { + any_array_t *intersects = any_array_create(0); + + // Get intersects + for (i32 i = 0; i < (i32)transforms->length; ++i) { + transform_t *t = (transform_t *)transforms->buffer[i]; + vec4_t intersect = raycast_box_intersect(t, input_x, input_y, camera); + if (!vec4_isnan(intersect)) { + any_array_push(intersects, t); + } + } + + // No intersects + if (intersects->length == 0) { + return NULL; + } + + // Get closest intersect + transform_t *closest = NULL; + f32 min_dist = 100000.0; + for (i32 i = 0; i < (i32)intersects->length; ++i) { + transform_t *t = (transform_t *)intersects->buffer[i]; + f32 dist = vec4_dist(t->loc, camera->base->transform->loc); + if (dist < min_dist) { + min_dist = dist; + closest = t; + } + } + + return closest; +} + +vec4_t raycast_plane_intersect(vec4_t normal, vec4_t a, f32 input_x, f32 input_y, camera_object_t *camera) { + ray_t *ray = raycast_get_ray(input_x, input_y, camera); + plane_t plane = plane_create(); + plane_set(&plane, normal, a); + return ray_intersect_plane(ray, &plane); +} + +ray_t *ray_create(vec4_t origin, vec4_t dir) { + ray_t *raw = gc_alloc(sizeof(ray_t)); + raw->origin = origin; + raw->dir = dir; + return raw; +} + +vec4_t ray_at(ray_t *raw, f32 t) { + return vec4_add(vec4_mult(raw->dir, t), raw->origin); +} + +f32 ray_dist_to_point(ray_t *raw, vec4_t point) { + vec4_t v1 = vec4_create(0.0, 0.0, 0.0, 0.0); + f32 dir_dist = vec4_dot(vec4_sub(point, raw->origin), raw->dir); + + // Point behind the ray + if (dir_dist < 0) { + return vec4_dist(raw->origin, point); + } + + raw->dir = vec4_mult(raw->dir, dir_dist); + raw->dir = vec4_add(raw->dir, raw->origin); + + return vec4_dist(v1, point); +} + +bool ray_intersects_sphere(ray_t *raw, vec4_t sphere_center, f32 sphere_radius) { + return ray_dist_to_point(raw, sphere_center) <= sphere_radius; +} + +bool ray_intersects_plane(ray_t *raw, plane_t *plane) { + // Check if the ray lies on the plane first + f32 dist_to_point = plane_dist_to_point(plane, raw->origin); + if (dist_to_point == 0) { + return true; + } + + f32 denominator = vec4_dot(plane->normal, raw->dir); + if (denominator * dist_to_point < 0) { + return true; + } + + // Ray origin is behind the plane (and is pointing behind it) + return false; +} + +f32 ray_dist_to_plane(ray_t *raw, plane_t *plane) { + f32 denominator = vec4_dot(plane->normal, raw->dir); + if (denominator == 0) { + // Line is coplanar, return origin + if (plane_dist_to_point(plane, raw->origin) == 0) { + return 0; + } + + return -1; + } + + f32 t = -(vec4_dot(raw->origin, plane->normal) + plane->constant) / denominator; + + // Return if the ray never intersects the plane + return t >= 0 ? t : -1; +} + +vec4_t ray_intersect_plane(ray_t *raw, plane_t *plane) { + f32 t = ray_dist_to_plane(raw, plane); + if (t == -1) { + return vec4_nan(); + } + return ray_at(raw, t); +} + +vec4_t ray_intersect_box(ray_t *raw, vec4_t center, vec4_t dim) { + // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + f32 tmin; + f32 tmax; + f32 tymin; + f32 tymax; + f32 tzmin; + f32 tzmax; + + f32 half_x = dim.x / 2; + f32 half_y = dim.y / 2; + f32 half_z = dim.z / 2; + f32 box_min_x = center.x - half_x; + f32 box_min_y = center.y - half_y; + f32 box_min_z = center.z - half_z; + f32 box_max_x = center.x + half_x; + f32 box_max_y = center.y + half_y; + f32 box_max_z = center.z + half_z; + + f32 invdirx = 1.0 / raw->dir.x; + f32 invdiry = 1.0 / raw->dir.y; + f32 invdirz = 1.0 / raw->dir.z; + vec4_t origin = raw->origin; + + if (invdirx >= 0) { + tmin = (box_min_x - origin.x) * invdirx; + tmax = (box_max_x - origin.x) * invdirx; + } + else { + tmin = (box_max_x - origin.x) * invdirx; + tmax = (box_min_x - origin.x) * invdirx; + } + + if (invdiry >= 0) { + tymin = (box_min_y - origin.y) * invdiry; + tymax = (box_max_y - origin.y) * invdiry; + } + else { + tymin = (box_max_y - origin.y) * invdiry; + tymax = (box_min_y - origin.y) * invdiry; + } + + if ((tmin > tymax) || (tymin > tmax)) { + return vec4_nan(); + } + + // These lines also handle the case where tmin or tmax is nan + // (result of 0 * inf). x != x returns true if x is nan + if (tymin > tmin || tmin != tmin) { + tmin = tymin; + } + if (tymax < tmax || tmax != tmax) { + tmax = tymax; + } + + if (invdirz >= 0) { + tzmin = (box_min_z - origin.z) * invdirz; + tzmax = (box_max_z - origin.z) * invdirz; + } + else { + tzmin = (box_max_z - origin.z) * invdirz; + tzmax = (box_min_z - origin.z) * invdirz; + } + + if ((tmin > tzmax) || (tzmin > tmax)) { + return vec4_nan(); + } + if (tzmin > tmin || tmin != tmin) { + tmin = tzmin; + } + if (tzmax < tmax || tmax != tmax) { + tmax = tzmax; + } + + // Return point closest to the ray (positive side) + if (tmax < 0) { + return vec4_nan(); + } + + return ray_at(raw, tmin >= 0 ? tmin : tmax); +} + +vec4_t ray_intersect_triangle(ray_t *raw, vec4_t a, vec4_t b, vec4_t c, bool cull_backface) { + // Compute the offset origin, edges, and normal + // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp + vec4_t edge1 = vec4_sub(b, a); + vec4_t edge2 = vec4_sub(c, a); + vec4_t normal = vec4_cross(edge1, edge2); + + f32 ddn = vec4_dot(raw->dir, normal); + i32 sign; + + if (ddn > 0) { + if (cull_backface) { + return vec4_nan(); + } + sign = 1; + } + else if (ddn < 0) { + sign = -1; + ddn = -ddn; + } + else { + return vec4_nan(); + } + + vec4_t diff = vec4_sub(raw->origin, a); + f32 ddqxe2 = sign * vec4_dot(raw->dir, vec4_cross(diff, edge2)); + + // b1 < 0, no intersection + if (ddqxe2 < 0) { + return vec4_nan(); + } + + f32 dde1xq = sign * vec4_dot(raw->dir, vec4_cross(edge1, diff)); + + // b2 < 0, no intersection + if (dde1xq < 0) { + return vec4_nan(); + } + + // b1+b2 > 1, no intersection + if (ddqxe2 + dde1xq > ddn) { + return vec4_nan(); + } + + // Line intersects triangle, check if ray does. + f32 qdn = -sign * vec4_dot(diff, normal); + + // t < 0, no intersection + if (qdn < 0) { + return vec4_nan(); + } + + // Ray intersects triangle. + return ray_at(raw, qdn / ddn); +} + +plane_t plane_create(void) { + plane_t raw; + raw.normal = vec4_create(1.0, 0.0, 0.0, 0.0); + raw.constant = 0.0; + return raw; +} + +f32 plane_dist_to_point(plane_t *raw, vec4_t point) { + return vec4_dot(raw->normal, point) + raw->constant; +} + +plane_t plane_set(plane_t *raw, vec4_t normal, vec4_t point) { + raw->normal = vec4_clone(normal); + raw->constant = -vec4_dot(point, raw->normal); + return *raw; +} diff --git a/base/sources/iron_raycast.h b/base/sources/iron_raycast.h index e69de29b..adfc35c4 100644 --- a/base/sources/iron_raycast.h +++ b/base/sources/iron_raycast.h @@ -0,0 +1,37 @@ +#pragma once + +#include "engine.h" +#include "iron_vec4.h" + +extern mat4_t _raycast_vp_inv; +extern mat4_t _raycast_p_inv; +extern mat4_t _raycast_v_inv; + +typedef struct ray { + vec4_t origin; + vec4_t dir; +} ray_t; + +typedef struct plane { + vec4_t normal; + f32 constant; +} plane_t; + +ray_t *ray_create(vec4_t origin, vec4_t dir); +vec4_t ray_at(ray_t *raw, f32 t); +f32 ray_dist_to_point(ray_t *raw, vec4_t point); +bool ray_intersects_sphere(ray_t *raw, vec4_t sphere_center, f32 sphere_radius); +bool ray_intersects_plane(ray_t *raw, plane_t *plane); +f32 ray_dist_to_plane(ray_t *raw, plane_t *plane); +vec4_t ray_intersect_plane(ray_t *raw, plane_t *plane); +vec4_t ray_intersect_box(ray_t *raw, vec4_t center, vec4_t dim); +vec4_t ray_intersect_triangle(ray_t *raw, vec4_t a, vec4_t b, vec4_t c, bool cull_backface); + +plane_t plane_create(void); +f32 plane_dist_to_point(plane_t *raw, vec4_t point); +plane_t plane_set(plane_t *raw, vec4_t normal, vec4_t point); + +ray_t *raycast_get_ray(f32 input_x, f32 input_y, camera_object_t *camera); +vec4_t raycast_box_intersect(transform_t *transform, f32 input_x, f32 input_y, camera_object_t *camera); +transform_t *raycast_closest_box_intersect(any_array_t *transforms, f32 input_x, f32 input_y, camera_object_t *camera); +vec4_t raycast_plane_intersect(vec4_t normal, vec4_t a, f32 input_x, f32 input_y, camera_object_t *camera); diff --git a/base/sources/iron_shape.c b/base/sources/iron_shape.c new file mode 100644 index 00000000..b7387911 --- /dev/null +++ b/base/sources/iron_shape.c @@ -0,0 +1,299 @@ +#include "iron_shape.h" + +#include "iron_array.h" +#include "iron_mat4.h" +#include "iron_vec4.h" + +gpu_shader_t *sys_get_shader(char *name); +object_t *scene_get_child(char *name); +i32 shader_context_type_size(char *t); +i32 shader_context_type_pad(i32 offset, i32 size); + +extern i32 pipes_offset; +extern camera_object_t *scene_camera; + +i32 pipes_get_constant_location(char *type); +// i32 pipes_get_constant_location(char *type) { +// i32 size = shader_context_type_size(type); +// pipes_offset += shader_context_type_pad(pipes_offset, size); +// i32 loc = pipes_offset; +// pipes_offset += size; +// return loc; +// } + +u8 color_get_rb(i32 c); +u8 color_get_gb(i32 c); +u8 color_get_bb(i32 c); + +gpu_buffer_t *gpu_create_vertex_buffer(i32 count, gpu_vertex_structure_t *structure); +gpu_buffer_t *gpu_create_index_buffer(i32 count); +buffer_t *gpu_lock_vertex_buffer(gpu_buffer_t *buffer); +u32_array_t *gpu_lock_index_buffer(gpu_buffer_t *buffer); +void gpu_vertex_buffer_unlock(gpu_buffer_t *buffer); +void gpu_index_buffer_unlock(gpu_buffer_t *buffer); +void gpu_pipeline_compile(gpu_pipeline_t *pipeline); +gpu_pipeline_t *gpu_create_pipeline(void); +void gpu_set_pipeline(gpu_pipeline_t *pipeline); +void gpu_set_vertex_buffer(gpu_buffer_t *buffer); +void gpu_set_index_buffer(gpu_buffer_t *buffer); +void gpu_set_matrix4(i32 location, mat4_t value); +void gpu_set_float3(i32 location, f32 value1, f32 value2, f32 value3); +void gpu_draw(void); +void gpu_vertex_structure_add(gpu_vertex_structure_t *structure, const char *name, gpu_vertex_data_t data); +void buffer_set_f32(buffer_t *b, u32 p, f32 n); + +i32 line_draw_color = 0xffff0000; +f32 line_draw_strength = 0.002; +mat4_t line_draw_mat; +vec4_t line_draw_dim; +gpu_buffer_t *line_draw_vertex_buffer = NULL; +gpu_buffer_t *line_draw_index_buffer = NULL; +gpu_pipeline_t *line_draw_pipeline = NULL; +gpu_pipeline_t *line_draw_overlay_pipeline = NULL; +mat4_t line_draw_vp; +i32 line_draw_vp_loc = 0; +i32 line_draw_color_loc = 0; +buffer_t *line_draw_vb_data = NULL; +u32_array_t *line_draw_ib_data = NULL; +i32 line_draw_max_lines = 300; +i32 line_draw_max_vertices = 300 * 4; +i32 line_draw_max_indices = 300 * 6; +i32 line_draw_lines = 0; + +static vec4_t line_draw_wpos; +static vec4_t line_draw_vx = {0}; +static vec4_t line_draw_vy = {0}; +static vec4_t line_draw_vz = {0}; + +static vec4_t line_draw_v1 = {0}; +static vec4_t line_draw_v2 = {0}; +static vec4_t line_draw_t = {0}; + +static vec4_t line_draw_mid_point = {0}; +static vec4_t line_draw_mid_line = {0}; +static vec4_t line_draw_corner1 = {0}; +static vec4_t line_draw_corner2 = {0}; +static vec4_t line_draw_corner3 = {0}; +static vec4_t line_draw_corner4 = {0}; +static vec4_t line_draw_camera_look = {0}; + +gpu_buffer_t *_shape_draw_sphere_vb = NULL; +gpu_buffer_t *_shape_draw_sphere_ib = NULL; + +void line_draw_init(void) { + if (line_draw_pipeline == NULL) { + gpu_vertex_structure_t structure = {0}; + gpu_vertex_structure_add(&structure, "pos", GPU_VERTEX_DATA_F32_3X); + line_draw_pipeline = gpu_create_pipeline(); + line_draw_pipeline->input_layout = &structure; + line_draw_pipeline->fragment_shader = sys_get_shader("line.frag"); + line_draw_pipeline->vertex_shader = sys_get_shader("line.vert"); + line_draw_pipeline->depth_write = true; + line_draw_pipeline->depth_mode = GPU_COMPARE_MODE_LESS; + line_draw_pipeline->cull_mode = GPU_CULL_MODE_NONE; + line_draw_pipeline->color_attachment_count = 2; + line_draw_pipeline->color_attachment[0] = GPU_TEXTURE_FORMAT_RGBA64; + line_draw_pipeline->color_attachment[1] = GPU_TEXTURE_FORMAT_RGBA64; + line_draw_pipeline->depth_attachment_bits = 32; + gpu_pipeline_compile(line_draw_pipeline); + pipes_offset = 0; + line_draw_vp_loc = pipes_get_constant_location("mat4"); + line_draw_color_loc = pipes_get_constant_location("vec3"); + line_draw_vp = mat4_identity(); + line_draw_vertex_buffer = gpu_create_vertex_buffer(line_draw_max_vertices, &structure); + line_draw_index_buffer = gpu_create_index_buffer(line_draw_max_indices); + } + if (line_draw_overlay_pipeline == NULL) { + gpu_vertex_structure_t structure = {0}; + gpu_vertex_structure_add(&structure, "pos", GPU_VERTEX_DATA_F32_3X); + line_draw_overlay_pipeline = gpu_create_pipeline(); + line_draw_overlay_pipeline->input_layout = &structure; + line_draw_overlay_pipeline->fragment_shader = sys_get_shader("line_overlay.frag"); + line_draw_overlay_pipeline->vertex_shader = sys_get_shader("line_overlay.vert"); + line_draw_overlay_pipeline->depth_write = false; + line_draw_overlay_pipeline->depth_mode = GPU_COMPARE_MODE_ALWAYS; + line_draw_overlay_pipeline->cull_mode = GPU_CULL_MODE_NONE; + line_draw_overlay_pipeline->color_attachment_count = 1; + line_draw_overlay_pipeline->color_attachment[0] = GPU_TEXTURE_FORMAT_RGBA64; + gpu_pipeline_compile(line_draw_overlay_pipeline); + } +} + +void line_draw_render(mat4_t matrix) { + line_draw_mat = matrix; + line_draw_dim = mat4_get_scale(matrix); + + line_draw_begin(); + line_draw_bounds(line_draw_mat, line_draw_dim); + line_draw_end(); +} + +void line_draw_bounds(mat4_t mat, vec4_t dim) { + line_draw_wpos = mat4_get_loc(mat); + f32 dx = dim.x / 2; + f32 dy = dim.y / 2; + f32 dz = dim.z / 2; + + vec4_t up = mat4_up(mat); + vec4_t look = mat4_look(mat); + vec4_t right = mat4_right(mat); + up = vec4_norm(up); + look = vec4_norm(look); + right = vec4_norm(right); + + line_draw_vx = vec4_mult(right, dx); + line_draw_vy = vec4_mult(look, dy); + line_draw_vz = vec4_mult(up, dz); + + line_draw_lineb(-1, -1, -1, 1, -1, -1); + line_draw_lineb(-1, 1, -1, 1, 1, -1); + line_draw_lineb(-1, -1, 1, 1, -1, 1); + line_draw_lineb(-1, 1, 1, 1, 1, 1); + + line_draw_lineb(-1, -1, -1, -1, 1, -1); + line_draw_lineb(-1, -1, 1, -1, 1, 1); + line_draw_lineb(1, -1, -1, 1, 1, -1); + line_draw_lineb(1, -1, 1, 1, 1, 1); + + line_draw_lineb(-1, -1, -1, -1, -1, 1); + line_draw_lineb(-1, 1, -1, -1, 1, 1); + line_draw_lineb(1, -1, -1, 1, -1, 1); + line_draw_lineb(1, 1, -1, 1, 1, 1); +} + +void line_draw_lineb(i32 a, i32 b, i32 c, i32 d, i32 e, i32 f) { + line_draw_v1 = vec4_clone(line_draw_wpos); + + line_draw_t = vec4_mult(line_draw_vx, (f32)a); + line_draw_v1 = vec4_add(line_draw_v1, line_draw_t); + + line_draw_t = vec4_mult(line_draw_vy, (f32)b); + line_draw_v1 = vec4_add(line_draw_v1, line_draw_t); + + line_draw_t = vec4_mult(line_draw_vz, (f32)c); + line_draw_v1 = vec4_add(line_draw_v1, line_draw_t); + + line_draw_v2 = vec4_clone(line_draw_wpos); + + line_draw_t = vec4_mult(line_draw_vx, (f32)d); + line_draw_v2 = vec4_add(line_draw_v2, line_draw_t); + + line_draw_t = vec4_mult(line_draw_vy, (f32)e); + line_draw_v2 = vec4_add(line_draw_v2, line_draw_t); + + line_draw_t = vec4_mult(line_draw_vz, (f32)f); + line_draw_v2 = vec4_add(line_draw_v2, line_draw_t); + + line_draw_line(line_draw_v1.x, line_draw_v1.y, line_draw_v1.z, line_draw_v2.x, line_draw_v2.y, line_draw_v2.z); +} + +void line_draw_line(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2) { + if (line_draw_lines >= line_draw_max_lines) { + line_draw_end(); + line_draw_begin(); + } + + line_draw_mid_point = vec4_mult(vec4_create(x1 + x2, y1 + y2, z1 + z2, 0.0), 0.5); + + line_draw_mid_line = vec4_sub(vec4_create(x1, y1, z1, 0.0), line_draw_mid_point); + + line_draw_camera_look = vec4_sub(mat4_get_loc(scene_camera->base->transform->world), line_draw_mid_point); + + vec4_t line_width = vec4_cross(line_draw_camera_look, line_draw_mid_line); + line_width = vec4_norm(line_width); + line_width = vec4_mult(line_width, line_draw_strength); + + line_draw_corner1 = vec4_add(vec4_create(x1, y1, z1, 0.0), line_width); + line_draw_corner2 = vec4_sub(vec4_create(x1, y1, z1, 0.0), line_width); + line_draw_corner3 = vec4_sub(vec4_create(x2, y2, z2, 0.0), line_width); + line_draw_corner4 = vec4_add(vec4_create(x2, y2, z2, 0.0), line_width); + + i32 i = line_draw_lines * 12; // 4 * 3 (structure len) + + buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner1.x); + buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner1.y); + buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner1.z); + + i += 3; + buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner2.x); + buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner2.y); + buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner2.z); + + i += 3; + buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner3.x); + buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner3.y); + buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner3.z); + + i += 3; + buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner4.x); + buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner4.y); + buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner4.z); + + i = line_draw_lines * 6; + line_draw_ib_data->buffer[i] = line_draw_lines * 4; + line_draw_ib_data->buffer[i + 1] = line_draw_lines * 4 + 1; + line_draw_ib_data->buffer[i + 2] = line_draw_lines * 4 + 2; + line_draw_ib_data->buffer[i + 3] = line_draw_lines * 4 + 2; + line_draw_ib_data->buffer[i + 4] = line_draw_lines * 4 + 3; + line_draw_ib_data->buffer[i + 5] = line_draw_lines * 4; + + line_draw_lines++; +} + +void line_draw_begin(void) { + line_draw_init(); + line_draw_lines = 0; + line_draw_vb_data = gpu_lock_vertex_buffer(line_draw_vertex_buffer); + line_draw_ib_data = gpu_lock_index_buffer(line_draw_index_buffer); + for (i32 i = 0; i < line_draw_max_indices; ++i) { + line_draw_ib_data->buffer[i] = 0; + } +} + +void line_draw_end(void) { + gpu_vertex_buffer_unlock(line_draw_vertex_buffer); + gpu_index_buffer_unlock(line_draw_index_buffer); + + gpu_set_vertex_buffer(line_draw_vertex_buffer); + gpu_set_index_buffer(line_draw_index_buffer); + gpu_set_pipeline(line_draw_pipeline); + line_draw_vp = mat4_clone(scene_camera->vp); + gpu_set_matrix4(line_draw_vp_loc, line_draw_vp); + gpu_set_float3(line_draw_color_loc, color_get_rb(line_draw_color) / 255.0, color_get_gb(line_draw_color) / 255.0, color_get_bb(line_draw_color) / 255.0); + gpu_draw(); +} + +void shape_draw_sphere(mat4_t mat) { + line_draw_init(); + + if (_shape_draw_sphere_vb == NULL) { + object_t *child = scene_get_child(".Sphere"); + mesh_object_t *sphere = (mesh_object_t *)child->ext; + mesh_data_t *md = sphere->data; + + i16_array_t *posa = ((vertex_array_t *)md->vertex_arrays->buffer[0])->values; + gpu_vertex_structure_t structure = {0}; + gpu_vertex_structure_add(&structure, "pos", GPU_VERTEX_DATA_F32_3X); + _shape_draw_sphere_vb = gpu_create_vertex_buffer(posa->length, &structure); + buffer_t *data = gpu_lock_vertex_buffer(_shape_draw_sphere_vb); + for (i32 i = 0; i < (i32)posa->length / 4; ++i) { + buffer_set_f32(data, (i * 3 + 0) * 4, posa->buffer[i * 4 + 0] / 32767.0); + buffer_set_f32(data, (i * 3 + 1) * 4, posa->buffer[i * 4 + 1] / 32767.0); + buffer_set_f32(data, (i * 3 + 2) * 4, posa->buffer[i * 4 + 2] / 32767.0); + } + gpu_vertex_buffer_unlock(_shape_draw_sphere_vb); + _shape_draw_sphere_ib = md->_->index_buffer; + } + + gpu_set_vertex_buffer(_shape_draw_sphere_vb); + gpu_set_index_buffer(_shape_draw_sphere_ib); + gpu_set_pipeline(line_draw_overlay_pipeline); + f32 f = line_draw_strength * 50; + line_draw_vp = mat4_clone(mat); + line_draw_vp = mat4_scale(line_draw_vp, vec4_create(f, f, f, 0.0)); + line_draw_vp = mat4_mult_mat(line_draw_vp, scene_camera->v); + line_draw_vp = mat4_mult_mat(line_draw_vp, scene_camera->p); + gpu_set_matrix4(line_draw_vp_loc, line_draw_vp); + gpu_set_float3(line_draw_color_loc, color_get_rb(line_draw_color) / 255.0, color_get_gb(line_draw_color) / 255.0, color_get_bb(line_draw_color) / 255.0); + gpu_draw(); +} diff --git a/base/sources/iron_shape.h b/base/sources/iron_shape.h new file mode 100644 index 00000000..1f2d63dc --- /dev/null +++ b/base/sources/iron_shape.h @@ -0,0 +1,36 @@ +#pragma once + +#include "engine.h" +#include "iron_global.h" +#include "iron_vec4.h" + +extern i32 line_draw_color; +extern f32 line_draw_strength; +extern mat4_t line_draw_mat; +extern vec4_t line_draw_dim; +extern gpu_buffer_t *line_draw_vertex_buffer; +extern gpu_buffer_t *line_draw_index_buffer; +extern gpu_pipeline_t *line_draw_pipeline; +extern gpu_pipeline_t *line_draw_overlay_pipeline; +extern mat4_t line_draw_vp; +extern i32 line_draw_vp_loc; +extern i32 line_draw_color_loc; +extern buffer_t *line_draw_vb_data; +extern u32_array_t *line_draw_ib_data; +extern i32 line_draw_max_lines; +extern i32 line_draw_max_vertices; +extern i32 line_draw_max_indices; +extern i32 line_draw_lines; + +void line_draw_init(void); +void line_draw_render(mat4_t matrix); +void line_draw_bounds(mat4_t mat, vec4_t dim); +void line_draw_lineb(i32 a, i32 b, i32 c, i32 d, i32 e, i32 f); +void line_draw_line(f32 x1, f32 y1, f32 z1, f32 x2, f32 y2, f32 z2); +void line_draw_begin(void); +void line_draw_end(void); + +extern gpu_buffer_t *_shape_draw_sphere_vb; +extern gpu_buffer_t *_shape_draw_sphere_ib; + +void shape_draw_sphere(mat4_t mat); diff --git a/base/sources/ts/camera_object.ts b/base/sources/ts/camera_object.ts deleted file mode 100644 index cf57b6cd..00000000 --- a/base/sources/ts/camera_object.ts +++ /dev/null @@ -1,202 +0,0 @@ - -type camera_object_t = { - base?: object_t; - data?: camera_data_t; - p?: mat4_t; - no_jitter_p?: mat4_t; - frame?: i32; - v?: mat4_t; - vp?: mat4_t; - frustum_planes?: frustum_plane_t[]; -}; - -let _camera_object_sphere_center: vec4_t = vec4_create(); -let camera_object_taa_frames: i32 = 1; - -function camera_object_create(data: camera_data_t): camera_object_t { - let raw: camera_object_t = {}; - raw.no_jitter_p = mat4_identity(); - raw.frame = 0; - raw.base = object_create(false); - raw.base.ext = raw; - raw.base.ext_type = "camera_object_t"; - raw.data = data; - - camera_object_build_proj(raw); - - raw.v = mat4_identity(); - raw.vp = mat4_identity(); - - if (data.frustum_culling) { - raw.frustum_planes = []; - for (let i: i32 = 0; i < 6; ++i) { - array_push(raw.frustum_planes, frustum_plane_create()); - } - } - - array_push(scene_cameras, raw); - return raw; -} - -function camera_object_build_proj(raw: camera_object_t, screen_aspect: f32 = -1.0) { - if (raw.data.ortho != null) { - raw.p = mat4_ortho(raw.data.ortho[0], raw.data.ortho[1], raw.data.ortho[2], raw.data.ortho[3], -raw.data.far_plane, raw.data.far_plane); - } - else { - if (screen_aspect < 0) { - screen_aspect = sys_w() / sys_h(); - } - let aspect: f32 = raw.data.aspect ? raw.data.aspect : screen_aspect; - raw.p = mat4_persp(raw.data.fov, aspect, raw.data.near_plane, raw.data.far_plane); - } - raw.no_jitter_p = mat4_clone(raw.p); -} - -function camera_object_remove(raw: camera_object_t) { - array_remove(scene_cameras, raw); - object_remove_super(raw.base); -} - -function camera_object_render_frame(raw: camera_object_t) { - camera_object_proj_jitter(raw); - camera_object_build_mat(raw); - render_path_render_frame(); -} - -function camera_object_proj_jitter(raw: camera_object_t) { - let w: i32 = render_path_current_w; - let h: i32 = render_path_current_h; - raw.p = mat4_clone(raw.no_jitter_p); - - let i: i32 = raw.frame % camera_object_taa_frames; - let x: f32 = 0.0; - let y: f32 = 0.0; - - if (i == 0) { - x = 0.5; - y = 0.333; - } - else if (i == 1) { - x = -0.5; - y = -0.333; - } - else if (i == 2) { - x = 0.25; - y = 0.111; - } - else if (i == 3) { - x = -0.25; - y = -0.111; - } - else if (i == 4) { - x = 0.375; - y = 0.444; - } - else { - x = -0.375; - y = -0.444; - } - x *= 2; - y *= 2; - - raw.p.m20 += x / w; - raw.p.m21 += y / h; - raw.frame++; -} - -function camera_object_build_mat(raw: camera_object_t) { - transform_build_matrix(raw.base.transform); - - raw.v = mat4_inv(raw.base.transform.world); - raw.vp = mat4_mult_mat(raw.v, raw.p); - - if (raw.data.frustum_culling) { - camera_object_build_view_frustum(raw.vp, raw.frustum_planes); - } -} - -function camera_object_right(raw: camera_object_t): vec4_t { - return vec4_norm(vec4_create(raw.base.transform.local.m00, raw.base.transform.local.m01, raw.base.transform.local.m02)); -} - -function camera_object_up(raw: camera_object_t): vec4_t { - return vec4_norm(vec4_create(raw.base.transform.local.m10, raw.base.transform.local.m11, raw.base.transform.local.m12)); -} - -function camera_object_look(raw: camera_object_t): vec4_t { - return vec4_norm(vec4_create(-raw.base.transform.local.m20, -raw.base.transform.local.m21, -raw.base.transform.local.m22)); -} - -function camera_object_right_world(raw: camera_object_t): vec4_t { - return vec4_norm(vec4_create(raw.base.transform.world.m00, raw.base.transform.world.m01, raw.base.transform.world.m02)); -} - -function camera_object_up_world(raw: camera_object_t): vec4_t { - return vec4_norm(vec4_create(raw.base.transform.world.m10, raw.base.transform.world.m11, raw.base.transform.world.m12)); -} - -function camera_object_look_world(raw: camera_object_t): vec4_t { - return vec4_norm(vec4_create(-raw.base.transform.world.m20, -raw.base.transform.world.m21, -raw.base.transform.world.m22)); -} - -function camera_object_build_view_frustum(vp: mat4_t, frustum_planes: frustum_plane_t[]) { - // Left plane - frustum_plane_set_components(frustum_planes[0], vp.m03 + vp.m00, vp.m13 + vp.m10, vp.m23 + vp.m20, vp.m33 + vp.m30); - // Right plane - frustum_plane_set_components(frustum_planes[1], vp.m03 - vp.m00, vp.m13 - vp.m10, vp.m23 - vp.m20, vp.m33 - vp.m30); - // Top plane - frustum_plane_set_components(frustum_planes[2], vp.m03 - vp.m01, vp.m13 - vp.m11, vp.m23 - vp.m21, vp.m33 - vp.m31); - // Bottom plane - frustum_plane_set_components(frustum_planes[3], vp.m03 + vp.m01, vp.m13 + vp.m11, vp.m23 + vp.m21, vp.m33 + vp.m31); - // Near plane - frustum_plane_set_components(frustum_planes[4], vp.m02, vp.m12, vp.m22, vp.m32); - // Far plane - frustum_plane_set_components(frustum_planes[5], vp.m03 - vp.m02, vp.m13 - vp.m12, vp.m23 - vp.m22, vp.m33 - vp.m32); - // Normalize planes - for (let i: i32 = 0; i < frustum_planes.length; ++i) { - let plane: frustum_plane_t = frustum_planes[i]; - frustum_plane_normalize(plane); - } -} - -function camera_object_sphere_in_frustum(frustum_planes: frustum_plane_t[], t: transform_t, radius_scale: f32 = 1.0, offset_x: f32 = 0.0, offset_y: f32 = 0.0, - offset_z: f32 = 0.0): bool { - // Use scale when radius is changing - let radius: f32 = t.radius * radius_scale; - for (let i: i32 = 0; i < frustum_planes.length; ++i) { - let plane: frustum_plane_t = frustum_planes[i]; - _camera_object_sphere_center = vec4_create(transform_world_x(t) + offset_x, transform_world_y(t) + offset_y, transform_world_z(t) + offset_z); - // Outside the frustum - if (frustum_plane_dist_to_sphere(plane, _camera_object_sphere_center, radius) + radius * 2 < 0) { - return false; - } - } - return true; -} - -type frustum_plane_t = { - normal?: vec4_t; - constant?: f32; -}; - -function frustum_plane_create(): frustum_plane_t { - let raw: frustum_plane_t = {}; - raw.normal = vec4_create(1.0, 0.0, 0.0); - raw.constant = 0.0; - return raw; -} - -function frustum_plane_normalize(raw: frustum_plane_t) { - let inv_normal_length: f32 = 1.0 / vec4_len(raw.normal); - raw.normal = vec4_mult(raw.normal, inv_normal_length); - raw.constant *= inv_normal_length; -} - -function frustum_plane_dist_to_sphere(raw: frustum_plane_t, sphere_center: vec4_t, sphere_radius: f32): f32 { - return (vec4_dot(raw.normal, sphere_center) + raw.constant) - sphere_radius; -} - -function frustum_plane_set_components(raw: frustum_plane_t, x: f32, y: f32, z: f32, w: f32) { - raw.normal = vec4_create(x, y, z); - raw.constant = w; -} diff --git a/base/sources/ts/line_draw.ts b/base/sources/ts/line_draw.ts deleted file mode 100644 index 3bf7ac22..00000000 --- a/base/sources/ts/line_draw.ts +++ /dev/null @@ -1,281 +0,0 @@ - -let line_draw_color: color_t = 0xffff0000; -let line_draw_strength: f32 = 0.002; -let line_draw_mat: mat4_t = mat4_nan(); -let line_draw_dim: vec4_t = vec4_nan(); - -let line_draw_vertex_buffer: gpu_buffer_t; -let line_draw_index_buffer: gpu_buffer_t; -let line_draw_pipeline: gpu_pipeline_t = null; -let line_draw_overlay_pipeline: gpu_pipeline_t = null; - -let line_draw_vp: mat4_t; -let line_draw_vp_loc: i32; -let line_draw_color_loc: i32; - -let line_draw_vb_data: buffer_t; -let line_draw_ib_data: u32_array_t; - -let line_draw_max_lines: i32 = 300; -let line_draw_max_vertices: i32 = line_draw_max_lines * 4; -let line_draw_max_indices: i32 = line_draw_max_lines * 6; -let line_draw_lines: i32 = 0; - -let line_draw_wpos: vec4_t; -let line_draw_vx: vec4_t = vec4_create(); -let line_draw_vy: vec4_t = vec4_create(); -let line_draw_vz: vec4_t = vec4_create(); - -let line_draw_v1: vec4_t = vec4_create(); -let line_draw_v2: vec4_t = vec4_create(); -let line_draw_t: vec4_t = vec4_create(); - -let line_draw_mid_point: vec4_t = vec4_create(); -let line_draw_mid_line: vec4_t = vec4_create(); -let line_draw_corner1: vec4_t = vec4_create(); -let line_draw_corner2: vec4_t = vec4_create(); -let line_draw_corner3: vec4_t = vec4_create(); -let line_draw_corner4: vec4_t = vec4_create(); -let line_draw_camera_look: vec4_t = vec4_create(); - -function line_draw_init() { - if (line_draw_pipeline == null) { - let structure: gpu_vertex_structure_t = {}; - gpu_vertex_struct_add(structure, "pos", gpu_vertex_data_t.F32_3X); - line_draw_pipeline = gpu_create_pipeline(); - line_draw_pipeline.input_layout = structure; - line_draw_pipeline.fragment_shader = sys_get_shader("line.frag"); - line_draw_pipeline.vertex_shader = sys_get_shader("line.vert"); - line_draw_pipeline.depth_write = true; - line_draw_pipeline.depth_mode = gpu_compare_mode_t.LESS; - line_draw_pipeline.cull_mode = gpu_cull_mode_t.NONE; - line_draw_pipeline.color_attachment_count = 2; - ARRAY_ACCESS(line_draw_pipeline.color_attachment, 0) = gpu_texture_format_t.RGBA64; - ARRAY_ACCESS(line_draw_pipeline.color_attachment, 1) = gpu_texture_format_t.RGBA64; - line_draw_pipeline.depth_attachment_bits = 32; - gpu_pipeline_compile(line_draw_pipeline); - pipes_offset = 0; - line_draw_vp_loc = pipes_get_constant_location("mat4"); - line_draw_color_loc = pipes_get_constant_location("vec3"); - line_draw_vp = mat4_identity(); - line_draw_vertex_buffer = gpu_create_vertex_buffer(line_draw_max_vertices, structure); - line_draw_index_buffer = gpu_create_index_buffer(line_draw_max_indices); - } - if (line_draw_overlay_pipeline == null) { - let structure: gpu_vertex_structure_t = {}; - gpu_vertex_struct_add(structure, "pos", gpu_vertex_data_t.F32_3X); - line_draw_overlay_pipeline = gpu_create_pipeline(); - line_draw_overlay_pipeline.input_layout = structure; - line_draw_overlay_pipeline.fragment_shader = sys_get_shader("line_overlay.frag"); - line_draw_overlay_pipeline.vertex_shader = sys_get_shader("line_overlay.vert"); - line_draw_overlay_pipeline.depth_write = false; - line_draw_overlay_pipeline.depth_mode = gpu_compare_mode_t.ALWAYS; - line_draw_overlay_pipeline.cull_mode = gpu_cull_mode_t.NONE; - line_draw_overlay_pipeline.color_attachment_count = 1; - ARRAY_ACCESS(line_draw_overlay_pipeline.color_attachment, 0) = gpu_texture_format_t.RGBA64; - gpu_pipeline_compile(line_draw_overlay_pipeline); - } -} - -function line_draw_render(matrix: mat4_t) { - line_draw_mat = matrix; - line_draw_dim = mat4_get_scale(matrix); - - line_draw_begin(); - line_draw_bounds(line_draw_mat, line_draw_dim); - line_draw_end(); -} - -function line_draw_bounds(mat: mat4_t, dim: vec4_t) { - line_draw_wpos = mat4_get_loc(mat); - let dx: f32 = dim.x / 2; - let dy: f32 = dim.y / 2; - let dz: f32 = dim.z / 2; - - let up: vec4_t = mat4_up(mat); - let look: vec4_t = mat4_look(mat); - let right: vec4_t = mat4_right(mat); - up = vec4_norm(up); - look = vec4_norm(look); - right = vec4_norm(right); - - line_draw_vx = vec4_clone(right); - line_draw_vx = vec4_mult(line_draw_vx, dx); - line_draw_vy = vec4_clone(look); - line_draw_vy = vec4_mult(line_draw_vy, dy); - line_draw_vz = vec4_clone(up); - line_draw_vz = vec4_mult(line_draw_vz, dz); - - line_draw_lineb(-1, -1, -1, 1, -1, -1); - line_draw_lineb(-1, 1, -1, 1, 1, -1); - line_draw_lineb(-1, -1, 1, 1, -1, 1); - line_draw_lineb(-1, 1, 1, 1, 1, 1); - - line_draw_lineb(-1, -1, -1, -1, 1, -1); - line_draw_lineb(-1, -1, 1, -1, 1, 1); - line_draw_lineb(1, -1, -1, 1, 1, -1); - line_draw_lineb(1, -1, 1, 1, 1, 1); - - line_draw_lineb(-1, -1, -1, -1, -1, 1); - line_draw_lineb(-1, 1, -1, -1, 1, 1); - line_draw_lineb(1, -1, -1, 1, -1, 1); - line_draw_lineb(1, 1, -1, 1, 1, 1); -} - -function line_draw_lineb(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) { - line_draw_v1 = vec4_clone(line_draw_wpos); - - line_draw_t = vec4_clone(line_draw_vx); - line_draw_t = vec4_mult(line_draw_t, a); - line_draw_v1 = vec4_add(line_draw_v1, line_draw_t); - - line_draw_t = vec4_clone(line_draw_vy); - line_draw_t = vec4_mult(line_draw_t, b); - line_draw_v1 = vec4_add(line_draw_v1, line_draw_t); - - line_draw_t = vec4_clone(line_draw_vz); - line_draw_t = vec4_mult(line_draw_t, c); - line_draw_v1 = vec4_add(line_draw_v1, line_draw_t); - - line_draw_v2 = vec4_clone(line_draw_wpos); - - line_draw_t = vec4_clone(line_draw_vx); - line_draw_t = vec4_mult(line_draw_t, d); - line_draw_v2 = vec4_add(line_draw_v2, line_draw_t); - - line_draw_t = vec4_clone(line_draw_vy); - line_draw_t = vec4_mult(line_draw_t, e); - line_draw_v2 = vec4_add(line_draw_v2, line_draw_t); - - line_draw_t = vec4_clone(line_draw_vz); - line_draw_t = vec4_mult(line_draw_t, f); - line_draw_v2 = vec4_add(line_draw_v2, line_draw_t); - - line_draw_line(line_draw_v1.x, line_draw_v1.y, line_draw_v1.z, line_draw_v2.x, line_draw_v2.y, line_draw_v2.z); -} - -function line_draw_line(x1: f32, y1: f32, z1: f32, x2: f32, y2: f32, z2: f32) { - if (line_draw_lines >= line_draw_max_lines) { - line_draw_end(); - line_draw_begin(); - } - - line_draw_mid_point = vec4_create(x1 + x2, y1 + y2, z1 + z2); - line_draw_mid_point = vec4_mult(line_draw_mid_point, 0.5); - - line_draw_mid_line = vec4_create(x1, y1, z1); - line_draw_mid_line = vec4_sub(line_draw_mid_line, line_draw_mid_point); - - let camera: camera_object_t = scene_camera; - line_draw_camera_look = mat4_get_loc(camera.base.transform.world); - line_draw_camera_look = vec4_sub(line_draw_camera_look, line_draw_mid_point); - - let line_width: vec4_t = vec4_cross(line_draw_camera_look, line_draw_mid_line); - line_width = vec4_norm(line_width); - line_width = vec4_mult(line_width, line_draw_strength); - - line_draw_corner1 = vec4_create(x1, y1, z1); - line_draw_corner1 = vec4_add(line_draw_corner1, line_width); - - line_draw_corner2 = vec4_create(x1, y1, z1); - line_draw_corner2 = vec4_sub(line_draw_corner2, line_width); - - line_draw_corner3 = vec4_create(x2, y2, z2); - line_draw_corner3 = vec4_sub(line_draw_corner3, line_width); - - line_draw_corner4 = vec4_create(x2, y2, z2); - line_draw_corner4 = vec4_add(line_draw_corner4, line_width); - - let i: i32 = line_draw_lines * 12; // 4 * 3 (structure len) - - buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner1.x); - buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner1.y); - buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner1.z); - - i += 3; - buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner2.x); - buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner2.y); - buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner2.z); - - i += 3; - buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner3.x); - buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner3.y); - buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner3.z); - - i += 3; - buffer_set_f32(line_draw_vb_data, (i + 0) * 4, line_draw_corner4.x); - buffer_set_f32(line_draw_vb_data, (i + 1) * 4, line_draw_corner4.y); - buffer_set_f32(line_draw_vb_data, (i + 2) * 4, line_draw_corner4.z); - - i = line_draw_lines * 6; - line_draw_ib_data[i] = line_draw_lines * 4; - line_draw_ib_data[i + 1] = line_draw_lines * 4 + 1; - line_draw_ib_data[i + 2] = line_draw_lines * 4 + 2; - line_draw_ib_data[i + 3] = line_draw_lines * 4 + 2; - line_draw_ib_data[i + 4] = line_draw_lines * 4 + 3; - line_draw_ib_data[i + 5] = line_draw_lines * 4; - - line_draw_lines++; -} - -function line_draw_begin() { - line_draw_init(); - line_draw_lines = 0; - line_draw_vb_data = gpu_lock_vertex_buffer(line_draw_vertex_buffer); - line_draw_ib_data = gpu_lock_index_buffer(line_draw_index_buffer); - for (let i: i32 = 0; i < line_draw_max_indices; ++i) { - line_draw_ib_data[i] = 0; - } -} - -function line_draw_end() { - gpu_vertex_buffer_unlock(line_draw_vertex_buffer); - gpu_index_buffer_unlock(line_draw_index_buffer); - - gpu_set_vertex_buffer(line_draw_vertex_buffer); - gpu_set_index_buffer(line_draw_index_buffer); - gpu_set_pipeline(line_draw_pipeline); - let camera: camera_object_t = scene_camera; - line_draw_vp = mat4_clone(camera.vp); - gpu_set_matrix4(line_draw_vp_loc, line_draw_vp); - gpu_set_float3(line_draw_color_loc, color_get_rb(line_draw_color) / 255, color_get_gb(line_draw_color) / 255, color_get_bb(line_draw_color) / 255); - gpu_draw(); -} - -let _shape_draw_sphere_vb: gpu_buffer_t = null; -let _shape_draw_sphere_ib: gpu_buffer_t = null; - -function shape_draw_sphere(mat: mat4_t) { - line_draw_init(); - - if (_shape_draw_sphere_vb == null) { - let sphere: mesh_object_t = scene_get_child(".Sphere").ext; - let md: mesh_data_t = sphere.data; - - let posa: i16_array_t = md.vertex_arrays[0].values; - let structure: gpu_vertex_structure_t = {}; - gpu_vertex_struct_add(structure, "pos", gpu_vertex_data_t.F32_3X); - _shape_draw_sphere_vb = gpu_create_vertex_buffer(posa.length, structure); - let data: buffer_t = gpu_lock_vertex_buffer(_shape_draw_sphere_vb); - for (let i: i32 = 0; i < posa.length / 4; ++i) { - buffer_set_f32(data, (i * 3 + 0) * 4, posa[i * 4 + 0] / 32767); - buffer_set_f32(data, (i * 3 + 1) * 4, posa[i * 4 + 1] / 32767); - buffer_set_f32(data, (i * 3 + 2) * 4, posa[i * 4 + 2] / 32767); - } - gpu_vertex_buffer_unlock(_shape_draw_sphere_vb); - _shape_draw_sphere_ib = md._.index_buffer; - } - - gpu_set_vertex_buffer(_shape_draw_sphere_vb); - gpu_set_index_buffer(_shape_draw_sphere_ib); - gpu_set_pipeline(line_draw_overlay_pipeline); - let camera: camera_object_t = scene_camera; - line_draw_vp = mat4_clone(mat); - let f: f32 = line_draw_strength * 50; - line_draw_vp = mat4_scale(line_draw_vp, vec4_create(f, f, f)); - line_draw_vp = mat4_mult_mat(line_draw_vp, camera.v); - line_draw_vp = mat4_mult_mat(line_draw_vp, camera.p); - gpu_set_matrix4(line_draw_vp_loc, line_draw_vp); - gpu_set_float3(line_draw_color_loc, color_get_rb(line_draw_color) / 255, color_get_gb(line_draw_color) / 255, color_get_bb(line_draw_color) / 255); - gpu_draw(); -} diff --git a/base/sources/ts/mesh_object.ts b/base/sources/ts/mesh_object.ts deleted file mode 100644 index 92b13a6e..00000000 --- a/base/sources/ts/mesh_object.ts +++ /dev/null @@ -1,109 +0,0 @@ - -type mesh_object_t = { - base?: object_t; - data?: mesh_data_t; - material?: material_data_t; - camera_dist?: f32; - frustum_culling?: bool; - skip_context?: string; // Do not draw this context - force_context?: string; // Draw only this context -}; - -let _mesh_object_last_pipeline: gpu_pipeline_t = null; - -function mesh_object_create(data: mesh_data_t, material: material_data_t): mesh_object_t { - let raw: mesh_object_t = {}; - raw.frustum_culling = true; - raw.base = object_create(false); - raw.base.ext = raw; - raw.base.ext_type = "mesh_object_t"; - - raw.material = material; - mesh_object_set_data(raw, data); - array_push(scene_meshes, raw); - return raw; -} - -function mesh_object_set_data(raw: mesh_object_t, data: mesh_data_t) { - raw.data = data; - // Scale-up packed (-1,1) mesh coords - raw.base.transform.scale_world = data.scale_pos; -} - -function mesh_object_remove(raw: mesh_object_t) { - array_remove(scene_meshes, raw); - object_remove_super(raw.base); -} - -function mesh_object_cull_material(raw: mesh_object_t, context: string): bool { - // Skip render if material does not contain current context - if (!mesh_object_valid_context(raw, raw.material, context)) { - raw.base.culled = true; - return true; - } - if (raw.skip_context == context) { - raw.base.culled = true; - return true; - } - if (raw.force_context != null && raw.force_context != context) { - raw.base.culled = true; - return true; - } - raw.base.culled = false; - return false; -} - -function mesh_object_cull_mesh(raw: mesh_object_t, context: string, camera: camera_object_t): bool { - if (camera.data.frustum_culling && raw.frustum_culling) { - let radius_scale: f32 = 1.0; - let frustum_planes: frustum_plane_t[] = camera.frustum_planes; - if (!camera_object_sphere_in_frustum(frustum_planes, raw.base.transform, radius_scale)) { - raw.base.culled = true; - return true; - } - } - raw.base.culled = false; - return false; -} - -function mesh_object_render(raw: mesh_object_t, context: string, bind_params: string[]) { - if (!raw.base.visible) { - return; // Skip render if object is hidden - } - if (mesh_object_cull_mesh(raw, context, scene_camera)) { - return; - } - if (mesh_object_cull_material(raw, context)) { - return; - } - - uniforms_pos_unpack = raw.data.scale_pos; - uniforms_tex_unpack = raw.data.scale_tex; - transform_update(raw.base.transform); - - let scontext: shader_context_t = null; - let mcontext: material_context_t = null; - let mat: material_data_t = raw.material; - for (let j: i32 = 0; j < mat.contexts.length; ++j) { - if (mat.contexts[j].name == context) { - scontext = shader_data_get_context(mat._.shader, context); - mcontext = mat.contexts[j]; - break; - } - } - - if (scontext._.pipe != _mesh_object_last_pipeline) { - gpu_set_pipeline(scontext._.pipe); - _mesh_object_last_pipeline = scontext._.pipe; - } - uniforms_set_context_consts(scontext, bind_params); - uniforms_set_obj_consts(scontext, raw.base); - uniforms_set_material_consts(scontext, mcontext); - gpu_set_vertex_buffer(raw.data._.vertex_buffer); - gpu_set_index_buffer(raw.data._.index_buffer); - gpu_draw(); -} - -function mesh_object_valid_context(raw: mesh_object_t, mat: material_data_t, context: string): bool { - return material_data_get_context(mat, context) != null; -} diff --git a/base/sources/ts/raycast.ts b/base/sources/ts/raycast.ts deleted file mode 100644 index b24e5386..00000000 --- a/base/sources/ts/raycast.ts +++ /dev/null @@ -1,326 +0,0 @@ - -type ray_t = { - origin?: vec4_t; - dir?: vec4_t; -}; - -type plane_t = { - normal?: vec4_t; - constant?: f32; -}; - -let _raycast_vp_inv: mat4_t = mat4_identity(); -let _raycast_p_inv: mat4_t = mat4_identity(); -let _raycast_v_inv: mat4_t = mat4_identity(); - -function raycast_get_ray(input_x: f32, input_y: f32, camera: camera_object_t): ray_t { - let start: vec4_t = vec4_create(); - let end: vec4_t = vec4_create(); - - // Get 3D point form screen coords - // Set two vectors with opposing z values - start.x = (input_x / sys_w()) * 2.0 - 1.0; - start.y = -((input_y / sys_h()) * 2.0 - 1.0); - start.z = -1.0; - end.x = start.x; - end.y = start.y; - end.z = 1.0; - - _raycast_p_inv = mat4_inv(camera.p); - _raycast_v_inv = mat4_inv(camera.v); - _raycast_vp_inv = mat4_mult_mat(_raycast_p_inv, _raycast_v_inv); - start = vec4_apply_proj(start, _raycast_vp_inv); - end = vec4_apply_proj(end, _raycast_vp_inv); - - // Find direction from start to end - end = vec4_sub(end, start); - end = vec4_norm(end); - end.x *= camera.data.far_plane; - end.y *= camera.data.far_plane; - end.z *= camera.data.far_plane; - - return ray_create(start, end); -} - -function raycast_box_intersect(transform: transform_t, input_x: f32, input_y: f32, camera: camera_object_t): vec4_t { - let ray: ray_t = raycast_get_ray(input_x, input_y, camera); - - let t: transform_t = transform; - let c: vec4_t = vec4_create(transform_world_x(t), transform_world_y(t), transform_world_z(t)); - let s: vec4_t = vec4_create(t.dim.x, t.dim.y, t.dim.z); - return ray_intersect_box(ray, c, s); -} - -function raycast_closest_box_intersect(transforms: transform_t[], input_x: f32, input_y: f32, camera: camera_object_t): transform_t { - let intersects: transform_t[] = []; - - // Get intersects - for (let i: i32 = 0; i < transforms.length; ++i) { - let t: transform_t = transforms[i]; - let intersect: vec4_t = raycast_box_intersect(t, input_x, input_y, camera); - if (!vec4_isnan(intersect)) { - array_push(intersects, t); - } - } - - // No intersects - if (intersects.length == 0) { - return null; - } - - // Get closest intersect - let closest: transform_t = null; - let inf: f32 = 100000; - let min_dist: f32 = inf; - for (let i: i32 = 0; i < intersects.length; ++i) { - let t: transform_t = intersects[i]; - let dist: f32 = vec4_dist(t.loc, camera.base.transform.loc); - if (dist < min_dist) { - min_dist = dist; - closest = t; - } - } - - return closest; -} - -function plane_create(): plane_t { - let raw: plane_t = {}; - raw.normal = vec4_create(1.0, 0.0, 0.0); - raw.constant = 0.0; - return raw; -} - -function raycast_plane_intersect(normal: vec4_t, a: vec4_t, input_x: f32, input_y: f32, camera: camera_object_t): vec4_t { - let ray: ray_t = raycast_get_ray(input_x, input_y, camera); - - let plane: plane_t = plane_create(); - plane_set(plane, normal, a); - - return ray_intersect_plane(ray, plane); -} - -function ray_create(origin: vec4_t, dir: vec4_t): ray_t { - let raw: ray_t = {}; - raw.origin = origin; - raw.dir = dir; - return raw; -} - -function ray_at(raw: ray_t, t: f32): vec4_t { - return vec4_add(vec4_mult(raw.dir, t), raw.origin); -} - -function ray_dist_to_point(raw: ray_t, point: vec4_t): f32 { - let v1: vec4_t = vec4_create(); - let dir_dist: f32 = vec4_dot(vec4_sub(point, raw.origin), raw.dir); - - // Point behind the ray - if (dir_dist < 0) { - return vec4_dist(raw.origin, point); - } - - raw.dir = vec4_mult(raw.dir, dir_dist); - raw.dir = vec4_add(raw.dir, raw.origin); - - return vec4_dist(v1, point); -} - -function ray_intersects_sphere(raw: ray_t, sphere_center: vec4_t, sphere_radius: f32): bool { - return ray_dist_to_point(raw, sphere_center) <= sphere_radius; -} - -function ray_intersects_plane(raw: ray_t, plane: plane_t): bool { - // Check if the ray lies on the plane first - let dist_to_point: f32 = plane_dist_to_point(plane, raw.origin); - if (dist_to_point == 0) { - return true; - } - - let denominator: f32 = vec4_dot(plane.normal, raw.dir); - if (denominator * dist_to_point < 0) { - return true; - } - - // Ray origin is behind the plane (and is pointing behind it) - return false; -} - -function ray_dist_to_plane(raw: ray_t, plane: plane_t): f32 { - let denominator: f32 = vec4_dot(plane.normal, raw.dir); - if (denominator == 0) { - // Line is coplanar, return origin - if (plane_dist_to_point(plane, raw.origin) == 0) { - return 0; - } - - return -1; - } - - let t: f32 = -(vec4_dot(raw.origin, plane.normal) + plane.constant) / denominator; - - // Return if the ray never intersects the plane - return t >= 0 ? t : -1; -} - -function ray_intersect_plane(raw: ray_t, plane: plane_t): vec4_t { - let t: f32 = ray_dist_to_plane(raw, plane); - if (t == -1) { - return vec4_nan(); - } - return ray_at(raw, t); -} - -function ray_intersect_box(raw: ray_t, center: vec4_t, dim: vec4_t): vec4_t { - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - let tmin: f32; - let tmax: f32; - let tymin: f32; - let tymax: f32; - let tzmin: f32; - let tzmax: f32; - - let half_x: f32 = dim.x / 2; - let half_y: f32 = dim.y / 2; - let half_z: f32 = dim.z / 2; - let box_min_x: f32 = center.x - half_x; - let box_min_y: f32 = center.y - half_y; - let box_min_z: f32 = center.z - half_z; - let box_max_x: f32 = center.x + half_x; - let box_max_y: f32 = center.y + half_y; - let box_max_z: f32 = center.z + half_z; - - let invdirx: f32 = 1 / raw.dir.x; - let invdiry: f32 = 1 / raw.dir.y; - let invdirz: f32 = 1 / raw.dir.z; - - let origin: vec4_t = raw.origin; - - if (invdirx >= 0) { - tmin = (box_min_x - origin.x) * invdirx; - tmax = (box_max_x - origin.x) * invdirx; - } - else { - tmin = (box_max_x - origin.x) * invdirx; - tmax = (box_min_x - origin.x) * invdirx; - } - - if (invdiry >= 0) { - tymin = (box_min_y - origin.y) * invdiry; - tymax = (box_max_y - origin.y) * invdiry; - } - else { - tymin = (box_max_y - origin.y) * invdiry; - tymax = (box_min_y - origin.y) * invdiry; - } - - if ((tmin > tymax) || (tymin > tmax)) { - return vec4_nan(); - } - - // These lines also handle the case where tmin or tmax is nan - // (result of 0 * inf). x !== x returns true if x is nan - if (tymin > tmin || tmin != tmin) { - tmin = tymin; - } - if (tymax < tmax || tmax != tmax) { - tmax = tymax; - } - - if (invdirz >= 0) { - tzmin = (box_min_z - origin.z) * invdirz; - tzmax = (box_max_z - origin.z) * invdirz; - } - else { - tzmin = (box_max_z - origin.z) * invdirz; - tzmax = (box_min_z - origin.z) * invdirz; - } - - if ((tmin > tzmax) || (tzmin > tmax)) { - return vec4_nan(); - } - if (tzmin > tmin || tmin != tmin) { - tmin = tzmin; - } - if (tzmax < tmax || tmax != tmax) { - tmax = tzmax; - } - - // Return point closest to the ray (positive side) - if (tmax < 0) { - return vec4_nan(); - } - - return ray_at(raw, tmin >= 0 ? tmin : tmax); -} - -function ray_intersect_triangle(raw: ray_t, a: vec4_t, b: vec4_t, c: vec4_t, cull_backface: bool): vec4_t { - // Compute the offset origin, edges, and normal - let diff: vec4_t = vec4_create(); - let edge1: vec4_t = vec4_create(); - let edge2: vec4_t = vec4_create(); - let normal: vec4_t = vec4_create(); - - // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp - edge1 = vec4_sub(b, a); - edge2 = vec4_sub(c, a); - normal = vec4_cross(edge1, edge2); - - let ddn: f32 = vec4_dot(raw.dir, normal); - let sign: i32; - - if (ddn > 0) { - if (cull_backface) { - return vec4_nan(); - } - sign = 1; - } - else if (ddn < 0) { - sign = -1; - ddn = -ddn; - } - else { - return vec4_nan(); - } - - diff = vec4_sub(raw.origin, a); - let ddqxe2: f32 = sign * vec4_dot(raw.dir, vec4_cross(diff, edge2)); - - // b1 < 0, no intersection - if (ddqxe2 < 0) { - return vec4_nan(); - } - - let dde1xq: f32 = sign * vec4_dot(raw.dir, vec4_cross(edge1, diff)); - - // b2 < 0, no intersection - if (dde1xq < 0) { - return vec4_nan(); - } - - // b1+b2 > 1, no intersection - if (ddqxe2 + dde1xq > ddn) { - return vec4_nan(); - } - - // Line intersects triangle, check if ray does. - let qdn: f32 = -sign * vec4_dot(diff, normal); - - // t < 0, no intersection - if (qdn < 0) { - return vec4_nan(); - } - - // Ray intersects triangle. - return ray_at(raw, qdn / ddn); -} - -function plane_dist_to_point(raw: plane_t, point: vec4_t): f32 { - return vec4_dot(raw.normal, point) + raw.constant; -} - -function plane_set(raw: plane_t, normal: vec4_t, point: vec4_t): plane_t { - raw.normal = vec4_clone(normal); - raw.constant = -vec4_dot(point, raw.normal); - return raw; -} diff --git a/base/sources/ts/render_path.ts b/base/sources/ts/render_path.ts index ece400e8..5da0a988 100644 --- a/base/sources/ts/render_path.ts +++ b/base/sources/ts/render_path.ts @@ -1,5 +1,5 @@ -type render_target_t = { +declare type render_target_t = { name?: string; width?: i32; height?: i32; diff --git a/base/sources/ts/scene.ts b/base/sources/ts/scene.ts index 6306c500..4b2ad952 100644 --- a/base/sources/ts/scene.ts +++ b/base/sources/ts/scene.ts @@ -72,7 +72,6 @@ function scene_render_frame() { camera_object_render_frame(scene_camera); } -// Objects function scene_add_object(parent: object_t = null): object_t { let object: object_t = object_create(); parent != null ? object_set_parent(object, parent) : object_set_parent(object, _scene_root); @@ -263,176 +262,3 @@ function scene_embed_data(file: string) { let image: gpu_texture_t = data_get_image(file); map_set(scene_embedded, file, image); } - -type scene_t = { - name?: string; - objects?: obj_t[]; - mesh_datas?: mesh_data_t[]; - camera_datas?: camera_data_t[]; - camera_ref?: string; - material_datas?: material_data_t[]; - shader_datas?: shader_data_t[]; - world_datas?: world_data_t[]; - world_ref?: string; - speaker_datas?: any; // TODO: deprecated - embedded_datas?: string[]; // Preload for this scene, images only for now -}; - -declare type mesh_data_t = { - name?: string; - scale_pos?: f32; // Unpack pos from (-1,1) coords - scale_tex?: f32; // Unpack tex from (-1,1) coords - vertex_arrays?: vertex_array_t[]; - index_array?: u32_array_t; // size = 3 - _?: mesh_data_runtime_t; -}; - -declare type mesh_data_runtime_t = { - handle?: string; // Handle used to retrieve this object in Data - vertex_buffer?: gpu_buffer_t; - index_buffer?: gpu_buffer_t; - structure?: gpu_vertex_structure_t; -}; - -declare type vertex_array_t = { - attrib?: string; - data?: string; // short4norm, short2norm - values?: i16_array_t; -}; - -declare type camera_data_t = { - name?: string; - near_plane?: f32; - far_plane?: f32; - fov?: f32; - aspect?: f32; - frustum_culling?: bool; - ortho?: f32_array_t; // Indicates ortho camera, left, right, bottom, top -}; - -declare type material_data_t = { - name?: string; - shader?: string; - contexts?: material_context_t[]; - _?: material_data_runtime_t; -}; - -declare type material_data_runtime_t = { - uid?: f32; - shader?: shader_data_t; -}; - -declare type material_context_t = { - name?: string; - bind_constants?: bind_const_t[]; - bind_textures?: bind_tex_t[]; - _?: material_context_runtime_t; -}; - -declare type material_context_runtime_t = { - textures?: gpu_texture_t[]; -}; - -declare type bind_const_t = { - name?: string; - vec?: f32_array_t; // bool (vec[0] > 0) | i32 | f32 | vec2 | vec3 | vec4 -}; - -declare type bind_tex_t = { - name?: string; - file?: string; -}; - -declare type shader_data_t = { - name?: string; - contexts?: shader_context_t[]; -}; - -declare type shader_context_t = { - name?: string; - depth_write?: bool; - compare_mode?: string; - cull_mode?: string; - vertex_shader?: string; - fragment_shader?: string; - shader_from_source?: bool; // Build shader at runtime using from_source() - blend_source?: string; - blend_destination?: string; - alpha_blend_source?: string; - alpha_blend_destination?: string; - color_writes_red?: bool[]; // Per target masks - color_writes_green?: bool[]; - color_writes_blue?: bool[]; - color_writes_alpha?: bool[]; - color_attachments?: string[]; // RGBA32, RGBA64, R8 - depth_attachment?: string; // D32 - vertex_elements?: vertex_element_t[]; - constants?: shader_const_t[]; - texture_units?: tex_unit_t[]; - _?: shader_context_runtime_t; -}; - -declare type shader_context_runtime_t = { - pipe?: gpu_pipeline_t; - constants?: i32[]; - tex_units?: i32[]; - structure?: gpu_vertex_structure_t; - vertex_shader_size?: i32; - fragment_shader_size?: i32; -}; - -declare type vertex_element_t = { - name?: string; - data?: string; // "short4norm", "short2norm" -}; - -declare type shader_const_t = { - name?: string; - type?: string; - link?: string; -}; - -declare type tex_unit_t = { - name?: string; - link?: string; -}; - -declare type world_data_t = { - name?: string; - color?: i32; - strength?: f32; - irradiance?: string; // Reference to irradiance_t blob - radiance?: string; - radiance_mipmaps?: i32; - envmap?: string; - _?: world_data_runtime_t; -}; - -declare type world_data_runtime_t = { - envmap?: gpu_texture_t; - radiance?: gpu_texture_t; - radiance_mipmaps?: gpu_texture_t[]; - irradiance?: f32_array_t; -}; - -declare type irradiance_t = { - irradiance?: f32_array_t; // Blob with spherical harmonics, bands 0,1,2 -}; - -declare type obj_t = { - name?: string; - type?: string; // object, mesh_object, camera_object - data_ref?: string; - transform?: f32_array_t; - dimensions?: f32_array_t; // Geometry objects - visible?: bool; - spawn?: bool; // Auto add object when creating scene - anim?: any; // TODO: deprecated - material_ref?: string; - children?: obj_t[]; - _?: obj_runtime_t; -}; - -declare type obj_runtime_t = { - _gc?: scene_t; // Link to armpack_decode result -}; diff --git a/base/sources/ts/uniforms.ts b/base/sources/ts/uniforms.ts deleted file mode 100644 index 94d58d98..00000000 --- a/base/sources/ts/uniforms.ts +++ /dev/null @@ -1,609 +0,0 @@ - -let _uniforms_mat: mat4_t = mat4_identity(); -let _uniforms_mat2: mat4_t = mat4_identity(); -let _uniforms_mat3: mat3_t = mat3_identity(); -let _uniforms_vec: vec4_t = vec4_create(); -let _uniforms_vec2: vec4_t = vec4_create(); -let _uniforms_quat: quat_t = quat_create(); - -let uniforms_tex_links: (o: object_t, md: material_data_t, s: string) => gpu_texture_t = null; -let uniforms_mat4_links: (o: object_t, md: material_data_t, s: string) => mat4_t = null; -let uniforms_vec4_links: (o: object_t, md: material_data_t, s: string) => vec4_t = null; -let uniforms_vec3_links: (o: object_t, md: material_data_t, s: string) => vec4_t = null; -let uniforms_vec2_links: (o: object_t, md: material_data_t, s: string) => vec2_t = null; -let uniforms_f32_links: (o: object_t, md: material_data_t, s: string) => f32 = null; -let uniforms_f32_array_links: (o: object_t, md: material_data_t, s: string) => f32_array_t = null; -let uniforms_i32_links: (o: object_t, md: material_data_t, s: string) => i32 = null; -let uniforms_pos_unpack: f32 = 1.0; -let uniforms_tex_unpack: f32 = 1.0; - -function uniforms_set_context_consts(context: shader_context_t, bind_params: string[]) { - // On shader compile error, _.constants.length will be 0 - if (context.constants != null && context.constants.length == context._.constants.length) { - for (let i: i32 = 0; i < context.constants.length; ++i) { - let c: shader_const_t = context.constants[i]; - uniforms_set_context_const(context._.constants[i], c); - } - } - - // Texture context constants - if (bind_params != null) { // Bind targets - for (let i: i32 = 0; i < math_floor(bind_params.length / 2); ++i) { - let pos: i32 = i * 2; // bind params = [texture, sampler_id] - let rt_id: string = bind_params[pos]; - let sampler_id: string = bind_params[pos + 1]; - let rt: render_target_t = map_get(render_path_render_targets, rt_id); - uniforms_bind_render_target(rt, context, sampler_id); - } - } - - // Texture links - if (context.texture_units != null && context.texture_units.length == context._.tex_units.length) { - for (let j: i32 = 0; j < context.texture_units.length; ++j) { - let tulink: string = context.texture_units[j].link; - if (tulink == null) { - continue; - } - - if (char_at(tulink, 0) == "$") { // Link to embedded data - gpu_set_texture(context._.tex_units[j], map_get(scene_embedded, substring(tulink, 1, tulink.length))); - } - else if (tulink == "_envmap_radiance") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.radiance); - } - } - else if (tulink == "_envmap_radiance0") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.radiance_mipmaps[0]); - } - } - else if (tulink == "_envmap_radiance1") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.radiance_mipmaps[1]); - } - } - else if (tulink == "_envmap_radiance2") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.radiance_mipmaps[2]); - } - } - else if (tulink == "_envmap_radiance3") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.radiance_mipmaps[3]); - } - } - else if (tulink == "_envmap_radiance4") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.radiance_mipmaps[4]); - } - } - else if (tulink == "_envmap") { - let w: world_data_t = scene_world; - if (w != null) { - gpu_set_texture(context._.tex_units[j], w._.envmap); - } - } - } - } -} - -function uniforms_set_obj_consts(context: shader_context_t, object: object_t) { - if (context.constants != null && context.constants.length == context._.constants.length) { - for (let i: i32 = 0; i < context.constants.length; ++i) { - let c: shader_const_t = context.constants[i]; - uniforms_set_obj_const(object, context._.constants[i], c); - } - } - - // Texture object constants - // External - if (uniforms_tex_links != null && context.texture_units != null && context.texture_units.length == context._.tex_units.length) { - for (let j: i32 = 0; j < context.texture_units.length; ++j) { - let tu: tex_unit_t = context.texture_units[j]; - if (tu.link == null) { - continue; - } - - let image: gpu_texture_t = uniforms_tex_links(object, current_material(object), tu.link); - if (image != null) { - gpu_set_texture(context._.tex_units[j], image); - } - } - } -} - -function uniforms_bind_render_target(rt: render_target_t, context: shader_context_t, sampler_id: string) { - if (rt == null) { - return; - } - - if (context.texture_units != null && context.texture_units.length == context._.tex_units.length) { - for (let j: i32 = 0; j < context.texture_units.length; ++j) { // Set texture - if (sampler_id == context.texture_units[j].name) { - gpu_set_texture(context._.tex_units[j], rt._image); - } - } - } -} - -function uniforms_set_context_const(location: i32, c: shader_const_t): bool { - if (c.link == null) { - return true; - } - - let camera: camera_object_t = scene_camera; - - if (c.type == "mat4") { - let m: mat4_t = mat4_nan(); - if (c.link == "_view_matrix") { - m = camera.v; - } - else if (c.link == "_proj_matrix") { - m = camera.p; - } - else if (c.link == "_inv_proj_matrix") { - m = mat4_inv(camera.p); - } - else if (c.link == "_view_proj_matrix") { - m = camera.vp; - } - else if (c.link == "_inv_view_proj_matrix") { - m = mat4_mult_mat(camera.v, camera.p); - m = mat4_inv(m); - } - else if (c.link == "_skydome_matrix") { - let tr: transform_t = camera.base.transform; - let v: vec4_t = vec4_create(transform_world_x(tr), transform_world_y(tr), transform_world_z(tr)); - let bounds: f32 = camera.data.far_plane * 0.9; - let v2: vec4_t = vec4_create(bounds, bounds, bounds); - m = mat4_compose(v, _uniforms_quat, v2); - m = mat4_mult_mat(m, camera.v); - m = mat4_mult_mat(m, camera.p); - } - else { // Unknown uniform - return false; - } - - gpu_set_matrix4(location, m); - return true; - } - else if (c.type == "vec4") { - let v: vec4_t = vec4_nan(); - if (c.link == "_envmap_irradiance0") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[0]; - v.y = fa[1]; - v.z = fa[2]; - v.w = fa[3]; - } - else if (c.link == "_envmap_irradiance1") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[4]; - v.y = fa[5]; - v.z = fa[6]; - v.w = fa[7]; - } - else if (c.link == "_envmap_irradiance2") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[8]; - v.y = fa[9]; - v.z = fa[10]; - v.w = fa[11]; - } - else if (c.link == "_envmap_irradiance3") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[12]; - v.y = fa[13]; - v.z = fa[14]; - v.w = fa[15]; - } - else if (c.link == "_envmap_irradiance4") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[16]; - v.y = fa[17]; - v.z = fa[18]; - v.w = fa[19]; - } - else if (c.link == "_envmap_irradiance5") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[20]; - v.y = fa[21]; - v.z = fa[22]; - v.w = fa[23]; - } - else if (c.link == "_envmap_irradiance6") { - let fa: f32_array_t = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - v.x = fa[24]; - v.y = fa[25]; - v.z = fa[26]; - v.w = fa[27]; - } - else { - return false; - } - - if (!vec4_isnan(v)) { - gpu_set_float4(location, v.x, v.y, v.z, v.w); - } - else { - gpu_set_float4(location, 0, 0, 0, 0); - } - return true; - } - else if (c.type == "vec3") { - let v: vec4_t = vec4_nan(); - - if (c.link == "_camera_pos") { - v = vec4_create(transform_world_x(camera.base.transform), transform_world_y(camera.base.transform), transform_world_z(camera.base.transform)); - } - else if (c.link == "_camera_look") { - v = vec4_norm(camera_object_look_world(camera)); - } - else { - return false; - } - - if (!vec4_isnan(v)) { - gpu_set_float3(location, v.x, v.y, v.z); - } - else { - gpu_set_float3(location, 0.0, 0.0, 0.0); - } - return true; - } - else if (c.type == "vec2") { - let v: vec4_t = vec4_nan(); - - if (c.link == "_vec2x") { - v.x = 1.0; - v.y = 0.0; - } - else if (c.link == "_vec2x_inv") { - v.x = 1.0 / render_path_current_w; - v.y = 0.0; - } - else if (c.link == "_vec2x2") { - v.x = 2.0; - v.y = 0.0; - } - else if (c.link == "_vec2x2_inv") { - v.x = 2.0 / render_path_current_w; - v.y = 0.0; - } - else if (c.link == "_vec2y") { - v.x = 0.0; - v.y = 1.0; - } - else if (c.link == "_vec2y_inv") { - v.x = 0.0; - v.y = 1.0 / render_path_current_h; - } - else if (c.link == "_vec2y2") { - v.x = 0.0; - v.y = 2.0; - } - else if (c.link == "_vec2y2_inv") { - v.x = 0.0; - v.y = 2.0 / render_path_current_h; - } - else if (c.link == "_vec2y3") { - v.x = 0.0; - v.y = 3.0; - } - else if (c.link == "_vec2y3_inv") { - v.x = 0.0; - v.y = 3.0 / render_path_current_h; - } - else if (c.link == "_screen_size") { - v.x = render_path_current_w; - v.y = render_path_current_h; - } - else if (c.link == "_screen_size_inv") { - v.x = 1.0 / render_path_current_w; - v.y = 1.0 / render_path_current_h; - } - else if (c.link == "_camera_plane_proj") { - let znear: f32 = camera.data.near_plane; - let zfar: f32 = camera.data.far_plane; - v.x = zfar / (zfar - znear); - v.y = (-zfar * znear) / (zfar - znear); - } - else if (starts_with(c.link, "_size(")) { - let tex: string = substring(c.link, 6, c.link.length - 1); - let image: gpu_texture_t = uniforms_tex_links(null, null, tex); - if (image != null) { - v.x = image.width; - v.y = image.height; - } - else if (_render_path_bind_params != null) { - for (let i: i32 = 0; i < math_floor(_render_path_bind_params.length / 2); ++i) { - let pos: i32 = i * 2; // bind params = [texture, sampler_id] - let sampler_id: string = _render_path_bind_params[pos + 1]; - if (sampler_id == tex) { - let rt_id: string = _render_path_bind_params[pos]; - let rt: render_target_t = map_get(render_path_render_targets, rt_id); - v.x = rt.width; - v.y = rt.height; - } - } - } - } - else { - return false; - } - - if (!vec4_isnan(v)) { - gpu_set_float2(location, v.x, v.y); - } - else { - gpu_set_float2(location, 0.0, 0.0); - } - return true; - } - else if (c.type == "float") { - let f: f32 = 0.0; - - if (c.link == "_time") { - f = sys_time(); - } - else if (c.link == "_aspect_ratio_window") { - f = sys_w() / sys_h(); - } - else { - return false; - } - - gpu_set_float(location, f); - return true; - } - else if (c.type == "floats") { - let fa: f32_array_t = null; - - if (c.link == "_envmap_irradiance") { - fa = scene_world == null ? world_data_get_empty_irradiance() : scene_world._.irradiance; - } - - if (fa != null) { - gpu_set_floats(location, fa); - return true; - } - } - else if (c.type == "int") { - let i: i32 = 0; - - if (c.link == "_envmap_num_mipmaps") { - let w: world_data_t = scene_world; - i = w != null ? w.radiance_mipmaps + 1 - 2 : 1; // Include basecolor and exclude 2 scaled mips - } - else { - return false; - } - - gpu_set_int(location, i); - return true; - } - return false; -} - -function uniforms_set_obj_const(obj: object_t, loc: i32, c: shader_const_t) { - if (c.link == null) { - return; - } - - let camera: camera_object_t = scene_camera; - if (c.type == "mat4") { - let m: mat4_t = mat4_nan(); - - if (c.link == "_world_matrix") { - m = obj.transform.world_unpack; - } - else if (c.link == "_inv_world_matrix") { - m = mat4_inv(obj.transform.world_unpack); - } - else if (c.link == "_world_view_proj_matrix") { - m = mat4_mult_mat(obj.transform.world_unpack, camera.v); - m = mat4_mult_mat(m, camera.p); - } - else if (c.link == "_world_wiew_matrix") { - m = mat4_mult_mat(obj.transform.world_unpack, camera.v); - } - else if (uniforms_mat4_links != null) { - m = uniforms_mat4_links(obj, current_material(obj), c.link); - } - - if (mat4_isnan(m)) { - return; - } - gpu_set_matrix4(loc, m); - } - else if (c.type == "mat3") { - let m: mat3_t = mat3_nan(); - - if (c.link == "_normal_matrix") { - let m4: mat4_t = mat4_inv(obj.transform.world); - m4 = mat4_transpose3x3(m4); - m = mat3_set_from4(m4); - } - else if (c.link == "_view_matrix3") { - m = mat3_set_from4(camera.v); - } - - if (mat3_isnan(m)) { - return; - } - gpu_set_matrix3(loc, m); - } - else if (c.type == "vec4") { - let v: vec4_t = vec4_nan(); - - if (uniforms_vec4_links != null) { - v = uniforms_vec4_links(obj, current_material(obj), c.link); - } - - if (vec4_isnan(v)) { - return; - } - gpu_set_float4(loc, v.x, v.y, v.z, v.w); - } - else if (c.type == "vec3") { - let v: vec4_t = vec4_nan(); - - if (c.link == "_dim") { // Model space - let d: vec4_t = obj.transform.dim; - let s: vec4_t = obj.transform.scale; - v = vec4_create((d.x / s.x), (d.y / s.y), (d.z / s.z)); - } - else if (c.link == "_half_dim") { // Model space - let d: vec4_t = obj.transform.dim; - let s: vec4_t = obj.transform.scale; - v = vec4_create((d.x / s.x) / 2, (d.y / s.y) / 2, (d.z / s.z) / 2); - } - else if (uniforms_vec3_links != null) { - v = uniforms_vec3_links(obj, current_material(obj), c.link); - } - - if (vec4_isnan(v)) { - return; - } - gpu_set_float3(loc, v.x, v.y, v.z); - } - else if (c.type == "vec2") { - let v: vec2_t = vec2_nan(); - - if (uniforms_vec2_links != null) { - v = uniforms_vec2_links(obj, current_material(obj), c.link); - } - - if (vec2_isnan(v)) { - return; - } - gpu_set_float2(loc, v.x, v.y); - } - else if (c.type == "float") { - let f: f32 = f32_nan(); - - if (c.link == "_object_info_index") { - f = obj.uid; - } - else if (c.link == "_object_info_material_index") { - f = current_material(obj)._.uid; - } - else if (c.link == "_object_info_random") { - f = obj.urandom; - } - else if (c.link == "_pos_unpack") { - f = uniforms_pos_unpack; - } - else if (c.link == "_tex_unpack") { - f = uniforms_tex_unpack; - } - else if (uniforms_f32_links != null) { - f = uniforms_f32_links(obj, current_material(obj), c.link); - } - - if (f32_isnan(f)) { - return; - } - gpu_set_float(loc, f); - } - else if (c.type == "floats") { - let fa: f32_array_t = null; - - if (uniforms_f32_array_links != null) { - fa = uniforms_f32_array_links(obj, current_material(obj), c.link); - } - - if (fa == null) { - return; - } - gpu_set_floats(loc, fa); - } - else if (c.type == "int") { - let i: i32 = INT_MAX; - - if (c.link == "_uid") { - i = obj.uid; - } - else if (uniforms_i32_links != null) { - i = uniforms_i32_links(obj, current_material(obj), c.link); - } - - if (i == INT_MAX) { - return; - } - - gpu_set_int(loc, i); - } -} - -function uniforms_set_material_consts(context: shader_context_t, material_context: material_context_t) { - if (material_context.bind_constants != null) { - for (let i: i32 = 0; i < material_context.bind_constants.length; ++i) { - let matc: bind_const_t = material_context.bind_constants[i]; - let pos: i32 = -1; - for (let i: i32 = 0; i < context.constants.length; ++i) { - let name: string = context.constants[i].name; - if (name == matc.name) { - pos = i; - break; - } - } - if (pos == -1) { - continue; - } - let c: shader_const_t = context.constants[pos]; - - uniforms_set_material_const(context._.constants[pos], c, matc); - } - } - - if (material_context._.textures != null) { - for (let i: i32 = 0; i < material_context._.textures.length; ++i) { - let mname: string = material_context.bind_textures[i].name; - - for (let j: i32 = 0; j < context._.tex_units.length; ++j) { - let sname: string = context.texture_units[j].name; - if (mname == sname) { - gpu_set_texture(context._.tex_units[j], material_context._.textures[i]); - break; - } - } - } - } -} - -function current_material(object: object_t): material_data_t { - if (object != null && object.ext != null) { - let mo: mesh_object_t = object.ext; - return mo.material; - } - return null; -} - -function uniforms_set_material_const(location: i32, shader_const: shader_const_t, material_const: bind_const_t) { - if (shader_const.type == "vec4") { - gpu_set_float4(location, material_const.vec[0], material_const.vec[1], material_const.vec[2], material_const.vec[3]); - } - else if (shader_const.type == "vec3") { - gpu_set_float3(location, material_const.vec[0], material_const.vec[1], material_const.vec[2]); - } - else if (shader_const.type == "vec2") { - gpu_set_float2(location, material_const.vec[0], material_const.vec[1]); - } - else if (shader_const.type == "float") { - gpu_set_float(location, material_const.vec[0]); - } - else if (shader_const.type == "bool") { - gpu_set_bool(location, material_const.vec[0] > 0.0); - } - else if (shader_const.type == "int") { - gpu_set_int(location, math_floor(material_const.vec[0])); - } -}