Sculpt Branch:

* Smooth brush works again for multires.
* Optimal Display option for multires modifier, same as subsurf.
This commit is contained in:
Brecht Van Lommel 2009-12-09 13:37:19 +00:00
parent abae1e2ccf
commit 9ea765e5d3
10 changed files with 237 additions and 68 deletions

@ -438,6 +438,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
col.prop(md, "levels", text="Preview")
col.prop(md, "sculpt_levels", text="Sculpt")
col.prop(md, "render_levels", text="Render")
col.prop(md, "optimal_display")
if wide_ui:
col = split.column()
@ -604,7 +605,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
if wide_ui:
col = split.column()
col.label(text="Options:")
col.prop(md, "optimal_draw", text="Optimal Display")
col.prop(md, "optimal_display")
def SURFACE(self, layout, ob, md, wide_ui):
layout.label(text="See Fields panel.")

@ -27,24 +27,22 @@
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_MULTIRES_H
#define BKE_MULTIRES_H
struct DerivedMesh;
struct Mesh;
struct MFace;
struct Multires;
struct MultiresModifierData;
struct Object;
typedef struct MultiresSubsurf {
struct MultiresModifierData *mmd;
struct Object *ob;
int local_mmd;
} MultiresSubsurf;
void multires_mark_as_modified(struct Object *ob);
void multires_force_update(struct Object *ob);
struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*, int local_mmd, struct DerivedMesh*,
struct Object *, int, int);
struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*,
int local_mmd, struct DerivedMesh*, struct Object *, int, int);
struct MultiresModifierData *find_multires_modifier(struct Object *ob);
void multiresModifier_join(struct Object *);
@ -53,7 +51,11 @@ void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object
int updateblock, int simple);
int multiresModifier_reshape(struct MultiresModifierData *mmd, struct Object *dst, struct Object *src);
void multires_stitch_grids(struct Object *);
/* Related to the old multires */
struct Multires;
void multires_load_old(struct DerivedMesh *, struct Multires *);
void multires_free(struct Multires*);
#endif

@ -2228,6 +2228,7 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
VertDataZero(FACE_getCenterData(f));
for (S=0; S<f->numVerts; S++)
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
for (x=0; x<gridSize; x++)
VertDataZero(FACE_getIECo(f, lvl, S, x));
@ -2237,16 +2238,21 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
CCGEdge *prevE = FACE_getEdges(f)[prevS];
VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
for (x=1; x<gridSize-1; x++) {
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
if (FACE_getEdges(f)[prevS]->flags&Edge_eEffected)
VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x));
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
if (FACE_getEdges(f)[prevS]->flags&Edge_eEffected)
if(x != 0)
VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
}
@ -2276,6 +2282,7 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
for (S=0; S<f->numVerts; S++)
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
for (x=1; x<gridSize-1; x++)
VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f);

