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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorNicholas Bishop <nicholasbishop@gmail.com>2009-10-27 22:53:34 +0300
committerNicholas Bishop <nicholasbishop@gmail.com>2009-10-27 22:53:34 +0300
commit93beb0b85a4a0e301d9bfae9edee1fe7bdabba12 (patch)
tree1eb245707476ea83a356671c1c84ce82127581a7 /source
parentb2c2dafb687fb3dea0b36a52d5b77695adfe5181 (diff)
Commit of the sculpt patch (#19672). Further development will be in this branch until we merge to trunk.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h7
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c91
-rw-r--r--source/blender/blenkernel/intern/object.c10
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2
-rw-r--r--source/blender/blenlib/BLI_pbvh.h62
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/SConscript2
-rw-r--r--source/blender/blenlib/intern/arithb.c2
-rw-r--r--source/blender/blenlib/intern/pbvh.c665
-rw-r--r--source/blender/editors/include/ED_sculpt.h7
-rw-r--r--source/blender/editors/include/ED_view3d.h6
-rw-r--r--source/blender/editors/object/object_modifier.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c736
-rw-r--r--source/blender/editors/space_view3d/drawobject.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c39
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c47
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c39
-rw-r--r--source/blender/gpu/gpu_buffers.h11
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c151
25 files changed, 1486 insertions, 481 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 076747cb845..75d9ae7f360 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -204,7 +204,7 @@ struct DerivedMesh {
*
* Also called for *final* editmode DerivedMeshes
*/
- void (*drawFacesSolid)(DerivedMesh *dm,
+ void (*drawFacesSolid)(DerivedMesh *dm, void *tree, float (*partial_redraw_planes)[4],
int (*setMaterial)(int, void *attribs));
/* Draw all faces
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index ba42aca1872..558659b520f 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -34,6 +34,7 @@ struct MultireModifierData;
struct MVert;
struct Object;
struct Paint;
+struct PBVH;
struct Scene;
struct StrokeCache;
@@ -76,8 +77,10 @@ typedef struct SculptSession {
/* Used temporarily per-stroke */
float *vertexcosnos;
- ListBase damaged_rects;
- ListBase damaged_verts;
+
+ /* Partial redraw */
+ struct PBVH *tree;
+ int partial_redraw;
/* Used to cache the render of the active texture */
unsigned int texcache_side, *texcache, texcache_actual;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index e38bb00fe8d..6ae1057767d 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -49,7 +49,7 @@
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
#include "BLI_editVert.h"
-#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -360,7 +360,68 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
}
}
-static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs))
+static int nodes_drawn = 0;
+static int is_partial = 0;
+/* XXX: Just a temporary replacement for the real drawing code */
+static void draw_partial_cb(const int *face_indices,
+ const int *vert_indices,
+ int totface, int totvert, void *data_v)
+{
+ /* XXX: Just some quick code to show leaf nodes in different colors */
+ /*float col[3]; int i;
+ if(is_partial) {
+ col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
+ }
+ else {
+ srand((long long)data_v);
+ for(i = 0; i < 3; ++i)
+ col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
+ }
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
+
+ glColor3f(1, 0, 0);*/
+ GPU_draw_buffers(data_v);
+ ++nodes_drawn;
+}
+
+int find_all(float bb_min[3], float bb_max[3], void *data)
+{
+ return 1;
+}
+
+/* Adapted from:
+ http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
+ Returns true if the AABB is at least partially within the frustum
+ (ok, not a real frustum), false otherwise.
+*/
+int planes_contain_AABB(float bb_min[3], float bb_max[3], void *data)
+{
+ float (*planes)[4] = data;
+ int i, axis;
+ float vmin[3], vmax[3];
+
+ for(i = 0; i < 4; ++i) {
+ for(axis = 0; axis < 3; ++axis) {
+ if(planes[i][axis] > 0) {
+ vmin[axis] = bb_min[axis];
+ vmax[axis] = bb_max[axis];
+ }
+ else {
+ vmin[axis] = bb_max[axis];
+ vmax[axis] = bb_min[axis];
+ }
+ }
+
+ if(Inpf(planes[i], vmin) + planes[i][3] > 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void cdDM_drawFacesSolid(DerivedMesh *dm, void *tree,
+ float (*partial_redraw_planes)[4],
+ int (*setMaterial)(int, void *attribs))
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mvert = cddm->mvert;
@@ -376,6 +437,32 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a
glVertex3fv(mvert[index].co); \
}
+ if(tree) {
+ BLI_pbvh_search(tree, BLI_pbvh_update_search_cb,
+ PBVH_NodeData, NULL, NULL,
+ PBVH_SEARCH_UPDATE);
+
+ if(partial_redraw_planes) {
+ BLI_pbvh_search(tree, planes_contain_AABB,
+ partial_redraw_planes,
+ draw_partial_cb, PBVH_DrawData,
+ PBVH_SEARCH_MODIFIED);
+ }
+ else {
+ BLI_pbvh_search(tree, find_all, NULL,
+ draw_partial_cb, PBVH_DrawData,
+ PBVH_SEARCH_NORMAL);
+
+ }
+
+ is_partial = !!partial_redraw_planes;
+
+ //printf("nodes drawn=%d\n", nodes_drawn);
+ nodes_drawn = 0;
+
+ return;
+ }
+
if( GPU_buffer_legacy(dm) ) {
DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
glBegin(glmode = GL_QUADS);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index ba8d41f54bb..5c3419fb488 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -72,6 +72,8 @@
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
#include "BKE_utildefines.h"
@@ -228,8 +230,6 @@ void free_sculptsession(SculptSession **ssp)
{
if(ssp && *ssp) {
SculptSession *ss = *ssp;
- if(ss->projverts)
- MEM_freeN(ss->projverts);
if(ss->fmap)
MEM_freeN(ss->fmap);
@@ -246,6 +246,12 @@ 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);
+
MEM_freeN(ss);
*ssp = NULL;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 6e95fe7ebc7..7c83431ebd8 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -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, int (*setMaterial)(int, void *attribs)) {
+static void ccgDM_drawFacesSolid(DerivedMesh *dm, void *tree, float (*partial_redraw_planes)[4], int (*setMaterial)(int, void *attribs)) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h
new file mode 100644
index 00000000000..edc363e65a3
--- /dev/null
+++ b/source/blender/blenlib/BLI_pbvh.h
@@ -0,0 +1,62 @@
+struct MFace;
+struct MVert;
+struct PBVH;
+
+/* Returns 1 if the search should continue from this node, 0 otherwise */
+typedef int (*BLI_pbvh_SearchCallback)(float bb_min[3], float bb_max[3],
+ void *data);
+
+typedef void (*BLI_pbvh_HitCallback)(const int *face_indices,
+ const int *vert_indices,
+ int totface, int totvert, void *data);
+int BLI_pbvh_search_range(float bb_min[3], float bb_max[3], void *data_v);
+
+typedef enum {
+ PBVH_SEARCH_NORMAL,
+
+ /* When the callback returns a 1 for a leaf node, that node will be
+ marked as modified */
+ PBVH_SEARCH_MARK_MODIFIED,
+
+ /* Update gpu data for modified nodes. Also clears the Modified flag. */
+ PBVH_SEARCH_MODIFIED,
+
+
+ PBVH_SEARCH_UPDATE
+} PBVH_SearchMode;
+
+/* Pass the node as data to the callback */
+#define PBVH_NodeData (void*)0xa
+/* Pass the draw buffers as data to the callback */
+#define PBVH_DrawData (void*)0xb
+
+void BLI_pbvh_search(struct PBVH *bvh, BLI_pbvh_SearchCallback scb,
+ void *search_data, BLI_pbvh_HitCallback hcb,
+ void *hit_data, PBVH_SearchMode mode);
+
+/* The hit callback is called for all leaf nodes intersecting the ray;
+ it's up to the callback to find the primitive within the leaves that is
+ hit first */
+void BLI_pbvh_raycast(struct PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
+ float ray_start[3], float ray_normal[3]);
+
+
+int BLI_pbvh_update_search_cb(float bb_min[3], float bb_max[3], void *data_v);
+
+/* Get the bounding box around all nodes that have been marked as modified. */
+void BLI_pbvh_modified_bounding_box(struct PBVH *bvh,
+ float bb_min[3], float bb_max[3]);
+void BLI_pbvh_reset_modified_bounding_box(struct PBVH *bvh);
+
+/* Lock is off by default, turn on to stop redraw from clearing the modified
+ flag from nodes */
+void BLI_pbvh_toggle_modified_lock(struct PBVH *bvh);
+
+
+
+struct PBVH *BLI_pbvh_new(BLI_pbvh_HitCallback update_cb, void *update_cb_data);
+void BLI_pbvh_build(struct PBVH *bvh, struct MFace *faces, struct MVert *verts,
+ int totface, int totvert);
+void BLI_pbvh_free(struct PBVH *bvh);
+
+void BLI_pbvh_set_source(struct PBVH *bvh, struct MVert *, struct MFace *mface);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 4ed9eb4b007..00a5440bc75 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -28,6 +28,7 @@ FILE(GLOB SRC intern/*.c)
SET(INC
. ../makesdna ../blenkernel ../../../intern/guardedalloc ../include
+ ../gpu
${FREETYPE_INCLUDE_DIRS}
${ZLIB_INC}
)
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
index fc586de5085..bca9399bc27 100644
--- a/source/blender/blenlib/SConscript
+++ b/source/blender/blenlib/SConscript
@@ -4,7 +4,7 @@ Import ('env')
sources = env.Glob('intern/*.c')
cflags=''
-incs = '. ../makesdna ../blenkernel #/intern/guardedalloc ../editors/include'
+incs = '. ../makesdna ../blenkernel #/intern/guardedalloc ../editors/include ../gpu'
incs += ' ' + env['BF_FREETYPE_INC']
incs += ' ' + env['BF_ZLIB_INC']
defs = ''
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
index 6c9ae78bac4..85cd46e6f33 100644
--- a/source/blender/blenlib/intern/arithb.c
+++ b/source/blender/blenlib/intern/arithb.c
@@ -4324,7 +4324,7 @@ int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], flo
Crossf(p, d, e2);
a = Inpf(e1, p);
- if ((a > -0.000001) && (a < 0.000001)) return 0;
+ if ((a > -FLT_EPSILON) && (a < FLT_EPSILON)) return 0;
f = 1.0f/a;
VecSubf(s, p1, v0);
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
new file mode 100644
index 00000000000..98492a8f429
--- /dev/null
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -0,0 +1,665 @@
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
+
+#include "BKE_utildefines.h"
+
+#include "gpu_buffers.h"
+
+#include <float.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LEAF_LIMIT 10000
+
+//#define PERFCNTRS
+
+/* Bitmap */
+typedef char* BLI_bitmap;
+
+BLI_bitmap BLI_bitmap_new(int tot)
+{
+ return MEM_callocN((tot >> 3) + 1, "BLI bitmap");
+}
+
+int BLI_bitmap_get(BLI_bitmap b, int index)
+{
+ return b[index >> 3] & (1 << (index & 7));
+}
+
+void BLI_bitmap_set(BLI_bitmap b, int index)
+{
+ b[index >> 3] |= (1 << (index & 7));
+}
+
+void BLI_bitmap_clear(BLI_bitmap b, int index)
+{
+ b[index >> 3] &= ~(1 << (index & 7));
+}
+
+typedef enum {
+ PBVH_Leaf = 1,
+ PBVH_Modified = 2
+} NodeFlags;
+
+/* Axis-aligned bounding box */
+typedef struct {
+ float bmin[3], bmax[3];
+} BB;
+
+/* Axis-aligned bounding box with centroid */
+typedef struct {
+ float bmin[3], bmax[3], bcentroid[3];
+} BBC;
+
+typedef struct {
+ /* Opaque handle for drawing code */
+ void *draw_buffers;
+
+ int *vert_indices;
+
+ /* Voxel bounds */
+ BB vb;
+
+ /* For internal nodes */
+ int children_offset;
+
+ /* Range of faces used in the node */
+ int face_offset;
+
+ unsigned short totface;
+ unsigned short uniq_verts, face_verts;
+
+ char flag;
+} Node;
+
+typedef struct PBVH {
+ Node *nodes;
+ int node_mem_count, totnode;
+
+ int *face_indices;
+ int totface;
+
+ BB modified_bb;
+
+ BLI_pbvh_HitCallback update_cb;
+ void *update_cb_data;
+
+ /* Mesh data */
+ MVert *verts;
+ MFace *faces;
+
+ int modified_lock;
+
+ /* Only used during BVH build and update,
+ don't need to remain valid after */
+ BLI_bitmap vert_bitmap;
+
+#ifdef PERFCNTRS
+ int perf_modified;
+#endif
+} PBVH;
+
+static void BB_reset(BB *bb)
+{
+ bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
+ bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
+}
+
+/* Expand the bounding box to include a new coordinate */
+static void BB_expand(BB *bb, float co[3])
+{
+ if(co[0] < bb->bmin[0]) bb->bmin[0] = co[0];
+ if(co[1] < bb->bmin[1]) bb->bmin[1] = co[1];
+ if(co[2] < bb->bmin[2]) bb->bmin[2] = co[2];
+
+ if(co[0] > bb->bmax[0]) bb->bmax[0] = co[0];
+ if(co[1] > bb->bmax[1]) bb->bmax[1] = co[1];
+ if(co[2] > bb->bmax[2]) bb->bmax[2] = co[2];
+}
+
+/* Expand the bounding box to include another bounding box */
+static void BB_expand_with_bb(BB *bb, BB *bb2)
+{
+ int i;
+ for(i = 0; i < 3; ++i) {
+ bb->bmin[i] = MIN2(bb->bmin[i], bb2->bmin[i]);
+ bb->bmax[i] = MAX2(bb->bmax[i], bb2->bmax[i]);
+ }
+}
+
+/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
+static int BB_widest_axis(BB *bb)
+{
+ float dim[3];
+ int i;
+
+ for(i = 0; i < 3; ++i)
+ dim[i] = bb->bmax[i] - bb->bmin[i];
+
+ if(dim[0] > dim[1]) {
+ if(dim[0] > dim[2])
+ return 0;
+ else
+ return 2;
+ }
+ else {
+ if(dim[1] > dim[2])
+ return 1;
+ else
+ return 2;
+ }
+}
+
+static void BBC_update_centroid(BBC *bbc)
+{
+ int i;
+ for(i = 0; i < 3; ++i)
+ bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
+}
+
+/* Not recursive */
+static void update_node_vb(PBVH *bvh, Node *node)
+{
+ BB_reset(&node->vb);
+
+ if(node->flag & PBVH_Leaf) {
+ int i, j;
+ for(i = node->face_offset + node->totface - 1;
+ i >= node->face_offset; --i) {
+ MFace *f = bvh->faces + bvh->face_indices[i];
+ const int sides = f->v4 ? 4 : 3;
+
+ for(j = 0; j < sides; ++j)
+ BB_expand(&node->vb,
+ bvh->verts[*((&f->v1) + j)].co);
+ }
+ }
+ else {
+ BB_expand_with_bb(&node->vb,
+ &bvh->nodes[node->children_offset].vb);
+ BB_expand_with_bb(&node->vb,
+ &bvh->nodes[node->children_offset + 1].vb);
+ }
+}
+
+/* Adapted from BLI_kdopbvh.c */
+/* Returns the index of the first element on the right of the partition */
+static int partition_indices(int *face_indices, int lo, int hi, int axis,
+ float mid, BBC *prim_bbc)
+{
+ int i=lo, j=hi;
+ for(;;) {
+ for(; prim_bbc[face_indices[i]].bcentroid[axis] < mid; i++);
+ for(; mid < prim_bbc[face_indices[j]].bcentroid[axis]; j--);
+
+ if(!(i < j))
+ return i;
+
+ SWAP(int, face_indices[i], face_indices[j]);
+ i++;
+ }
+}
+
+void check_partitioning(int *face_indices, int lo, int hi, int axis,
+ float mid, BBC *prim_bbc, int index_of_2nd_partition)
+{
+ int i;
+ for(i = lo; i <= hi; ++i) {
+ const float c = prim_bbc[face_indices[i]].bcentroid[axis];
+
+ if((i < index_of_2nd_partition && c > mid) ||
+ (i > index_of_2nd_partition && c < mid)) {
+ printf("fail\n");
+ }
+ }
+}
+
+static void grow_nodes(PBVH *bvh, int totnode)
+{
+ if(totnode > bvh->node_mem_count) {
+ Node *prev = bvh->nodes;
+ bvh->node_mem_count *= 1.33;
+ if(bvh->node_mem_count < totnode)
+ bvh->node_mem_count = totnode;
+ bvh->nodes = MEM_callocN(sizeof(Node) * bvh->node_mem_count,
+ "bvh nodes");
+ memcpy(bvh->nodes, prev, bvh->totnode * sizeof(Node));
+ MEM_freeN(prev);
+ }
+
+ bvh->totnode = totnode;
+}
+
+/* Add a vertex to the map, with a positive value for unique vertices and
+ a negative value for additional vertices */
+static void map_insert_vert(PBVH *bvh, GHash *map,
+ unsigned short *face_verts,
+ unsigned short *uniq_verts, int vertex)
+{
+ void *value, *key = SET_INT_IN_POINTER(vertex);
+
+ if(!BLI_ghash_haskey(map, key)) {
+ if(BLI_bitmap_get(bvh->vert_bitmap, vertex)) {
+ value = SET_INT_IN_POINTER(-(*face_verts) - 1);
+ ++(*face_verts);
+ }
+ else {
+ BLI_bitmap_set(bvh->vert_bitmap, vertex);
+ value = SET_INT_IN_POINTER(*uniq_verts);
+ ++(*uniq_verts);
+ }
+
+ BLI_ghash_insert(map, key, value);
+ }
+}
+
+/* Find vertices used by the faces in this node and update the draw buffers */
+static void build_leaf_node(PBVH *bvh, Node *node)
+{
+ GHashIterator *iter;
+ GHash *map;
+ int i, j;
+
+ map = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+
+ node->uniq_verts = node->face_verts = 0;
+
+ for(i = node->face_offset + node->totface - 1;
+ i >= node->face_offset; --i) {
+ MFace *f = bvh->faces + bvh->face_indices[i];
+ int sides = f->v4 ? 4 : 3;
+
+ for(j = 0; j < sides; ++j) {
+ map_insert_vert(bvh, map, &node->face_verts,
+ &node->uniq_verts, (&f->v1)[j]);
+ }
+ }
+
+ node->vert_indices = MEM_callocN(sizeof(int) *
+ (node->uniq_verts + node->face_verts),
+ "bvh node vert indices");
+
+ /* Build the vertex list, unique verts first */
+ for(iter = BLI_ghashIterator_new(map), i = 0;
+ !BLI_ghashIterator_isDone(iter);
+ BLI_ghashIterator_step(iter), ++i) {
+ void *value = BLI_ghashIterator_getValue(iter);
+ int ndx = GET_INT_FROM_POINTER(value);
+
+ if(ndx < 0)
+ ndx = -ndx + node->uniq_verts - 1;
+
+ node->vert_indices[ndx] =
+ GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(iter));
+ }
+
+ node->draw_buffers =
+ GPU_build_buffers(map, bvh->verts, bvh->faces,
+ bvh->face_indices + node->face_offset,
+ node->totface, node->vert_indices,
+ node->uniq_verts,
+ node->uniq_verts + node->face_verts);
+
+ BLI_ghash_free(map, NULL, NULL);
+}
+
+/* Recursively build a node in the tree
+
+ vb is the voxel box around all of the primitives contained in
+ this node.
+
+ cb is the bounding box around all the centroids of the primitives
+ contained in this node
+
+ offset and start indicate a range in the array of primitive indices
+*/
+
+void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
+ int offset, int count)
+{
+ int i, axis, end;
+ BB cb_backing;
+
+ /* Decide whether this is a leaf or not */
+ if(count <= LEAF_LIMIT) {
+ bvh->nodes[node_index].flag |= PBVH_Leaf;
+
+ bvh->nodes[node_index].face_offset = offset;
+ bvh->nodes[node_index].totface = count;
+
+ /* Still need vb for searches */
+ BB_reset(&bvh->nodes[node_index].vb);
+ for(i = offset + count - 1; i >= offset; --i) {
+ BB_expand_with_bb(&bvh->nodes[node_index].vb,
+ (BB*)(prim_bbc +
+ bvh->face_indices[i]));
+ }
+
+ build_leaf_node(bvh, bvh->nodes + node_index);
+
+ /* Done with this subtree */
+ return;
+ }
+ else {
+ BB_reset(&bvh->nodes[node_index].vb);
+ bvh->nodes[node_index].children_offset = bvh->totnode;
+ grow_nodes(bvh, bvh->totnode + 2);
+
+ if(!cb) {
+ cb = &cb_backing;
+ BB_reset(cb);
+ for(i = offset + count - 1; i >= offset; --i)
+ BB_expand(cb, prim_bbc[bvh->face_indices[i]].bcentroid);
+ }
+ }
+
+ axis = BB_widest_axis(cb);
+
+ for(i = offset + count - 1; i >= offset; --i) {
+ BB_expand_with_bb(&bvh->nodes[node_index].vb,
+ (BB*)(prim_bbc + bvh->face_indices[i]));
+ }
+
+ end = partition_indices(bvh->face_indices, offset, offset + count - 1,
+ axis,
+ (cb->bmax[axis] + cb->bmin[axis]) * 0.5f,
+ prim_bbc);
+ check_partitioning(bvh->face_indices, offset, offset + count - 1,
+ axis,
+ (cb->bmax[axis] + cb->bmin[axis]) * 0.5f,
+ prim_bbc, end);
+
+ build_sub(bvh, bvh->nodes[node_index].children_offset, NULL,
+ prim_bbc, offset, end - offset);
+ build_sub(bvh, bvh->nodes[node_index].children_offset + 1, NULL,
+ prim_bbc, end, offset + count - end);
+}
+
+/* Do a full rebuild */
+void BLI_pbvh_build(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert)
+{
+ BBC *prim_bbc = NULL;
+ BB cb;
+ int i, j;
+
+ if(totface != bvh->totface) {
+ bvh->totface = totface;
+ if(bvh->nodes) MEM_freeN(bvh->nodes);
+ if(bvh->face_indices) MEM_freeN(bvh->face_indices);
+ bvh->face_indices = MEM_callocN(sizeof(int) * totface,
+ "bvh face indices");
+ for(i = 0; i < totface; ++i)
+ bvh->face_indices[i] = i;
+ bvh->totnode = 0;
+ if(bvh->node_mem_count < 100) {
+ bvh->node_mem_count = 100;
+ bvh->nodes = MEM_callocN(sizeof(Node) *
+ bvh->node_mem_count,
+ "bvh initial nodes");
+ }
+ }
+
+ bvh->faces = faces;
+ bvh->verts = verts;
+ bvh->vert_bitmap = BLI_bitmap_new(totvert);
+
+ BB_reset(&bvh->modified_bb);
+
+ BB_reset(&cb);
+
+ /* For each face, store the AABB and the AABB centroid */
+ prim_bbc = MEM_mallocN(sizeof(BBC) * totface, "prim_bbc");
+
+ for(i = 0; i < totface; ++i) {
+ MFace *f = faces + i;
+ const int sides = f->v4 ? 4 : 3;
+ BBC *bbc = prim_bbc + i;
+
+ BB_reset((BB*)bbc);
+
+ for(j = 0; j < sides; ++j)
+ BB_expand((BB*)bbc, verts[(&f->v1)[j]].co);
+
+ BBC_update_centroid(bbc);
+
+ BB_expand(&cb, bbc->bcentroid);
+ }
+
+ bvh->totnode = 1;
+ build_sub(bvh, 0, &cb, prim_bbc, 0, totface);
+
+ MEM_freeN(prim_bbc);
+ MEM_freeN(bvh->vert_bitmap);
+}
+
+PBVH *BLI_pbvh_new(BLI_pbvh_HitCallback update_cb, void *update_cb_data)
+{
+ PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
+
+ bvh->update_cb = update_cb;
+ bvh->update_cb_data = update_cb_data;
+
+ return bvh;
+}
+
+void BLI_pbvh_free(PBVH *bvh)
+{
+ int i;
+
+ for(i = 0; i < bvh->totnode; ++i) {
+ if(bvh->nodes[i].flag & PBVH_Leaf) {
+ GPU_free_buffers(bvh->nodes[i].draw_buffers);
+ MEM_freeN(bvh->nodes[i].vert_indices);
+ }
+ }
+
+ MEM_freeN(bvh->nodes);
+ MEM_freeN(bvh->face_indices);
+ MEM_freeN(bvh);
+}
+
+void BLI_pbvh_set_source(PBVH *bvh, MVert *mvert, MFace *mface)
+{
+ bvh->verts = mvert;
+ bvh->faces = mface;
+}
+
+static void do_hit_callback(PBVH *bvh, Node *node,
+ BLI_pbvh_HitCallback cb, void *data)
+{
+ if(cb) {
+ cb(bvh->face_indices + node->face_offset, node->vert_indices,
+ node->totface, node->uniq_verts, data);
+ }
+}
+
+static int search_sub(PBVH *bvh, Node *node,
+ BLI_pbvh_SearchCallback scb, void *search_data_f,
+ BLI_pbvh_HitCallback hcb, void *hit_data_f,
+ PBVH_SearchMode mode)
+{
+ void *search_data = search_data_f;
+ void *hit_data = hit_data_f;
+
+ if(search_data_f == PBVH_NodeData)
+ search_data = &node->flag;
+ if(hit_data_f == PBVH_DrawData)
+ hit_data = node->draw_buffers;
+
+ if(scb(node->vb.bmin, node->vb.bmax, search_data)) {
+ if(node->flag & PBVH_Leaf) {
+ switch(mode) {
+ case PBVH_SEARCH_MARK_MODIFIED:
+ node->flag |= PBVH_Modified;
+#ifdef PERFCNTRS
+ ++bvh->perf_modified;
+#endif
+ break;
+ case PBVH_SEARCH_MODIFIED:
+ if(node->flag & PBVH_Modified) {
+ if(bvh->update_cb) {
+ do_hit_callback
+ (bvh, node,
+ bvh->update_cb,
+ bvh->update_cb_data);
+ }
+
+ GPU_update_buffers(node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts +
+ node->face_verts);
+ }
+ default:
+ break;
+ }
+
+ do_hit_callback(bvh, node, hcb, hit_data);
+ }
+ else {
+ int mod = 0;
+ if(search_sub(bvh, bvh->nodes + node->children_offset,
+ scb, search_data_f, hcb,hit_data_f, mode))
+ mod = 1;
+ if(search_sub(bvh,
+ bvh->nodes + node->children_offset + 1,
+ scb, search_data_f, hcb,hit_data_f, mode))
+ mod = 1;
+
+ if(mod)
+ node->flag |= PBVH_Modified;
+ }
+ }
+
+ if(mode == PBVH_SEARCH_MODIFIED) {
+#ifdef PERFCNTRS
+ if(node->flag & PBVH_Modified && node->flag & PBVH_Leaf)
+ --bvh->perf_modified;
+#endif
+ if(!bvh->modified_lock)
+ node->flag &= ~PBVH_Modified;
+ }
+ else if(mode == PBVH_SEARCH_UPDATE) {
+ if(node->flag & PBVH_Modified) {
+ update_node_vb(bvh, node);
+ if(node->flag & PBVH_Leaf)
+ BB_expand_with_bb(&bvh->modified_bb, &node->vb);
+ }
+ }
+
+ return node->flag & PBVH_Modified;
+}
+
+void BLI_pbvh_search(PBVH *bvh, BLI_pbvh_SearchCallback scb, void *search_data,
+ BLI_pbvh_HitCallback hcb, void *hit_data,
+ PBVH_SearchMode mode)
+{
+#ifdef PERFCNTRS
+ printf("search mode=%s\n",
+ mode==PBVH_SEARCH_MARK_MODIFIED?"mark-modified":
+ mode==PBVH_SEARCH_MODIFIED?"modified":
+ mode==PBVH_SEARCH_UPDATE?"update":
+ mode==PBVH_SEARCH_NORMAL?"normal":"unknown-mode");
+ if(mode == PBVH_SEARCH_MARK_MODIFIED)
+ bvh->perf_modified = 0;
+#endif
+
+ search_sub(bvh, bvh->nodes, scb, search_data, hcb, hit_data, mode);
+#ifdef PERFCNTRS
+ printf("%d nodes marked modified\n", bvh->perf_modified);
+ printf("search complete\n\n");
+#endif
+}
+
+typedef struct {
+ /* Ray */
+ float start[3];
+ int sign[3];
+ float inv_dir[3];
+} RaycastData;
+
+/* Adapted from here: http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
+static int ray_aabb_intersect(float bb_min[3], float bb_max[3], void *data_v)
+{
+ RaycastData *ray = data_v;
+ float bbox[2][3];
+ float tmin, tmax, tymin, tymax, tzmin, tzmax;
+
+ VecCopyf(bbox[0], bb_min);
+ VecCopyf(bbox[1], bb_max);
+
+ tmin = (bbox[ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
+ tmax = (bbox[1-ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
+
+ tymin = (bbox[ray->sign[1]][1] - ray->start[1]) * ray->inv_dir[1];
+ tymax = (bbox[1-ray->sign[1]][1] - ray->start[1]) * ray->inv_dir[1];
+
+ if((tmin > tymax) || (tymin > tmax))
+ return 0;
+ if(tymin > tmin)
+ tmin = tymin;
+ if(tymax < tmax)
+ tmax = tymax;
+
+ tzmin = (bbox[ray->sign[2]][2] - ray->start[2]) * ray->inv_dir[2];
+ tzmax = (bbox[1-ray->sign[2]][2] - ray->start[2]) * ray->inv_dir[2];
+
+ if((tmin > tzmax) || (tzmin > tmax))
+ return 0;
+
+ return 1;
+
+ /* XXX: Not sure about this?
+ if(tzmin > tmin)
+ tmin = tzmin;
+ if(tzmax < tmax)
+ tmax = tzmax;
+ return ((tmin < t1) && (tmax > t0));
+ */
+
+}
+
+void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
+ float ray_start[3], float ray_normal[3])
+{
+ RaycastData rcd;
+
+ VecCopyf(rcd.start, ray_start);
+ rcd.inv_dir[0] = 1.0f / ray_normal[0];
+ rcd.inv_dir[1] = 1.0f / ray_normal[1];
+ rcd.inv_dir[2] = 1.0f / ray_normal[2];
+ rcd.sign[0] = rcd.inv_dir[0] < 0;
+ rcd.sign[1] = rcd.inv_dir[1] < 0;
+ rcd.sign[2] = rcd.inv_dir[2] < 0;
+
+ BLI_pbvh_search(bvh, ray_aabb_intersect, &rcd, cb, data,
+ PBVH_SEARCH_NORMAL);
+}
+
+int BLI_pbvh_update_search_cb(float bb_min[3], float bb_max[3], void *data_v)
+{
+ int *data = data_v;
+
+ return ((*data) & PBVH_Modified);
+}
+
+void BLI_pbvh_modified_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3])
+{
+ VecCopyf(bb_min, bvh->modified_bb.bmin);
+ VecCopyf(bb_max, bvh->modified_bb.bmax);
+}
+
+void BLI_pbvh_reset_modified_bounding_box(PBVH *bvh)
+{
+ BB_reset(&bvh->modified_bb);
+}
+
+void BLI_pbvh_toggle_modified_lock(PBVH *bvh)
+{
+ bvh->modified_lock = !bvh->modified_lock;
+}
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 764efb4ef0c..12ebd74b64b 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -28,11 +28,18 @@
#ifndef ED_SCULPT_H
#define ED_SCULPT_H
+struct ARegion;
struct bContext;
+struct Object;
+struct RegionView3D;
struct wmKeyConfig;
+struct wmWindowManager;
/* sculpt.c */
void ED_operatortypes_sculpt(void);
+void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar,
+ struct RegionView3D *rv3d, struct Object *ob);
+
/* paint_ops.c */
void ED_operatortypes_paint(void);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index be2822d8c49..d9220387073 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -30,6 +30,7 @@
/* ********* exports for space_view3d/ module ********** */
struct ARegion;
+struct BoundBox;
struct View3D;
struct RegionView3D;
struct ViewContext;
@@ -44,6 +45,7 @@ struct ImBuf;
struct Scene;
struct bContext;
struct Main;
+struct rcti;
/* for derivedmesh drawing callbacks, for view3d_select, .... */
typedef struct ViewContext {
@@ -80,6 +82,8 @@ void request_depth_update(struct RegionView3D *rv3d);
/* Projection */
#define IS_CLIPPED 12000
+void view3d_calculate_clipping(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, struct rcti *rect);
+
void project_short(struct ARegion *ar, float *vec, short *adr);
void project_short_noclip(struct ARegion *ar, float *vec, short *adr);
@@ -125,7 +129,7 @@ short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigne
void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_get_view_aligned_coordinate(struct ViewContext *vc, float *fp, short mval[2]);
-void view3d_get_transformation(struct ViewContext *vc, struct Object *ob, struct bglMats *mats);
+void view3d_get_transformation(struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats);
/* XXX should move to arithb.c */
int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 1b0dc95480a..39a8a026afb 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -718,6 +718,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
MultiresModifierData *mmd= ptr.data;
multiresModifier_subdivide(mmd, ob, 1, 0, mmd->simple);
+
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index ee1a21db7e5..0681cf0fe0d 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -362,7 +362,7 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
PE_set_data(C, data);
view3d_set_viewcontext(C, &data->vc);
- view3d_get_transformation(&data->vc, data->ob, &data->mats);
+ view3d_get_transformation(data->vc.ar, data->vc.rv3d, data->ob, &data->mats);
if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
view3d_validate_backbuf(&data->vc);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b5748d7bc88..0689e8e63d7 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -43,11 +43,13 @@ struct ARegion;
struct VPaint;
/* paint_stroke.c */
+typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr);
typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(struct bContext *C, StrokeTestStart test_start,
+struct PaintStroke *paint_stroke_new(struct bContext *C,
+ StrokeGetLocation get_location, StrokeTestStart test_start,
StrokeUpdateStep update_step, StrokeDone done);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 6e256bee7f2..f8ffaacc0b7 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -73,6 +73,7 @@ typedef struct PaintStroke {
passes over the mesh */
int stroke_started;
+ StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
StrokeDone done;
@@ -118,12 +119,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
{
PointerRNA itemptr;
- float cur_depth, pressure = 1;
- float center[3];
+ float pressure = 1;
+ float center[3] = {0, 0, 0};
PaintStroke *stroke = op->customdata;
- cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]);
- view3d_unproject(&stroke->mats, center, mouse[0], mouse[1], cur_depth);
+ /* XXX: can remove the if statement once all modes have this */
+ if(stroke->get_location)
+ stroke->get_location(C, stroke, center, mouse);
/* Tablet */
if(event->custom == EVT_DATA_TABLET) {
@@ -208,15 +210,19 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
/**** Public API ****/
-PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
- StrokeUpdateStep update_step, StrokeDone done)
+PaintStroke *paint_stroke_new(bContext *C,
+ StrokeGetLocation get_location,
+ StrokeTestStart test_start,
+ StrokeUpdateStep update_step,
+ StrokeDone done)
{
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C)));
view3d_set_viewcontext(C, &stroke->vc);
- view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats);
+ view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
+ stroke->get_location = get_location;
stroke->test_start = test_start;
stroke->update_step = update_step;
stroke->done = done;
@@ -226,7 +232,6 @@ PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
{
- ARegion *ar = CTX_wm_region(C);
PaintStroke *stroke = op->customdata;
float mouse[2];
@@ -246,20 +251,20 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
}
- ED_region_tag_redraw(ar);
+ //ED_region_tag_redraw(ar);
}
if(stroke->stroke_started) {
if(paint_smooth_stroke(stroke, mouse, event)) {
if(paint_space_stroke_enabled(stroke->brush)) {
if(!paint_space_stroke(C, op, event, mouse))
- ED_region_tag_redraw(ar);
+ ;//ED_region_tag_redraw(ar);
}
else
paint_brush_stroke_add_step(C, op, event, mouse);
}
else
- ED_region_tag_redraw(ar);
+ ;//ED_region_tag_redraw(ar);
}
/* TODO: fix hardcoded event here */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 1dac98780da..c4379ac187b 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1493,7 +1493,7 @@ static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- op->customdata = paint_stroke_new(C, wpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step,
wpaint_stroke_done);
@@ -1792,7 +1792,7 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- op->customdata = paint_stroke_new(C, vpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step,
vpaint_stroke_done);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c4c7f436f12..b4b002283fd 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -35,6 +35,8 @@
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
@@ -52,6 +54,7 @@
#include "DNA_color_types.h"
#include "BKE_brush.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
@@ -131,7 +134,6 @@ typedef struct StrokeCache {
int flag;
float clip_tolerance[3];
float initial_mouse[2];
- float depth;
/* Variants */
float radius;
@@ -147,6 +149,10 @@ typedef struct StrokeCache {
bglMats *mats;
+ /* Clean this up! */
+ ViewContext *vc;
+ Brush *brush;
+
short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
float rotation; /* Texture rotation (radians) for anchored and rake modes */
@@ -159,20 +165,6 @@ typedef struct StrokeCache {
int last_rake[2]; /* Last location of updating rake rotation */
} StrokeCache;
-typedef struct RectNode {
- struct RectNode *next, *prev;
- rcti r;
-} RectNode;
-
-/* Used to store to 2D screen coordinates of each vertex in the mesh. */
-typedef struct ProjVert {
- short co[2];
-
- /* Used to mark whether a vertex is inside a rough bounding box
- containing the brush. */
- char inside;
-} ProjVert;
-
/* ===== OPENGL =====
*
* Simple functions to get data from the GL
@@ -189,7 +181,7 @@ static void projectf(bglMats *mats, const float v[3], float p[2])
p[1]= uy;
}
-static void project(bglMats *mats, const float v[3], short p[2])
+/*XXX: static void project(bglMats *mats, const float v[3], short p[2])
{
float f[2];
projectf(mats, v, f);
@@ -197,6 +189,120 @@ static void project(bglMats *mats, const float v[3], short p[2])
p[0]= f[0];
p[1]= f[1];
}
+*/
+
+/*** 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)
+{
+ float bb_min[3], bb_max[3], pmat[4][4];
+ int i, j, k;
+
+ view3d_get_object_project_mat(rv3d, ob, pmat);
+
+ BLI_pbvh_modified_bounding_box(ob->sculpt->tree, bb_min, bb_max);
+
+ rect->xmin = rect->ymin = INT_MAX;
+ rect->xmax = rect->ymax = INT_MIN;
+
+ for(i = 0; i < 2; ++i) {
+ for(j = 0; j < 2; ++j) {
+ for(k = 0; k < 2; ++k) {
+ float vec[3], proj[2];
+ vec[0] = i ? bb_min[0] : bb_max[0];
+ vec[1] = j ? bb_min[1] : bb_max[1];
+ vec[2] = k ? bb_min[2] : bb_max[2];
+ view3d_project_float(ar, vec, proj, pmat);
+ rect->xmin = MIN2(rect->xmin, proj[0]);
+ rect->xmax = MAX2(rect->xmax, proj[0]);
+ rect->ymin = MIN2(rect->ymin, proj[1]);
+ rect->ymax = MAX2(rect->ymax, proj[1]);
+ }
+ }
+ }
+
+ return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
+}
+
+void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
+ RegionView3D *rv3d, Object *ob)
+{
+ BoundBox *bb = MEM_callocN(sizeof(BoundBox), "sculpt boundbox");
+ bglMats mats;
+ int i;
+ rcti rect;
+
+ view3d_get_transformation(ar, rv3d, ob, &mats);
+ sculpt_get_redraw_rect(ar, rv3d,ob, &rect);
+ BLI_pbvh_reset_modified_bounding_box(ob->sculpt->tree);
+
+
+ rect.xmin += 2;
+ rect.xmax -= 2;
+ rect.ymin += 2;
+ rect.ymax -= 2;
+
+ view3d_calculate_clipping(bb, planes, &mats, &rect);
+
+ for(i = 0; i < 16; ++i)
+ ((float*)planes)[i] = -((float*)planes)[i];
+
+ MEM_freeN(bb);
+}
+
/* ===== Sculpting =====
*
@@ -306,12 +412,9 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_
{
float area_normal[3];
ActiveData *node= active_verts->first;
- float* buffer;
calc_area_normal(sd, ss, area_normal, active_verts);
- buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-
while(node){
float *co= ss->mvert[node->Index].co;
@@ -319,20 +422,10 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_
co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1],
co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]};
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
- }
-
sculpt_clip(sd, ss, co, val);
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
/* For the smooth brush, uses the neighboring vertices around vert to calculate
@@ -382,7 +475,6 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
{
ActiveData *node= active_verts->first;
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
int i;
for(i = 0; i < 2; ++i) {
@@ -396,24 +488,15 @@ static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active
val[2] = co[2]+(avg[2]-co[2])*node->Fade;
sculpt_clip(s, ss, co, val);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(s, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
- }
+
node= node->next;
}
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
{
ActiveData *node= active_verts->first;
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
while(node) {
float *co= ss->mvert[node->Index].co;
@@ -421,19 +504,9 @@ static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_
co[1]+(ss->cache->location[1]-co[1])*node->Fade,
co[2]+(ss->cache->location[2]-co[2])*node->Fade};
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(s, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
- }
-
sculpt_clip(s, ss, co, val);
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
static void do_grab_brush(Sculpt *sd, SculptSession *ss)
@@ -441,7 +514,6 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss)
ActiveData *node= ss->cache->grab_active_verts[ss->cache->symmetry].first;
float add[3];
float grab_delta[3];
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
VecCopyf(grab_delta, ss->cache->grab_delta_symmetry);
@@ -452,28 +524,16 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss)
VecMulf(add, node->Fade);
VecAddf(add, add, co);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], add);
- cur = cur->next;
- }
- }
-
sculpt_clip(sd, ss, co, add);
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
-
}
static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts)
{
float area_normal[3];
ActiveData *node= active_verts->first;
- float *buffer;
float lim= ss->cache->radius / 4;
if(ss->cache->flip)
@@ -481,7 +541,6 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
calc_area_normal(sd, ss, area_normal, active_verts);
- buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
while(node){
float *disp= &ss->layer_disps[node->Index];
float *co= ss->mvert[node->Index].co;
@@ -497,27 +556,16 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1];
val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2];
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
- }
-
sculpt_clip(sd, ss, co, val);
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts)
{
ActiveData *node= active_verts->first;
float add[3];
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
while(node) {
float *co= ss->mvert[node->Index].co;
@@ -532,20 +580,10 @@ static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *activ
add[2]*= ss->cache->scale[2];
VecAddf(add, add, co);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(s, ss, &buffer[cur->element*3], add);
- cur = cur->next;
- }
- }
-
sculpt_clip(s, ss, co, add);
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3])
@@ -606,7 +644,6 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
float area_normal[3];
float cntr[3], cntr2[3], bstr = 0;
int flip = 0;
- float *buffer;
calc_area_normal(sd, ss, area_normal, active_verts);
calc_flatten_center(ss, node, cntr);
@@ -619,8 +656,6 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
flip = bstr < 0;
}
- buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-
while(node){
float *co= ss->mvert[node->Index].co;
float intr[3], val[3];
@@ -646,21 +681,12 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
VecAddf(val, val, co);
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[node->Index];
- while( cur != 0 && cur->element != -1 ) {
- sculpt_clip(sd, ss, &buffer[cur->element*3], val);
- cur = cur->next;
- }
- }
sculpt_clip(sd, ss, co, val);
}
node= node->next;
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
/* Uses symm to selectively flip any axis of a coordinate. */
@@ -718,9 +744,8 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
}
/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len)
+static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
{
- Brush *br = paint_brush(&sd->paint);
MTex *tex = NULL;
float avg= 1;
@@ -795,111 +820,124 @@ static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const flo
return avg;
}
-/* Mark area around the brush as damaged. projverts are marked if they are
- inside the area and the damaged rectangle in 2D screen coordinates is
- added to damaged_rects. */
-static void sculpt_add_damaged_rect(SculptSession *ss)
+typedef struct {
+ SculptSession *ss;
+ float radius_squared;
+ ListBase *active_verts;
+} SculptSearchSphereData;
+
+/* Test AABB against sphere */
+static int sculpt_search_sphere_cb(float bb_min[3], float bb_max[3],
+ void *data_v)
{
- short p[2];
- RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode");
- const float radius = MAX2(ss->cache->pixel_radius, ss->cache->previous_pixel_radius);
- unsigned i;
+ SculptSearchSphereData *data = data_v;
+ float *center = data->ss->cache->location, nearest[3];
+ float t[3];
+ int i;
- /* Find center */
- project(ss->cache->mats, ss->cache->location, p);
- rn->r.xmin= p[0] - radius;
- rn->r.ymin= p[1] - radius;
- rn->r.xmax= p[0] + radius;
- rn->r.ymax= p[1] + radius;
+ for(i = 0; i < 3; ++i) {
+ if(bb_min[i] > center[i])
+ nearest[i] = bb_min[i];
+ else if(bb_max[i] < center[i])
+ nearest[i] = bb_max[i];
+ else
+ nearest[i] = center[i];
+ }
+
+ VecSubf(t, center, nearest);
- BLI_addtail(&ss->damaged_rects, rn);
+ return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
+}
- /* Update insides */
- for(i=0; i<ss->totvert; ++i) {
- if(!ss->projverts[i].inside) {
- if(ss->projverts[i].co[0] > rn->r.xmin && ss->projverts[i].co[1] > rn->r.ymin &&
- ss->projverts[i].co[0] < rn->r.xmax && ss->projverts[i].co[1] < rn->r.ymax) {
- ss->projverts[i].inside= 1;
- }
+static void sculpt_brush_hit_cb(const int *face_indices,
+ const int *vert_indices,
+ int totface, int totvert, void *data_v)
+{
+ SculptSearchSphereData *data = data_v;
+ int i;
+
+ /* XXX: for now we still make an active vert list,
+ can be fixed later */
+
+ for(i = 0; i < totvert; ++i) {
+ int v = vert_indices[i];
+ float delta[3], dsq;
+
+ VecSubf(delta, data->ss->mvert[v].co,
+ data->ss->cache->location);
+ dsq = Inpf(delta, delta);
+
+ if(dsq < data->radius_squared) {
+ ActiveData *adata =
+ (ActiveData*)MEM_mallocN(sizeof(ActiveData),
+ "ActiveData");
+ adata->Index = v;
+ adata->dist = sqrt(dsq);
+ BLI_addtail(data->active_verts, adata);
}
- // XXX: remember to fix this!
- // temporary pass
- ss->projverts[i].inside = 1;
}
}
static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
{
Brush *brush = paint_brush(&sd->paint);
- float av_dist;
- ListBase active_verts={0,0};
+ ListBase local_active_verts = {0, 0};
ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry];
- ActiveData *adata= 0;
- float *vert;
- Mesh *me= NULL; /*XXX: get_mesh(OBACT); */
+ ListBase *active_verts = &local_active_verts;
const float bstrength= brush_strength(sd, cache);
- KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
- Brush *b = brush;
- int i;
-
- sculpt_add_damaged_rect(ss);
+ //KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
+ ActiveData *adata;
+
+ /* For grab brush, only find active vertices once */
+ if(brush->sculpt_tool == SCULPT_TOOL_GRAB)
+ active_verts = grab_active_verts;
/* Build a list of all vertices that are potentially within the brush's
- area of influence. Only do this once for the grab brush. */
- if((b->sculpt_tool != SCULPT_TOOL_GRAB) || cache->first_time) {
- for(i=0; i<ss->totvert; ++i) {
- /* Projverts.inside provides a rough bounding box */
- if(ss->multires || ss->projverts[i].inside) {
- //vert= ss->vertexcosnos ? &ss->vertexcosnos[i*6] : a->verts[i].co;
- vert= ss->mvert[i].co;
- av_dist= VecLenf(ss->cache->location, vert);
- if(av_dist < cache->radius) {
- adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData");
-
- adata->Index = i;
- /* Fade is used to store the final strength at which the brush
- should modify a particular vertex. */
- adata->Fade= tex_strength(sd, ss, vert, av_dist) * bstrength;
- adata->dist = av_dist;
-
- if(b->sculpt_tool == SCULPT_TOOL_GRAB && cache->first_time)
- BLI_addtail(grab_active_verts, adata);
- else
- BLI_addtail(&active_verts, adata);
- }
- }
- }
+ area of influence */
+ if(brush->sculpt_tool != SCULPT_TOOL_GRAB || cache->first_time) {
+ SculptSearchSphereData data;
+ data.ss = ss;
+ data.radius_squared = ss->cache->radius * ss->cache->radius;
+ data.active_verts = active_verts;
+ BLI_pbvh_search(ss->tree, sculpt_search_sphere_cb, &data,
+ sculpt_brush_hit_cb, &data,
+ PBVH_SEARCH_MARK_MODIFIED);
+
+ /* Update brush strength for each vertex */
+ for(adata = active_verts->first; adata; adata = adata->next)
+ adata->Fade = tex_strength(ss, brush, ss->mvert[adata->Index].co, adata->dist) * bstrength;
}
/* Only act if some verts are inside the brush area */
- if(active_verts.first || (b->sculpt_tool == SCULPT_TOOL_GRAB && grab_active_verts->first)) {
+ if(active_verts->first) {
/* Apply one type of brush action */
- switch(b->sculpt_tool){
+ switch(brush->sculpt_tool){
case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ss, &active_verts);
+ do_draw_brush(sd, ss, active_verts);
break;
case SCULPT_TOOL_SMOOTH:
- do_smooth_brush(sd, ss, &active_verts);
+ do_smooth_brush(sd, ss, active_verts);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ss, &active_verts);
+ do_pinch_brush(sd, ss, active_verts);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ss, &active_verts);
+ do_inflate_brush(sd, ss, active_verts);
break;
case SCULPT_TOOL_GRAB:
do_grab_brush(sd, ss);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ss, &active_verts);
+ do_layer_brush(sd, ss, active_verts);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_clay_brush(sd, ss, &active_verts, 0);
+ do_flatten_clay_brush(sd, ss, active_verts, 0);
break;
case SCULPT_TOOL_CLAY:
- do_flatten_clay_brush(sd, ss, &active_verts, 1);
+ do_flatten_clay_brush(sd, ss, active_verts, 1);
}
+#if 0
/* Copy the modified vertices from mesh to the active key */
if(keyblock && !ss->multires) {
float *co= keyblock->data;
@@ -919,9 +957,13 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
BLI_freelistN(&active_verts);
else {
if(b->sculpt_tool != SCULPT_TOOL_GRAB)
- addlisttolist(&ss->damaged_verts, &active_verts);
+ addlisttolist(&ss->modified_verts, &active_verts);
}
- }
+#endif
+
+ BLI_freelistN(&local_active_verts);
+
+ }
}
/* Flip all the editdata across the axis/axes specified by symm. Used to
@@ -955,110 +997,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
cache->first_time = 0;
}
-static void add_face_normal(vec3f *norm, MVert *mvert, const MFace* face, float *fn)
-{
- vec3f c= {mvert[face->v1].co[0],mvert[face->v1].co[1],mvert[face->v1].co[2]};
- vec3f b= {mvert[face->v2].co[0],mvert[face->v2].co[1],mvert[face->v2].co[2]};
- vec3f a= {mvert[face->v3].co[0],mvert[face->v3].co[1],mvert[face->v3].co[2]};
- vec3f s1, s2;
- float final[3];
-
- VecSubf(&s1.x,&a.x,&b.x);
- VecSubf(&s2.x,&c.x,&b.x);
-
- final[0] = s1.y * s2.z - s1.z * s2.y;
- final[1] = s1.z * s2.x - s1.x * s2.z;
- final[2] = s1.x * s2.y - s1.y * s2.x;
-
- if(fn)
- VecCopyf(fn, final);
-
- norm->x+= final[0];
- norm->y+= final[1];
- norm->z+= final[2];
-}
-
-static void update_damaged_vert(SculptSession *ss, ListBase *lb)
-{
- ActiveData *vert;
-
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->normals ):0;
- for(vert= lb->first; vert; vert= vert->next) {
- vec3f norm= {0,0,0};
- IndexNode *face= ss->fmap[vert->Index].first;
-
- while(face){
- float *fn = NULL;
- if(ss->face_normals)
- fn = &ss->face_normals[face->index*3];
- add_face_normal(&norm, ss->mvert, &ss->mface[face->index], fn);
- face= face->next;
- }
- Normalize(&norm.x);
-
- ss->mvert[vert->Index].no[0]=norm.x*32767;
- ss->mvert[vert->Index].no[1]=norm.y*32767;
- ss->mvert[vert->Index].no[2]=norm.z*32767;
-
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[vert->Index];
- while( cur != 0 && cur->element != -1 ) {
- int i = ss->drawobject->faceRemap[cur->element/3];
- if( ss->mface[i].flag & ME_SMOOTH ) {
- VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
- }
- else {
- float norm[3];
- if( ss->mface[i].v4 )
- CalcNormFloat4(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, ss->mvert[ss->mface[i].v4].co, norm);
- else
- CalcNormFloat(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, norm);
- VECCOPY(&buffer[(cur->element-cur->element%3)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+1)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+2)*3],norm);
-
- /* maybe this was a quad - need to update the other triangle of the quad */
- if( ss->drawobject->faceRemap[cur->element/3-1] == i ) {
- VECCOPY(&buffer[(cur->element-cur->element%3-3)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3-2)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3-1)*3],norm);
- }
- if( ss->drawobject->faceRemap[cur->element/3+1] == i ) {
- VECCOPY(&buffer[(cur->element-cur->element%3+3)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+4)*3],norm);
- VECCOPY(&buffer[(cur->element-cur->element%3+5)*3],norm);
- }
- }
-
- //VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
- cur = cur->next;
- }
- }
- }
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->normals );
-}
-
-static void calc_damaged_verts(SculptSession *ss)
-{
- int i;
-
- for(i=0; i<8; ++i)
- update_damaged_vert(ss, &ss->cache->grab_active_verts[i]);
- update_damaged_vert(ss, &ss->damaged_verts);
- BLI_freelistN(&ss->damaged_verts);
- ss->damaged_verts.first = ss->damaged_verts.last = NULL;
-}
-
-#if 0
-static void projverts_clear_inside(SculptSession *ss)
-{
- int i;
- for(i = 0; i < ss->totvert; ++i)
- ss->projverts[i].inside = 0;
-}
-#endif
-
static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
{
Brush *brush = paint_brush(&sd->paint);
@@ -1076,20 +1014,6 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
}
}
-static void sculptmode_update_all_projverts(SculptSession *ss)
-{
- unsigned i;
-
- if(!ss->projverts)
- ss->projverts = MEM_mallocN(sizeof(ProjVert)*ss->totvert,"ProjVerts");
-
- for(i=0; i<ss->totvert; ++i) {
- project(ss->cache->mats, ss->vertexcosnos ? &ss->vertexcosnos[i * 6] : ss->mvert[i].co,
- ss->projverts[i].co);
- ss->projverts[i].inside= 0;
- }
-}
-
/* Checks whether full update mode (slower) needs to be used to work with modifiers */
char sculpt_modifiers_active(Object *ob)
{
@@ -1132,10 +1056,9 @@ static void sculpt_update_mesh_elements(bContext *C)
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
int oldtotvert = ss->totvert;
- DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
if((ss->multires = sculpt_multires_active(ob))) {
- //DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
+ 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);
@@ -1148,23 +1071,20 @@ static void sculpt_update_mesh_elements(bContext *C)
ss->totface = me->totface;
ss->mvert = me->mvert;
ss->mface = me->mface;
- ss->face_normals = NULL;
- }
- if( GPU_buffer_legacy( dm ) ) {
- ss->drawobject = 0;
- }
- else {
- ss->drawobject = dm->drawObject;
+ if(!ss->face_normals)
+ ss->face_normals = MEM_callocN(sizeof(float) * 3 * me->totface, "sculpt face normals");
}
- if(ss->totvert != oldtotvert) {
- if(ss->projverts) MEM_freeN(ss->projverts);
- ss->projverts = NULL;
+ 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);
}
}
@@ -1251,15 +1171,13 @@ static void SCULPT_OT_radial_control(wmOperatorType *ot)
/**** Operator for applying a stroke (various attributes including mouse path)
using the current brush. ****/
-static float unproject_brush_radius(SculptSession *ss, float offset)
+static float unproject_brush_radius(ViewContext *vc, float center[3], float offset)
{
- float brush_edge[3];
-
- /* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */
- view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
- ss->cache->initial_mouse[1], ss->cache->depth);
+ float delta[3];
- return VecLenf(ss->cache->true_location, brush_edge);
+ initgrabz(vc->rv3d, center[0], center[1], center[2]);
+ window_to_3d_delta(vc->ar, delta, offset, 0);
+ return VecLength(delta);
}
static void sculpt_cache_free(StrokeCache *cache)
@@ -1290,15 +1208,17 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
cache->flag = RNA_int_get(op->ptr, "flag");
RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance);
RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse);
- cache->depth = RNA_float_get(op->ptr, "depth");
cache->mouse[0] = cache->initial_mouse[0];
cache->mouse[1] = cache->initial_mouse[1];
/* Truly temporary data that isn't stored in properties */
+ cache->vc = vc;
+ cache->brush = brush;
+
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
- view3d_get_transformation(vc, vc->obact, cache->mats);
+ view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
sculpt_update_mesh_elements(C);
@@ -1338,14 +1258,14 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
}
}
- view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
- cache->initial_radius = unproject_brush_radius(ss, brush->size);
+ //view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
+ cache->initial_radius = unproject_brush_radius(vc, cache->true_location, brush->size);
cache->rotation = 0;
cache->first_time = 1;
}
/* Initialize the stroke cache variants from operator properties */
-static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerRNA *ptr)
+static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
@@ -1375,7 +1295,8 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
cache->pixel_radius = sqrt(dx*dx + dy*dy);
- cache->radius = unproject_brush_radius(ss, cache->pixel_radius);
+ cache->radius = unproject_brush_radius(paint_stroke_view_context(stroke),
+ cache->true_location, cache->pixel_radius);
cache->rotation = atan2(dy, dx);
}
else if(brush->flag & BRUSH_RAKE) {
@@ -1398,13 +1319,103 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
/* Find the grab delta */
if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+ // XXX: view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+ initgrabz(cache->vc->rv3d, cache->true_location[0], cache->true_location[1], cache->true_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
if(!cache->first_time)
VecSubf(cache->grab_delta, grab_location, cache->old_grab_location);
VecCopyf(cache->old_grab_location, grab_location);
}
}
+/* XXX: Code largely copied from bvhutils.c, should be unified */
+/* Returns 1 if a better intersection has been found */
+static int ray_face_intersection(float ray_start[3], float ray_normal[3],
+ float *t0, float *t1, float *t2, float *t3,
+ float *fdist)
+{
+ int hit = 0;
+
+ do
+ {
+ float dist = FLT_MAX;
+
+ if(!RayIntersectsTriangle(ray_start, ray_normal, t0, t1, t2,
+ &dist, NULL))
+ dist = FLT_MAX;
+
+ if(dist >= 0 && dist < *fdist) {
+ hit = 1;
+ *fdist = dist;
+ }
+
+ t1 = t2;
+ t2 = t3;
+ t3 = NULL;
+
+ } while(t2);
+
+ return hit;
+}
+
+typedef struct {
+ SculptSession *ss;
+ float *ray_start, *ray_normal;
+ int hit;
+ float dist;
+} SculptRaycastData;
+
+void sculpt_raycast_cb(const int *face_indices,
+ const int *vert_indices,
+ int totface, int totvert, void *data_v)
+{
+ SculptRaycastData *srd = data_v;
+ MVert *vert = srd->ss->mvert;
+ int i;
+
+ for(i = 0; i < totface; ++i) {
+ MFace *f = srd->ss->mface + face_indices[i];
+ if(ray_face_intersection(srd->ray_start, srd->ray_normal,
+ vert[f->v1].co,
+ vert[f->v2].co,
+ vert[f->v3].co,
+ f->v4 ? vert[f->v4].co : NULL,
+ &srd->dist)) {
+ srd->hit = face_indices[i];
+ }
+ }
+}
+
+/* Do a raycast in the tree to find the 3d brush location
+ (This allows us to ignore the GL depth buffer)
+ Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
+ */
+int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2])
+{
+ ViewContext *vc = paint_stroke_view_context(stroke);
+ float ray_start[3], ray_normal[3];
+ float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
+ mouse[1] - vc->ar->winrct.ymin};
+ SculptRaycastData srd;
+
+ viewray(vc->ar, vc->v3d, mval, ray_start, ray_normal);
+
+ srd.ss = vc->obact->sculpt;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.dist = FLT_MAX;
+ srd.hit = -1;
+ BLI_pbvh_raycast(vc->obact->sculpt->tree, sculpt_raycast_cb, &srd,
+ ray_start, ray_normal);
+
+ VecCopyf(out, ray_normal);
+ VecMulf(out, srd.dist);
+ VecAddf(out, out, ray_start);
+
+ return srd.hit != -1;
+}
+
/* Initialize stroke operator properties */
static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss)
{
@@ -1442,9 +1453,6 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
mouse[1] = event->y;
RNA_float_set_array(op->ptr, "initial_mouse", mouse);
- /* Initial screen depth under the mouse */
- RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y));
-
sculpt_update_cache_invariants(sd, ss, C, op);
}
@@ -1467,30 +1475,16 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
- float *buffer= NULL;
int i;
/* Restore the mesh before continuing with anchored stroke */
if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) {
-
- if(ss->drawobject)
- buffer= (float *)GPU_buffer_lock(ss->drawobject->normals);
-
for(i = 0; i < ss->totvert; ++i) {
VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]);
ss->mvert[i].no[0] = cache->orig_norms[i][0];
ss->mvert[i].no[1] = cache->orig_norms[i][1];
ss->mvert[i].no[2] = cache->orig_norms[i][2];
- if( buffer != 0 ) {
- IndexLink *cur = &ss->drawobject->indices[i];
- while( cur != 0 && cur->element != -1 ) {
- VECCOPY(&buffer[cur->element*3],cache->orig_norms[i]);
- cur = cur->next;
- }
- }
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->normals );
if(ss->face_normals) {
float *fn = ss->face_normals;
@@ -1503,20 +1497,14 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
}
}
-static void sculpt_post_stroke_free(SculptSession *ss)
-{
- BLI_freelistN(&ss->damaged_rects);
- BLI_freelistN(&ss->damaged_verts);
-}
-
static void sculpt_flush_update(bContext *C)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
-
- calc_damaged_verts(ss);
+ rcti r;
+ int redraw = 0;
if(mmd) {
if(mmd->undo_verts && mmd->undo_verts != ss->mvert)
@@ -1527,23 +1515,46 @@ static void sculpt_flush_update(bContext *C)
multires_mark_as_modified(ob);
}
- ED_region_tag_redraw(ar);
+ redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r);
+
+ if(!redraw) {
+ BLI_pbvh_search(ss->tree, BLI_pbvh_update_search_cb,
+ PBVH_NodeData, NULL, NULL,
+ PBVH_SEARCH_UPDATE);
+
+ redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C),
+ ob, &r);
+ }
+
+ if(redraw) {
+ r.xmin += ar->winrct.xmin + 1;
+ r.xmax += ar->winrct.xmin - 1;
+ r.ymin += ar->winrct.ymin + 1;
+ r.ymax += ar->winrct.ymin - 1;
+
+ ss->partial_redraw = 1;
+ ED_region_tag_redraw_partial(ar, &r);
+ }
}
static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
{
- ViewContext vc;
- float cur_depth;
-
- view3d_set_viewcontext(C, &vc);
- cur_depth = read_cached_depth(&vc, event->x, event->y);
+ float mouse[2] = {event->x, event->y}, location[3];
+ int over_mesh;
- /* Don't start the stroke until a valid depth is found */
- if(cur_depth < 1.0 - FLT_EPSILON) {
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ over_mesh = sculpt_stroke_get_location(C, op->customdata, location, mouse);
+
+ /* Don't start the stroke until mouse goes over the mesh */
+ if(over_mesh) {
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if(paint_brush(&CTX_data_tool_settings(C)->sculpt->paint)->sculpt_tool == SCULPT_TOOL_GRAB)
+ BLI_pbvh_toggle_modified_lock(ss->tree);
+
+ ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
sculpt_brush_stroke_init_properties(C, op, event, ss);
- sculptmode_update_all_projverts(ss);
return 1;
}
@@ -1556,13 +1567,12 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
- sculpt_update_cache_variants(sd, ss, itemptr);
+ sculpt_update_cache_variants(sd, ss, stroke, itemptr);
sculpt_restore_mesh(sd, ss);
do_symmetrical_brush_actions(sd, ss);
/* Cleanup */
sculpt_flush_update(C);
- sculpt_post_stroke_free(ss);
}
static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
@@ -1571,9 +1581,11 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
/* Finished */
if(ss->cache) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ if(paint_brush(&CTX_data_tool_settings(C)->sculpt->paint)->sculpt_tool == SCULPT_TOOL_GRAB)
+ BLI_pbvh_toggle_modified_lock(ss->tree);
- request_depth_update(paint_stroke_view_context(stroke)->rv3d);
sculpt_cache_free(ss->cache);
ss->cache = NULL;
sculpt_undo_push(C, sd);
@@ -1584,7 +1596,8 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
{
sculpt_brush_stroke_init(C);
- op->customdata = paint_stroke_new(C, sculpt_stroke_test_start,
+ op->customdata = paint_stroke_new(C, sculpt_stroke_get_location,
+ sculpt_stroke_test_start,
sculpt_stroke_update_step,
sculpt_stroke_done);
@@ -1601,12 +1614,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
- op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done);
+ op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
+ sculpt_stroke_update_step, sculpt_stroke_done);
sculpt_brush_stroke_init(C);
sculpt_update_cache_invariants(sd, ss, C, op);
- sculptmode_update_all_projverts(ss);
paint_stroke_exec(C, op);
@@ -1649,9 +1662,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* The initial 2D location of the mouse */
RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
-
- /* The initial screen depth of the mouse */
- RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX);
}
/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
@@ -1688,6 +1698,13 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
/**** Toggle operator for turning sculpt mode on or off ****/
+static void sculpt_init_session(bContext *C, Object *ob)
+{
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+
+ sculpt_update_mesh_elements(C);
+}
+
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1713,7 +1730,8 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
/* Create sculpt mode session data */
if(ob->sculpt)
free_sculptsession(&ob->sculpt);
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+
+ sculpt_init_session(C, ob);
paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 22fd77afd88..5d7e5932bd8 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -107,6 +107,7 @@
#include "ED_mesh.h"
#include "ED_particle.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
#include "ED_types.h"
#include "ED_util.h"
@@ -2691,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, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, NULL, GPU_enable_material);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GPU_disable_material();
}
@@ -2710,7 +2711,7 @@ static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmoot
return 1;
}
-static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
+static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
{
Object *ob= base->object;
Mesh *me = ob->data;
@@ -2783,7 +2784,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
}
}
else if(dt==OB_SOLID) {
- if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire)
+ if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
draw_mesh_object_outline(v3d, ob, dm);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
@@ -2791,7 +2792,21 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
- dm->drawFacesSolid(dm, GPU_enable_material);
+ if(ob->sculpt) {
+ float planes[4][4];
+ float (*fpl)[4] = NULL;
+
+ if(ob->sculpt->partial_redraw) {
+ sculpt_get_redraw_planes(planes, ar, rv3d, ob);
+ fpl = planes;
+ ob->sculpt->partial_redraw = 0;
+ }
+
+ dm->drawFacesSolid(dm, ob->sculpt->tree, fpl, GPU_enable_material);
+ }
+ else
+ dm->drawFacesSolid(dm, NULL, NULL, GPU_enable_material);
+
GPU_disable_material();
glFrontFace(GL_CCW);
@@ -2802,7 +2817,8 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
} else {
UI_ThemeColor(TH_WIRE);
}
- dm->drawLooseEdges(dm);
+ if(!ob->sculpt)
+ dm->drawLooseEdges(dm);
}
else if(dt==OB_SHADED) {
int do_draw= 1; /* to resolve all G.f settings below... */
@@ -2920,7 +2936,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
}
/* returns 1 if nothing was drawn, for detecting to draw an object center */
-static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
+static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
{
Object *ob= base->object;
Object *obedit= scene->obedit;
@@ -2970,7 +2986,7 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
(check_alpha)? &do_alpha_pass: NULL);
}
- draw_mesh_fancy(scene, v3d, rv3d, base, dt, flag);
+ draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, flag);
GPU_end_object_materials();
@@ -5566,7 +5582,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
switch( ob->type) {
case OB_MESH:
- empty_object= draw_mesh_object(scene, v3d, rv3d, base, dt, flag);
+ empty_object= draw_mesh_object(scene, ar, v3d, rv3d, base, dt, flag);
if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself
break;
@@ -6260,7 +6276,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
glEnable(GL_LIGHTING);
if(dm) {
- dm->drawFacesSolid(dm, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, NULL, GPU_enable_material);
GPU_end_object_materials();
}
else if(edm)
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 15e41a66981..05de5ce1169 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1642,37 +1642,6 @@ void view3d_update_depths(ARegion *ar, View3D *v3d)
}
}
-/* Enable sculpting in wireframe mode by drawing sculpt object only to the depth buffer */
-static void draw_sculpt_depths(Scene *scene, ARegion *ar, View3D *v3d)
-{
- Object *ob = OBACT;
-
- int dt= MIN2(v3d->drawtype, ob->dt);
- if(v3d->zbuf==0 && dt>OB_WIRE)
- dt= OB_WIRE;
- if(dt == OB_WIRE) {
- GLboolean depth_on;
- int orig_vdt = v3d->drawtype;
- int orig_zbuf = v3d->zbuf;
- int orig_odt = ob->dt;
-
- glGetBooleanv(GL_DEPTH_TEST, &depth_on);
- v3d->drawtype = ob->dt = OB_SOLID;
- v3d->zbuf = 1;
-
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glEnable(GL_DEPTH_TEST);
- draw_object(scene, ar, v3d, BASACT, 0);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- if(!depth_on)
- glDisable(GL_DEPTH_TEST);
-
- v3d->drawtype = orig_vdt;
- v3d->zbuf = orig_zbuf;
- ob->dt = orig_odt;
- }
-}
-
void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (* func)(void *))
{
RegionView3D *rv3d= ar->regiondata;
@@ -2038,7 +2007,7 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
}
// retopo= retopo_mesh_check() || retopo_curve_check();
- sculptparticle= (obact && obact->mode & (OB_MODE_SCULPT|OB_MODE_PARTICLE_EDIT)) && !scene->obedit;
+ sculptparticle= (obact && obact->mode & (OB_MODE_PARTICLE_EDIT)) && !scene->obedit;
if(retopo)
view3d_update_depths(ar, v3d);
@@ -2051,8 +2020,6 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
}
if(!retopo && sculptparticle && !(obact && (obact->dtx & OB_DRAWXRAY))) {
- if(obact && obact->mode & OB_MODE_SCULPT)
- draw_sculpt_depths(scene, ar, v3d);
view3d_update_depths(ar, v3d);
}
@@ -2067,8 +2034,6 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
view3d_draw_xray(scene, ar, v3d, 1); // clears zbuffer if it is used!
if(!retopo && sculptparticle && (obact && (OBACT->dtx & OB_DRAWXRAY))) {
- if(obact && obact->mode & OB_MODE_SCULPT)
- draw_sculpt_depths(scene, ar, v3d);
view3d_update_depths(ar, v3d);
}
@@ -2090,8 +2055,6 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
ED_region_pixelspace(ar);
- /* Draw Sculpt Mode brush XXX (removed) */
-
// retopo_paint_view_update(v3d);
// retopo_draw_paint_lines();
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 51f257da432..45aa2434897 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -1802,12 +1802,9 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot)
static int view3d_clipping_exec(bContext *C, wmOperator *op)
{
RegionView3D *rv3d= CTX_wm_region_view3d(C);
+ ViewContext vc;
+ bglMats mats;
rcti rect;
- double mvmatrix[16];
- double projmatrix[16];
- double xs, ys, p[3];
- GLint viewport[4];
- short val;
rect.xmin= RNA_int_get(op->ptr, "xmin");
rect.ymin= RNA_int_get(op->ptr, "ymin");
@@ -1820,44 +1817,10 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op)
/* note; otherwise opengl won't work */
view3d_operator_needs_opengl(C);
- /* Get the matrices needed for gluUnProject */
- glGetIntegerv(GL_VIEWPORT, viewport);
- glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
- glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
-
- /* near zero floating point values can give issues with gluUnProject
- in side view on some implementations */
- if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
- if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
-
- /* Set up viewport so that gluUnProject will give correct values */
- viewport[0] = 0;
- viewport[1] = 0;
-
- /* four clipping planes and bounding volume */
- /* first do the bounding volume */
- for(val=0; val<4; val++) {
-
- xs= (val==0||val==3)?rect.xmin:rect.xmax;
- ys= (val==0||val==1)?rect.ymin:rect.ymax;
-
- gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
- VECCOPY(rv3d->clipbb->vec[val], p);
+ view3d_set_viewcontext(C, &vc);
+ view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
+ view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
- gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
- VECCOPY(rv3d->clipbb->vec[4+val], p);
- }
-
- /* then plane equations */
- for(val=0; val<4; val++) {
-
- CalcNormFloat(rv3d->clipbb->vec[val], rv3d->clipbb->vec[val==3?0:val+1], rv3d->clipbb->vec[val+4],
- rv3d->clip[val]);
-
- rv3d->clip[val][3]= - rv3d->clip[val][0]*rv3d->clipbb->vec[val][0]
- - rv3d->clip[val][1]*rv3d->clipbb->vec[val][1]
- - rv3d->clip[val][2]*rv3d->clipbb->vec[val][2];
- }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index b13d83c0157..1f7d50e00ed 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -124,24 +124,24 @@ void view3d_get_view_aligned_coordinate(ViewContext *vc, float *fp, short mval[2
}
}
-void view3d_get_transformation(ViewContext *vc, Object *ob, bglMats *mats)
+void view3d_get_transformation(ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats)
{
float cpy[4][4];
int i, j;
- Mat4MulMat4(cpy, ob->obmat, vc->rv3d->viewmat);
+ Mat4MulMat4(cpy, ob->obmat, rv3d->viewmat);
for(i = 0; i < 4; ++i) {
for(j = 0; j < 4; ++j) {
- mats->projection[i*4+j] = vc->rv3d->winmat[i][j];
+ mats->projection[i*4+j] = rv3d->winmat[i][j];
mats->modelview[i*4+j] = cpy[i][j];
}
}
- mats->viewport[0] = vc->ar->winrct.xmin;
- mats->viewport[1] = vc->ar->winrct.ymin;
- mats->viewport[2] = vc->ar->winx;
- mats->viewport[3] = vc->ar->winy;
+ mats->viewport[0] = ar->winrct.xmin;
+ mats->viewport[1] = ar->winrct.ymin;
+ mats->viewport[2] = ar->winx;
+ mats->viewport[3] = ar->winy;
}
/* ********************** view3d_select: selection manipulations ********************* */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 12654bdac14..77833ceb5c5 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -481,6 +481,45 @@ void VIEW3D_OT_setobjectascamera(wmOperatorType *ot)
}
/* ********************************** */
+void view3d_calculate_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
+{
+ double xs, ys, p[3];
+ short val;
+
+ /* near zero floating point values can give issues with gluUnProject
+ in side view on some implementations */
+ if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
+ if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
+
+ /* Set up viewport so that gluUnProject will give correct values */
+ mats->viewport[0] = 0;
+ mats->viewport[1] = 0;
+
+ /* four clipping planes and bounding volume */
+ /* first do the bounding volume */
+ for(val=0; val<4; val++) {
+ xs= (val==0||val==3)?rect->xmin:rect->xmax;
+ ys= (val==0||val==1)?rect->ymin:rect->ymax;
+
+ gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
+ VECCOPY(bb->vec[val], p);
+
+ gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
+ VECCOPY(bb->vec[4+val], p);
+ }
+
+ /* then plane equations */
+ for(val=0; val<4; val++) {
+
+ CalcNormFloat(bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4],
+ planes[val]);
+
+ planes[val][3]= - planes[val][0]*bb->vec[val][0]
+ - planes[val][1]*bb->vec[val][1]
+ - planes[val][2]*bb->vec[val][2];
+ }
+}
+
/* create intersection coordinates in view Z direction at mouse coordinates */
void viewline(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float ray_end[3])
{
diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h
index 662912f9c19..eceb0cdeca4 100644
--- a/source/blender/gpu/gpu_buffers.h
+++ b/source/blender/gpu/gpu_buffers.h
@@ -43,6 +43,7 @@
#endif
struct DerivedMesh;
+struct GHash;
/* V - vertex, N - normal, T - uv, C - color
F - float, UB - unsigned byte */
@@ -124,6 +125,16 @@ void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
void GPU_drawobject_free( struct DerivedMesh *dm );
+/* Buffers for non-DerivedMesh drawing */
+void *GPU_build_buffers(struct GHash *map, struct MVert *mvert,
+ struct MFace *mface, int *face_indices,
+ int totface, int *vert_indices, int uniq_verts,
+ int totvert);
+void GPU_draw_buffers(void *buffers);
+void GPU_update_buffers(void *buffers, struct MVert *mvert,
+ int *vert_indices, int totvert);
+void GPU_free_buffers(void *buffers);
+
/* called before drawing */
void GPU_vertex_setup( struct DerivedMesh *dm );
void GPU_normal_setup( struct DerivedMesh *dm );
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 9e164f46e4c..14f2c1b6d5b 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
+#include "BLI_ghash.h"
#include "DNA_meshdata_types.h"
@@ -376,6 +377,156 @@ void GPU_drawobject_free( DerivedMesh *dm )
dm->drawObject = 0;
}
+/* Convenience struct for building the VBO.
+ TODO: check that (lack-of) padding is OK,
+ also check performance of short vs float for normals */
+typedef struct {
+ float co[3];
+ short no[3];
+
+ char pad[14];
+} VertexBufferFormat;
+
+typedef struct {
+ unsigned int vert_buf, tri_buf;
+ unsigned short tot_tri;
+} GPU_Buffers;
+
+void GPU_update_buffers2(void *buffers_v, MVert *mvert,
+ int *vert_indices, int totvert)
+{
+ GPU_Buffers *buffers = buffers_v;
+ VertexBufferFormat *vert_data;
+ int i;
+
+ vert_data = MEM_callocN(sizeof(VertexBufferFormat) * totvert, "bad");
+
+ for(i = 0; i < totvert; ++i) {
+ MVert *v = mvert + vert_indices[i];
+ VertexBufferFormat *out = vert_data + i;
+
+ VecCopyf(out->co, v->co);
+ memcpy(out->no, v->no, sizeof(short) * 3);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers->vert_buf);
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(VertexBufferFormat) * totvert,
+ vert_data, GL_STATIC_DRAW);
+
+ MEM_freeN(vert_data);
+}
+
+void GPU_update_buffers(void *buffers_v, MVert *mvert,
+ int *vert_indices, int totvert)
+{
+ GPU_Buffers *buffers = buffers_v;
+ VertexBufferFormat *vert_data;
+ int i;
+
+ /* Build VBO */
+ glBindBuffer(GL_ARRAY_BUFFER, buffers->vert_buf);
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(VertexBufferFormat) * totvert,
+ NULL, GL_STATIC_DRAW);
+ vert_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+ for(i = 0; i < totvert; ++i) {
+ MVert *v = mvert + vert_indices[i];
+ VertexBufferFormat *out = vert_data + i;
+
+ VecCopyf(out->co, v->co);
+ memcpy(out->no, v->no, sizeof(short) * 3);
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ //printf("node updated %p\n", buffers_v);
+}
+
+void *GPU_build_buffers(GHash *map, MVert *mvert, MFace *mface,
+ int *face_indices, int totface,
+ int *vert_indices, int tot_uniq_verts,
+ int totvert)
+{
+ GPU_Buffers *buffers;
+ unsigned short *tri_data;
+ int i, j, k, tottri;
+
+ buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
+
+ /* Count the number of triangles */
+ for(i = 0, tottri = 0; i < totface; ++i)
+ tottri += mface[face_indices[i]].v4 ? 2 : 1;
+
+ /* Generate index buffer object */
+ glGenBuffers(1, &buffers->tri_buf);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers->tri_buf);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW);
+
+ /* Fill the triangle buffer */
+ tri_data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ for(i = 0; i < totface; ++i) {
+ MFace *f = mface + face_indices[i];
+ int v[3] = {f->v1, f->v2, f->v3};
+
+ for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
+ for(k = 0; k < 3; ++k) {
+ void *value, *key = SET_INT_IN_POINTER(v[k]);
+ int vbo_index;
+
+ value = BLI_ghash_lookup(map, key);
+ vbo_index = GET_INT_FROM_POINTER(value);
+
+ if(vbo_index < 0) {
+ vbo_index = -vbo_index +
+ tot_uniq_verts - 1;
+ }
+
+ *tri_data = vbo_index;
+ ++tri_data;
+ }
+ v[0] = f->v4;
+ v[1] = f->v1;
+ v[2] = f->v3;
+ }
+ }
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* Build VBO */
+ glGenBuffers(1, &buffers->vert_buf);
+ GPU_update_buffers(buffers, mvert, vert_indices, totvert);
+
+ buffers->tot_tri = tottri;
+
+ return buffers;
+}
+
+void GPU_draw_buffers(void *buffers_v)
+{
+ GPU_Buffers *buffers = buffers_v;
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffers->vert_buf);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers->tri_buf);
+
+ glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), 0);
+ glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)12);
+
+ glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, GL_UNSIGNED_SHORT, 0);
+}
+
+void GPU_free_buffers(void *buffers_v)
+{
+ if(buffers_v) {
+ GPU_Buffers *buffers = buffers_v;
+
+ glDeleteBuffers(1, &buffers->vert_buf);
+ glDeleteBuffers(1, &buffers->tri_buf);
+
+ MEM_freeN(buffers);
+ }
+}
+
GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
{
GPUBuffer *buffer;