1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 9 апр. 2017 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <core/alloc.h> 23 #include <core/status.h> 24 #include <core/3d/Scene3D.h> 25 #include <core/3d/Object3D.h> 26 27 namespace lsp 28 { Object3D(Scene3D * scene,const LSPString * name)29 Object3D::Object3D(Scene3D *scene, const LSPString *name) 30 { 31 pScene = scene; 32 bVisible = true; 33 34 sName.set(name); 35 dsp::init_matrix3d_identity(&sMatrix); 36 37 dsp::init_point_xyz(&sBoundBox.p[0], 0.0f, 0.0f, 0.0f); 38 dsp::init_point_xyz(&sBoundBox.p[1], 0.0f, 0.0f, 0.0f); 39 dsp::init_point_xyz(&sBoundBox.p[2], 0.0f, 0.0f, 0.0f); 40 dsp::init_point_xyz(&sBoundBox.p[3], 0.0f, 0.0f, 0.0f); 41 dsp::init_point_xyz(&sBoundBox.p[4], 0.0f, 0.0f, 0.0f); 42 dsp::init_point_xyz(&sBoundBox.p[5], 0.0f, 0.0f, 0.0f); 43 dsp::init_point_xyz(&sBoundBox.p[6], 0.0f, 0.0f, 0.0f); 44 dsp::init_point_xyz(&sBoundBox.p[7], 0.0f, 0.0f, 0.0f); 45 46 dsp::init_point_xyz(&sCenter, 0.0f, 0.0f, 0.0f); 47 } 48 ~Object3D()49 Object3D::~Object3D() 50 { 51 destroy(); 52 } 53 destroy()54 void Object3D::destroy() 55 { 56 vTriangles.flush(); 57 } 58 post_load()59 void Object3D::post_load() 60 { 61 dsp::init_point_xyz(&sCenter, 0.0f, 0.0f, 0.0f); 62 for (size_t i=0; i<8; ++i) 63 { 64 sCenter.x += sBoundBox.p[i].x; 65 sCenter.y += sBoundBox.p[i].y; 66 sCenter.z += sBoundBox.p[i].z; 67 } 68 sCenter.x *= 0.125f; // 1/8 69 sCenter.y *= 0.125f; // 1/8 70 sCenter.z *= 0.125f; // 1/8 71 } 72 add_triangle(ssize_t face_id,ssize_t v1,ssize_t v2,ssize_t v3,ssize_t vn1,ssize_t vn2,ssize_t vn3)73 status_t Object3D::add_triangle( 74 ssize_t face_id, 75 ssize_t v1, ssize_t v2, ssize_t v3, 76 ssize_t vn1, ssize_t vn2, ssize_t vn3 77 ) 78 { 79 // Check vertex index 80 ssize_t v_limit = pScene->vVertexes.size(); 81 if ((v1 >= v_limit) || (v2 >= v_limit) || (v3 >= v_limit)) 82 return -STATUS_INVALID_VALUE; 83 if ((v1 < 0) || (v2 < 0) || (v3 < 0)) 84 return -STATUS_INVALID_VALUE; 85 86 // Check normal index 87 ssize_t n_limit = pScene->vNormals.size(); 88 if ((vn1 >= n_limit) || (vn2 >= n_limit) || (vn3 >= n_limit)) 89 return -STATUS_INVALID_VALUE; 90 91 // Allocate triangle 92 ssize_t tid = pScene->vTriangles.size(); 93 obj_triangle_t *t = pScene->vTriangles.alloc(); 94 if (t == NULL) 95 return -STATUS_NO_MEM; 96 97 // Store vertexes 98 t->id = tid; 99 t->face = face_id; 100 t->ptag = NULL; 101 t->itag = -1; 102 t->v[0] = pScene->vertex(v1); 103 t->v[1] = pScene->vertex(v2); 104 t->v[2] = pScene->vertex(v3); 105 106 // Store normals 107 obj_normal_t *xvn = NULL; 108 if ((vn1 < 0) || (vn2 < 0) || (vn3 < 0)) 109 { 110 // Add normal 111 xvn = pScene->vXNormals.alloc(); 112 if (xvn == NULL) 113 return -STATUS_NO_MEM; 114 115 // Get points 116 dsp::calc_normal3d_p3(xvn, t->v[0], t->v[1], t->v[2]); 117 } 118 119 t->n[0] = (vn1 >= 0) ? pScene->normal(vn1) : xvn; 120 t->n[1] = (vn2 >= 0) ? pScene->normal(vn2) : xvn; 121 t->n[2] = (vn3 >= 0) ? pScene->normal(vn3) : xvn; 122 123 // Store edges 124 for (size_t i=0; i<3; ++i) 125 { 126 // Lookup for already existing edge 127 obj_edge_t *e = register_edge(t->v[i], t->v[(i+1)%3]); 128 if (e == NULL) 129 return STATUS_NO_MEM; 130 131 // Add edge to triangle 132 t->e[i] = e; 133 } 134 135 bool first = vTriangles.size() <= 0; 136 if (!vTriangles.add(t)) 137 return STATUS_NO_MEM; 138 139 // Commit triangle edges 140 if (first) 141 { 142 for (size_t i=0; i<8; ++i) 143 sBoundBox.p[i] = *(t->v[0]); 144 } 145 else 146 calc_bound_box(t->v[0]); 147 148 calc_bound_box(t->v[1]); 149 calc_bound_box(t->v[2]); 150 151 return STATUS_OK; 152 } 153 calc_bound_box()154 void Object3D::calc_bound_box() 155 { 156 obj_triangle_t **vt = vTriangles.get_array(); 157 for (size_t i=0, n=vTriangles.size(); i<n; ++i) 158 { 159 obj_triangle_t *t = *(vt++); 160 if (i == 0) 161 { 162 for (size_t i=0; i<8; ++i) 163 sBoundBox.p[i] = *(t->v[0]); 164 } 165 else 166 calc_bound_box(t->v[0]); 167 168 calc_bound_box(t->v[1]); 169 calc_bound_box(t->v[2]); 170 } 171 } 172 register_edge(obj_vertex_t * v0,obj_vertex_t * v1)173 obj_edge_t *Object3D::register_edge(obj_vertex_t *v0, obj_vertex_t *v1) 174 { 175 // Lookup for already existing edge 176 obj_edge_t *e = v0->ve; 177 while (e != NULL) 178 { 179 if (e->v[0] == v0) 180 { 181 if (e->v[1] == v1) 182 break; 183 e = e->vlnk[0]; 184 } 185 else // e->v[1] == v0 186 { 187 if (e->v[0] == v1) 188 break; 189 e = e->vlnk[1]; 190 } 191 } 192 193 // Need to create new edge and link? 194 if (e == NULL) 195 { 196 ssize_t res = pScene->vEdges.ialloc(&e); 197 if (res < 0) 198 return NULL; 199 200 e->id = res; 201 e->v[0] = v0; 202 e->v[1] = v1; 203 e->vlnk[0] = v0->ve; 204 e->vlnk[1] = v1->ve; 205 e->ptag = NULL; 206 e->itag = -1; 207 208 v0->ve = e; 209 v1->ve = e; 210 } 211 212 return e; 213 } 214 calc_bound_box(const obj_vertex_t * p)215 void Object3D::calc_bound_box(const obj_vertex_t *p) 216 { 217 obj_boundbox_t *b = &sBoundBox; 218 219 // Left plane 220 if (b->p[0].x > p->x) 221 b->p[0].x = p->x; 222 if (b->p[1].x > p->x) 223 b->p[1].x = p->x; 224 if (b->p[4].x > p->x) 225 b->p[4].x = p->x; 226 if (b->p[5].x > p->x) 227 b->p[5].x = p->x; 228 229 // Right plane 230 if (b->p[2].x < p->x) 231 b->p[2].x = p->x; 232 if (b->p[3].x < p->x) 233 b->p[3].x = p->x; 234 if (b->p[6].x < p->x) 235 b->p[6].x = p->x; 236 if (b->p[7].x < p->x) 237 b->p[7].x = p->x; 238 239 // Near plane 240 if (b->p[1].y > p->y) 241 b->p[1].y = p->y; 242 if (b->p[2].y > p->y) 243 b->p[2].y = p->y; 244 if (b->p[5].y > p->y) 245 b->p[5].y = p->y; 246 if (b->p[6].y > p->y) 247 b->p[6].y = p->y; 248 249 // Far plane 250 if (b->p[0].y < p->y) 251 b->p[0].y = p->y; 252 if (b->p[3].y < p->y) 253 b->p[3].y = p->y; 254 if (b->p[4].y < p->y) 255 b->p[4].y = p->y; 256 if (b->p[7].y < p->y) 257 b->p[7].y = p->y; 258 259 // Top plane 260 if (b->p[0].z < p->z) 261 b->p[0].z = p->z; 262 if (b->p[1].z < p->z) 263 b->p[1].z = p->z; 264 if (b->p[2].z < p->z) 265 b->p[2].z = p->z; 266 if (b->p[3].z < p->z) 267 b->p[3].z = p->z; 268 269 // Bottom plane 270 if (b->p[4].z > p->z) 271 b->p[4].z = p->z; 272 if (b->p[5].z > p->z) 273 b->p[5].z = p->z; 274 if (b->p[6].z > p->z) 275 b->p[6].z = p->z; 276 if (b->p[7].z > p->z) 277 b->p[7].z = p->z; 278 } 279 add_triangle(ssize_t * vv,ssize_t * vn)280 status_t Object3D::add_triangle(ssize_t *vv, ssize_t *vn) 281 { 282 return add_triangle(vv[0], vv[1], vv[2], vn[0], vn[1], vn[2]); 283 } 284 add_triangle(ssize_t * vv)285 status_t Object3D::add_triangle(ssize_t *vv) 286 { 287 return add_triangle(vv[0], vv[1], vv[2], -1, -1, -1); 288 } 289 290 } /* namespace lsp */ 291