From 2a6bf7c6beeb1d463b6dc9ddcd85c541549326f7 Mon Sep 17 00:00:00 2001 From: Aki-7 Date: Thu, 1 Dec 2022 12:24:19 +0900 Subject: [PATCH] add sphere region --- common/include/zen-common/types.h | 5 ++++ common/types.c | 10 +++++++ zgnroot/include/zgnr/intersection.h | 7 +++++ zgnroot/include/zgnr/region/node.h | 4 +++ zgnroot/include/zgnr/region/sphere.h | 11 ++++++++ zgnroot/meson.build | 1 + zgnroot/src/intersection.c | 26 ++++++++++++++++++ zgnroot/src/region.c | 40 ++++++++++++++++++++++++++-- zgnroot/src/region/node.c | 31 +++++++++++++++++++-- zgnroot/src/region/node.h | 4 +++ zgnroot/src/region/sphere.c | 33 +++++++++++++++++++++++ zgnroot/src/region/sphere.h | 7 +++++ 12 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 zgnroot/include/zgnr/region/sphere.h create mode 100644 zgnroot/src/region/sphere.c create mode 100644 zgnroot/src/region/sphere.h diff --git a/common/include/zen-common/types.h b/common/include/zen-common/types.h index fbe4f2af..86c48514 100644 --- a/common/include/zen-common/types.h +++ b/common/include/zen-common/types.h @@ -49,6 +49,11 @@ int zn_vec3_to_array(vec3 vec, struct wl_array *array); */ int zn_array_to_versor(struct wl_array *array, versor vec); +/** + * @return 0 if successful, -1 otherwise + */ +int zn_array_to_float(struct wl_array *array, float *value); + #ifdef __cplusplus } #endif diff --git a/common/types.c b/common/types.c index 70e88358..8957eda5 100644 --- a/common/types.c +++ b/common/types.c @@ -86,3 +86,13 @@ zn_array_to_versor(struct wl_array *array, versor vec) return 0; } + +int +zn_array_to_float(struct wl_array *array, float *value) +{ + if (sizeof(float) != array->size) return -1; + + memcpy(value, array->data, sizeof(float)); + + return 0; +} diff --git a/zgnroot/include/zgnr/intersection.h b/zgnroot/include/zgnr/intersection.h index 4504d3f5..7635d1ad 100644 --- a/zgnroot/include/zgnr/intersection.h +++ b/zgnroot/include/zgnr/intersection.h @@ -8,3 +8,10 @@ */ float zgnr_intersection_ray_obb( vec3 origin, vec3 direction, vec3 aabb_half_size, mat4 transform); + +/** + * @return the distance from the origin to the intersection, or FLT_MAX if not + * intersecting + */ +float zgnr_intersection_ray_sphere( + vec3 origin, vec3 direction, vec3 center, float radius); diff --git a/zgnroot/include/zgnr/region/node.h b/zgnroot/include/zgnr/region/node.h index dafcc764..c9dc14e3 100644 --- a/zgnroot/include/zgnr/region/node.h +++ b/zgnroot/include/zgnr/region/node.h @@ -6,7 +6,11 @@ struct zgnr_region_node { struct wl_list cuboid_list; // zgnr_cuboid_region::link + struct wl_list sphere_list; // zgnr_sphere_region::link }; +/** + * @param transform : translation & rotation only + */ float zgnr_region_node_ray_cast( struct zgnr_region_node *self, mat4 transform, vec3 origin, vec3 direction); diff --git a/zgnroot/include/zgnr/region/sphere.h b/zgnroot/include/zgnr/region/sphere.h new file mode 100644 index 00000000..45ec618c --- /dev/null +++ b/zgnroot/include/zgnr/region/sphere.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +struct zgnr_sphere_region { + vec3 center; + float radius; + + struct wl_list link; +}; diff --git a/zgnroot/meson.build b/zgnroot/meson.build index 867b168b..b4e30d36 100644 --- a/zgnroot/meson.build +++ b/zgnroot/meson.build @@ -20,6 +20,7 @@ _zgnr_srcs = [ 'src/region.c', 'src/region/node.c', 'src/region/cuboid.c', + 'src/region/sphere.c', 'src/rendering-unit.c', 'src/seat.c', 'src/seat-ray.c', diff --git a/zgnroot/src/intersection.c b/zgnroot/src/intersection.c index 65961bc8..2fcdabb1 100644 --- a/zgnroot/src/intersection.c +++ b/zgnroot/src/intersection.c @@ -45,3 +45,29 @@ zgnr_intersection_ray_obb( return t_min; } + +float +zgnr_intersection_ray_sphere( + vec3 origin, vec3 direction, vec3 center, float radius) +{ + float t; // intersection point is (origin + t * direction) + + vec3 ray_origin; + + // The center of the sphere is the origin of the coordinates. + glm_vec3_sub(origin, center, ray_origin); + + // A t^2 + B t + C = 0 + float A = glm_vec3_dot(direction, direction); + float B = 2 * glm_vec3_dot(ray_origin, direction); + float C = glm_vec3_dot(ray_origin, ray_origin) - radius * radius; + float D = B * B - 4 * A * C; + + if (D < 0) return FLT_MAX; + + t = (-B - sqrtf(D)) / (2 * A); + + if (t <= 0) return FLT_MAX; + + return t; +} diff --git a/zgnroot/src/region.c b/zgnroot/src/region.c index 524c8096..47028a86 100644 --- a/zgnroot/src/region.c +++ b/zgnroot/src/region.c @@ -5,6 +5,7 @@ #include #include "region/cuboid.h" +#include "region/sphere.h" static void zgnr_region_destroy(struct zgnr_region* self); @@ -28,8 +29,6 @@ zgnr_region_protocol_add_cuboid(struct wl_client* client, struct wl_resource* resource, struct wl_array* half_size_array, struct wl_array* center_array, struct wl_array* quaternion_array) { - UNUSED(client); - struct zgnr_region* self = wl_resource_get_user_data(resource); struct zgnr_cuboid_region* cuboid; @@ -60,6 +59,7 @@ zgnr_region_protocol_add_cuboid(struct wl_client* client, cuboid = zgnr_cuboid_region_create(half_size, center, quaternion); if (cuboid == NULL) { + wl_client_post_no_memory(client); zn_error("Failed to creat a cuboid region"); return; } @@ -67,9 +67,45 @@ zgnr_region_protocol_add_cuboid(struct wl_client* client, zgnr_region_node_add_cuboid(self->node, cuboid); } +static void +zgnr_region_protocol_add_sphere(struct wl_client* client, + struct wl_resource* resource, struct wl_array* center_wl_array, + struct wl_array* radius_wl_array) +{ + struct zgnr_region* self = wl_resource_get_user_data(resource); + struct zgnr_sphere_region* sphere; + + vec3 center; + float radius; + + if (zn_array_to_vec3(center_wl_array, center) != 0) { + wl_resource_post_error(resource, ZGN_COMPOSITOR_ERROR_WL_ARRAY_SIZE, + "center is expected vec3 (%ld bytes) but got %ld bytes", sizeof(vec3), + center_wl_array->size); + return; + } + + if (zn_array_to_float(radius_wl_array, &radius) != 0) { + wl_resource_post_error(resource, ZGN_COMPOSITOR_ERROR_WL_ARRAY_SIZE, + "radius is expected float (%ld bytes) but got %ld bytes", sizeof(float), + radius_wl_array->size); + return; + } + + sphere = zgnr_sphere_region_create(center, radius); + if (sphere == NULL) { + wl_client_post_no_memory(client); + zn_error("Failed to creat a sphere region"); + return; + } + + zgnr_region_node_add_sphere(self->node, sphere); +} + static const struct zgn_region_interface implementation = { .destroy = zgnr_region_protocol_destroy, .add_cuboid = zgnr_region_protocol_add_cuboid, + .add_sphere = zgnr_region_protocol_add_sphere, }; struct zgnr_region* diff --git a/zgnroot/src/region/node.c b/zgnroot/src/region/node.c index 569dd94c..1c97b804 100644 --- a/zgnroot/src/region/node.c +++ b/zgnroot/src/region/node.c @@ -11,6 +11,8 @@ zgnr_region_node_ray_cast(struct zgnr_region_node* self, mat4 outer_transform, vec3 origin, vec3 direction) { struct zgnr_cuboid_region* cuboid_region; + struct zgnr_sphere_region* sphere_region; + float min_distance = FLT_MAX; wl_list_for_each (cuboid_region, &self->cuboid_list, link) { float distance; @@ -26,6 +28,18 @@ zgnr_region_node_ray_cast(struct zgnr_region_node* self, mat4 outer_transform, if (distance < min_distance) min_distance = distance; } + wl_list_for_each (sphere_region, &self->sphere_list, link) { + float distance; + + vec3 center; + glm_mat4_mulv3(outer_transform, sphere_region->center, 1, center); + + distance = zgnr_intersection_ray_sphere( + origin, direction, center, sphere_region->radius); + + if (distance < min_distance) min_distance = distance; + } + return min_distance; } @@ -36,6 +50,13 @@ zgnr_region_node_add_cuboid( wl_list_insert(&self->cuboid_list, &cuboid->link); } +void +zgnr_region_node_add_sphere( + struct zgnr_region_node* self, struct zgnr_sphere_region* sphere) +{ + wl_list_insert(&self->sphere_list, &sphere->link); +} + struct zgnr_region_node* zgnr_region_node_create_copy(struct zgnr_region_node* self) { @@ -63,6 +84,7 @@ zgnr_region_node_create(void) } wl_list_init(&self->cuboid_list); + wl_list_init(&self->sphere_list); return self; @@ -73,11 +95,16 @@ zgnr_region_node_create(void) void zgnr_region_node_destroy(struct zgnr_region_node* self) { - struct zgnr_cuboid_region *cuboid, *tmp; + struct zgnr_cuboid_region *cuboid, *tmp_cuboid; + struct zgnr_sphere_region *sphere, *tmp_sphere; - wl_list_for_each_safe (cuboid, tmp, &self->cuboid_list, link) { + wl_list_for_each_safe (cuboid, tmp_cuboid, &self->cuboid_list, link) { zgnr_cuboid_region_destroy(cuboid); } + wl_list_for_each_safe (sphere, tmp_sphere, &self->sphere_list, link) { + zgnr_sphere_region_destroy(sphere); + } + free(self); } diff --git a/zgnroot/src/region/node.h b/zgnroot/src/region/node.h index ef7127f8..8110162e 100644 --- a/zgnroot/src/region/node.h +++ b/zgnroot/src/region/node.h @@ -1,11 +1,15 @@ #pragma once #include "cuboid.h" +#include "sphere.h" #include "zgnr/region/node.h" void zgnr_region_node_add_cuboid( struct zgnr_region_node* self, struct zgnr_cuboid_region* cuboid); +void zgnr_region_node_add_sphere( + struct zgnr_region_node* self, struct zgnr_sphere_region* sphere); + struct zgnr_region_node* zgnr_region_node_create_copy( struct zgnr_region_node* self); diff --git a/zgnroot/src/region/sphere.c b/zgnroot/src/region/sphere.c new file mode 100644 index 00000000..7f6ee637 --- /dev/null +++ b/zgnroot/src/region/sphere.c @@ -0,0 +1,33 @@ +#include "sphere.h" + +#include +#include + +struct zgnr_sphere_region* +zgnr_sphere_region_create(vec3 center, float radius) +{ + struct zgnr_sphere_region* self; + + self = zalloc(sizeof *self); + if (self == NULL) { + zn_error("Failed to allocate memory"); + goto err; + } + + glm_vec3_copy(center, self->center); + self->radius = radius; + + wl_list_init(&self->link); + + return self; + +err: + return NULL; +} + +void +zgnr_sphere_region_destroy(struct zgnr_sphere_region* self) +{ + wl_list_remove(&self->link); + free(self); +} diff --git a/zgnroot/src/region/sphere.h b/zgnroot/src/region/sphere.h new file mode 100644 index 00000000..cfbcab81 --- /dev/null +++ b/zgnroot/src/region/sphere.h @@ -0,0 +1,7 @@ +#pragma once + +#include "zgnr/region/sphere.h" + +struct zgnr_sphere_region* zgnr_sphere_region_create(vec3 center, float radius); + +void zgnr_sphere_region_destroy(struct zgnr_sphere_region* self);