@ -39,6 +39,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_pbvh.h"
#include "BKE_btex.h"
#include "BKE_cdderivedmesh.h"
@ -60,8 +61,8 @@
/* MULTIRES MODIFIER */
static const int multires_max_levels = 13;
static const int multires_grid_tot[] = {1, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
static const int multires_side_tot[] = {1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
static const int multires_side_tot[] = {0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
@ -307,7 +308,7 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0);
}
static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple)
static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal)
{
SubsurfModifierData smd;
@ -316,6 +317,8 @@ static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl
smd.flags |= eSubsurfModifierFlag_SubsurfUv;
if(simple)
smd.subdivType = ME_SIMPLE_SUBSURF;
if(optimal)
smd.flags |= eSubsurfModifierFlag_ControlEdges;
return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0);
}
@ -363,7 +366,7 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me, NULL);
highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple);
highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0);
/* create multires DM from original mesh at low level */
lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple);
@ -551,7 +554,7 @@ static void multiresModifier_update(DerivedMesh *dm)
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me, NULL);
highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple);
highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0);
/* create multires DM from original mesh and displacements */
lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple);
@ -602,7 +605,7 @@ static void multiresModifier_update(DerivedMesh *dm)
DerivedMesh *cddm, *subdm;
cddm = CDDM_from_mesh(me, NULL);
subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple);
subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0);
cddm->release(cddm);
multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
@ -629,6 +632,25 @@ void multires_force_update(Object *ob)
}
}
void multires_stitch_grids(Object *ob)
{
/* utility for smooth brush */
if(ob && ob->derivedFinal) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)ob->derivedFinal;
CCGFace **faces;
int totface;
if(ccgdm->pbvh) {
BLI_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void***)&faces, &totface);
if(totface) {
ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
MEM_freeN(faces);
}
}
}
}
struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
int useRenderParams, int isFinalCalc)
{
@ -642,7 +664,8 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i
if(lvl == 0)
return dm;
result = subsurf_dm_create_local(ob, dm, lvl, 0);
result = subsurf_dm_create_local(ob, dm, lvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges);
if(!local_mmd) {
ccgdm = (CCGDerivedMesh*)result;
@ -680,6 +703,36 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i
/**** Old Multires code ****
***************************/
#if 0
static void mdisp_copy_grid(float (*new)[3], int newstride, float (*old)[3], int oldstride, int xoff, int yoff, int xsize, int ysize)
{
int x, y;
for(y = 0; y < ysize; ++y)
for(x = 0; x < xsize; ++x)
copy_v3_v3(disps[x + y*side], mdisp->disps[(x + xoffs) + (y + yoffs)*oldside]);
}
static void mdisps_convert(MFace *mface, MDisps *mdisp, int lvl)
{
int side = multires_side_tot[lvl];
int nvert = (mface->v4)? 4: 3;
int totdisp = multires_grid_tot[lvl]*nvert;
int x, y;
float (*disps)[3];
disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
static const int multires_max_levels = 13;
static const int multires_grid_tot[] = {1, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
static const int multires_side_tot[] = {1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
}
#endif
/* Does not actually free lvl itself */
static void multires_free_level(MultiresLevel *lvl)
{

@ -1235,7 +1235,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
CCGFace **faces;
int totface;
BLI_pbvh_get_grid_updates(ccgdm->pbvh, (void***)&faces, &totface);
BLI_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void***)&faces, &totface);
if(totface) {
ccgSubSurf_updateFromFaces(ss, 0, faces, totface);
ccgSubSurf_updateNormals(ss, faces, totface);
@ -2155,8 +2155,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids = ccgDM_getNumGrids(dm);
ccgdm->pbvh = BLI_pbvh_new();
BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, numGrids, gridSize,
(void**)ccgdm->gridFaces);
BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
numGrids, gridSize, (void**)ccgdm->gridFaces);
}
else if(ob->type == OB_MESH) {
Mesh *me= ob->data;

@ -27,6 +27,7 @@
struct MFace;
struct MVert;
struct DMGridAdjacency;
struct DMGridData;
struct PBVH;
struct PBVHNode;
@ -47,7 +48,8 @@ typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data);
PBVH *BLI_pbvh_new(void);
void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts,
int totface, int totvert);
void BLI_pbvh_build_grids(PBVH *bvh, struct DMGridData **grids, int totgrid,
void BLI_pbvh_build_grids(PBVH *bvh, struct DMGridData **grids,
struct DMGridAdjacency *gridadj, int totgrid,
int gridsize, void **gridfaces);
void BLI_pbvh_free(PBVH *bvh);
@ -94,7 +96,8 @@ typedef enum {
void BLI_pbvh_node_mark_update(PBVHNode *node);
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node,
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize);
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize,
struct DMGridData ***griddata, struct DMGridAdjacency **gridadj);
void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node,
int *uniquevert, int *totvert);
@ -105,7 +108,7 @@ void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BLI_pbvh_get_grid_updates(PBVH *bvh, void ***gridfaces, int *totface);
void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface);
/* Vertex Iterator */

