Moved the PBVH from sculpt session to DerivedMesh/CDDM.

* Multires sculpting appears to work now
* PBVH gets recalculated in some cases where it shouldn't, haven't looked into this yet
This commit is contained in:
Nicholas Bishop 2009-10-28 06:06:05 +00:00
parent 93beb0b85a
commit 243c73e96e
7 changed files with 122 additions and 90 deletions

View File

@ -59,6 +59,8 @@ struct MCol;
struct ColorBand;
struct GPUVertexAttribs;
struct GPUDrawObject;
struct ListBase;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
#define SUB_ELEMS_VERT 0
@ -73,6 +75,7 @@ struct DerivedMesh {
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache bvhCache;
struct GPUDrawObject *drawObject;
/* Misc. Queries */
@ -180,6 +183,14 @@ struct DerivedMesh {
/* Get vertex normal, undefined if index is not valid */
void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);
/* Get a map of vertices to faces
*/
struct ListBase *(*getFaceMap)(DerivedMesh *dm);
/* Get the BVH used for paint modes
*/
struct PBVH *(*getPBVH)(DerivedMesh *dm);
/* Drawing Operations */
/* Draw all vertices as bgl points (no options) */
@ -204,7 +215,7 @@ struct DerivedMesh {
*
* Also called for *final* editmode DerivedMeshes
*/
void (*drawFacesSolid)(DerivedMesh *dm, void *tree, float (*partial_redraw_planes)[4],
void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
int (*setMaterial)(int, void *attribs));
/* Draw all faces

View File

@ -69,17 +69,15 @@ typedef struct SculptSession {
struct MFace *mface;
int totvert, totface;
float *face_normals;
struct PBVH *tree;
/* Mesh connectivity */
struct ListBase *fmap;
struct IndexNode *fmap_mem;
int fmap_size;
/* Used temporarily per-stroke */
float *vertexcosnos;
/* Partial redraw */
struct PBVH *tree;
int partial_redraw;
/* Used to cache the render of the active texture */

View File

@ -77,6 +77,12 @@ typedef struct {
MVert *mvert;
MEdge *medge;
MFace *mface;
/* Cached */
struct PBVH *pbvh;
/* Mesh connectivity */
struct ListBase *fmap;
struct IndexNode *fmap_mem;
} CDDerivedMesh;
/**************** DerivedMesh interface functions ****************/
@ -171,6 +177,82 @@ static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
no_r[2] = no[2]/32767.f;
}
/* Updates all the face and vertex normals in a node
Note: the correctness of some vertex normals will be a little
off, not sure if this will be noticeable or not */
static void update_node_normals(const int *face_indices,
const int *vert_indices,
int totface, int totvert, void *data)
{
DerivedMesh *dm = data;
CDDerivedMesh *cddm = data;
float (*face_nors)[3];
int i;
/* make a face normal layer if not present */
face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
if(!face_nors)
face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
NULL, dm->numFaceData);
/* Update face normals */
for(i = 0; i < totface; ++i) {
MFace *f = cddm->mface + face_indices[i];
float *fn = face_nors[face_indices[i]];
if(f->v4)
CalcNormFloat4(cddm->mvert[f->v1].co, cddm->mvert[f->v2].co,
cddm->mvert[f->v3].co, cddm->mvert[f->v4].co, fn);
else
CalcNormFloat(cddm->mvert[f->v1].co, cddm->mvert[f->v2].co,
cddm->mvert[f->v3].co, fn);
}
/* Update vertex normals */
for(i = 0; i < totvert; ++i) {
const int v = vert_indices[i];
float no[3] = {0,0,0};
IndexNode *face;
for(face = cddm->fmap[v].first; face; face = face->next)
VecAddf(no, no, face_nors[face->index]);
Normalize(no);
cddm->mvert[v].no[0] = no[0] * 32767;
cddm->mvert[v].no[1] = no[1] * 32767;
cddm->mvert[v].no[2] = no[2] * 32767;
}
}
static ListBase *cdDM_getFaceMap(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
if(!cddm->fmap) {
create_vert_face_map(&cddm->fmap, &cddm->fmap_mem, cddm->mface,
dm->getNumVerts(dm), dm->getNumFaces(dm));
printf("rebuild fmap\n");
}
return cddm->fmap;
}
static struct PBVH *cdDM_getPBVH(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
if(!cddm->pbvh) {
cddm->pbvh = BLI_pbvh_new(update_node_normals, cddm);
BLI_pbvh_build(cddm->pbvh, cddm->mface, cddm->mvert,
dm->getNumFaces(dm), dm->getNumVerts(dm));
printf("rebuild pbvh\n");
}
return cddm->pbvh;
}
static void cdDM_drawVerts(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@ -419,7 +501,7 @@ int planes_contain_AABB(float bb_min[3], float bb_max[3], void *data)
return 1;
}
static void cdDM_drawFacesSolid(DerivedMesh *dm, void *tree,
static void cdDM_drawFacesSolid(DerivedMesh *dm,
float (*partial_redraw_planes)[4],
int (*setMaterial)(int, void *attribs))
{
@ -437,19 +519,19 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, void *tree,
glVertex3fv(mvert[index].co); \
}
if(tree) {
BLI_pbvh_search(tree, BLI_pbvh_update_search_cb,
if(cddm->pbvh) {
BLI_pbvh_search(cddm->pbvh, BLI_pbvh_update_search_cb,
PBVH_NodeData, NULL, NULL,
PBVH_SEARCH_UPDATE);
if(partial_redraw_planes) {
BLI_pbvh_search(tree, planes_contain_AABB,
BLI_pbvh_search(cddm->pbvh, planes_contain_AABB,
partial_redraw_planes,
draw_partial_cb, PBVH_DrawData,
PBVH_SEARCH_MODIFIED);
}
else {
BLI_pbvh_search(tree, find_all, NULL,
BLI_pbvh_search(cddm->pbvh, find_all, NULL,
draw_partial_cb, PBVH_DrawData,
PBVH_SEARCH_NORMAL);
@ -1376,12 +1458,21 @@ static void cdDM_foreachMappedFaceCenter(
}
}
static void cdDM_free_internal(CDDerivedMesh *cddm)
{
if(cddm->pbvh) BLI_pbvh_free(cddm->pbvh);
if(cddm->fmap) MEM_freeN(cddm->fmap);
if(cddm->fmap_mem) MEM_freeN(cddm->fmap_mem);
}
static void cdDM_release(DerivedMesh *dm)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
if (DM_release(dm))
if (DM_release(dm)) {
cdDM_free_internal(cddm);
MEM_freeN(cddm);
}
}
/**************** CDDM interface functions ****************/
@ -1416,6 +1507,9 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getVertCo = cdDM_getVertCo;
dm->getVertNo = cdDM_getVertNo;
dm->getPBVH = cdDM_getPBVH;
dm->getFaceMap = cdDM_getFaceMap;
dm->drawVerts = cdDM_drawVerts;
dm->drawUVEdges = cdDM_drawUVEdges;
@ -1901,6 +1995,7 @@ static void MultiresDM_release(DerivedMesh *dm)
}
if(DM_release(dm)) {
cdDM_free_internal(&mrdm->cddm);
MEM_freeN(mrdm->subco);
MEM_freeN(mrdm->orco);
if(mrdm->vert_face_map)

View File

@ -72,8 +72,6 @@
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
#include "BLI_ghash.h"
#include "BLI_pbvh.h"
#include "BKE_utildefines.h"
@ -231,12 +229,6 @@ void free_sculptsession(SculptSession **ssp)
if(ssp && *ssp) {
SculptSession *ss = *ssp;
if(ss->fmap)
MEM_freeN(ss->fmap);
if(ss->fmap_mem)
MEM_freeN(ss->fmap_mem);
if(ss->texcache)
MEM_freeN(ss->texcache);
@ -246,9 +238,6 @@ void free_sculptsession(SculptSession **ssp)
if(ss->mesh_co_orig)
MEM_freeN(ss->mesh_co_orig);
if(ss->tree)
BLI_pbvh_free(ss->tree);
if(ss->face_normals)
MEM_freeN(ss->face_normals);

View File

@ -1615,7 +1615,7 @@ static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
}
/* Only used by non-editmesh types */
static void ccgDM_drawFacesSolid(DerivedMesh *dm, void *tree, float (*partial_redraw_planes)[4], int (*setMaterial)(int, void *attribs)) {
static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], int (*setMaterial)(int, void *attribs)) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);

View File

@ -193,57 +193,6 @@ static void projectf(bglMats *mats, const float v[3], float p[2])
/*** BVH Tree ***/
/* Updates all the face and vertex normals in a node
Note: the correctness of some vertex normals will be a little
off, not sure if this will be noticeable or not */
static void sculpt_update_normals(const int *face_indices,
const int *vert_indices,
int totface, int totvert, void *data)
{
SculptSession *ss = data;
int i;
/* Update face normals */
for(i = 0; i < totface; ++i) {
MFace *f = ss->mface + face_indices[i];
float *fn = ss->face_normals + face_indices[i] * 3;
if(f->v4)
CalcNormFloat4(ss->mvert[f->v1].co, ss->mvert[f->v2].co,
ss->mvert[f->v3].co, ss->mvert[f->v4].co, fn);
else
CalcNormFloat(ss->mvert[f->v1].co, ss->mvert[f->v2].co,
ss->mvert[f->v3].co, fn);
}
/* Update vertex normals */
for(i = 0; i < totvert; ++i) {
const int v = vert_indices[i];
float no[3] = {0,0,0};
IndexNode *face;
for(face = ss->fmap[v].first; face; face = face->next)
VecAddf(no, no, ss->face_normals + face->index*3);
Normalize(no);
ss->mvert[v].no[0] = no[0] * 32767;
ss->mvert[v].no[1] = no[1] * 32767;
ss->mvert[v].no[2] = no[2] * 32767;
}
}
static void sculpt_rebuild_tree(SculptSession *ss)
{
if(ss->tree)
BLI_pbvh_free(ss->tree);
ss->tree = BLI_pbvh_new(sculpt_update_normals, ss);
BLI_pbvh_build(ss->tree, ss->mface, ss->mvert, ss->totface,
ss->totvert);
}
/* Get a screen-space rectangle of the modified area */
int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
Object *ob, rcti *rect)
@ -1054,11 +1003,10 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
static void sculpt_update_mesh_elements(bContext *C)
{
Object *ob = CTX_data_active_object(C);
DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
SculptSession *ss = ob->sculpt;
int oldtotvert = ss->totvert;
if((ss->multires = sculpt_multires_active(ob))) {
DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
ss->totvert = dm->getNumVerts(dm);
ss->totface = dm->getNumFaces(dm);
ss->mvert = dm->getVertDataArray(dm, CD_MVERT);
@ -1075,17 +1023,8 @@ static void sculpt_update_mesh_elements(bContext *C)
ss->face_normals = MEM_callocN(sizeof(float) * 3 * me->totface, "sculpt face normals");
}
if(ss->tree)
BLI_pbvh_set_source(ss->tree, ss->mvert, ss->mface);
if(ss->totvert != oldtotvert) {
if(ss->fmap) MEM_freeN(ss->fmap);
if(ss->fmap_mem) MEM_freeN(ss->fmap_mem);
create_vert_face_map(&ss->fmap, &ss->fmap_mem, ss->mface, ss->totvert, ss->totface);
ss->fmap_size = ss->totvert;
sculpt_rebuild_tree(ss);
}
ss->tree = dm->getPBVH(dm);
ss->fmap = dm->getFaceMap(dm);
}
static int sculpt_mode_poll(bContext *C)

View File

@ -2692,7 +2692,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
drawFacesSolid() doesn't draw the transparent faces */
if(ob->dtx & OB_DRAWTRANSP) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
dm->drawFacesSolid(dm, NULL, NULL, GPU_enable_material);
dm->drawFacesSolid(dm, NULL, GPU_enable_material);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GPU_disable_material();
}
@ -2802,10 +2802,10 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
ob->sculpt->partial_redraw = 0;
}
dm->drawFacesSolid(dm, ob->sculpt->tree, fpl, GPU_enable_material);
dm->drawFacesSolid(dm, fpl, GPU_enable_material);
}
else
dm->drawFacesSolid(dm, NULL, NULL, GPU_enable_material);
dm->drawFacesSolid(dm, NULL, GPU_enable_material);
GPU_disable_material();
@ -6276,7 +6276,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
glEnable(GL_LIGHTING);
if(dm) {
dm->drawFacesSolid(dm, NULL, NULL, GPU_enable_material);
dm->drawFacesSolid(dm, NULL, GPU_enable_material);
GPU_end_object_materials();
}
else if(edm)