diff options
author | Ton Roosendaal <ton@blender.org> | 2007-12-29 20:07:55 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2007-12-29 20:07:55 +0300 |
commit | da7208eab5332b78e8fcd1ce6299f9ad06738ee5 (patch) | |
tree | a3007351195911d7a983fdd631716e3ff29d11ed /source | |
parent | c27b65a255df7a5d0d1aeb8b89cffcea2d5f8021 (diff) |
Ported over the bad-level cleanup from Chris for Sculpt.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_multires.h | 68 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_sculpt.h | 93 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 72 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/multires-firstlevel.c | 409 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/multires.c | 1305 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.c | 132 | ||||
-rw-r--r-- | source/blender/editors/include/BDR_sculptmode.h | 60 | ||||
-rw-r--r-- | source/blender/editors/screen/stubs.c | 23 |
9 files changed, 2091 insertions, 76 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index be0a04ba563..b60fd0ce954 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -111,6 +111,11 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v); void free_uv_vert_map(UvVertMap *vmap); +/* Partial Mesh Visibility */ +struct PartialVisibility *mesh_pmv_copy(struct PartialVisibility *); +void mesh_pmv_free(struct PartialVisibility *); +void mesh_pmv_revert(struct Object *ob, struct Mesh *me); +void mesh_pmv_off(struct Object *ob, struct Mesh *me); /* functions for making menu's from customdata layers */ int mesh_layers_menu_charlen(struct CustomData *data, int type); /* use this to work out how many chars to allocate */ diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h new file mode 100644 index 00000000000..61eb796e53d --- /dev/null +++ b/source/blender/blenkernel/BKE_multires.h @@ -0,0 +1,68 @@ +/* + * $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 Object *ob, 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); +void multires_to_mcol(struct MultiresColFace *f, MCol mcol[4]); +/* 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/BKE_sculpt.h b/source/blender/blenkernel/BKE_sculpt.h new file mode 100644 index 00000000000..d539bcf5e8c --- /dev/null +++ b/source/blender/blenkernel/BKE_sculpt.h @@ -0,0 +1,93 @@ +/* + * $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 ***** + */ + +#ifndef BKE_SCULPT_H +#define BKE_SCULPT_H + +struct NumInput; +struct Scene; +struct SculptData; +struct SculptSession; + +typedef enum PropsetMode { + PropsetNone = 0, + PropsetSize, + PropsetStrength, + PropsetTexRot +} PropsetMode; + +typedef struct PropsetData { + PropsetMode mode; + unsigned int tex; + short origloc[2]; + float *texdata; + + short origsize; + char origstrength; + float origtexrot; + + struct NumInput *num; +} PropsetData; + +typedef struct SculptSession { + struct ProjVert *projverts; + + struct bglMats *mats; + + /* An array of lists; array is sized as + large as the number of verts in the mesh, + the list for each vert contains the index + for all the faces that use that vertex */ + struct ListBase *vertex_users; + struct IndexNode *vertex_users_mem; + int vertex_users_size; + + /* Used temporarily per-stroke */ + float *vertexcosnos; + ListBase damaged_rects; + ListBase damaged_verts; + + /* Used to cache the render of the active texture */ + unsigned int texcache_w, texcache_h, *texcache; + + struct PropsetData *propset; + + /* For rotating around a pivot point */ + vec3f pivot; + + struct SculptStroke *stroke; +} SculptSession; + +void sculptdata_init(struct Scene *sce); +void sculptdata_free(struct Scene *sce); +void sculptsession_free(struct Scene *sce); +void sculpt_vertexusers_free(struct SculptSession *ss); +void sculpt_reset_curve(struct SculptData *sd); + +#endif diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 56b1fe7e75b..25a391be566 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -55,14 +55,13 @@ #include "DNA_meshdata_types.h" #include "DNA_ipo_types.h" -#include "BDR_sculptmode.h" - #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_main.h" #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 +82,6 @@ #include "BLI_editVert.h" #include "BLI_arithb.h" -#include "multires.h" - int update_realtime_texture(MTFace *tface, double time) { Image *ima; @@ -1231,3 +1228,70 @@ void free_uv_vert_map(UvVertMap *vmap) } } +/* Partial Mesh Visibility */ +PartialVisibility *mesh_pmv_copy(PartialVisibility *pmv) +{ + PartialVisibility *n= MEM_dupallocN(pmv); + n->vert_map= MEM_dupallocN(pmv->vert_map); + n->edge_map= MEM_dupallocN(pmv->edge_map); + n->old_edges= MEM_dupallocN(pmv->old_edges); + n->old_faces= MEM_dupallocN(pmv->old_faces); + return n; +} + +void mesh_pmv_free(PartialVisibility *pv) +{ + MEM_freeN(pv->vert_map); + MEM_freeN(pv->edge_map); + MEM_freeN(pv->old_faces); + MEM_freeN(pv->old_edges); + MEM_freeN(pv); +} + +void mesh_pmv_revert(Object *ob, Mesh *me) +{ + if(me->pv) { + unsigned i; + MVert *nve, *old_verts; + + /* Reorder vertices */ + nve= me->mvert; + old_verts = MEM_mallocN(sizeof(MVert)*me->pv->totvert,"PMV revert verts"); + for(i=0; i<me->pv->totvert; ++i) + old_verts[i]= nve[me->pv->vert_map[i]]; + + /* Restore verts, edges and faces */ + 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_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, old_verts, me->pv->totvert); + CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, me->pv->old_edges, me->pv->totedge); + CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, me->pv->old_faces, me->pv->totface); + mesh_update_customdata_pointers(me); + + me->totvert= me->pv->totvert; + me->totedge= me->pv->totedge; + me->totface= me->pv->totface; + + me->pv->old_edges= NULL; + me->pv->old_faces= NULL; + + /* Free maps */ + MEM_freeN(me->pv->edge_map); + me->pv->edge_map= NULL; + MEM_freeN(me->pv->vert_map); + me->pv->vert_map= NULL; + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } +} + +void mesh_pmv_off(Object *ob, Mesh *me) +{ + if(ob && me->pv) { + mesh_pmv_revert(ob, me); + MEM_freeN(me->pv); + me->pv= NULL; + } +} diff --git a/source/blender/blenkernel/intern/multires-firstlevel.c b/source/blender/blenkernel/intern/multires-firstlevel.c new file mode 100644 index 00000000000..a276266d34f --- /dev/null +++ b/source/blender/blenkernel/intern/multires-firstlevel.c @@ -0,0 +1,409 @@ +/* + * $Id: multires-firstlevel.c 13001 2007-12-26 09:39:15Z nicholasbishop $ + * + * ***** 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) 2006 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Deals with the first-level data in multires (edge flags, weights, and UVs) + * + * multires.h + * + */ + +#include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BIF_editmesh.h" + +#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 <string.h> + +MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl); +MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl); +void multires_update_edge_flags(Mesh *me, EditMesh *em); +void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease); + +/*********** Generic ***********/ + +CustomDataMask cdmask(const int type) +{ + if(type == CD_MDEFORMVERT) + return CD_MASK_MDEFORMVERT; + else if(type == CD_MTFACE) + return CD_MASK_MTFACE; + return -1; +} + +char type_ok(const int type) +{ + return (type == CD_MDEFORMVERT) || (type == CD_MTFACE); +} + +/* Copy vdata or fdata from Mesh or EditMesh to Multires. */ +void multires_update_customdata(MultiresLevel *lvl1, CustomData *src, CustomData *dst, const int type) +{ + if(src && dst && type_ok(type)) { + const int tot= (type == CD_MDEFORMVERT ? lvl1->totvert : lvl1->totface); + int i; + + CustomData_free(dst, tot); + + if(CustomData_has_layer(src, type)) { + if(G.obedit) { + EditVert *eve= G.editMesh->verts.first; + EditFace *efa= G.editMesh->faces.first; + CustomData_copy(src, dst, cdmask(type), CD_CALLOC, tot); + for(i=0; i<tot; ++i) { + if(type == CD_MDEFORMVERT) { + CustomData_from_em_block(&G.editMesh->vdata, dst, eve->data, i); + eve= eve->next; + } + else if(type == CD_MTFACE) { + CustomData_from_em_block(&G.editMesh->fdata, dst, efa->data, i); + efa= efa->next; + } + } + } + else + CustomData_copy(src, dst, cdmask(type), CD_DUPLICATE, tot); + } + } +} + +/* Uses subdivide_dverts or subdivide_mtfaces to subdivide src to match lvl_end. Does not free src. */ +void *subdivide_customdata_to_level(void *src, MultiresLevel *lvl_start, + MultiresLevel *lvl_end, const int type) +{ + if(src && lvl_start && lvl_end && type_ok(type)) { + MultiresLevel *lvl; + void *cr_data= NULL, *pr_data= NULL; + + pr_data= src; + for(lvl= lvl_start; lvl && lvl != lvl_end; lvl= lvl->next) { + if(type == CD_MDEFORMVERT) + cr_data= subdivide_dverts(pr_data, lvl); + else if(type == CD_MTFACE) + cr_data= subdivide_mtfaces(pr_data, lvl); + + /* Free previous subdivision level's data */ + if(lvl != lvl_start) { + if(type == CD_MDEFORMVERT) + free_dverts(pr_data, lvl->totvert); + else if(type == CD_MTFACE) + MEM_freeN(pr_data); + } + + pr_data= cr_data; + cr_data= NULL; + } + + return pr_data; + } + + return NULL; +} + +/* Directly copy src into dst (handles both Mesh and EditMesh) */ +void customdata_to_mesh(Mesh *me, EditMesh *em, CustomData *src, CustomData *dst, const int tot, const int type) +{ + if(me && me->mr && src && dst && type_ok(type)) { + if(em) { + int i; + EditVert *eve= em->verts.first; + EditFace *efa= em->faces.first; + CustomData_copy(src, dst, cdmask(type), CD_CALLOC, 0); + + for(i=0; i<tot; ++i) { + if(type == CD_MDEFORMVERT) { + CustomData_to_em_block(src, dst, i, &eve->data); + eve= eve->next; + } + else if(type == CD_MTFACE) { + CustomData_to_em_block(src, dst, i, &efa->data); + efa= efa->next; + } + } + } else { + CustomData_merge(src, dst, cdmask(type), CD_DUPLICATE, tot); + } + } +} + +/* Subdivide vdata or fdata from Multires into either Mesh or EditMesh. */ +void multires_customdata_to_mesh(Mesh *me, EditMesh *em, MultiresLevel *lvl, CustomData *src, + CustomData *dst, const int type) +{ + if(me && me->mr && lvl && src && dst && type_ok(type) && + CustomData_has_layer(src, type)) { + const int tot= (type == CD_MDEFORMVERT ? lvl->totvert : lvl->totface); + if(lvl == me->mr->levels.first) { + customdata_to_mesh(me, em, src, dst, tot, type); + } + else { + CustomData cdf; + const int count = CustomData_number_of_layers(src, type); + int i; + + /* Construct a new CustomData containing the subdivided data */ + CustomData_copy(src, &cdf, cdmask(type), CD_ASSIGN, tot); + for(i=0; i<count; ++i) { + void *layer= CustomData_get_layer_n(&cdf, type, i); + CustomData_set_layer_n(&cdf, type, i, + subdivide_customdata_to_level(layer, me->mr->levels.first, lvl, type)); + } + + customdata_to_mesh(me, em, &cdf, dst, tot, type); + CustomData_free(&cdf, tot); + } + } +} + +/* Subdivide the first-level customdata up to cr_lvl, then delete the original data */ +void multires_del_lower_customdata(Multires *mr, MultiresLevel *cr_lvl) +{ + MultiresLevel *lvl1= mr->levels.first; + MDeformVert *dverts= NULL; + CustomData cdf; + int i; + + /* dverts */ + dverts= subdivide_customdata_to_level(CustomData_get(&mr->vdata, 0, CD_MDEFORMVERT), + lvl1, cr_lvl, CD_MDEFORMVERT); + if(dverts) { + CustomData_free_layers(&mr->vdata, CD_MDEFORMVERT, lvl1->totvert); + CustomData_add_layer(&mr->vdata, CD_MDEFORMVERT, CD_ASSIGN, dverts, cr_lvl->totvert); + } + + /* mtfaces */ + CustomData_copy(&mr->fdata, &cdf, CD_MASK_MTFACE, CD_ASSIGN, cr_lvl->totface); + for(i=0; i<CustomData_number_of_layers(&mr->fdata, CD_MTFACE); ++i) { + MTFace *mtfaces= + subdivide_customdata_to_level(CustomData_get_layer_n(&mr->fdata, CD_MTFACE, i), + lvl1, cr_lvl, CD_MTFACE); + if(mtfaces) + CustomData_set_layer_n(&cdf, CD_MTFACE, i, mtfaces); + } + + CustomData_free(&mr->fdata, lvl1->totface); + mr->fdata= cdf; +} + +/* Update all special first-level data, if the first-level is active */ +void multires_update_first_level(Mesh *me, EditMesh *em) +{ + if(me && me->mr && me->mr->current == 1) { + multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, + &me->mr->vdata, CD_MDEFORMVERT); + multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, + &me->mr->fdata, CD_MTFACE); + multires_update_edge_flags(me, em); + } +} + +/*********** Multires.edge_flags ***********/ +void multires_update_edge_flags(Mesh *me, EditMesh *em) +{ + MultiresLevel *lvl= me->mr->levels.first; + EditEdge *eed= NULL; + int i; + + if(em) eed= em->edges.first; + for(i=0; i<lvl->totedge; ++i) { + if(em) { + me->mr->edge_flags[i]= 0; + eed_to_medge_flag(eed, &me->mr->edge_flags[i], &me->mr->edge_creases[i]); + eed= eed->next; + } + else { + me->mr->edge_flags[i]= me->medge[i].flag; + me->mr->edge_creases[i]= me->medge[i].crease; + } + } +} + + + +/*********** Multires.vdata ***********/ + +/* MDeformVert */ + +/* Add each weight from in to out. Scale each weight by w. */ +void multires_add_dvert(MDeformVert *out, const MDeformVert *in, const float w) +{ + if(out && in) { + int i, j; + char found; + + for(i=0; i<in->totweight; ++i) { + found= 0; + for(j=0; j<out->totweight; ++j) { + if(out->dw[j].def_nr==in->dw[i].def_nr) { + out->dw[j].weight += in->dw[i].weight * w; + found= 1; + } + } + if(!found) { + MDeformWeight *newdw= MEM_callocN(sizeof(MDeformWeight)*(out->totweight+1), + "multires dvert"); + if(out->dw) { + memcpy(newdw, out->dw, sizeof(MDeformWeight)*out->totweight); + MEM_freeN(out->dw); + } + + out->dw= newdw; + out->dw[out->totweight].weight= in->dw[i].weight * w; + out->dw[out->totweight].def_nr= in->dw[i].def_nr; + + ++out->totweight; + } + } + } +} + +/* Takes an input array of dverts and subdivides them (linear) using the topology of lvl */ +MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl) +{ + if(lvl && lvl->next) { + MDeformVert *out = MEM_callocN(sizeof(MDeformVert)*lvl->next->totvert, "dvert prop array"); + int i, j; + + /* Copy lower level */ + for(i=0; i<lvl->totvert; ++i) + multires_add_dvert(&out[i], &src[i], 1); + /* Edge verts */ + for(i=0; i<lvl->totedge; ++i) { + for(j=0; j<2; ++j) + multires_add_dvert(&out[lvl->totvert+i], &src[lvl->edges[i].v[j]],0.5); + } + + /* Face verts */ + for(i=0; i<lvl->totface; ++i) { + for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j) + multires_add_dvert(&out[lvl->totvert + lvl->totedge + i], + &src[lvl->faces[i].v[j]], + lvl->faces[i].v[3]?0.25:(1.0f/3.0f)); + } + + return out; + } + + return NULL; +} + + + +/*********** Multires.fdata ***********/ + +/* MTFace */ + +void multires_uv_avg2(float out[2], const float a[2], const float b[2]) +{ + int i; + for(i=0; i<2; ++i) + out[i] = (a[i] + b[i]) / 2.0f; +} + +/* Takes an input array of mtfaces and subdivides them (linear) using the topology of lvl */ +MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl) +{ + if(lvl && lvl->next) { + MTFace *out= MEM_callocN(sizeof(MultiresColFace)*lvl->next->totface,"Multirescolfaces"); + int i, j, curf; + + for(i=0, curf=0; i<lvl->totface; ++i) { + const char sides= lvl->faces[i].v[3]?4:3; + float cntr[2]= {0, 0}; + + /* Find average uv coord of the current face */ + for(j=0; j<sides; ++j) { + cntr[0]+= src[i].uv[j][0]; + cntr[1]+= src[i].uv[j][1]; + } + cntr[0]/= sides; + cntr[1]/= sides; + + for(j=0; j<sides; ++j, ++curf) { + out[curf]= src[i]; + + multires_uv_avg2(out[curf].uv[0], src[i].uv[j], src[i].uv[j==0?sides-1:j-1]); + + out[curf].uv[1][0]= src[i].uv[j][0]; + out[curf].uv[1][1]= src[i].uv[j][1]; + + multires_uv_avg2(out[curf].uv[2], src[i].uv[j], src[i].uv[j==sides-1?0:j+1]); + + out[curf].uv[3][0]= cntr[0]; + out[curf].uv[3][1]= cntr[1]; + } + } + + return out; + } + + return NULL; +} + +void multires_delete_layer(Mesh *me, CustomData *cd, const int type, int n) +{ + if(me && me->mr && cd) { + MultiresLevel *lvl1= me->mr->levels.first; + + multires_update_levels(me, 0); + + CustomData_set_layer_active(cd, type, n); + CustomData_free_layer_active(cd, type, lvl1->totface); + + multires_level_to_mesh(OBACT, me, 0); + } +} + +void multires_add_layer(Mesh *me, CustomData *cd, const int type, const int n) +{ + if(me && me->mr && cd) { + multires_update_levels(me, 0); + + if(CustomData_has_layer(cd, type)) + CustomData_add_layer(cd, type, CD_DUPLICATE, CustomData_get_layer(cd, type), + current_level(me->mr)->totface); + else + CustomData_add_layer(cd, type, CD_DEFAULT, NULL, current_level(me->mr)->totface); + + CustomData_set_layer_active(cd, type, n); + multires_level_to_mesh(OBACT, me, 0); + } +} diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c new file mode 100644 index 00000000000..0874890a2c6 --- /dev/null +++ b/source/blender/blenkernel/intern/multires.c @@ -0,0 +1,1305 @@ +/* + * $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 "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(Object *ob, 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) mesh_pmv_off(ob, 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); +} + +static void multires_update_colors(Mesh *me, EditMesh *em) +{ + MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); + MultiresCol *pr_deltas= NULL, *cr_deltas= 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, em); +} + +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 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; + } +} + +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; + + if(em) + return; + + 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) { + me->mvert[i]= me->mr->verts[i]; + } + for(i=0; i<lvl->totedge; ++i) { + 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) { + 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(lvl==me->mr->levels.first) { + for(i=0; i<lvl->totedge; ++i) { + 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); + + me->medge[i].flag= me->mr->edge_flags[ndx]; + me->medge[i].crease= me->mr->edge_creases[ndx]; + } + } + + 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) { + CustomData *src= &me->fdata; + + 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(me->mr->use_col) + multires_to_mcol(&lvl->colfaces[i], &me->mcol[i*4]); + } + + } + + mesh_update_customdata_pointers(me); + + 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) mesh_pmv_off(ob, 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) mesh_pmv_off(ob, 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/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index ff7b429845d..47640ad07ae 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -47,6 +47,7 @@ #include "MEM_guardedalloc.h" #include "DNA_armature_types.h" +#include "DNA_color_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" @@ -63,6 +64,7 @@ #include "BKE_anim.h" #include "BKE_armature.h" #include "BKE_bad_level_calls.h" +#include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_depsgraph.h" #include "BKE_global.h" @@ -75,11 +77,11 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_sculpt.h" #include "BKE_world.h" #include "BKE_utildefines.h" #include "BIF_previewrender.h" -#include "BDR_sculptmode.h" #include "BPY_extern.h" #include "BLI_arithb.h" @@ -168,7 +170,7 @@ void free_scene(Scene *sce) MEM_freeN(sce->nodetree); } - sculptmode_free_all(sce); + sculptdata_free(sce); } Scene *add_scene(char *name) @@ -259,7 +261,7 @@ Scene *add_scene(char *name) BLI_init_rctf(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f); sce->r.osa= 8; - sculptmode_init(sce); + sculptdata_init(sce); /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */ scene_add_render_layer(sce); @@ -578,3 +580,127 @@ void scene_add_render_layer(Scene *sce) srl->passflag= SCE_PASS_COMBINED|SCE_PASS_Z; } +/* Initialize 'permanent' sculpt data that is saved with file kept after + switching out of sculptmode. */ +void sculptdata_init(Scene *sce) +{ + SculptData *sd; + + if(!sce) + return; + + sd= &sce->sculptdata; + + if(sd->cumap) + curvemapping_free(sd->cumap); + + memset(sd, 0, sizeof(SculptData)); + + sd->drawbrush.size = sd->smoothbrush.size = sd->pinchbrush.size = + sd->inflatebrush.size = sd->grabbrush.size = + sd->layerbrush.size = sd->flattenbrush.size = 50; + sd->drawbrush.strength = sd->smoothbrush.strength = + sd->pinchbrush.strength = sd->inflatebrush.strength = + sd->grabbrush.strength = sd->layerbrush.strength = + sd->flattenbrush.strength = 25; + sd->drawbrush.dir = sd->pinchbrush.dir = sd->inflatebrush.dir = sd->layerbrush.dir= 1; + sd->drawbrush.airbrush = sd->smoothbrush.airbrush = + sd->pinchbrush.airbrush = sd->inflatebrush.airbrush = + sd->layerbrush.airbrush = sd->flattenbrush.airbrush = 0; + sd->drawbrush.view= 0; + sd->brush_type= DRAW_BRUSH; + sd->texact= -1; + sd->texfade= 1; + sd->averaging= 1; + sd->texsep= 0; + sd->texrept= SCULPTREPT_DRAG; + sd->flags= SCULPT_DRAW_BRUSH; + sd->tablet_size=3; + sd->tablet_strength=10; + sd->rake=0; + sculpt_reset_curve(sd); +} + +void sculptdata_free(Scene *sce) +{ + SculptData *sd= &sce->sculptdata; + int a; + + sculptsession_free(sce); + + for(a=0; a<MAX_MTEX; a++) { + MTex *mtex= sd->mtex[a]; + if(mtex) { + if(mtex->tex) mtex->tex->id.us--; + MEM_freeN(mtex); + } + } + + curvemapping_free(sd->cumap); + sd->cumap = NULL; +} + +void sculpt_vertexusers_free(SculptSession *ss) +{ + if(ss && ss->vertex_users){ + MEM_freeN(ss->vertex_users); + MEM_freeN(ss->vertex_users_mem); + ss->vertex_users= NULL; + ss->vertex_users_mem= NULL; + ss->vertex_users_size= 0; + } +} + +void sculptsession_free(Scene *sce) +{ + SculptSession *ss= sce->sculptdata.session; + if(ss) { + if(ss->projverts) + MEM_freeN(ss->projverts); + if(ss->mats) + MEM_freeN(ss->mats); + + if(ss->propset) { + if(ss->propset->texdata) + MEM_freeN(ss->propset->texdata); + if(ss->propset->num) + MEM_freeN(ss->propset->num); + MEM_freeN(ss->propset); + } + + sculpt_vertexusers_free(ss); + if(ss->texcache) + MEM_freeN(ss->texcache); + MEM_freeN(ss); + sce->sculptdata.session= NULL; + } +} + +/* Default curve approximates 0.5 * (cos(pi * x) + 1), with 0 <= x <= 1 */ +void sculpt_reset_curve(SculptData *sd) +{ + CurveMap *cm = NULL; + + if(!sd->cumap) + sd->cumap = curvemapping_add(1, 0, 0, 1, 1); + + cm = sd->cumap->cm; + + if(cm->curve) + MEM_freeN(cm->curve); + cm->curve= MEM_callocN(6*sizeof(CurveMapPoint), "curve points"); + cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE; + cm->totpoint= 6; + cm->curve[0].x= 0; + cm->curve[0].y= 1; + cm->curve[1].x= 0.1; + cm->curve[1].y= 0.97553; + cm->curve[2].x= 0.3; + cm->curve[2].y= 0.79389; + cm->curve[3].x= 0.9; + cm->curve[3].y= 0.02447; + cm->curve[4].x= 0.7; + cm->curve[4].y= 0.20611; + cm->curve[5].x= 1; + cm->curve[5].y= 0; +} diff --git a/source/blender/editors/include/BDR_sculptmode.h b/source/blender/editors/include/BDR_sculptmode.h index f1b5170f395..ca9d77d179f 100644 --- a/source/blender/editors/include/BDR_sculptmode.h +++ b/source/blender/editors/include/BDR_sculptmode.h @@ -1,5 +1,5 @@ /* - * $Id: BDR_sculptmode.h 11036 2007-06-24 22:28:28Z nicholasbishop $ + * $Id: BDR_sculptmode.h 13014 2007-12-26 23:08:00Z nicholasbishop $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -32,8 +32,7 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" -/* For bglMats */ -#include "BIF_glutil.h" +#include "BKE_sculpt.h" #include "transform.h" struct uiBlock; @@ -49,62 +48,15 @@ struct ScrArea; struct SculptData; struct SculptStroke; -typedef enum PropsetMode { - PropsetNone = 0, - PropsetSize, - PropsetStrength, - PropsetTexRot -} PropsetMode; -typedef struct PropsetData { - PropsetMode mode; - unsigned int tex; - short origloc[2]; - float *texdata; - - short origsize; - char origstrength; - float origtexrot; - - NumInput num; -} PropsetData; - -typedef struct SculptSession { - bglMats mats; - - /* An array of lists; array is sized as - large as the number of verts in the mesh, - the list for each vert contains the index - for all the faces that use that vertex */ - struct ListBase *vertex_users; - struct IndexNode *vertex_users_mem; - int vertex_users_size; - - /* Used temporarily per-stroke */ - float *vertexcosnos; - ListBase damaged_rects; - ListBase damaged_verts; - - /* Used to cache the render of the active texture */ - unsigned int texcache_w, texcache_h, *texcache; - - PropsetData *propset; - - /* For rotating around a pivot point */ - vec3f pivot; - - struct SculptStroke *stroke; -} SculptSession; - -SculptSession *sculpt_session(void); +struct SculptSession *sculpt_session(void); struct SculptData *sculpt_data(void); /* Memory */ -void sculptmode_init(struct Scene *); -void sculptmode_free_all(struct Scene *); void sculptmode_correct_state(void); /* Interface */ void sculptmode_draw_interface_tools(struct uiBlock *block,unsigned short cx, unsigned short cy); +void sculptmode_draw_interface_brush(struct uiBlock *block,unsigned short cx, unsigned short cy); void sculptmode_draw_interface_textures(struct uiBlock *block,unsigned short cx, unsigned short cy); void sculptmode_rem_tex(void*,void*); void sculptmode_propset_init(PropsetMode mode); @@ -133,10 +85,6 @@ void sculpt_stroke_draw(); /* Partial Mesh Visibility */ -struct PartialVisibility *sculptmode_copy_pmv(struct PartialVisibility *); -void sculptmode_pmv_free(struct PartialVisibility *); -void sculptmode_revert_pmv(struct Mesh *me); -void sculptmode_pmv_off(struct Mesh *me); void sculptmode_pmv(int mode); #endif diff --git a/source/blender/editors/screen/stubs.c b/source/blender/editors/screen/stubs.c index 879a9e83b48..0fd1bc352d5 100644 --- a/source/blender/editors/screen/stubs.c +++ b/source/blender/editors/screen/stubs.c @@ -41,15 +41,11 @@ void saveover() {} void texstr() {} void pupmenu() {} +/* global vars */ void *curarea; void *editNurb; void *editelems; -/* blenkernel errors */ -void PE_recalc_world_cos() {} -void PE_free_particle_edit() {} -void PE_get_colors() {} - /* python, will come back */ void BPY_post_start_python() {} void BPY_run_python_script() {} @@ -87,20 +83,21 @@ void deselectall() {} /* sculpt */ void sculptmode_free_all() {} void sculptmode_init() {} -void multires_level_n() {} -void multires_set_level() {} -void multires_update_levels() {} -void multires_copy() {} -void multires_free() {} -void sculpt_reset_curve() {} +/* mesh */ void free_realtime_image() {} +void NewBooleanDerivedMesh() {} +void harmonic_coordinates_bind() {} +/* particle */ +void PE_recalc_world_cos() {} +void PE_free_particle_edit() {} +void PE_get_colors() {} + +/* fluid */ void fluidsimSettingsCopy() {} void fluidsimSettingsFree() {} -void NewBooleanDerivedMesh() {} -void harmonic_coordinates_bind() {} void BIF_filelist_freelib() {} |