s3dstl.c (6651B)
1 /* Copyright (C) 2016, 2018, 2021, 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 "s3dstl.h" 17 18 #include <rsys/float3.h> 19 #include <rsys/logger.h> 20 #include <rsys/mem_allocator.h> 21 #include <rsys/ref_count.h> 22 23 #include <star/s3d.h> 24 #include <star/sstl.h> 25 26 struct s3dstl { 27 struct s3d_device* s3d; 28 struct s3d_shape* shape; 29 30 struct sstl* sstl; 31 struct logger* logger; 32 struct mem_allocator* allocator; 33 int verbose; 34 ref_T ref; 35 }; 36 37 /******************************************************************************* 38 * Helper functions 39 ******************************************************************************/ 40 static void 41 get_position(const unsigned ivert, float pos[3], void* ctx) 42 { 43 const struct sstl_desc* desc = ctx; 44 ASSERT(ctx && pos && ivert < desc->vertices_count); 45 f3_set(pos, desc->vertices + ivert * 3); 46 } 47 48 static void 49 get_indices(const unsigned itri, unsigned ids[3], void* ctx) 50 { 51 const struct sstl_desc* desc = ctx; 52 const unsigned* indices; 53 ASSERT(ctx && ids && itri < desc->triangles_count); 54 indices = desc->indices + itri*3; 55 /* Note that in the Star-STL loader, front faces are CCW ordered while in to 56 * the Star-3D library front faces are CW ordered. Flip the vertex index in 57 * order to ensure that the 3D and the STL front faces are the same */ 58 ids[0] = indices[2]; 59 ids[1] = indices[1]; 60 ids[2] = indices[0]; 61 } 62 63 static void 64 log_error(const struct s3dstl* s3dstl, const char* msg, ...) 65 { 66 va_list vargs_list; 67 ASSERT(s3dstl && msg); 68 if(s3dstl->verbose) { 69 res_T res; (void)res; 70 va_start(vargs_list, msg); 71 res = logger_vprint(s3dstl->logger, LOG_ERROR, msg, vargs_list); 72 ASSERT(res == RES_OK); 73 va_end(vargs_list); 74 } 75 } 76 77 static res_T 78 shape_create(struct s3dstl* s3dstl, const char* filename) 79 { 80 struct s3d_vertex_data vertex_data; 81 struct s3d_shape* shape = NULL; 82 struct sstl_desc desc; 83 res_T res = RES_OK; 84 ASSERT(s3dstl && filename); 85 86 res = sstl_get_desc(s3dstl->sstl, &desc); 87 if(res != RES_OK) { 88 log_error(s3dstl, "%s: couldn't retrieve the STL descriptor.\n", filename); 89 goto error; 90 } 91 92 if(!desc.triangles_count) goto exit; 93 94 res = s3d_shape_create_mesh(s3dstl->s3d, &shape); 95 if(res != RES_OK) { 96 log_error(s3dstl, "%s: couldn't create the Star-3D shape.\n", filename); 97 goto error; 98 } 99 100 vertex_data.usage = S3D_POSITION; 101 vertex_data.type = S3D_FLOAT3; 102 vertex_data.get = get_position; 103 104 res = s3d_mesh_setup_indexed_vertices(shape, (unsigned)desc.triangles_count, 105 get_indices, (unsigned)desc.vertices_count, &vertex_data, 1, &desc); 106 if(res != RES_OK) { 107 log_error(s3dstl, "%s: couldn't setup the data of the Star-3D shape.\n", 108 filename); 109 goto error; 110 } 111 112 if(s3dstl->shape) S3D(shape_ref_put(s3dstl->shape)); 113 s3dstl->shape = shape; 114 115 exit: 116 return res; 117 error: 118 if(shape) S3D(shape_ref_put(shape)); 119 goto exit; 120 } 121 122 static void 123 release_s3dstl(ref_T* ref) 124 { 125 struct s3dstl* s3dstl; 126 ASSERT(ref); 127 128 s3dstl = CONTAINER_OF(ref, struct s3dstl, ref); 129 if(s3dstl->sstl) SSTL(ref_put(s3dstl->sstl)); 130 if(s3dstl->s3d) S3D(device_ref_put(s3dstl->s3d)); 131 if(s3dstl->shape) S3D(shape_ref_put(s3dstl->shape)); 132 133 MEM_RM(s3dstl->allocator, s3dstl); 134 } 135 136 /******************************************************************************* 137 * Exported functions 138 ******************************************************************************/ 139 res_T 140 s3dstl_create 141 (struct logger* log, 142 struct mem_allocator* allocator, 143 struct sstl* sstl, 144 struct s3d_device* s3d, 145 const int verbose, 146 struct s3dstl** out_s3dstl) 147 { 148 struct s3dstl* s3dstl = NULL; 149 struct mem_allocator* mem_allocator; 150 struct logger* logger = NULL; 151 res_T res = RES_OK; 152 153 if(!s3d || !out_s3dstl) { 154 res = RES_BAD_ARG; 155 goto error; 156 } 157 158 mem_allocator = allocator ? allocator : &mem_default_allocator; 159 logger = log ? log : LOGGER_DEFAULT; 160 161 s3dstl = MEM_CALLOC(mem_allocator, 1, sizeof(struct s3dstl)); 162 if(!s3dstl) { 163 if(verbose) { 164 logger_print(logger, LOG_ERROR, 165 "Couldn't allocate the Star-3DSTL device.\n"); 166 } 167 res = RES_MEM_ERR; 168 goto error; 169 } 170 ref_init(&s3dstl->ref); 171 s3dstl->allocator = mem_allocator; 172 s3dstl->logger = logger; 173 s3dstl->verbose = verbose; 174 S3D(device_ref_get(s3d)); 175 s3dstl->s3d = s3d; 176 177 if(sstl) { 178 SSTL(ref_get(sstl)); 179 s3dstl->sstl = sstl; 180 } else { 181 res = sstl_create(logger, allocator, verbose, &s3dstl->sstl); 182 if(res != RES_OK) { 183 if(verbose) { 184 logger_print(logger, LOG_ERROR, 185 "Couldn't create the loader of the STL fileformat.\n"); 186 } 187 goto error; 188 } 189 } 190 191 exit: 192 if(out_s3dstl) *out_s3dstl = s3dstl; 193 return res; 194 error: 195 if(s3dstl) { 196 S3DSTL(ref_put(s3dstl)); 197 s3dstl = NULL; 198 } 199 goto exit; 200 } 201 202 res_T 203 s3dstl_ref_get(struct s3dstl* s3dstl) 204 { 205 if(!s3dstl) return RES_BAD_ARG; 206 ref_get(&s3dstl->ref); 207 return RES_OK; 208 } 209 210 res_T 211 s3dstl_ref_put(struct s3dstl* s3dstl) 212 { 213 if(!s3dstl) return RES_BAD_ARG; 214 ref_put(&s3dstl->ref, release_s3dstl); 215 return RES_OK; 216 } 217 218 res_T 219 s3dstl_get_sstl(struct s3dstl* s3dstl, struct sstl** sstl) 220 { 221 if(!s3dstl || !sstl) return RES_BAD_ARG; 222 *sstl = s3dstl->sstl; 223 return RES_OK; 224 } 225 226 res_T 227 s3dstl_load(struct s3dstl* s3dstl, const char* filename) 228 { 229 res_T res; 230 if(!s3dstl || !filename) return RES_BAD_ARG; 231 res = sstl_load(s3dstl->sstl, filename); 232 if(res != RES_OK) return res; 233 return shape_create(s3dstl, filename); 234 } 235 236 res_T 237 s3dstl_load_stream(struct s3dstl* s3dstl, FILE* stream) 238 { 239 res_T res; 240 if(!s3dstl || !stream) return RES_BAD_ARG; 241 res = sstl_load_stream(s3dstl->sstl, stream); 242 if(res != RES_OK) return res; 243 return shape_create(s3dstl, "STREAM"); 244 } 245 246 res_T 247 s3dstl_clear(struct s3dstl* s3dstl) 248 { 249 if(!s3dstl) return RES_BAD_ARG; 250 if(s3dstl->shape) { 251 S3D(shape_ref_put(s3dstl->shape)); 252 s3dstl->shape = NULL; 253 } 254 return RES_OK; 255 } 256 257 res_T 258 s3dstl_get_shape(struct s3dstl* s3dstl, struct s3d_shape** shape) 259 { 260 if(!s3dstl || !shape) return RES_BAD_ARG; 261 *shape = s3dstl->shape; 262 return RES_OK; 263 } 264