@ -114,6 +114,7 @@ struct PBVH {
/* Grid Data */
DMGridData **grids;
DMGridAdjacency *gridadj;
void **gridfaces;
int totgrid;
int gridsize;
@ -510,14 +511,15 @@ void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int
}
/* Do a full rebuild with on Grids data structure */
void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids, int totgrid,
int gridsize, void **gridfaces)
void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids, DMGridAdjacency *gridadj,
int totgrid, int gridsize, void **gridfaces)
{
BBC *prim_bbc = NULL;
BB cb;
int i, j;
bvh->grids= grids;
bvh->gridadj= gridadj;
bvh->gridfaces= gridfaces;
bvh->totgrid= totgrid;
bvh->gridsize= gridsize;
@ -948,7 +950,7 @@ void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
copy_v3_v3(bb_max, bb.bmax);
}
void BLI_pbvh_get_grid_updates(PBVH *bvh, void ***gridfaces, int *totface)
void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface)
{
PBVHIter iter;
PBVHNode *node;
@ -965,9 +967,11 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, void ***gridfaces, int *totface)
if(node->flag & PBVH_UpdateNormals) {
for(i = 0; i < node->totprim; ++i) {
face= bvh->gridfaces[node->prim_indices[i]];
if(!BLI_ghash_lookup(map, face))
BLI_ghash_insert(map, face, face);
}
if(clear)
node->flag &= ~PBVH_UpdateNormals;
}
}
@ -1021,19 +1025,23 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
}
}
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize)
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, DMGridData ***griddata, DMGridAdjacency **gridadj)
{
if(bvh->grids) {
if(grid_indices) *grid_indices= node->prim_indices;
if(totgrid) *totgrid= node->totprim;
if(maxgrid) *maxgrid= bvh->totgrid;
if(gridsize) *gridsize= bvh->gridsize;
if(griddata) *griddata= bvh->grids;
if(gridadj) *gridadj= bvh->gridadj;
}
else {
if(grid_indices) *grid_indices= NULL;
if(totgrid) *totgrid= 0;
if(maxgrid) *maxgrid= 0;
if(gridsize) *gridsize= 0;
if(griddata) *griddata= NULL;
if(gridadj) *gridadj= NULL;
}
}

