s3d_geometry.c (6595B)
1 /* Copyright (C) 2015-2023 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "s3d_device_c.h" 17 #include "s3d_geometry.h" 18 #include "s3d_instance.h" 19 #include "s3d_mesh.h" 20 #include "s3d_scene_view_c.h" 21 #include "s3d_sphere.h" 22 23 #include <rsys/mem_allocator.h> 24 25 /******************************************************************************* 26 * Helper functions 27 ******************************************************************************/ 28 static FINLINE void 29 sphere_ray_hit_setup 30 (const struct RTCIntersectFunctionNArguments* args, const float tfar) 31 { 32 struct geometry* geom = args->geometryUserPtr; 33 struct RTCRayN* rayN; 34 struct RTCHitN* hitN; 35 struct RTCHit hit; 36 struct RTCRay ray; 37 float Ng[3]; 38 float uv[2]; 39 size_t i; 40 ASSERT(args && args->primID == 0 && args->N == 1 && args->valid[0] != 0); 41 42 geom = args->geometryUserPtr; 43 ASSERT(geom && geom->type == GEOM_SPHERE); 44 45 rayN = RAYHITN_GET_RAYN(args->rayhit, args->N); 46 hitN = RAYHITN_GET_HITN(args->rayhit, args->N); 47 48 rtc_rayN_get_ray(rayN, args->N, 0, &ray); 49 ray.tfar = tfar; 50 51 Ng[0] = ray.dir_x*tfar + ray.org_x - geom->data.sphere->pos[0]; 52 Ng[1] = ray.dir_y*tfar + ray.org_y - geom->data.sphere->pos[1]; 53 Ng[2] = ray.dir_z*tfar + ray.org_z - geom->data.sphere->pos[2]; 54 55 f3_normalize(Ng, Ng); 56 sphere_normal_to_uv(Ng, uv); 57 58 hit.Ng_x = Ng[0]; 59 hit.Ng_y = Ng[1]; 60 hit.Ng_z = Ng[2]; 61 hit.u = uv[0]; 62 hit.v = uv[1]; 63 hit.primID = 0; 64 hit.geomID = geom->rtc_id; 65 FOR_EACH(i, 0, RTC_MAX_INSTANCE_LEVEL_COUNT) { 66 hit.instID[i] = args->context->instID[i]; 67 } 68 69 /* Filter the intersection if required */ 70 if(geom->data.sphere->filter.func) { 71 struct RTCFilterFunctionNArguments filter_args; 72 int valid = 1; 73 74 filter_args.valid = &valid; 75 filter_args.geometryUserPtr = args->geometryUserPtr; 76 filter_args.context = args->context; 77 filter_args.ray = (struct RTCRayN*)&ray; 78 filter_args.hit = (struct RTCHitN*)&hit; 79 filter_args.N = args->N; 80 81 rtc_hit_filter_wrapper(&filter_args); 82 if(!filter_args.valid[0]) return; 83 } 84 85 RAYN_GRAB(rayN, args->N, 0, float, tfar) = tfar; 86 rtc_hitN_set_hit(hitN, args->N, 0, &hit); 87 } 88 89 static void 90 geometry_release(ref_T* ref) 91 { 92 struct geometry* geom; 93 struct s3d_device* dev; 94 95 geom = CONTAINER_OF(ref, struct geometry, ref); 96 dev = geom->dev; 97 switch(geom->type) { 98 case GEOM_MESH: 99 if(geom->data.mesh) mesh_ref_put(geom->data.mesh); 100 break; 101 case GEOM_INSTANCE: 102 if(geom->data.instance) instance_ref_put(geom->data.instance); 103 break; 104 case GEOM_SPHERE: 105 if(geom->data.sphere) sphere_ref_put(geom->data.sphere); 106 break; 107 default: FATAL("Unreachable code\n"); break; 108 } 109 MEM_RM(dev->allocator, geom); 110 S3D(device_ref_put(dev)); 111 } 112 113 /******************************************************************************* 114 * Local functions 115 ******************************************************************************/ 116 res_T 117 geometry_create 118 (struct s3d_device* dev, 119 struct geometry** out_geom) 120 { 121 struct geometry* geom = NULL; 122 res_T res = RES_OK; 123 ASSERT(dev && out_geom); 124 125 geom = (struct geometry*)MEM_CALLOC 126 (dev->allocator, 1, sizeof(struct geometry)); 127 if(!geom) { 128 res = RES_MEM_ERR; 129 goto error; 130 } 131 ref_init(&geom->ref); 132 S3D(device_ref_get(dev)); 133 geom->dev = dev; 134 geom->name = S3D_INVALID_ID; 135 geom->flip_surface = 0; 136 geom->is_enabled = 1; 137 geom->type = GEOM_NONE; 138 geom->data.mesh = NULL; 139 geom->rtc = NULL; 140 geom->rtc_id = RTC_INVALID_GEOMETRY_ID; 141 geom->rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM; 142 143 exit: 144 *out_geom = geom; 145 return res; 146 error: 147 if(geom) { 148 geometry_ref_put(geom); 149 geom = NULL; 150 } 151 goto exit; 152 } 153 154 void 155 geometry_ref_get(struct geometry* geom) 156 { 157 ASSERT(geom); 158 ref_get(&geom->ref); 159 } 160 161 void 162 geometry_ref_put(struct geometry* geom) 163 { 164 ASSERT(geom); 165 ref_put(&geom->ref, geometry_release); 166 } 167 168 void 169 geometry_rtc_sphere_bounds(const struct RTCBoundsFunctionArguments* args) 170 { 171 struct geometry* geom; 172 struct sphere sphere; 173 ASSERT(args && args->primID == 0 && args->timeStep == 0); 174 175 geom = args->geometryUserPtr; 176 ASSERT(geom && geom->type == GEOM_SPHERE); 177 178 sphere = *geom->data.sphere; 179 args->bounds_o->lower_x = sphere.pos[0] - sphere.radius; 180 args->bounds_o->lower_y = sphere.pos[1] - sphere.radius; 181 args->bounds_o->lower_z = sphere.pos[2] - sphere.radius; 182 args->bounds_o->upper_x = sphere.pos[0] + sphere.radius; 183 args->bounds_o->upper_y = sphere.pos[1] + sphere.radius; 184 args->bounds_o->upper_z = sphere.pos[2] + sphere.radius; 185 } 186 187 void 188 geometry_rtc_sphere_intersect(const struct RTCIntersectFunctionNArguments* args) 189 { 190 float v[3]; 191 float ray_org[3]; 192 float ray_dir[3]; 193 float A, B, C, D, Q, rcpA, t0, t1; 194 struct geometry* geom; 195 struct sphere sphere; 196 struct RTCRayN* rayN; 197 ASSERT(args && args->primID == 0 && args->N == 1 && args->valid[0] != 0); 198 199 geom = args->geometryUserPtr; 200 ASSERT(geom && geom->type == GEOM_SPHERE); 201 202 rayN = RAYHITN_GET_RAYN(args->rayhit, args->N); 203 ray_org[0] = RAYN_GRAB(rayN, args->N, 0, float, org_x); 204 ray_org[1] = RAYN_GRAB(rayN, args->N, 0, float, org_y); 205 ray_org[2] = RAYN_GRAB(rayN, args->N, 0, float, org_z); 206 ray_dir[0] = RAYN_GRAB(rayN, args->N, 0, float, dir_x); 207 ray_dir[1] = RAYN_GRAB(rayN, args->N, 0, float, dir_y); 208 ray_dir[2] = RAYN_GRAB(rayN, args->N, 0, float, dir_z); 209 210 sphere = *geom->data.sphere; 211 f3_sub(v, ray_org, sphere.pos); 212 A = f3_dot(ray_dir, ray_dir); 213 B = 2*f3_dot(v, ray_dir); 214 C = f3_dot(v, v) - sphere.radius*sphere.radius; 215 D = B*B - 4*A*C; 216 217 if(D < 0.0f) return; 218 Q = (float)sqrt(D); 219 rcpA = 1.f / A; 220 t0 = 0.5f * rcpA * (-B - Q); 221 t1 = 0.5f * rcpA * (-B + Q); 222 223 if(RAYN_GRAB(rayN, args->N, 0, float, tnear) < t0 224 && RAYN_GRAB(rayN, args->N, 0, float, tfar) > t0) { 225 sphere_ray_hit_setup(args, t0); 226 } 227 if(RAYN_GRAB(rayN, args->N, 0, float, tnear) < t1 228 && RAYN_GRAB(rayN, args->N, 0, float, tfar) > t1) { 229 sphere_ray_hit_setup(args, t1); 230 } 231 } 232