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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/ED_sculpt.h16
-rw-r--r--source/blender/editors/include/ED_view3d.h6
-rw-r--r--source/blender/editors/mesh/editface.c10
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modifier.c122
-rw-r--r--source/blender/editors/object/object_ops.c17
-rw-r--r--source/blender/editors/physics/particle_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c212
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h14
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c70
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c235
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1981
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h6
-rw-r--r--source/blender/editors/space_file/file_draw.c2
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c46
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c41
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c74
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c49
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/util/undo.c6
26 files changed, 1841 insertions, 1104 deletions
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 764efb4ef0c..aae79e9a1de 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -28,18 +28,28 @@
#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);
+void ED_sculpt_force_update(struct bContext *C);
/* paint_ops.c */
void ED_operatortypes_paint(void);
void ED_keymap_paint(struct wmKeyConfig *keyconf);
-/* paint_image.c */
-void undo_imagepaint_step(int step);
-void undo_imagepaint_clear(void);
+/* paint_undo.c */
+#define UNDO_PAINT_IMAGE 0
+#define UNDO_PAINT_MESH 1
+
+void ED_undo_paint_step(struct bContext *C, int type, int step);
+void ED_undo_paint_free(void);
#endif
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 0e7f55bef8d..13ef235d8fe 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);
@@ -131,7 +135,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/mesh/editface.c b/source/blender/editors/mesh/editface.c
index d034fe4a783..d7df018acd7 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -99,15 +99,17 @@ void object_facesel_flush_dm(Object *ob)
int totface;
int i;
-
- if(me==NULL || dm==NULL || !CustomData_has_layer( &dm->faceData, CD_ORIGINDEX))
+ if(me==NULL || dm==NULL)
+ return;
+
+ index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+
+ if(!index_array)
return;
faces = dm->getFaceArray(dm);
totface = dm->getNumFaces(dm);
- index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
-
mf= faces;
for (i= 0; i<totface; i++, mf++) { /* loop over derived mesh faces */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index c87210d6070..848855da1b0 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -143,6 +143,8 @@ void OBJECT_OT_modifier_convert(struct wmOperatorType *ot);
void OBJECT_OT_modifier_copy(struct wmOperatorType *ot);
void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
+void OBJECT_OT_multires_save_external(struct wmOperatorType *ot);
+void OBJECT_OT_multires_pack_external(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 14c342d4ecd..a1e70c011fe 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_util.h"
#include "BKE_action.h"
#include "BKE_curve.h"
@@ -187,6 +188,12 @@ int ED_object_modifier_remove(ReportList *reports, Scene *scene, Object *ob, Mod
else if(md->type == eModifierType_Smoke) {
ob->dt = OB_TEXTURE;
}
+ else if(md->type == eModifierType_Multires) {
+ Mesh *me= ob->data;
+
+ CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
+ CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface);
+ }
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
@@ -414,7 +421,7 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tesselated/bevel vertices");
- if (!(md->mode&eModifierMode_Realtime) || (mti->isDisabled && mti->isDisabled(md))) {
+ if (!(md->mode&eModifierMode_Realtime) || (mti->isDisabled && mti->isDisabled(md, 0))) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
return 0;
}
@@ -745,6 +752,13 @@ void OBJECT_OT_modifier_copy(wmOperatorType *ot)
/************* multires delete higher levels operator ****************/
+static int multires_poll(bContext *C)
+{
+ PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_MultiresModifier);
+ ID *id= ptr.id.data;
+ return (ptr.data && id && !id->lib);
+}
+
static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_MultiresModifier);
@@ -763,8 +777,8 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
{
ot->name= "Delete Higher Levels";
ot->idname= "OBJECT_OT_multires_higher_levels_delete";
- ot->poll= ED_operator_object_active_editable;
+ ot->poll= multires_poll;
ot->exec= multires_higher_levels_delete_exec;
/* flags */
@@ -779,27 +793,113 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
Object *ob= ptr.id.data;
MultiresModifierData *mmd= ptr.data;
- multiresModifier_subdivide(mmd, ob, 1, 0, mmd->simple);
+ multiresModifier_subdivide(mmd, ob, 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;
}
-static int multires_subdivide_poll(bContext *C)
-{
- PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_MultiresModifier);
- ID *id= ptr.id.data;
- return (ptr.data && id && !id->lib);
-}
-
void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
{
ot->name= "Multires Subdivide";
ot->description= "Add a new level of subdivision.";
ot->idname= "OBJECT_OT_multires_subdivide";
+ ot->poll= multires_poll;
ot->exec= multires_subdivide_exec;
- ot->poll= multires_subdivide_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/****************** multires save external operator *********************/
+
+static int multires_save_external_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_MultiresModifier);
+ Object *ob= ptr.id.data;
+ Mesh *me= (ob)? ob->data: op->customdata;
+ char path[FILE_MAX];
+
+ if(CustomData_external_test(&me->fdata, CD_MDISPS))
+ return OPERATOR_CANCELLED;
+
+ RNA_string_get(op->ptr, "path", path);
+ if(G.save_over)
+ BLI_makestringcode(G.sce, path); /* make relative */
+
+ CustomData_external_add(&me->fdata, &me->id, CD_MDISPS, me->totface, path);
+ CustomData_external_write(&me->fdata, &me->id, CD_MASK_MESH, me->totface, 0);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_save_external_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_MultiresModifier);
+ Object *ob= ptr.id.data;
+ Mesh *me= ob->data;
+ char path[FILE_MAX];
+
+ if(CustomData_external_test(&me->fdata, CD_MDISPS))
+ return OPERATOR_CANCELLED;
+
+ if(RNA_property_is_set(op->ptr, "path"))
+ return multires_save_external_exec(C, op);
+
+ op->customdata= me;
+
+ BLI_snprintf(path, sizeof(path), "//%s.btx", me->id.name+2);
+ RNA_string_set(op->ptr, "path", path);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void OBJECT_OT_multires_save_external(wmOperatorType *ot)
+{
+ ot->name= "Multires Save External";
+ ot->description= "Save displacements to an external file.";
+ ot->idname= "OBJECT_OT_multires_save_external";
+
+ ot->poll= multires_poll;
+ ot->exec= multires_save_external_exec;
+ ot->invoke= multires_save_external_invoke;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(ot, FOLDERFILE|BTXFILE, FILE_SPECIAL);
+}
+
+/****************** multires pack operator *********************/
+
+static int multires_pack_external_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_MultiresModifier);
+ Object *ob= ptr.id.data;
+ Mesh *me= ob->data;
+
+ if(!CustomData_external_test(&me->fdata, CD_MDISPS))
+ return OPERATOR_CANCELLED;
+
+ // XXX don't remove..
+ CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_multires_pack_external(wmOperatorType *ot)
+{
+ ot->name= "Multires Pack External";
+ ot->description= "Pack displacements from an external file.";
+ ot->idname= "OBJECT_OT_multires_pack_external";
+
+ ot->poll= multires_poll;
+ ot->exec= multires_pack_external_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 66a03d4aec5..8def741ed2b 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -136,6 +136,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_modifier_copy);
WM_operatortype_append(OBJECT_OT_multires_subdivide);
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
+ WM_operatortype_append(OBJECT_OT_multires_save_external);
+ WM_operatortype_append(OBJECT_OT_multires_pack_external);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
@@ -227,6 +229,7 @@ void ED_keymap_object(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
wmKeyMapItem *kmi;
+ int i;
/* Objects, Regardless of Mode -------------------------------------------------- */
keymap= WM_keymap_find(keyconf, "Object Non-modal", 0, 0);
@@ -314,16 +317,10 @@ void ED_keymap_object(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "GROUP_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subsurf_set", ONEKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", 1);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subsurf_set", TWOKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", 2);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subsurf_set", THREEKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", 3);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subsurf_set", FOURKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", 4);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subsurf_set", FIVEKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", 5);
+ for(i=1; i<=5; i++) {
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY+i, KM_PRESS, KM_CTRL, 0);
+ RNA_int_set(kmi->ptr, "level", i);
+ }
/* Lattice -------------------------------------------------------------------- */
keymap= WM_keymap_find(keyconf, "Lattice", 0, 0);
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 7c6b3a5ee26..ac986ba7df6 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_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 55f7a6a23b9..1f0d158ece9 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -86,6 +86,7 @@
#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
#include "ED_view3d.h"
#include "WM_api.h"
@@ -113,8 +114,6 @@
#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
#define IMAPAINT_TILE_NUMBER(size) (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
-#define MAXUNDONAME 64
-
static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
@@ -204,7 +203,7 @@ typedef struct ProjPaintImage {
Image *ima;
ImBuf *ibuf;
ImagePaintPartialRedraw *partRedrawRect;
- struct UndoTile **undoRect; /* only used to build undo tiles after painting */
+ void **undoRect; /* only used to build undo tiles after painting */
int touch;
} ProjPaintImage;
@@ -332,32 +331,20 @@ typedef struct ProjPixelClone {
/* Finish projection painting structs */
+typedef struct UndoImageTile {
+ struct UndoImageTile *next, *prev;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
-typedef struct UndoTile {
- struct UndoTile *next, *prev;
- ID id;
void *rect;
int x, y;
-} UndoTile;
-
-typedef struct UndoElem {
- struct UndoElem *next, *prev;
- char name[MAXUNDONAME];
- uintptr_t undosize;
+} UndoImageTile;
- ImBuf *ibuf;
- ListBase tiles;
-} UndoElem;
-
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
/* UNDO */
-/* internal functions */
-
-static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
{
/* copy or swap contents of tile->rect and region in ibuf->rect */
IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE,
@@ -374,49 +361,52 @@ static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int rest
tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
}
-static UndoTile *undo_init_tile(ID *id, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
{
- UndoTile *tile;
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
int allocsize;
+
+ for(tile=lb->first; tile; tile=tile->next)
+ if(tile->x == x_tile && tile->y == y_tile && strcmp(tile->idname, ima->id.name)==0)
+ return tile->rect;
if (*tmpibuf==NULL)
*tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0);
- tile= MEM_callocN(sizeof(UndoTile), "ImaUndoTile");
- tile->id= *id;
+ tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
+ strcpy(tile->idname, ima->id.name);
tile->x= x_tile;
tile->y= y_tile;
allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4;
allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char);
- tile->rect= MEM_mapallocN(allocsize, "ImaUndoRect");
+ tile->rect= MEM_mapallocN(allocsize, "UndeImageTile.rect");
undo_copy_tile(tile, *tmpibuf, ibuf, 0);
- curundo->undosize += allocsize;
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
- BLI_addtail(&curundo->tiles, tile);
+ BLI_addtail(lb, tile);
- return tile;
+ return tile->rect;
}
-static void undo_restore(UndoElem *undo)
+static void image_undo_restore(bContext *C, ListBase *lb)
{
+ Main *bmain= CTX_data_main(C);
Image *ima = NULL;
ImBuf *ibuf, *tmpibuf;
- UndoTile *tile;
-
- if(!undo)
- return;
+ UndoImageTile *tile;
tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
IB_rectfloat|IB_rect, 0);
- for(tile=undo->tiles.first; tile; tile=tile->next) {
+ for(tile=lb->first; tile; tile=tile->next) {
/* find image based on name, pointer becomes invalid with global undo */
- if(ima && strcmp(tile->id.name, ima->id.name)==0);
+ if(ima && strcmp(tile->idname, ima->id.name)==0);
else {
- for(ima=G.main->image.first; ima; ima=ima->id.next)
- if(strcmp(tile->id.name, ima->id.name)==0)
+ for(ima=bmain->image.first; ima; ima=ima->id.next)
+ if(strcmp(tile->idname, ima->id.name)==0)
break;
}
@@ -435,117 +425,12 @@ static void undo_restore(UndoElem *undo)
IMB_freeImBuf(tmpibuf);
}
-static void undo_free(UndoElem *undo)
+static void image_undo_free(ListBase *lb)
{
- UndoTile *tile;
+ UndoImageTile *tile;
- for(tile=undo->tiles.first; tile; tile=tile->next)
+ for(tile=lb->first; tile; tile=tile->next)
MEM_freeN(tile->rect);
- BLI_freelistN(&undo->tiles);
-}
-
-static void undo_imagepaint_push_begin(char *name)
-{
- UndoElem *uel;
- int nr;
-
- /* Undo push is split up in begin and end, the reason is that as painting
- * happens more tiles are added to the list, and at the very end we know
- * how much memory the undo used to remove old undo elements */
-
- /* remove all undos after (also when curundo==NULL) */
- while(undobase.last != curundo) {
- uel= undobase.last;
- undo_free(uel);
- BLI_freelinkN(&undobase, uel);
- }
-
- /* make new */
- curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
- BLI_addtail(&undobase, uel);
-
- /* name can be a dynamic string */
- strncpy(uel->name, name, MAXUNDONAME-1);
-
- /* limit amount to the maximum amount*/
- nr= 0;
- uel= undobase.last;
- while(uel) {
- nr++;
- if(nr==U.undosteps) break;
- uel= uel->prev;
- }
- if(uel) {
- while(undobase.first!=uel) {
- UndoElem *first= undobase.first;
- undo_free(first);
- BLI_freelinkN(&undobase, first);
- }
- }
-}
-
-static void undo_imagepaint_push_end()
-{
- UndoElem *uel;
- uintptr_t totmem, maxmem;
-
- if(U.undomemory != 0) {
- /* limit to maximum memory (afterwards, we can't know in advance) */
- totmem= 0;
- maxmem= ((uintptr_t)U.undomemory)*1024*1024;
-
- uel= undobase.last;
- while(uel) {
- totmem+= uel->undosize;
- if(totmem>maxmem) break;
- uel= uel->prev;
- }
-
- if(uel) {
- while(undobase.first!=uel) {
- UndoElem *first= undobase.first;
- undo_free(first);
- BLI_freelinkN(&undobase, first);
- }
- }
- }
-}
-
-void undo_imagepaint_step(int step)
-{
- UndoElem *undo;
-
- if(step==1) {
- if(curundo==NULL);
- else {
- if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
- undo_restore(curundo);
- curundo= curundo->prev;
- }
- }
- else if(step==-1) {
- if((curundo!=NULL && curundo->next==NULL) || undobase.first==NULL);
- else {
- undo= (curundo && curundo->next)? curundo->next: undobase.first;
- undo_restore(undo);
- curundo= undo;
- if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
- }
- }
-}
-
-void undo_imagepaint_clear(void)
-{
- UndoElem *uel;
-
- uel= undobase.first;
- while(uel) {
- undo_free(uel);
- uel= uel->next;
- }
-
- BLI_freelistN(&undobase);
- curundo= NULL;
}
/* fast projection bucket array lookup, use the safe version for bound checking */
@@ -3315,7 +3200,7 @@ static void project_paint_end(ProjPaintState *ps)
ProjPixel *projPixel;
ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
LinkNode *pixel_node;
- UndoTile *tile;
+ void *tilerect;
MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
@@ -3331,8 +3216,8 @@ static void project_paint_end(ProjPaintState *ps)
int last_tile_width=0;
for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) {
- int size = sizeof(UndoTile **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
- last_projIma->undoRect = (UndoTile **) BLI_memarena_alloc(arena, size);
+ int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
+ last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size);
memset(last_projIma->undoRect, 0, size);
last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
}
@@ -3372,21 +3257,21 @@ static void project_paint_end(ProjPaintState *ps)
if (last_projIma->undoRect[tile_index]==NULL) {
/* add the undo tile from the modified image, then write the original colors back into it */
- tile = last_projIma->undoRect[tile_index] = undo_init_tile(&last_projIma->ima->id, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
+ tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
}
else {
- tile = last_projIma->undoRect[tile_index];
+ tilerect = last_projIma->undoRect[tile_index];
}
/* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
* because allocating the tiles allong the way slows down painting */
if (is_float) {
- float *rgba_fp = (float *)tile->rect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
+ float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
QUATCOPY(rgba_fp, projPixel->origColor.f);
}
else {
- ((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
+ ((unsigned int *)tilerect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
}
}
}
@@ -3957,7 +3842,6 @@ static void imapaint_clear_partial_redraw()
static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
{
ImBuf *tmpibuf = NULL;
- UndoTile *tile;
int srcx= 0, srcy= 0, origx;
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
@@ -3984,17 +3868,9 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
origx = (x >> IMAPAINT_TILE_BITS);
y = (y >> IMAPAINT_TILE_BITS);
- for (; y <= h; y++) {
- for (x=origx; x <= w; x++) {
- for(tile=curundo->tiles.first; tile; tile=tile->next)
- if(tile->x == x && tile->y == y && strcmp(tile->id.name, ima->id.name)==0)
- break;
-
- if(!tile) {
- undo_init_tile(&ima->id, ibuf, &tmpibuf, x, y);
- }
- }
- }
+ for (; y <= h; y++)
+ for (x=origx; x <= w; x++)
+ image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -4592,7 +4468,8 @@ static int texture_paint_init(bContext *C, wmOperator *op)
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
- undo_imagepaint_push_begin("Image Paint");
+ undo_paint_push_begin(UNDO_PAINT_IMAGE, "Image Paint",
+ image_undo_restore, image_undo_free);
/* create painter */
pop->painter= brush_painter_new(pop->s.brush);
@@ -4656,7 +4533,7 @@ static void paint_exit(bContext *C, wmOperator *op)
}
paint_redraw(C, &pop->s, 1);
- undo_imagepaint_push_end();
+ undo_paint_push_end(UNDO_PAINT_IMAGE);
if(pop->s.warnmultifile)
BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
@@ -5255,3 +5132,4 @@ int facemask_paint_poll(bContext *C)
{
return paint_facesel_test(CTX_data_active_object(C));
}
+
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index f86e1077ef3..108be50267d 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -41,13 +41,16 @@ struct wmOperator;
struct wmOperatorType;
struct ARegion;
struct VPaint;
+struct ListBase;
/* 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);
@@ -100,5 +103,14 @@ void PAINT_OT_face_select_all(struct wmOperatorType *ot);
int facemask_paint_poll(struct bContext *C);
+/* paint_undo.c */
+typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
+typedef void (*UndoFreeCb)(struct ListBase *lb);
+
+void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFreeCb free);
+struct ListBase *undo_paint_push_get_list(int type);
+void undo_paint_push_count_alloc(int type, int size);
+void undo_paint_push_end(int type);
+
#endif /* ED_PAINT_INTERN_H */
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 92812c2ab08..ae694ed863b 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -179,6 +179,7 @@ static void ed_keymap_paint_brush_switch(wmKeyMap *keymap, const char *path)
void ED_keymap_paint(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
+ int i;
/* Sculpt mode */
keymap= WM_keymap_find(keyconf, "Sculpt", 0, 0);
@@ -193,6 +194,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_paint_brush_switch(keymap, "tool_settings.sculpt.active_brush_index");
+ for(i=1; i<=5; i++)
+ RNA_int_set(WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY+i, KM_PRESS, KM_CTRL, 0)->ptr, "level", i);
+
/* Vertex Paint mode */
keymap= WM_keymap_find(keyconf, "Vertex Paint", 0, 0);
keymap->poll= vertex_paint_poll;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 8e795c5542e..e26b1945e7f 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;
@@ -100,7 +101,11 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
{
- Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C)));
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(paint);
+
+ if(!(paint->flags & PAINT_SHOW_BRUSH))
+ return;
glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
glEnable(GL_LINE_SMOOTH);
@@ -118,13 +123,14 @@ 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};
int flip= event->shift?1: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) {
@@ -211,15 +217,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;
@@ -229,12 +239,9 @@ 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];
-
- if(event->type == TIMER && (event->customdata != stroke->timer))
- return OPERATOR_RUNNING_MODAL;
+ int first= 0;
if(!stroke->stroke_started) {
stroke->last_mouse_position[0] = event->x;
@@ -249,26 +256,13 @@ 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);
- }
-
- 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);
- }
- else
- paint_brush_stroke_add_step(C, op, event, mouse);
- }
- else
- ED_region_tag_redraw(ar);
+ first= 1;
+ //ED_region_tag_redraw(ar);
}
- /* TODO: fix hardcoded event here */
+ /* TODO: fix hardcoded events here */
if(event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- /* Exit stroke, free data */
-
+ /* exit stroke, free data */
if(stroke->smooth_stroke_cursor)
WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
@@ -279,8 +273,22 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
MEM_freeN(stroke);
return OPERATOR_FINISHED;
}
- else
- return OPERATOR_RUNNING_MODAL;
+ else if(first || event->type == MOUSEMOVE || (event->type == TIMER && (event->customdata == stroke->timer))) {
+ 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);
+ }
+ else
+ paint_brush_stroke_add_step(C, op, event, mouse);
+ }
+ else
+ ;//ED_region_tag_redraw(ar);
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
int paint_stroke_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
new file mode 100644
index 00000000000..05f2b565e82
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -0,0 +1,235 @@
+/**
+ * $Id$
+ *
+ * Undo system for painting and sculpting.
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "ED_sculpt.h"
+
+#include "paint_intern.h"
+
+#define MAXUNDONAME 64
+
+typedef struct UndoElem {
+ struct UndoElem *next, *prev;
+ char name[MAXUNDONAME];
+ uintptr_t undosize;
+
+ ListBase elems;
+
+ UndoRestoreCb restore;
+ UndoFreeCb free;
+} UndoElem;
+
+typedef struct UndoStack {
+ int type;
+ ListBase elems;
+ UndoElem *current;
+} UndoStack;
+
+static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL};
+static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL};
+
+/* Generic */
+
+static void undo_restore(bContext *C, UndoStack *stack, UndoElem *uel)
+{
+ if(uel && uel->restore)
+ uel->restore(C, &uel->elems);
+}
+
+static void undo_elem_free(UndoStack *stack, UndoElem *uel)
+{
+ if(uel && uel->free) {
+ uel->free(&uel->elems);
+ BLI_freelistN(&uel->elems);
+ }
+}
+
+static void undo_stack_push_begin(UndoStack *stack, char *name, UndoRestoreCb restore, UndoFreeCb free)
+{
+ UndoElem *uel;
+ int nr;
+
+ /* Undo push is split up in begin and end, the reason is that as painting
+ * happens more tiles/nodes are added to the list, and at the very end we
+ * know how much memory the undo used to remove old undo elements */
+
+ /* remove all undos after (also when stack->current==NULL) */
+ while(stack->elems.last != stack->current) {
+ uel= stack->elems.last;
+ undo_elem_free(stack, uel);
+ BLI_freelinkN(&stack->elems, uel);
+ }
+
+ /* make new */
+ stack->current= uel= MEM_callocN(sizeof(UndoElem), "undo file");
+ uel->restore= restore;
+ uel->free= free;
+ BLI_addtail(&stack->elems, uel);
+
+ /* name can be a dynamic string */
+ strncpy(uel->name, name, MAXUNDONAME-1);
+
+ /* limit amount to the maximum amount*/
+ nr= 0;
+ uel= stack->elems.last;
+ while(uel) {
+ nr++;
+ if(nr==U.undosteps) break;
+ uel= uel->prev;
+ }
+ if(uel) {
+ while(stack->elems.first!=uel) {
+ UndoElem *first= stack->elems.first;
+ undo_elem_free(stack, first);
+ BLI_freelinkN(&stack->elems, first);
+ }
+ }
+}
+
+static void undo_stack_push_end(UndoStack *stack)
+{
+ UndoElem *uel;
+ uintptr_t totmem, maxmem;
+
+ if(U.undomemory != 0) {
+ /* limit to maximum memory (afterwards, we can't know in advance) */
+ totmem= 0;
+ maxmem= ((uintptr_t)U.undomemory)*1024*1024;
+
+ uel= stack->elems.last;
+ while(uel) {
+ totmem+= uel->undosize;
+ if(totmem>maxmem) break;
+ uel= uel->prev;
+ }
+
+ if(uel) {
+ while(stack->elems.first!=uel) {
+ UndoElem *first= stack->elems.first;
+ undo_elem_free(stack, first);
+ BLI_freelinkN(&stack->elems, first);
+ }
+ }
+ }
+}
+
+static void undo_stack_step(bContext *C, UndoStack *stack, int step)
+{
+ UndoElem *undo;
+
+ if(step==1) {
+ if(stack->current==NULL);
+ else {
+ if(G.f & G_DEBUG) printf("undo %s\n", stack->current->name);
+ undo_restore(C, stack, stack->current);
+ stack->current= stack->current->prev;
+ }
+ }
+ else if(step==-1) {
+ if((stack->current!=NULL && stack->current->next==NULL) || stack->elems.first==NULL);
+ else {
+ undo= (stack->current && stack->current->next)? stack->current->next: stack->elems.first;
+ undo_restore(C, stack, undo);
+ stack->current= undo;
+ if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
+ }
+ }
+}
+
+static void undo_stack_free(UndoStack *stack)
+{
+ UndoElem *uel;
+
+ for(uel=stack->elems.first; uel; uel=uel->next)
+ undo_elem_free(stack, uel);
+
+ BLI_freelistN(&stack->elems);
+ stack->current= NULL;
+}
+
+/* Exported Functions */
+
+void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFreeCb free)
+{
+ if(type == UNDO_PAINT_IMAGE)
+ undo_stack_push_begin(&ImageUndoStack, name, restore, free);
+ else if(type == UNDO_PAINT_MESH)
+ undo_stack_push_begin(&MeshUndoStack, name, restore, free);
+}
+
+ListBase *undo_paint_push_get_list(int type)
+{
+ if(type == UNDO_PAINT_IMAGE) {
+ if(ImageUndoStack.current)
+ return &ImageUndoStack.current->elems;
+ }
+ else if(type == UNDO_PAINT_MESH) {
+ if(MeshUndoStack.current)
+ return &MeshUndoStack.current->elems;
+ }
+
+ return NULL;
+}
+
+void undo_paint_push_count_alloc(int type, int size)
+{
+ if(type == UNDO_PAINT_IMAGE)
+ ImageUndoStack.current->undosize += size;
+ else if(type == UNDO_PAINT_MESH)
+ MeshUndoStack.current->undosize += size;
+}
+
+void undo_paint_push_end(int type)
+{
+ if(type == UNDO_PAINT_IMAGE)
+ undo_stack_push_end(&ImageUndoStack);
+ else if(type == UNDO_PAINT_MESH)
+ undo_stack_push_end(&MeshUndoStack);
+}
+
+void ED_undo_paint_step(bContext *C, int type, int step)
+{
+ if(type == UNDO_PAINT_IMAGE)
+ undo_stack_step(C, &ImageUndoStack, step);
+ else if(type == UNDO_PAINT_MESH)
+ undo_stack_step(C, &MeshUndoStack, step);
+}
+
+void ED_undo_paint_free(void)
+{
+ undo_stack_free(&ImageUndoStack);
+ undo_stack_free(&MeshUndoStack);
+}
+
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 496d15d793f..b968930128a 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -96,7 +96,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceind
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
- int numfaces = dm->getNumFaces(dm), a;
+ int numfaces = dm->getNumFaces(dm), a, findex;
float p[2], w[3], absw, minabsw;
MFace mf;
MVert mv[4];
@@ -106,7 +106,9 @@ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceind
/* test all faces in the derivedmesh with the original index of the picked face */
for(a = 0; a < numfaces; a++) {
- if(index[a] == faceindex) {
+ findex= (index)? index[a]: a;
+
+ if(findex == faceindex) {
dm->getFace(dm, a, &mf);
dm->getVert(dm, mf.v1, &mv[0]);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 2512ecbc248..7021d76b1c4 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1629,7 +1629,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);
@@ -1931,7 +1931,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 f4006e63dc0..8b705ff5b5e 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -35,6 +35,9 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
+#include "BLI_threads.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
@@ -52,6 +55,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"
@@ -106,15 +110,6 @@
*
*/
-/* ActiveData stores an Index into the mvert array of Mesh, plus Fade, which
- stores how far the vertex is from the brush center, scaled to the range [0,1]. */
-typedef struct ActiveData {
- struct ActiveData *next, *prev;
- unsigned int Index;
- float Fade;
- float dist;
-} ActiveData;
-
typedef enum StrokeFlags {
CLIP_X = 1,
CLIP_Y = 2,
@@ -133,7 +128,6 @@ typedef struct StrokeCache {
int flag;
float clip_tolerance[3];
float initial_mouse[2];
- float depth;
/* Variants */
float radius;
@@ -142,6 +136,7 @@ typedef struct StrokeCache {
float flip;
float pressure;
float mouse[2];
+ float bstrength;
float tex_mouse[2];
/* The rest is temporary storage that isn't saved as a property */
@@ -150,32 +145,24 @@ typedef struct StrokeCache {
bglMats *mats;
- short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */
+ /* Clean this up! */
+ ViewContext *vc;
+ Brush *brush;
+
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
float rotation; /* Texture rotation (radians) for anchored and rake modes */
int pixel_radius, previous_pixel_radius;
- ListBase grab_active_verts[8]; /* The same list of verts is used throught grab stroke */
+ PBVHNode **grab_active_nodes[8]; /* The same list of nodes is used throught grab stroke */
+ int grab_active_totnode[8];
+ float grab_active_location[8][3];
float grab_delta[3], grab_delta_symmetry[3];
- float old_grab_location[3];
+ float old_grab_location[3], orig_grab_location[3];
int symmetry; /* Symmetry index between 0 and 7 */
float view_normal[3], view_normal_symmetry[3];
int last_rake[2]; /* Last location of updating rake rotation */
+ int original;
} 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
@@ -192,7 +179,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);
@@ -200,6 +187,337 @@ static void project(bglMats *mats, const float v[3], short p[2])
p[0]= f[0];
p[1]= f[1];
}
+*/
+
+/*** BVH Tree ***/
+
+/* 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_redraw_BB(ob->sculpt->tree, bb_min, bb_max);
+
+ rect->xmin = rect->ymin = INT_MAX;
+ rect->xmax = rect->ymax = INT_MIN;
+
+ if(bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
+ return 0;
+
+ 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);
+
+#if 1
+ /* use some extra space just in case */
+ rect.xmin -= 2;
+ rect.xmax += 2;
+ rect.ymin -= 2;
+ rect.ymax += 2;
+#else
+ /* it was doing this before, allows to redraw a smaller
+ part of the screen but also gives artifaces .. */
+ rect.xmin += 2;
+ rect.xmax -= 2;
+ rect.ymin += 2;
+ rect.ymax -= 2;
+#endif
+
+ view3d_calculate_clipping(bb, planes, &mats, &rect);
+
+ for(i = 0; i < 16; ++i)
+ ((float*)planes)[i] = -((float*)planes)[i];
+
+ MEM_freeN(bb);
+
+ /* clear redraw flag from nodes */
+ BLI_pbvh_update(ob->sculpt->tree, PBVH_UpdateRedraw, NULL);
+}
+
+/************************** Undo *************************/
+
+typedef struct SculptUndoNode {
+ struct SculptUndoNode *next, *prev;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ void *node; /* only during push, not valid afterwards! */
+
+ float (*co)[3];
+ short (*no)[3];
+ int totvert;
+
+ /* non-multires */
+ int maxvert; /* to verify if totvert it still the same */
+ int *index; /* to restore into right location */
+
+ /* multires */
+ int maxgrid; /* same for grid */
+ int gridsize; /* same for grid */
+ int totgrid; /* to restore into right location */
+ int *grids; /* to restore into right location */
+} SculptUndoNode;
+
+static void update_cb(PBVHNode *node, void *data)
+{
+ BLI_pbvh_node_mark_update(node);
+}
+
+static void sculpt_undo_restore(bContext *C, ListBase *lb)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
+ SculptSession *ss = ob->sculpt;
+ SculptUndoNode *unode;
+ MVert *mvert;
+ MultiresModifierData *mmd;
+ int *index;
+ int i, j, update= 0;
+
+ sculpt_update_mesh_elements(scene, ob, 0);
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(!(strcmp(unode->idname, ob->id.name)==0))
+ continue;
+
+ if(unode->maxvert) {
+ /* regular mesh restore */
+ if(ss->totvert != unode->maxvert)
+ continue;
+
+ index= unode->index;
+ mvert= ss->mvert;
+
+ for(i=0; i<unode->totvert; i++) {
+ swap_v3_v3(mvert[index[i]].co, unode->co[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ else if(unode->maxgrid) {
+ /* multires restore */
+ DMGridData **grids, *grid;
+ float (*co)[3];
+ int gridsize;
+
+ if(dm->getNumGrids(dm) != unode->maxgrid)
+ continue;
+ if(dm->getGridSize(dm) != unode->gridsize)
+ continue;
+
+ grids= dm->getGridData(dm);
+ gridsize= dm->getGridSize(dm);
+
+ co = unode->co;
+ for(j=0; j<unode->totgrid; j++) {
+ grid= grids[unode->grids[j]];
+
+ for(i=0; i<gridsize*gridsize; i++, co++)
+ swap_v3_v3(grid[i].co, co[0]);
+ }
+ }
+
+ update= 1;
+ }
+
+ if(update) {
+ if(ss->kb) sculpt_mesh_to_key(ss->ob, ss->kb);
+ if(ss->refkb) sculpt_key_to_mesh(ss->refkb, ob);
+
+ /* we update all nodes still, should be more clever, but also
+ needs to work correct when exiting/entering sculpt mode and
+ the nodes get recreated, though in that case it could do all */
+ BLI_pbvh_search_callback(ss->tree, NULL, NULL, update_cb, NULL);
+ BLI_pbvh_update(ss->tree, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
+
+ if((mmd=sculpt_multires_active(ob)))
+ multires_mark_as_modified(ob);
+ }
+}
+
+static void sculpt_undo_free(ListBase *lb)
+{
+ SculptUndoNode *unode;
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->co)
+ MEM_freeN(unode->co);
+ if(unode->no)
+ MEM_freeN(unode->no);
+ if(unode->index)
+ MEM_freeN(unode->index);
+ if(unode->grids)
+ MEM_freeN(unode->grids);
+ }
+}
+
+static SculptUndoNode *sculpt_undo_get_node(SculptSession *ss, PBVHNode *node)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ SculptUndoNode *unode;
+
+ if(!lb)
+ return NULL;
+
+ for(unode=lb->first; unode; unode=unode->next)
+ if(unode->node == node)
+ return unode;
+
+ return NULL;
+}
+
+static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ Object *ob= ss->ob;
+ SculptUndoNode *unode;
+ int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
+
+ /* list is manipulated by multiple threads, so we lock */
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ if((unode= sculpt_undo_get_node(ss, node))) {
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return unode;
+ }
+
+ unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+ strcpy(unode->idname, ob->id.name);
+ unode->node= node;
+
+ BLI_pbvh_node_num_verts(ss->tree, node, &totvert, &allvert);
+ BLI_pbvh_node_get_grids(ss->tree, node, &grids, &totgrid,
+ &maxgrid, &gridsize, NULL, NULL);
+
+ unode->totvert= totvert;
+ /* we will use this while sculpting, is mapalloc slow to access then? */
+ unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co");
+ unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no");
+ undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert);
+ BLI_addtail(lb, unode);
+
+ if(maxgrid) {
+ /* multires */
+ unode->maxgrid= maxgrid;
+ unode->totgrid= totgrid;
+ unode->gridsize= gridsize;
+ unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids");
+ }
+ else {
+ /* regular mesh */
+ unode->maxvert= ss->totvert;
+ unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
+ }
+
+ BLI_unlock_thread(LOCK_CUSTOM1);
+
+ /* copy threaded, hopefully this is the performance critical part */
+ {
+ PBVHVertexIter vd;
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, node, vd, PBVH_ITER_ALL) {
+ copy_v3_v3(unode->co[vd.i], vd.co);
+ if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
+ else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+ if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+
+ if(unode->grids)
+ memcpy(unode->grids, grids, sizeof(int)*totgrid);
+
+ return unode;
+}
+
+static void sculpt_undo_push_begin(SculptSession *ss, char *name)
+{
+ undo_paint_push_begin(UNDO_PAINT_MESH, name,
+ sculpt_undo_restore, sculpt_undo_free);
+}
+
+static void sculpt_undo_push_end(SculptSession *ss)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ SculptUndoNode *unode;
+
+ /* we don't need normals in the undo stack */
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->no) {
+ MEM_freeN(unode->no);
+ unode->no= NULL;
+ }
+ }
+
+ undo_paint_push_end(UNDO_PAINT_MESH);
+}
+
+void ED_sculpt_force_update(bContext *C)
+{
+ Object *ob= CTX_data_active_object(C);
+
+ if(ob && (ob->mode & OB_MODE_SCULPT))
+ multires_force_update(ob);
+}
+
+/************************ Brush Testing *******************/
+
+typedef struct SculptBrushTest {
+ float radius_squared;
+ float location[3];
+
+ float dist;
+} SculptBrushTest;
+
+static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
+{
+ test->radius_squared= ss->cache->radius*ss->cache->radius;
+ copy_v3_v3(test->location, ss->cache->location);
+}
+
+static int sculpt_brush_test(SculptBrushTest *test, float co[3])
+{
+ float distsq, delta[3];
+
+ sub_v3_v3v3(delta, co, test->location);
+ distsq = INPR(delta, delta);
+
+ if(distsq < test->radius_squared) {
+ test->dist = sqrt(distsq);
+ return 1;
+ }
+
+ return 0;
+}
/* ===== Sculpting =====
*
@@ -239,6 +557,169 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache)
}
}
+/* Uses symm to selectively flip any axis of a coordinate. */
+static void flip_coord(float out[3], float in[3], const char symm)
+{
+ if(symm & SCULPT_SYMM_X)
+ out[0]= -in[0];
+ else
+ out[0]= in[0];
+ if(symm & SCULPT_SYMM_Y)
+ out[1]= -in[1];
+ else
+ out[1]= in[1];
+ if(symm & SCULPT_SYMM_Z)
+ out[2]= -in[2];
+ else
+ out[2]= in[2];
+}
+
+/* Get a pixel from the texcache at (px, py) */
+static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
+{
+ unsigned *p;
+ p = ss->texcache + py * ss->texcache_side + px;
+ return ((unsigned char*)(p))[0];
+}
+
+static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
+{
+ int x, y, x2, y2;
+ const int tc_max = ss->texcache_side - 1;
+ float urat, vrat, uopp;
+
+ if(u < 0) u = 0;
+ else if(u >= ss->texcache_side) u = tc_max;
+ if(v < 0) v = 0;
+ else if(v >= ss->texcache_side) v = tc_max;
+
+ x = floor(u);
+ y = floor(v);
+ x2 = x + 1;
+ y2 = y + 1;
+
+ if(x2 > ss->texcache_side) x2 = tc_max;
+ if(y2 > ss->texcache_side) y2 = tc_max;
+
+ urat = u - x;
+ vrat = v - y;
+ uopp = 1 - urat;
+
+ return ((get_texcache_pixel(ss, x, y) * uopp +
+ get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) +
+ (get_texcache_pixel(ss, x, y2) * uopp +
+ get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
+}
+
+/* Return a multiplier for brush strength on a particular vertex. */
+static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
+{
+ MTex *tex = NULL;
+ float avg= 1;
+
+ if(br->texact >= 0)
+ tex = br->mtex[br->texact];
+
+ if(!tex) {
+ avg= 1;
+ }
+ else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ float jnk;
+
+ /* Get strength by feeding the vertex
+ location directly into a texture */
+ externtex(tex, point, &avg,
+ &jnk, &jnk, &jnk, &jnk);
+ }
+ else if(ss->texcache) {
+ const float bsize= ss->cache->pixel_radius * 2;
+ const float rot= tex->rot + ss->cache->rotation;
+ int px, py;
+ float flip[3], point_2d[2];
+
+ /* If the active area is being applied for symmetry, flip it
+ across the symmetry axis in order to project it. This insures
+ that the brush texture will be oriented correctly. */
+ copy_v3_v3(flip, point);
+ flip_coord(flip, flip, ss->cache->symmetry);
+ projectf(ss->cache->mats, flip, point_2d);
+
+ /* For Tile and Drag modes, get the 2D screen coordinates of the
+ and scale them up or down to the texture size. */
+ if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ const int sx= (const int)tex->size[0];
+ const int sy= (const int)tex->size[1];
+
+ float fx= point_2d[0];
+ float fy= point_2d[1];
+
+ float angle= atan2(fy, fx) - rot;
+ float flen= sqrtf(fx*fx + fy*fy);
+
+ if(rot<0.001 && rot>-0.001) {
+ px= point_2d[0];
+ py= point_2d[1];
+ } else {
+ px= flen * cos(angle) + 2000;
+ py= flen * sin(angle) + 2000;
+ }
+ if(sx != 1)
+ px %= sx-1;
+ if(sy != 1)
+ py %= sy-1;
+ avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
+ }
+ else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ float fx= (point_2d[0] - ss->cache->tex_mouse[0]) / bsize;
+ float fy= (point_2d[1] - ss->cache->tex_mouse[1]) / bsize;
+
+ float angle= atan2(fy, fx) - rot;
+ float flen= sqrtf(fx*fx + fy*fy);
+
+ fx = flen * cos(angle) + 0.5;
+ fy = flen * sin(angle) + 0.5;
+
+ avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
+ }
+ }
+
+ avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
+
+ return avg;
+}
+
+typedef struct {
+ Sculpt *sd;
+ SculptSession *ss;
+ float radius_squared;
+ ListBase *active_verts;
+ float area_normal[3];
+} SculptSearchSphereData;
+
+/* Test AABB against sphere */
+static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
+{
+ SculptSearchSphereData *data = data_v;
+ float *center = data->ss->cache->location, nearest[3];
+ float t[3], bb_min[3], bb_max[3];
+ int i;
+
+ BLI_pbvh_node_get_BB(node, bb_min, bb_max);
+
+ 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];
+ }
+
+ sub_v3_v3v3(t, center, nearest);
+
+ return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
+}
+
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float val[3])
{
@@ -255,12 +736,8 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float va
}
}
-static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], const short no[3])
+static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
{
- float fno[3] = {no[0], no[1], no[2]};
-
- normalize_v3(fno);
-
if((dot_v3v3(view_vec, fno)) > 0) {
add_v3_v3v3(out, out, fno);
} else {
@@ -268,74 +745,119 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons
}
}
-/* Currently only for the draw brush; finds average normal for all active
- vertices */
-static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const ListBase* active_verts)
+/* For draw/layer/flatten; finds average normal for all active vertices */
+static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3], PBVHNode **nodes, int totnode)
{
- Brush *brush = paint_brush(&sd->paint);
+ PBVH *bvh= ss->tree;
StrokeCache *cache = ss->cache;
- ActiveData *node = active_verts->first;
const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
- float out_flip[3];
- float *out_dir = cache->view_normal_symmetry;
-
- out[0]=out[1]=out[2] = out_flip[0]=out_flip[1]=out_flip[2] = 0;
+ float out[3] = {0.0f, 0.0f, 0.0f};
+ float out_flip[3] = {0.0f, 0.0f, 0.0f};
+ float out_dir[3];
+ int n;
+
+ copy_v3_v3(out_dir, cache->view_normal_symmetry);
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float fno[3];
+ float nout[3] = {0.0f, 0.0f, 0.0f};
+ float nout_flip[3] = {0.0f, 0.0f, 0.0f};
+
+ // XXX push instead of get for thread safety in draw
+ // brush .. lame, but also not harmful really
+ unode= sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ if(ss->cache->original) {
+ BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, unode->co[vd.i])) {
+ normal_short_to_float_v3(fno, unode->no[vd.i]);
+ add_norm_if(out_dir, nout, nout_flip, fno);
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+ else {
+ BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ if(vd.no) {
+ normal_short_to_float_v3(fno, vd.no);
+ add_norm_if(out_dir, nout, nout_flip, fno);
+ }
+ else
+ add_norm_if(out_dir, nout, nout_flip, vd.fno);
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
- if(brush->flag & BRUSH_ANCHORED) {
- for(; node; node = node->next)
- add_norm_if(out_dir, out, out_flip, cache->orig_norms[node->Index]);
- }
- else {
- for(; node; node = node->next)
- add_norm_if(out_dir, out, out_flip, ss->mvert[node->Index].no);
+ #pragma omp critical
+ {
+ /* we sum per node and add together later for threads */
+ add_v3_v3v3(out, out, nout);
+ add_v3_v3v3(out_flip, out_flip, nout_flip);
+ }
}
if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) {
- VECCOPY(out, out_flip);
+ copy_v3_v3(out, out_flip);
}
normalize_v3(out);
- if(out_dir) {
- out[0] = out_dir[0] * view + out[0] * (10-view);
- out[1] = out_dir[1] * view + out[1] * (10-view);
- out[2] = out_dir[2] * view + out[2] * (10-view);
- }
+ out[0] = out_dir[0] * view + out[0] * (10-view);
+ out[1] = out_dir[1] * view + out[1] * (10-view);
+ out[2] = out_dir[2] * view + out[2] * (10-view);
normalize_v3(out);
+ copy_v3_v3(area_normal, out);
}
-static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_verts)
+static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- 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;
-
- const float val[3]= {co[0]+area_normal[0]*ss->cache->radius*node->Fade*ss->cache->scale[0],
- 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;
+ Brush *brush = paint_brush(&sd->paint);
+ float offset[3], area_normal[3];
+ float bstrength= ss->cache->bstrength;
+ int n;
+
+ /* area normal */
+ calc_area_normal(sd, ss, area_normal, nodes, totnode);
+
+ /* offset with as much as possible factored in already */
+ offset[0]= area_normal[0]*ss->cache->radius*ss->cache->scale[0]*bstrength;
+ offset[1]= area_normal[1]*ss->cache->radius*ss->cache->scale[1]*bstrength;
+ offset[2]= area_normal[2]*ss->cache->radius*ss->cache->scale[2]*bstrength;
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ /* offset vertex */
+ float fade = tex_strength(ss, brush, vd.co, test.dist);
+ float val[3]= {vd.co[0] + offset[0]*fade,
+ vd.co[1] + offset[1]*fade,
+ vd.co[2] + offset[2]*fade};
+
+ sculpt_clip(sd, ss, vd.co, val);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
+ BLI_pbvh_vertex_iter_end;
- sculpt_clip(sd, ss, co, val);
-
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
/* For the smooth brush, uses the neighboring vertices around vert to calculate
@@ -382,195 +904,340 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
copy_v3_v3(avg, ss->mvert[vert].co);
}
-static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
+static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
{
- ActiveData *node= active_verts->first;
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
- int i;
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ PBVHVertexIter vd;
+ SculptBrushTest test;
- for(i = 0; i < 2; ++i) {
- while(node){
- float *co= ss->mvert[node->Index].co;
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, node, vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
float avg[3], val[3];
- neighbor_average(ss, avg, node->Index);
- val[0] = co[0]+(avg[0]-co[0])*node->Fade;
- val[1] = co[1]+(avg[1]-co[1])*node->Fade;
- val[2] = co[2]+(avg[2]-co[2])*node->Fade;
+ neighbor_average(ss, avg, vd.vert_indices[vd.i]);
+ val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade;
+ val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade;
+ val[2] = vd.co[2]+(avg[2]-vd.co[2])*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;
+ sculpt_clip(sd, ss, vd.co, val);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+}
+
+static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ SculptBrushTest test;
+ DMGridData **griddata, *data;
+ DMGridAdjacency *gridadj, *adj;
+ float bstrength= ss->cache->bstrength;
+ float co[3], (*tmpgrid)[3];
+ int v1, v2, v3, v4;
+ int *grid_indices, totgrid, gridsize, i, x, y;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_node_get_grids(ss->tree, node, &grid_indices, &totgrid,
+ NULL, &gridsize, &griddata, &gridadj);
+
+ #pragma omp critical
+ tmpgrid= MEM_mallocN(sizeof(float)*3*gridsize*gridsize, "tmpgrid");
+
+ for(i = 0; i < totgrid; ++i) {
+ data = griddata[grid_indices[i]];
+ adj = &gridadj[grid_indices[i]];
+
+ memset(tmpgrid, 0, sizeof(float)*3*gridsize*gridsize);
+
+ /* average grid values */
+ for(y = 0; y < gridsize-1; ++y) {
+ for(x = 0; x < gridsize-1; ++x) {
+ v1 = x + y*gridsize;
+ v2 = (x + 1) + y*gridsize;
+ v3 = (x + 1) + (y + 1)*gridsize;
+ v4 = x + (y + 1)*gridsize;
+
+ cent_quad_v3(co, data[v1].co, data[v2].co, data[v3].co, data[v4].co);
+ mul_v3_fl(co, 0.25f);
+
+ add_v3_v3(tmpgrid[v1], co);
+ add_v3_v3(tmpgrid[v2], co);
+ add_v3_v3(tmpgrid[v3], co);
+ add_v3_v3(tmpgrid[v4], co);
+ }
+ }
+
+ /* blend with existing coordinates */
+ for(y = 0; y < gridsize; ++y) {
+ for(x = 0; x < gridsize; ++x) {
+ if(x == 0 && adj->index[0] == -1) continue;
+ if(x == gridsize - 1 && adj->index[2] == -1) continue;
+ if(y == 0 && adj->index[3] == -1) continue;
+ if(y == gridsize - 1 && adj->index[1] == -1) continue;
+
+ copy_v3_v3(co, data[x + y*gridsize].co);
+
+ if(sculpt_brush_test(&test, co)) {
+ float fade = tex_strength(ss, brush, co, test.dist)*bstrength;
+ float avg[3], val[3];
+
+ copy_v3_v3(avg, tmpgrid[x + y*gridsize]);
+ if(x == 0 || x == gridsize - 1)
+ mul_v3_fl(avg, 2.0f);
+ if(y == 0 || y == gridsize - 1)
+ mul_v3_fl(avg, 2.0f);
+
+ val[0] = co[0]+(avg[0]-co[0])*fade;
+ val[1] = co[1]+(avg[1]-co[1])*fade;
+ val[2] = co[2]+(avg[2]-co[2])*fade;
+
+ sculpt_clip(sd, ss, data[x + y*gridsize].co, val);
}
}
- node= node->next;
}
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
+
+ #pragma omp critical
+ MEM_freeN(tmpgrid);
}
-static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
+static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- ActiveData *node= active_verts->first;
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
+ int iteration, n;
+
+ for(iteration = 0; iteration < 2; ++iteration) {
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ sculpt_undo_push_node(ss, nodes[n]);
+
+ if(ss->fmap)
+ do_mesh_smooth_brush(sd, ss, nodes[n]);
+ else
+ do_multires_smooth_brush(sd, ss, nodes[n]);
+
+ BLI_pbvh_node_mark_update(nodes[n]);
+ }
+
+ if(!ss->fmap)
+ multires_stitch_grids(ss->ob);
+ }
+}
- while(node) {
- float *co= ss->mvert[node->Index].co;
- const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade,
- co[1]+(ss->cache->location[1]-co[1])*node->Fade,
- co[2]+(ss->cache->location[2]-co[2])*node->Fade};
+static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ int n;
- 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;
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+ float val[3]= {vd.co[0]+(test.location[0]-vd.co[0])*fade,
+ vd.co[1]+(test.location[1]-vd.co[1])*fade,
+ vd.co[2]+(test.location[2]-vd.co[2])*fade};
+
+ sculpt_clip(sd, ss, vd.co, val);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
+ BLI_pbvh_vertex_iter_end;
- sculpt_clip(s, ss, co, val);
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void do_grab_brush(Sculpt *sd, SculptSession *ss)
+static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- ActiveData *node= ss->cache->grab_active_verts[ss->cache->symmetry].first;
- float add[3];
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
float grab_delta[3];
- float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
+ int n;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- while(node) {
- float *co= ss->mvert[node->Index].co;
+
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*origco)[3];
- copy_v3_v3(add, grab_delta);
- mul_v3_fl(add, node->Fade);
- add_v3_v3v3(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;
+ origco= sculpt_undo_push_node(ss, nodes[n])->co;
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, origco[vd.i])) {
+ float fade = tex_strength(ss, brush, origco[vd.i], test.dist)*bstrength;
+ float add[3]= {vd.co[0]+fade*grab_delta[0],
+ vd.co[1]+fade*grab_delta[1],
+ vd.co[2]+fade*grab_delta[2]};
+
+ sculpt_clip(sd, ss, vd.co, add);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
+ BLI_pbvh_vertex_iter_end;
- sculpt_clip(sd, ss, co, add);
-
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
-
}
-static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts)
+static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- float area_normal[3];
- ActiveData *node= active_verts->first;
- float *buffer;
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ float area_normal[3], offset[3];
float lim= ss->cache->radius / 4;
+ int n;
+
+ /* XXX not working yet for multires */
+ if(!ss->mvert)
+ return;
if(ss->cache->flip)
lim = -lim;
- calc_area_normal(sd, ss, area_normal, active_verts);
+ calc_area_normal(sd, ss, area_normal, nodes, totnode);
- 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;
- float val[3];
-
- *disp+= node->Fade;
-
- /* Don't let the displacement go past the limit */
- if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
- *disp = lim;
+ offset[0]= ss->cache->scale[0]*area_normal[0];
+ offset[1]= ss->cache->scale[1]*area_normal[1];
+ offset[2]= ss->cache->scale[2]*area_normal[2];
+
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*origco)[3];
- val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0];
- 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;
+ origco= sculpt_undo_push_node(ss, nodes[n])->co;
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+ int index= vd.vert_indices[vd.i];
+ float *disp= &ss->layer_disps[index];
+ float val[3];
+
+ *disp+= fade;
+
+ /* Don't let the displacement go past the limit */
+ if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
+ *disp = lim;
+
+ if(ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ /* persistent base */
+ val[0] = ss->layer_co[index][0] + (*disp)*offset[0];
+ val[1] = ss->layer_co[index][1] + (*disp)*offset[1];
+ val[2] = ss->layer_co[index][2] + (*disp)*offset[2];
+ }
+ else {
+ val[0] = origco[vd.i][0] + (*disp)*offset[0];
+ val[1] = origco[vd.i][1] + (*disp)*offset[1];
+ val[2] = origco[vd.i][2] + (*disp)*offset[2];
+ }
+
+ sculpt_clip(sd, ss, vd.co, val);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
+ BLI_pbvh_vertex_iter_end;
- sculpt_clip(sd, ss, co, val);
-
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts)
+static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- 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;
- short *no= ss->mvert[node->Index].no;
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ int n;
- add[0]= no[0]/ 32767.0f;
- add[1]= no[1]/ 32767.0f;
- add[2]= no[2]/ 32767.0f;
- mul_v3_fl(add, node->Fade * ss->cache->radius);
- add[0]*= ss->cache->scale[0];
- add[1]*= ss->cache->scale[1];
- add[2]*= ss->cache->scale[2];
- add_v3_v3v3(add, add, co);
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
- 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_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+ float add[3];
+
+ if(vd.fno) copy_v3_v3(add, vd.fno);
+ else normal_short_to_float_v3(add, vd.no);
+
+ mul_v3_fl(add, fade * ss->cache->radius);
+ add[0]*= ss->cache->scale[0];
+ add[1]*= ss->cache->scale[1];
+ add[2]*= ss->cache->scale[2];
+ add_v3_v3v3(add, add, vd.co);
+
+ sculpt_clip(sd, ss, vd.co, add);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
+ BLI_pbvh_vertex_iter_end;
- sculpt_clip(s, ss, co, add);
-
- node= node->next;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->vertices );
}
-static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3])
+static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float co[3])
{
- ActiveData *outer[FLATTEN_SAMPLE_SIZE];
- int i;
+ float outer_dist[FLATTEN_SAMPLE_SIZE];
+ float outer_co[FLATTEN_SAMPLE_SIZE][3];
+ int i, n;
- for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
- outer[i] = node;
+ for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
+ zero_v3(outer_co[i]);
+ outer_dist[i]= -1.0f;
+ }
+
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ int j;
- for(; node; node = node->next) {
- for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
- if(node->dist > outer[i]->dist) {
- outer[i] = node;
- break;
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ for(j = 0; j < FLATTEN_SAMPLE_SIZE; ++j) {
+ if(test.dist > outer_dist[j]) {
+ copy_v3_v3(outer_co[j], vd.co);
+ outer_dist[j] = test.dist;
+ break;
+ }
+ }
}
}
+ BLI_pbvh_vertex_iter_end;
+
+ BLI_pbvh_node_mark_update(nodes[n]);
}
co[0] = co[1] = co[2] = 0.0f;
for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
- add_v3_v3v3(co, co, ss->mvert[outer[i]->Index].co);
+ if(outer_dist[i] >= 0.0f)
+ add_v3_v3v3(co, co, outer_co[i]);
mul_v3_fl(co, 1.0f / FLATTEN_SAMPLE_SIZE);
}
@@ -602,16 +1269,17 @@ static int plane_point_side(float co[3], float plane_normal[3], float plane_cent
return d <= 0.0f;
}
-static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts, int clay)
+static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, int clay)
{
- ActiveData *node= active_verts->first;
/* area_normal and cntr define the plane towards which vertices are squashed */
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
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);
+ int n, flip = 0;
+
+ calc_area_normal(sd, ss, area_normal, nodes, totnode);
+ calc_flatten_center(sd, ss, nodes, totnode, cntr);
if(clay) {
bstr= brush_strength(sd, ss->cache);
@@ -622,295 +1290,123 @@ 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];
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
- if(!clay || plane_point_side(co, area_normal, cntr2, flip)) {
- /* Find the intersection between squash-plane and vertex (along the area normal) */
- point_plane_project(intr, co, area_normal, cntr);
-
- sub_v3_v3v3(val, intr, co);
-
- if(clay) {
- if(bstr > FLT_EPSILON)
- mul_v3_fl(val, node->Fade / bstr);
- else
- mul_v3_fl(val, node->Fade);
- /* Clay displacement */
- val[0]+=area_normal[0] * ss->cache->scale[0]*node->Fade;
- val[1]+=area_normal[1] * ss->cache->scale[1]*node->Fade;
- val[2]+=area_normal[2] * ss->cache->scale[2]*node->Fade;
- }
- else
- mul_v3_fl(val, fabs(node->Fade));
+ sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ float intr[3], val[3];
+
+ if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) {
+ const float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+
+ /* Find the intersection between squash-plane and vertex (along the area normal) */
+ point_plane_project(intr, vd.co, area_normal, cntr);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if(clay) {
+ if(bstr > FLT_EPSILON)
+ mul_v3_fl(val, fade / bstr);
+ else
+ mul_v3_fl(val, fade);
+ /* Clay displacement */
+ val[0]+=area_normal[0] * ss->cache->scale[0]*fade;
+ val[1]+=area_normal[1] * ss->cache->scale[1]*fade;
+ val[2]+=area_normal[2] * ss->cache->scale[2]*fade;
+ }
+ else
+ mul_v3_fl(val, fabs(fade));
- add_v3_v3v3(val, val, co);
+ add_v3_v3v3(val, val, vd.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, vd.co, val);
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- }
- 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. */
-static void flip_coord(float out[3], float in[3], const char symm)
-{
- if(symm & SCULPT_SYMM_X)
- out[0]= -in[0];
- else
- out[0]= in[0];
- if(symm & SCULPT_SYMM_Y)
- out[1]= -in[1];
- else
- out[1]= in[1];
- if(symm & SCULPT_SYMM_Z)
- out[2]= -in[2];
- else
- out[2]= in[2];
-}
-
-/* Get a pixel from the texcache at (px, py) */
-static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
-{
- unsigned *p;
- p = ss->texcache + py * ss->texcache_side + px;
- return ((unsigned char*)(p))[0];
-}
-
-static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
-{
- int x, y, x2, y2;
- const int tc_max = ss->texcache_side - 1;
- float urat, vrat, uopp;
-
- if(u < 0) u = 0;
- else if(u >= ss->texcache_side) u = tc_max;
- if(v < 0) v = 0;
- else if(v >= ss->texcache_side) v = tc_max;
-
- x = floor(u);
- y = floor(v);
- x2 = x + 1;
- y2 = y + 1;
-
- if(x2 > ss->texcache_side) x2 = tc_max;
- if(y2 > ss->texcache_side) y2 = tc_max;
-
- urat = u - x;
- vrat = v - y;
- uopp = 1 - urat;
-
- return ((get_texcache_pixel(ss, x, y) * uopp +
- get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) +
- (get_texcache_pixel(ss, x, y2) * uopp +
- get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
-}
-
-/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len)
-{
- Brush *br = paint_brush(&sd->paint);
- MTex *tex = NULL;
- float avg= 1;
-
- if(br->texact >= 0)
- tex = br->mtex[br->texact];
-
- if(!tex) {
- avg= 1;
- }
- else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
- float jnk;
-
- /* Get strength by feeding the vertex
- location directly into a texture */
- externtex(tex, point, &avg,
- &jnk, &jnk, &jnk, &jnk);
- }
- else if(ss->texcache) {
- const float bsize= ss->cache->pixel_radius * 2;
- const float rot= tex->rot + ss->cache->rotation;
- int px, py;
- float flip[3], point_2d[2];
-
- /* If the active area is being applied for symmetry, flip it
- across the symmetry axis in order to project it. This insures
- that the brush texture will be oriented correctly. */
- copy_v3_v3(flip, point);
- flip_coord(flip, flip, ss->cache->symmetry);
- projectf(ss->cache->mats, flip, point_2d);
-
- /* For Tile and Drag modes, get the 2D screen coordinates of the
- and scale them up or down to the texture size. */
- if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- const int sx= (const int)tex->size[0];
- const int sy= (const int)tex->size[1];
-
- float fx= point_2d[0];
- float fy= point_2d[1];
-
- float angle= atan2(fy, fx) - rot;
- float flen= sqrtf(fx*fx + fy*fy);
-
- if(rot<0.001 && rot>-0.001) {
- px= point_2d[0];
- py= point_2d[1];
- } else {
- px= flen * cos(angle) + 2000;
- py= flen * sin(angle) + 2000;
}
- if(sx != 1)
- px %= sx-1;
- if(sy != 1)
- py %= sy-1;
- avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
- }
- else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
- float fx= (point_2d[0] - ss->cache->tex_mouse[0]) / bsize;
- float fy= (point_2d[1] - ss->cache->tex_mouse[1]) / bsize;
-
- float angle= atan2(fy, fx) - rot;
- float flen= sqrtf(fx*fx + fy*fy);
-
- fx = flen * cos(angle) + 0.5;
- fy = flen * sin(angle) + 0.5;
-
- avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
}
- }
-
- avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
-
- return avg;
-}
+ BLI_pbvh_vertex_iter_end;
-/* 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)
-{
- 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;
-
- /* 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;
-
- BLI_addtail(&ss->damaged_rects, rn);
-
- /* 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;
- }
- }
- // XXX: remember to fix this!
- // temporary pass
- ss->projverts[i].inside = 1;
+ BLI_pbvh_node_mark_update(nodes[n]);
}
}
static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
{
+ SculptSearchSphereData data;
Brush *brush = paint_brush(&sd->paint);
- float av_dist;
- ListBase active_verts={0,0};
- ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry];
- ActiveData *adata= 0;
- float *vert;
- const float bstrength= brush_strength(sd, cache);
- Brush *b = brush;
- int i;
+ PBVHNode **nodes= NULL;
+ int totnode;
- sculpt_add_damaged_rect(ss);
-
- /* 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= len_v3v3(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);
- }
- }
+ data.ss = ss;
+ data.sd = sd;
+ data.radius_squared = ss->cache->radius * ss->cache->radius;
+
+ /* Build a list of all nodes that are potentially within the brush's
+ area of influence */
+ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ if(cache->first_time) {
+ /* For the grab tool we store these nodes once in the beginning
+ and then reuse them. */
+ BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data,
+ &nodes, &totnode);
+
+ ss->cache->grab_active_nodes[ss->cache->symmetry]= nodes;
+ ss->cache->grab_active_totnode[ss->cache->symmetry]= totnode;
+ copy_v3_v3(ss->cache->grab_active_location[ss->cache->symmetry], ss->cache->location);
+ }
+ else {
+ nodes= ss->cache->grab_active_nodes[ss->cache->symmetry];
+ totnode= ss->cache->grab_active_totnode[ss->cache->symmetry];
+ copy_v3_v3(ss->cache->location, ss->cache->grab_active_location[ss->cache->symmetry]);
}
}
+ else {
+ BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data,
+ &nodes, &totnode);
+ }
/* 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(totnode) {
/* 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, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
- do_smooth_brush(sd, ss, &active_verts);
+ do_smooth_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ss, &active_verts);
+ do_pinch_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ss, &active_verts);
+ do_inflate_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ss);
+ do_grab_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ss, &active_verts);
+ do_layer_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_clay_brush(sd, ss, &active_verts, 0);
+ do_flatten_clay_brush(sd, ss, nodes, totnode, 0);
break;
case SCULPT_TOOL_CLAY:
- do_flatten_clay_brush(sd, ss, &active_verts, 1);
+ do_flatten_clay_brush(sd, ss, nodes, totnode, 1);
+ break;
}
- /* Copy the modified vertices from mesh to the active key */
+ /* copy the modified vertices from mesh to the active key */
if(ss->kb) mesh_to_key(ss->ob->data, ss->kb);
-
- if(ss->vertexcosnos && !ss->multires)
- BLI_freelistN(&active_verts);
- else {
- if(b->sculpt_tool != SCULPT_TOOL_GRAB)
- addlisttolist(&ss->damaged_verts, &active_verts);
- }
- }
+
+ if((brush->sculpt_tool != SCULPT_TOOL_GRAB) && nodes)
+ MEM_freeN(nodes);
+ }
}
/* Flip all the editdata across the axis/axes specified by symm. Used to
@@ -932,6 +1428,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
copy_v3_v3(cache->location, cache->true_location);
copy_v3_v3(cache->grab_delta_symmetry, cache->grab_delta);
cache->symmetry = 0;
+ cache->bstrength = brush_strength(sd, cache);
do_brush_action(sd, ss, cache);
for(i = 1; i <= symm; ++i) {
@@ -944,110 +1441,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];
-
- sub_v3_v3v3(&s1.x,&a.x,&b.x);
- sub_v3_v3v3(&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)
- copy_v3_v3(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_v3(&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 )
- normal_quad_v3( norm,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);
- else
- normal_tri_v3( norm,ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co);
- 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);
@@ -1065,28 +1458,15 @@ 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)
{
ModifierData *md;
for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
- if(modifier_isEnabled(md, eModifierMode_Realtime) && md->type != eModifierType_Multires)
- return 1;
+ if(modifier_isEnabled(md, eModifierMode_Realtime))
+ if(!ELEM(md->type, eModifierType_Multires, eModifierType_ShapeKey))
+ return 1;
}
return 0;
@@ -1094,7 +1474,7 @@ char sculpt_modifiers_active(Object *ob)
/* Sculpt mode handles multires differently from regular meshes, but only if
it's the last modifier on the stack and it is not on the first level */
-static struct MultiresModifierData *sculpt_multires_active(Object *ob)
+struct MultiresModifierData *sculpt_multires_active(Object *ob)
{
ModifierData *md, *nmd;
@@ -1116,22 +1496,46 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
return NULL;
}
-static void sculpt_update_mesh_elements(bContext *C)
+void sculpt_key_to_mesh(KeyBlock *kb, Object *ob)
{
- 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);
+ Mesh *me= ob->data;
+
+ key_to_mesh(kb, me);
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+}
+
+void sculpt_mesh_to_key(Object *ob, KeyBlock *kb)
+{
+ Mesh *me= ob->data;
+
+ mesh_to_key(me, kb);
+}
+void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
+{
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
+ SculptSession *ss = ob->sculpt;
+
ss->ob= ob;
+ if((ob->shapeflag & OB_SHAPE_LOCK) && !sculpt_multires_active(ob)) {
+ ss->kb= ob_get_keyblock(ob);
+ ss->refkb= ob_get_reference_keyblock(ob);
+ }
+ else {
+ ss->kb= NULL;
+ ss->refkb= NULL;
+ }
+
+ /* need to make PBVH with shape key coordinates */
+ if(ss->kb) sculpt_key_to_mesh(ss->kb, ss->ob);
+
if((ss->multires = sculpt_multires_active(ob))) {
- //DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
ss->totvert = dm->getNumVerts(dm);
ss->totface = dm->getNumFaces(dm);
- ss->mvert = dm->getVertDataArray(dm, CD_MVERT);
- ss->mface = dm->getFaceDataArray(dm, CD_MFACE);
- ss->face_normals = dm->getFaceDataArray(dm, CD_NORMAL);
+ ss->mvert= NULL;
+ ss->mface= NULL;
+ ss->face_normals= NULL;
}
else {
Mesh *me = get_mesh(ob);
@@ -1141,31 +1545,9 @@ static void sculpt_update_mesh_elements(bContext *C)
ss->mface = me->mface;
ss->face_normals = NULL;
}
- if( GPU_buffer_legacy( dm ) ) {
- ss->drawobject = 0;
- }
- else {
- ss->drawobject = dm->drawObject;
- }
- 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;
- }
-
- if((ob->shapeflag & OB_SHAPE_LOCK) && !sculpt_multires_active(ob)) {
- ss->kb= ob_get_keyblock(ob);
- ss->refkb= ob_get_reference_keyblock(ob);
- }
- else {
- ss->kb= NULL;
- ss->refkb= NULL;
- }
+ ss->tree = dm->getPBVH(ob, dm);
+ ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(dm): NULL;
}
static int sculpt_mode_poll(bContext *C)
@@ -1179,27 +1561,27 @@ int sculpt_poll(bContext *C)
return sculpt_mode_poll(C) && paint_poll(C);
}
-static void sculpt_undo_push(bContext *C, Sculpt *sd)
+static char *sculpt_tool_name(Sculpt *sd)
{
Brush *brush = paint_brush(&sd->paint);
switch(brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- ED_undo_push(C, "Draw Brush"); break;
+ return "Draw Brush"; break;
case SCULPT_TOOL_SMOOTH:
- ED_undo_push(C, "Smooth Brush"); break;
+ return "Smooth Brush"; break;
case SCULPT_TOOL_PINCH:
- ED_undo_push(C, "Pinch Brush"); break;
+ return "Pinch Brush"; break;
case SCULPT_TOOL_INFLATE:
- ED_undo_push(C, "Inflate Brush"); break;
+ return "Inflate Brush"; break;
case SCULPT_TOOL_GRAB:
- ED_undo_push(C, "Grab Brush"); break;
+ return "Grab Brush"; break;
case SCULPT_TOOL_LAYER:
- ED_undo_push(C, "Layer Brush"); break;
+ return "Layer Brush"; break;
case SCULPT_TOOL_FLATTEN:
- ED_undo_push(C, "Flatten Brush"); break;
+ return "Flatten Brush"; break;
default:
- ED_undo_push(C, "Sculpting"); break;
+ return "Sculpting"; break;
}
}
@@ -1251,28 +1633,26 @@ 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 len_v3v3(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 len_v3(delta);
}
static void sculpt_cache_free(StrokeCache *cache)
{
int i;
- if(cache->orig_norms)
- MEM_freeN(cache->orig_norms);
if(cache->face_norms)
MEM_freeN(cache->face_norms);
if(cache->mats)
MEM_freeN(cache->mats);
- for(i = 0; i < 8; ++i)
- BLI_freelistN(&cache->grab_active_verts[i]);
+ for(i = 0; i < 8; ++i) {
+ if(cache->grab_active_nodes[i])
+ MEM_freeN(cache->grab_active_nodes[i]);
+ }
MEM_freeN(cache);
}
@@ -1290,70 +1670,63 @@ 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");
copy_v2_v2(cache->mouse, cache->initial_mouse);
copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
/* Truly temporary data that isn't stored in properties */
- cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
- view3d_get_transformation(vc, vc->obact, cache->mats);
+ cache->vc = vc;
+ cache->brush = brush;
- sculpt_update_mesh_elements(C);
-
- /* Initialize layer brush displacements */
- if(brush->sculpt_tool == SCULPT_TOOL_LAYER &&
- (!ss->layer_disps || !(brush->flag & BRUSH_PERSISTENT))) {
- if(ss->layer_disps)
- MEM_freeN(ss->layer_disps);
- ss->layer_disps = MEM_callocN(sizeof(float) * ss->totvert, "layer brush displacements");
- }
-
- /* Make copies of the mesh vertex locations and normals for some tools */
- if(brush->sculpt_tool == SCULPT_TOOL_LAYER || (brush->flag & BRUSH_ANCHORED)) {
- if(brush->sculpt_tool != SCULPT_TOOL_LAYER ||
- !ss->mesh_co_orig || !(brush->flag & BRUSH_PERSISTENT)) {
- if(!ss->mesh_co_orig)
- ss->mesh_co_orig= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
+ cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
+ view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
+
+ /* Initialize layer brush displacements and persistent coords */
+ if(brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+ if(!ss->layer_disps || !(brush->flag & BRUSH_PERSISTENT)) {
+ if(ss->layer_disps)
+ MEM_freeN(ss->layer_disps);
+ ss->layer_disps = MEM_callocN(sizeof(float) * ss->totvert, "layer brush displacements");
+ }
+ if(!ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ if(!ss->layer_co)
+ ss->layer_co= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
for(i = 0; i < ss->totvert; ++i)
- copy_v3_v3(ss->mesh_co_orig[i], ss->mvert[i].co);
+ copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
}
+ }
- if(brush->flag & BRUSH_ANCHORED) {
- cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * ss->totvert, "Sculpt orig norm");
- for(i = 0; i < ss->totvert; ++i) {
- cache->orig_norms[i][0] = ss->mvert[i].no[0];
- cache->orig_norms[i][1] = ss->mvert[i].no[1];
- cache->orig_norms[i][2] = ss->mvert[i].no[2];
- }
-
- if(ss->face_normals) {
- float *fn = ss->face_normals;
- cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms");
- for(i = 0; i < ss->totface; ++i, fn += 3)
- copy_v3_v3(cache->face_norms[i], fn);
- }
+ /* Make copies of the mesh vertex locations and normals for some tools */
+ if(brush->flag & BRUSH_ANCHORED) {
+ if(ss->face_normals) {
+ float *fn = ss->face_normals;
+ cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms");
+ for(i = 0; i < ss->totface; ++i, fn += 3)
+ copy_v3_v3(cache->face_norms[i], fn);
}
+
+ cache->original = 1;
}
- 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);
+ if(ELEM3(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE))
+ if(!(brush->flag & BRUSH_ACCUMULATE))
+ cache->original = 1;
+
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);
- float grab_location[3];
int dx, dy;
- if(!(brush->flag & BRUSH_ANCHORED))
+ if(!(brush->flag & BRUSH_ANCHORED) || cache->first_time)
RNA_float_get_array(ptr, "location", cache->true_location);
cache->flip = RNA_boolean_get(ptr, "flip");
RNA_float_get_array(ptr, "mouse", cache->mouse);
@@ -1364,6 +1737,9 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
cache->previous_pixel_radius = cache->pixel_radius;
cache->pixel_radius = brush->size;
+ if(cache->first_time)
+ cache->initial_radius = unproject_brush_radius(cache->vc, cache->true_location, brush->size);
+
if(brush->flag & BRUSH_SIZE_PRESSURE) {
cache->pixel_radius *= cache->pressure;
cache->radius = cache->initial_radius * cache->pressure;
@@ -1378,7 +1754,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) {
@@ -1401,17 +1778,91 @@ 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);
+ float grab_location[3];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0], cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
if(!cache->first_time)
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
copy_v3_v3(cache->old_grab_location, grab_location);
}
}
+static void sculpt_stroke_modifiers_check(bContext *C, SculptSession *ss)
+{
+ if(sculpt_modifiers_active(ss->ob))
+ sculpt_update_mesh_elements(CTX_data_scene(C), ss->ob, 0); // XXX brush->sculpt_tool == SCULPT_TOOL_SMOOTH);
+}
+
+typedef struct {
+ SculptSession *ss;
+ float *ray_start, *ray_normal;
+ int hit;
+ float dist;
+ int original;
+} SculptRaycastData;
+
+void sculpt_raycast_cb(PBVHNode *node, void *data_v)
+{
+ SculptRaycastData *srd = data_v;
+ float (*origco)[3]= NULL;
+
+ if(srd->original && srd->ss->cache) {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode= sculpt_undo_get_node(srd->ss, node);
+ origco= (unode)? unode->co: NULL;
+ }
+
+ srd->hit |= BLI_pbvh_node_raycast(srd->ss->tree, node, origco,
+ srd->ray_start, srd->ray_normal, &srd->dist);
+}
+
+/* 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);
+ SculptSession *ss= vc->obact->sculpt;
+ StrokeCache *cache= ss->cache;
+ float ray_start[3], ray_normal[3];
+ float obimat[4][4];
+ float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
+ mouse[1] - vc->ar->winrct.ymin};
+ SculptRaycastData srd;
+
+ sculpt_stroke_modifiers_check(C, ss);
+
+ viewray(vc->ar, vc->v3d, mval, ray_start, ray_normal);
+
+ invert_m4_m4(obimat, ss->ob->obmat);
+ mul_m4_v3(obimat, ray_start);
+ mul_mat3_m4_v3(obimat, ray_normal);
+
+ srd.ss = vc->obact->sculpt;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.dist = FLT_MAX;
+ srd.hit = 0;
+ srd.original = (cache)? cache->original: 0;
+ BLI_pbvh_raycast(ss->tree, sculpt_raycast_cb, &srd,
+ ray_start, ray_normal, srd.original);
+
+ copy_v3_v3(out, ray_normal);
+ mul_v3_fl(out, srd.dist);
+ add_v3_v3v3(out, out, ray_start);
+
+ return srd.hit;
+}
+
/* Initialize stroke operator properties */
static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss)
{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob= CTX_data_active_object(C);
ModifierData *md;
float scale[3], clip_tolerance[3] = {0,0,0};
@@ -1444,18 +1895,15 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
mouse[0] = event->x;
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);
}
static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
{
+ Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ Brush *brush = paint_brush(&sd->paint);
if(ob_get_key(ob) && !(ob->shapeflag & OB_SHAPE_LOCK)) {
BKE_report(reports, RPT_ERROR, "Shape key sculpting requires a locked shape.");
@@ -1469,9 +1917,7 @@ static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
changes are made to the texture. */
sculpt_update_tex(sd, ss);
- sculpt_update_mesh_elements(C);
-
- if(ss->kb) key_to_mesh(ss->kb, ss->ob->data);
+ sculpt_update_mesh_elements(scene, ob, brush->sculpt_tool == SCULPT_TOOL_SMOOTH);
return 1;
}
@@ -1480,30 +1926,31 @@ 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) {
- copy_v3_v3(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(brush->flag & BRUSH_ANCHORED) {
+ PBVHNode **nodes;
+ int n, totnode;
+
+ BLI_pbvh_search_gather(ss->tree, NULL, NULL, &nodes, &totnode);
+
+ #pragma omp parallel for private(n) schedule(static)
+ for(n=0; n<totnode; n++) {
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_get_node(ss, nodes[n]);
+ if(unode) {
+ PBVHVertexIter vd;
+
+ BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ copy_v3_v3(vd.co, unode->co[vd.i]);
+ if(vd.no) VECCOPY(vd.no, unode->no[vd.i])
+ else normal_short_to_float_v3(vd.fno, unode->no[vd.i]);
}
+ BLI_pbvh_vertex_iter_end;
}
}
- if( buffer != 0 )
- GPU_buffer_unlock( ss->drawobject->normals );
if(ss->face_normals) {
float *fn = ss->face_normals;
@@ -1516,50 +1963,59 @@ 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;
+ int redraw = 0;
- calc_damaged_verts(ss);
-
- if(mmd) {
- if(mmd->undo_verts && mmd->undo_verts != ss->mvert)
- MEM_freeN(mmd->undo_verts);
-
- mmd->undo_verts = ss->mvert;
- mmd->undo_verts_tot = ss->totvert;
+ if(mmd)
multires_mark_as_modified(ob);
- }
- if(sculpt_modifiers_active(ob))
+ if(sculpt_modifiers_active(ob)) {
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ ED_region_tag_redraw(ar);
+ }
+ else {
+ rcti r;
- ED_region_tag_redraw(ar);
+ BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL);
+ 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;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ 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);
+
+ sculpt_update_cache_invariants(sd, ss, C, op);
+
+ sculpt_undo_push_begin(ss, sculpt_tool_name(sd));
return 1;
}
@@ -1572,13 +2028,13 @@ 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_stroke_modifiers_check(C, ss);
+ 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)
@@ -1588,14 +2044,18 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
/* Finished */
if(ss->cache) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- if(ss->refkb) key_to_mesh(ss->refkb, ob->data);
+ sculpt_stroke_modifiers_check(C, ss);
- request_depth_update(paint_stroke_view_context(stroke)->rv3d);
sculpt_cache_free(ss->cache);
ss->cache = NULL;
- sculpt_undo_push(C, sd);
+
+ sculpt_undo_push_end(ss);
+
+ BLI_pbvh_update(ss->tree, PBVH_UpdateOriginalBB, NULL);
+
+ if(ss->refkb) sculpt_key_to_mesh(ss->refkb, ob);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
}
}
@@ -1604,7 +2064,8 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
if(!sculpt_brush_stroke_init(C, op->reports))
return OPERATOR_CANCELLED;
- 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);
@@ -1624,18 +2085,16 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
if(!sculpt_brush_stroke_init(C, op->reports))
return OPERATOR_CANCELLED;
- 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_update_cache_invariants(sd, ss, C, op);
- sculptmode_update_all_projverts(ss);
paint_stroke_exec(C, op);
sculpt_flush_update(C);
sculpt_cache_free(ss->cache);
- sculpt_undo_push(C, sd);
-
return OPERATOR_FINISHED;
}
@@ -1670,9 +2129,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) ****/
@@ -1686,9 +2142,9 @@ static int sculpt_set_persistent_base(bContext *C, wmOperator *op)
MEM_freeN(ss->layer_disps);
ss->layer_disps = NULL;
- if(ss->mesh_co_orig)
- MEM_freeN(ss->mesh_co_orig);
- ss->mesh_co_orig = NULL;
+ if(ss->layer_co)
+ MEM_freeN(ss->layer_co);
+ ss->layer_co = NULL;
}
return OPERATOR_FINISHED;
@@ -1709,15 +2165,30 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
/**** Toggle operator for turning sculpt mode on or off ****/
+static void sculpt_init_session(Scene *scene, Object *ob)
+{
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+
+ sculpt_update_mesh_elements(scene, ob, 0);
+
+ if(ob->sculpt->refkb)
+ sculpt_key_to_mesh(ob->sculpt->refkb, ob);
+}
+
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
+ MultiresModifierData *mmd = sculpt_multires_active(ob);
if(ob->mode & OB_MODE_SCULPT) {
if(sculpt_multires_active(ob))
multires_force_update(ob);
+ if(mmd && mmd->sculptlvl != mmd->lvl)
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+
/* Leave sculptmode */
ob->mode &= ~OB_MODE_SCULPT;
@@ -1725,8 +2196,10 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
}
else {
/* Enter sculptmode */
-
ob->mode |= OB_MODE_SCULPT;
+
+ if(mmd && mmd->sculptlvl != mmd->lvl)
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
/* Create persistent sculpt mode data */
if(!ts->sculpt)
@@ -1735,7 +2208,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(scene, ob);
paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
@@ -1767,3 +2241,4 @@ void ED_operatortypes_sculpt()
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
}
+
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 15ccacc294a..0e1c0510902 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -35,7 +35,9 @@
struct bContext;
struct Brush;
+struct KeyBlock;
struct Mesh;
+struct MultiresModifierData;
struct Object;
struct Scene;
struct Sculpt;
@@ -47,6 +49,7 @@ void sculptmode_draw_mesh(int);
void sculpt_paint_brush(char clear);
void sculpt_stroke_draw(struct SculptStroke *);
void sculpt_radialcontrol_start(int mode);
+struct MultiresModifierData *sculpt_multires_active(struct Object *ob);
struct Brush *sculptmode_brush(void);
//void do_symmetrical_brush_actions(struct Sculpt *sd, struct wmOperator *wm, struct BrushAction *a, short *, short *);
@@ -55,6 +58,9 @@ char sculpt_modifiers_active(struct Object *ob);
void sculpt(Sculpt *sd);
int sculpt_poll(struct bContext *C);
+void sculpt_update_mesh_elements(struct Scene *scene, struct Object *ob, int need_fmap);
+void sculpt_key_to_mesh(struct KeyBlock *kb, struct Object *ob);
+void sculpt_mesh_to_key(struct Object *ob, struct KeyBlock *kb);
/* Stroke */
struct SculptStroke *sculpt_stroke_new(const int max);
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index a1f9a9fd250..93bedd0b866 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -310,6 +310,8 @@ static int get_file_icon(struct direntry *file)
return ICON_FILE_SOUND;
else if (file->flags & FTFONTFILE)
return ICON_FILE_FONT;
+ else if (file->flags & BTXFILE)
+ return ICON_FILE_BLANK;
else
return ICON_FILE_BLANK;
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 640f365b073..81aa63dcad9 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -871,6 +871,8 @@ void filelist_setfiletypes(struct FileList* filelist, short has_quicktime)
|| BLI_testextensie(file->relname, ".otf")
|| BLI_testextensie(file->relname, ".otc")) {
file->flags |= FTFONTFILE;
+ } else if(BLI_testextensie(file->relname, ".btx")) {
+ file->flags |= BTXFILE;
} else if (has_quicktime){
if( BLI_testextensie(file->relname, ".int")
|| BLI_testextensie(file->relname, ".inta")
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index d681a58b276..bf580545455 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -161,6 +161,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0;
if(RNA_struct_find_property(op->ptr, "filter_folder"))
params->filter |= RNA_boolean_get(op->ptr, "filter_folder") ? FOLDERFILE : 0;
+ if(RNA_struct_find_property(op->ptr, "filter_btx"))
+ params->filter |= RNA_boolean_get(op->ptr, "filter_btx") ? BTXFILE : 0;
if (params->filter != 0)
params->flag |= FILE_FILTER;
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 31c12285293..edb91f2b0c9 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -108,6 +108,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"
@@ -2703,7 +2704,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, 0, GPU_enable_material);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GPU_disable_material();
}
@@ -2722,7 +2723,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;
@@ -2795,7 +2796,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 );
@@ -2803,7 +2804,23 @@ 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) {
+ Paint *p = paint_get_active(scene);
+ float planes[4][4];
+ float (*fpl)[4] = NULL;
+ int fast= (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
+
+ if(ob->sculpt->partial_redraw) {
+ sculpt_get_redraw_planes(planes, ar, rv3d, ob);
+ fpl = planes;
+ ob->sculpt->partial_redraw = 0;
+ }
+
+ dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material);
+ }
+ else
+ dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+
GPU_disable_material();
glFrontFace(GL_CCW);
@@ -2814,7 +2831,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... */
@@ -2932,7 +2950,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;
@@ -2967,10 +2985,6 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
if (obedit!=ob && finalDM)
finalDM->release(finalDM);
}
-// else if(!em && (G.f & G_SCULPTMODE) &&(scene->sculptdata.flags & SCULPT_DRAW_FAST) &&
-// OBACT==ob && !sculpt_modifiers_active(ob)) {
-// XXX sculptmode_draw_mesh(0);
-// }
else {
/* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
if(me->totface<=4 || boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) {
@@ -2982,7 +2996,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();
@@ -5744,7 +5758,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;
@@ -6333,10 +6347,8 @@ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob)
int ind;
colors = MEM_mallocN(dm->getNumFaces(dm)*sizeof(MCol)*4,"bbs_mesh_solid");
for(i=0;i<dm->getNumFaces(dm);i++) {
- if( index != 0 )
- ind = index[i];
- else
- ind = i;
+ ind= ( index )? index[i]: i;
+
if (face_sel_mode==0 || !(me->mface[ind].flag&ME_HIDE)) {
unsigned int fbindex = index_to_framebuffer(ind+1);
for(j=0;j<4;j++) {
@@ -6463,7 +6475,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, 0, 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 5a2040a44aa..19667beaaf9 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1643,37 +1643,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;
@@ -1891,8 +1860,6 @@ static CustomDataMask get_viewedit_datamask(bScreen *screen, Scene *scene, Objec
mask |= CD_MASK_MCOL;
if(ob->mode & OB_MODE_WEIGHT_PAINT)
mask |= CD_MASK_WEIGHT_MCOL;
- if(ob->mode & OB_MODE_SCULPT)
- mask |= CD_MASK_MDISPS;
}
return mask;
@@ -2137,7 +2104,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);
@@ -2150,8 +2117,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);
}
@@ -2166,8 +2131,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);
}
@@ -2189,8 +2152,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 fd20b534dd7..6a58e3c2e8d 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -278,7 +278,7 @@ static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
}
-static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
+static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
{
static float lastofs[3] = {0,0,0};
View3D *v3d = CTX_wm_view3d(C);
@@ -359,6 +359,21 @@ static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
if (rv3d->persmat[2][1] < 0.0f)
vod->reverse= -1.0f;
+ rv3d->rflag |= RV3D_NAVIGATING;
+}
+
+static void viewops_data_free(bContext *C, wmOperator *op)
+{
+ Paint *p = paint_get_active(CTX_data_scene(C));
+ ViewOpsData *vod= op->customdata;
+
+ vod->rv3d->rflag &= ~RV3D_NAVIGATING;
+
+ if(p && (p->flags & PAINT_FAST_NAVIGATE))
+ ED_region_tag_redraw(vod->ar);
+
+ MEM_freeN(vod);
+ op->customdata= NULL;
}
/* ************************** viewrotate **********************************/
@@ -622,9 +637,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
}
else if (event_code==VIEW_CONFIRM) {
request_depth_update(CTX_wm_region_view3d(C));
-
- MEM_freeN(vod);
- op->customdata= NULL;
+ viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -641,7 +654,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_CANCELLED;
/* makes op->customdata */
- viewops_data(C, op, event);
+ viewops_data_create(C, op, event);
vod= op->customdata;
/* switch from camera view when: */
@@ -762,8 +775,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
else if (event_code==VIEW_CONFIRM) {
request_depth_update(CTX_wm_region_view3d(C));
- MEM_freeN(vod);
- op->customdata= NULL;
+ viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -774,7 +786,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
/* makes op->customdata */
- viewops_data(C, op, event);
+ viewops_data_create(C, op, event);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -966,9 +978,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
}
else if (event_code==VIEW_CONFIRM) {
request_depth_update(CTX_wm_region_view3d(C));
-
- MEM_freeN(vod);
- op->customdata= NULL;
+ viewops_data_free(C, op);
return OPERATOR_FINISHED;
}
@@ -1029,7 +1039,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
else {
/* makes op->customdata */
- viewops_data(C, op, event);
+ viewops_data_create(C, op, event);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -1971,12 +1981,9 @@ void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
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");
@@ -1989,36 +1996,9 @@ 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);
-
- gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
- VECCOPY(rv3d->clipbb->vec[4+val], p);
- }
-
- /* then plane equations */
- calc_clipping_plane(rv3d->clip, rv3d->clipbb);
+ view3d_set_viewcontext(C, &vc);
+ view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
+ view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index e7ebcbdb849..a1135bf6986 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;
- mul_m4_m4m4(cpy, ob->obmat, vc->rv3d->viewmat);
+ mul_m4_m4m4(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 9cd9d12b975..a569eff1ebe 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -287,6 +287,8 @@ void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, flo
/* ensure it shows correct */
if(sms.to_camera) rv3d->persp= RV3D_PERSP;
+
+ rv3d->rflag |= RV3D_NAVIGATING;
/* keep track of running timer! */
if(rv3d->sms==NULL)
@@ -349,6 +351,7 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *op, wmEvent *event)
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
rv3d->smooth_timer= NULL;
+ rv3d->rflag &= ~RV3D_NAVIGATING;
}
else {
int i;
@@ -486,6 +489,44 @@ 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++) {
+
+ normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
+
+ 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])
{
@@ -501,8 +542,8 @@ void viewline(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float
mul_m4_v4(rv3d->persinv, vec);
mul_v3_fl(vec, 1.0f / vec[3]);
- VECCOPY(ray_start, rv3d->viewinv[3]);
- VECSUB(vec, vec, ray_start);
+ copy_v3_v3(ray_start, rv3d->viewinv[3]);
+ sub_v3_v3v3(vec, vec, ray_start);
normalize_v3(vec);
VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
@@ -1920,7 +1961,7 @@ int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event)
fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer();
- fly->rv3d->rflag |= RV3D_FLYMODE; /* so we draw the corner margins */
+ fly->rv3d->rflag |= RV3D_FLYMODE|RV3D_NAVIGATING; /* so we draw the corner margins */
/* detect weather to start with Z locking */
upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f;
@@ -2019,7 +2060,7 @@ static int flyEnd(bContext *C, FlyInfo *fly)
/*Done with correcting for the dist */
}
- rv3d->rflag &= ~RV3D_FLYMODE;
+ rv3d->rflag &= ~(RV3D_FLYMODE|RV3D_NAVIGATING);
//XXX2.5 BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index ae1e932bb81..fc2576eef5d 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -60,7 +60,7 @@ void ED_editors_exit(bContext *C)
/* frees all editmode undos */
undo_editmode_clear();
- undo_imagepaint_clear();
+ ED_undo_paint_free();
for(sce=G.main->scene.first; sce; sce= sce->id.next) {
if(sce->obedit) {
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index d26f7a7a484..e20c88ba41f 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -124,7 +124,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
- undo_imagepaint_step(step);
+ ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
@@ -146,7 +146,9 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
int do_glob_undo= 0;
if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
- undo_imagepaint_step(step);
+ ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
+ else if(obact && obact->mode & OB_MODE_SCULPT)
+ ED_undo_paint_step(C, UNDO_PAINT_MESH, step);
else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
if(step==1)
PE_undo(CTX_data_scene(C));