/*! * Calculates the vertex normals corresponding to the smoothing group * settings for each face of a mesh. * * \param mesh A pointer to the mesh to calculate the normals for. * \param normals A pointer to a buffer to store the calculated * normals. The buffer must have the size: * 3*3*sizeof(float)*mesh->nfaces. * * To allocate the normal buffer do for example the following: * \code * Lib3dsVector *normals = malloc(3*3*sizeof(float)*mesh->nfaces); * \endcode * * To access the normal of the i-th vertex of the j-th face do the * following: * \code * normals[3*j+i] * \endcode */ void lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh *mesh, float (*normals)[3]) { Lib3dsFaces **fl; Lib3dsFaces *fa; int i, j; if (!mesh->nfaces) { return; } fl = (Lib3dsFaces**)calloc(sizeof(Lib3dsFaces*), mesh->nvertices); fa = (Lib3dsFaces*)malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces); for (i = 0; i < mesh->nfaces; ++i) { for (j = 0; j < 3; ++j) { Lib3dsFaces* l = &fa[3*i+j]; float p[3], q[3], n[3]; float len, weight; l->index = i; l->next = fl[mesh->faces[i].index[j]]; fl[mesh->faces[i].index[j]] = l; lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]); lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]); lib3ds_vector_cross(n, p, q); len = lib3ds_vector_length(n); if (len > 0) { weight = (float)atan2(len, lib3ds_vector_dot(p, q)); lib3ds_vector_scalar_mul(l->normal, n, weight / len); } else { lib3ds_vector_zero(l->normal); } } } for (i = 0; i < mesh->nfaces; ++i) { Lib3dsFace *f = &mesh->faces[i]; for (j = 0; j < 3; ++j) { float n[3]; Lib3dsFaces *p; Lib3dsFace *pf; assert(mesh->faces[i].index[j] < mesh->nvertices); if (f->smoothing_group) { unsigned smoothing_group = f->smoothing_group; lib3ds_vector_zero(n); for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) { pf = &mesh->faces[p->index]; if (pf->smoothing_group & f->smoothing_group) smoothing_group |= pf->smoothing_group; } for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) { pf = &mesh->faces[p->index]; if (smoothing_group & pf->smoothing_group) { lib3ds_vector_add(n, n, p->normal); } } } else { lib3ds_vector_copy(n, fa[3*i+j].normal); } lib3ds_vector_normalize(n); lib3ds_vector_copy(normals[3*i+j], n); } } free(fa); free(fl); }
/*! * Calculates the vertex normals corresponding to the smoothing group * settings for each face of a mesh. * * \param mesh A pointer to the mesh to calculate the normals for. * \param normalL A pointer to a buffer to store the calculated * normals. The buffer must have the size: * 3*sizeof(Lib3dsVector)*mesh->faces. * * To allocate the normal buffer do for example the following: * \code * Lib3dsVector *normalL = malloc(3*sizeof(Lib3dsVector)*mesh->faces); * \endcode * * To access the normal of the i-th vertex of the j-th face do the * following: * \code * normalL[3*j+i] * \endcode * * \ingroup mesh */ void lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL) { Lib3dsFaces **fl; Lib3dsFaces *fa; unsigned i,j,k; if (!mesh->faces) { return; } fl=calloc(sizeof(Lib3dsFaces*),mesh->points); ASSERT(fl); fa=calloc(sizeof(Lib3dsFaces),3*mesh->faces); ASSERT(fa); k=0; for (i=0; i<mesh->faces; ++i) { Lib3dsFace *f=&mesh->faceL[i]; for (j=0; j<3; ++j) { Lib3dsFaces* l=&fa[k++]; ASSERT(f->points[j]<mesh->points); l->face=f; l->next=fl[f->points[j]]; fl[f->points[j]]=l; } } for (i=0; i<mesh->faces; ++i) { Lib3dsFace *f=&mesh->faceL[i]; for (j=0; j<3; ++j) { // FIXME: static array needs at least check!! Lib3dsVector n,N[128]; Lib3dsFaces *p; int k,l; int found; ASSERT(f->points[j]<mesh->points); if (f->smoothing) { lib3ds_vector_zero(n); k=0; for (p=fl[f->points[j]]; p; p=p->next) { found=0; for (l=0; l<k; ++l) { if( l >= 128 ) printf("array N overflow: i=%d, j=%d, k=%d\n", i,j,k); if (fabs(lib3ds_vector_dot(N[l], p->face->normal)-1.0)<1e-5) { found=1; break; } } if (!found) { if (f->smoothing & p->face->smoothing) { lib3ds_vector_add(n,n, p->face->normal); lib3ds_vector_copy(N[k], p->face->normal); ++k; } } } } else { lib3ds_vector_copy(n, f->normal); } lib3ds_vector_normalize(n); lib3ds_vector_copy(normalL[3*i+j], n); } } free(fa); free(fl); }