Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/multires.c')
-rw-r--r--source/blender/blenkernel/intern/multires.c2352
1 files changed, 1309 insertions, 1043 deletions
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 4d312632b1a..b1387281cf5 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -32,1278 +32,1544 @@
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "DNA_vec_types.h"
-
-#include "BIF_editmesh.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
-#include "BLI_editVert.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_multires.h"
-
-#include "blendef.h"
-#include "editmesh.h"
+#include "BKE_object.h"
+#include "BKE_subsurf.h"
#include <math.h>
+#include <string.h>
-/* Returns the active multires level (currently applied to the mesh) */
-MultiresLevel *current_level(Multires *mr)
-{
- return BLI_findlink(&mr->levels, mr->current - 1);
-}
+/* MULTIRES MODIFIER */
+static const int multires_max_levels = 13;
+static const int multires_quad_tot[] = {4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
+static const int multires_side_tot[] = {2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
-/* Returns the nth multires level, starting at 1 */
-MultiresLevel *multires_level_n(Multires *mr, int n)
+MultiresModifierData *find_multires_modifier(Object *ob)
{
- if(mr)
- return BLI_findlink(&mr->levels, n - 1);
- else
- return NULL;
-}
+ ModifierData *md;
+ MultiresModifierData *mmd = 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;
+ for(md = ob->modifiers.first; md; md = md->next) {
+ if(md->type == eModifierType_Multires) {
+ mmd = (MultiresModifierData*)md;
+ break;
+ }
}
+
+ return mmd;
+
}
-/* Does not actually free lvl itself */
-void multires_free_level(MultiresLevel *lvl)
+int multiresModifier_switch_level(Object *ob, const int distance)
{
- 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);
+ MultiresModifierData *mmd = find_multires_modifier(ob);
+
+ if(mmd) {
+ mmd->lvl += distance;
+ if(mmd->lvl < 1) mmd->lvl = 1;
+ else if(mmd->lvl > mmd->totlvl) mmd->lvl = mmd->totlvl;
+ /* XXX: DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ object_handle_update(ob);*/
+ return 1;
}
+ else
+ return 0;
}
-void multires_free(Multires *mr)
+/* XXX */
+#if 0
+void multiresModifier_join(Object *ob)
{
- 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);
+ Base *base = NULL;
+ int highest_lvl = 0;
+
+ /* First find the highest level of subdivision */
+ base = FIRSTBASE;
+ while(base) {
+ if(TESTBASELIB_BGMODE(base) && base->object->type==OB_MESH) {
+ ModifierData *md;
+ for(md = base->object->modifiers.first; md; md = md->next) {
+ if(md->type == eModifierType_Multires) {
+ int totlvl = ((MultiresModifierData*)md)->totlvl;
+ if(totlvl > highest_lvl)
+ highest_lvl = totlvl;
+
+ /* Ensure that all updates are processed */
+ multires_force_update(base->object);
+ }
+ }
}
+ base = base->next;
+ }
- while(lvl) {
- multires_free_level(lvl);
- lvl= lvl->next;
- }
+ /* No multires meshes selected */
+ if(highest_lvl == 0)
+ return;
- MEM_freeN(mr->verts);
+ /* Subdivide all the displacements to the highest level */
+ base = FIRSTBASE;
+ while(base) {
+ if(TESTBASELIB_BGMODE(base) && base->object->type==OB_MESH) {
+ ModifierData *md = NULL;
+ MultiresModifierData *mmd = NULL;
- BLI_freelistN(&mr->levels);
+ for(md = base->object->modifiers.first; md; md = md->next) {
+ if(md->type == eModifierType_Multires)
+ mmd = (MultiresModifierData*)md;
+ }
- MEM_freeN(mr);
- }
-}
+ /* If the object didn't have multires enabled, give it a new modifier */
+ if(!mmd) {
+ md = base->object->modifiers.first;
+
+ while(md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform)
+ md = md->next;
+
+ mmd = (MultiresModifierData*)modifier_new(eModifierType_Multires);
+ BLI_insertlinkbefore(&base->object->modifiers, md, mmd);
+ }
-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;
+ if(mmd)
+ multiresModifier_subdivide(mmd, base->object, highest_lvl - mmd->totlvl, 0, 0);
+ }
+ base = base->next;
}
- return NULL;
}
+#endif
-Multires *multires_copy(Multires *orig)
+/* Returns 0 on success, 1 if the src's totvert doesn't match */
+int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src)
{
- const CustomDataMask vdata_mask= CD_MASK_MDEFORMVERT;
+ Mesh *src_me = get_mesh(src);
+ DerivedMesh *mrdm = dst->derivedFinal;
- 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));
+ if(mrdm && mrdm->getNumVerts(mrdm) == src_me->totvert) {
+ MVert *mvert = CDDM_get_verts(mrdm);
+ int i;
- 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;
-}
+ for(i = 0; i < src_me->totvert; ++i)
+ VecCopyf(mvert[i].co, src_me->mvert[i].co);
+ mrdm->needsFree = 1;
+ MultiresDM_mark_as_modified(mrdm);
+ mrdm->release(mrdm);
+ dst->derivedFinal = 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;
+ return 0;
}
- 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);
+ return 1;
}
-static void multires_get_edge(MultiresEdge *e, EditEdge *eed, MEdge *m, short *flag, char *crease)
+static void Mat3FromColVecs(float mat[][3], float v1[3], float v2[3], float v3[3])
{
- 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;
- }
+ VecCopyf(mat[0], v1);
+ VecCopyf(mat[1], v2);
+ VecCopyf(mat[2], v3);
}
-static void multires_get_face(MultiresFace *f, CustomData *fdata, int findex, EditFace *efa, MFace *m)
+static DerivedMesh *multires_subdisp_pre(DerivedMesh *mrdm, int distance, int simple)
{
- 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, fdata, findex, 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;
- }
+ DerivedMesh *final;
+ SubsurfModifierData smd;
+
+ memset(&smd, 0, sizeof(SubsurfModifierData));
+ smd.levels = distance;
+ if(simple)
+ smd.subdivType = ME_SIMPLE_SUBSURF;
+
+ final = subsurf_make_derived_from_derived_with_multires(mrdm, &smd, NULL, 0, NULL, 0, 0);
+
+ return final;
}
-/* For manipulating vertex colors / uvs */
-static void mcol_to_multires(MultiresColFace *mrf, MCol *mcol)
+static void VecAddUf(float a[3], float b[3])
{
- 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;
- }
+ a[0] += b[0];
+ a[1] += b[1];
+ a[2] += b[2];
}
-/* 1 <= count <= 4 */
-static void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count)
+static void multires_subdisp(DerivedMesh *orig, Mesh *me, DerivedMesh *final, int lvl, int totlvl,
+ int totsubvert, int totsubedge, int totsubface, int addverts)
{
- 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;
+ DerivedMesh *mrdm;
+ MultiresModifierData mmd_sub;
+ MVert *mvs = CDDM_get_verts(final);
+ MVert *mvd, *mvd_f1, *mvs_f1, *mvd_f3, *mvd_f4;
+ MVert *mvd_f2, *mvs_f2, *mvs_e1, *mvd_e1, *mvs_e2;
+ int totvert;
+ int slo1 = multires_side_tot[lvl - 1];
+ int sll = slo1 / 2;
+ int slo2 = multires_side_tot[totlvl - 2];
+ int shi2 = multires_side_tot[totlvl - 1];
+ int skip = multires_side_tot[totlvl - lvl] - 1;
+ int i, j, k;
+
+ mmd_sub.lvl = mmd_sub.totlvl = totlvl;
+ mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0);
+
+ mvd = CDDM_get_verts(mrdm);
+ /* Need to map from ccg to mrdm */
+ totvert = mrdm->getNumVerts(mrdm);
+
+ if(!addverts) {
+ for(i = 0; i < totvert; ++i) {
+ float z[3] = {0,0,0};
+ VecCopyf(mvd[i].co, z);
+ }
}
- 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);
-}
+ /* Load base verts */
+ for(i = 0; i < me->totvert; ++i)
+ VecAddUf(mvd[totvert - me->totvert + i].co, mvs[totvert - me->totvert + i].co);
+
+ mvd_f1 = mvd;
+ mvs_f1 = mvs;
+ mvd_f2 = mvd;
+ mvs_f2 = mvs + totvert - totsubvert;
+ mvs_e1 = mvs + totsubface * (skip-1) * (skip-1);
+
+ for(i = 0; i < me->totface; ++i) {
+ const int end = me->mface[i].v4 ? 4 : 3;
+ int x, y, x2, y2, mov= 0;
+
+ mvd_f1 += 1 + end * (slo2-2); //center+edgecross
+ mvd_f3 = mvd_f4 = mvd_f1;
+
+ for(j = 0; j < end; ++j) {
+ mvd_f1 += (skip/2 - 1) * (slo2 - 2) + (skip/2 - 1);
+ /* Update sub faces */
+ for(y = 0; y < sll; ++y) {
+ for(x = 0; x < sll; ++x) {
+ /* Face center */
+ VecAddUf(mvd_f1->co, mvs_f1->co);
+ mvs_f1 += 1;
+
+ /* Now we hold the center of the subface at mvd_f1
+ and offset it to the edge cross and face verts */
+
+ /* Edge cross */
+ for(k = 0; k < 4; ++k) {
+ if(k == 0) mov = -1;
+ else if(k == 1) mov = slo2 - 2;
+ else if(k == 2) mov = 1;
+ else if(k == 3) mov = -(slo2 - 2);
+
+ for(x2 = 1; x2 < skip/2; ++x2) {
+ VecAddUf((mvd_f1 + mov * x2)->co, mvs_f1->co);
+ ++mvs_f1;
+ }
+ }
-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;
+ /* Main face verts */
+ for(k = 0; k < 4; ++k) {
+ int movx= 0, movy= 0;
+
+ if(k == 0) { movx = -1; movy = -(slo2 - 2); }
+ else if(k == 1) { movx = slo2 - 2; movy = -1; }
+ else if(k == 2) { movx = 1; movy = slo2 - 2; }
+ else if(k == 3) { movx = -(slo2 - 2); movy = 1; }
+
+ for(y2 = 1; y2 < skip/2; ++y2) {
+ for(x2 = 1; x2 < skip/2; ++x2) {
+ VecAddUf((mvd_f1 + movy * y2 + movx * x2)->co, mvs_f1->co);
+ ++mvs_f1;
+ }
+ }
+ }
+
+ mvd_f1 += skip;
+ }
+ mvd_f1 += (skip - 1) * (slo2 - 2) - 1;
+ }
+ mvd_f1 -= (skip - 1) * (slo2 - 2) - 1 + skip;
+ mvd_f1 += (slo2 - 2) * (skip/2-1) + skip/2-1 + 1;
+ }
- if(!CustomData_has_layer(src, CD_MCOL) && !CustomData_has_layer(src, CD_MTFACE)) return;
+ /* update face center verts */
+ VecAddUf(mvd_f2->co, mvs_f2->co);
- /* 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");
+ mvd_f2 += 1;
+ mvs_f2 += 1;
- me->mr->use_col= CustomData_has_layer(src, CD_MCOL);
+ /* update face edge verts */
+ for(j = 0; j < end; ++j) {
+ MVert *restore;
- if(em) efa= em->faces.first;
- for(i=0; i<lvl->totface; ++i) {
- MultiresColFace *f= &lvl->colfaces[i];
+ /* Super-face edge cross */
+ for(k = 0; k < skip-1; ++k) {
+ VecAddUf(mvd_f2->co, mvs_e1->co);
+ mvd_f2++;
+ mvs_e1++;
+ }
+ for(x = 1; x < sll; ++x) {
+ VecAddUf(mvd_f2->co, mvs_f2->co);
+ mvd_f2++;
+ mvs_f2++;
+
+ for(k = 0; k < skip-1; ++k) {
+ VecAddUf(mvd_f2->co, mvs_e1->co);
+ mvd_f2++;
+ mvs_e1++;
+ }
+ }
- 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;
+ restore = mvs_e1;
+ for(y = 0; y < sll - 1; ++y) {
+ for(x = 0; x < sll; ++x) {
+ for(k = 0; k < skip - 1; ++k) {
+ VecAddUf(mvd_f3[(skip-1)+(y*skip) + (x*skip+k)*(slo2-2)].co,
+ mvs_e1->co);
+ ++mvs_e1;
+ }
+ mvs_e1 += skip-1;
+ }
+ }
+
+ mvs_e1 = restore + skip - 1;
+ for(y = 0; y < sll - 1; ++y) {
+ for(x = 0; x < sll; ++x) {
+ for(k = 0; k < skip - 1; ++k) {
+ VecAddUf(mvd_f3[(slo2-2)*(skip-1)+(x*skip)+k + y*skip*(slo2-2)].co,
+ mvs_e1->co);
+ ++mvs_e1;
+ }
+ mvs_e1 += skip - 1;
+ }
+ }
+
+ mvd_f3 += (slo2-2)*(slo2-2);
+ mvs_e1 -= skip - 1;
+ }
+
+ /* update base (2) face verts */
+ for(j = 0; j < end; ++j) {
+ mvd_f2 += (slo2 - 1) * (skip - 1);
+ for(y = 0; y < sll - 1; ++y) {
+ for(x = 0; x < sll - 1; ++x) {
+ VecAddUf(mvd_f2->co, mvs_f2->co);
+ mvd_f2 += skip;
+ ++mvs_f2;
+ }
+ mvd_f2 += (slo2 - 1) * (skip - 1);
+ }
+ mvd_f2 -= (skip - 1);
+ }
}
- /* 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);
+ /* edges */
+ mvd_e1 = mvd + totvert - me->totvert - me->totedge * (shi2-2);
+ mvs_e2 = mvs + totvert - me->totvert - me->totedge * (slo1-2);
+ for(i = 0; i < me->totedge; ++i) {
+ for(j = 0; j < skip - 1; ++j) {
+ VecAddUf(mvd_e1->co, mvs_e1->co);
+ mvd_e1++;
+ mvs_e1++;
+ }
+ for(j = 0; j < slo1 - 2; j++) {
+ VecAddUf(mvd_e1->co, mvs_e2->co);
+ mvd_e1++;
+ mvs_e2++;
- 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;
+ for(k = 0; k < skip - 1; ++k) {
+ VecAddUf(mvd_e1->co, mvs_e1->co);
+ mvd_e1++;
+ mvs_e1++;
}
}
- 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;
+ final->needsFree = 1;
+ final->release(final);
+ mrdm->needsFree = 1;
+ MultiresDM_mark_as_modified(mrdm);
+ mrdm->release(mrdm);
+}
+
+/* direction=1 for delete higher, direction=0 for lower (not implemented yet) */
+void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Object *ob, int direction)
+{
+ Mesh *me = get_mesh(ob);
+ int distance = mmd->totlvl - mmd->lvl;
+ MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+
+ multires_force_update(ob);
+
+ if(mdisps && distance > 0 && direction == 1) {
+ int skip = multires_side_tot[distance] - 1;
+ int st = multires_side_tot[mmd->totlvl - 1];
+ int totdisp = multires_quad_tot[mmd->lvl - 1];
+ int i, j, x, y;
+
+ for(i = 0; i < me->totface; ++i) {
+ float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires del disps");
+
+ for(j = 0, y = 0; y < st; y += skip) {
+ for(x = 0; x < st; x += skip) {
+ VecCopyf(disps[j], mdisps[i].disps[y * st + x]);
+ ++j;
+ }
}
+
+ MEM_freeN(mdisps[i].disps);
+ mdisps[i].disps = disps;
+ mdisps[i].totdisp = totdisp;
}
- lvl= lvl->prev;
}
+
+ mmd->totlvl = mmd->lvl;
}
-void multires_create(Object *ob, Mesh *me)
+void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int distance, int updateblock, int simple)
{
- MultiresLevel *lvl;
- EditMesh *em= G.obedit ? G.editMesh : NULL;
- EditVert *eve= NULL;
- EditFace *efa= NULL;
- EditEdge *eed= NULL;
+ DerivedMesh *final = NULL;
+ int totsubvert = 0, totsubface = 0, totsubedge = 0;
+ Mesh *me = get_mesh(ob);
+ MDisps *mdisps;
int i;
-
- lvl= MEM_callocN(sizeof(MultiresLevel), "multires level");
- if(me->pv) mesh_pmv_off(ob, me);
+ if(distance == 0)
+ return;
+
+ if(mmd->totlvl > multires_max_levels)
+ mmd->totlvl = multires_max_levels;
+ if(mmd->lvl > multires_max_levels)
+ mmd->lvl = multires_max_levels;
- 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 ? &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;
+ multires_force_update(ob);
+
+ mmd->lvl = mmd->totlvl;
+ mmd->totlvl += distance;
+
+ mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ if(!mdisps)
+ mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
+
+ if(mdisps->disps && !updateblock && mmd->totlvl > 2) {
+ DerivedMesh *orig, *mrdm;
+ MultiresModifierData mmd_sub;
+
+ orig = CDDM_from_mesh(me, NULL);
+ mmd_sub.lvl = mmd_sub.totlvl = mmd->lvl;
+ mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0);
+ totsubvert = mrdm->getNumVerts(mrdm);
+ totsubedge = mrdm->getNumEdges(mrdm);
+ totsubface = mrdm->getNumFaces(mrdm);
+ orig->needsFree = 1;
+ orig->release(orig);
+
+ final = multires_subdisp_pre(mrdm, distance, simple);
+ mrdm->needsFree = 1;
+ mrdm->release(mrdm);
}
- /* 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 ? &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], &me->mr->fdata, i, efa, &me->mface[i]);
- if(em) efa= efa->next;
+ for(i = 0; i < me->totface; ++i) {
+ const int totdisp = multires_quad_tot[mmd->totlvl - 1];
+ float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+
+ if(mdisps[i].disps)
+ MEM_freeN(mdisps[i].disps);
+
+ mdisps[i].disps = disps;
+ mdisps[i].totdisp = totdisp;
}
- /* 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;
+
+ if(final) {
+ DerivedMesh *orig;
+
+ orig = CDDM_from_mesh(me, NULL);
+
+ multires_subdisp(orig, me, final, mmd->lvl, mmd->totlvl, totsubvert, totsubedge, totsubface, 0);
+
+ orig->needsFree = 1;
+ orig->release(orig);
}
- multires_load_cols(me);
+ mmd->lvl = mmd->totlvl;
}
-typedef struct MultiresMapNode {
- struct MultiresMapNode *next, *prev;
- unsigned Index;
-} MultiresMapNode;
+typedef struct DisplacerEdges {
+ /* DerivedMesh index at the start of each edge (using face x/y directions to define the start) */
+ int base[4];
+ /* 1 if edge moves in the positive x or y direction, -1 otherwise */
+ int dir[4];
+} DisplacerEdges;
+
+typedef struct DisplacerSpill {
+ /* Index of face (in base mesh), -1 for none */
+ int face;
+
+ /* Spill flag */
+ /* 1 = Negative variable axis */
+ /* 2 = Near fixed axis */
+ /* 4 = Flip axes */
+ int f;
+
+ /* Neighboring edges */
+ DisplacerEdges edges;
+} DisplacerSpill;
+
+typedef struct MultiresDisplacer {
+ Mesh *me;
+ MDisps *grid;
+ MFace *face;
+
+ int dm_first_base_vert_index;
+
+ int spacing;
+ int sidetot, interior_st, disp_st;
+ int sidendx;
+ int type;
+ int invert;
+ MVert *subco;
+ int subco_index, face_index;
+ float weight;
+
+ /* Valence for each corner */
+ int valence[4];
+
+ /* Neighboring edges for current face */
+ DisplacerEdges edges_primary;
+
+ /* Neighboring faces */
+ DisplacerSpill spill_x, spill_y;
+
+ int *face_offsets;
+
+ int x, y, ax, ay;
+} MultiresDisplacer;
-/* Produces temporary connectivity data for the multires lvl */
-static void multires_calc_temp_data(MultiresLevel *lvl)
+static int mface_v(MFace *f, int v)
{
- unsigned i, j, emax;
- MultiresMapNode *indexnode= NULL;
+ return v == 0 ? f->v1 : v == 1 ? f->v2 : v == 2 ? f->v3 : v == 3 ? f->v4 : -1;
+}
- 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);
- }
- }
+/* Get the edges (and their directions) */
+static void find_displacer_edges(MultiresDisplacer *d, DerivedMesh *dm, DisplacerEdges *de, MFace *f)
+{
+ ListBase *emap = MultiresDM_get_vert_edge_map(dm);
+ IndexNode *n;
+ int i, end = f->v4 ? 4 : 3;
+ int offset = dm->getNumVerts(dm) - d->me->totvert - d->me->totedge * d->interior_st;
- /* 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);
- }
- }
+ for(i = 0; i < end; ++i) {
+ int vcur = mface_v(f, i);
+ int vnext = mface_v(f, i == end - 1 ? 0 : i + 1);
- /* 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;
+ de->dir[i] = 1;
- 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;
- }
+ for(n = emap[vcur].first; n; n = n->next) {
+ MEdge *e = &d->me->medge[n->index];
+
+ if(e->v1 == vnext || e->v2 == vnext) {
+ de->base[i] = n->index * d->interior_st;
+ if(((i == 0 || i == 1) && e->v1 == vnext) ||
+ ((i == 2 || i == 3) && e->v2 == vnext)) {
+ de->dir[i] = -1;
+ de->base[i] += d->interior_st - 1;
}
-
- n2= n2->next;
+ de->base[i] += offset;
+ break;
}
- 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)
+/* Returns in out the corners [0-3] that use v1 and v2 */
+void find_face_corners(MFace *f, int v1, int v2, int out[2])
{
- const float total= data->corner1[i]+data->corner2[i]+data->corner3[i];
- return data->quad ? (total+data->corner4[i])/4 : total/3;
+ int i, end = f->v4 ? 4 : 3;
+
+ for(i = 0; i < end; ++i) {
+ int corner = mface_v(f, i);
+ if(corner == v1)
+ out[0] = i;
+ if(corner == v2)
+ out[1] = i;
+ }
}
-static float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i)
+static void multires_displacer_get_spill_faces(MultiresDisplacer *d, DerivedMesh *dm, MFace *mface)
{
- float accum= 0;
- unsigned count= 2;
-
- accum+= data->endpoint1[i] + data->endpoint2[i];
+ ListBase *map = MultiresDM_get_vert_face_map(dm);
+ IndexNode *n1, *n2;
+ int v4 = d->face->v4 ? d->face->v4 : d->face->v1;
+ int crn[2], lv;
+
+ memset(&d->spill_x, 0, sizeof(DisplacerSpill));
+ memset(&d->spill_y, 0, sizeof(DisplacerSpill));
+ d->spill_x.face = d->spill_y.face = -1;
+
+ for(n1 = map[d->face->v3].first; n1; n1 = n1->next) {
+ if(n1->index == d->face_index)
+ continue;
+
+ for(n2 = map[d->face->v2].first; n2; n2 = n2->next) {
+ if(n1->index == n2->index)
+ d->spill_x.face = n1->index;
+ }
+ for(n2 = map[v4].first; n2; n2 = n2->next) {
+ if(n1->index == n2->index)
+ d->spill_y.face = n1->index;
+ }
+ }
- if(!data->boundary) {
- accum+= data->edge_face_neighbor_midpoints_accum[i];
- count+= data->edge_face_neighbor_midpoints_total;
+ if(d->spill_x.face != -1) {
+ /* Neighbor of v2/v3 found, find flip and orientation */
+ find_face_corners(&mface[d->spill_x.face], d->face->v2, d->face->v3, crn);
+ lv = mface[d->spill_x.face].v4 ? 3 : 2;
+
+ if(crn[0] == 0 && crn[1] == lv)
+ d->spill_x.f = 0+2+0;
+ else if(crn[0] == lv && crn[1] == 0)
+ d->spill_x.f = 1+2+0;
+ else if(crn[0] == 1 && crn[1] == 0)
+ d->spill_x.f = 1+2+4;
+ else if(crn[0] == 0 && crn[1] == 1)
+ d->spill_x.f = 0+2+4;
+ else if(crn[0] == 2 && crn[1] == 1)
+ d->spill_x.f = 1+0+0;
+ else if(crn[0] == 1 && crn[1] == 2)
+ d->spill_x.f = 0+0+0;
+ else if(crn[0] == 3 && crn[1] == 2)
+ d->spill_x.f = 0+0+4;
+ else if(crn[0] == 2 && crn[1] == 3)
+ d->spill_x.f = 1+0+4;
+
+ find_displacer_edges(d, dm, &d->spill_x.edges, &mface[d->spill_x.face]);
}
- return accum / count;
+ if(d->spill_y.face != -1) {
+ /* Neighbor of v3/v4 found, find flip and orientation */
+ find_face_corners(&mface[d->spill_y.face], d->face->v3, v4, crn);
+ lv = mface[d->spill_y.face].v4 ? 3 : 2;
+
+ if(crn[0] == 1 && crn[1] == 0)
+ d->spill_y.f = 1+2+0;
+ else if(crn[0] == 0 && crn[1] == 1)
+ d->spill_y.f = 0+2+0;
+ else if(crn[0] == 2 && crn[1] == 1)
+ d->spill_y.f = 1+0+4;
+ else if(crn[0] == 1 && crn[1] == 2)
+ d->spill_y.f = 0+0+4;
+ else if(crn[0] == 3 && crn[1] == 2)
+ d->spill_y.f = 0+0+0;
+ else if(crn[0] == 2 && crn[1] == 3)
+ d->spill_y.f = 1+0+0;
+ else if(crn[0] == 0 && crn[1] == lv)
+ d->spill_y.f = 0+2+4;
+ else if(crn[0] == lv && crn[1] == 0)
+ d->spill_y.f = 1+2+4;
+
+ find_displacer_edges(d, dm, &d->spill_y.edges, &mface[d->spill_y.face]);
+ }
}
-static float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i)
+static void find_corner_valences(MultiresDisplacer *d, DerivedMesh *dm)
{
- 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;
- }
-}
+ int i;
+ d->valence[3] = -1;
+ /* Set the vertex valence for the corners */
+ for(i = 0; i < (d->face->v4 ? 4 : 3); ++i)
+ d->valence[i] = BLI_countlist(&MultiresDM_get_vert_edge_map(dm)[mface_v(d->face, i)]);
+}
-/* 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))
+static void multires_displacer_init(MultiresDisplacer *d, DerivedMesh *dm,
+ const int face_index, const int invert)
{
- unsigned i;
- for(i=0; i<count; ++i)
- out[i]= func(data,i);
+ Mesh *me = MultiresDM_get_mesh(dm);
+
+ d->me = me;
+ d->face = me->mface + face_index;
+ d->face_index = face_index;
+ d->face_offsets = MultiresDM_get_face_offsets(dm);
+ /* Get the multires grid from customdata */
+ d->grid = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ if(d->grid)
+ d->grid += face_index;
+
+ d->spacing = pow(2, MultiresDM_get_totlvl(dm) - MultiresDM_get_lvl(dm));
+ d->sidetot = multires_side_tot[MultiresDM_get_lvl(dm) - 1];
+ d->interior_st = d->sidetot - 2;
+ d->disp_st = multires_side_tot[MultiresDM_get_totlvl(dm) - 1];
+ d->invert = invert;
+
+ multires_displacer_get_spill_faces(d, dm, me->mface);
+ find_displacer_edges(d, dm, &d->edges_primary, d->face);
+ find_corner_valences(d, dm);
+
+ d->dm_first_base_vert_index = dm->getNumVerts(dm) - me->totvert;
}
-static short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v)
+static void multires_displacer_weight(MultiresDisplacer *d, const float w)
{
- MultiresMapNode *node= lvl->vert_edge_map[v].first;
- while(node) {
- if(lvl->edge_boundary_states[node->Index])
- return 1;
- node= node->next;
- }
- return 0;
+ d->weight = w;
}
-#define GET_FLOAT(array, i, j, stride) (((float*)((char*)(array)+((i)*(stride))))[(j)])
+static void multires_displacer_anchor(MultiresDisplacer *d, const int type, const int side_index)
+{
+ d->sidendx = side_index;
+ d->x = d->y = d->sidetot / 2;
+ d->type = type;
+
+ if(type == 2) {
+ if(side_index == 0)
+ d->y -= 1;
+ else if(side_index == 1)
+ d->x += 1;
+ else if(side_index == 2)
+ d->y += 1;
+ else if(side_index == 3)
+ d->x -= 1;
+ }
+ else if(type == 3) {
+ if(side_index == 0) {
+ d->x -= 1;
+ d->y -= 1;
+ }
+ else if(side_index == 1) {
+ d->x += 1;
+ d->y -= 1;
+ }
+ else if(side_index == 2) {
+ d->x += 1;
+ d->y += 1;
+ }
+ else if(side_index == 3) {
+ d->x -= 1;
+ d->y += 1;
+ }
+ }
+
+ d->ax = d->x;
+ d->ay = d->y;
+}
-static void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl,
- void *array, const char stride, const MultiresEdge *e)
+static void multires_displacer_anchor_edge(MultiresDisplacer *d, int v1, int v2, int x)
{
- 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;
+ d->type = 4;
+
+ if(v1 == d->face->v1) {
+ d->x = 0;
+ d->y = 0;
+ if(v2 == d->face->v2)
+ d->x += x;
+ else if(v2 == d->face->v3) {
+ if(x < d->sidetot / 2)
+ d->y = x;
+ else {
+ d->x = x;
+ d->y = d->sidetot - 1;
}
}
+ else
+ d->y += x;
+ }
+ else if(v1 == d->face->v2) {
+ d->x = d->sidetot - 1;
+ d->y = 0;
+ if(v2 == d->face->v1)
+ d->x -= x;
+ else
+ d->y += x;
+ }
+ else if(v1 == d->face->v3) {
+ d->x = d->sidetot - 1;
+ d->y = d->sidetot - 1;
+ if(v2 == d->face->v2)
+ d->y -= x;
+ else if(v2 == d->face->v1) {
+ if(x < d->sidetot / 2)
+ d->x -= x;
+ else {
+ d->x = 0;
+ d->y -= x;
+ }
+ }
+ else
+ d->x -= x;
+ }
+ else if(v1 == d->face->v4) {
+ d->x = 0;
+ d->y = d->sidetot - 1;
+ if(v2 == d->face->v3)
+ d->x += x;
+ else
+ d->y -= x;
}
-
- 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)
+static void multires_displacer_anchor_vert(MultiresDisplacer *d, const int v)
{
- ListBase *neighbors= &lvl->vert_face_map[i];
- MultiresMapNode *n1;
- unsigned j,count= 0;
- float *out= data->vert_face_neighbor_midpoints_average;
+ const int e = d->sidetot - 1;
- out[0]=out[1]=out[2]= 0;
+ d->type = 5;
- 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;
+ d->x = d->y = 0;
+ if(v == d->face->v2)
+ d->x = e;
+ else if(v == d->face->v3)
+ d->x = d->y = e;
+ else if(v == d->face->v4)
+ d->y = e;
}
-static void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
- void *array, const char stride, const unsigned i)
+static void multires_displacer_jump(MultiresDisplacer *d)
{
- 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;
+ if(d->sidendx == 0) {
+ d->x -= 1;
+ d->y = d->ay;
+ }
+ else if(d->sidendx == 1) {
+ d->x = d->ax;
+ d->y -= 1;
+ }
+ else if(d->sidendx == 2) {
+ d->x += 1;
+ d->y = d->ay;
+ }
+ else if(d->sidendx == 3) {
+ d->x = d->ax;
+ d->y += 1;
}
- 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)
+/* Treating v1 as (0,0) and v3 as (st-1,st-1),
+ returns the index of the vertex at (x,y).
+ If x or y is >= st, wraps over to the adjacent face,
+ or if there is no adjacent face, returns -2. */
+static int multires_index_at_loc(int face_index, int x, int y, MultiresDisplacer *d, DisplacerEdges *de)
{
- ListBase *neighbors= &lvl->vert_edge_map[i];
- MultiresMapNode *n1;
- unsigned j,count= 0;
- float *out= data->boundary_edges_average;
+ int coord_edge = d->sidetot - 1; /* Max value of x/y at edge of grid */
+ int mid = d->sidetot / 2;
+ int lim = mid - 1;
+ int qtot = lim * lim;
+ int base = d->face_offsets[face_index];
+
+ /* Edge spillover */
+ if(x == d->sidetot || y == d->sidetot) {
+ int flags, v_axis, f_axis, lx, ly;
+
+ if(x == d->sidetot && d->spill_x.face != -1) {
+ flags = d->spill_x.f;
+
+ /* Handle triangle seam between v1 and v3 */
+ if(!d->me->mface[d->spill_x.face].v4 &&
+ ((flags == 2 && y >= mid) || (flags == 3 && y < mid)))
+ flags += 2;
+
+ v_axis = (flags & 1) ? d->sidetot - 1 - y : y;
+ f_axis = (flags & 2) ? 1 : d->sidetot - 2;
+ lx = f_axis, ly = v_axis;
+
+ if(flags & 4) {
+ lx = v_axis;
+ ly = f_axis;
+ }
- 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;
+ return multires_index_at_loc(d->spill_x.face, lx, ly, d, &d->spill_x.edges);
+ }
+ else if(y == d->sidetot && d->spill_y.face != -1) {
+ flags = d->spill_y.f;
+
+ /* Handle triangle seam between v1 and v3 */
+ if(!d->me->mface[d->spill_y.face].v4 &&
+ ((flags == 6 && x >= mid) || (flags == 7 && x < mid)))
+ flags = ~flags;
+
+ v_axis = (flags & 1) ? x : d->sidetot - 1 - x;
+ f_axis = (flags & 2) ? 1 : d->sidetot - 2;
+ lx = v_axis, ly = f_axis;
+
+ if(flags & 4) {
+ lx = f_axis;
+ ly = v_axis;
+ }
+
+ return multires_index_at_loc(d->spill_y.face, lx, ly, d, &d->spill_y.edges);
}
+ else
+ return -2;
+ }
+ /* Corners */
+ else if(x == 0 && y == 0)
+ return d->dm_first_base_vert_index + d->face->v1;
+ else if(x == coord_edge && y == 0)
+ return d->dm_first_base_vert_index + d->face->v2;
+ else if(x == coord_edge && y == coord_edge)
+ return d->dm_first_base_vert_index + d->face->v3;
+ else if(x == 0 && y == coord_edge)
+ return d->dm_first_base_vert_index + d->face->v4;
+ /* Edges */
+ else if(x == 0) {
+ if(d->face->v4)
+ return de->base[3] + de->dir[3] * (y - 1);
+ else
+ return de->base[2] + de->dir[2] * (y - 1);
+ }
+ else if(y == 0)
+ return de->base[0] + de->dir[0] * (x - 1);
+ else if(x == d->sidetot - 1)
+ return de->base[1] + de->dir[1] * (y - 1);
+ else if(y == d->sidetot - 1)
+ return de->base[2] + de->dir[2] * (x - 1);
+ /* Face center */
+ else if(x == mid && y == mid)
+ return base;
+ /* Cross */
+ else if(x == mid && y < mid)
+ return base + (mid - y);
+ else if(y == mid && x > mid)
+ return base + lim + (x - mid);
+ else if(x == mid && y > mid)
+ return base + lim*2 + (y - mid);
+ else if(y == mid && x < mid) {
+ if(d->face->v4)
+ return base + lim*3 + (mid - x);
+ else
+ return base + lim*2 + (mid - x);
+ }
+ /* Quarters */
+ else {
+ int offset = base + lim * (d->face->v4 ? 4 : 3);
+ if(x < mid && y < mid)
+ return offset + ((mid - x - 1)*lim + (mid - y));
+ else if(x > mid && y < mid)
+ return offset + qtot + ((mid - y - 1)*lim + (x - mid));
+ else if(x > mid && y > mid)
+ return offset + qtot*2 + ((x - mid - 1)*lim + (y - mid));
+ else if(x < mid && y > mid)
+ return offset + qtot*3 + ((y - mid - 1)*lim + (mid - x));
}
- for(j=0; j<3; ++j) out[j]/= count;
+
+ return -1;
}
-/* END CATMULL-CLARK
- ================= */
-
-/* Update vertex locations and vertex flags */
-static void multires_update_vertices(Mesh *me, EditMesh *em)
+/* Calculate the TS matrix used for applying displacements.
+ Uses the undisplaced subdivided mesh's curvature to find a
+ smoothly normal and tangents. */
+static void calc_disp_mat(MultiresDisplacer *d, float mat[3][3])
{
- 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;
-
- /* XXX added this to prevent crash, but if it works? (ton) */
- if(me->mr->verts==NULL)
- return;
+ int u = multires_index_at_loc(d->face_index, d->x + 1, d->y, d, &d->edges_primary);
+ int v = multires_index_at_loc(d->face_index, d->x, d->y + 1, d, &d->edges_primary);
+ float norm[3], t1[3], t2[3], inv[3][3];
+ MVert *base = d->subco + d->subco_index;
+
+ //printf("f=%d, x=%d, y=%d, i=%d, u=%d, v=%d ", d->face_index, d->x, d->y, d->subco_index, u, v);
- /* 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);
+ norm[0] = base->no[0] / 32767.0f;
+ norm[1] = base->no[1] / 32767.0f;
+ norm[2] = base->no[2] / 32767.0f;
+
+ /* Special handling for vertices of valence 3 */
+ if(d->valence[1] == 3 && d->x == d->sidetot - 1 && d->y == 0)
+ u = -1;
+ else if(d->valence[2] == 3 && d->x == d->sidetot - 1 && d->y == d->sidetot - 1)
+ u = v = -1;
+ else if(d->valence[3] == 3 && d->x == 0 && d->y == d->sidetot - 1)
+ v = -1;
+
+ /* If either u or v is -2, it's on a boundary. In this
+ case, back up by one row/column and use the same
+ vector as the preceeding sub-edge. */
+
+ if(u < 0) {
+ u = multires_index_at_loc(d->face_index, d->x - 1, d->y, d, &d->edges_primary);
+ VecSubf(t1, base->co, d->subco[u].co);
}
+ else
+ VecSubf(t1, d->subco[u].co, base->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(v < 0) {
+ v = multires_index_at_loc(d->face_index, d->x, d->y - 1, d, &d->edges_primary);
+ VecSubf(t2, base->co, d->subco[v].co);
}
+ else
+ VecSubf(t2, d->subco[v].co, base->co);
- /* 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;
- }
+ //printf("uu=%d, vv=%d\n", u, v);
+
+ Normalize(t1);
+ Normalize(t2);
+ Mat3FromColVecs(mat, t1, t2, norm);
+
+ if(d->invert) {
+ Mat3Inv(inv, mat);
+ Mat3CpyMat3(mat, inv);
}
+}
- /* 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;
- }
+static void multires_displace(MultiresDisplacer *d, float co[3])
+{
+ float disp[3], mat[3][3];
+ float *data;
+ MVert *subco = &d->subco[d->subco_index];
- 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;
- }
+ if(!d->grid || !d->grid->disps) return;
- 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);
- }
+ data = d->grid->disps[(d->y * d->spacing) * d->disp_st + (d->x * d->spacing)];
+
+ if(d->invert)
+ VecSubf(disp, co, subco->co);
+ else
+ VecCopyf(disp, data);
- /* 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);
+ /* Apply ts matrix to displacement */
+ calc_disp_mat(d, mat);
+ Mat3MulVecfl(mat, disp);
- pr_lvl= pr_lvl->next;
- cr_lvl= cr_lvl->next;
+ if(d->invert) {
+ VecCopyf(data, disp);
+
+ }
+ else {
+ if(d->type == 4 || d->type == 5)
+ VecMulf(disp, d->weight);
+ VecAddf(co, co, disp);
}
- if(pr_deltas) MEM_freeN(pr_deltas);
- if(cr_deltas) MEM_freeN(cr_deltas);
+ if(d->type == 2) {
+ if(d->sidendx == 0)
+ d->y -= 1;
+ else if(d->sidendx == 1)
+ d->x += 1;
+ else if(d->sidendx == 2)
+ d->y += 1;
+ else if(d->sidendx == 3)
+ d->x -= 1;
+ }
+ else if(d->type == 3) {
+ if(d->sidendx == 0)
+ d->y -= 1;
+ else if(d->sidendx == 1)
+ d->x += 1;
+ else if(d->sidendx == 2)
+ d->y += 1;
+ else if(d->sidendx == 3)
+ d->x -= 1;
+ }
}
-static void multires_update_faces(Mesh *me, EditMesh *em)
+static void multiresModifier_disp_run(DerivedMesh *dm, MVert *subco, int invert)
{
- 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, &me->mr->fdata, i, 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;
- }
+ const int lvl = MultiresDM_get_lvl(dm);
+ const int gridFaces = multires_side_tot[lvl - 2] - 1;
+ const int edgeSize = multires_side_tot[lvl - 1] - 1;
+ MVert *mvert = CDDM_get_verts(dm);
+ MEdge *medge = MultiresDM_get_mesh(dm)->medge;
+ MFace *mface = MultiresDM_get_mesh(dm)->mface;
+ ListBase *map = MultiresDM_get_vert_face_map(dm);
+ Mesh *me = MultiresDM_get_mesh(dm);
+ MultiresDisplacer d;
+ int i, S, x, y;
+
+ d.subco = subco;
+ d.subco_index = 0;
+
+ for(i = 0; i < me->totface; ++i) {
+ const int numVerts = mface[i].v4 ? 4 : 3;
+
+ /* Center */
+ multires_displacer_init(&d, dm, i, invert);
+ multires_displacer_anchor(&d, 1, 0);
+ multires_displace(&d, mvert->co);
+ ++mvert;
+ ++d.subco_index;
+
+ /* Cross */
+ for(S = 0; S < numVerts; ++S) {
+ multires_displacer_anchor(&d, 2, S);
+ for(x = 1; x < gridFaces; ++x) {
+ multires_displace(&d, mvert->co);
+ ++mvert;
+ ++d.subco_index;
}
}
- 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;
+ /* Quarters */
+ for(S = 0; S < numVerts; S++) {
+ multires_displacer_anchor(&d, 3, S);
+ for(y = 1; y < gridFaces; y++) {
+ for(x = 1; x < gridFaces; x++) {
+ multires_displace(&d, mvert->co);
+ ++mvert;
+ ++d.subco_index;
}
+ multires_displacer_jump(&d);
}
}
-
- 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 < me->totedge; ++i) {
+ const MEdge *e = &medge[i];
+ for(x = 1; x < edgeSize; ++x) {
+ IndexNode *n1, *n2;
+ int numFaces = 0;
+ for(n1 = map[e->v1].first; n1; n1 = n1->next) {
+ for(n2 = map[e->v2].first; n2; n2 = n2->next) {
+ if(n1->index == n2->index)
+ ++numFaces;
}
}
-
- 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;
+ multires_displacer_weight(&d, 1.0f / numFaces);
+ /* TODO: Better to have these loops outside the x loop */
+ for(n1 = map[e->v1].first; n1; n1 = n1->next) {
+ for(n2 = map[e->v2].first; n2; n2 = n2->next) {
+ if(n1->index == n2->index) {
+ multires_displacer_init(&d, dm, n1->index, invert);
+ multires_displacer_anchor_edge(&d, e->v1, e->v2, x);
+ multires_displace(&d, mvert->co);
+ }
}
}
-
- lvl= lvl->next;
+ ++mvert;
+ ++d.subco_index;
}
- 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;
+ for(i = 0; i < me->totvert; ++i) {
+ IndexNode *n;
+ multires_displacer_weight(&d, 1.0f / BLI_countlist(&map[i]));
+ for(n = map[i].first; n; n = n->next) {
+ multires_displacer_init(&d, dm, n->index, invert);
+ multires_displacer_anchor_vert(&d, i);
+ multires_displace(&d, mvert->co);
}
+ ++mvert;
+ ++d.subco_index;
}
+
+ if(!invert)
+ CDDM_calc_normals(dm);
}
-void multires_update_levels(Mesh *me, const int render)
+static void multiresModifier_update(DerivedMesh *dm)
{
- EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL;
+ Mesh *me;
+ MDisps *mdisps;
- multires_update_first_level(me, em);
- multires_update_vertices(me, em);
- multires_update_faces(me, em);
- multires_update_colors(me, em);
-}
+ me = MultiresDM_get_mesh(dm);
+ mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
-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);
- }
-}
+ if(mdisps) {
+ const int lvl = MultiresDM_get_lvl(dm);
+ const int totlvl = MultiresDM_get_totlvl(dm);
+
+ if(lvl < totlvl) {
+ /* Propagate disps upwards */
+ DerivedMesh *final, *subco_dm, *orig;
+ MVert *verts_new = NULL, *cur_lvl_orig_verts = NULL;
+ MultiresModifierData mmd;
+ int i;
+
+ orig = CDDM_from_mesh(me, NULL);
+
+ /* Regenerate the current level's vertex coordinates
+ (includes older displacements but not new sculpts) */
+ mmd.totlvl = totlvl;
+ mmd.lvl = lvl;
+ subco_dm = multires_dm_create_from_derived(&mmd, orig, me, 0, 0);
+ cur_lvl_orig_verts = CDDM_get_verts(subco_dm);
-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;
+ /* Subtract the original vertex cos from the new vertex cos */
+ verts_new = CDDM_get_verts(dm);
+ for(i = 0; i < dm->getNumVerts(dm); ++i)
+ VecSubf(verts_new[i].co, verts_new[i].co, cur_lvl_orig_verts[i].co);
+
+ final = multires_subdisp_pre(dm, totlvl - lvl, 0);
+
+ multires_subdisp(orig, me, final, lvl, totlvl, dm->getNumVerts(dm), dm->getNumEdges(dm),
+ dm->getNumFaces(dm), 1);
- n= n->next;
+ subco_dm->release(subco_dm);
+ orig->release(orig);
+ }
+ else
+ multiresModifier_disp_run(dm, MultiresDM_get_subco(dm), 1);
}
- return -1;
}
-static float clamp_component(const float c)
+void multires_mark_as_modified(struct Object *ob)
{
- if(c<0) return 0;
- else if(c>255) return 255;
- else return c;
+ if(ob && ob->derivedFinal) {
+ MultiresDM_mark_as_modified(ob->derivedFinal);
+ }
}
-void multires_to_mcol(MultiresColFace *f, MCol mcol[4])
+void multires_force_update(Object *ob)
{
- 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;
+ if(ob && ob->derivedFinal) {
+ ob->derivedFinal->needsFree =1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal = NULL;
}
}
-void multires_level_to_mesh(Object *ob, Mesh *me, const int render)
+struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, DerivedMesh *dm, Mesh *me,
+ int useRenderParams, int isFinalCalc)
{
- MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+ SubsurfModifierData smd;
+ MultiresSubsurf ms;
+ DerivedMesh *result;
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;
+ ms.mmd = mmd;
+ ms.me = me;
- 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);
+ memset(&smd, 0, sizeof(SubsurfModifierData));
+ smd.levels = smd.renderLevels = mmd->lvl - 1;
+ smd.flags |= eSubsurfModifierFlag_SubsurfUv;
- /* 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;
+ result = subsurf_make_derived_from_derived_with_multires(dm, &smd, &ms, useRenderParams, NULL, isFinalCalc, 0);
+ for(i = 0; i < result->getNumVerts(result); ++i)
+ MultiresDM_get_subco(result)[i] = CDDM_get_verts(result)[i];
+ multiresModifier_disp_run(result, MultiresDM_get_subco(result), 0);
+ MultiresDM_set_update(result, multiresModifier_update);
+
+ return result;
+}
+
+/**** Old Multires code ****
+***************************/
+
+/* 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);
}
-
- /* 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];
+}
+
+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);
}
- } 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];
+
+ while(lvl) {
+ multires_free_level(lvl);
+ lvl= lvl->next;
}
- }
- 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);
+ MEM_freeN(mr->verts);
- /* 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]);
- }
-
+ BLI_freelistN(&mr->levels);
+
+ MEM_freeN(mr);
}
+}
+
+static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface,
+ const int totvert, const int totface)
+{
+ int i,j;
+ IndexNode *node = NULL;
- mesh_update_customdata_pointers(me);
+ (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
+ (*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem");
+ node = *mem;
- 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);
+ /* Find the users */
+ for(i = 0; i < totface; ++i){
+ for(j = 0; j < (mface[i].v[3]?4:3); ++j, ++node) {
+ node->index = i;
+ BLI_addtail(&(*map)[mface[i].v[j]], node);
+ }
+ }
}
-void multires_add_level(Object *ob, Mesh *me, const char subdiv_type)
+static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge,
+ const int totvert, const int totedge)
{
- int i,j, curf, cure;
- MultiresLevel *lvl= NULL;
- MultiApplyData data;
- MVert *oldverts= NULL;
+ int i,j;
+ IndexNode *node = NULL;
+
+ (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map");
+ (*mem) = MEM_callocN(sizeof(IndexNode) * totedge*2, "vert edge map mem");
+ node = *mem;
- 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;
+ /* Find the users */
+ for(i = 0; i < totedge; ++i){
+ for(j = 0; j < 2; ++j, ++node) {
+ node->index = i;
+ BLI_addtail(&(*map)[medge[i].v[j]], node);
+ }
}
- /* Create new face verts */
- for(i=0; i<lvl->prev->totface; ++i) {
- lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i;
+}
+
+static MultiresFace *find_old_face(ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4)
+{
+ IndexNode *n1;
+ int v[4] = {v1, v2, v3, v4}, i, j;
+
+ for(n1 = map[v1].first; n1; n1 = n1->next) {
+ int fnd[4] = {0, 0, 0, 0};
+
+ for(i = 0; i < 4; ++i) {
+ for(j = 0; j < 4; ++j) {
+ if(v[i] == faces[n1->index].v[j])
+ fnd[i] = 1;
+ }
+ }
+
+ if(fnd[0] && fnd[1] && fnd[2] && fnd[3])
+ return &faces[n1->index];
}
- multires_calc_temp_data(lvl->prev);
+ return NULL;
+}
- /* 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");
+static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2)
+{
+ IndexNode *n1, *n2;
- 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;
+ for(n1 = map[v1].first; n1; n1 = n1->next) {
+ for(n2 = map[v2].first; n2; n2 = n2->next) {
+ if(n1->index == n2->index)
+ return &edges[n1->index];
}
}
- /* 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];
+ return NULL;
+}
+
+static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov)
+{
+ int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid;
+ vvmap[dst + mov] = emid;
+
+ if(lvl->next->next) {
+ multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2);
+ multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2);
}
- /* 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;
+}
+
+static void multires_load_old_faces(ListBase **fmap, ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst,
+ int v1, int v2, int v3, int v4, int st2, int st3)
+{
+ int fmid;
+ int emid13, emid14, emid23, emid24;
+
+ if(lvl && lvl->next) {
+ fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid;
+ vvmap[dst] = fmid;
+
+ emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid;
+ emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid;
+ emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid;
+ emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid;
+
+
+ multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 + st3,
+ fmid, v2, emid23, emid24, st2, st3 / 2);
+
+ multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 + st3,
+ emid14, emid24, fmid, v4, st2, st3 / 2);
+
+ multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 - st3,
+ emid13, emid23, v3, fmid, st2, st3 / 2);
+
+ multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 - st3,
+ v1, fmid, emid13, emid14, st2, st3 / 2);
+
+ if(lvl->next->next) {
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3);
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3);
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3);
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3);
}
}
+}
- /* 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);
+/* Loads a multires object stored in the old Multires struct into the new format */
+void multires_load_old(DerivedMesh *dm, Multires *mr)
+{
+ MultiresLevel *lvl, *lvl1;
+ MVert *vsrc, *vdst;
+ int src, dst;
+ int totlvl = MultiresDM_get_totlvl(dm);
+ int st = multires_side_tot[totlvl - 2] - 1;
+ int extedgelen = multires_side_tot[totlvl - 1] - 2;
+ int *vvmap; // inorder for dst, map to src
+ int crossedgelen;
+ int i, j, s, x, totvert, tottri, totquad;
+
+ src = 0;
+ dst = 0;
+ vsrc = mr->verts;
+ vdst = CDDM_get_verts(dm);
+ totvert = dm->getNumVerts(dm);
+ vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap");
+
+ lvl1 = mr->levels.first;
+ /* Load base verts */
+ for(i = 0; i < lvl1->totvert; ++i) {
+ vvmap[totvert - lvl1->totvert + i] = src;
+ ++src;
}
- 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);
+ /* Original edges */
+ dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge;
+ for(i = 0; i < lvl1->totedge; ++i) {
+ int ldst = dst + extedgelen * i;
+ int lsrc = src;
+ lvl = lvl1->next;
+
+ for(j = 2; j <= mr->level_count; ++j) {
+ int base = multires_side_tot[totlvl - j] - 2;
+ int skip = multires_side_tot[totlvl - j + 1] - 1;
+ int st = multires_side_tot[j - 2] - 1;
+
+ for(x = 0; x < st; ++x)
+ vvmap[ldst + base + x * skip] = lsrc + st * i + x;
+
+ lsrc += lvl->totvert - lvl->prev->totvert;
+ lvl = lvl->next;
}
}
- 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;
- }
- }
+ /* Center points */
+ dst = 0;
+ for(i = 0; i < lvl1->totface; ++i) {
+ int sides = lvl1->faces[i].v[3] ? 4 : 3;
+
+ vvmap[dst] = src + lvl1->totedge + i;
+ dst += 1 + sides * (st - 1) * st;
}
- 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);
-}
+ /* The rest is only for level 3 and up */
+ if(lvl1->next && lvl1->next->next) {
+ ListBase **fmap, **emap;
+ IndexNode **fmem, **emem;
-void multires_set_level(Object *ob, Mesh *me, const int render)
-{
- if(me->pv) mesh_pmv_off(ob, me);
+ /* Face edge cross */
+ tottri = totquad = 0;
+ crossedgelen = multires_side_tot[totlvl - 2] - 2;
+ dst = 0;
+ for(i = 0; i < lvl1->totface; ++i) {
+ int sides = lvl1->faces[i].v[3] ? 4 : 3;
- check_colors(me);
- multires_update_levels(me, render);
+ lvl = lvl1->next->next;
+ ++dst;
- 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;
+ for(j = 3; j <= mr->level_count; ++j) {
+ int base = multires_side_tot[totlvl - j] - 2;
+ int skip = multires_side_tot[totlvl - j + 1] - 1;
+ int st = pow(2, j - 2);
+ int st2 = pow(2, j - 3);
+ int lsrc = lvl->prev->totvert;
- multires_level_to_mesh(ob, me, render);
-}
+ /* Skip exterior edge verts */
+ lsrc += lvl1->totedge * st;
-/* 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 * pow(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;
+ /* Skip earlier face edge crosses */
+ lsrc += st2 * (tottri * 3 + totquad * 4);
+
+ for(s = 0; s < sides; ++s) {
+ for(x = 0; x < st2; ++x) {
+ vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc;
+ ++lsrc;
+ }
+ }
+
+ lvl = lvl->next;
}
+
+ dst += sides * (st - 1) * st;
+
+ if(sides == 4) ++totquad;
+ else ++tottri;
+
}
-
- DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ /* calculate vert to edge/face maps for each level (except the last) */
+ fmap = MEM_callocN(sizeof(ListBase*) * (mr->level_count-1), "multires fmap");
+ emap = MEM_callocN(sizeof(ListBase*) * (mr->level_count-1), "multires emap");
+ fmem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires fmem");
+ emem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires emem");
+ lvl = lvl1;
+ for(i = 0; i < mr->level_count - 1; ++i) {
+ create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
+ create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
+ lvl = lvl->next;
+ }
+
+ /* Interior face verts */
+ lvl = lvl1->next->next;
+ dst = 0;
+ for(j = 0; j < lvl1->totface; ++j) {
+ int sides = lvl1->faces[j].v[3] ? 4 : 3;
+ int ldst = dst + 1 + sides * (st - 1);
+
+ for(s = 0; s < sides; ++s) {
+ int st2 = multires_side_tot[totlvl - 2] - 2;
+ int st3 = multires_side_tot[totlvl - 3] - 2;
+ int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
+ int mid = ldst + st2 * st3 + st3;
+ int cv = lvl1->faces[j].v[s];
+ int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1];
+ int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1];
+
+ multires_load_old_faces(fmap, emap, lvl1->next, vvmap, mid,
+ vvmap[dst], cv,
+ find_old_edge(emap[0], lvl1->edges, pv, cv)->mid,
+ find_old_edge(emap[0], lvl1->edges, cv, nv)->mid,
+ st2, st4);
+
+ ldst += (st - 1) * (st - 1);
+ }
+
+
+ dst = ldst;
+ }
+
+ lvl = lvl->next;
+
+ for(i = 0; i < mr->level_count - 1; ++i) {
+ MEM_freeN(fmap[i]);
+ MEM_freeN(fmem[i]);
+ MEM_freeN(emap[i]);
+ MEM_freeN(emem[i]);
+ }
+
+ MEM_freeN(fmap);
+ MEM_freeN(emap);
+ MEM_freeN(fmem);
+ MEM_freeN(emem);
}
+
+ /* Transfer verts */
+ for(i = 0; i < totvert; ++i)
+ VecCopyf(vdst[i].co, vsrc[vvmap[i]].co);
+
+ MEM_freeN(vvmap);
}