s2d_primitive.c (5636B)
1 /* Copyright (C) 2016-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 "s2d.h" 17 #include "s2d_c.h" 18 #include "s2d_geometry.h" 19 #include "s2d_line_segments.h" 20 21 #include <rsys/float2.h> 22 23 /******************************************************************************* 24 * Helper functions 25 ******************************************************************************/ 26 static int 27 check_primitive(const struct s2d_primitive* prim) 28 { 29 return prim 30 && prim->geom_id != S2D_INVALID_ID 31 && prim->prim_id != S2D_INVALID_ID 32 && prim->mesh__ != NULL; 33 } 34 35 /******************************************************************************* 36 * Exported functions 37 ******************************************************************************/ 38 res_T 39 s2d_primitive_get_attrib 40 (const struct s2d_primitive* prim, 41 const enum s2d_attrib_usage usage, 42 const float s, 43 struct s2d_attrib* attrib) 44 { 45 const uint32_t* ids; 46 struct geometry* geom = NULL; 47 res_T res = RES_OK; 48 49 if(!check_primitive(prim) 50 || !attrib 51 || (usage != S2D_GEOMETRY_NORMAL && (unsigned)usage >= S2D_ATTRIBS_COUNT__)) { 52 res = RES_BAD_ARG; 53 goto error; 54 } 55 56 /* Unnormalized barycentric coordinates */ 57 if(s < 0.f || s > 1.f) { 58 res = RES_BAD_ARG; 59 goto error; 60 } 61 62 geom = (struct geometry*)prim->mesh__; 63 64 /* The line segments haven't tge required attrib */ 65 if(usage != S2D_GEOMETRY_NORMAL && !geom->lines->attribs[usage]) { 66 res = RES_BAD_ARG; 67 goto error; 68 } 69 70 /* Out of bound primitive index */ 71 if(prim->prim_id >= line_segments_get_nsegments(geom->lines)) { 72 res = RES_BAD_ARG; 73 goto error; 74 } 75 76 ids = line_segments_get_ids(geom->lines) + prim->prim_id * 2/*#segment ids*/; 77 attrib->usage = usage; 78 79 if(usage == S2D_POSITION || usage == S2D_GEOMETRY_NORMAL) { 80 const float* v0; 81 const float* v1; 82 const float* pos; 83 84 attrib->type = S2D_FLOAT2; 85 pos = line_segments_get_pos(geom->lines); 86 v0 = pos + ids[0] * 2; 87 v1 = pos + ids[1] * 2; 88 89 if(usage == S2D_POSITION) { 90 float tmp[2]; 91 f2_mulf(attrib->value, v1, s); 92 f2_add(attrib->value, attrib->value, f2_mulf(tmp, v0, 1.f-s)); 93 } else { ASSERT(usage == S2D_GEOMETRY_NORMAL); 94 const float dx = v1[0] - v0[0]; 95 const float dy = v1[1] - v0[1]; 96 /* Build the segment normal with respect to edge orientation. 97 * Default is clock wise */ 98 if(geom->flip_contour) { 99 attrib->value[0] = -dy; 100 attrib->value[1] = dx; 101 } else { 102 attrib->value[0] = dy; 103 attrib->value[1] = -dx; 104 } 105 } 106 } else { 107 FATAL("Unimplemented attribute getter.\n"); 108 } 109 110 exit: 111 return res; 112 error: 113 goto exit; 114 } 115 116 res_T 117 s2d_primitive_sample 118 (const struct s2d_primitive* prim, 119 const float u, 120 float* s) 121 { 122 if(!check_primitive(prim) || !s) 123 return RES_BAD_ARG; 124 125 if(u < 0.f || u >= 1.f) 126 return RES_BAD_ARG; 127 128 /* Only line segments primitives are currently supported. So the "u" 129 * canonical variable is directly the parametric coordinate of the sample 130 * onto the segment */ 131 *s = u; 132 return RES_OK; 133 } 134 135 res_T 136 s2d_primitive_compute_length(const struct s2d_primitive* prim, float* length) 137 { 138 const uint32_t* ids; 139 const float* pos; 140 const float* v0, *v1; 141 float tmp[2]; 142 struct geometry* geom; 143 144 if(!check_primitive(prim) || !length) 145 return RES_BAD_ARG; 146 147 geom = (struct geometry*)prim->mesh__; 148 pos = line_segments_get_pos(geom->lines); 149 ids = line_segments_get_ids(geom->lines) + prim->prim_id * 2/*#segment ids*/; 150 v0 = pos + ids[0] * 2/*#coords*/; 151 v1 = pos + ids[1] * 2/*#coords*/; 152 *length = f2_len(f2_sub(tmp, v1, v0)); 153 return RES_OK; 154 } 155 156 res_T 157 s2d_segment_get_vertex_attrib 158 (const struct s2d_primitive* prim, 159 const size_t ivertex, /* in [0..2[ */ 160 const enum s2d_attrib_usage usage, 161 struct s2d_attrib* attrib) /* Resulting attrib */ 162 { 163 struct geometry* geom; 164 const uint32_t* ids; 165 166 if(!check_primitive(prim) || ivertex > 1 167 || (unsigned)usage >= S2D_ATTRIBS_COUNT__ || !attrib) { 168 return RES_BAD_ARG; 169 } 170 171 geom = (struct geometry*)prim->mesh__; 172 ASSERT(prim->geom_id == geom->name); 173 174 /* The segment have not the required attrib */ 175 if(!geom->lines->attribs[usage]) { 176 return RES_BAD_ARG; 177 } 178 179 /* Out of bound primitive index */ 180 if(prim->prim_id >= line_segments_get_nsegments(geom->lines)) { 181 return RES_BAD_ARG; 182 } 183 184 ids = line_segments_get_ids(geom->lines) + prim->prim_id*2/*#segment ids*/; 185 attrib->usage = usage; 186 187 if(usage != S2D_POSITION) { 188 const float* attr; 189 unsigned i, dim; 190 attrib->type = geom->lines->attribs_type[usage]; 191 /* Fetch attrib data */ 192 dim = s2d_type_get_dimension(attrib->type); 193 attr = line_segments_get_attr(geom->lines, usage) + ids[ivertex]*dim; 194 FOR_EACH(i, 0, dim) attrib->value[i] = attr[i]; 195 } else { 196 const float* pos; 197 attrib->type = S2D_FLOAT2; 198 /* Fetch data */ 199 pos = line_segments_get_pos(geom->lines) + ids[ivertex]*2; 200 f2_set(attrib->value, pos); 201 } 202 return RES_OK; 203 } 204