Commit of the sculpt patch (#19672). Further development will be in this branch until we merge to trunk.

This commit is contained in:
Nicholas Bishop
2009-10-27 19:53:34 +00:00
parent b2c2dafb68
commit 93beb0b85a
25 changed files with 1485 additions and 480 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

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, 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);

View File

@@ -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);

View File

@@ -28,6 +28,7 @@ FILE(GLOB SRC intern/*.c)
SET(INC
. ../makesdna ../blenkernel ../../../intern/guardedalloc ../include
../gpu
${FREETYPE_INCLUDE_DIRS}
${ZLIB_INC}
)

View File

@@ -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 = ''

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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");
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);
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);
}
}
}
/* 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->tree)
BLI_pbvh_set_source(ss->tree, ss->mvert, ss->mface);
if(ss->totvert != oldtotvert) {
if(ss->projverts) MEM_freeN(ss->projverts);
ss->projverts = NULL;
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];
float delta[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);
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);

View File

@@ -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)

View File

@@ -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();

View File

@@ -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);
view3d_set_viewcontext(C, &vc);
view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
/* 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);
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;
}

View File

@@ -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 ********************* */

View File

@@ -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])
{

View File

@@ -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 );

View File

@@ -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;