2010-04-11 22:12:30 +00:00
|
|
|
/*
|
2011-10-23 17:52:20 +00:00
|
|
|
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
2012-05-26 09:39:04 +00:00
|
|
|
* Contributor(s): Campbell Barton
|
|
|
|
* Shinsuke Irie
|
2014-08-15 17:26:39 +10:00
|
|
|
* Martin Felke
|
2011-10-23 17:52:20 +00:00
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
*/
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2011-02-25 13:57:17 +00:00
|
|
|
/** \file blender/modifiers/intern/MOD_solidify.c
|
|
|
|
* \ingroup modifiers
|
|
|
|
*/
|
|
|
|
|
2013-02-26 14:32:53 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
2010-04-12 22:33:43 +00:00
|
|
|
#include "DNA_meshdata_types.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2011-12-28 09:47:24 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2011-05-09 04:06:48 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2014-06-25 00:01:10 +10:00
|
|
|
#include "BLI_stackdefines.h"
|
2014-01-16 17:46:32 +06:00
|
|
|
#include "BLI_bitmap.h"
|
2010-04-12 00:36:50 +00:00
|
|
|
#include "BLI_math.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
#include "BKE_cdderivedmesh.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_particle.h"
|
|
|
|
#include "BKE_deform.h"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
#include "MOD_modifiertypes.h"
|
2011-07-11 09:15:20 +00:00
|
|
|
#include "MOD_util.h"
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
#ifdef __GNUC__
|
|
|
|
# pragma GCC diagnostic error "-Wsign-conversion"
|
|
|
|
#endif
|
|
|
|
|
2013-06-12 10:03:13 +00:00
|
|
|
/* skip shell thickness for non-manifold edges, see [#35710] */
|
|
|
|
#define USE_NONMANIFOLD_WORKAROUND
|
|
|
|
|
2012-05-26 09:18:47 +00:00
|
|
|
/* *** derived mesh high quality normal calculation function *** */
|
|
|
|
/* could be exposed for other functions to use */
|
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
typedef struct EdgeFaceRef {
|
|
|
|
int f1; /* init as -1 */
|
|
|
|
int f2;
|
|
|
|
} EdgeFaceRef;
|
|
|
|
|
2013-06-12 07:16:13 +00:00
|
|
|
BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
|
|
|
|
{
|
2013-06-12 08:24:31 +00:00
|
|
|
return !((edge_ref->f1 == 0) && (edge_ref->f2 == 0));
|
2013-06-12 07:16:13 +00:00
|
|
|
}
|
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
/**
|
|
|
|
* \param dm Mesh to calculate normals for.
|
|
|
|
* \param face_nors Precalculated face normals.
|
|
|
|
* \param r_vert_nors Return vert normals.
|
|
|
|
*/
|
|
|
|
static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_vert_nors)[3])
|
2010-04-11 22:12:30 +00:00
|
|
|
{
|
|
|
|
int i, numVerts, numEdges, numFaces;
|
2011-04-03 00:25:01 +00:00
|
|
|
MPoly *mpoly, *mp;
|
|
|
|
MLoop *mloop, *ml;
|
2013-06-12 07:16:13 +00:00
|
|
|
MEdge *medge, *ed;
|
2010-04-11 22:12:30 +00:00
|
|
|
MVert *mvert, *mv;
|
|
|
|
|
|
|
|
numVerts = dm->getNumVerts(dm);
|
|
|
|
numEdges = dm->getNumEdges(dm);
|
2011-11-29 13:01:51 +00:00
|
|
|
numFaces = dm->getNumPolys(dm);
|
2012-01-23 21:04:56 +00:00
|
|
|
mpoly = dm->getPolyArray(dm);
|
2013-06-12 07:16:13 +00:00
|
|
|
medge = dm->getEdgeArray(dm);
|
2010-04-11 22:12:30 +00:00
|
|
|
mvert = dm->getVertArray(dm);
|
2012-01-23 21:04:56 +00:00
|
|
|
mloop = dm->getLoopArray(dm);
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
/* we don't want to overwrite any referenced layers */
|
|
|
|
|
2012-03-09 18:28:30 +00:00
|
|
|
/* Doesn't work here! */
|
|
|
|
#if 0
|
2011-12-19 08:26:53 +00:00
|
|
|
mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
|
2010-04-11 22:12:30 +00:00
|
|
|
cddm->mvert = mv;
|
2012-03-09 18:28:30 +00:00
|
|
|
#endif
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
mv = mvert;
|
2011-04-03 00:25:01 +00:00
|
|
|
mp = mpoly;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
{
|
2013-06-12 06:51:02 +00:00
|
|
|
EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity");
|
2010-04-11 22:12:30 +00:00
|
|
|
EdgeFaceRef *edge_ref;
|
|
|
|
float edge_normal[3];
|
|
|
|
|
2012-05-23 06:39:29 +00:00
|
|
|
/* This loop adds an edge hash if its not there, and adds the face index */
|
2012-03-24 06:24:53 +00:00
|
|
|
for (i = 0; i < numFaces; i++, mp++) {
|
2011-04-03 00:25:01 +00:00
|
|
|
int j;
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2011-04-03 00:25:01 +00:00
|
|
|
ml = mloop + mp->loopstart;
|
2012-05-23 06:39:29 +00:00
|
|
|
|
2013-06-12 07:16:13 +00:00
|
|
|
for (j = 0; j < mp->totloop; j++, ml++) {
|
2012-05-23 06:39:29 +00:00
|
|
|
/* --- add edge ref to face --- */
|
2013-06-12 07:16:13 +00:00
|
|
|
edge_ref = &edge_ref_array[ml->e];
|
|
|
|
if (!edgeref_is_init(edge_ref)) {
|
2012-05-23 06:39:29 +00:00
|
|
|
edge_ref->f1 = i;
|
|
|
|
edge_ref->f2 = -1;
|
|
|
|
}
|
2013-06-12 07:53:54 +00:00
|
|
|
else if ((edge_ref->f1 != -1) && (edge_ref->f2 == -1)) {
|
2012-05-23 06:39:29 +00:00
|
|
|
edge_ref->f2 = i;
|
|
|
|
}
|
2013-06-12 07:53:54 +00:00
|
|
|
else {
|
|
|
|
/* 3+ faces using an edge, we can't handle this usefully */
|
|
|
|
edge_ref->f1 = edge_ref->f2 = -1;
|
2013-06-12 10:03:13 +00:00
|
|
|
#ifdef USE_NONMANIFOLD_WORKAROUND
|
2013-06-12 08:24:31 +00:00
|
|
|
medge[ml->e].flag |= ME_EDGE_TMP_TAG;
|
2013-06-12 10:03:13 +00:00
|
|
|
#endif
|
2013-06-12 07:53:54 +00:00
|
|
|
}
|
2012-05-23 06:39:29 +00:00
|
|
|
/* --- done --- */
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-12 07:16:13 +00:00
|
|
|
for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) {
|
|
|
|
/* Get the edge vert indices, and edge value (the face indices that use it) */
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2013-06-12 07:53:54 +00:00
|
|
|
if (edgeref_is_init(edge_ref) && (edge_ref->f1 != -1)) {
|
|
|
|
if (edge_ref->f2 != -1) {
|
|
|
|
/* We have 2 faces using this edge, calculate the edges normal
|
|
|
|
* using the angle between the 2 faces as a weighting */
|
2013-05-08 14:33:02 +00:00
|
|
|
#if 0
|
2013-06-12 07:53:54 +00:00
|
|
|
add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
|
|
|
|
normalize_v3(edge_normal);
|
2013-05-08 14:33:02 +00:00
|
|
|
|
2013-06-12 07:53:54 +00:00
|
|
|
mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
|
2013-05-08 14:33:02 +00:00
|
|
|
#else
|
2013-06-12 07:53:54 +00:00
|
|
|
mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
|
2013-05-08 14:33:02 +00:00
|
|
|
#endif
|
2013-06-12 07:53:54 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* only one face attached to that edge */
|
|
|
|
/* an edge without another attached- the weight on this is undefined */
|
|
|
|
copy_v3_v3(edge_normal, face_nors[edge_ref->f1]);
|
|
|
|
}
|
2013-06-12 09:35:02 +00:00
|
|
|
add_v3_v3(r_vert_nors[ed->v1], edge_normal);
|
|
|
|
add_v3_v3(r_vert_nors[ed->v2], edge_normal);
|
2012-03-24 06:24:53 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
MEM_freeN(edge_ref_array);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* normalize vertex normals and assign */
|
2012-03-24 06:24:53 +00:00
|
|
|
for (i = 0; i < numVerts; i++, mv++) {
|
2013-06-12 09:35:02 +00:00
|
|
|
if (normalize_v3(r_vert_nors[i]) == 0.0f) {
|
|
|
|
normal_short_to_float_v3(r_vert_nors[i], mv->no);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-23 06:25:31 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
static void initData(ModifierData *md)
|
|
|
|
{
|
2012-05-06 13:38:33 +00:00
|
|
|
SolidifyModifierData *smd = (SolidifyModifierData *) md;
|
2010-04-11 22:12:30 +00:00
|
|
|
smd->offset = 0.01f;
|
2010-07-14 08:24:24 +00:00
|
|
|
smd->offset_fac = -1.0f;
|
2010-04-11 22:12:30 +00:00
|
|
|
smd->flag = MOD_SOLIDIFY_RIM;
|
|
|
|
}
|
2012-05-23 06:25:31 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
static void copyData(ModifierData *md, ModifierData *target)
|
|
|
|
{
|
2013-12-22 04:35:52 +11:00
|
|
|
#if 0
|
2012-05-06 13:38:33 +00:00
|
|
|
SolidifyModifierData *smd = (SolidifyModifierData *) md;
|
|
|
|
SolidifyModifierData *tsmd = (SolidifyModifierData *) target;
|
2013-12-22 04:35:52 +11:00
|
|
|
#endif
|
|
|
|
modifier_copyData_generic(md, target);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2010-10-14 06:29:17 +00:00
|
|
|
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
|
2010-06-03 22:08:14 +00:00
|
|
|
{
|
2012-05-06 13:38:33 +00:00
|
|
|
SolidifyModifierData *smd = (SolidifyModifierData *) md;
|
2010-06-03 22:08:14 +00:00
|
|
|
CustomDataMask dataMask = 0;
|
|
|
|
|
|
|
|
/* ask for vertexgroups if we need them */
|
2012-03-24 06:24:53 +00:00
|
|
|
if (smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
|
2010-06-03 22:08:14 +00:00
|
|
|
|
|
|
|
return dataMask;
|
|
|
|
}
|
|
|
|
|
2012-07-16 23:23:33 +00:00
|
|
|
/* specific function for solidify - define locally */
|
2012-05-26 09:18:47 +00:00
|
|
|
BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
|
|
|
|
{
|
|
|
|
r[0] += (float)a[0] * f;
|
|
|
|
r[1] += (float)a[1] * f;
|
|
|
|
r[2] += (float)a[2] * f;
|
|
|
|
}
|
2010-06-03 22:08:14 +00:00
|
|
|
|
2012-11-09 09:33:28 +00:00
|
|
|
static DerivedMesh *applyModifier(
|
|
|
|
ModifierData *md, Object *ob,
|
|
|
|
DerivedMesh *dm,
|
|
|
|
ModifierApplyFlag UNUSED(flag))
|
2010-04-11 22:12:30 +00:00
|
|
|
{
|
2012-01-19 23:51:40 +00:00
|
|
|
DerivedMesh *result;
|
2012-05-06 13:38:33 +00:00
|
|
|
const SolidifyModifierData *smd = (SolidifyModifierData *) md;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
MVert *mv, *mvert, *orig_mvert;
|
2011-04-03 00:25:01 +00:00
|
|
|
MEdge *ed, *medge, *orig_medge;
|
|
|
|
MLoop *ml, *mloop, *orig_mloop;
|
|
|
|
MPoly *mp, *mpoly, *orig_mpoly;
|
2013-06-12 06:51:02 +00:00
|
|
|
const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm);
|
|
|
|
const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
|
|
|
|
const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm);
|
2013-06-12 09:35:02 +00:00
|
|
|
const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm);
|
2015-02-26 18:44:45 +11:00
|
|
|
unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2011-03-03 05:09:07 +00:00
|
|
|
/* only use material offsets if we have 2 or more materials */
|
2012-05-06 13:38:33 +00:00
|
|
|
const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0;
|
|
|
|
const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
|
|
|
|
const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
|
2011-03-03 05:09:07 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
/* use for edges */
|
2013-06-12 06:20:24 +00:00
|
|
|
/* over-alloc new_vert_arr, old_vert_arr */
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int *new_vert_arr = NULL;
|
2013-06-12 06:20:24 +00:00
|
|
|
STACK_DECLARE(new_vert_arr);
|
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int *new_edge_arr = NULL;
|
2013-06-12 06:20:24 +00:00
|
|
|
STACK_DECLARE(new_edge_arr);
|
|
|
|
|
2013-07-13 05:43:35 +00:00
|
|
|
unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify");
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int *edge_users = NULL;
|
2012-05-06 13:38:33 +00:00
|
|
|
char *edge_order = NULL;
|
2012-05-25 06:54:01 +00:00
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
float (*vert_nors)[3] = NULL;
|
2013-06-12 09:35:02 +00:00
|
|
|
float (*face_nors)[3] = NULL;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN);
|
2012-02-26 18:12:01 +00:00
|
|
|
|
2012-05-22 09:53:33 +00:00
|
|
|
const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
|
2012-05-22 10:10:14 +00:00
|
|
|
const float ofs_new = smd->offset + ofs_orig;
|
2012-05-06 13:38:33 +00:00
|
|
|
const float offset_fac_vg = smd->offset_fac_vg;
|
|
|
|
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
|
2013-03-13 17:31:26 +00:00
|
|
|
const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
|
|
|
|
const bool do_clamp = (smd->offset_clamp != 0.0f);
|
2014-08-15 17:26:39 +10:00
|
|
|
const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* weights */
|
2014-08-20 20:30:45 +10:00
|
|
|
MDeformVert *dvert;
|
2010-10-21 04:21:09 +00:00
|
|
|
const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
|
2011-07-11 09:15:20 +00:00
|
|
|
int defgrp_index;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
/* array size is doubled in case of using a shell */
|
|
|
|
const unsigned int stride = do_shell ? 2 : 1;
|
|
|
|
|
2011-07-11 09:15:20 +00:00
|
|
|
modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
|
2012-01-19 23:51:40 +00:00
|
|
|
|
|
|
|
orig_mvert = dm->getVertArray(dm);
|
|
|
|
orig_medge = dm->getEdgeArray(dm);
|
|
|
|
orig_mloop = dm->getLoopArray(dm);
|
|
|
|
orig_mpoly = dm->getPolyArray(dm);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
if (need_face_normals) {
|
|
|
|
/* calculate only face normals */
|
|
|
|
face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__);
|
|
|
|
BKE_mesh_calc_normals_poly(
|
|
|
|
orig_mvert, (int)numVerts,
|
|
|
|
orig_mloop, orig_mpoly,
|
|
|
|
(int)numLoops, (int)numFaces,
|
|
|
|
face_nors, true);
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:06:22 +10:00
|
|
|
STACK_INIT(new_vert_arr, numVerts * 2);
|
|
|
|
STACK_INIT(new_edge_arr, numEdges * 2);
|
2013-06-12 06:20:24 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (smd->flag & MOD_SOLIDIFY_RIM) {
|
2014-01-17 06:58:09 +11:00
|
|
|
BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int eidx;
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
#define INVALID_UNUSED ((unsigned int)-1)
|
|
|
|
#define INVALID_PAIR ((unsigned int)-2)
|
2012-05-22 09:53:33 +00:00
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__);
|
|
|
|
new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__);
|
2013-06-12 06:20:24 +00:00
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges");
|
|
|
|
edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder");
|
2012-05-22 09:53:33 +00:00
|
|
|
|
2014-01-17 06:58:09 +11:00
|
|
|
|
2012-05-22 09:53:33 +00:00
|
|
|
/* save doing 2 loops here... */
|
|
|
|
#if 0
|
|
|
|
fill_vn_i(edge_users, numEdges, INVALID_UNUSED);
|
|
|
|
#endif
|
|
|
|
|
2013-06-12 07:16:13 +00:00
|
|
|
for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
|
|
|
|
edge_users[eidx] = INVALID_UNUSED;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) {
|
2013-06-15 08:59:54 +00:00
|
|
|
MLoop *ml_prev;
|
2012-10-20 09:56:40 +00:00
|
|
|
int j;
|
|
|
|
|
|
|
|
ml = orig_mloop + mp->loopstart;
|
2013-06-15 08:59:54 +00:00
|
|
|
ml_prev = ml + (mp->totloop - 1);
|
2012-05-22 10:10:14 +00:00
|
|
|
|
2013-06-14 16:10:32 +00:00
|
|
|
for (j = 0; j < mp->totloop; j++, ml++) {
|
2012-05-22 10:10:14 +00:00
|
|
|
/* add edge user */
|
2013-06-15 08:59:54 +00:00
|
|
|
eidx = ml_prev->e;
|
2012-05-22 10:10:14 +00:00
|
|
|
if (edge_users[eidx] == INVALID_UNUSED) {
|
|
|
|
ed = orig_medge + eidx;
|
2013-06-15 08:59:54 +00:00
|
|
|
BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) &&
|
|
|
|
ELEM(ml->v, ed->v1, ed->v2));
|
|
|
|
edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces);
|
2012-05-22 10:10:14 +00:00
|
|
|
edge_order[eidx] = j;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
edge_users[eidx] = INVALID_PAIR;
|
|
|
|
}
|
2013-06-15 08:59:54 +00:00
|
|
|
ml_prev = ml;
|
2012-05-22 10:10:14 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2013-06-12 07:16:13 +00:00
|
|
|
for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
|
2013-06-12 06:51:02 +00:00
|
|
|
if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
|
2014-06-06 16:05:15 +10:00
|
|
|
BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
|
|
|
|
BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
|
2013-06-12 06:20:24 +00:00
|
|
|
STACK_PUSH(new_edge_arr, eidx);
|
2010-04-11 22:12:30 +00:00
|
|
|
newFaces++;
|
2011-04-03 00:25:01 +00:00
|
|
|
newLoops += 4;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-16 17:46:32 +06:00
|
|
|
for (i = 0; i < numVerts; i++) {
|
2014-06-06 16:05:15 +10:00
|
|
|
if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
|
2013-06-12 06:20:24 +00:00
|
|
|
old_vert_arr[i] = STACK_SIZE(new_vert_arr);
|
|
|
|
STACK_PUSH(new_vert_arr, i);
|
2015-02-26 18:44:45 +11:00
|
|
|
rimVerts++;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
2014-08-15 17:26:39 +10:00
|
|
|
else {
|
|
|
|
old_vert_arr[i] = INVALID_UNUSED;
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
2014-01-17 06:58:09 +11:00
|
|
|
|
|
|
|
MEM_freeN(orig_mvert_tag);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2015-02-26 18:44:45 +11:00
|
|
|
if (do_shell == false) {
|
|
|
|
/* only add rim vertices */
|
|
|
|
newVerts = rimVerts;
|
|
|
|
/* each extruded face needs an opposite edge */
|
|
|
|
newEdges = newFaces;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* (stride == 2) in this case, so no need to add newVerts/newEdges */
|
|
|
|
BLI_assert(newVerts == 0);
|
|
|
|
BLI_assert(newEdges == 0);
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
|
2013-06-12 06:51:02 +00:00
|
|
|
vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq");
|
2013-06-12 09:35:02 +00:00
|
|
|
dm_calc_normal(dm, face_nors, vert_nors);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2013-06-12 06:51:02 +00:00
|
|
|
result = CDDM_from_template(dm,
|
2014-08-15 17:26:39 +10:00
|
|
|
(int)((numVerts * stride) + newVerts),
|
2015-02-26 18:44:45 +11:00
|
|
|
(int)((numEdges * stride) + newEdges + rimVerts), 0,
|
2014-08-15 17:26:39 +10:00
|
|
|
(int)((numLoops * stride) + newLoops),
|
|
|
|
(int)((numFaces * stride) + newFaces));
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2011-04-03 00:25:01 +00:00
|
|
|
mpoly = CDDM_get_polys(result);
|
|
|
|
mloop = CDDM_get_loops(result);
|
|
|
|
medge = CDDM_get_edges(result);
|
|
|
|
mvert = CDDM_get_verts(result);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
if (do_shell) {
|
|
|
|
DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
|
|
|
|
DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
|
|
|
|
DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
|
|
|
|
DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);
|
2011-04-03 00:25:01 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
|
|
|
|
DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int i, j;
|
|
|
|
DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
|
|
|
|
for (i = 0, j = (int)numVerts; i < numVerts; i++) {
|
|
|
|
if (old_vert_arr[i] != INVALID_UNUSED) {
|
|
|
|
DM_copy_vert_data(dm, result, i, j, 1);
|
|
|
|
j++;
|
|
|
|
}
|
2012-02-11 21:39:09 +00:00
|
|
|
}
|
2011-03-03 05:09:07 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
|
|
|
|
|
|
|
|
for (i = 0, j = (int)numEdges; i < numEdges; i++) {
|
|
|
|
if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
|
2014-08-18 16:04:44 +10:00
|
|
|
MEdge *ed_src, *ed_dst;
|
2014-08-15 17:26:39 +10:00
|
|
|
DM_copy_edge_data(dm, result, i, j, 1);
|
2012-02-11 21:39:09 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
ed_src = &medge[i];
|
|
|
|
ed_dst = &medge[j];
|
|
|
|
ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
|
|
|
|
ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
|
|
|
|
j++;
|
|
|
|
}
|
2011-04-03 00:25:01 +00:00
|
|
|
}
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
/* will be created later */
|
|
|
|
DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
|
|
|
|
DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef INVALID_UNUSED
|
|
|
|
#undef INVALID_PAIR
|
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
|
|
|
|
/* initializes: (i_end, do_shell_align, mv) */
|
|
|
|
#define INIT_VERT_ARRAY_OFFSETS(test) \
|
|
|
|
if (((ofs_new >= ofs_orig) == do_flip) == test) { \
|
|
|
|
i_end = numVerts; \
|
|
|
|
do_shell_align = true; \
|
|
|
|
mv = mvert; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
if (do_shell) { \
|
|
|
|
i_end = numVerts; \
|
|
|
|
do_shell_align = true; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
i_end = newVerts ; \
|
|
|
|
do_shell_align = false; \
|
|
|
|
} \
|
|
|
|
mv = &mvert[numVerts]; \
|
|
|
|
} (void)0
|
|
|
|
|
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
/* flip normals */
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
if (do_shell) {
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i;
|
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
mp = mpoly + numFaces;
|
|
|
|
for (i = 0; i < dm->numPolyData; i++, mp++) {
|
|
|
|
MLoop *ml2;
|
|
|
|
unsigned int e;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
ml2 = mloop + mp->loopstart + dm->numLoopData;
|
|
|
|
for (j = 0; j < mp->totloop; j++) {
|
|
|
|
CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
|
|
|
|
mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mat_ofs) {
|
|
|
|
mp->mat_nr += mat_ofs;
|
|
|
|
CLAMP(mp->mat_nr, 0, mat_nr_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
e = ml2[0].e;
|
|
|
|
for (j = 0; j < mp->totloop - 1; j++) {
|
|
|
|
ml2[j].e = ml2[j + 1].e;
|
|
|
|
}
|
|
|
|
ml2[mp->totloop - 1].e = e;
|
|
|
|
|
|
|
|
mp->loopstart += dm->numLoopData;
|
|
|
|
|
|
|
|
for (j = 0; j < mp->totloop; j++) {
|
|
|
|
ml2[j].e += numEdges;
|
|
|
|
ml2[j].v += numVerts;
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
|
|
|
|
ed->v1 += numVerts;
|
|
|
|
ed->v2 += numVerts;
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
|
2012-03-24 06:24:53 +00:00
|
|
|
if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
|
2010-04-11 22:12:30 +00:00
|
|
|
/* no even thickness, very simple */
|
|
|
|
float scalar_short;
|
|
|
|
float scalar_short_vgroup;
|
|
|
|
|
2013-03-13 17:31:26 +00:00
|
|
|
/* for clamping */
|
|
|
|
float *vert_lens = NULL;
|
|
|
|
const float offset = fabsf(smd->offset) * smd->offset_clamp;
|
|
|
|
const float offset_sq = offset * offset;
|
|
|
|
|
|
|
|
if (do_clamp) {
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i;
|
|
|
|
|
2014-02-03 02:46:45 +11:00
|
|
|
vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
|
2013-06-12 06:51:02 +00:00
|
|
|
fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
|
2013-03-13 17:31:26 +00:00
|
|
|
for (i = 0; i < numEdges; i++) {
|
2014-02-03 02:46:45 +11:00
|
|
|
const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
|
|
|
|
vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
|
|
|
|
vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
|
2013-03-13 17:31:26 +00:00
|
|
|
}
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (ofs_new != 0.0f) {
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i_orig, i_end;
|
|
|
|
bool do_shell_align;
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
|
2014-08-15 17:26:39 +10:00
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
INIT_VERT_ARRAY_OFFSETS(false);
|
2014-08-15 17:26:39 +10:00
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
|
|
|
|
const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
|
|
|
|
if (dvert) {
|
|
|
|
MDeformVert *dv = &dvert[i];
|
2012-05-06 13:38:33 +00:00
|
|
|
if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
|
|
|
|
else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
|
|
|
|
scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
2013-03-13 17:31:26 +00:00
|
|
|
if (do_clamp) {
|
|
|
|
/* always reset becaise we may have set before */
|
2014-08-20 20:30:45 +10:00
|
|
|
if (dvert == NULL) {
|
2013-03-13 17:31:26 +00:00
|
|
|
scalar_short_vgroup = scalar_short;
|
|
|
|
}
|
|
|
|
if (vert_lens[i] < offset_sq) {
|
|
|
|
float scalar = sqrtf(vert_lens[i]) / offset;
|
|
|
|
scalar_short_vgroup *= scalar;
|
|
|
|
}
|
|
|
|
}
|
2012-05-23 06:32:02 +00:00
|
|
|
madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (ofs_orig != 0.0f) {
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i_orig, i_end;
|
|
|
|
bool do_shell_align;
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
|
2014-08-15 17:26:39 +10:00
|
|
|
|
|
|
|
/* as above but swapped */
|
2014-08-20 20:30:45 +10:00
|
|
|
INIT_VERT_ARRAY_OFFSETS(true);
|
2014-08-15 17:26:39 +10:00
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
|
|
|
|
const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
|
|
|
|
if (dvert) {
|
|
|
|
MDeformVert *dv = &dvert[i];
|
2012-05-06 13:38:33 +00:00
|
|
|
if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
|
|
|
|
else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
|
|
|
|
scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
2013-03-13 17:31:26 +00:00
|
|
|
if (do_clamp) {
|
|
|
|
/* always reset becaise we may have set before */
|
2014-08-20 20:30:45 +10:00
|
|
|
if (dvert == NULL) {
|
2013-03-13 17:31:26 +00:00
|
|
|
scalar_short_vgroup = scalar_short;
|
|
|
|
}
|
|
|
|
if (vert_lens[i] < offset_sq) {
|
|
|
|
float scalar = sqrtf(vert_lens[i]) / offset;
|
|
|
|
scalar_short_vgroup *= scalar;
|
|
|
|
}
|
|
|
|
}
|
2012-05-23 06:32:02 +00:00
|
|
|
madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-13 17:31:26 +00:00
|
|
|
|
|
|
|
if (do_clamp) {
|
|
|
|
MEM_freeN(vert_lens);
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-06-12 10:03:13 +00:00
|
|
|
#ifdef USE_NONMANIFOLD_WORKAROUND
|
2013-06-12 08:24:31 +00:00
|
|
|
const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
|
2013-06-12 10:03:13 +00:00
|
|
|
#endif
|
2010-04-11 22:12:30 +00:00
|
|
|
/* same as EM_solidify() in editmesh_lib.c */
|
2012-05-06 13:38:33 +00:00
|
|
|
float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
|
|
|
|
float *vert_accum = vert_angles + numVerts;
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int vidx;
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
if (vert_nors == NULL) {
|
|
|
|
vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
|
|
|
|
for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
|
2010-04-11 22:12:30 +00:00
|
|
|
normal_short_to_float_v3(vert_nors[i], mv->no);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
for (i = 0, mp = mpoly; i < numFaces; i++, mp++) {
|
2013-05-08 12:56:51 +00:00
|
|
|
/* #BKE_mesh_calc_poly_angles logic is inlined here */
|
2012-05-08 14:58:38 +00:00
|
|
|
float nor_prev[3];
|
|
|
|
float nor_next[3];
|
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
int i_curr = mp->totloop - 1;
|
2012-05-08 14:58:38 +00:00
|
|
|
int i_next = 0;
|
|
|
|
|
|
|
|
ml = &mloop[mp->loopstart];
|
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
|
2012-05-08 14:58:38 +00:00
|
|
|
normalize_v3(nor_prev);
|
|
|
|
|
|
|
|
while (i_next < mp->totloop) {
|
2012-05-07 18:07:34 +00:00
|
|
|
float angle;
|
2013-06-12 09:35:02 +00:00
|
|
|
sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
|
2012-05-08 14:58:38 +00:00
|
|
|
normalize_v3(nor_next);
|
|
|
|
angle = angle_normalized_v3v3(nor_prev, nor_next);
|
2012-05-07 15:45:41 +00:00
|
|
|
|
2012-05-07 18:07:34 +00:00
|
|
|
|
2012-05-08 14:58:38 +00:00
|
|
|
/* --- not related to angle calc --- */
|
2012-05-07 18:07:34 +00:00
|
|
|
if (angle < FLT_EPSILON) {
|
|
|
|
angle = FLT_EPSILON;
|
|
|
|
}
|
2013-06-12 08:24:31 +00:00
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
vidx = ml[i_curr].v;
|
2012-05-07 18:07:34 +00:00
|
|
|
vert_accum[vidx] += angle;
|
2013-06-12 08:24:31 +00:00
|
|
|
|
2013-06-12 10:03:13 +00:00
|
|
|
#ifdef USE_NONMANIFOLD_WORKAROUND
|
2013-06-12 08:24:31 +00:00
|
|
|
/* skip 3+ face user edges */
|
|
|
|
if ((check_non_manifold == false) ||
|
2013-06-12 09:35:02 +00:00
|
|
|
LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
|
2013-06-12 08:24:31 +00:00
|
|
|
((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0)))
|
|
|
|
{
|
2014-04-19 22:12:50 +10:00
|
|
|
vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle;
|
2013-06-12 08:24:31 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
vert_angles[vidx] += angle;
|
|
|
|
}
|
2013-06-12 10:03:13 +00:00
|
|
|
#else
|
2014-04-19 22:12:50 +10:00
|
|
|
vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle;
|
2013-06-12 10:03:13 +00:00
|
|
|
#endif
|
2012-05-08 14:58:38 +00:00
|
|
|
/* --- end non-angle-calc section --- */
|
|
|
|
|
|
|
|
|
|
|
|
/* step */
|
|
|
|
copy_v3_v3(nor_prev, nor_next);
|
2013-06-12 09:35:02 +00:00
|
|
|
i_curr = i_next;
|
2012-05-08 14:58:38 +00:00
|
|
|
i_next++;
|
2011-04-03 00:25:01 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* vertex group support */
|
2012-03-24 06:24:53 +00:00
|
|
|
if (dvert) {
|
2014-08-20 20:30:45 +10:00
|
|
|
MDeformVert *dv = dvert;
|
2011-08-14 06:43:58 +00:00
|
|
|
float scalar;
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (defgrp_invert) {
|
2012-05-06 13:38:33 +00:00
|
|
|
for (i = 0; i < numVerts; i++, dv++) {
|
|
|
|
scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
|
|
|
|
scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
|
2011-08-14 06:43:58 +00:00
|
|
|
vert_angles[i] *= scalar;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-05-06 13:38:33 +00:00
|
|
|
for (i = 0; i < numVerts; i++, dv++) {
|
|
|
|
scalar = defvert_find_weight(dv, defgrp_index);
|
|
|
|
scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
|
2011-08-14 06:43:58 +00:00
|
|
|
vert_angles[i] *= scalar;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-13 17:31:26 +00:00
|
|
|
if (do_clamp) {
|
2015-02-24 18:25:56 +11:00
|
|
|
float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
|
2013-03-13 17:31:26 +00:00
|
|
|
const float offset = fabsf(smd->offset) * smd->offset_clamp;
|
|
|
|
const float offset_sq = offset * offset;
|
2014-02-03 02:46:45 +11:00
|
|
|
fill_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
|
2013-03-13 17:31:26 +00:00
|
|
|
for (i = 0; i < numEdges; i++) {
|
|
|
|
const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
|
2014-02-03 02:46:45 +11:00
|
|
|
vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
|
|
|
|
vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
|
2013-03-13 17:31:26 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < numVerts; i++) {
|
2014-02-03 02:46:45 +11:00
|
|
|
if (vert_lens_sq[i] < offset_sq) {
|
|
|
|
float scalar = sqrtf(vert_lens_sq[i]) / offset;
|
2013-03-13 17:31:26 +00:00
|
|
|
vert_angles[i] *= scalar;
|
|
|
|
}
|
|
|
|
}
|
2014-02-03 02:46:45 +11:00
|
|
|
MEM_freeN(vert_lens_sq);
|
2013-03-13 17:31:26 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
if (ofs_new != 0.0f) {
|
|
|
|
unsigned int i_orig, i_end;
|
|
|
|
bool do_shell_align;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
INIT_VERT_ARRAY_OFFSETS(false);
|
2014-08-15 17:26:39 +10:00
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
|
|
|
|
const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
|
2012-03-24 06:24:53 +00:00
|
|
|
if (vert_accum[i]) { /* zero if unselected */
|
2010-04-11 22:12:30 +00:00
|
|
|
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
if (ofs_orig != 0.0f) {
|
|
|
|
unsigned int i_orig, i_end;
|
|
|
|
bool do_shell_align;
|
2014-08-15 17:26:39 +10:00
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
/* same as above but swapped, intentional use of 'ofs_new' */
|
2014-08-20 20:30:45 +10:00
|
|
|
INIT_VERT_ARRAY_OFFSETS(true);
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2014-08-20 20:30:45 +10:00
|
|
|
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
|
|
|
|
const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
|
2012-03-24 06:24:53 +00:00
|
|
|
if (vert_accum[i]) { /* zero if unselected */
|
2010-04-11 22:12:30 +00:00
|
|
|
madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(vert_angles);
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (vert_nors)
|
2010-04-11 22:12:30 +00:00
|
|
|
MEM_freeN(vert_nors);
|
|
|
|
|
2013-06-12 06:06:19 +00:00
|
|
|
/* must recalculate normals with vgroups since they can displace unevenly [#26888] */
|
|
|
|
if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
|
|
|
|
result->dirty |= DM_DIRTY_NORMALS;
|
|
|
|
}
|
2014-08-15 17:26:39 +10:00
|
|
|
else if (do_shell) {
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i;
|
2013-06-12 06:06:19 +00:00
|
|
|
/* flip vertex normals for copied verts */
|
|
|
|
mv = mvert + numVerts;
|
|
|
|
for (i = 0; i < numVerts; i++, mv++) {
|
|
|
|
negate_v3_short(mv->no);
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (smd->flag & MOD_SOLIDIFY_RIM) {
|
2014-08-20 20:30:45 +10:00
|
|
|
unsigned int i;
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
/* bugger, need to re-calculate the normals for the new edge faces.
|
2012-05-06 13:38:33 +00:00
|
|
|
* This could be done in many ways, but probably the quickest way
|
|
|
|
* is to calculate the average normals for side faces only.
|
2010-04-11 22:12:30 +00:00
|
|
|
* Then blend them with the normals of the edge verts.
|
2012-05-26 09:39:04 +00:00
|
|
|
*
|
2012-05-06 13:38:33 +00:00
|
|
|
* at the moment its easiest to allocate an entire array for every vertex,
|
|
|
|
* even though we only need edge verts - campbell
|
2010-04-11 22:12:30 +00:00
|
|
|
*/
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
#define SOLIDIFY_SIDE_NORMALS
|
|
|
|
|
|
|
|
#ifdef SOLIDIFY_SIDE_NORMALS
|
2013-06-12 06:06:19 +00:00
|
|
|
const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS);
|
2010-04-11 22:12:30 +00:00
|
|
|
/* annoying to allocate these since we only need the edge verts, */
|
2013-06-12 06:06:19 +00:00
|
|
|
float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL;
|
2010-04-11 22:12:30 +00:00
|
|
|
float nor[3];
|
|
|
|
#endif
|
2012-05-06 13:38:33 +00:00
|
|
|
const unsigned char crease_rim = smd->crease_rim * 255.0f;
|
|
|
|
const unsigned char crease_outer = smd->crease_outer * 255.0f;
|
|
|
|
const unsigned char crease_inner = smd->crease_inner * 255.0f;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-05-25 06:54:01 +00:00
|
|
|
int *origindex_edge;
|
|
|
|
int *orig_ed;
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int j;
|
2012-05-25 06:54:01 +00:00
|
|
|
|
2013-02-26 14:32:53 +00:00
|
|
|
if (crease_rim || crease_outer || crease_inner) {
|
|
|
|
result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
|
|
|
|
}
|
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
/* add faces & edges */
|
2012-05-25 06:54:01 +00:00
|
|
|
origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
|
2015-02-26 18:44:45 +11:00
|
|
|
ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */
|
|
|
|
orig_ed = &origindex_edge[(numEdges * stride) + newEdges];
|
|
|
|
for (i = 0; i < rimVerts; i++, ed++, orig_ed++) {
|
2012-05-06 13:38:33 +00:00
|
|
|
ed->v1 = new_vert_arr[i];
|
2014-08-15 17:26:39 +10:00
|
|
|
ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
|
2010-04-11 22:12:30 +00:00
|
|
|
ed->flag |= ME_EDGEDRAW;
|
|
|
|
|
2012-05-25 06:54:01 +00:00
|
|
|
*orig_ed = ORIGINDEX_NONE;
|
2011-09-22 16:57:16 +00:00
|
|
|
|
2012-05-25 06:54:01 +00:00
|
|
|
if (crease_rim) {
|
2012-05-06 13:38:33 +00:00
|
|
|
ed->crease = crease_rim;
|
2012-05-25 06:54:01 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* faces */
|
2014-08-15 17:26:39 +10:00
|
|
|
mp = mpoly + (numFaces * stride);
|
|
|
|
ml = mloop + (numLoops * stride);
|
2011-04-03 00:25:01 +00:00
|
|
|
j = 0;
|
2012-05-06 13:38:33 +00:00
|
|
|
for (i = 0; i < newFaces; i++, mp++) {
|
2013-06-12 06:51:02 +00:00
|
|
|
unsigned int eidx = new_edge_arr[i];
|
|
|
|
unsigned int fidx = edge_users[eidx];
|
|
|
|
int k1, k2;
|
|
|
|
bool flip;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (fidx >= numFaces) {
|
2010-04-11 22:12:30 +00:00
|
|
|
fidx -= numFaces;
|
2013-06-12 06:51:02 +00:00
|
|
|
flip = true;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-06-12 06:51:02 +00:00
|
|
|
flip = false;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
ed = medge + eidx;
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* copy most of the face settings */
|
2014-08-15 17:26:39 +10:00
|
|
|
DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1);
|
|
|
|
mp->loopstart = (int)(j + (numLoops * stride));
|
2011-06-01 19:30:19 +00:00
|
|
|
mp->flag = mpoly[fidx].flag;
|
2012-01-17 13:18:23 +00:00
|
|
|
|
2012-01-17 13:26:59 +00:00
|
|
|
/* notice we use 'mp->totloop' which is later overwritten,
|
|
|
|
* we could lookup the original face but theres no point since this is a copy
|
|
|
|
* and will have the same value, just take care when changing order of assignment */
|
2012-09-25 01:21:21 +00:00
|
|
|
k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */
|
2013-06-12 06:51:02 +00:00
|
|
|
k2 = mpoly[fidx].loopstart + (edge_order[eidx]);
|
2012-01-17 13:26:59 +00:00
|
|
|
|
|
|
|
mp->totloop = 4;
|
2012-01-17 13:18:23 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1);
|
|
|
|
CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1);
|
|
|
|
CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1);
|
|
|
|
CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1);
|
2012-01-17 13:18:23 +00:00
|
|
|
|
2014-03-20 22:56:28 +11:00
|
|
|
if (flip == false) {
|
2011-04-03 00:25:01 +00:00
|
|
|
ml[j].v = ed->v1;
|
|
|
|
ml[j++].e = eidx;
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2011-04-03 00:25:01 +00:00
|
|
|
ml[j].v = ed->v2;
|
2015-02-26 18:44:45 +11:00
|
|
|
ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
|
|
|
|
ml[j++].e = (do_shell ? eidx : i) + numEdges;
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
|
2015-02-26 18:44:45 +11:00
|
|
|
ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-17 13:18:23 +00:00
|
|
|
ml[j].v = ed->v2;
|
|
|
|
ml[j++].e = eidx;
|
|
|
|
|
|
|
|
ml[j].v = ed->v1;
|
2015-02-26 18:44:45 +11:00
|
|
|
ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
|
2011-04-03 00:25:01 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
|
|
|
|
ml[j++].e = (do_shell ? eidx : i) + numEdges;
|
2011-04-03 00:25:01 +00:00
|
|
|
|
2014-08-15 17:26:39 +10:00
|
|
|
ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
|
2015-02-26 18:44:45 +11:00
|
|
|
ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2012-05-25 06:54:01 +00:00
|
|
|
origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
|
|
|
|
origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
|
2012-02-11 21:39:09 +00:00
|
|
|
|
|
|
|
/* use the next material index if option enabled */
|
2012-03-24 06:24:53 +00:00
|
|
|
if (mat_ofs_rim) {
|
2012-02-11 21:39:09 +00:00
|
|
|
mp->mat_nr += mat_ofs_rim;
|
|
|
|
CLAMP(mp->mat_nr, 0, mat_nr_max);
|
|
|
|
}
|
2012-03-24 06:24:53 +00:00
|
|
|
if (crease_outer) {
|
2011-03-06 22:10:33 +00:00
|
|
|
/* crease += crease_outer; without wrapping */
|
2014-08-15 17:26:39 +10:00
|
|
|
char *cr = &(ed->crease);
|
2012-05-06 13:38:33 +00:00
|
|
|
int tcr = *cr + crease_outer;
|
|
|
|
*cr = tcr > 255 ? 255 : tcr;
|
2011-03-06 22:10:33 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
|
2012-03-24 06:24:53 +00:00
|
|
|
if (crease_inner) {
|
2011-03-06 22:10:33 +00:00
|
|
|
/* crease += crease_inner; without wrapping */
|
2014-08-15 17:26:39 +10:00
|
|
|
char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
|
2012-05-03 21:35:04 +00:00
|
|
|
int tcr = *cr + crease_inner;
|
|
|
|
*cr = tcr > 255 ? 255 : tcr;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
#ifdef SOLIDIFY_SIDE_NORMALS
|
2013-06-12 06:06:19 +00:00
|
|
|
if (do_side_normals) {
|
|
|
|
normal_quad_v3(nor,
|
|
|
|
mvert[ml[j - 4].v].co,
|
|
|
|
mvert[ml[j - 3].v].co,
|
|
|
|
mvert[ml[j - 2].v].co,
|
|
|
|
mvert[ml[j - 1].v].co);
|
|
|
|
|
|
|
|
add_v3_v3(edge_vert_nos[ed->v1], nor);
|
|
|
|
add_v3_v3(edge_vert_nos[ed->v2], nor);
|
2012-02-26 18:12:01 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
#endif
|
|
|
|
}
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
#ifdef SOLIDIFY_SIDE_NORMALS
|
2013-06-12 06:06:19 +00:00
|
|
|
if (do_side_normals) {
|
2014-08-15 17:26:39 +10:00
|
|
|
ed = medge + (numEdges * stride);
|
2015-02-26 18:44:45 +11:00
|
|
|
for (i = 0; i < rimVerts; i++, ed++) {
|
2013-06-12 06:06:19 +00:00
|
|
|
float nor_cpy[3];
|
|
|
|
short *nor_short;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
/* note, only the first vertex (lower half of the index) is calculated */
|
|
|
|
normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
|
|
|
|
|
|
|
|
for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
|
|
|
|
nor_short = mvert[*(&ed->v1 + k)].no;
|
|
|
|
normal_short_to_float_v3(nor, nor_short);
|
|
|
|
add_v3_v3(nor, nor_cpy);
|
|
|
|
normalize_v3(nor);
|
|
|
|
normal_float_to_short_v3(nor_short, nor);
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
2013-06-12 06:06:19 +00:00
|
|
|
MEM_freeN(edge_vert_nos);
|
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
#endif
|
|
|
|
|
2013-06-12 06:20:24 +00:00
|
|
|
MEM_freeN(new_vert_arr);
|
|
|
|
MEM_freeN(new_edge_arr);
|
2013-06-12 06:51:02 +00:00
|
|
|
|
2010-04-11 22:12:30 +00:00
|
|
|
MEM_freeN(edge_users);
|
|
|
|
MEM_freeN(edge_order);
|
|
|
|
}
|
|
|
|
|
2011-04-03 00:25:01 +00:00
|
|
|
if (old_vert_arr)
|
|
|
|
MEM_freeN(old_vert_arr);
|
2012-05-26 09:39:04 +00:00
|
|
|
|
2013-06-12 09:35:02 +00:00
|
|
|
if (face_nors)
|
|
|
|
MEM_freeN(face_nors);
|
|
|
|
|
2012-12-05 01:02:41 +00:00
|
|
|
if (numFaces == 0 && numEdges != 0) {
|
|
|
|
modifier_setError(md, "Faces needed for useful output");
|
|
|
|
}
|
|
|
|
|
2011-04-03 00:25:01 +00:00
|
|
|
return result;
|
2010-04-11 22:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef SOLIDIFY_SIDE_NORMALS
|
|
|
|
|
2013-06-12 06:06:19 +00:00
|
|
|
static bool dependsOnNormals(ModifierData *UNUSED(md))
|
2013-06-02 04:09:29 +00:00
|
|
|
{
|
2013-06-12 06:06:19 +00:00
|
|
|
/* even when we calculate our own normals,
|
|
|
|
* the vertex normals are used as a fallback */
|
|
|
|
return true;
|
2013-06-02 04:09:29 +00:00
|
|
|
}
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
ModifierTypeInfo modifierType_Solidify = {
|
|
|
|
/* name */ "Solidify",
|
|
|
|
/* structName */ "SolidifyModifierData",
|
|
|
|
/* structSize */ sizeof(SolidifyModifierData),
|
|
|
|
/* type */ eModifierTypeType_Constructive,
|
|
|
|
|
2012-05-06 13:38:33 +00:00
|
|
|
/* flags */ eModifierTypeFlag_AcceptsMesh |
|
|
|
|
eModifierTypeFlag_AcceptsCVs |
|
|
|
|
eModifierTypeFlag_SupportsMapping |
|
|
|
|
eModifierTypeFlag_SupportsEditmode |
|
|
|
|
eModifierTypeFlag_EnableInEditmode,
|
2010-04-11 22:12:30 +00:00
|
|
|
|
|
|
|
/* copyData */ copyData,
|
2011-02-20 15:48:01 +00:00
|
|
|
/* deformVerts */ NULL,
|
|
|
|
/* deformMatrices */ NULL,
|
|
|
|
/* deformVertsEM */ NULL,
|
|
|
|
/* deformMatricesEM */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
/* applyModifier */ applyModifier,
|
2013-05-02 14:42:05 +00:00
|
|
|
/* applyModifierEM */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
/* initData */ initData,
|
2010-06-03 22:08:14 +00:00
|
|
|
/* requiredDataMask */ requiredDataMask,
|
2011-02-20 15:48:01 +00:00
|
|
|
/* freeData */ NULL,
|
|
|
|
/* isDisabled */ NULL,
|
|
|
|
/* updateDepgraph */ NULL,
|
|
|
|
/* dependsOnTime */ NULL,
|
2013-06-02 04:09:29 +00:00
|
|
|
/* dependsOnNormals */ dependsOnNormals,
|
2011-02-20 15:48:01 +00:00
|
|
|
/* foreachObjectLink */ NULL,
|
2011-08-12 18:11:22 +00:00
|
|
|
/* foreachIDLink */ NULL,
|
|
|
|
/* foreachTexLink */ NULL,
|
2010-04-11 22:12:30 +00:00
|
|
|
};
|