2007-12-29 17:07:55 +00:00
|
|
|
/*
|
|
|
|
|
* $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"
|
2009-01-06 18:59:03 +00:00
|
|
|
#include "DNA_modifier_types.h"
|
2007-12-29 17:07:55 +00:00
|
|
|
#include "DNA_object_types.h"
|
2009-01-06 18:59:03 +00:00
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_view3d_types.h"
|
2007-12-29 17:07:55 +00:00
|
|
|
|
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
#include "BKE_cdderivedmesh.h"
|
2007-12-29 17:07:55 +00:00
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
#include "BKE_depsgraph.h"
|
2009-01-06 18:59:03 +00:00
|
|
|
#include "BKE_DerivedMesh.h"
|
2007-12-29 17:07:55 +00:00
|
|
|
#include "BKE_global.h"
|
2009-01-04 14:14:06 +00:00
|
|
|
#include "BKE_mesh.h"
|
2009-01-06 18:59:03 +00:00
|
|
|
#include "BKE_modifier.h"
|
2007-12-29 17:07:55 +00:00
|
|
|
#include "BKE_multires.h"
|
2009-01-06 18:59:03 +00:00
|
|
|
#include "BKE_object.h"
|
|
|
|
|
#include "BKE_subsurf.h"
|
2007-12-29 17:07:55 +00:00
|
|
|
|
|
|
|
|
#include <math.h>
|
2009-01-06 18:59:03 +00:00
|
|
|
#include <string.h>
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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};
|
|
|
|
|
|
2009-05-23 07:12:55 +00:00
|
|
|
MultiresModifierData *find_multires_modifier(Object *ob)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-05-23 07:12:55 +00:00
|
|
|
ModifierData *md;
|
2009-01-06 18:59:03 +00:00
|
|
|
MultiresModifierData *mmd = NULL;
|
|
|
|
|
|
|
|
|
|
for(md = ob->modifiers.first; md; md = md->next) {
|
2009-05-23 07:12:55 +00:00
|
|
|
if(md->type == eModifierType_Multires) {
|
2009-01-06 18:59:03 +00:00
|
|
|
mmd = (MultiresModifierData*)md;
|
2009-05-23 07:12:55 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-05-23 07:12:55 +00:00
|
|
|
return mmd;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int multiresModifier_switch_level(Object *ob, const int distance)
|
|
|
|
|
{
|
|
|
|
|
MultiresModifierData *mmd = find_multires_modifier(ob);
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(mmd) {
|
|
|
|
|
mmd->lvl += distance;
|
|
|
|
|
if(mmd->lvl < 1) mmd->lvl = 1;
|
|
|
|
|
else if(mmd->lvl > mmd->totlvl) mmd->lvl = mmd->totlvl;
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
/* XXX: DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
2009-01-06 18:59:03 +00:00
|
|
|
object_handle_update(ob);*/
|
|
|
|
|
return 1;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
else
|
|
|
|
|
return 0;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* XXX */
|
|
|
|
|
#if 0
|
|
|
|
|
void multiresModifier_join(Object *ob)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
Base *base = NULL;
|
|
|
|
|
int highest_lvl = 0;
|
|
|
|
|
|
|
|
|
|
/* First find the highest level of subdivision */
|
|
|
|
|
base = FIRSTBASE;
|
|
|
|
|
while(base) {
|
2009-07-19 00:49:44 +00:00
|
|
|
if(TESTBASELIB_BGMODE(v3d, base) && base->object->type==OB_MESH) {
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
base = base->next;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* No multires meshes selected */
|
|
|
|
|
if(highest_lvl == 0)
|
|
|
|
|
return;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Subdivide all the displacements to the highest level */
|
|
|
|
|
base = FIRSTBASE;
|
|
|
|
|
while(base) {
|
2009-07-19 00:49:44 +00:00
|
|
|
if(TESTBASELIB_BGMODE(v3d, base) && base->object->type==OB_MESH) {
|
2009-01-06 18:59:03 +00:00
|
|
|
ModifierData *md = NULL;
|
|
|
|
|
MultiresModifierData *mmd = NULL;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
for(md = base->object->modifiers.first; md; md = md->next) {
|
|
|
|
|
if(md->type == eModifierType_Multires)
|
|
|
|
|
mmd = (MultiresModifierData*)md;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(mmd)
|
|
|
|
|
multiresModifier_subdivide(mmd, base->object, highest_lvl - mmd->totlvl, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
base = base->next;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
#endif
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Returns 0 on success, 1 if the src's totvert doesn't match */
|
|
|
|
|
int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
Mesh *src_me = get_mesh(src);
|
|
|
|
|
DerivedMesh *mrdm = dst->derivedFinal;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(mrdm && mrdm->getNumVerts(mrdm) == src_me->totvert) {
|
|
|
|
|
MVert *mvert = CDDM_get_verts(mrdm);
|
|
|
|
|
int i;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
for(i = 0; i < src_me->totvert; ++i)
|
|
|
|
|
VecCopyf(mvert[i].co, src_me->mvert[i].co);
|
|
|
|
|
mrdm->needsFree = 1;
|
2009-06-07 18:09:22 +00:00
|
|
|
MultiresDM_mark_as_modified(mrdm);
|
2009-01-06 18:59:03 +00:00
|
|
|
mrdm->release(mrdm);
|
|
|
|
|
dst->derivedFinal = NULL;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
return 0;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
return 1;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void Mat3FromColVecs(float mat[][3], float v1[3], float v2[3], float v3[3])
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
VecCopyf(mat[0], v1);
|
|
|
|
|
VecCopyf(mat[1], v2);
|
|
|
|
|
VecCopyf(mat[2], v3);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static DerivedMesh *multires_subdisp_pre(DerivedMesh *mrdm, int distance, int simple)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void VecAddUf(float a[3], float b[3])
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
a[0] += b[0];
|
|
|
|
|
a[1] += b[1];
|
|
|
|
|
a[2] += b[2];
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-20 17:37:38 +00:00
|
|
|
static void multires_subdisp(DerivedMesh *orig, Object *ob, DerivedMesh *final, int lvl, int totlvl,
|
2009-01-06 18:59:03 +00:00
|
|
|
int totsubvert, int totsubedge, int totsubface, int addverts)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
DerivedMesh *mrdm;
|
2009-08-20 17:37:38 +00:00
|
|
|
Mesh *me = ob->data;
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
|
2009-08-14 01:48:05 +00:00
|
|
|
memset(&mmd_sub, 0, sizeof(MultiresModifierData));
|
2009-01-06 18:59:03 +00:00
|
|
|
mmd_sub.lvl = mmd_sub.totlvl = totlvl;
|
2009-08-21 18:15:50 +00:00
|
|
|
mrdm = multires_dm_create_from_derived(&mmd_sub, 1, orig, ob, 0, 0);
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2009-02-19 16:22:07 +00:00
|
|
|
int x, y, x2, y2, mov= 0;
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Main face verts */
|
|
|
|
|
for(k = 0; k < 4; ++k) {
|
2009-02-19 16:22:07 +00:00
|
|
|
int movx= 0, movy= 0;
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* update face center verts */
|
|
|
|
|
VecAddUf(mvd_f2->co, mvs_f2->co);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
mvd_f2 += 1;
|
|
|
|
|
mvs_f2 += 1;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* update face edge verts */
|
|
|
|
|
for(j = 0; j < end; ++j) {
|
|
|
|
|
MVert *restore;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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++;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
for(k = 0; k < skip - 1; ++k) {
|
|
|
|
|
VecAddUf(mvd_e1->co, mvs_e1->co);
|
|
|
|
|
mvd_e1++;
|
|
|
|
|
mvs_e1++;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-20 17:37:38 +00:00
|
|
|
final->needsFree = 1;
|
2009-01-06 18:59:03 +00:00
|
|
|
final->release(final);
|
|
|
|
|
mrdm->needsFree = 1;
|
2009-06-07 18:09:22 +00:00
|
|
|
MultiresDM_mark_as_modified(mrdm);
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
MEM_freeN(mdisps[i].disps);
|
|
|
|
|
mdisps[i].disps = disps;
|
|
|
|
|
mdisps[i].totdisp = totdisp;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
mmd->totlvl = mmd->lvl;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int distance, int updateblock, int simple)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
DerivedMesh *final = NULL;
|
2009-01-23 20:36:47 +00:00
|
|
|
int totsubvert = 0, totsubface = 0, totsubedge = 0;
|
2009-01-06 18:59:03 +00:00
|
|
|
Mesh *me = get_mesh(ob);
|
|
|
|
|
MDisps *mdisps;
|
2007-12-29 17:07:55 +00:00
|
|
|
int i;
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(distance == 0)
|
|
|
|
|
return;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(mmd->totlvl > multires_max_levels)
|
|
|
|
|
mmd->totlvl = multires_max_levels;
|
|
|
|
|
if(mmd->lvl > multires_max_levels)
|
|
|
|
|
mmd->lvl = multires_max_levels;
|
|
|
|
|
|
|
|
|
|
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);
|
2009-08-14 01:48:05 +00:00
|
|
|
memset(&mmd_sub, 0, sizeof(MultiresModifierData));
|
2009-01-06 18:59:03 +00:00
|
|
|
mmd_sub.lvl = mmd_sub.totlvl = mmd->lvl;
|
2009-08-21 18:35:40 +00:00
|
|
|
mmd_sub.simple = simple;
|
2009-08-21 18:15:50 +00:00
|
|
|
mrdm = multires_dm_create_from_derived(&mmd_sub, 1, orig, ob, 0, 0);
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
if(final) {
|
|
|
|
|
DerivedMesh *orig;
|
|
|
|
|
|
|
|
|
|
orig = CDDM_from_mesh(me, NULL);
|
|
|
|
|
|
2009-08-20 17:37:38 +00:00
|
|
|
multires_subdisp(orig, ob, final, mmd->lvl, mmd->totlvl, totsubvert, totsubedge, totsubface, 0);
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
orig->needsFree = 1;
|
|
|
|
|
orig->release(orig);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
mmd->lvl = mmd->totlvl;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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];
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Neighboring edges for current face */
|
|
|
|
|
DisplacerEdges edges_primary;
|
|
|
|
|
|
|
|
|
|
/* Neighboring faces */
|
|
|
|
|
DisplacerSpill spill_x, spill_y;
|
|
|
|
|
|
|
|
|
|
int *face_offsets;
|
|
|
|
|
|
|
|
|
|
int x, y, ax, ay;
|
|
|
|
|
} MultiresDisplacer;
|
|
|
|
|
|
|
|
|
|
static int mface_v(MFace *f, int v)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
return v == 0 ? f->v1 : v == 1 ? f->v2 : v == 2 ? f->v3 : v == 3 ? f->v4 : -1;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
for(i = 0; i < end; ++i) {
|
|
|
|
|
int vcur = mface_v(f, i);
|
|
|
|
|
int vnext = mface_v(f, i == end - 1 ? 0 : i + 1);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
de->dir[i] = 1;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
de->base[i] += offset;
|
|
|
|
|
break;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Returns in out the corners [0-3] that use v1 and v2 */
|
2009-09-14 16:52:06 +00:00
|
|
|
static void find_face_corners(MFace *f, int v1, int v2, int out[2])
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_get_spill_faces(MultiresDisplacer *d, DerivedMesh *dm, MFace *mface)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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]);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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]);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void find_corner_valences(MultiresDisplacer *d, DerivedMesh *dm)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
d->valence[3] = -1;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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)]);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_init(MultiresDisplacer *d, DerivedMesh *dm,
|
|
|
|
|
const int face_index, const int invert)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_weight(MultiresDisplacer *d, const float w)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
d->weight = w;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_anchor(MultiresDisplacer *d, const int type, const int side_index)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
d->ax = d->x;
|
|
|
|
|
d->ay = d->y;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_anchor_edge(MultiresDisplacer *d, int v1, int v2, int x)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_anchor_vert(MultiresDisplacer *d, const int v)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
const int e = d->sidetot - 1;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
d->type = 5;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displacer_jump(MultiresDisplacer *d)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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])
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
//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);
|
2008-10-08 18:35:41 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
else
|
|
|
|
|
VecSubf(t1, d->subco[u].co, base->co);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
else
|
|
|
|
|
VecSubf(t2, d->subco[v].co, base->co);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
//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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_displace(MultiresDisplacer *d, float co[3])
|
|
|
|
|
{
|
|
|
|
|
float disp[3], mat[3][3];
|
|
|
|
|
float *data;
|
|
|
|
|
MVert *subco = &d->subco[d->subco_index];
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(!d->grid || !d->grid->disps) return;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Apply ts matrix to displacement */
|
|
|
|
|
calc_disp_mat(d, mat);
|
|
|
|
|
Mat3MulVecfl(mat, disp);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(d->invert) {
|
|
|
|
|
VecCopyf(data, disp);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if(d->type == 4 || d->type == 5)
|
|
|
|
|
VecMulf(disp, d->weight);
|
|
|
|
|
VecAddf(co, co, disp);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multiresModifier_disp_run(DerivedMesh *dm, MVert *subco, int invert)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
++mvert;
|
|
|
|
|
++d.subco_index;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(!invert)
|
|
|
|
|
CDDM_calc_normals(dm);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multiresModifier_update(DerivedMesh *dm)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-08-20 17:37:38 +00:00
|
|
|
Object *ob;
|
2009-01-06 18:59:03 +00:00
|
|
|
Mesh *me;
|
|
|
|
|
MDisps *mdisps;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-08-20 17:37:38 +00:00
|
|
|
ob = MultiresDM_get_object(dm);
|
2009-01-06 18:59:03 +00:00
|
|
|
me = MultiresDM_get_mesh(dm);
|
|
|
|
|
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(mdisps) {
|
|
|
|
|
const int lvl = MultiresDM_get_lvl(dm);
|
|
|
|
|
const int totlvl = MultiresDM_get_totlvl(dm);
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2009-08-21 18:15:50 +00:00
|
|
|
subco_dm = multires_dm_create_from_derived(&mmd, 1, orig, ob, 0, 0);
|
2009-01-06 18:59:03 +00:00
|
|
|
cur_lvl_orig_verts = CDDM_get_verts(subco_dm);
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
2009-08-20 17:37:38 +00:00
|
|
|
multires_subdisp(orig, ob, final, lvl, totlvl, dm->getNumVerts(dm), dm->getNumEdges(dm),
|
2009-01-06 18:59:03 +00:00
|
|
|
dm->getNumFaces(dm), 1);
|
|
|
|
|
|
|
|
|
|
subco_dm->release(subco_dm);
|
|
|
|
|
orig->release(orig);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
else
|
|
|
|
|
multiresModifier_disp_run(dm, MultiresDM_get_subco(dm), 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-07 18:09:22 +00:00
|
|
|
void multires_mark_as_modified(struct Object *ob)
|
|
|
|
|
{
|
|
|
|
|
if(ob && ob->derivedFinal) {
|
|
|
|
|
MultiresDM_mark_as_modified(ob->derivedFinal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
void multires_force_update(Object *ob)
|
|
|
|
|
{
|
2009-02-05 01:12:47 +00:00
|
|
|
if(ob && ob->derivedFinal) {
|
2009-01-06 18:59:03 +00:00
|
|
|
ob->derivedFinal->needsFree =1;
|
|
|
|
|
ob->derivedFinal->release(ob->derivedFinal);
|
|
|
|
|
ob->derivedFinal = NULL;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-21 18:15:50 +00:00
|
|
|
struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
|
2009-01-06 18:59:03 +00:00
|
|
|
int useRenderParams, int isFinalCalc)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
SubsurfModifierData smd;
|
|
|
|
|
MultiresSubsurf ms;
|
|
|
|
|
DerivedMesh *result;
|
|
|
|
|
int i;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
ms.mmd = mmd;
|
2009-08-20 17:37:38 +00:00
|
|
|
ms.ob = ob;
|
2009-08-21 18:15:50 +00:00
|
|
|
ms.local_mmd = local_mmd;
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
memset(&smd, 0, sizeof(SubsurfModifierData));
|
|
|
|
|
smd.levels = smd.renderLevels = mmd->lvl - 1;
|
|
|
|
|
smd.flags |= eSubsurfModifierFlag_SubsurfUv;
|
|
|
|
|
|
|
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/**** Old Multires code ****
|
|
|
|
|
***************************/
|
|
|
|
|
|
|
|
|
|
/* Does not actually free lvl itself */
|
2009-09-14 16:52:06 +00:00
|
|
|
static void multires_free_level(MultiresLevel *lvl)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
if(lvl) {
|
|
|
|
|
if(lvl->faces) MEM_freeN(lvl->faces);
|
|
|
|
|
if(lvl->edges) MEM_freeN(lvl->edges);
|
|
|
|
|
if(lvl->colfaces) MEM_freeN(lvl->colfaces);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
void multires_free(Multires *mr)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2009-06-21 02:51:42 +00:00
|
|
|
if(mr->edge_flags)
|
|
|
|
|
MEM_freeN(mr->edge_flags);
|
|
|
|
|
if(mr->edge_creases)
|
|
|
|
|
MEM_freeN(mr->edge_creases);
|
2009-01-06 18:59:03 +00:00
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
while(lvl) {
|
|
|
|
|
multires_free_level(lvl);
|
|
|
|
|
lvl= lvl->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(mr->verts);
|
|
|
|
|
|
|
|
|
|
BLI_freelistN(&mr->levels);
|
|
|
|
|
|
|
|
|
|
MEM_freeN(mr);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface,
|
|
|
|
|
const int totvert, const int totface)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
int i,j;
|
|
|
|
|
IndexNode *node = NULL;
|
|
|
|
|
|
|
|
|
|
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
|
|
|
|
|
(*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem");
|
|
|
|
|
node = *mem;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge,
|
|
|
|
|
const int totvert, const int totedge)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static MultiresFace *find_old_face(ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
IndexNode *n1;
|
|
|
|
|
int v[4] = {v1, v2, v3, v4}, i, j;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
for(n1 = map[v1].first; n1; n1 = n1->next) {
|
|
|
|
|
int fnd[4] = {0, 0, 0, 0};
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
for(i = 0; i < 4; ++i) {
|
|
|
|
|
for(j = 0; j < 4; ++j) {
|
|
|
|
|
if(v[i] == faces[n1->index].v[j])
|
|
|
|
|
fnd[i] = 1;
|
|
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
if(fnd[0] && fnd[1] && fnd[2] && fnd[3])
|
|
|
|
|
return &faces[n1->index];
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2)
|
|
|
|
|
{
|
|
|
|
|
IndexNode *n1, *n2;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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];
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
return NULL;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov)
|
2007-12-29 17:07:55 +00:00
|
|
|
{
|
2009-01-06 18:59:03 +00:00
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
if(lvl && lvl->next) {
|
|
|
|
|
fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid;
|
|
|
|
|
vvmap[dst] = fmid;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
}
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* The rest is only for level 3 and up */
|
|
|
|
|
if(lvl1->next && lvl1->next->next) {
|
|
|
|
|
ListBase **fmap, **emap;
|
|
|
|
|
IndexNode **fmem, **emem;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
lvl = lvl1->next->next;
|
|
|
|
|
++dst;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
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;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* Skip exterior edge verts */
|
|
|
|
|
lsrc += lvl1->totedge * st;
|
2007-12-29 17:07:55 +00:00
|
|
|
|
2009-01-06 18:59:03 +00:00
|
|
|
/* 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;
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
dst += sides * (st - 1) * st;
|
|
|
|
|
|
|
|
|
|
if(sides == 4) ++totquad;
|
|
|
|
|
else ++tottri;
|
|
|
|
|
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
/* 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);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|
2009-01-06 18:59:03 +00:00
|
|
|
|
|
|
|
|
/* Transfer verts */
|
|
|
|
|
for(i = 0; i < totvert; ++i)
|
|
|
|
|
VecCopyf(vdst[i].co, vsrc[vvmap[i]].co);
|
|
|
|
|
|
|
|
|
|
MEM_freeN(vvmap);
|
2007-12-29 17:07:55 +00:00
|
|
|
}
|