/* subsurf.c * * jun 2001 * * * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #ifdef HAVE_CONFIG_H #include #endif #ifdef WIN32 #include "BLI_winstuff.h" #endif #include #include #include #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "BKE_bad_level_calls.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_subsurf.h" #include "BKE_displist.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_arithb.h" #include "BLI_linklist.h" #include "BLI_memarena.h" /* * TODO * * make uvco's && vcol's properly subdivided * - requires moving uvco and vcol data to vertices * (where it belongs?), or making sharedness explicit * remove/integrate zsl functions * clean up uvco && vcol stuff * add option to update subsurf only after done transverting * decouple display subdivlevel and render subdivlevel * look into waves/particles with subsurfs * groan... make it work with sticky? * U check if storing tfaces (clut, tpage) in a displist is * going to be a mem problem (for example, on duplicate) * U write game blender convert routine * U thorough rendering check + background * */ /****/ static float *Vec2Cpy(float *t, float *a) { t[0]= a[0]; t[1]= a[1]; return t; } static float *Vec3Cpy(float *t, float *a) { t[0]= a[0]; t[1]= a[1]; t[2]= a[2]; return t; } static float *Vec2CpyI(float *t, float x, float y) { t[0]= x; t[1]= y; return t; } static float *Vec3CpyI(float *t, float x, float y, float z) { t[0]= x; t[1]= y; t[2]= z; return t; } static float *Vec2AvgT(float *t, float *a, float *b) { t[0]= (a[0]+b[0])*0.5f; t[1]= (a[1]+b[1])*0.5f; return t; } static float *Vec3AvgT(float *t, float *a, float *b) { t[0]= (a[0]+b[0])*0.5f; t[1]= (a[1]+b[1])*0.5f; t[2]= (a[2]+b[2])*0.5f; return t; } static float *Vec3AddT(float *t, float *a, float *b) { t[0]= a[0]+b[0]; t[1]= a[1]+b[1]; t[2]= a[2]+b[2]; return t; } static float *Vec2Add(float *ta, float *b) { ta[0]+= b[0]; ta[1]+= b[1]; return ta; } static float *Vec3MulNT(float *t, float *a, float n) { t[0]= a[0]*n; t[1]= a[1]*n; t[2]= a[2]*n; return t; } static float *Vec3Add(float *ta, float *b) { ta[0]+= b[0]; ta[1]+= b[1]; ta[2]+= b[2]; return ta; } static float *Vec2MulN(float *ta, float n) { ta[0]*= n; ta[1]*= n; return ta; } static float *Vec3MulN(float *ta, float n) { ta[0]*= n; ta[1]*= n; ta[2]*= n; return ta; } /****/ typedef struct _HyperVert HyperVert; typedef struct _HyperEdge HyperEdge; typedef struct _HyperFace HyperFace; typedef struct _HyperMesh HyperMesh; struct _HyperVert { HyperVert *next; float co[3]; EditVert *orig; // if set, pointer to original vertex HyperVert *nmv; LinkNode *edges, *faces; }; /* hyper edge flags */ #define DR_OPTIM 1 #define HE_SEAM 2 struct _HyperEdge { HyperEdge *next; HyperVert *v[2]; HyperVert *ep; int flag; // added for drawing optimal float sharp; // sharpness weight EditEdge *ee; // for selection state LinkNode *faces; }; struct _HyperFace { HyperFace *next; int nverts; HyperVert **verts; HyperEdge **edges; HyperVert *mid; unsigned char (*vcol)[4]; float (*uvco)[2]; short unwrap; /* for getting back tface, matnr, etc */ union { int ind; EditFace *ef; } orig; }; struct _HyperMesh { HyperVert *verts; HyperEdge *edges; HyperFace *faces; HyperFace *lastface; // we add faces in same order they get delivered now (ton) Mesh *orig_me; short hasuvco, hasvcol; MemArena *arena; }; /***/ static HyperEdge *hypervert_find_edge(HyperVert *v, HyperVert *to) { LinkNode *l; for (l= v->edges; l; l= l->next) { HyperEdge *e= l->link; if ((e->v[0]==v&&e->v[1]==to) || (e->v[1]==v&&e->v[0]==to)) return e; } return NULL; } static int hyperedge_is_boundary(HyperEdge *e) { /* len(e->faces) <= 1 */ return (!e->faces || !e->faces->next); } static int hypervert_is_boundary(HyperVert *v) { LinkNode *l; for (l= v->edges; l; l= l->next) if (hyperedge_is_boundary(l->link)) return 1; return 0; } static HyperVert *hyperedge_other_vert(HyperEdge *e, HyperVert *a) { return (a==e->v[0])?e->v[1]:e->v[0]; } static HyperVert *hypermesh_add_vert(HyperMesh *hme, float *co, EditVert *orig) { HyperVert *hv= BLI_memarena_alloc(hme->arena, sizeof(*hv)); hv->nmv= NULL; hv->edges= NULL; hv->faces= NULL; Vec3Cpy(hv->co, co); hv->orig= orig; hv->next= hme->verts; hme->verts= hv; return hv; } static HyperEdge *hypermesh_add_edge(HyperMesh *hme, HyperVert *v1, HyperVert *v2, int flag, float sharp, EditEdge *ee) { HyperEdge *he= BLI_memarena_alloc(hme->arena, sizeof(*he)); BLI_linklist_prepend_arena(&v1->edges, he, hme->arena); BLI_linklist_prepend_arena(&v2->edges, he, hme->arena); he->v[0]= v1; he->v[1]= v2; he->ep= NULL; he->faces= NULL; he->sharp = sharp; he->flag= flag; he->ee= ee; he->next= hme->edges; hme->edges= he; return he; } static HyperFace *hypermesh_add_face(HyperMesh *hme, HyperVert **verts, int nverts, int flag) { HyperFace *f= BLI_memarena_alloc(hme->arena, sizeof(*f)); HyperVert *last; int j; f->mid= NULL; f->vcol= NULL; f->uvco= NULL; f->nverts= nverts; f->verts= BLI_memarena_alloc(hme->arena, sizeof(*f->verts)*f->nverts); f->edges= BLI_memarena_alloc(hme->arena, sizeof(*f->edges)*f->nverts); last= verts[nverts-1]; for (j=0; jverts[j]= v; f->edges[j]= e; BLI_linklist_prepend_arena(&v->faces, f, hme->arena); BLI_linklist_prepend_arena(&e->faces, f, hme->arena); last= v; } // less elegant, but for many reasons i prefer the order of faces to remain same (vpaint etc) (ton) f->next= NULL; if(hme->lastface) hme->lastface->next= f; else hme->faces= f; hme->lastface= f; return f; } static HyperMesh *hypermesh_new(void) { HyperMesh *hme= MEM_mallocN(sizeof(*hme), "hme"); hme->verts= NULL; hme->edges= NULL; hme->faces= hme->lastface= NULL; hme->orig_me= NULL; hme->hasuvco= hme->hasvcol= 0; hme->arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); return hme; } static HyperMesh *hypermesh_from_mesh(Mesh *me, float *extverts, int subdivLevels) { HyperMesh *hme= hypermesh_new(); HyperVert **vert_tbl; MFace *mface= me->mface; MEdge *medge= me->medge; float creasefac= ((float)subdivLevels)/255.0; // in Mesh sharpness is byte int i, j, flag; hme->orig_me= me; if (me->tface) hme->hasvcol= hme->hasuvco= 1; else if (me->mcol) hme->hasvcol= 1; vert_tbl= MEM_mallocN(sizeof(*vert_tbl)*me->totvert, "vert_tbl"); for (i= 0; itotvert; i++) { if (extverts) vert_tbl[i]= hypermesh_add_vert(hme, &extverts[i*3], NULL); else vert_tbl[i]= hypermesh_add_vert(hme, me->mvert[i].co, NULL); } if(medge) { for (i=0; itotedge; i++) { MEdge *med= &medge[i]; flag= DR_OPTIM; if(med->flag & ME_SEAM) flag |= HE_SEAM; hypermesh_add_edge(hme, vert_tbl[med->v1], vert_tbl[med->v2], flag, creasefac*((float)med->crease), NULL); } } for (i=0; itotface; i++) { MFace *mf= &mface[i]; if (mf->v3) { int nverts= mf->v4?4:3; HyperVert *verts[4]; HyperFace *f; verts[0]= vert_tbl[mf->v1]; verts[1]= vert_tbl[mf->v2]; verts[2]= vert_tbl[mf->v3]; if (nverts>3) verts[3]= vert_tbl[mf->v4]; f= hypermesh_add_face(hme, verts, nverts, DR_OPTIM); f->orig.ind= i; if (hme->hasuvco) { TFace *tf= &((TFace*) me->tface)[i]; f->uvco= BLI_memarena_alloc(hme->arena, sizeof(*f->uvco)*nverts); for (j=0; juvco[j], tf->uv[j]); f->vcol= BLI_memarena_alloc(hme->arena, sizeof(*f->vcol)*nverts); for (j=0; jvcol[j])= tf->col[j]; f->unwrap= tf->unwrap; } else if (hme->hasvcol) { MCol *mcol= &me->mcol[i*4]; f->vcol= BLI_memarena_alloc(hme->arena, sizeof(*f->vcol)*nverts); for (j=0; jvcol[j])= *((unsigned int*) &mcol[j]); } } else if(medge==NULL) { hypermesh_add_edge(hme, vert_tbl[mf->v1], vert_tbl[mf->v2], DR_OPTIM, 0.0, NULL); } } MEM_freeN(vert_tbl); return hme; } static HyperMesh *hypermesh_from_editmesh(EditMesh *em, int subdivLevels) { HyperMesh *hme= hypermesh_new(); EditVert *ev, *prevev; EditEdge *ee; EditFace *ef; float creasefac= (float)subdivLevels; int flag; /* hide flags rule: - face hidden, not do. is easy - edge hidden, always means face is hidden too - vertex hidden, always means edge is hidden too */ /* we only add vertices with edges, 'f1' is a free flag */ /* added: check for hide flag in vertices */ for (ev= em->verts.first; ev; ev= ev->next) { ev->f1= 1; ev->prev= NULL; } /* hack, tuck the new hypervert pointer into * the ev->prev link so we can find it easy, * then restore real prev links later. */ for (ee= em->edges.first; ee; ee= ee->next) { if(ee->v1->f1) { ee->v1->prev= (EditVert*) hypermesh_add_vert(hme, ee->v1->co, ee->v1); ee->v1->f1= 0; } if(ee->v2->f1) { ee->v2->prev= (EditVert*) hypermesh_add_vert(hme, ee->v2->co, ee->v2); ee->v2->f1= 0; } if((ee->h & 1)==0) { flag= DR_OPTIM; if(ee->seam) flag |= HE_SEAM; hypermesh_add_edge(hme, (HyperVert*) ee->v1->prev, (HyperVert*) ee->v2->prev, flag, creasefac*ee->crease, ee); } } for (ef= em->faces.first; ef; ef= ef->next) { if(ef->h==0) { int nverts= ef->v4?4:3; HyperVert *verts[4]; HyperFace *f; verts[0]= (HyperVert*) ef->v1->prev; verts[1]= (HyperVert*) ef->v2->prev; verts[2]= (HyperVert*) ef->v3->prev; if (nverts>3) verts[3]= (HyperVert*) ef->v4->prev; f= hypermesh_add_face(hme, verts, nverts, DR_OPTIM); f->orig.ef= ef; } } /* see hack above, restore the prev links */ for (prevev= NULL, ev= em->verts.first; ev; prevev= ev, ev= ev->next) ev->prev= prevev; return hme; } static void VColAvgT(unsigned char *t, unsigned char *a, unsigned char *b) { t[0]= (a[0]+b[0])>>1; t[1]= (a[1]+b[1])>>1; t[2]= (a[2]+b[2])>>1; t[3]= (a[3]+b[3])>>1; } static void hypermesh_calc_sharp_edge(HyperEdge *e, float co[3]) { Vec3AvgT(co, e->v[0]->co, e->v[1]->co); } static void hypermesh_calc_smooth_edge(HyperEdge *e, float co[3]) { int count; LinkNode *link; HyperFace *f; Vec3AddT(co, e->v[0]->co, e->v[1]->co); for (count=2, link= e->faces; link; count++, link= link->next) { f= (HyperFace *) link->link; Vec3Add(co, f->mid->co); } Vec3MulN(co, (float)(1.0/count)); } static void hypermesh_lininterp_vert(float co[3], float co1[3], float co2[3], float w) { float codiff[3]; codiff[0] = co2[0] - co1[0]; codiff[1] = co2[1] - co1[1]; codiff[2] = co2[2] - co1[2]; Vec3MulN(codiff, w); Vec3AddT(co, co1, codiff); } static void hypermesh_calc_interp_edge(HyperEdge *e, float co[3]) { float co1[3]; float co2[3]; hypermesh_calc_smooth_edge(e, co1); hypermesh_calc_sharp_edge(e, co2); hypermesh_lininterp_vert(co, co1, co2, e->sharp); } static void hypermesh_calc_smooth_vert(HyperVert *v, float co[3]) { float q[3], r[3], s[3]; LinkNode *link; HyperFace *f; HyperEdge *e; int count = 0; if (hypervert_is_boundary(v)) { Vec3CpyI(r, 0.0, 0.0, 0.0); for (count= 0, link= v->edges; link; link= link->next) { if (hyperedge_is_boundary(link->link)) { HyperVert *ov= hyperedge_other_vert(link->link, v); Vec3Add(r, ov->co); count++; } } /* I believe CC give the factors as 3/2k and 1/4k, but that doesn't make sense (to me) as they don't sum to unity... It's rarely important. */ Vec3MulNT(s, v->co, 0.75f); Vec3Add(s, Vec3MulN(r, (float)(1.0/(4.0*count)))); } else { Vec3Cpy(q, Vec3Cpy(r, Vec3CpyI(s, 0.0f, 0.0f, 0.0f))); for (count=0, link= v->faces; link; count++, link= link->next) { f= (HyperFace *) link->link; Vec3Add(q, f->mid->co); } Vec3MulN(q, (float)(1.0/count)); for (count=0, link= v->edges; link; count++, link= link->next) { e= (HyperEdge *) link->link; Vec3Add(r, hyperedge_other_vert(e, v)->co); } Vec3MulN(r, (float)(1.0/count)); Vec3MulNT(s, v->co, (float)(count-2)); Vec3Add(s, q); Vec3Add(s, r); Vec3MulN(s, (float)(1.0/count)); } Vec3Cpy(co, s); } static void hypermesh_calc_sharp_vert(HyperVert *v, float co[3]) { co[0] = v->co[0]; co[1] = v->co[1]; co[2] = v->co[2]; } static void hypermesh_calc_creased_vert(HyperVert *v, float co[3]) { HyperVert *e1v = NULL, *e2v = NULL; HyperEdge *he; LinkNode *link; int count; /* use the crease rule */ for (count= 0, link= v->edges; link; link= link->next) { he = (HyperEdge *)link->link; if (he->sharp != 0.0) { if (e1v) e2v = hyperedge_other_vert(he, v); else e1v = hyperedge_other_vert(he, v); } } co[0] = (e1v->co[0] + 6.0 * v->co[0] + e2v->co[0]) / 8.0; co[1] = (e1v->co[1] + 6.0 * v->co[1] + e2v->co[1]) / 8.0; co[2] = (e1v->co[2] + 6.0 * v->co[2] + e2v->co[2]) / 8.0; } static void hypermesh_calc_interp_vert(HyperVert *v, float co[3], float w) { float co1[3]; float co2[3]; hypermesh_calc_smooth_vert(v, co1); hypermesh_calc_creased_vert(v, co2); hypermesh_lininterp_vert(co, co1, co2, w); } static void hypermesh_subdivide(HyperMesh *me, HyperMesh *nme) { HyperVert *v; HyperEdge *e; HyperFace *f; LinkNode *link; float co[3]; int j, k; for (f= me->faces; f; f= f->next) { Vec3CpyI(co, 0.0, 0.0, 0.0); for (j=0; jnverts; j++) Vec3Add(co, f->verts[j]->co); Vec3MulN(co, (float)(1.0/f->nverts)); f->mid= hypermesh_add_vert(nme, co, NULL); } for (e= me->edges; e; e= e->next) { if (hyperedge_is_boundary(e) || (e->sharp > 1.0)) { hypermesh_calc_sharp_edge(e, co); } else { hypermesh_calc_interp_edge(e, co); } e->ep= hypermesh_add_vert(nme, co, NULL); } for (v= me->verts; v; v= v->next) { float s[3]; int sharpcnt = 0; float avgw = 0.0; /* count the sharp edges */ for (link= v->edges; link; link= link->next) { if (((HyperEdge *)link->link)->sharp != 0.0) { sharpcnt++; avgw += ((HyperEdge *)link->link)->sharp; } } avgw /= (float)sharpcnt; if (avgw > 1.0) avgw = 1.0; switch (sharpcnt) { case 0: case 1: hypermesh_calc_smooth_vert(v, s); break; case 2: hypermesh_calc_interp_vert(v, s, avgw); break; default: hypermesh_calc_sharp_vert(v, s); break; } v->nmv= hypermesh_add_vert(nme, s, v->orig); } for (e= me->edges; e; e= e->next) { hypermesh_add_edge(nme, e->v[0]->nmv, e->ep, e->flag, e->sharp>1.0?e->sharp-1.0:0.0, e->ee); hypermesh_add_edge(nme, e->v[1]->nmv, e->ep, e->flag, e->sharp>1.0?e->sharp-1.0:0.0, e->ee); } for (f= me->faces; f; f= f->next) { int last= f->nverts-1; unsigned char vcol_mid[4]; unsigned char vcol_edge[4][4]; float uvco_mid[2]; float uvco_edge[4][4]; if (me->hasvcol) { int t[4]= {0, 0, 0, 0}; for (j=0; jnverts; j++) { t[0]+= f->vcol[j][0]; t[1]+= f->vcol[j][1]; t[2]+= f->vcol[j][2]; t[3]+= f->vcol[j][3]; } vcol_mid[0]= t[0]/f->nverts; vcol_mid[1]= t[1]/f->nverts; vcol_mid[2]= t[2]/f->nverts; vcol_mid[3]= t[3]/f->nverts; for (j=0; jnverts; last= j, j++) VColAvgT(vcol_edge[j], f->vcol[last], f->vcol[j]); last= f->nverts-1; } if (me->hasuvco) { Vec2CpyI(uvco_mid, 0.0, 0.0); for (j=0; jnverts; j++) Vec2Add(uvco_mid, f->uvco[j]); Vec2MulN(uvco_mid, (float)(1.0/f->nverts)); for (j=0; jnverts; last= j, j++) Vec2AvgT(uvco_edge[j], f->uvco[last], f->uvco[j]); last= f->nverts-1; } for (j=0; jnverts; last=j, j++) { HyperVert *nv[4]; HyperFace *nf; nv[0]= f->verts[last]->nmv; nv[1]= f->edges[j]->ep; nv[2]= f->mid; nv[3]= f->edges[last]->ep; nf= hypermesh_add_face(nme, nv, 4, 0); nf->orig= f->orig; if (me->hasvcol) { nf->vcol= BLI_memarena_alloc(nme->arena, sizeof(*nf->vcol)*4); for (k=0; k<4; k++) { nf->vcol[0][k]= f->vcol[last][k]; nf->vcol[1][k]= vcol_edge[j][k]; nf->vcol[2][k]= vcol_mid[k]; nf->vcol[3][k]= vcol_edge[last][k]; } } if (me->hasuvco) { nf->uvco= BLI_memarena_alloc(nme->arena, sizeof(*nf->uvco)*4); Vec2Cpy(nf->uvco[0], f->uvco[last]); Vec2Cpy(nf->uvco[1], uvco_edge[j]); Vec2Cpy(nf->uvco[2], uvco_mid); Vec2Cpy(nf->uvco[3], uvco_edge[last]); if(j==0 && (f->unwrap & ((f->nverts==4)?TF_PIN4:TF_PIN3))) nf->unwrap= TF_PIN1; else if(j==1 && f->unwrap & TF_PIN1) nf->unwrap= TF_PIN1; else if(j==2 && f->unwrap & TF_PIN2) nf->unwrap= TF_PIN1; else if(j==3 && f->unwrap & TF_PIN3) nf->unwrap= TF_PIN1; else nf->unwrap= 0; } } } } /* Simple subdivision surface for radio and displacement */ static void hypermesh_simple_subdivide(HyperMesh *me, HyperMesh *nme) { HyperVert *v; HyperEdge *e; HyperFace *f; float co[3]; int j, k; for (f= me->faces; f; f= f->next) { /* Adds vert at center of each existing face */ Vec3CpyI(co, 0.0, 0.0, 0.0); for (j=0; jnverts; j++) Vec3Add(co, f->verts[j]->co); Vec3MulN(co, (float)(1.0/f->nverts)); f->mid= hypermesh_add_vert(nme, co, NULL); } for (e= me->edges; e; e= e->next) { /* Add vert in middle of each edge */ Vec3AvgT(co, e->v[0]->co, e->v[1]->co); e->ep= hypermesh_add_vert(nme, co, NULL); } for (v= me->verts; v; v= v->next) { v->nmv= hypermesh_add_vert(nme, v->co, v->orig); } for (e= me->edges; e; e= e->next) { /* Add original edges */ hypermesh_add_edge(nme, e->v[0]->nmv, e->ep, e->flag, 0.0, e->ee); hypermesh_add_edge(nme, e->v[1]->nmv, e->ep, e->flag, 0.0, e->ee); } for (f= me->faces; f; f= f->next) { int last= f->nverts-1; unsigned char vcol_mid[4]; unsigned char vcol_edge[4][4]; float uvco_mid[2]; float uvco_edge[4][4]; if (me->hasvcol) { int t[4]= {0, 0, 0, 0}; for (j=0; jnverts; j++) { t[0]+= f->vcol[j][0]; t[1]+= f->vcol[j][1]; t[2]+= f->vcol[j][2]; t[3]+= f->vcol[j][3]; } vcol_mid[0]= t[0]/f->nverts; vcol_mid[1]= t[1]/f->nverts; vcol_mid[2]= t[2]/f->nverts; vcol_mid[3]= t[3]/f->nverts; for (j=0; jnverts; last= j, j++) VColAvgT(vcol_edge[j], f->vcol[last], f->vcol[j]); last= f->nverts-1; } if (me->hasuvco) { Vec2CpyI(uvco_mid, 0.0, 0.0); for (j=0; jnverts; j++) Vec2Add(uvco_mid, f->uvco[j]); Vec2MulN(uvco_mid, (float)(1.0/f->nverts)); for (j=0; jnverts; last= j, j++) Vec2AvgT(uvco_edge[j], f->uvco[last], f->uvco[j]); last= f->nverts-1; } for (j=0; jnverts; last=j, j++) { HyperVert *nv[4]; HyperFace *nf; nv[0]= f->verts[last]->nmv; nv[1]= f->edges[j]->ep; nv[2]= f->mid; nv[3]= f->edges[last]->ep; nf= hypermesh_add_face(nme, nv, 4, 0); nf->orig= f->orig; if (me->hasvcol) { nf->vcol= BLI_memarena_alloc(nme->arena, sizeof(*nf->vcol)*4); for (k=0; k<4; k++) { nf->vcol[0][k]= f->vcol[last][k]; nf->vcol[1][k]= vcol_edge[j][k]; nf->vcol[2][k]= vcol_mid[k]; nf->vcol[3][k]= vcol_edge[last][k]; } } if (me->hasuvco) { nf->uvco= BLI_memarena_alloc(nme->arena, sizeof(*nf->uvco)*4); Vec2Cpy(nf->uvco[0], f->uvco[last]); Vec2Cpy(nf->uvco[1], uvco_edge[j]); Vec2Cpy(nf->uvco[2], uvco_mid); Vec2Cpy(nf->uvco[3], uvco_edge[last]); } } } } static void hypermesh_free(HyperMesh *me) { BLI_memarena_free(me->arena); MEM_freeN(me); } /*****/ static int hypermesh_get_nverts(HyperMesh *hme) { HyperVert *v; int count= 0; for (v= hme->verts; v; v= v->next) count++; return count; } static int hypermesh_get_nfaces(HyperMesh *hme) { HyperFace *f; int count= 0; for (f= hme->faces; f; f= f->next) count++; return count; } static int hypermesh_get_nedges(HyperMesh *hme) { HyperEdge *e; int count= 0; for (e= hme->edges; e; e= e->next) count++; return count; } /* flag is me->flag, for 'optim' */ static DispListMesh *hypermesh_to_displistmesh(HyperMesh *hme, short flag) { int nverts= hypermesh_get_nverts(hme); int nedges= hypermesh_get_nedges(hme); int nfaces= hypermesh_get_nfaces(hme); DispListMesh *dlm= MEM_callocN(sizeof(*dlm), "dlmesh"); HyperFace *f; HyperVert *v; HyperEdge *e; TFace *tfaces; MEdge *med; MFace *mfaces, *mf; int i, j; /* hme->orig_me==NULL if we are working on an editmesh */ if (hme->orig_me) { tfaces= hme->orig_me->tface; mfaces= hme->orig_me->mface; } else { tfaces= NULL; mfaces= NULL; } /* removed: handles for editmode. it now stores pointer to subsurfed vertex in editvert */ dlm->totvert= nverts; dlm->totface= nfaces; dlm->totedge= nedges; /* calloc for clear flag and nor in mvert */ dlm->mvert= MEM_callocN(dlm->totvert*sizeof(*dlm->mvert), "dlm->mvert"); dlm->medge= MEM_callocN(dlm->totedge*sizeof(*dlm->medge), "dlm->medge"); dlm->mface= MEM_mallocN(dlm->totface*sizeof(*dlm->mface), "dlm->mface"); /* these two blocks for live update of selection in editmode */ if (hme->orig_me==NULL) { dlm->editedge= MEM_callocN(dlm->totedge*sizeof(EditEdge *), "dlm->editface"); dlm->editface= MEM_mallocN(dlm->totface*sizeof(EditFace *), "dlm->editedge"); } if (hme->orig_me) { dlm->flag= hme->orig_me->flag; } else { dlm->flag= flag; } if (hme->hasuvco) dlm->tface= MEM_callocN(dlm->totface*sizeof(*dlm->tface), "dlm->tface"); else if (hme->hasvcol) dlm->mcol= MEM_mallocN(dlm->totface*4*sizeof(*dlm->mcol), "dlm->mcol"); for (i=0, v= hme->verts; inext) { MVert *mv= &dlm->mvert[i]; Vec3Cpy(mv->co, v->co); v->nmv= (void*) i; } /* we use by default edges for displistmesh now */ med= dlm->medge; for (i=0, e= hme->edges; e; e= e->next, med++, i++) { med->v1= (int) e->v[0]->nmv; med->v2= (int) e->v[1]->nmv; if (hme->orig_me==NULL) dlm->editedge[i]= e->ee; if(e->flag & DR_OPTIM) med->flag |= ME_EDGEDRAW; if(e->flag & HE_SEAM) med->flag |= ME_SEAM; } /* and we add pointer to subsurfed vertex in editvert */ if(hme->orig_me==NULL) { MVert *mv= dlm->mvert; for (v= hme->verts; v; v= v->next, mv++) { if(v->orig) v->orig->ssco= mv->co; } } /* faces */ mf= dlm->mface; for (i=0, f= hme->faces; f; i++, f= f->next) { /* There is a complicated dependancy here: * After a subdivision the points that were shifted will always be * first in the hme->verts list (because they are added last, but to * the head). This means that the HVert with index 0 will always be * a shifted vertice, and the shifted vertices (corners) are always * HFace->verts[0]. Therefore it is guaranteed that if any vertice * index is 0, it will always be in mf->v1, so we do not have to worry * about tweaking the indices. */ mf->v1= (int) f->verts[0]->nmv; mf->v2= (int) f->verts[1]->nmv; mf->v3= (int) f->verts[2]->nmv; mf->v4= (int) f->verts[3]->nmv; if (hme->orig_me) { MFace *origmf= &mfaces[f->orig.ind]; mf->mat_nr= origmf->mat_nr; mf->flag= origmf->flag; mf->puno= 0; } else { EditFace *origef= f->orig.ef; mf->mat_nr= origef->mat_nr; mf->flag= origef->flag; mf->puno= 0; // for subsurf draw in editmode dlm->editface[i]= origef; } /* although not used by 3d display, still needed for wire-render */ mf->edcode= 0; if (f->edges[0]->flag) mf->edcode|= ME_V4V1; if (f->edges[1]->flag) mf->edcode|= ME_V1V2; if (f->edges[2]->flag) mf->edcode|= ME_V2V3; if (f->edges[3]->flag) mf->edcode|= ME_V3V4; if (hme->hasuvco) { TFace *origtf, *tf= &dlm->tface[i]; //if (hme->orig_me) origtf= &tfaces[f->orig.ind]; //else ton: removed, hme->hasuvco doesn't happen in editmode (yet?) // origtf= f->orig.ef->tface; for (j=0; j<4; j++) { Vec2Cpy(tf->uv[j], f->uvco[j]); tf->col[j]= *((unsigned int*) f->vcol[j]); } tf->tpage= origtf->tpage; tf->flag= origtf->flag; tf->transp= origtf->transp; tf->mode= origtf->mode; tf->tile= origtf->tile; tf->unwrap= f->unwrap; } else if (hme->hasvcol) { MCol *mcolbase= &dlm->mcol[i*4]; for (j=0; j<4; j++) *((unsigned int*) &mcolbase[j])= *((unsigned int*) f->vcol[j]); } mf++; } displistmesh_calc_vert_normals(dlm); return dlm; } /* flag is me->flag, and 'optim' */ static DispListMesh *subsurf_subdivide_to_displistmesh(HyperMesh *hme, short subdiv, short flag, short type) { DispListMesh *dlm; int i; for (i= 0; ihasvcol= hme->hasvcol; tmp->hasuvco= hme->hasuvco; tmp->orig_me= hme->orig_me; if (type == ME_SIMPLE_SUBSURF) hypermesh_simple_subdivide(hme, tmp); else hypermesh_subdivide(hme, tmp); /* default to CC subdiv. */ hypermesh_free(hme); hme= tmp; } dlm= hypermesh_to_displistmesh(hme, flag); hypermesh_free(hme); return dlm; } DispListMesh *subsurf_make_dispListMesh_from_editmesh(EditMesh *em, int subdivLevels, int flags, short type) { if (subdivLevels<1) { return displistmesh_from_editmesh(em); } else { HyperMesh *hme= hypermesh_from_editmesh(em, subdivLevels); return subsurf_subdivide_to_displistmesh(hme, subdivLevels, flags, type); } } DispListMesh *subsurf_make_dispListMesh_from_mesh(Mesh *me, float *extverts, int subdivLevels, int flags) { if (subdivLevels<1) { return displistmesh_from_mesh(me, extverts); } else { HyperMesh *hme= hypermesh_from_mesh(me, extverts, subdivLevels); return subsurf_subdivide_to_displistmesh(hme, subdivLevels, flags, me->subsurftype); } } // editarmature.c void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) { /* Finds the subsurf limit positions for the verts in a mesh * and puts them in an array of floats. Please note that the * calculated vert positions is incorrect for the verts * on the boundary of the mesh. */ HyperMesh *hme= hypermesh_from_mesh(me, NULL, 1); // 1=subdivlevel HyperMesh *nme= hypermesh_new(); float edge_sum[3], face_sum[3]; HyperVert *hv; LinkNode *l; int i; hypermesh_subdivide(hme, nme); for (i= me->totvert-1,hv=hme->verts; i>=0; i--,hv=hv->next) { int N= 0; edge_sum[0]= edge_sum[1]= edge_sum[2]= 0.0; face_sum[0]= face_sum[1]= face_sum[2]= 0.0; for (N=0,l=hv->edges; l; N++,l= l->next) { Vec3Add(edge_sum, ((HyperEdge*) l->link)->ep->co); } for (l=hv->faces; l; l= l->next) { Vec3Add(face_sum, ((HyperFace*) l->link)->mid->co); } positions_r[i][0] = (hv->nmv->co[0]*N*N + edge_sum[0]*4 + face_sum[0])/(N*(N+5)); positions_r[i][1] = (hv->nmv->co[1]*N*N + edge_sum[1]*4 + face_sum[1])/(N*(N+5)); positions_r[i][2] = (hv->nmv->co[2]*N*N + edge_sum[2]*4 + face_sum[2])/(N*(N+5)); } hypermesh_free(nme); hypermesh_free(hme); }