test_senc3d_enclosure.c (9978B)
1 /* Copyright (C) 2018-2020, 2023, 2024 |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 "senc3d.h" 17 #include "senc3d_sXd_helper.h" 18 #include "test_senc3d_utils.h" 19 20 #include <rsys/double3.h> 21 22 #include <star/s3d.h> 23 24 static void 25 test(const int convention) 26 { 27 struct mem_allocator allocator; 28 struct senc3d_device* dev = NULL; 29 struct senc3d_scene* scn = NULL; 30 struct senc3d_enclosure* enclosures[2] = { NULL, NULL }; 31 struct senc3d_enclosure* enclosure; 32 struct senc3d_enclosure_header header; 33 struct s3d_device* s3d = NULL; 34 struct s3d_scene* s3d_scn = NULL; 35 struct s3d_shape* s3d_shp = NULL; 36 struct s3d_vertex_data s3d_attribs; 37 unsigned indices[2][3]; 38 unsigned medium; 39 unsigned gid; 40 enum senc3d_side side; 41 double vrtx[3]; 42 double ext_v = 0; 43 struct context ctx = CONTEXT_NULL__; 44 unsigned i, n, t, count; 45 int conv; 46 const int conv_front = (convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0; 47 const int conv_in = (convention & SENC3D_CONVENTION_NORMAL_INSIDE) != 0; 48 49 OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); 50 OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev)); 51 52 /* A 3D cube. 53 * 2 enclosures (inside, outside) sharing the same triangles, 54 * but opposite sides */ 55 ctx.positions = box_vertices; 56 ctx.indices = box_indices; 57 ctx.front_media = medium0; 58 ctx.back_media = medium1; 59 60 OK(senc3d_scene_create(dev, convention, ntriangles, get_indices, get_media, 61 nvertices, get_position, &ctx, &scn)); 62 63 OK(senc3d_scene_get_convention(scn, &conv)); 64 CHK(conv == convention); 65 66 OK(senc3d_scene_get_enclosure_count(scn, &count)); 67 CHK(count == 2); 68 69 OK(senc3d_scene_get_enclosure(scn, 0, &enclosure)); 70 BA(senc3d_enclosure_ref_get(NULL)); 71 OK(senc3d_enclosure_ref_get(enclosure)); 72 BA(senc3d_enclosure_ref_put(NULL)); 73 OK(senc3d_enclosure_ref_put(enclosure)); 74 75 BA(senc3d_enclosure_get_triangle(NULL, 0, indices[0])); 76 BA(senc3d_enclosure_get_triangle(enclosure, ntriangles, indices[0])); 77 BA(senc3d_enclosure_get_triangle(enclosure, 0, NULL)); 78 BA(senc3d_enclosure_get_triangle(NULL, ntriangles, indices[0])); 79 BA(senc3d_enclosure_get_triangle(NULL, 0, NULL)); 80 BA(senc3d_enclosure_get_triangle(enclosure, ntriangles, NULL)); 81 BA(senc3d_enclosure_get_triangle(NULL, ntriangles, NULL)); 82 OK(senc3d_enclosure_get_triangle(enclosure, 0, indices[0])); 83 84 BA(senc3d_enclosure_get_vertex(NULL, 0, vrtx)); 85 BA(senc3d_enclosure_get_vertex(enclosure, nvertices, vrtx)); 86 BA(senc3d_enclosure_get_vertex(enclosure, 0, NULL)); 87 BA(senc3d_enclosure_get_vertex(NULL, nvertices, vrtx)); 88 BA(senc3d_enclosure_get_vertex(NULL, 0, NULL)); 89 BA(senc3d_enclosure_get_vertex(enclosure, nvertices, NULL)); 90 BA(senc3d_enclosure_get_vertex(NULL, nvertices, NULL)); 91 OK(senc3d_enclosure_get_vertex(enclosure, 0, vrtx)); 92 93 BA(senc3d_enclosure_get_triangle_id(NULL, 0, &gid, NULL)); 94 BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, &gid, NULL)); 95 BA(senc3d_enclosure_get_triangle_id(enclosure, 0, NULL, NULL)); 96 BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, &gid, NULL)); 97 BA(senc3d_enclosure_get_triangle_id(NULL, 0, NULL, NULL)); 98 BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, NULL, NULL)); 99 BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, NULL, NULL)); 100 BA(senc3d_enclosure_get_triangle_id(enclosure, 0, &gid, NULL)); 101 BA(senc3d_enclosure_get_triangle_id(NULL, 0, &gid, &side)); 102 BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, &gid, &side)); 103 BA(senc3d_enclosure_get_triangle_id(enclosure, 0, NULL, &side)); 104 BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, &gid, &side)); 105 BA(senc3d_enclosure_get_triangle_id(NULL, 0, NULL, &side)); 106 BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, NULL, &side)); 107 BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, NULL, &side)); 108 OK(senc3d_enclosure_get_triangle_id(enclosure, 0, &gid, &side)); 109 110 BA(senc3d_enclosure_get_medium(NULL, 0, &medium)); 111 BA(senc3d_enclosure_get_medium(enclosure, 2, &medium)); 112 BA(senc3d_enclosure_get_medium(enclosure, 0, NULL)); 113 BA(senc3d_enclosure_get_medium(NULL, 2, &medium)); 114 BA(senc3d_enclosure_get_medium(NULL, 0, NULL)); 115 BA(senc3d_enclosure_get_medium(enclosure, 2, NULL)); 116 BA(senc3d_enclosure_get_medium(NULL, 2, NULL)); 117 OK(senc3d_enclosure_get_medium(enclosure, 0, &medium)); 118 119 OK(senc3d_enclosure_ref_put(enclosure)); 120 121 FOR_EACH(i, 0, count) { 122 OK(senc3d_scene_get_enclosure(scn, i, &enclosure)); 123 124 BA(senc3d_enclosure_get_header(NULL, &header)); 125 BA(senc3d_enclosure_get_header(enclosure, NULL)); 126 BA(senc3d_enclosure_get_header(NULL, NULL)); 127 OK(senc3d_enclosure_get_header(enclosure, &header)); 128 129 CHK(header.enclosure_id == i); 130 CHK(header.enclosed_media_count == 1); 131 OK(senc3d_enclosure_get_medium(enclosure, 0, &medium)); 132 /* Geometrical normals point outside the cube in input triangles: 133 * if convention is front, front medium (0) is outside, 134 * that is medium 0's enclosure is infinite */ 135 CHK(conv_front == ((medium == 0) == header.is_infinite)); 136 CHK(header.primitives_count == ntriangles); 137 CHK(header.unique_primitives_count == ntriangles); 138 CHK(header.vertices_count == nvertices); 139 CHK(header.is_infinite == (i == 0)); 140 if(i == 0) ext_v = header.volume; 141 else CHK(header.volume == -ext_v); 142 143 FOR_EACH(t, 0, header.primitives_count) { 144 OK(senc3d_enclosure_get_triangle_id(enclosure, t, &gid, &side)); 145 CHK(gid == t); 146 CHK(side == (medium == 0) ? SENC3D_FRONT : SENC3D_BACK); 147 } 148 149 OK(senc3d_enclosure_ref_put(enclosure)); 150 } 151 152 FOR_EACH(i, 0, 2) 153 OK(senc3d_scene_get_enclosure(scn, i, enclosures + i)); 154 FOR_EACH(n, 0, ntriangles) { 155 int same, reversed; 156 /* Read same triangles in both enclosures */ 157 FOR_EACH(i, 0, 2) 158 OK(senc3d_enclosure_get_triangle(enclosures[i], n, indices[i])); 159 /* Same triangles and opposite sides for the 2 enclosures */ 160 FOR_EACH(i, 0, 3) CHK(indices[0][i] == indices[1][2 - i]); 161 /* Enclosure 0 is outside (and contains medium 0 if convention is front). 162 * Geometrical normals in output data point in the same direction that those 163 * of input triangles for enclosure 0 iff convention is inside. 164 * The opposite holds for enclosure 1. */ 165 cmp_trg(n, enclosures[0], box_indices + 3 * n, box_vertices, &same, &reversed); 166 CHK((same && !reversed) == conv_in); 167 cmp_trg(n, enclosures[1], box_indices + 3 * n, box_vertices, &same, &reversed); 168 CHK(same && reversed == conv_in); 169 } 170 FOR_EACH(i, 0, 2) 171 OK(senc3d_enclosure_ref_put(enclosures[i])); 172 173 OK(senc3d_scene_ref_put(scn)); 174 175 /* Same 3D cube, but with a hole (incomplete). 176 * 1 single enclosure including both sides of triangles */ 177 178 ctx.positions = box_vertices; 179 ctx.indices = box_indices; 180 ctx.front_media = medium0; 181 ctx.back_media = medium1; 182 183 OK(senc3d_scene_create(dev, convention, ntriangles - 1, get_indices, get_media, 184 nvertices, get_position, &ctx, &scn)); 185 186 OK(senc3d_scene_get_frontier_segments_count(scn, &count)); 187 CHK(count == 3); 188 189 OK(senc3d_scene_get_enclosure_count(scn, &count)); 190 CHK(count == 1); 191 192 #ifdef DUMP_ENCLOSURES 193 dump_enclosure(scn, 0, "test_enclosure_hole.obj"); 194 #endif 195 196 OK(senc3d_scene_get_enclosure(scn, 0, &enclosure)); 197 198 BA(senc3d_enclosure_get_header(NULL, &header)); 199 BA(senc3d_enclosure_get_header(enclosure, NULL)); 200 BA(senc3d_enclosure_get_header(NULL, NULL)); 201 OK(senc3d_enclosure_get_header(enclosure, &header)); 202 203 CHK(header.enclosure_id == 0); 204 CHK(header.enclosed_media_count == 2); 205 CHK(header.primitives_count == 2 * header.unique_primitives_count); 206 CHK(header.unique_primitives_count == ntriangles - 1); 207 CHK(header.vertices_count == nvertices); 208 CHK(header.is_infinite == 1); 209 CHK(header.volume == 0); 210 211 FOR_EACH(t, 0, header.primitives_count) { 212 OK(senc3d_enclosure_get_triangle_id(enclosure, t, &gid, &side)); 213 /* The first unique_triangle_count triangles of an enclosure 214 * are unique triangles */ 215 if(t < header.unique_primitives_count) CHK(gid == t); 216 CHK(side == (t < header.unique_primitives_count) ? SENC3D_FRONT : SENC3D_BACK); 217 } 218 219 /* Put geometry in a 3D view using helper functions */ 220 s3d_attribs.type = S3D_FLOAT3; 221 s3d_attribs.usage = S3D_POSITION; 222 s3d_attribs.get = senc3d_sXd_enclosure_get_position; 223 OK(s3d_device_create(NULL, &allocator, 0, &s3d)); 224 OK(s3d_scene_create(s3d, &s3d_scn)); 225 OK(s3d_shape_create_mesh(s3d, &s3d_shp)); 226 OK(s3d_mesh_setup_indexed_vertices(s3d_shp, header.primitives_count, 227 senc3d_sXd_enclosure_get_indices, header.vertices_count, &s3d_attribs, 228 1, enclosure)); 229 OK(s3d_scene_attach_shape(s3d_scn, s3d_shp)); 230 S3D(shape_ref_put(s3d_shp)); 231 S3D(device_ref_put(s3d)); 232 S3D(scene_ref_put(s3d_scn)); 233 234 SENC3D(scene_ref_put(scn)); 235 SENC3D(device_ref_put(dev)); 236 SENC3D(enclosure_ref_put(enclosure)); 237 238 check_memory_allocator(&allocator); 239 mem_shutdown_proxy_allocator(&allocator); 240 CHK(mem_allocated_size() == 0); 241 } 242 243 int 244 main(int argc, char** argv) 245 { 246 (void) argc, (void) argv; 247 test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE); 248 test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE); 249 test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_OUTSIDE); 250 test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE); 251 return 0; 252 }