commit af4bd70e24d11df5c83fb85bc0612a382ff405b4
parent fed683466778f5706b32676c12cfb7bf71365500
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 18 Jan 2018 13:54:42 +0100
Handle the spherical shapes in s3d_primitive_get_attrib function
Diffstat:
| M | src/s3d_primitive.c | | | 194 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
1 file changed, 142 insertions(+), 52 deletions(-)
diff --git a/src/s3d_primitive.c b/src/s3d_primitive.c
@@ -42,73 +42,36 @@
/*******************************************************************************
* Helper functions
******************************************************************************/
-static int
-check_primitive(const struct s3d_primitive* prim)
-{
- return prim
- && prim->geom_id != S3D_INVALID_ID
- && prim->prim_id != S3D_INVALID_ID
- && prim->shape__ != NULL
- && (prim->inst_id != S3D_INVALID_ID || prim->inst__ == NULL);
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-s3d_primitive_get_attrib
- (const struct s3d_primitive* prim,
+static res_T
+mesh_get_primitive_attrib
+ (const struct geometry* geom,
+ const float* transform, /* Can be NULL => no transform */
+ const char flip_surface,
+ const struct s3d_primitive* prim,
const enum s3d_attrib_usage usage,
const float uv[2],
struct s3d_attrib* attrib)
{
const uint32_t* ids;
- struct geometry* geom_shape = NULL;
- const float* transform = NULL;
- char flip_surface = 0;
float w;
res_T res = RES_OK;
+ ASSERT(geom && geom->type == GEOM_MESH && prim && prim->shape__ == geom);
+ ASSERT(uv && attrib);
- if(!check_primitive(prim) || usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib)
- return RES_BAD_ARG;
-
- /* Unormalized barycentric coordinates */
w = CLAMP(1.f - uv[0] - uv[1], 0.f, 1.f);
- if(uv[0] < 0.f || uv[1] < 0.f || uv[0] > 1.f || uv[1] > 1.f
- || !eq_epsf(w + uv[0] + uv[1], 1.f, 1.e-3f))
- return RES_BAD_ARG;
-
- if(prim->inst__ == NULL) {
- geom_shape = (struct geometry*)prim->shape__;
- flip_surface = geom_shape->flip_surface;
- } else {
- const struct geometry* geom_inst = (const struct geometry*)prim->inst__;
- ASSERT(geom_inst->type == GEOM_INSTANCE);
- ASSERT(prim->inst_id == geom_inst->name);
- geom_shape = (struct geometry*)prim->shape__;
- transform = geom_inst->data.instance->transform;
- ASSERT(geom_shape);
- flip_surface = geom_inst->flip_surface ^ geom_shape->flip_surface;
- }
- ASSERT(prim->geom_id == geom_shape->name);
-
- if(geom_shape->type == GEOM_SPHERE) { /* TODO */
- log_error(geom_shape->dev, "%s: unsupported sphere primitive.\n", FUNC_NAME);
- return RES_BAD_ARG;
- }
/* The mesh haven't the required mesh attrib */
- if(usage != S3D_GEOMETRY_NORMAL && !geom_shape->data.mesh->attribs[usage]) {
+ if(usage != S3D_GEOMETRY_NORMAL && !geom->data.mesh->attribs[usage]) {
res = RES_BAD_ARG;
goto error;
}
/* Out of bound primitive index */
- if(prim->prim_id >= mesh_get_ntris(geom_shape->data.mesh)) {
+ if(prim->prim_id >= mesh_get_ntris(geom->data.mesh)) {
res = RES_BAD_ARG;
goto error;
}
- ids = mesh_get_ids(geom_shape->data.mesh) + prim->prim_id * 3/*#triangle ids*/;
+ ids = mesh_get_ids(geom->data.mesh) + prim->prim_id * 3/*#triangle ids*/;
attrib->usage = usage;
if(usage == S3D_POSITION || usage == S3D_GEOMETRY_NORMAL) {
@@ -116,7 +79,7 @@ s3d_primitive_get_attrib
const float* pos;
attrib->type = S3D_FLOAT3;
/* Fetch data */
- pos = mesh_get_pos(geom_shape->data.mesh);
+ pos = mesh_get_pos(geom->data.mesh);
v0 = pos + ids[0] * 3;
v1 = pos + ids[1] * 3;
v2 = pos + ids[2] * 3;
@@ -150,10 +113,10 @@ s3d_primitive_get_attrib
const float* attr;
const float* v0, *v1, *v2;
unsigned i, dim;
- attrib->type = geom_shape->data.mesh->attribs_type[usage];
+ attrib->type = geom->data.mesh->attribs_type[usage];
/* Fetch attrib data */
dim = s3d_type_get_dimension(attrib->type);
- attr = mesh_get_attr(geom_shape->data.mesh, usage);
+ attr = mesh_get_attr(geom->data.mesh, usage);
v0 = attr + ids[0] * dim;
v1 = attr + ids[1] * dim;
v2 = attr + ids[2] * dim;
@@ -169,6 +132,133 @@ error:
goto exit;
}
+static res_T
+sphere_get_attrib
+ (const struct geometry* geom,
+ const float* transform, /* Can be NULL => no transform */
+ const char flip_surface,
+ const struct s3d_primitive* prim,
+ const enum s3d_attrib_usage usage,
+ const float uv[2],
+ struct s3d_attrib* attrib)
+{
+ res_T res = RES_OK;
+ double phi, cos_theta, sin_theta;
+ float P[3];
+ float N[3];
+ ASSERT(geom && geom->type == GEOM_MESH && prim && prim->shape__ == geom);
+ ASSERT(uv && attrib);
+
+ /* Only position and geometry normal are valid sphere attribs */
+ if(usage != S3D_GEOMETRY_NORMAL || usage != S3D_POSITION) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Compute the sampled position on the unit sphere that is actually equal to
+ * the normal at this position. */
+ phi = uv[0] * 2*PI;
+ cos_theta = 1 - 2 * uv[1];
+ sin_theta = 2 * sqrtf(uv[1] * (1 - uv[1]));
+ N[0] = (float)(cos(phi) * sin_theta);
+ N[1] = (float)(sin(phi) * sin_theta);
+ N[2] = (float)cos_theta;
+
+ if(usage == S3D_GEOMETRY_NORMAL) {
+ if(flip_surface) f3_minus(N, N);
+ if(transform) { /* Transform the normal from local to world space */
+ float invtrans[9];
+ f33_invtrans(invtrans, transform);
+ f33_mulf3(attrib->value, invtrans, N);
+ }
+ f3_set(attrib->value, N);
+ } else {
+ ASSERT(usage == S3D_POSITION);
+ /* Compute the sampled position in local space */
+ f3_mulf(P, N, geom->data.sphere->radius);
+ f3_add(P, P, geom->data.sphere->pos);
+ if(transform) { /* Transform the position from local to world space */
+ f33_mulf3(P, transform, P); /* Affine */
+ f3_add(P, P, transform + 9); /* Linear */
+ }
+ f3_set(attrib->value, P);
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static int
+check_primitive(const struct s3d_primitive* prim)
+{
+ return prim
+ && prim->geom_id != S3D_INVALID_ID
+ && prim->prim_id != S3D_INVALID_ID
+ && prim->shape__ != NULL
+ && (prim->inst_id != S3D_INVALID_ID || prim->inst__ == NULL);
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+s3d_primitive_get_attrib
+ (const struct s3d_primitive* prim,
+ const enum s3d_attrib_usage usage,
+ const float uv[2],
+ struct s3d_attrib* attrib)
+{
+ struct geometry* geom_shape = NULL;
+ const float* transform = NULL;
+ char flip_surface = 0;
+ float w;
+ res_T res = RES_OK;
+
+ if(!check_primitive(prim) || usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Unormalized barycentric coordinates */
+ w = CLAMP(1.f - uv[0] - uv[1], 0.f, 1.f);
+ if(uv[0] < 0.f || uv[1] < 0.f || uv[0] > 1.f || uv[1] > 1.f
+ || !eq_epsf(w + uv[0] + uv[1], 1.f, 1.e-3f)) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(prim->inst__ == NULL) {
+ geom_shape = (struct geometry*)prim->shape__;
+ flip_surface = geom_shape->flip_surface;
+ } else {
+ const struct geometry* geom_inst = (const struct geometry*)prim->inst__;
+ ASSERT(geom_inst->type == GEOM_INSTANCE);
+ ASSERT(prim->inst_id == geom_inst->name);
+ geom_shape = (struct geometry*)prim->shape__;
+ transform = geom_inst->data.instance->transform;
+ ASSERT(geom_shape);
+ flip_surface = geom_inst->flip_surface ^ geom_shape->flip_surface;
+ }
+ ASSERT(prim->geom_id == geom_shape->name);
+
+ if(geom_shape->type == GEOM_SPHERE) {
+ res = sphere_get_attrib
+ (geom_shape, transform, flip_surface, prim, usage, uv, attrib);
+ } else {
+ ASSERT(geom_shape->type == GEOM_MESH);
+ res = mesh_get_primitive_attrib
+ (geom_shape, transform, flip_surface, prim, usage, uv, attrib);
+ }
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
res_T
s3d_primitive_has_attrib
(const struct s3d_primitive* prim,
@@ -218,7 +308,7 @@ s3d_primitive_sample
st[1] = (float)(v * sqrt_u);
break;
case GEOM_SPHERE:
- st[0] = (float)(u * 2*PI);
+ st[0] = u;
st[1] = v;
break;
default: FATAL("Unreachable code\n"); break;