diff options
author | Nicholas Bishop <nicholasbishop@gmail.com> | 2007-12-26 12:39:15 +0300 |
---|---|---|
committer | Nicholas Bishop <nicholasbishop@gmail.com> | 2007-12-26 12:39:15 +0300 |
commit | 88e71a5b799e852d6803a8c9075c4b46305e2478 (patch) | |
tree | 44486d6b994b41aa9911dee0c7dc6070135e70a9 /source/blender | |
parent | b0b3a69c19fd60e6c48a877b22cab0ba48882c20 (diff) |
== Multires ==
Cleaned up bad level calls for multires; moved most of multires functions to blenkern, where they should have been in the first place. Functionality of the tool is unchanged.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_bad_level_calls.h | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_multires.h | 67 | ||||
-rw-r--r-- | source/blender/blenkernel/bad_level_call_stubs/stubs.c | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/multires-firstlevel.c (renamed from source/blender/src/multires-firstlevel.c) | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/multires.c | 1393 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 2 | ||||
-rw-r--r-- | source/blender/include/multires.h | 28 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Mesh.c | 3 | ||||
-rw-r--r-- | source/blender/src/buttons_editing.c | 5 | ||||
-rw-r--r-- | source/blender/src/editface.c | 2 | ||||
-rw-r--r-- | source/blender/src/editmesh.c | 1 | ||||
-rw-r--r-- | source/blender/src/editobject.c | 2 | ||||
-rw-r--r-- | source/blender/src/multires.c | 1355 | ||||
-rw-r--r-- | source/blender/src/space.c | 1 | ||||
-rw-r--r-- | source/blender/src/vpaint.c | 1 |
17 files changed, 1497 insertions, 1389 deletions
diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h index 02e2f799103..923504dfeab 100644 --- a/source/blender/blenkernel/BKE_bad_level_calls.h +++ b/source/blender/blenkernel/BKE_bad_level_calls.h @@ -207,15 +207,6 @@ void post_layer_create(struct VLayer *vlayer); void post_layer_destroy(struct VLayer *vlayer); void post_server_add(void); -/* multires.c */ -struct Multires; -struct MultiresLevel; -struct MultiresLevel *multires_level_n(struct Multires *mr, int n); -void multires_free(struct Multires *mr); -void multires_set_level(struct Object *ob, struct Mesh *me, const int render); -void multires_update_levels(struct Mesh *me, const int render); -void multires_calc_level_maps(struct MultiresLevel *lvl); -struct Multires *multires_copy(struct Multires *orig); /* sculptmode.c */ struct SculptData; void sculpt_reset_curve(struct SculptData *sd); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h new file mode 100644 index 00000000000..54bf801fd25 --- /dev/null +++ b/source/blender/blenkernel/BKE_multires.h @@ -0,0 +1,67 @@ +/* + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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) 2007 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +struct CustomData; +struct EditMesh; +struct Multires; +struct MultiresLevel; +struct Mesh; +struct Object; + +/* Level access */ +struct MultiresLevel *current_level(struct Multires *mr); +struct MultiresLevel *multires_level_n(struct Multires *mr, int n); + +/* Level control */ +void multires_add_level(struct Object *ob, struct Mesh *me, const char subdiv_type); +void multires_set_level(struct Object *ob, struct Mesh *me, const int render); +void multires_free_level(struct MultiresLevel *lvl); + +void multires_edge_level_update(struct Object *ob, struct Mesh *me); + +void multires_free(struct Multires *mr); +struct Multires *multires_copy(struct Multires *orig); +void multires_create(struct Mesh *me); + +/* CustomData */ +void multires_delete_layer(struct Mesh *me, struct CustomData *cd, const int type, int n); +void multires_add_layer(struct Mesh *me, struct CustomData *cd, const int type, const int n); +void multires_del_lower_customdata(struct Multires *mr, struct MultiresLevel *cr_lvl); +/* After adding or removing vcolor layers, run this */ +void multires_load_cols(struct Mesh *me); + +/* Private (used in multires-firstlevel.c) */ +void multires_level_to_mesh(struct Object *ob, struct Mesh *me, const int render); +void multires_update_levels(struct Mesh *me, const int render); +void multires_update_first_level(struct Mesh *me, struct EditMesh *em); +void multires_update_customdata(struct MultiresLevel *lvl1, struct CustomData *src, + struct CustomData *dst, const int type); +void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em, + struct MultiresLevel *lvl, struct CustomData *src, + struct CustomData *dst, const int type); diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index e0aa288c7b2..8885d4db760 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -310,13 +310,7 @@ void post_geometry_free_constraint(struct VNode *vnode) {} void post_layer_create(struct VLayer *vlayer) {} void post_layer_destroy(struct VLayer *vlayer) {} void post_server_add(void) {} - /* Multires/sculpt stubs */ -struct MultiresLevel *multires_level_n(struct Multires *mr, int n) {return NULL;} -void multires_free(struct Multires *mr) {} -void multires_set_level(struct Object *ob, struct Mesh *me, const int render) {} -void multires_update_levels(struct Mesh *me, const int render) {} -void multires_calc_level_maps(struct MultiresLevel *lvl) {} -struct Multires *multires_copy(struct Multires *orig) {return NULL;} + /* sculpt stubs */ void sculpt_reset_curve(struct SculptData *sd) {} void sculptmode_init(struct Scene *sce) {} void sculptmode_free_all(struct Scene *sce) {} diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 9d51fc645ba..aada60be21b 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -74,6 +74,7 @@ #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_object.h" #include "BKE_subsurf.h" #include "BKE_texture.h" @@ -87,8 +88,6 @@ #include "BIF_gl.h" #include "BIF_glutil.h" -#include "multires.h" - // headers for fluidsim bobj meshes #include <stdlib.h> #include "LBM_fluidsim.h" diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 56b1fe7e75b..6156b2bed89 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -63,6 +63,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_subsurf.h" #include "BKE_displist.h" #include "BKE_library.h" @@ -83,8 +84,6 @@ #include "BLI_editVert.h" #include "BLI_arithb.h" -#include "multires.h" - int update_realtime_texture(MTFace *tface, double time) { Image *ima; diff --git a/source/blender/src/multires-firstlevel.c b/source/blender/blenkernel/intern/multires-firstlevel.c index 2be867b5db0..778dd6f9c77 100644 --- a/source/blender/src/multires-firstlevel.c +++ b/source/blender/blenkernel/intern/multires-firstlevel.c @@ -43,13 +43,13 @@ #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BLI_editVert.h" #include "MEM_guardedalloc.h" #include "blendef.h" -#include "multires.h" #include <string.h> @@ -392,7 +392,6 @@ void multires_delete_layer(Mesh *me, CustomData *cd, const int type, int n) } } -MultiresLevel *current_level(Multires *mr); void multires_add_layer(Mesh *me, CustomData *cd, const int type, const int n) { if(me && me->mr && cd) { diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c new file mode 100644 index 00000000000..2b50f37e7a1 --- /dev/null +++ b/source/blender/blenkernel/intern/multires.c @@ -0,0 +1,1393 @@ +/* + * $Id$ + * + * ***** BEGIN GPL 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. + * + * 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) 2007 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_vec_types.h" + +#include "BDR_sculptmode.h" + +#include "BIF_editmesh.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_editVert.h" + +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_multires.h" + +#include "blendef.h" +#include "editmesh.h" + +#include <math.h> + +/* Returns the active multires level (currently applied to the mesh) */ +MultiresLevel *current_level(Multires *mr) +{ + return BLI_findlink(&mr->levels, mr->current - 1); +} + +/* Returns the nth multires level, starting at 1 */ +MultiresLevel *multires_level_n(Multires *mr, int n) +{ + if(mr) + return BLI_findlink(&mr->levels, n - 1); + else + return NULL; +} + +/* Free and clear the temporary connectivity data */ +static void multires_free_temp_data(MultiresLevel *lvl) +{ + if(lvl) { + if(lvl->edge_boundary_states) MEM_freeN(lvl->edge_boundary_states); + if(lvl->vert_edge_map) MEM_freeN(lvl->vert_edge_map); + if(lvl->vert_face_map) MEM_freeN(lvl->vert_face_map); + if(lvl->map_mem) MEM_freeN(lvl->map_mem); + + lvl->edge_boundary_states = NULL; + lvl->vert_edge_map = lvl->vert_face_map = NULL; + lvl->map_mem = NULL; + } +} + +/* Does not actually free lvl itself */ +void multires_free_level(MultiresLevel *lvl) +{ + if(lvl) { + if(lvl->faces) MEM_freeN(lvl->faces); + if(lvl->edges) MEM_freeN(lvl->edges); + if(lvl->colfaces) MEM_freeN(lvl->colfaces); + + multires_free_temp_data(lvl); + } +} + +void multires_free(Multires *mr) +{ + if(mr) { + MultiresLevel* lvl= mr->levels.first; + + /* Free the first-level data */ + if(lvl) { + CustomData_free(&mr->vdata, lvl->totvert); + CustomData_free(&mr->fdata, lvl->totface); + MEM_freeN(mr->edge_flags); + MEM_freeN(mr->edge_creases); + } + + while(lvl) { + multires_free_level(lvl); + lvl= lvl->next; + } + + MEM_freeN(mr->verts); + + BLI_freelistN(&mr->levels); + + MEM_freeN(mr); + } +} + +static MultiresLevel *multires_level_copy(MultiresLevel *orig) +{ + if(orig) { + MultiresLevel *lvl= MEM_dupallocN(orig); + + lvl->next= lvl->prev= NULL; + lvl->faces= MEM_dupallocN(orig->faces); + lvl->colfaces= MEM_dupallocN(orig->colfaces); + lvl->edges= MEM_dupallocN(orig->edges); + lvl->edge_boundary_states = NULL; + lvl->vert_edge_map= lvl->vert_face_map= NULL; + lvl->map_mem= NULL; + + return lvl; + } + return NULL; +} + +Multires *multires_copy(Multires *orig) +{ + const CustomDataMask vdata_mask= CD_MASK_MDEFORMVERT; + + if(orig) { + Multires *mr= MEM_dupallocN(orig); + MultiresLevel *lvl; + + mr->levels.first= mr->levels.last= NULL; + + for(lvl= orig->levels.first; lvl; lvl= lvl->next) + BLI_addtail(&mr->levels, multires_level_copy(lvl)); + + mr->verts= MEM_dupallocN(orig->verts); + + lvl= mr->levels.first; + if(lvl) { + CustomData_copy(&orig->vdata, &mr->vdata, vdata_mask, CD_DUPLICATE, lvl->totvert); + CustomData_copy(&orig->fdata, &mr->fdata, CD_MASK_MTFACE, CD_DUPLICATE, lvl->totface); + mr->edge_flags= MEM_dupallocN(orig->edge_flags); + mr->edge_creases= MEM_dupallocN(orig->edge_creases); + } + + return mr; + } + return NULL; +} + +static void multires_get_vert(MVert *out, EditVert *eve, MVert *m, int i) +{ + if(eve) { + VecCopyf(out->co, eve->co); + out->flag= 0; + if(eve->f & SELECT) out->flag |= 1; + if(eve->h) out->flag |= ME_HIDE; + eve->tmp.l= i; + } + else + *out= *m; +} + +void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease) +{ + if(!eed || !flag) return; + + /* Would be nice if EditMesh edge flags could be unified with Mesh flags! */ + *flag= (eed->f & SELECT) | ME_EDGERENDER; + if(eed->f2<2) *flag |= ME_EDGEDRAW; + if(eed->f2==0) *flag |= ME_LOOSEEDGE; + if(eed->sharp) *flag |= ME_SHARP; + if(eed->seam) *flag |= ME_SEAM; + if(eed->h & EM_FGON) *flag |= ME_FGON; + if(eed->h & 1) *flag |= ME_HIDE; + + *crease= (char)(255.0*eed->crease); +} + +static void multires_get_edge(MultiresEdge *e, EditEdge *eed, MEdge *m, short *flag, char *crease) +{ + if(eed) { + e->v[0]= eed->v1->tmp.l; + e->v[1]= eed->v2->tmp.l; + eed_to_medge_flag(eed, flag, crease); + } else { + e->v[0]= m->v1; + e->v[1]= m->v2; + *flag= m->flag; + *crease= m->crease; + } +} + +static void multires_get_face(MultiresFace *f, EditFace *efa, MFace *m) +{ + if(efa) { + MFace tmp; + int j; + tmp.v1= efa->v1->tmp.l; + tmp.v2= efa->v2->tmp.l; + tmp.v3= efa->v3->tmp.l; + tmp.v4= 0; + if(efa->v4) tmp.v4= efa->v4->tmp.l; + test_index_face(&tmp, NULL, 0, efa->v4?4:3); + for(j=0; j<4; ++j) f->v[j]= (&tmp.v1)[j]; + + /* Flags */ + f->flag= efa->flag; + if(efa->f & 1) f->flag |= ME_FACE_SEL; + else f->flag &= ~ME_FACE_SEL; + if(efa->h) f->flag |= ME_HIDE; + f->mat_nr= efa->mat_nr; + } else { + f->v[0]= m->v1; + f->v[1]= m->v2; + f->v[2]= m->v3; + f->v[3]= m->v4; + f->flag= m->flag; + f->mat_nr= m->mat_nr; + } +} + +/* For manipulating vertex colors / uvs */ +static void mcol_to_multires(MultiresColFace *mrf, MCol *mcol) +{ + char i; + for(i=0; i<4; ++i) { + mrf->col[i].a= mcol[i].a; + mrf->col[i].r= mcol[i].r; + mrf->col[i].g= mcol[i].g; + mrf->col[i].b= mcol[i].b; + } +} + +/* 1 <= count <= 4 */ +static void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count) +{ + unsigned i; + avg->a= avg->r= avg->g= avg->b= 0; + for(i=0; i<count; ++i) { + avg->a+= cols[i].a; + avg->r+= cols[i].r; + avg->g+= cols[i].g; + avg->b+= cols[i].b; + } + avg->a/= count; + avg->r/= count; + avg->g/= count; + avg->b/= count; +} + +static void multires_col_avg2(MultiresCol *avg, MultiresCol *c1, MultiresCol *c2) +{ + MultiresCol in[2]; + in[0]= *c1; + in[1]= *c2; + multires_col_avg(avg,in,2); +} + +void multires_load_cols(Mesh *me) +{ + MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *cur; + EditMesh *em= G.obedit ? G.editMesh : NULL; + CustomData *src= em ? &em->fdata : &me->fdata; + EditFace *efa= NULL; + unsigned i,j; + + if(!CustomData_has_layer(src, CD_MCOL) && !CustomData_has_layer(src, CD_MTFACE)) return; + + /* Add texcol data */ + for(cur= me->mr->levels.first; cur; cur= cur->next) + if(!cur->colfaces) + cur->colfaces= MEM_callocN(sizeof(MultiresColFace)*cur->totface,"ColFaces"); + + me->mr->use_col= CustomData_has_layer(src, CD_MCOL); + + if(em) efa= em->faces.first; + for(i=0; i<lvl->totface; ++i) { + MultiresColFace *f= &lvl->colfaces[i]; + + if(me->mr->use_col) + mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]); + + if(em) efa= efa->next; + } + + /* Update higher levels */ + lvl= lvl->next; + while(lvl) { + MultiresColFace *cf= lvl->colfaces; + for(i=0; i<lvl->prev->totface; ++i) { + const char sides= lvl->prev->faces[i].v[3]?4:3; + MultiresCol cntr; + + /* Find average color of 4 (or 3 for triangle) verts */ + multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides); + + for(j=0; j<sides; ++j) { + MultiresColFace *pf= &lvl->prev->colfaces[i]; + + multires_col_avg2(&cf->col[0], + &pf->col[j], + &pf->col[j==0?sides-1:j-1]); + cf->col[1]= pf->col[j]; + multires_col_avg2(&cf->col[2], + &pf->col[j], + &pf->col[j==sides-1?0:j+1]); + cf->col[3]= cntr; + + ++cf; + } + } + lvl= lvl->next; + } + + /* Update lower levels */ + lvl= me->mr->levels.last; + lvl= lvl->prev; + while(lvl) { + unsigned curf= 0; + for(i=0; i<lvl->totface; ++i) { + MultiresFace *f= &lvl->faces[i]; + for(j=0; j<(f->v[3]?4:3); ++j) { + lvl->colfaces[i].col[j]= lvl->next->colfaces[curf].col[1]; + ++curf; + } + } + lvl= lvl->prev; + } +} + +void multires_create(Mesh *me) +{ + MultiresLevel *lvl; + EditMesh *em= G.obedit ? G.editMesh : NULL; + EditVert *eve= NULL; + EditFace *efa= NULL; + EditEdge *eed= NULL; + int i; + + lvl= MEM_callocN(sizeof(MultiresLevel), "multires level"); + + if(me->pv) sculptmode_pmv_off(me); + + me->mr= MEM_callocN(sizeof(Multires), "multires data"); + + BLI_addtail(&me->mr->levels,lvl); + me->mr->current= 1; + me->mr->level_count= 1; + me->mr->edgelvl= 1; + me->mr->pinlvl= 1; + me->mr->renderlvl= 1; + + /* Load mesh (or editmesh) into multires data */ + + /* Load vertices and vdata (MDeformVerts) */ + lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert; + me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); + multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, + &me->mr->vdata, CD_MDEFORMVERT); + if(em) eve= em->verts.first; + for(i=0; i<lvl->totvert; ++i) { + multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); + if(em) eve= eve->next; + } + + /* Load faces and fdata (MTFaces) */ + lvl->totface= em ? BLI_countlist(&em->faces) : me->totface; + lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); + multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, + &me->mr->fdata, CD_MTFACE); + if(em) efa= em->faces.first; + for(i=0; i<lvl->totface; ++i) { + multires_get_face(&lvl->faces[i], efa, &me->mface[i]); + if(em) efa= efa->next; + } + + /* Load edges and edge_flags */ + lvl->totedge= em ? BLI_countlist(&em->edges) : me->totedge; + lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges"); + me->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge flags"); + me->mr->edge_creases= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge creases"); + if(em) eed= em->edges.first; + for(i=0; i<lvl->totedge; ++i) { + multires_get_edge(&lvl->edges[i], eed, &me->medge[i], &me->mr->edge_flags[i], &me->mr->edge_creases[i]); + if(em) eed= eed->next; + } + + multires_load_cols(me); +} + +typedef struct MultiresMapNode { + struct MultiresMapNode *next, *prev; + unsigned Index; +} MultiresMapNode; + +/* Produces temporary connectivity data for the multires lvl */ +static void multires_calc_temp_data(MultiresLevel *lvl) +{ + unsigned i, j, emax; + MultiresMapNode *indexnode= NULL; + + lvl->map_mem= MEM_mallocN(sizeof(MultiresMapNode)*(lvl->totedge*2 + lvl->totface*4), "map_mem"); + indexnode= lvl->map_mem; + + /* edge map */ + lvl->vert_edge_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_edge_map"); + for(i=0; i<lvl->totedge; ++i) { + for(j=0; j<2; ++j, ++indexnode) { + indexnode->Index= i; + BLI_addtail(&lvl->vert_edge_map[lvl->edges[i].v[j]], indexnode); + } + } + + /* face map */ + lvl->vert_face_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_face_map"); + for(i=0; i<lvl->totface; ++i){ + for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j, ++indexnode) { + indexnode->Index= i; + BLI_addtail(&lvl->vert_face_map[lvl->faces[i].v[j]], indexnode); + } + } + + /* edge boundaries */ + emax = (lvl->prev ? (lvl->prev->totedge * 2) : lvl->totedge); + lvl->edge_boundary_states= MEM_callocN(sizeof(char)*lvl->totedge, "edge_boundary_states"); + for(i=0; i<emax; ++i) { + MultiresMapNode *n1= lvl->vert_face_map[lvl->edges[i].v[0]].first; + unsigned total= 0; + + lvl->edge_boundary_states[i] = 1; + while(n1 && lvl->edge_boundary_states[i] == 1) { + MultiresMapNode *n2= lvl->vert_face_map[lvl->edges[i].v[1]].first; + while(n2) { + if(n1->Index == n2->Index) { + ++total; + + if(total > 1) { + lvl->edge_boundary_states[i] = 0; + break; + } + } + + n2= n2->next; + } + n1= n1->next; + } + } +} + +/* CATMULL-CLARK + ============= */ + +typedef struct MultiApplyData { + /* Smooth faces */ + float *corner1, *corner2, *corner3, *corner4; + char quad; + + /* Smooth edges */ + char boundary; + float edge_face_neighbor_midpoints_accum[3]; + unsigned edge_face_neighbor_midpoints_total; + float *endpoint1, *endpoint2; + + /* Smooth verts */ + /* uses 'char boundary' */ + float *original; + int edge_count; + float vert_face_neighbor_midpoints_average[3]; + float vert_edge_neighbor_midpoints_average[3]; + float boundary_edges_average[3]; +} MultiApplyData; + +/* Simply averages the four corners of a polygon. */ +static float catmullclark_smooth_face(MultiApplyData *data, const unsigned i) +{ + const float total= data->corner1[i]+data->corner2[i]+data->corner3[i]; + return data->quad ? (total+data->corner4[i])/4 : total/3; +} + +static float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i) +{ + float accum= 0; + unsigned count= 2; + + accum+= data->endpoint1[i] + data->endpoint2[i]; + + if(!data->boundary) { + accum+= data->edge_face_neighbor_midpoints_accum[i]; + count+= data->edge_face_neighbor_midpoints_total; + } + + return accum / count; +} + +static float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i) +{ + if(data->boundary) { + return data->original[i]*0.75 + data->boundary_edges_average[i]*0.25; + } else { + return (data->vert_face_neighbor_midpoints_average[i] + + 2*data->vert_edge_neighbor_midpoints_average[i] + + data->original[i]*(data->edge_count-3))/data->edge_count; + } +} + + + +/* Call func count times, passing in[i] as the input and storing the output in out[i] */ +static void multi_apply(float *out, MultiApplyData *data, + const unsigned count, float (*func)(MultiApplyData *, const unsigned)) +{ + unsigned i; + for(i=0; i<count; ++i) + out[i]= func(data,i); +} + +static short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v) +{ + MultiresMapNode *node= lvl->vert_edge_map[v].first; + while(node) { + if(lvl->edge_boundary_states[node->Index]) + return 1; + node= node->next; + } + return 0; +} + +#define GET_FLOAT(array, i, j, stride) (((float*)((char*)(array)+((i)*(stride))))[(j)]) + +static void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl, + void *array, const char stride, const MultiresEdge *e) +{ + ListBase *neighbors1= &lvl->vert_face_map[e->v[0]]; + ListBase *neighbors2= &lvl->vert_face_map[e->v[1]]; + MultiresMapNode *n1, *n2; + unsigned j,count= 0; + float *out= data->edge_face_neighbor_midpoints_accum; + + out[0]=out[1]=out[2]= 0; + + for(n1= neighbors1->first; n1; n1= n1->next) { + for(n2= neighbors2->first; n2; n2= n2->next) { + if(n1->Index == n2->Index) { + for(j=0; j<3; ++j) + out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride); + ++count; + } + } + } + + data->edge_face_neighbor_midpoints_total= count; +} + +static void vert_face_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl, + void *array, const char stride, const unsigned i) +{ + ListBase *neighbors= &lvl->vert_face_map[i]; + MultiresMapNode *n1; + unsigned j,count= 0; + float *out= data->vert_face_neighbor_midpoints_average; + + out[0]=out[1]=out[2]= 0; + + for(n1= neighbors->first; n1; n1= n1->next) { + for(j=0; j<3; ++j) + out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride); + ++count; + } + for(j=0; j<3; ++j) out[j]/= count; +} + +static void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl, + void *array, const char stride, const unsigned i) +{ + ListBase *neighbors= &lvl->vert_edge_map[i]; + MultiresMapNode *n1; + unsigned j,count= 0; + float *out= data->vert_edge_neighbor_midpoints_average; + + out[0]=out[1]=out[2]= 0; + + for(n1= neighbors->first; n1; n1= n1->next) { + for(j=0; j<3; ++j) + out[j]+= (GET_FLOAT(array,lvl->edges[n1->Index].v[0],j,stride) + + GET_FLOAT(array,lvl->edges[n1->Index].v[1],j,stride)) / 2; + ++count; + } + for(j=0; j<3; ++j) out[j]/= count; +} + +static void boundary_edges_average(MultiApplyData *data, MultiresLevel *lvl, + void *array, const char stride, const unsigned i) +{ + ListBase *neighbors= &lvl->vert_edge_map[i]; + MultiresMapNode *n1; + unsigned j,count= 0; + float *out= data->boundary_edges_average; + + out[0]=out[1]=out[2]= 0; + + for(n1= neighbors->first; n1; n1= n1->next) { + const MultiresEdge *e= &lvl->edges[n1->Index]; + const unsigned end= e->v[0]==i ? e->v[1] : e->v[0]; + + if(lvl->edge_boundary_states[n1->Index]) { + for(j=0; j<3; ++j) + out[j]+= GET_FLOAT(array,end,j,stride); + ++count; + } + } + for(j=0; j<3; ++j) out[j]/= count; +} + +/* END CATMULL-CLARK + ================= */ + +/* Update vertex locations and vertex flags */ +static void multires_update_vertices(Mesh *me, EditMesh *em) +{ + MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, + *last_lvl= me->mr->levels.last; + vec3f *pr_deltas= NULL, *cr_deltas= NULL, *swap_deltas= NULL; + EditVert *eve= NULL; + MultiApplyData data; + int i, j; + + /* Prepare deltas */ + pr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 1"); + cr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 2"); + + /* Calculate initial deltas -- current mesh subtracted from current level*/ + if(em) eve= em->verts.first; + for(i=0; i<cr_lvl->totvert; ++i) { + if(em) { + VecSubf(&cr_deltas[i].x, eve->co, me->mr->verts[i].co); + eve= eve->next; + } else + VecSubf(&cr_deltas[i].x, me->mvert[i].co, me->mr->verts[i].co); + } + + + /* Copy current level's vertex flags and clear the rest */ + if(em) eve= em->verts.first; + for(i=0; i < last_lvl->totvert; ++i) { + if(i < cr_lvl->totvert) { + MVert mvflag; + multires_get_vert(&mvflag, eve, &me->mvert[i], i); + if(em) eve= eve->next; + me->mr->verts[i].flag= mvflag.flag; + } + else + me->mr->verts[i].flag= 0; + } + + /* If already on the highest level, copy current verts (including flags) into current level */ + if(cr_lvl == last_lvl) { + if(em) + eve= em->verts.first; + for(i=0; i<cr_lvl->totvert; ++i) { + multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); + if(em) eve= eve->next; + } + } + + /* Update higher levels */ + pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); + cr_lvl= pr_lvl->next; + while(cr_lvl) { + multires_calc_temp_data(pr_lvl); + + /* Swap the old/new deltas */ + swap_deltas= pr_deltas; + pr_deltas= cr_deltas; + cr_deltas= swap_deltas; + + /* Calculate and add new deltas + ============================ */ + for(i=0; i<pr_lvl->totface; ++i) { + const MultiresFace *f= &pr_lvl->faces[i]; + data.corner1= &pr_deltas[f->v[0]].x; + data.corner2= &pr_deltas[f->v[1]].x; + data.corner3= &pr_deltas[f->v[2]].x; + data.corner4= &pr_deltas[f->v[3]].x; + data.quad= f->v[3] ? 1 : 0; + multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face); + + for(j=0; j<(data.quad?4:3); ++j) + me->mr->verts[f->mid].flag |= me->mr->verts[f->v[j]].flag; + } + + for(i=0; i<pr_lvl->totedge; ++i) { + const MultiresEdge *e= &pr_lvl->edges[i]; + data.boundary= pr_lvl->edge_boundary_states[i]; + edge_face_neighbor_midpoints_accum(&data,pr_lvl,cr_deltas,sizeof(vec3f),e); + data.endpoint1= &pr_deltas[e->v[0]].x; + data.endpoint2= &pr_deltas[e->v[1]].x; + multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge); + + for(j=0; j<2; ++j) + me->mr->verts[e->mid].flag |= me->mr->verts[e->v[j]].flag; + } + + for(i=0; i<pr_lvl->totvert; ++i) { + data.boundary= multires_vert_is_boundary(pr_lvl,i); + data.original= &pr_deltas[i].x; + data.edge_count= BLI_countlist(&pr_lvl->vert_edge_map[i]); + if(data.boundary) + boundary_edges_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); + else { + vert_face_neighbor_midpoints_average(&data,pr_lvl,cr_deltas,sizeof(vec3f),i); + vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); + } + multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert); + } + + /* Apply deltas to vertex locations */ + for(i=0; (cr_lvl == last_lvl) && (i < cr_lvl->totvert); ++i) { + VecAddf(me->mr->verts[i].co, + me->mr->verts[i].co, + &cr_deltas[i].x); + } + + multires_free_temp_data(pr_lvl); + + pr_lvl= pr_lvl->next; + cr_lvl= cr_lvl->next; + } + if(pr_deltas) MEM_freeN(pr_deltas); + if(cr_deltas) MEM_freeN(cr_deltas); + +} + +static void multires_update_faces(Mesh *me, EditMesh *em) +{ + MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, + *last_lvl= me->mr->levels.last; + char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *or_flag_damaged= NULL, + *pr_mat_damaged= NULL, *cr_mat_damaged= NULL, *or_mat_damaged= NULL, *swap= NULL; + EditFace *efa= NULL; + unsigned i,j,curf; + + /* Find for each face whether flag/mat has changed */ + pr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); + cr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); + pr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); + cr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); + if(em) efa= em->faces.first; + for(i=0; i<cr_lvl->totface; ++i) { + MultiresFace mftmp; + multires_get_face(&mftmp, efa, &me->mface[i]); + if(cr_lvl->faces[i].flag != mftmp.flag) + cr_flag_damaged[i]= 1; + if(cr_lvl->faces[i].mat_nr != mftmp.mat_nr) + cr_mat_damaged[i]= 1; + + /* Update current level */ + cr_lvl->faces[i].flag= mftmp.flag; + cr_lvl->faces[i].mat_nr= mftmp.mat_nr; + + if(em) efa= efa->next; + } + or_flag_damaged= MEM_dupallocN(cr_flag_damaged); + or_mat_damaged= MEM_dupallocN(cr_mat_damaged); + + /* Update lower levels */ + cr_lvl= cr_lvl->prev; + while(cr_lvl) { + swap= pr_flag_damaged; + pr_flag_damaged= cr_flag_damaged; + cr_flag_damaged= swap; + + swap= pr_mat_damaged; + pr_mat_damaged= cr_mat_damaged; + cr_mat_damaged= swap; + + curf= 0; + for(i=0; i<cr_lvl->totface; ++i) { + const int sides= cr_lvl->faces[i].v[3] ? 4 : 3; + + /* Check damages */ + for(j=0; j<sides; ++j, ++curf) { + if(pr_flag_damaged[curf]) { + cr_lvl->faces[i].flag= cr_lvl->next->faces[curf].flag; + cr_flag_damaged[i]= 1; + } + if(pr_mat_damaged[curf]) { + cr_lvl->faces[i].mat_nr= cr_lvl->next->faces[curf].mat_nr; + cr_mat_damaged[i]= 1; + } + } + } + + cr_lvl= cr_lvl->prev; + } + + /* Clear to original damages */ + if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); + if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); + cr_flag_damaged= or_flag_damaged; + cr_mat_damaged= or_mat_damaged; + + /* Update higher levels */ + pr_lvl= current_level(me->mr); + cr_lvl= pr_lvl->next; + while(cr_lvl) { + swap= pr_flag_damaged; + pr_flag_damaged= cr_flag_damaged; + cr_flag_damaged= swap; + + swap= pr_mat_damaged; + pr_mat_damaged= cr_mat_damaged; + cr_mat_damaged= swap; + + /* Update faces */ + for(i=0, curf= 0; i<pr_lvl->totface; ++i) { + const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3; + for(j=0; j<sides; ++j, ++curf) { + if(pr_flag_damaged[i]) { + cr_lvl->faces[curf].flag= pr_lvl->faces[i].flag; + cr_flag_damaged[curf]= 1; + } + if(pr_mat_damaged[i]) { + cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr; + cr_mat_damaged[curf]= 1; + } + } + } + + pr_lvl= pr_lvl->next; + cr_lvl= cr_lvl->next; + } + + if(pr_flag_damaged) MEM_freeN(pr_flag_damaged); + if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); + if(pr_mat_damaged) MEM_freeN(pr_mat_damaged); + if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); +} + +void multires_update_colors(Mesh *me) +{ + MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); + MultiresCol *pr_deltas= NULL, *cr_deltas= NULL; + EditMesh *em= G.obedit ? G.editMesh : NULL; + CustomData *src= em ? &em->fdata : &me->fdata; + EditFace *efa= NULL; + unsigned i,j,curf= 0; + + if(me->mr->use_col) { + /* Calc initial deltas */ + cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"initial color/uv deltas"); + + if(em) efa= em->faces.first; + for(i=0; i<lvl->totface; ++i) { + MCol *col= em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]; + for(j=0; j<4; ++j) { + if(me->mr->use_col) { + cr_deltas[i*4+j].a= col[j].a - lvl->colfaces[i].col[j].a; + cr_deltas[i*4+j].r= col[j].r - lvl->colfaces[i].col[j].r; + cr_deltas[i*4+j].g= col[j].g - lvl->colfaces[i].col[j].g; + cr_deltas[i*4+j].b= col[j].b - lvl->colfaces[i].col[j].b; + } + } + if(em) efa= efa->next; + } + + /* Update current level */ + if(em) efa= em->faces.first; + for(i=0; i<lvl->totface; ++i) { + MultiresColFace *f= &lvl->colfaces[i]; + + if(me->mr->use_col) + mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]); + + if(em) efa= efa->next; + } + + /* Update higher levels */ + lvl= lvl->next; + while(lvl) { + /* Set up new deltas, but keep the ones from the previous level */ + if(pr_deltas) MEM_freeN(pr_deltas); + pr_deltas= cr_deltas; + cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"color deltas"); + + curf= 0; + for(i=0; i<lvl->prev->totface; ++i) { + const char sides= lvl->prev->faces[i].v[3]?4:3; + MultiresCol cntr; + + /* Find average color of 4 (or 3 for triangle) verts */ + multires_col_avg(&cntr,&pr_deltas[i*4],sides); + + for(j=0; j<sides; ++j) { + multires_col_avg2(&cr_deltas[curf*4], + &pr_deltas[i*4+j], + &pr_deltas[i*4+(j==0?sides-1:j-1)]); + cr_deltas[curf*4+1]= pr_deltas[i*4+j]; + multires_col_avg2(&cr_deltas[curf*4+2], + &pr_deltas[i*4+j], + &pr_deltas[i*4+(j==sides-1?0:j+1)]); + cr_deltas[curf*4+3]= cntr; + ++curf; + } + } + + for(i=0; i<lvl->totface; ++i) { + for(j=0; j<4; ++j) { + lvl->colfaces[i].col[j].a+= cr_deltas[i*4+j].a; + lvl->colfaces[i].col[j].r+= cr_deltas[i*4+j].r; + lvl->colfaces[i].col[j].g+= cr_deltas[i*4+j].g; + lvl->colfaces[i].col[j].b+= cr_deltas[i*4+j].b; + } + } + + lvl= lvl->next; + } + if(pr_deltas) MEM_freeN(pr_deltas); + if(cr_deltas) MEM_freeN(cr_deltas); + + /* Update lower levels */ + lvl= me->mr->levels.last; + lvl= lvl->prev; + while(lvl) { + MultiresColFace *nf= lvl->next->colfaces; + for(i=0; i<lvl->totface; ++i) { + MultiresFace *f= &lvl->faces[i]; + for(j=0; j<(f->v[3]?4:3); ++j) { + lvl->colfaces[i].col[j]= nf->col[1]; + ++nf; + } + } + lvl= lvl->prev; + } + } +} + +void multires_update_levels(Mesh *me, const int render) +{ + EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; + + multires_update_first_level(me, em); + multires_update_vertices(me, em); + multires_update_faces(me, em); + multires_update_colors(me); +} + +static void check_colors(Mesh *me) +{ + CustomData *src= G.obedit ? &G.editMesh->fdata : &me->fdata; + const char col= CustomData_has_layer(src, CD_MCOL); + + /* Check if vertex colors have been deleted or added */ + if(me->mr->use_col && !col) + me->mr->use_col= 0; + else if(!me->mr->use_col && col) { + me->mr->use_col= 1; + multires_load_cols(me); + } +} + +static unsigned int find_mid_edge(ListBase *vert_edge_map, + MultiresLevel *lvl, + const unsigned int v1, + const unsigned int v2 ) +{ + MultiresMapNode *n= vert_edge_map[v1].first; + while(n) { + if(lvl->edges[n->Index].v[0]==v2 || + lvl->edges[n->Index].v[1]==v2) + return lvl->edges[n->Index].mid; + + n= n->next; + } + return -1; +} + +static void medge_flag_to_eed(const short flag, const char crease, EditEdge *eed) +{ + if(!eed) return; + + if(flag & ME_SEAM) eed->seam= 1; + if(flag & ME_SHARP) eed->sharp = 1; + if(flag & SELECT) eed->f |= SELECT; + if(flag & ME_FGON) eed->h= EM_FGON; + if(flag & ME_HIDE) eed->h |= 1; + + eed->crease= ((float)crease)/255.0; +} + +static float clamp_component(const float c) +{ + if(c<0) return 0; + else if(c>255) return 255; + else return c; +} + +static void multires_to_mcol(MultiresColFace *f, MCol mcol[4]) +{ + unsigned char j; + for(j=0; j<4; ++j) { + mcol->a= clamp_component(f->col[j].a); + mcol->r= clamp_component(f->col[j].r); + mcol->g= clamp_component(f->col[j].g); + mcol->b= clamp_component(f->col[j].b); + ++mcol; + } +} + +void multires_level_to_mesh(Object *ob, Mesh *me, const int render) +{ + MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); + int i; + EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; + EditVert **eves= NULL; + EditEdge *eed= NULL; + + if(em) { + /* Remove editmesh elements */ + free_editMesh(em); + + eves= MEM_callocN(sizeof(EditVert*)*lvl->totvert, "editvert pointers"); + } else { + CustomData_free_layer_active(&me->vdata, CD_MVERT, me->totvert); + CustomData_free_layer_active(&me->edata, CD_MEDGE, me->totedge); + CustomData_free_layer_active(&me->fdata, CD_MFACE, me->totface); + CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); + CustomData_free_layers(&me->fdata, CD_MTFACE, me->totface); + CustomData_free_layers(&me->fdata, CD_MCOL, me->totface); + + me->totvert= lvl->totvert; + me->totface= lvl->totface; + me->totedge= lvl->totedge; + + CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); + CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge); + CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); + mesh_update_customdata_pointers(me); + } + + /* Vertices/Edges/Faces */ + + for(i=0; i<lvl->totvert; ++i) { + if(em) { + eves[i]= addvertlist(me->mr->verts[i].co, NULL); + if(me->mr->verts[i].flag & 1) eves[i]->f |= SELECT; + if(me->mr->verts[i].flag & ME_HIDE) eves[i]->h= 1; + eves[i]->data= NULL; + } + else + me->mvert[i]= me->mr->verts[i]; + } + for(i=0; i<lvl->totedge; ++i) { + if(em) { + addedgelist(eves[lvl->edges[i].v[0]], eves[lvl->edges[i].v[1]], NULL); + } else { + me->medge[i].v1= lvl->edges[i].v[0]; + me->medge[i].v2= lvl->edges[i].v[1]; + me->medge[i].flag &= ~ME_HIDE; + } + } + for(i=0; i<lvl->totface; ++i) { + if(em) { + EditVert *eve4= lvl->faces[i].v[3] ? eves[lvl->faces[i].v[3]] : NULL; + EditFace *efa= addfacelist(eves[lvl->faces[i].v[0]], eves[lvl->faces[i].v[1]], + eves[lvl->faces[i].v[2]], eve4, NULL, NULL); + efa->flag= lvl->faces[i].flag & ~ME_HIDE; + efa->mat_nr= lvl->faces[i].mat_nr; + if(lvl->faces[i].flag & ME_FACE_SEL) + efa->f |= SELECT; + if(lvl->faces[i].flag & ME_HIDE) efa->h= 1; + efa->data= NULL; + } + else { + me->mface[i].v1= lvl->faces[i].v[0]; + me->mface[i].v2= lvl->faces[i].v[1]; + me->mface[i].v3= lvl->faces[i].v[2]; + me->mface[i].v4= lvl->faces[i].v[3]; + me->mface[i].flag= lvl->faces[i].flag; + me->mface[i].flag &= ~ME_HIDE; + me->mface[i].mat_nr= lvl->faces[i].mat_nr; + } + } + + /* Edge flags */ + if(em) eed= em->edges.first; + if(lvl==me->mr->levels.first) { + for(i=0; i<lvl->totedge; ++i) { + if(em) { + medge_flag_to_eed(me->mr->edge_flags[i], me->mr->edge_creases[i], eed); + eed= eed->next; + } + else { + me->medge[i].flag= me->mr->edge_flags[i]; + me->medge[i].crease= me->mr->edge_creases[i]; + } + } + } else { + MultiresLevel *lvl1= me->mr->levels.first; + const int last= lvl1->totedge * pow(2, me->mr->current-1); + for(i=0; i<last; ++i) { + const int ndx= i / pow(2, me->mr->current-1); + + if(em) { + medge_flag_to_eed(me->mr->edge_flags[ndx], me->mr->edge_creases[ndx], eed); + eed= eed->next; + } + else { + me->medge[i].flag= me->mr->edge_flags[ndx]; + me->medge[i].crease= me->mr->edge_creases[ndx]; + } + } + } + + if(em) { + eed= em->edges.first; + for(i=0, eed= em->edges.first; i<lvl->totedge; ++i, eed= eed->next) { + eed->h= me->mr->verts[lvl->edges[i].v[0]].flag & ME_HIDE || + me->mr->verts[lvl->edges[i].v[1]].flag & ME_HIDE; + } + } + + EM_select_flush(); + + multires_customdata_to_mesh(me, em, lvl, &me->mr->vdata, em ? &em->vdata : &me->vdata, CD_MDEFORMVERT); + multires_customdata_to_mesh(me, em, lvl, &me->mr->fdata, em ? &em->fdata : &me->fdata, CD_MTFACE); + + /* Colors */ + if(me->mr->use_col) { + MCol c[4]; + EditFace *efa= NULL; + CustomData *src= em ? &em->fdata : &me->fdata; + if(em) { + if(me->mr->use_col) EM_add_data_layer(src, CD_MCOL); + efa= em->faces.first; + } + else { + if(me->mr->use_col) me->mcol= CustomData_add_layer(src, CD_MCOL, CD_CALLOC, NULL, me->totface); + } + + for(i=0; i<lvl->totface; ++i) { + if(em) { + if(me->mr->use_col) { + multires_to_mcol(&lvl->colfaces[i], c); + CustomData_em_set(src, efa->data, CD_MCOL, c); + } + efa= efa->next; + } + else if(me->mr->use_col) multires_to_mcol(&lvl->colfaces[i], &me->mcol[i*4]); + } + + } + + mesh_update_customdata_pointers(me); + + if(em) { + MEM_freeN(eves); + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + recalc_editnormals(); + } else { + multires_edge_level_update(ob,me); + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + } +} + +void multires_add_level(Object *ob, Mesh *me, const char subdiv_type) +{ + int i,j, curf, cure; + MultiresLevel *lvl= NULL; + MultiApplyData data; + MVert *oldverts= NULL; + + lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel"); + if(me->pv) sculptmode_pmv_off(me); + + check_colors(me); + multires_update_levels(me, 0); + + ++me->mr->level_count; + BLI_addtail(&me->mr->levels,lvl); + + /* Create vertices + =============== */ + lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface; + oldverts= me->mr->verts; + me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert, "multitres verts"); + /* Copy old verts */ + for(i=0; i<lvl->prev->totvert; ++i) + me->mr->verts[i]= oldverts[i]; + /* Create new edge verts */ + for(i=0; i<lvl->prev->totedge; ++i) { + VecMidf(me->mr->verts[lvl->prev->totvert + i].co, + oldverts[lvl->prev->edges[i].v[0]].co, + oldverts[lvl->prev->edges[i].v[1]].co); + lvl->prev->edges[i].mid= lvl->prev->totvert + i; + } + /* Create new face verts */ + for(i=0; i<lvl->prev->totface; ++i) { + lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i; + } + + multires_calc_temp_data(lvl->prev); + + /* Create faces + ============ */ + /* Allocate all the new faces (each triangle creates three, and + each quad creates four */ + lvl->totface= 0; + for(i=0; i<lvl->prev->totface; ++i) + lvl->totface+= lvl->prev->faces[i].v[3] ? 4 : 3; + lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); + + curf= 0; + for(i=0; i<lvl->prev->totface; ++i) { + const int max= lvl->prev->faces[i].v[3] ? 3 : 2; + + for(j=0; j<max+1; ++j) { + lvl->faces[curf].v[0]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev, + lvl->prev->faces[i].v[j], + lvl->prev->faces[i].v[j==0?max:j-1]); + lvl->faces[curf].v[1]= lvl->prev->faces[i].v[j]; + lvl->faces[curf].v[2]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev, + lvl->prev->faces[i].v[j], + lvl->prev->faces[i].v[j==max?0:j+1]); + lvl->faces[curf].v[3]= lvl->prev->totvert + lvl->prev->totedge + i; + lvl->faces[curf].flag= lvl->prev->faces[i].flag; + lvl->faces[curf].mat_nr= lvl->prev->faces[i].mat_nr; + + ++curf; + } + } + + /* Create edges + ============ */ + /* Figure out how many edges to allocate */ + lvl->totedge= lvl->prev->totedge*2; + for(i=0; i<lvl->prev->totface; ++i) + lvl->totedge+= lvl->prev->faces[i].v[3]?4:3; + lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges"); + + for(i=0; i<lvl->prev->totedge; ++i) { + lvl->edges[i*2].v[0]= lvl->prev->edges[i].v[0]; + lvl->edges[i*2].v[1]= lvl->prev->edges[i].mid; + lvl->edges[i*2+1].v[0]= lvl->prev->edges[i].mid; + lvl->edges[i*2+1].v[1]= lvl->prev->edges[i].v[1]; + } + /* Add edges inside of old polygons */ + curf= 0; + cure= lvl->prev->totedge*2; + for(i=0; i<lvl->prev->totface; ++i) { + for(j=0; j<(lvl->prev->faces[i].v[3]?4:3); ++j) { + lvl->edges[cure].v[0]= lvl->faces[curf].v[2]; + lvl->edges[cure].v[1]= lvl->faces[curf].v[3]; + ++cure; + ++curf; + } + } + + /* Smooth vertices + =============== */ + for(i=0; i<lvl->prev->totface; ++i) { + const MultiresFace *f= &lvl->prev->faces[i]; + data.corner1= oldverts[f->v[0]].co; + data.corner2= oldverts[f->v[1]].co; + data.corner3= oldverts[f->v[2]].co; + data.corner4= oldverts[f->v[3]].co; + data.quad= f->v[3] ? 1 : 0; + multi_apply(me->mr->verts[f->mid].co, &data, 3, catmullclark_smooth_face); + } + + if(subdiv_type == 0) { + for(i=0; i<lvl->prev->totedge; ++i) { + const MultiresEdge *e= &lvl->prev->edges[i]; + data.boundary= lvl->prev->edge_boundary_states[i]; + edge_face_neighbor_midpoints_accum(&data,lvl->prev, me->mr->verts, sizeof(MVert),e); + data.endpoint1= oldverts[e->v[0]].co; + data.endpoint2= oldverts[e->v[1]].co; + multi_apply(me->mr->verts[e->mid].co, &data, 3, catmullclark_smooth_edge); + } + + for(i=0; i<lvl->prev->totvert; ++i) { + data.boundary= multires_vert_is_boundary(lvl->prev,i); + data.original= oldverts[i].co; + data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]); + if(data.boundary) + boundary_edges_average(&data,lvl->prev, oldverts, sizeof(MVert),i); + else { + vert_face_neighbor_midpoints_average(&data,lvl->prev, me->mr->verts, + sizeof(MVert),i); + vert_edge_neighbor_midpoints_average(&data,lvl->prev, oldverts, + sizeof(MVert),i); + } + multi_apply(me->mr->verts[i].co, &data, 3, catmullclark_smooth_vert); + } + } + + multires_free_temp_data(lvl->prev); + MEM_freeN(oldverts); + + /* Vertex Colors + ============= */ + curf= 0; + if(me->mr->use_col) { + MultiresColFace *cf= MEM_callocN(sizeof(MultiresColFace)*lvl->totface,"Multirescolfaces"); + lvl->colfaces= cf; + for(i=0; i<lvl->prev->totface; ++i) { + const char sides= lvl->prev->faces[i].v[3]?4:3; + MultiresCol cntr; + + /* Find average color of 4 (or 3 for triangle) verts */ + multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides); + + for(j=0; j<sides; ++j) { + multires_col_avg2(&cf->col[0], + &lvl->prev->colfaces[i].col[j], + &lvl->prev->colfaces[i].col[j==0?sides-1:j-1]); + cf->col[1]= lvl->prev->colfaces[i].col[j]; + multires_col_avg2(&cf->col[2], + &lvl->prev->colfaces[i].col[j], + &lvl->prev->colfaces[i].col[j==sides-1?0:j+1]); + cf->col[3]= cntr; + + ++cf; + } + } + } + + me->mr->newlvl= me->mr->level_count; + me->mr->current= me->mr->newlvl; + /* Unless the render level has been set to something other than the + highest level (by the user), increment the render level to match + the highest available level */ + if(me->mr->renderlvl == me->mr->level_count - 1) me->mr->renderlvl= me->mr->level_count; + + multires_level_to_mesh(ob, me, 0); +} + +void multires_set_level(Object *ob, Mesh *me, const int render) +{ + if(me->pv) sculptmode_pmv_off(me); + + check_colors(me); + multires_update_levels(me, render); + + me->mr->current= me->mr->newlvl; + if(me->mr->current<1) me->mr->current= 1; + else if(me->mr->current>me->mr->level_count) me->mr->current= me->mr->level_count; + + multires_level_to_mesh(ob, me, render); +} + +/* Update the edge visibility flags to only show edges on or below the edgelvl */ +void multires_edge_level_update(Object *ob, Mesh *me) +{ + if(!G.obedit) { + MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); + MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1); + const int threshold= edge_lvl->totedge * powf(2, me->mr->current - me->mr->edgelvl); + unsigned i; + + for(i=0; i<cr_lvl->totedge; ++i) { + const int ndx= me->pv ? me->pv->edge_map[i] : i; + if(ndx != -1) { /* -1= hidden edge */ + if(me->mr->edgelvl >= me->mr->current || i<threshold) + me->medge[ndx].flag |= ME_EDGEDRAW | ME_EDGERENDER; + else + me->medge[ndx].flag &= ~ME_EDGEDRAW & ~ME_EDGERENDER; + } + } + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a90914e6dcb..d30f0da95d6 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -147,8 +147,6 @@ #include "BLO_undofile.h" #include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory -#include "multires.h" - #include "readfile.h" #include "genfile.h" diff --git a/source/blender/include/multires.h b/source/blender/include/multires.h index bfa765e62ef..54bba82b02d 100644 --- a/source/blender/include/multires.h +++ b/source/blender/include/multires.h @@ -43,39 +43,15 @@ struct uiBlock; int multires_test(); int multires_level1_test(); -struct MultiresLevel *multires_level_n(struct Multires *mr, int n); - void multires_draw_interface(struct uiBlock *block, unsigned short cx, unsigned short cy); -void multires_disp_map(void *, void*); void multires_make(void *ob, void *me); void multires_delete(void *ob, void *me); -struct Multires *multires_copy(struct Multires *orig); -void multires_free(struct Multires *mr); -void multires_free_level(struct MultiresLevel *lvl); +void multires_subdivide(void *ob, void *me); void multires_del_lower(void *ob, void *me); void multires_del_higher(void *ob, void *me); -void multires_add_level(void *ob, void *me); void multires_set_level_cb(void *ob, void *me); -void multires_set_level(struct Object *ob, struct Mesh *me, const int render); -void multires_update_levels(struct Mesh *me, const int render); -void multires_level_to_mesh(struct Object *ob, struct Mesh *me, const int render); -void multires_edge_level_update(void *ob, void *me); +void multires_edge_level_update_cb(void *ob, void *me); int multires_modifier_warning(); -/* after adding or removing vcolor layers, run this */ -void multires_load_cols(Mesh *me); - -/* multires-firstlevel.c */ -/* Generic */ -void multires_update_first_level(struct Mesh *me, struct EditMesh *em); -void multires_update_customdata(struct MultiresLevel *lvl1, struct CustomData *src, - struct CustomData *dst, const int type); -void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em, struct MultiresLevel *lvl, - struct CustomData *src, struct CustomData *dst, const int type); -void multires_del_lower_customdata(struct Multires *mr, struct MultiresLevel *cr_lvl); - -void multires_add_layer(struct Mesh *me, struct CustomData *cd, const int type, const int n); -void multires_delete_layer(struct Mesh *me, struct CustomData *cd, const int type, int n); - #endif diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 4424fd08ffd..8afbc75682a 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -1,5 +1,5 @@ /* - * $Id: Mesh.c 12892 2007-12-15 17:41:13Z joeedh $ + * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * @@ -60,6 +60,7 @@ #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_main.h" +#include "BKE_multires.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_DerivedMesh.h" diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index ca878933499..7da08378d56 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -89,6 +89,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_multires.h" #include "BKE_packedFile.h" #include "BKE_particle.h" #include "BKE_scene.h" @@ -5865,7 +5866,7 @@ void editing_panel_mesh_multires() uiBlockBeginAlign(block); but= uiDefBut(block,BUT,B_NOP,"Add Level", cx,cy,134,19,0,0,0,0,0,"Add a new level of subdivision at the end of the chain"); - uiButSetFunc(but,multires_add_level,ob,me); + uiButSetFunc(but, multires_subdivide, ob, me); uiDefButC(block, MENU, B_NOP, subsurfmenu, cx + 134, cy, 134, 19, &G.scene->toolsettings->multires_subdiv_type, 0, 0, 0, 0, "Selects type of subdivision algorithm."); cy-= 20; @@ -5881,7 +5882,7 @@ void editing_panel_mesh_multires() cy-= 20; but= uiDefButC(block,NUM,B_NOP,"Edges: ",cx,cy,268,19,(char *)&me->mr->edgelvl,1.0,me->mr->level_count,0,0,"Set level of edges to display"); - uiButSetFunc(but,multires_edge_level_update,ob,me); + uiButSetFunc(but,multires_edge_level_update_cb,ob,me); cy-= 20; uiBlockEndAlign(block); diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c index be3d9429d31..33b9a60104f 100644 --- a/source/blender/src/editface.c +++ b/source/blender/src/editface.c @@ -63,6 +63,7 @@ #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_object.h" #include "BKE_texture.h" #include "BKE_utildefines.h" @@ -93,7 +94,6 @@ #include "mydevice.h" #include "blendef.h" #include "butspace.h" -#include "multires.h" #include "BSE_trans_types.h" diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c index 15f4e652490..6e0eb42aaf6 100644 --- a/source/blender/src/editmesh.c +++ b/source/blender/src/editmesh.c @@ -72,6 +72,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_object.h" #include "BKE_texture.h" #include "BKE_utildefines.h" diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index c563548759c..163417d9f08 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -117,6 +117,7 @@ #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_nla.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -178,7 +179,6 @@ #include "blendef.h" #include "butspace.h" -#include "multires.h" #include "BIF_transform.h" #include "BIF_poseobject.h" diff --git a/source/blender/src/multires.c b/source/blender/src/multires.c index 8704f9abfa4..69e2caaf12e 100644 --- a/source/blender/src/multires.c +++ b/source/blender/src/multires.c @@ -52,6 +52,7 @@ #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_multires.h" #include "BKE_object.h" #include "BIF_editmesh.h" @@ -78,8 +79,6 @@ #include <math.h> -const CustomDataMask vdata_mask= CD_MASK_MDEFORMVERT; - void multires_calc_temp_data(struct MultiresLevel *lvl); int multires_test() @@ -109,24 +108,6 @@ void multires_check_state() sculptmode_correct_state(); } -typedef struct MultiresMapNode { - struct MultiresMapNode *next, *prev; - unsigned Index; -} MultiresMapNode; - -MultiresLevel *current_level(Multires *mr) -{ - return BLI_findlink(&mr->levels, mr->current - 1); -} - -MultiresLevel *multires_level_n(Multires *mr, int n) -{ - if(mr) - return BLI_findlink(&mr->levels, n - 1); - else - return NULL; -} - void Vec3fAvg3(float *out, float *v1, float *v2, float *v3) { out[0]= (v1[0]+v2[0]+v3[0])/3; @@ -140,376 +121,10 @@ void Vec3fAvg4(float *out, float *v1, float *v2, float *v3, float *v4) out[2]= (v1[2]+v2[2]+v3[2]+v4[2])/4; } -short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v) -{ - MultiresMapNode *node= lvl->vert_edge_map[v].first; - while(node) { - if(lvl->edge_boundary_states[node->Index]) - return 1; - node= node->next; - } - return 0; -} - -typedef struct MultiApplyData { - /* Smooth faces */ - float *corner1, *corner2, *corner3, *corner4; - char quad; - - /* Smooth edges */ - char boundary; - float edge_face_neighbor_midpoints_accum[3]; - unsigned edge_face_neighbor_midpoints_total; - float *endpoint1, *endpoint2; - - /* Smooth verts */ - /* uses 'char boundary' */ - float *original; - int edge_count; - float vert_face_neighbor_midpoints_average[3]; - float vert_edge_neighbor_midpoints_average[3]; - float boundary_edges_average[3]; -} MultiApplyData; - -/* CATMULL-CLARK - ============= */ - -/* Simply averages the four corners of a polygon. */ -float catmullclark_smooth_face(MultiApplyData *data, const unsigned i) -{ - const float total= data->corner1[i]+data->corner2[i]+data->corner3[i]; - return data->quad ? (total+data->corner4[i])/4 : total/3; -} - -float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i) -{ - float accum= 0; - unsigned count= 2; - - accum+= data->endpoint1[i] + data->endpoint2[i]; - - if(!data->boundary) { - accum+= data->edge_face_neighbor_midpoints_accum[i]; - count+= data->edge_face_neighbor_midpoints_total; - } - - return accum / count; -} -float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i) -{ - if(data->boundary) { - return data->original[i]*0.75 + data->boundary_edges_average[i]*0.25; - } else { - return (data->vert_face_neighbor_midpoints_average[i] + - 2*data->vert_edge_neighbor_midpoints_average[i] + - data->original[i]*(data->edge_count-3))/data->edge_count; - } -} - - - -/* Call func count times, passing in[i] as the input and storing the output in out[i] */ -void multi_apply(float *out, MultiApplyData *data, - const unsigned count, float (*func)(MultiApplyData *, const unsigned)) -{ - unsigned i; - for(i=0; i<count; ++i) - out[i]= func(data,i); -} - -#define GET_FLOAT(array, i, j, stride) (((float*)((char*)(array)+((i)*(stride))))[(j)]) - -void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const MultiresEdge *e) -{ - ListBase *neighbors1= &lvl->vert_face_map[e->v[0]]; - ListBase *neighbors2= &lvl->vert_face_map[e->v[1]]; - MultiresMapNode *n1, *n2; - unsigned j,count= 0; - float *out= data->edge_face_neighbor_midpoints_accum; - - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors1->first; n1; n1= n1->next) { - for(n2= neighbors2->first; n2; n2= n2->next) { - if(n1->Index == n2->Index) { - for(j=0; j<3; ++j) - out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride); - ++count; - } - } - } - - data->edge_face_neighbor_midpoints_total= count; -} -void vert_face_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const unsigned i) -{ - ListBase *neighbors= &lvl->vert_face_map[i]; - MultiresMapNode *n1; - unsigned j,count= 0; - float *out= data->vert_face_neighbor_midpoints_average; - - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors->first; n1; n1= n1->next) { - for(j=0; j<3; ++j) - out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride); - ++count; - } - for(j=0; j<3; ++j) out[j]/= count; -} -void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const unsigned i) -{ - ListBase *neighbors= &lvl->vert_edge_map[i]; - MultiresMapNode *n1; - unsigned j,count= 0; - float *out= data->vert_edge_neighbor_midpoints_average; - - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors->first; n1; n1= n1->next) { - for(j=0; j<3; ++j) - out[j]+= (GET_FLOAT(array,lvl->edges[n1->Index].v[0],j,stride) + - GET_FLOAT(array,lvl->edges[n1->Index].v[1],j,stride)) / 2; - ++count; - } - for(j=0; j<3; ++j) out[j]/= count; -} -void boundary_edges_average(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const unsigned i) -{ - ListBase *neighbors= &lvl->vert_edge_map[i]; - MultiresMapNode *n1; - unsigned j,count= 0; - float *out= data->boundary_edges_average; - - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors->first; n1; n1= n1->next) { - const MultiresEdge *e= &lvl->edges[n1->Index]; - const unsigned end= e->v[0]==i ? e->v[1] : e->v[0]; - - if(lvl->edge_boundary_states[n1->Index]) { - for(j=0; j<3; ++j) - out[j]+= GET_FLOAT(array,end,j,stride); - ++count; - } - } - for(j=0; j<3; ++j) out[j]/= count; -} - -/* For manipulating vertex colors / uvs */ -void mcol_to_multires(MultiresColFace *mrf, MCol *mcol) -{ - char i; - for(i=0; i<4; ++i) { - mrf->col[i].a= mcol[i].a; - mrf->col[i].r= mcol[i].r; - mrf->col[i].g= mcol[i].g; - mrf->col[i].b= mcol[i].b; - } -} - -float clamp_component(const float c) -{ - if(c<0) return 0; - else if(c>255) return 255; - else return c; -} - -void multires_to_mcol(MultiresColFace *f, MCol mcol[4]) -{ - unsigned char j; - for(j=0; j<4; ++j) { - mcol->a= clamp_component(f->col[j].a); - mcol->r= clamp_component(f->col[j].r); - mcol->g= clamp_component(f->col[j].g); - mcol->b= clamp_component(f->col[j].b); - ++mcol; - } -} - -/* 1 <= count <= 4 */ -void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count) -{ - unsigned i; - avg->a= avg->r= avg->g= avg->b= 0; - for(i=0; i<count; ++i) { - avg->a+= cols[i].a; - avg->r+= cols[i].r; - avg->g+= cols[i].g; - avg->b+= cols[i].b; - } - avg->a/= count; - avg->r/= count; - avg->g/= count; - avg->b/= count; -} - -void multires_col_avg2(MultiresCol *avg, MultiresCol *c1, MultiresCol *c2) -{ - MultiresCol in[2]; - in[0]= *c1; - in[1]= *c2; - multires_col_avg(avg,in,2); -} - -void multires_load_cols(Mesh *me) -{ - MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *cur; - EditMesh *em= G.obedit ? G.editMesh : NULL; - CustomData *src= em ? &em->fdata : &me->fdata; - EditFace *efa= NULL; - unsigned i,j; - - if(!CustomData_has_layer(src, CD_MCOL) && !CustomData_has_layer(src, CD_MTFACE)) return; - - /* Add texcol data */ - for(cur= me->mr->levels.first; cur; cur= cur->next) - if(!cur->colfaces) - cur->colfaces= MEM_callocN(sizeof(MultiresColFace)*cur->totface,"ColFaces"); - - me->mr->use_col= CustomData_has_layer(src, CD_MCOL); - - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - MultiresColFace *f= &lvl->colfaces[i]; - - if(me->mr->use_col) - mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]); - - if(em) efa= efa->next; - } - - /* Update higher levels */ - lvl= lvl->next; - while(lvl) { - MultiresColFace *cf= lvl->colfaces; - for(i=0; i<lvl->prev->totface; ++i) { - const char sides= lvl->prev->faces[i].v[3]?4:3; - MultiresCol cntr; - - /* Find average color of 4 (or 3 for triangle) verts */ - multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides); - - for(j=0; j<sides; ++j) { - MultiresColFace *pf= &lvl->prev->colfaces[i]; - - multires_col_avg2(&cf->col[0], - &pf->col[j], - &pf->col[j==0?sides-1:j-1]); - cf->col[1]= pf->col[j]; - multires_col_avg2(&cf->col[2], - &pf->col[j], - &pf->col[j==sides-1?0:j+1]); - cf->col[3]= cntr; - - ++cf; - } - } - lvl= lvl->next; - } - - /* Update lower levels */ - lvl= me->mr->levels.last; - lvl= lvl->prev; - while(lvl) { - unsigned curf= 0; - for(i=0; i<lvl->totface; ++i) { - MultiresFace *f= &lvl->faces[i]; - for(j=0; j<(f->v[3]?4:3); ++j) { - lvl->colfaces[i].col[j]= lvl->next->colfaces[curf].col[1]; - ++curf; - } - } - lvl= lvl->prev; - } -} - -void multires_get_vert(MVert *out, EditVert *eve, MVert *m, int i) -{ - if(eve) { - VecCopyf(out->co, eve->co); - out->flag= 0; - if(eve->f & SELECT) out->flag |= 1; - if(eve->h) out->flag |= ME_HIDE; - eve->tmp.l= i; - } - else - *out= *m; -} - -void multires_get_face(MultiresFace *f, EditFace *efa, MFace *m) -{ - if(efa) { - MFace tmp; - int j; - tmp.v1= efa->v1->tmp.l; - tmp.v2= efa->v2->tmp.l; - tmp.v3= efa->v3->tmp.l; - tmp.v4= 0; - if(efa->v4) tmp.v4= efa->v4->tmp.l; - test_index_face(&tmp, NULL, 0, efa->v4?4:3); - for(j=0; j<4; ++j) f->v[j]= (&tmp.v1)[j]; - - /* Flags */ - f->flag= efa->flag; - if(efa->f & 1) f->flag |= ME_FACE_SEL; - else f->flag &= ~ME_FACE_SEL; - if(efa->h) f->flag |= ME_HIDE; - f->mat_nr= efa->mat_nr; - } else { - f->v[0]= m->v1; - f->v[1]= m->v2; - f->v[2]= m->v3; - f->v[3]= m->v4; - f->flag= m->flag; - f->mat_nr= m->mat_nr; - } -} - -void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease) -{ - if(!eed || !flag) return; - - /* Would be nice if EditMesh edge flags could be unified with Mesh flags! */ - *flag= (eed->f & SELECT) | ME_EDGERENDER; - if(eed->f2<2) *flag |= ME_EDGEDRAW; - if(eed->f2==0) *flag |= ME_LOOSEEDGE; - if(eed->sharp) *flag |= ME_SHARP; - if(eed->seam) *flag |= ME_SEAM; - if(eed->h & EM_FGON) *flag |= ME_FGON; - if(eed->h & 1) *flag |= ME_HIDE; - - *crease= (char)(255.0*eed->crease); -} - -void multires_get_edge(MultiresEdge *e, EditEdge *eed, MEdge *m, short *flag, char *crease) -{ - if(eed) { - e->v[0]= eed->v1->tmp.l; - e->v[1]= eed->v2->tmp.l; - eed_to_medge_flag(eed, flag, crease); - } else { - e->v[0]= m->v1; - e->v[1]= m->v2; - *flag= m->flag; - *crease= m->crease; - } -} - void multires_make(void *ob, void *me_v) { Mesh *me= me_v; - MultiresLevel *lvl; - EditMesh *em= G.obedit ? G.editMesh : NULL; - EditVert *eve= NULL; - EditFace *efa= NULL; - EditEdge *eed= NULL; Key *key; - int i; /* Check for shape keys */ key= me->key; @@ -522,64 +137,14 @@ void multires_make(void *ob, void *me_v) return; } - lvl= MEM_callocN(sizeof(MultiresLevel), "multires level"); - waitcursor(1); multires_check_state(); - if(me->pv) sculptmode_pmv_off(me); - - me->mr= MEM_callocN(sizeof(Multires), "multires data"); - - BLI_addtail(&me->mr->levels,lvl); - me->mr->current= 1; - me->mr->level_count= 1; - me->mr->edgelvl= 1; - me->mr->pinlvl= 1; - me->mr->renderlvl= 1; - - /* Load mesh (or editmesh) into multires data */ - - /* Load vertices and vdata (MDeformVerts) */ - lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert; - me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); - multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, - &me->mr->vdata, CD_MDEFORMVERT); - if(em) eve= em->verts.first; - for(i=0; i<lvl->totvert; ++i) { - multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); - if(em) eve= eve->next; - } - - /* Load faces and fdata (MTFaces) */ - lvl->totface= em ? BLI_countlist(&em->faces) : me->totface; - lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); - multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, - &me->mr->fdata, CD_MTFACE); - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - multires_get_face(&lvl->faces[i], efa, &me->mface[i]); - if(em) efa= efa->next; - } - - /* Load edges and edge_flags */ - lvl->totedge= em ? BLI_countlist(&em->edges) : me->totedge; - lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges"); - me->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge flags"); - me->mr->edge_creases= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge creases"); - if(em) eed= em->edges.first; - for(i=0; i<lvl->totedge; ++i) { - multires_get_edge(&lvl->edges[i], eed, &me->medge[i], &me->mr->edge_flags[i], &me->mr->edge_creases[i]); - if(em) eed= eed->next; - } - - multires_load_cols(me); + multires_create(me); allqueue(REDRAWBUTSEDIT, 0); - BIF_undo_push("Make multires"); - waitcursor(0); } @@ -596,103 +161,6 @@ void multires_delete(void *ob, void *me_v) BIF_undo_push("Apply multires"); } -MultiresLevel *multires_level_copy(MultiresLevel *orig) -{ - if(orig) { - MultiresLevel *lvl= MEM_dupallocN(orig); - - lvl->next= lvl->prev= NULL; - lvl->faces= MEM_dupallocN(orig->faces); - lvl->colfaces= MEM_dupallocN(orig->colfaces); - lvl->edges= MEM_dupallocN(orig->edges); - lvl->edge_boundary_states = NULL; - lvl->vert_edge_map= lvl->vert_face_map= NULL; - lvl->map_mem= NULL; - - return lvl; - } - return NULL; -} - -Multires *multires_copy(Multires *orig) -{ - if(orig) { - Multires *mr= MEM_dupallocN(orig); - MultiresLevel *lvl; - - mr->levels.first= mr->levels.last= NULL; - - for(lvl= orig->levels.first; lvl; lvl= lvl->next) - BLI_addtail(&mr->levels, multires_level_copy(lvl)); - - mr->verts= MEM_dupallocN(orig->verts); - - lvl= mr->levels.first; - if(lvl) { - CustomData_copy(&orig->vdata, &mr->vdata, vdata_mask, CD_DUPLICATE, lvl->totvert); - CustomData_copy(&orig->fdata, &mr->fdata, CD_MASK_MTFACE, CD_DUPLICATE, lvl->totface); - mr->edge_flags= MEM_dupallocN(orig->edge_flags); - mr->edge_creases= MEM_dupallocN(orig->edge_creases); - } - - return mr; - } - return NULL; -} - -void multires_free(Multires *mr) -{ - if(mr) { - MultiresLevel* lvl= mr->levels.first; - - /* Free the first-level data */ - if(lvl) { - CustomData_free(&mr->vdata, lvl->totvert); - CustomData_free(&mr->fdata, lvl->totface); - MEM_freeN(mr->edge_flags); - MEM_freeN(mr->edge_creases); - } - - while(lvl) { - multires_free_level(lvl); - lvl= lvl->next; - } - - MEM_freeN(mr->verts); - - BLI_freelistN(&mr->levels); - - MEM_freeN(mr); - } -} - -/* Free and clear the temporary connectivity data */ -void multires_free_temp_data(MultiresLevel *lvl) -{ - if(lvl) { - if(lvl->edge_boundary_states) MEM_freeN(lvl->edge_boundary_states); - if(lvl->vert_edge_map) MEM_freeN(lvl->vert_edge_map); - if(lvl->vert_face_map) MEM_freeN(lvl->vert_face_map); - if(lvl->map_mem) MEM_freeN(lvl->map_mem); - - lvl->edge_boundary_states = NULL; - lvl->vert_edge_map = lvl->vert_face_map = NULL; - lvl->map_mem = NULL; - } -} - -/* Does not actually free lvl itself! */ -void multires_free_level(MultiresLevel *lvl) -{ - if(lvl) { - if(lvl->faces) MEM_freeN(lvl->faces); - if(lvl->edges) MEM_freeN(lvl->edges); - if(lvl->colfaces) MEM_freeN(lvl->colfaces); - - multires_free_temp_data(lvl); - } -} - /* Make sure that all level indices are clipped to [1, mr->level_count] */ void multires_clip_levels(Multires *mr) { @@ -789,44 +257,23 @@ void multires_del_higher(void *ob, void *me) BIF_undo_push("Multires delete higher"); } -unsigned int find_mid_edge(ListBase *vert_edge_map, - MultiresLevel *lvl, - const unsigned int v1, - const unsigned int v2 ) +static void multires_finish_mesh_update(Object *ob) { - MultiresMapNode *n= vert_edge_map[v1].first; - while(n) { - if(lvl->edges[n->Index].v[0]==v2 || - lvl->edges[n->Index].v[1]==v2) - return lvl->edges[n->Index].mid; - - n= n->next; + /* friendly check for background render */ + if(G.background==0) { + object_handle_update(ob); + countall(); + + if(G.vd && G.vd->depths) G.vd->depths->damaged= 1; + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWIMAGE, 0); } - return -1; } -void check_colors(Mesh *me) +void multires_subdivide(void *ob_v, void *me_v) { - CustomData *src= G.obedit ? &G.editMesh->fdata : &me->fdata; - const char col= CustomData_has_layer(src, CD_MCOL); - - /* Check if vertex colors have been deleted or added */ - if(me->mr->use_col && !col) - me->mr->use_col= 0; - else if(!me->mr->use_col && col) { - me->mr->use_col= 1; - multires_load_cols(me); - } -} + Mesh *me = me_v; -void multires_add_level(void *ob, void *me_v) -{ - int i,j, curf, cure; - Mesh *me= me_v; - MultiresLevel *lvl= NULL; - MultiApplyData data; - MVert *oldverts= NULL; - multires_check_state(); if(CustomData_number_of_layers(G.obedit ? &G.editMesh->fdata : &me->fdata, CD_MCOL) > 1) { @@ -836,201 +283,24 @@ void multires_add_level(void *ob, void *me_v) } waitcursor(1); + multires_add_level(ob_v, me, G.scene->toolsettings->multires_subdiv_type); + multires_finish_mesh_update(ob_v); - lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel"); - if(me->pv) sculptmode_pmv_off(me); - - check_colors(me); - multires_update_levels(me, 0); - - ++me->mr->level_count; - BLI_addtail(&me->mr->levels,lvl); - - /* Create vertices - =============== */ - lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface; - oldverts= me->mr->verts; - me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert, "multitres verts"); - /* Copy old verts */ - for(i=0; i<lvl->prev->totvert; ++i) - me->mr->verts[i]= oldverts[i]; - /* Create new edge verts */ - for(i=0; i<lvl->prev->totedge; ++i) { - VecMidf(me->mr->verts[lvl->prev->totvert + i].co, - oldverts[lvl->prev->edges[i].v[0]].co, - oldverts[lvl->prev->edges[i].v[1]].co); - lvl->prev->edges[i].mid= lvl->prev->totvert + i; - } - /* Create new face verts */ - for(i=0; i<lvl->prev->totface; ++i) { - lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i; - } - - multires_calc_temp_data(lvl->prev); - - /* Create faces - ============ */ - /* Allocate all the new faces (each triangle creates three, and - each quad creates four */ - lvl->totface= 0; - for(i=0; i<lvl->prev->totface; ++i) - lvl->totface+= lvl->prev->faces[i].v[3] ? 4 : 3; - lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); - - curf= 0; - for(i=0; i<lvl->prev->totface; ++i) { - const int max= lvl->prev->faces[i].v[3] ? 3 : 2; - - for(j=0; j<max+1; ++j) { - lvl->faces[curf].v[0]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev, - lvl->prev->faces[i].v[j], - lvl->prev->faces[i].v[j==0?max:j-1]); - lvl->faces[curf].v[1]= lvl->prev->faces[i].v[j]; - lvl->faces[curf].v[2]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev, - lvl->prev->faces[i].v[j], - lvl->prev->faces[i].v[j==max?0:j+1]); - lvl->faces[curf].v[3]= lvl->prev->totvert + lvl->prev->totedge + i; - lvl->faces[curf].flag= lvl->prev->faces[i].flag; - lvl->faces[curf].mat_nr= lvl->prev->faces[i].mat_nr; - - ++curf; - } - } - - /* Create edges - ============ */ - /* Figure out how many edges to allocate */ - lvl->totedge= lvl->prev->totedge*2; - for(i=0; i<lvl->prev->totface; ++i) - lvl->totedge+= lvl->prev->faces[i].v[3]?4:3; - lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges"); - - for(i=0; i<lvl->prev->totedge; ++i) { - lvl->edges[i*2].v[0]= lvl->prev->edges[i].v[0]; - lvl->edges[i*2].v[1]= lvl->prev->edges[i].mid; - lvl->edges[i*2+1].v[0]= lvl->prev->edges[i].mid; - lvl->edges[i*2+1].v[1]= lvl->prev->edges[i].v[1]; - } - /* Add edges inside of old polygons */ - curf= 0; - cure= lvl->prev->totedge*2; - for(i=0; i<lvl->prev->totface; ++i) { - for(j=0; j<(lvl->prev->faces[i].v[3]?4:3); ++j) { - lvl->edges[cure].v[0]= lvl->faces[curf].v[2]; - lvl->edges[cure].v[1]= lvl->faces[curf].v[3]; - ++cure; - ++curf; - } - } - - /* Smooth vertices - =============== */ - for(i=0; i<lvl->prev->totface; ++i) { - const MultiresFace *f= &lvl->prev->faces[i]; - data.corner1= oldverts[f->v[0]].co; - data.corner2= oldverts[f->v[1]].co; - data.corner3= oldverts[f->v[2]].co; - data.corner4= oldverts[f->v[3]].co; - data.quad= f->v[3] ? 1 : 0; - multi_apply(me->mr->verts[f->mid].co, &data, 3, catmullclark_smooth_face); - } - - if(G.scene->toolsettings->multires_subdiv_type == 0) { - for(i=0; i<lvl->prev->totedge; ++i) { - const MultiresEdge *e= &lvl->prev->edges[i]; - data.boundary= lvl->prev->edge_boundary_states[i]; - edge_face_neighbor_midpoints_accum(&data,lvl->prev, me->mr->verts, sizeof(MVert),e); - data.endpoint1= oldverts[e->v[0]].co; - data.endpoint2= oldverts[e->v[1]].co; - multi_apply(me->mr->verts[e->mid].co, &data, 3, catmullclark_smooth_edge); - } - - for(i=0; i<lvl->prev->totvert; ++i) { - data.boundary= multires_vert_is_boundary(lvl->prev,i); - data.original= oldverts[i].co; - data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]); - if(data.boundary) - boundary_edges_average(&data,lvl->prev, oldverts, sizeof(MVert),i); - else { - vert_face_neighbor_midpoints_average(&data,lvl->prev, me->mr->verts, - sizeof(MVert),i); - vert_edge_neighbor_midpoints_average(&data,lvl->prev, oldverts, - sizeof(MVert),i); - } - multi_apply(me->mr->verts[i].co, &data, 3, catmullclark_smooth_vert); - } - } - - multires_free_temp_data(lvl->prev); - MEM_freeN(oldverts); - - /* Vertex Colors - ============= */ - curf= 0; - if(me->mr->use_col) { - MultiresColFace *cf= MEM_callocN(sizeof(MultiresColFace)*lvl->totface,"Multirescolfaces"); - lvl->colfaces= cf; - for(i=0; i<lvl->prev->totface; ++i) { - const char sides= lvl->prev->faces[i].v[3]?4:3; - MultiresCol cntr; - - /* Find average color of 4 (or 3 for triangle) verts */ - multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides); - - for(j=0; j<sides; ++j) { - multires_col_avg2(&cf->col[0], - &lvl->prev->colfaces[i].col[j], - &lvl->prev->colfaces[i].col[j==0?sides-1:j-1]); - cf->col[1]= lvl->prev->colfaces[i].col[j]; - multires_col_avg2(&cf->col[2], - &lvl->prev->colfaces[i].col[j], - &lvl->prev->colfaces[i].col[j==sides-1?0:j+1]); - cf->col[3]= cntr; - - ++cf; - } - } - } - - me->mr->newlvl= me->mr->level_count; - me->mr->current= me->mr->newlvl; - /* Unless the render level has been set to something other than the - highest level (by the user), increment the render level to match - the highest available level */ - if(me->mr->renderlvl == me->mr->level_count - 1) me->mr->renderlvl= me->mr->level_count; - - multires_level_to_mesh(ob, me, 0); - allqueue(REDRAWBUTSEDIT, 0); - BIF_undo_push("Add multires level"); - waitcursor(0); } void multires_set_level_cb(void *ob, void *me) { - multires_set_level(ob, me, 0); -} - -void multires_set_level(struct Object *ob, struct Mesh *me, const int render) -{ waitcursor(1); multires_check_state(); - if(me->pv) sculptmode_pmv_off(me); - - check_colors(me); - multires_update_levels(me, render); - - me->mr->current= me->mr->newlvl; - if(me->mr->current<1) me->mr->current= 1; - else if(me->mr->current>me->mr->level_count) me->mr->current= me->mr->level_count; - - multires_level_to_mesh(ob, me, render); + multires_set_level(ob, me, 0); + multires_finish_mesh_update(ob); - if(!render && (G.obedit || G.f & G_SCULPTMODE)) + if(G.obedit || G.f & G_SCULPTMODE) BIF_undo_push("Multires set level"); allqueue(REDRAWBUTSEDIT, 0); @@ -1038,593 +308,10 @@ void multires_set_level(struct Object *ob, struct Mesh *me, const int render) waitcursor(0); } - -void medge_flag_to_eed(const short flag, const char crease, EditEdge *eed) -{ - if(!eed) return; - - if(flag & ME_SEAM) eed->seam= 1; - if(flag & ME_SHARP) eed->sharp = 1; - if(flag & SELECT) eed->f |= SELECT; - if(flag & ME_FGON) eed->h= EM_FGON; - if(flag & ME_HIDE) eed->h |= 1; - - eed->crease= ((float)crease)/255.0; -} - -/* note, function is called in background render too, without UI */ -void multires_level_to_mesh(Object *ob, Mesh *me, const int render) +void multires_edge_level_update_cb(void *ob_v, void *me_v) { - MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - int i; - EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; - EditVert **eves= NULL; - EditEdge *eed= NULL; - - if(em) { - /* Remove editmesh elements */ - free_editMesh(em); - - eves= MEM_callocN(sizeof(EditVert*)*lvl->totvert, "editvert pointers"); - } else { - CustomData_free_layer_active(&me->vdata, CD_MVERT, me->totvert); - CustomData_free_layer_active(&me->edata, CD_MEDGE, me->totedge); - CustomData_free_layer_active(&me->fdata, CD_MFACE, me->totface); - CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); - CustomData_free_layers(&me->fdata, CD_MTFACE, me->totface); - CustomData_free_layers(&me->fdata, CD_MCOL, me->totface); - - me->totvert= lvl->totvert; - me->totface= lvl->totface; - me->totedge= lvl->totedge; - - CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge); - CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); - mesh_update_customdata_pointers(me); - } - - /* Vertices/Edges/Faces */ - - for(i=0; i<lvl->totvert; ++i) { - if(em) { - eves[i]= addvertlist(me->mr->verts[i].co, NULL); - if(me->mr->verts[i].flag & 1) eves[i]->f |= SELECT; - if(me->mr->verts[i].flag & ME_HIDE) eves[i]->h= 1; - eves[i]->data= NULL; - } - else - me->mvert[i]= me->mr->verts[i]; - } - for(i=0; i<lvl->totedge; ++i) { - if(em) { - addedgelist(eves[lvl->edges[i].v[0]], eves[lvl->edges[i].v[1]], NULL); - } else { - me->medge[i].v1= lvl->edges[i].v[0]; - me->medge[i].v2= lvl->edges[i].v[1]; - me->medge[i].flag &= ~ME_HIDE; - } - } - for(i=0; i<lvl->totface; ++i) { - if(em) { - EditVert *eve4= lvl->faces[i].v[3] ? eves[lvl->faces[i].v[3]] : NULL; - EditFace *efa= addfacelist(eves[lvl->faces[i].v[0]], eves[lvl->faces[i].v[1]], - eves[lvl->faces[i].v[2]], eve4, NULL, NULL); - efa->flag= lvl->faces[i].flag & ~ME_HIDE; - efa->mat_nr= lvl->faces[i].mat_nr; - if(lvl->faces[i].flag & ME_FACE_SEL) - efa->f |= SELECT; - if(lvl->faces[i].flag & ME_HIDE) efa->h= 1; - efa->data= NULL; - } - else { - me->mface[i].v1= lvl->faces[i].v[0]; - me->mface[i].v2= lvl->faces[i].v[1]; - me->mface[i].v3= lvl->faces[i].v[2]; - me->mface[i].v4= lvl->faces[i].v[3]; - me->mface[i].flag= lvl->faces[i].flag; - me->mface[i].flag &= ~ME_HIDE; - me->mface[i].mat_nr= lvl->faces[i].mat_nr; - } - } - - /* Edge flags */ - if(em) eed= em->edges.first; - if(lvl==me->mr->levels.first) { - for(i=0; i<lvl->totedge; ++i) { - if(em) { - medge_flag_to_eed(me->mr->edge_flags[i], me->mr->edge_creases[i], eed); - eed= eed->next; - } - else { - me->medge[i].flag= me->mr->edge_flags[i]; - me->medge[i].crease= me->mr->edge_creases[i]; - } - } - } else { - MultiresLevel *lvl1= me->mr->levels.first; - const int last= lvl1->totedge * pow(2, me->mr->current-1); - for(i=0; i<last; ++i) { - const int ndx= i / pow(2, me->mr->current-1); - - if(em) { - medge_flag_to_eed(me->mr->edge_flags[ndx], me->mr->edge_creases[ndx], eed); - eed= eed->next; - } - else { - me->medge[i].flag= me->mr->edge_flags[ndx]; - me->medge[i].crease= me->mr->edge_creases[ndx]; - } - } - } - - if(em) { - eed= em->edges.first; - for(i=0, eed= em->edges.first; i<lvl->totedge; ++i, eed= eed->next) { - eed->h= me->mr->verts[lvl->edges[i].v[0]].flag & ME_HIDE || - me->mr->verts[lvl->edges[i].v[1]].flag & ME_HIDE; - } - } - - EM_select_flush(); - - multires_customdata_to_mesh(me, em, lvl, &me->mr->vdata, em ? &em->vdata : &me->vdata, CD_MDEFORMVERT); - multires_customdata_to_mesh(me, em, lvl, &me->mr->fdata, em ? &em->fdata : &me->fdata, CD_MTFACE); - - /* Colors */ - if(me->mr->use_col) { - MCol c[4]; - EditFace *efa= NULL; - CustomData *src= em ? &em->fdata : &me->fdata; - if(em) { - if(me->mr->use_col) EM_add_data_layer(src, CD_MCOL); - efa= em->faces.first; - } - else { - if(me->mr->use_col) me->mcol= CustomData_add_layer(src, CD_MCOL, CD_CALLOC, NULL, me->totface); - } - - for(i=0; i<lvl->totface; ++i) { - if(em) { - if(me->mr->use_col) { - multires_to_mcol(&lvl->colfaces[i], c); - CustomData_em_set(src, efa->data, CD_MCOL, c); - } - efa= efa->next; - } - else if(me->mr->use_col) multires_to_mcol(&lvl->colfaces[i], &me->mcol[i*4]); - } - - } - - mesh_update_customdata_pointers(me); - - if(em) { - MEM_freeN(eves); - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - recalc_editnormals(); - } else { - multires_edge_level_update(ob,me); - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); - } - - /* friendly check for background render */ - if(G.background==0) { - object_handle_update(ob); - countall(); - - if(G.vd && G.vd->depths) G.vd->depths->damaged= 1; - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWIMAGE, 0); - } -} - -void multires_update_colors(Mesh *me) -{ - MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - MultiresCol *pr_deltas= NULL, *cr_deltas= NULL; - EditMesh *em= G.obedit ? G.editMesh : NULL; - CustomData *src= em ? &em->fdata : &me->fdata; - EditFace *efa= NULL; - unsigned i,j,curf= 0; - - if(me->mr->use_col) { - /* Calc initial deltas */ - cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"initial color/uv deltas"); - - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - MCol *col= em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]; - for(j=0; j<4; ++j) { - if(me->mr->use_col) { - cr_deltas[i*4+j].a= col[j].a - lvl->colfaces[i].col[j].a; - cr_deltas[i*4+j].r= col[j].r - lvl->colfaces[i].col[j].r; - cr_deltas[i*4+j].g= col[j].g - lvl->colfaces[i].col[j].g; - cr_deltas[i*4+j].b= col[j].b - lvl->colfaces[i].col[j].b; - } - } - if(em) efa= efa->next; - } - - /* Update current level */ - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - MultiresColFace *f= &lvl->colfaces[i]; - - if(me->mr->use_col) - mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]); - - if(em) efa= efa->next; - } - - /* Update higher levels */ - lvl= lvl->next; - while(lvl) { - /* Set up new deltas, but keep the ones from the previous level */ - if(pr_deltas) MEM_freeN(pr_deltas); - pr_deltas= cr_deltas; - cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"color deltas"); - - curf= 0; - for(i=0; i<lvl->prev->totface; ++i) { - const char sides= lvl->prev->faces[i].v[3]?4:3; - MultiresCol cntr; - - /* Find average color of 4 (or 3 for triangle) verts */ - multires_col_avg(&cntr,&pr_deltas[i*4],sides); - - for(j=0; j<sides; ++j) { - multires_col_avg2(&cr_deltas[curf*4], - &pr_deltas[i*4+j], - &pr_deltas[i*4+(j==0?sides-1:j-1)]); - cr_deltas[curf*4+1]= pr_deltas[i*4+j]; - multires_col_avg2(&cr_deltas[curf*4+2], - &pr_deltas[i*4+j], - &pr_deltas[i*4+(j==sides-1?0:j+1)]); - cr_deltas[curf*4+3]= cntr; - ++curf; - } - } - - for(i=0; i<lvl->totface; ++i) { - for(j=0; j<4; ++j) { - lvl->colfaces[i].col[j].a+= cr_deltas[i*4+j].a; - lvl->colfaces[i].col[j].r+= cr_deltas[i*4+j].r; - lvl->colfaces[i].col[j].g+= cr_deltas[i*4+j].g; - lvl->colfaces[i].col[j].b+= cr_deltas[i*4+j].b; - } - } - - lvl= lvl->next; - } - if(pr_deltas) MEM_freeN(pr_deltas); - if(cr_deltas) MEM_freeN(cr_deltas); - - /* Update lower levels */ - lvl= me->mr->levels.last; - lvl= lvl->prev; - while(lvl) { - MultiresColFace *nf= lvl->next->colfaces; - for(i=0; i<lvl->totface; ++i) { - MultiresFace *f= &lvl->faces[i]; - for(j=0; j<(f->v[3]?4:3); ++j) { - lvl->colfaces[i].col[j]= nf->col[1]; - ++nf; - } - } - lvl= lvl->prev; - } - } -} - -/* Update vertex locations and vertex flags */ -void multires_update_vertices(Mesh *me, EditMesh *em) -{ - MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, - *last_lvl= me->mr->levels.last; - vec3f *pr_deltas= NULL, *cr_deltas= NULL, *swap_deltas= NULL; - EditVert *eve= NULL; - MultiApplyData data; - int i, j; - - /* Prepare deltas */ - pr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 1"); - cr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 2"); - - /* Calculate initial deltas -- current mesh subtracted from current level*/ - if(em) eve= em->verts.first; - for(i=0; i<cr_lvl->totvert; ++i) { - if(em) { - VecSubf(&cr_deltas[i].x, eve->co, me->mr->verts[i].co); - eve= eve->next; - } else - VecSubf(&cr_deltas[i].x, me->mvert[i].co, me->mr->verts[i].co); - } - - - /* Copy current level's vertex flags and clear the rest */ - if(em) eve= em->verts.first; - for(i=0; i < last_lvl->totvert; ++i) { - if(i < cr_lvl->totvert) { - MVert mvflag; - multires_get_vert(&mvflag, eve, &me->mvert[i], i); - if(em) eve= eve->next; - me->mr->verts[i].flag= mvflag.flag; - } - else - me->mr->verts[i].flag= 0; - } - - /* If already on the highest level, copy current verts (including flags) into current level */ - if(cr_lvl == last_lvl) { - if(em) - eve= em->verts.first; - for(i=0; i<cr_lvl->totvert; ++i) { - multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); - if(em) eve= eve->next; - } - } - - /* Update higher levels */ - pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - cr_lvl= pr_lvl->next; - while(cr_lvl) { - multires_calc_temp_data(pr_lvl); - - /* Swap the old/new deltas */ - swap_deltas= pr_deltas; - pr_deltas= cr_deltas; - cr_deltas= swap_deltas; - - /* Calculate and add new deltas - ============================ */ - for(i=0; i<pr_lvl->totface; ++i) { - const MultiresFace *f= &pr_lvl->faces[i]; - data.corner1= &pr_deltas[f->v[0]].x; - data.corner2= &pr_deltas[f->v[1]].x; - data.corner3= &pr_deltas[f->v[2]].x; - data.corner4= &pr_deltas[f->v[3]].x; - data.quad= f->v[3] ? 1 : 0; - multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face); - - for(j=0; j<(data.quad?4:3); ++j) - me->mr->verts[f->mid].flag |= me->mr->verts[f->v[j]].flag; - } - - for(i=0; i<pr_lvl->totedge; ++i) { - const MultiresEdge *e= &pr_lvl->edges[i]; - data.boundary= pr_lvl->edge_boundary_states[i]; - edge_face_neighbor_midpoints_accum(&data,pr_lvl,cr_deltas,sizeof(vec3f),e); - data.endpoint1= &pr_deltas[e->v[0]].x; - data.endpoint2= &pr_deltas[e->v[1]].x; - multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge); - - for(j=0; j<2; ++j) - me->mr->verts[e->mid].flag |= me->mr->verts[e->v[j]].flag; - } - - for(i=0; i<pr_lvl->totvert; ++i) { - data.boundary= multires_vert_is_boundary(pr_lvl,i); - data.original= &pr_deltas[i].x; - data.edge_count= BLI_countlist(&pr_lvl->vert_edge_map[i]); - if(data.boundary) - boundary_edges_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); - else { - vert_face_neighbor_midpoints_average(&data,pr_lvl,cr_deltas,sizeof(vec3f),i); - vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); - } - multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert); - } - - /* Apply deltas to vertex locations */ - for(i=0; (cr_lvl == last_lvl) && (i < cr_lvl->totvert); ++i) { - VecAddf(me->mr->verts[i].co, - me->mr->verts[i].co, - &cr_deltas[i].x); - } - - multires_free_temp_data(pr_lvl); - - pr_lvl= pr_lvl->next; - cr_lvl= cr_lvl->next; - } - if(pr_deltas) MEM_freeN(pr_deltas); - if(cr_deltas) MEM_freeN(cr_deltas); - -} - -void multires_update_faces(Mesh *me, EditMesh *em) -{ - MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, - *last_lvl= me->mr->levels.last; - char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *or_flag_damaged= NULL, - *pr_mat_damaged= NULL, *cr_mat_damaged= NULL, *or_mat_damaged= NULL, *swap= NULL; - EditFace *efa= NULL; - unsigned i,j,curf; - - /* Find for each face whether flag/mat has changed */ - pr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); - cr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); - pr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); - cr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); - if(em) efa= em->faces.first; - for(i=0; i<cr_lvl->totface; ++i) { - MultiresFace mftmp; - multires_get_face(&mftmp, efa, &me->mface[i]); - if(cr_lvl->faces[i].flag != mftmp.flag) - cr_flag_damaged[i]= 1; - if(cr_lvl->faces[i].mat_nr != mftmp.mat_nr) - cr_mat_damaged[i]= 1; - - /* Update current level */ - cr_lvl->faces[i].flag= mftmp.flag; - cr_lvl->faces[i].mat_nr= mftmp.mat_nr; - - if(em) efa= efa->next; - } - or_flag_damaged= MEM_dupallocN(cr_flag_damaged); - or_mat_damaged= MEM_dupallocN(cr_mat_damaged); - - /* Update lower levels */ - cr_lvl= cr_lvl->prev; - while(cr_lvl) { - swap= pr_flag_damaged; - pr_flag_damaged= cr_flag_damaged; - cr_flag_damaged= swap; - - swap= pr_mat_damaged; - pr_mat_damaged= cr_mat_damaged; - cr_mat_damaged= swap; - - curf= 0; - for(i=0; i<cr_lvl->totface; ++i) { - const int sides= cr_lvl->faces[i].v[3] ? 4 : 3; - - /* Check damages */ - for(j=0; j<sides; ++j, ++curf) { - if(pr_flag_damaged[curf]) { - cr_lvl->faces[i].flag= cr_lvl->next->faces[curf].flag; - cr_flag_damaged[i]= 1; - } - if(pr_mat_damaged[curf]) { - cr_lvl->faces[i].mat_nr= cr_lvl->next->faces[curf].mat_nr; - cr_mat_damaged[i]= 1; - } - } - } - - cr_lvl= cr_lvl->prev; - } - - /* Clear to original damages */ - if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); - if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); - cr_flag_damaged= or_flag_damaged; - cr_mat_damaged= or_mat_damaged; - - /* Update higher levels */ - pr_lvl= current_level(me->mr); - cr_lvl= pr_lvl->next; - while(cr_lvl) { - swap= pr_flag_damaged; - pr_flag_damaged= cr_flag_damaged; - cr_flag_damaged= swap; - - swap= pr_mat_damaged; - pr_mat_damaged= cr_mat_damaged; - cr_mat_damaged= swap; - - /* Update faces */ - for(i=0, curf= 0; i<pr_lvl->totface; ++i) { - const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3; - for(j=0; j<sides; ++j, ++curf) { - if(pr_flag_damaged[i]) { - cr_lvl->faces[curf].flag= pr_lvl->faces[i].flag; - cr_flag_damaged[curf]= 1; - } - if(pr_mat_damaged[i]) { - cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr; - cr_mat_damaged[curf]= 1; - } - } - } - - pr_lvl= pr_lvl->next; - cr_lvl= cr_lvl->next; - } - - if(pr_flag_damaged) MEM_freeN(pr_flag_damaged); - if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); - if(pr_mat_damaged) MEM_freeN(pr_mat_damaged); - if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); -} - -void multires_update_levels(Mesh *me, const int render) -{ - EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; - - multires_update_first_level(me, em); - multires_update_vertices(me, em); - multires_update_faces(me, em); - multires_update_colors(me); -} - -void multires_calc_temp_data(MultiresLevel *lvl) -{ - unsigned i, j, emax; - MultiresMapNode *indexnode= NULL; - - lvl->map_mem= MEM_mallocN(sizeof(MultiresMapNode)*(lvl->totedge*2 + lvl->totface*4), "map_mem"); - indexnode= lvl->map_mem; - - /* edge map */ - lvl->vert_edge_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_edge_map"); - for(i=0; i<lvl->totedge; ++i) { - for(j=0; j<2; ++j, ++indexnode) { - indexnode->Index= i; - BLI_addtail(&lvl->vert_edge_map[lvl->edges[i].v[j]], indexnode); - } - } - - /* face map */ - lvl->vert_face_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_face_map"); - for(i=0; i<lvl->totface; ++i){ - for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j, ++indexnode) { - indexnode->Index= i; - BLI_addtail(&lvl->vert_face_map[lvl->faces[i].v[j]], indexnode); - } - } - - /* edge boundaries */ - emax = (lvl->prev ? (lvl->prev->totedge * 2) : lvl->totedge); - lvl->edge_boundary_states= MEM_callocN(sizeof(char)*lvl->totedge, "edge_boundary_states"); - for(i=0; i<emax; ++i) { - MultiresMapNode *n1= lvl->vert_face_map[lvl->edges[i].v[0]].first; - unsigned total= 0; - - lvl->edge_boundary_states[i] = 1; - while(n1 && lvl->edge_boundary_states[i] == 1) { - MultiresMapNode *n2= lvl->vert_face_map[lvl->edges[i].v[1]].first; - while(n2) { - if(n1->Index == n2->Index) { - ++total; - - if(total > 1) { - lvl->edge_boundary_states[i] = 0; - break; - } - } - - n2= n2->next; - } - n1= n1->next; - } - } -} - -void multires_edge_level_update(void *ob, void *me_v) -{ - if(!G.obedit) { - Mesh *me= me_v; - MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1); - const int threshold= edge_lvl->totedge * powf(2, me->mr->current - me->mr->edgelvl); - unsigned i; - - for(i=0; i<cr_lvl->totedge; ++i) { - const int ndx= me->pv ? me->pv->edge_map[i] : i; - if(ndx != -1) { /* -1= hidden edge */ - if(me->mr->edgelvl >= me->mr->current || i<threshold) - me->medge[ndx].flag |= ME_EDGEDRAW | ME_EDGERENDER; - else - me->medge[ndx].flag &= ~ME_EDGEDRAW & ~ME_EDGERENDER; - } - } - - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - } + multires_edge_level_update(ob_v, me_v); + allqueue(REDRAWVIEW3D, 0); } int multires_modifier_warning() diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 2e560b05228..a9c677342ae 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -86,6 +86,7 @@ #include "BKE_ipo.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_node.h" #include "BKE_scene.h" #include "BKE_texture.h" diff --git a/source/blender/src/vpaint.c b/source/blender/src/vpaint.c index 4e1c6cd59a6..ac7ad0fa5fb 100644 --- a/source/blender/src/vpaint.c +++ b/source/blender/src/vpaint.c @@ -71,6 +71,7 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_multires.h" #include "BKE_object.h" #include "BKE_utildefines.h" |