@ -415,7 +415,8 @@ static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
unode->node= node;
BLI_pbvh_node_num_verts(ss->tree, node, &totvert, &allvert);
BLI_pbvh_node_get_grids(ss->tree, node, &grids, &totgrid, &maxgrid, &gridsize);
BLI_pbvh_node_get_grids(ss->tree, node, &grids, &totgrid,
&maxgrid, &gridsize, NULL, NULL);
unode->totvert= totvert;
/* we will use this while sculpting, is mapalloc slow to access then? */
@ -795,9 +796,9 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3]
BLI_pbvh_vertex_iter_end;
}
#pragma omp critical
{
/* we sum per node and add together later for threads */
#pragma omp critical
add_v3_v3v3(out, out, nout);
add_v3_v3v3(out_flip, out_flip, nout_flip);
}
@ -903,26 +904,16 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
copy_v3_v3(avg, ss->mvert[vert].co);
}
static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
int iteration, n;
/* XXX not working for multires yet */
if(!ss->fmap)
return;
for(iteration = 0; iteration < 2; ++iteration) {
#pragma omp parallel for private(n) schedule(static)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
BLI_pbvh_vertex_iter_begin(ss->tree, node, vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
float avg[3], val[3];
@ -937,9 +928,104 @@ static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
BLI_pbvh_vertex_iter_end;
}
static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
{
Brush *brush = paint_brush(&sd->paint);
SculptBrushTest test;
DMGridData **griddata, *data;
DMGridAdjacency *gridadj, *adj;
float bstrength= ss->cache->bstrength;
float co[3], (*tmpgrid)[3];
int v1, v2, v3, v4;
int *grid_indices, totgrid, gridsize, i, x, y;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_node_get_grids(ss->tree, node, &grid_indices, &totgrid,
NULL, &gridsize, &griddata, &gridadj);
#pragma omp critical
tmpgrid= MEM_mallocN(sizeof(float)*3*gridsize*gridsize, "tmpgrid");
for(i = 0; i < totgrid; ++i) {
data = griddata[grid_indices[i]];
adj = &gridadj[grid_indices[i]];
memset(tmpgrid, 0, sizeof(float)*3*gridsize*gridsize);
/* average grid values */
for(y = 0; y < gridsize-1; ++y) {
for(x = 0; x < gridsize-1; ++x) {
v1 = x + y*gridsize;
v2 = (x + 1) + y*gridsize;
v3 = (x + 1) + (y + 1)*gridsize;
v4 = x + (y + 1)*gridsize;
cent_quad_v3(co, data[v1].co, data[v2].co, data[v3].co, data[v4].co);
mul_v3_fl(co, 0.25f);
add_v3_v3(tmpgrid[v1], co);
add_v3_v3(tmpgrid[v2], co);
add_v3_v3(tmpgrid[v3], co);
add_v3_v3(tmpgrid[v4], co);
}
}
/* blend with existing coordinates */
for(y = 0; y < gridsize; ++y) {
for(x = 0; x < gridsize; ++x) {
if(x == 0 && adj->index[0] == -1) continue;
if(x == gridsize - 1 && adj->index[2] == -1) continue;
if(y == 0 && adj->index[3] == -1) continue;
if(y == gridsize - 1 && adj->index[1] == -1) continue;
copy_v3_v3(co, data[x + y*gridsize].co);
if(sculpt_brush_test(&test, co)) {
float fade = tex_strength(ss, brush, co, test.dist)*bstrength;
float avg[3], val[3];
copy_v3_v3(avg, tmpgrid[x + y*gridsize]);
if(x == 0 || x == gridsize - 1)
mul_v3_fl(avg, 2.0f);
if(y == 0 || y == gridsize - 1)
mul_v3_fl(avg, 2.0f);
val[0] = co[0]+(avg[0]-co[0])*fade;
val[1] = co[1]+(avg[1]-co[1])*fade;
val[2] = co[2]+(avg[2]-co[2])*fade;
sculpt_clip(sd, ss, data[x + y*gridsize].co, val);
}
}
}
}
#pragma omp critical
MEM_freeN(tmpgrid);
}
static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
int iteration, n;
for(iteration = 0; iteration < 2; ++iteration) {
#pragma omp parallel for private(n) schedule(static)
for(n=0; n<totnode; n++) {
sculpt_undo_push_node(ss, nodes[n]);
if(ss->fmap)
do_mesh_smooth_brush(sd, ss, nodes[n]);
else
do_multires_smooth_brush(sd, ss, nodes[n]);
BLI_pbvh_node_mark_update(nodes[n]);
}
if(!ss->fmap)
multires_stitch_grids(ss->ob);
}
}

@ -586,9 +586,13 @@ typedef struct MultiresModifierData {
ModifierData modifier;
char lvl, sculptlvl, renderlvl, totlvl;
char simple, pad[3];
char simple, flags, pad[2];
} MultiresModifierData;
typedef enum {
eMultiresModifierFlag_ControlEdges = (1<<0),
} MultiresModifierFlag;
typedef struct FluidsimModifierData {
ModifierData modifier;

@ -534,9 +534,9 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 6, 1, 0);
RNA_def_property_ui_text(prop, "Render Levels", "Number of subdivisions to perform when rendering.");
prop= RNA_def_property(srna, "optimal_draw", PROP_BOOLEAN, PROP_NONE);
prop= RNA_def_property(srna, "optimal_display", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_ControlEdges);
RNA_def_property_ui_text(prop, "Optimal Draw", "Skip drawing/rendering of interior subdivided edges");
RNA_def_property_ui_text(prop, "Optimal Display", "Skip drawing/rendering of interior subdivided edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop= RNA_def_property(srna, "subsurf_uv", PROP_BOOLEAN, PROP_NONE);
@ -583,6 +583,11 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_MultiresModifier_external_get", "rna_MultiresModifier_external_set");
RNA_def_property_editable_func(prop, "rna_MultiresModifier_external_editable");
RNA_def_property_ui_text(prop, "External", "Store multires displacements outside the .blend file, to save memory.");
prop= RNA_def_property(srna, "optimal_display", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_ControlEdges);
RNA_def_property_ui_text(prop, "Optimal Display", "Skip drawing/rendering of interior subdivided edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_lattice(BlenderRNA *brna)