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_mesh.h7
-rw-r--r--source/blender/editors/include/ED_sculpt.h23
-rw-r--r--source/blender/editors/interface/interface_templates.c5
-rw-r--r--source/blender/editors/mesh/mesh_data.c82
-rw-r--r--source/blender/editors/mesh/mesh_intern.h1
-rw-r--r--source/blender/editors/mesh/mesh_ops.c1
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_modifier.c41
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/SConscript1
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h169
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c555
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c67
-rw-r--r--source/blender/editors/sculpt_paint/paint_overlay.c427
-rw-r--r--source/blender/editors/sculpt_paint/paint_ptex.c1414
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c609
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c244
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c331
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c588
-rw-r--r--source/blender/editors/sculpt_paint/pbvh_undo.c570
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1857
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h69
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c302
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c106
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c44
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c2
-rw-r--r--source/blender/editors/util/undo.c2
29 files changed, 5271 insertions, 2251 deletions
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 22779fbba0b..c866b12ed22 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -58,6 +58,7 @@ struct CustomData;
struct Material;
struct Object;
struct rcti;
+struct CustomDataLayer;
#define EM_FGON_DRAW 1 // face flag
#define EM_FGON 2 // edge and face flag both
@@ -220,6 +221,10 @@ void ED_mesh_faces_add(struct Mesh *mesh, struct ReportList *reports, int count)
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_delete_customdata_layer(struct bContext *C, struct Object *ob, struct CustomDataLayer *layer);
+
+void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
+
void ED_mesh_transform(struct Mesh *me, float *mat);
void ED_mesh_calc_normals(struct Mesh *me);
void ED_mesh_material_link(struct Mesh *me, struct Material *ma);
@@ -230,6 +235,8 @@ int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh
int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set);
int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
+int ED_mesh_layers_poll(struct bContext *C);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 506813ce626..67e65409e6c 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -30,16 +30,16 @@
struct ARegion;
struct bContext;
+struct MultiresModifierData;
struct Object;
+struct PaintOverlay;
struct RegionView3D;
+struct Scene;
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);
@@ -52,4 +52,21 @@ void ED_keymap_paint(struct wmKeyConfig *keyconf);
int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
void ED_undo_paint_free(void);
+typedef struct PaintLayerUndoNode PaintLayerUndoNode;
+PaintLayerUndoNode *paint_layer_undo_push(int type, char *description);
+void paint_layer_undo_set_add(PaintLayerUndoNode *unode, char *name);
+void paint_layer_undo_set_remove(PaintLayerUndoNode *unode, char *name,
+ struct CustomData *data, struct CustomData *fdata,
+ int totvert, int totface);
+
+/* paint_util.c */
+struct MultiresModifierData *ED_paint_multires_active(struct Scene *scene, struct Object *ob);
+void paint_get_redraw_planes(float planes[4][4], struct ARegion *ar,
+ struct RegionView3D *rv3d, struct Object *ob);
+void ED_paint_force_update(struct bContext *C);
+
+/* paint_vertex.c */
+void ED_paint_overlay_draw(const struct bContext *C, struct ARegion *ar);
+void ED_paint_update_overlay(struct PaintOverlay *overlay);
+
#endif
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index bbbb5bec7c0..c7edec09340 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2013,6 +2013,11 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe
//uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
uiBlockSetEmboss(block, UI_EMBOSS);
}
+ else if(itemptr->type == &RNA_MeshPaintMaskLayer) {
+ uiItemL(sub, name, icon);
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "enabled", 0, 0, 0, 0, 0, NULL);
+ }
else
uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 080151a8dca..39489dc7264 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -45,6 +45,7 @@
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_multires.h"
#include "BKE_report.h"
#include "BLI_math.h"
@@ -59,6 +60,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_sculpt.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -66,7 +68,7 @@
#include "mesh_intern.h"
-static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
+void ED_mesh_delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
{
Mesh *me = ob->data;
CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
@@ -207,7 +209,7 @@ int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
if(!cdl)
return 0;
- delete_customdata_layer(C, ob, cdl);
+ ED_mesh_delete_customdata_layer(C, ob, cdl);
DAG_id_flush_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -270,7 +272,7 @@ int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
if(!cdl)
return 0;
- delete_customdata_layer(C, ob, cdl);
+ ED_mesh_delete_customdata_layer(C, ob, cdl);
DAG_id_flush_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -279,7 +281,7 @@ int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
/*********************** UV texture operators ************************/
-static int layers_poll(bContext *C)
+int ED_mesh_layers_poll(bContext *C)
{
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
ID *data= (ob)? ob->data: NULL;
@@ -305,7 +307,7 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot)
ot->idname= "MESH_OT_uv_texture_add";
/* api callbacks */
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
ot->exec= uv_texture_add_exec;
/* flags */
@@ -379,7 +381,7 @@ void MESH_OT_drop_named_image(wmOperatorType *ot)
ot->idname= "MESH_OT_drop_named_image";
/* api callbacks */
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
ot->invoke= drop_named_image_invoke;
/* flags */
@@ -409,7 +411,7 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
ot->idname= "MESH_OT_uv_texture_remove";
/* api callbacks */
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
ot->exec= uv_texture_remove_exec;
/* flags */
@@ -418,6 +420,37 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
/*********************** vertex color operators ************************/
+static int vertex_color_multires_toggle(Object *ob)
+{
+ Mesh *me= ob->data;
+ CustomDataMultires *cdm;
+ CustomDataLayer *cdl;
+ int active;
+
+ /* so that dm is recalculated correctly after */
+ multires_force_update(ob);
+
+ active = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
+ cdm = CustomData_get_layer(&me->fdata, CD_GRIDS);
+
+ if(active == -1)
+ return 1;
+
+ cdl = &me->fdata.layers[active];
+
+ if(cdm) {
+ if(cdl->flag & CD_FLAG_MULTIRES)
+ CustomData_multires_remove_layers(cdm, me->totface, CD_MCOL, cdl->name);
+ else
+ CustomData_multires_add_layers(cdm, me->totface, CD_MCOL, cdl->name);
+ }
+
+ /* note - if there's no griddata, it can still be synced up later */
+ cdl->flag ^= CD_FLAG_MULTIRES;
+
+ return 1;
+}
+
static int vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
@@ -427,6 +460,10 @@ static int vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
if(!ED_mesh_color_add(C, scene, ob, me, NULL, TRUE))
return OPERATOR_CANCELLED;
+ if((ob->mode & OB_MODE_VERTEX_PAINT) &&
+ ED_paint_multires_active(scene, ob))
+ vertex_color_multires_toggle(ob);
+
return OPERATOR_FINISHED;
}
@@ -438,7 +475,7 @@ void MESH_OT_vertex_color_add(wmOperatorType *ot)
ot->idname= "MESH_OT_vertex_color_add";
/* api callbacks */
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
ot->exec= vertex_color_add_exec;
/* flags */
@@ -465,7 +502,30 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec= vertex_color_remove_exec;
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int vertex_color_multires_toggle_exec(bContext *C, wmOperator *op)
+{
+ if(vertex_color_multires_toggle(CTX_data_active_object(C)))
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void MESH_OT_vertex_color_multiresolution_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Color Multiresolution Toggle";
+ ot->description= "Add or remove multiresolution data from this layer";
+ ot->idname= "MESH_OT_vertex_color_multiresolution_toggle";
+
+ /* api callbacks */
+ ot->exec= vertex_color_multires_toggle_exec;
+ ot->poll= ED_mesh_layers_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -499,7 +559,7 @@ void MESH_OT_sticky_add(wmOperatorType *ot)
ot->idname= "MESH_OT_sticky_add";
/* api callbacks */
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
ot->exec= sticky_add_exec;
/* flags */
@@ -531,7 +591,7 @@ void MESH_OT_sticky_remove(wmOperatorType *ot)
ot->idname= "MESH_OT_sticky_remove";
/* api callbacks */
- ot->poll= layers_poll;
+ ot->poll= ED_mesh_layers_poll;
ot->exec= sticky_remove_exec;
/* flags */
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index fcd1eb40a02..89186f2d1f6 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -249,6 +249,7 @@ void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
+void MESH_OT_vertex_color_multiresolution_toggle(struct wmOperatorType *ot);
void MESH_OT_sticky_add(struct wmOperatorType *ot);
void MESH_OT_sticky_remove(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 2ff7095cfea..5eb6fea362f 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -133,6 +133,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_uv_texture_remove);
WM_operatortype_append(MESH_OT_vertex_color_add);
WM_operatortype_append(MESH_OT_vertex_color_remove);
+ WM_operatortype_append(MESH_OT_vertex_color_multiresolution_toggle);
WM_operatortype_append(MESH_OT_sticky_add);
WM_operatortype_append(MESH_OT_sticky_remove);
WM_operatortype_append(MESH_OT_drop_named_image);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index ed75c4060a2..9222b33aa8f 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -153,6 +153,7 @@ void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
+void OBJECT_OT_multires_base_apply(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 c273b375a06..0eb2d89061a 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -1147,6 +1147,47 @@ void OBJECT_OT_multires_external_pack(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
+/********************* multires apply base ***********************/
+static int multires_base_apply_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires);
+
+ if (!mmd)
+ return OPERATOR_CANCELLED;
+
+ multiresModifier_base_apply(mmd, ob);
+
+ 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_base_apply_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return multires_base_apply_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+
+void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
+{
+ ot->name= "Multires Apply Base";
+ ot->description= "Modify the base mesh to conform to the displaced mesh";
+ ot->idname= "OBJECT_OT_multires_base_apply";
+
+ ot->poll= multires_poll;
+ ot->invoke= multires_base_apply_invoke;
+ ot->exec= multires_base_apply_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ edit_modifier_properties(ot);
+}
+
/************************ mdef bind operator *********************/
static int meshdeform_poll(bContext *C)
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 221d1211930..d09cc9a7626 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -136,6 +136,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
WM_operatortype_append(OBJECT_OT_multires_external_save);
WM_operatortype_append(OBJECT_OT_multires_external_pack);
+ WM_operatortype_append(OBJECT_OT_multires_base_apply);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 3211763b619..96bfab97c5f 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,6 +27,7 @@ SET(INC
../../imbuf
../../gpu
../../blenlib
+ ../../../../extern/ptex
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index 2902b21fff1..4c49b19d307 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -9,6 +9,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
incs += ' ../../gpu ../../makesrna'
+incs += ' #/extern/ptex'
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 6232a8f2de1..68599dfcda2 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -29,10 +29,17 @@
#ifndef ED_PAINT_INTERN_H
#define ED_PAINT_INTERN_H
+#include "BLI_pbvh.h"
+
struct bContext;
+struct Brush;
struct Scene;
struct Object;
struct Mesh;
+struct Multires;
+struct Object;
+struct Paint;
+struct PaintOverlay;
struct PaintStroke;
struct PointerRNA;
struct ViewContext;
@@ -44,24 +51,83 @@ struct VPaint;
struct ListBase;
/* paint_stroke.c */
-typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
+typedef struct PaintStroke PaintStroke;
+typedef int (*StrokeGetLocation)(struct bContext *C, 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);
+typedef void (*StrokeUpdateStep)(struct bContext *C, PaintStroke *stroke, struct PointerRNA *itemptr);
+typedef void (*StrokeUpdateSymmetry)(struct bContext *C, PaintStroke *stroke,
+ char symmetry, char axis, float angle,
+ int mirror_symmetry_pass, int radial_symmetry_pass,
+ float (*symmetry_rot_mat)[4]);
+typedef void (*StrokeBrushAction)(struct bContext *C, PaintStroke *stroke);
+typedef void (*StrokeDone)(struct bContext *C, PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(struct bContext *C,
- StrokeGetLocation get_location, StrokeTestStart test_start,
- StrokeUpdateStep update_step, StrokeDone done);
-void paint_stroke_free(struct PaintStroke *stroke);
+PaintStroke *paint_stroke_new(struct bContext *C,
+ StrokeGetLocation get_location,
+ StrokeTestStart test_start,
+ StrokeUpdateStep update_step,
+ StrokeUpdateSymmetry update_symmetry,
+ StrokeBrushAction brush_action,
+ StrokeDone done);
+void paint_stroke_free(PaintStroke *stroke);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
+void paint_stroke_apply_brush(struct bContext *C, PaintStroke *stroke, struct Paint *paint);
+float paint_stroke_combined_strength(PaintStroke *stroke,
+ float dist, float co[3], float mask);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
-struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
-void *paint_stroke_mode_data(struct PaintStroke *stroke);
-void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
+void *paint_stroke_mode_data(PaintStroke *stroke);
+void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data);
+
+/* paint stroke cache access */
+struct ViewContext *paint_stroke_view_context(PaintStroke *stroke);
+float paint_stroke_feather(PaintStroke *stroke);
+void paint_stroke_mouse_location(PaintStroke *stroke, float mouse[2]);
+void paint_stroke_initial_mouse_location(PaintStroke *stroke, float initial_mouse[2]);
+void paint_stroke_location(PaintStroke *stroke, float location[3]);
+float paint_stroke_pressure(PaintStroke *stroke);
+float paint_stroke_radius(PaintStroke *stroke);
+float paint_stroke_radius_squared(PaintStroke *stroke);
+void paint_stroke_symmetry_location(PaintStroke *stroke, float loc[3]);
+int paint_stroke_first_dab(PaintStroke *stroke);
+void paint_stroke_project(PaintStroke *stroke, float loc[3], float out[2]);
+void paint_stroke_symmetry_unflip(PaintStroke *stroke, float out[3], float vec[3]);
+
+/* paint stroke modifiers */
+void paint_stroke_set_modifier_use_original_location(PaintStroke *stroke);
+void paint_stroke_set_modifier_initial_radius_factor(PaintStroke *stroke, float initial_radius_factor);
+void paint_stroke_set_modifier_use_original_texture_coords(PaintStroke *stroke);
+
+typedef struct {
+ void *mode_data;
+ struct Object *ob;
+ float *ray_start, *ray_normal;
+ int hit;
+ float dist;
+ int original;
+} PaintStrokeRaycastData;
+
+int paint_stroke_over_mesh(struct bContext *C, PaintStroke *stroke, int x, int y);
+int paint_stroke_get_location(struct bContext *C, PaintStroke *stroke,
+ BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
+ float out[3], float mouse[2], int original);
+
int paint_poll(struct bContext *C);
void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C));
+typedef struct PaintStrokeTest {
+ float radius_squared;
+ float location[3];
+ float dist;
+} PaintStrokeTest;
+void paint_stroke_test_init(PaintStrokeTest *test, PaintStroke *stroke);
+int paint_stroke_test(PaintStrokeTest *test, float co[3]);
+int paint_stroke_test_sq(PaintStrokeTest *test, float co[3]);
+int paint_stroke_test_fast(PaintStrokeTest *test, float co[3]);
+int paint_stroke_test_cube(PaintStrokeTest *test, float co[3],
+ float local[4][4]);
+float paint_stroke_test_dist(PaintStrokeTest *test);
+
/* paint_vertex.c */
int weight_paint_poll(struct bContext *C);
int weight_paint_mode_poll(struct bContext *C);
@@ -80,7 +146,6 @@ void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_radial_control(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
-
unsigned int vpaint_get_current_col(struct VPaint *vp);
/* paint_image.c */
@@ -110,6 +175,24 @@ void PAINT_OT_face_select_all(struct wmOperatorType *ot);
int facemask_paint_poll(struct bContext *C);
+float paint_calc_object_space_radius(struct ViewContext *vc,
+ float center[3],
+ float pixel_radius);
+
+void paint_tag_partial_redraw(struct bContext *C, struct Object *ob);
+
+void paint_flip_coord(float out[3], float in[3], const char symm);
+
+float brush_tex_strength(struct ViewContext *vc,
+ float pmat[4][4], struct Brush *br,
+ float co[3], float mask, const float len,
+ float pixel_radius, float radius3d,
+ float special_rotation, float tex_mouse[2]);
+
+int paint_util_raycast(struct ViewContext *vc,
+ BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
+ float out[3], float mouse[2], int original);
+
/* stroke operator */
typedef enum wmBrushStrokeMode {
WM_BRUSHSTROKE_NORMAL,
@@ -126,5 +209,69 @@ 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);
+/* paint_mask.c */
+void paintmask_brush_apply(struct Paint *paint, PaintStroke *stroke,
+ struct PBVHNode **nodes,
+ int totnode, float bstrength);
+
+void PAINT_OT_mask_layer_add(struct wmOperatorType *ot);
+void PAINT_OT_mask_layer_remove(struct wmOperatorType *ot);
+
+typedef enum {
+ MASKING_CLEAR,
+ MASKING_FILL,
+ MASKING_INVERT,
+ MASKING_RANDOM,
+} MaskSetMode;
+void PAINT_OT_mask_set(struct wmOperatorType *ot);
+void PAINT_OT_mask_from_texture(struct wmOperatorType *ot);
+
+/* pbvh_undo.c */
+typedef enum {
+ PBVH_UNDO_CO_NO = (1<<0),
+ PBVH_UNDO_PMASK = (1<<1),
+ PBVH_UNDO_PTEX = (1<<2)
+} PBVHUndoFlag;
+
+typedef struct PBVHUndoNode PBVHUndoNode;
+
+PBVHUndoNode *pbvh_undo_push_node(PBVHNode *node, PBVHUndoFlag flag,
+ struct Object *ob, struct Scene *scene);
+void pbvh_undo_push_begin(char *name);
+void pbvh_undo_push_end(void);
+/* undo node access */
+PBVHUndoNode *pbvh_undo_get_node(struct PBVHNode *node);
+typedef float (*pbvh_undo_f3)[3];
+typedef short (*pbvh_undo_s3)[3];
+int pbvh_undo_node_totvert(PBVHUndoNode *unode);
+pbvh_undo_f3 pbvh_undo_node_co(PBVHUndoNode *unode);
+pbvh_undo_s3 pbvh_undo_node_no(PBVHUndoNode *unode);
+float *pbvh_undo_node_layer_disp(PBVHUndoNode *unode);
+void pbvh_undo_node_set_layer_disp(PBVHUndoNode *unode, float *layer_disp);
+const char *pbvh_undo_node_mptex_name(PBVHUndoNode *unode);
+void *pbvh_undo_node_mptex_data(PBVHUndoNode *unode, int ndx);
+
+/* paint_ptex.c */
+void PTEX_OT_layer_add(struct wmOperatorType *ot);
+void PTEX_OT_layer_remove(struct wmOperatorType *ot);
+void PTEX_OT_layer_save(struct wmOperatorType *ot);
+void PTEX_OT_layer_convert(struct wmOperatorType *ot);
+void PTEX_OT_open(struct wmOperatorType *ot);
+void PTEX_OT_face_resolution_set(struct wmOperatorType *ot);
+void PTEX_OT_subface_select(struct wmOperatorType *ot);
+void PTEX_OT_select_all(struct wmOperatorType *ot);
+void PTEX_OT_subface_flag_set(struct wmOperatorType *ot);
+
+/* paint_overlay.c */
+int paint_sample_overlay(PaintStroke *stroke, float col[3], float co[2]);
+typedef enum {
+ PAINT_MANIP_GRAB,
+ PAINT_MANIP_SCALE,
+ PAINT_MANIP_ROTATE
+} PaintManipAction;
+void paint_overlay_transform(struct PaintOverlay *overlay, struct ARegion *ar, struct ImBuf *ibuf,
+ int out[2], float vec[2], int scale, int rotate);
+void PAINT_OT_overlay_manipulate(struct wmOperatorType *ot);
+
#endif /* ED_PAINT_INTERN_H */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
new file mode 100644
index 00000000000..fb9624b8f60
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -0,0 +1,555 @@
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
+#include "BKE_mesh.h"
+#include "BKE_multires.h"
+#include "BKE_paint.h"
+#include "BKE_texture.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_pbvh.h"
+#include "BLI_string.h"
+
+#include "ED_mesh.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
+
+/* for redraw, just need to update the pbvh's vbo buffers */
+static void paintmask_redraw(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ paint_refresh_mask_display(ob);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+}
+
+static int mask_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return ob && get_mesh(ob) && ob->paint &&
+ (ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT));
+}
+
+static int mask_active_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if(mask_poll(C)) {
+ Mesh *me = get_mesh(ob);
+ return CustomData_get_active_layer_index(&me->vdata, CD_PAINTMASK) != -1;
+ }
+
+ return 0;
+}
+
+void paintmask_brush_apply(Paint *paint, PaintStroke *stroke, PBVHNode **nodes, int totnode,
+ float bstrength)
+{
+ Object *ob = paint_stroke_view_context(stroke)->obact;
+ int n;
+
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ PaintStrokeTest test;
+
+ pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, NULL);
+ paint_stroke_test_init(&test, stroke);
+
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ /* TODO: should add a mask layer if needed */
+ if(vd.mask_active) {
+ if(paint_stroke_test(&test, vd.co)) {
+ float fade;
+
+ fade = paint_stroke_combined_strength(stroke,
+ test.dist,
+ vd.co,
+ 0) *
+ bstrength;
+
+ *vd.mask_active += fade;
+ CLAMP(*vd.mask_active, 0, 1);
+
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+
+ BLI_pbvh_node_set_flags(nodes[n], SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|PBVH_UpdateRedraw));
+ }
+}
+
+static float get_tex_mask_strength(MTex *tex_slot, float *uv, float vco[3])
+{
+ float texvec[3] = {0, 0, 0};
+ TexResult texres;
+ int mapping = tex_slot->texco;
+
+ if(mapping == TEXCO_UV && !uv)
+ mapping = TEXCO_ORCO;
+
+ switch(tex_slot->texco) {
+ case TEXCO_UV:
+ texvec[0] = uv[0] * 2 - 1;
+ texvec[1] = uv[1] * 2 - 1;
+ break;
+ default:
+ copy_v3_v3(texvec, vco);
+ }
+
+ memset(&texres, 0, sizeof(TexResult));
+ get_texture_value(tex_slot->tex, texvec, &texres);
+
+ return texres.tin;
+}
+
+/* Set the value of a single mask element from either a UV or a coord */
+#define SET_MASK(elem, uv) \
+ GRIDELEM_MASK(elem, gridkey)[active] = \
+ get_tex_mask_strength(tex_slot, uv, \
+ GRIDELEM_CO(elem, gridkey)) \
+
+/* Fill active mask layer of entire grid from either MTFaces or coords */
+static void mask_grid_from_tex(DMGridData *grid, int gridsize,
+ GridKey *gridkey, MTFace *mtface,
+ MTex *tex_slot, int active)
+{
+ int x, y, boundary;
+
+ boundary = gridsize - 2;
+
+ for(y = 0; y <= boundary; ++y) {
+ for(x = 0; x <= boundary; ++x) {
+ SET_MASK(GRIDELEM_AT(grid, y*gridsize+x, gridkey),
+ mtface ? mtface->uv[0] : NULL);
+
+ /* Do the edge of the grid separately because the UV
+ grid is one element smaller on each side compared
+ to the vert-data grid */
+ if(x == boundary && y == boundary) {
+ SET_MASK(GRIDELEM_AT(grid, (y+1)*gridsize+x+1, gridkey),
+ mtface ? mtface->uv[2] : NULL);
+ }
+ if(x == boundary) {
+ SET_MASK(GRIDELEM_AT(grid, y*gridsize+x+1, gridkey),
+ mtface ? mtface->uv[3] : NULL);
+ }
+ if(y == boundary) {
+ SET_MASK(GRIDELEM_AT(grid, (y+1)*gridsize+x, gridkey),
+ mtface ? mtface->uv[1] : NULL);
+ }
+
+ if(mtface) ++mtface;
+ }
+ }
+}
+
+static void mask_face_from_tex(MFace *f, MVert *mvert, MTFace *mtface,
+ float *pmask, MTex *tex_slot, int active)
+{
+ int S = f->v4 ? 4 : 3;
+ int i;
+
+ /* Masks are per-vertex, not per-face-corner, so the mask
+ value at each vertex comes from one arbitrary face
+ corner; not averaged or otherwise combined yet */
+ for(i = 0; i < S; ++i) {
+ int vndx = (&f->v1)[i];
+ float *vco = mvert[vndx].co;
+
+ pmask[vndx] = get_tex_mask_strength(tex_slot,
+ mtface ? mtface->uv[i] : NULL, vco);
+ }
+}
+
+static int paint_mask_from_texture_exec(bContext *C, wmOperator *op)
+{
+ struct Scene *scene;
+ Object *ob;
+ Mesh *me;
+ struct MultiresModifierData *mmd;
+ PaintSession *ps;
+ MTex *tex_slot;
+ DerivedMesh *dm = NULL;
+ PBVH *pbvh;
+ MTFace *mtfaces = NULL;
+ PBVHNode **nodes;
+ int totnode, n, i, active;
+
+ tex_slot = CTX_data_pointer_get_type(C, "texture_slot",
+ &RNA_TextureSlot).data;
+
+ scene = CTX_data_scene(C);
+ ob = CTX_data_active_object(C);
+ ps = ob->paint;
+ me = get_mesh(ob);
+ mmd = ED_paint_multires_active(scene, ob);
+
+ pbvh_undo_push_begin("Paint mask from texture");
+
+ active = CustomData_get_active_layer(&me->vdata, CD_PAINTMASK);
+
+ /* if using UV mapping, check for a matching MTFace layer */
+ if(tex_slot->texco == TEXCO_UV) {
+ mtfaces = CustomData_get_layer_named(&me->fdata, CD_MTFACE,
+ tex_slot->uvname);
+ }
+
+ /* the MTFace mask is needed only for multires+UV */
+ dm = mesh_get_derived_final(scene, ob,
+ (mtfaces && mmd) ? CD_MASK_MTFACE : 0);
+
+ /* use the subdivided UVs for multires */
+ if(mtfaces && mmd) {
+ mtfaces = CustomData_get_layer_named(&dm->faceData,
+ CD_MTFACE,
+ tex_slot->uvname);
+ }
+
+ /* update the pbvh */
+ ps->pbvh = pbvh = dm->getPBVH(ob, dm);
+
+ /* get all nodes in the pbvh */
+ BLI_pbvh_search_gather(pbvh,
+ NULL, NULL,
+ &nodes, &totnode);
+
+ if(mmd) {
+ /* For all grids, find offset into mtfaces and apply
+ the texture to the grid */
+ for(n = 0; n < totnode; ++n) {
+ DMGridData **grids;
+ GridKey *gridkey;
+ int *grid_indices, totgrid, gridsize;
+
+ pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, scene);
+
+ BLI_pbvh_node_get_grids(pbvh, nodes[n], &grid_indices,
+ &totgrid, NULL, &gridsize,
+ &grids, NULL, &gridkey);
+
+ for(i = 0; i < totgrid; ++i) {
+ int grid_index = grid_indices[i];
+ MTFace *mtface = NULL;
+
+ if(mtfaces) {
+ mtface = &mtfaces[grid_index *
+ ((gridsize-1) *
+ (gridsize-1))];
+ }
+
+ mask_grid_from_tex(grids[grid_index],
+ gridsize, gridkey,
+ mtface, tex_slot, active);
+ }
+
+ BLI_pbvh_node_set_flags(nodes[n],
+ SET_INT_IN_POINTER(PBVH_UpdateColorBuffers));
+ }
+
+ multires_mark_as_modified(ob);
+ }
+ else {
+ float *pmask = CustomData_get_layer(&me->vdata, CD_PAINTMASK);
+
+ for(n = 0; n < totnode; ++n) {
+ MFace *mface;
+ int *face_indices, totface;
+
+ pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, scene);
+
+ BLI_pbvh_node_get_faces(pbvh, nodes[n], &mface,
+ &face_indices, NULL, &totface);
+
+ for(i = 0; i < totface; ++i) {
+ int face_index = face_indices[i];
+ MTFace *mtface = NULL;
+
+ if(mtfaces)
+ mtface = mtfaces + face_index;
+
+ mask_face_from_tex(me->mface + face_index,
+ me->mvert, mtface,
+ pmask, tex_slot, active);
+ }
+
+ BLI_pbvh_node_set_flags(nodes[n],
+ SET_INT_IN_POINTER(PBVH_UpdateColorBuffers));
+ }
+ }
+
+ MEM_freeN(nodes);
+
+ pbvh_undo_push_end();
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* fills a mask with intensity values from a texture, using an
+ mtex to provide mapping */
+void PAINT_OT_mask_from_texture(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mask From Texture";
+ ot->idname= "PAINT_OT_mask_from_texture";
+
+ /* api callbacks */
+ ot->exec= paint_mask_from_texture_exec;
+ ot->poll= mask_active_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+}
+
+static void set_mask_value(MaskSetMode mode, float *m)
+{
+ *m = (mode == MASKING_CLEAR ? 0 :
+ mode == MASKING_FILL ? 1 :
+ mode == MASKING_INVERT ? (1 - *m) :
+ mode == MASKING_RANDOM ? (float)rand() / RAND_MAX : 0);
+}
+
+static int paint_mask_set_exec(bContext *C, wmOperator *op)
+{
+ MaskSetMode mode = RNA_enum_get(op->ptr, "mode");
+ struct Scene *scene;
+ Object *ob;
+ DerivedMesh *dm;
+ struct MultiresModifierData *mmd;
+ PaintSession *ps;
+ Mesh *me;
+ PBVH *pbvh;
+
+ scene = CTX_data_scene(C);
+ ob = CTX_data_active_object(C);
+ ps = ob->paint;
+ me = get_mesh(ob);
+ mmd = ED_paint_multires_active(scene, ob);
+
+ dm = mesh_get_derived_final(scene, ob, 0);
+ ps->pbvh = pbvh = dm->getPBVH(ob, dm);
+
+ if(pbvh) {
+ PBVHNode **nodes;
+ int n, totnode;
+
+ BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ pbvh_undo_push_begin("Paint mask fill");
+
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+
+ pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, scene);
+
+ BLI_pbvh_vertex_iter_begin(pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(vd.mask_active)
+ set_mask_value(mode, vd.mask_active);
+ }
+ BLI_pbvh_vertex_iter_end;
+
+ BLI_pbvh_node_set_flags(nodes[n], SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|PBVH_UpdateRedraw));
+ }
+
+ if(nodes)
+ MEM_freeN(nodes);
+
+ if(mmd)
+ multires_mark_as_modified(ob);
+
+ pbvh_undo_push_end();
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+/* fills up a mask for the entire object, setting each vertex to
+ either 0, 1, or a random value */
+void PAINT_OT_mask_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem mask_items[] = {
+ {MASKING_CLEAR, "CLEAR", 0, "Clear", ""},
+ {MASKING_FILL, "FILL", 0, "Fill", ""},
+ {MASKING_INVERT, "INVERT", 0, "Invert", ""},
+ {MASKING_RANDOM, "RANDOM", 0, "Random", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Set Mask";
+ ot->idname= "PAINT_OT_mask_set";
+
+ /* api callbacks */
+ ot->exec= paint_mask_set_exec;
+ ot->poll= mask_active_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "mode", mask_items, MASKING_CLEAR, "Mode", "");
+}
+
+/* if this is a multires mesh, update it and free the DM.
+ returns 1 if this is a multires mesh, 0 otherwise */
+static int paintmask_check_multires(bContext *C)
+{
+ struct Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+
+ if(ED_paint_multires_active(scene, ob)) {
+ multires_force_update(ob);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mask_layer_poll(bContext *C)
+{
+ return mask_poll(C) && ED_mesh_layers_poll(C);
+}
+
+static int mask_layer_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob= CTX_data_active_object(C);
+ Mesh *me= ob->data;
+ int multires, top, first;
+ char *layer_name;
+ PaintLayerUndoNode *unode;
+
+ unode = paint_layer_undo_push(CD_PAINTMASK, "Add mask layer");
+
+ multires = paintmask_check_multires(C);
+
+ top= CustomData_number_of_layers(&me->vdata, CD_PAINTMASK);
+ CustomData_add_layer(&me->vdata, CD_PAINTMASK, CD_DEFAULT,
+ NULL, me->totvert);
+
+ first = CustomData_get_layer_index(&me->vdata, CD_PAINTMASK);
+ assert(first >= 0);
+
+ me->vdata.layers[first + top].flag |= CD_FLAG_MULTIRES;
+ CustomData_set_layer_active(&me->vdata, CD_PAINTMASK, top);
+ layer_name = me->vdata.layers[first + top].name;
+
+ /* now that we have correct name, update multires and finish undo push */
+
+ if(multires) {
+ CustomDataMultires *cdm;
+
+ cdm = CustomData_get_layer(&me->fdata, CD_GRIDS);
+
+ CustomData_multires_add_layers(cdm, me->totface,
+ CD_PAINTMASK, layer_name);
+ }
+
+ paint_layer_undo_set_add(unode, layer_name);
+
+ paintmask_redraw(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static int mask_layer_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob= CTX_data_active_object(C);
+ Mesh *me= ob->data;
+ int active_offset, first;
+
+ active_offset = CustomData_get_active_layer(&me->vdata, CD_PAINTMASK);
+
+ if(active_offset >= 0) {
+ PaintLayerUndoNode *unode;
+ int multires = paintmask_check_multires(C);
+ char *layer_name;
+
+ unode = paint_layer_undo_push(CD_PAINTMASK,
+ "Remove mask layer");
+
+ first = CustomData_get_layer_index(&me->vdata, CD_PAINTMASK);
+ layer_name = me->vdata.layers[first + active_offset].name;
+
+ paint_layer_undo_set_remove(unode, layer_name,
+ &me->vdata, &me->fdata,
+ me->totvert, me->totface);
+
+ if(multires) {
+ CustomDataMultires *cdm;
+
+ cdm = CustomData_get_layer(&me->fdata, CD_GRIDS);
+
+ CustomData_multires_remove_layers(cdm, me->totface,
+ CD_PAINTMASK,
+ layer_name);
+ }
+
+ CustomData_free_layer_active(&me->vdata, CD_PAINTMASK,
+ me->totvert);
+
+ paintmask_redraw(C);
+ }
+ else
+ return OPERATOR_CANCELLED;
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_mask_layer_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Mask Layer";
+ ot->description= "Add a paint mask layer";
+ ot->idname= "PAINT_OT_mask_layer_add";
+
+ /* api callbacks */
+ ot->poll= mask_layer_poll;
+ ot->exec= mask_layer_add_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+void PAINT_OT_mask_layer_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Remove Mask Layer";
+ ot->description= "Remove the active paint mask layer";
+ ot->idname= "PAINT_OT_mask_layer_remove";
+
+ /* api callbacks */
+ ot->poll= mask_layer_poll;
+ ot->exec= mask_layer_remove_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 2e0338b370e..b190398037d 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -19,6 +19,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -216,11 +217,29 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
WM_operatortype_append(PAINT_OT_vertex_paint);
WM_operatortype_append(PAINT_OT_vertex_color_set);
+ WM_operatortype_append(PAINT_OT_overlay_manipulate);
+
+ /* ptex */
+ WM_operatortype_append(PTEX_OT_layer_add);
+ WM_operatortype_append(PTEX_OT_layer_remove);
+ WM_operatortype_append(PTEX_OT_layer_save);
+ WM_operatortype_append(PTEX_OT_layer_convert);
+ WM_operatortype_append(PTEX_OT_open);
+ WM_operatortype_append(PTEX_OT_face_resolution_set);
+ WM_operatortype_append(PTEX_OT_subface_select);
+ WM_operatortype_append(PTEX_OT_select_all);
+ WM_operatortype_append(PTEX_OT_subface_flag_set);
/* face-select */
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
+
+ /* mask */
+ WM_operatortype_append(PAINT_OT_mask_layer_add);
+ WM_operatortype_append(PAINT_OT_mask_layer_remove);
+ WM_operatortype_append(PAINT_OT_mask_set);
+ WM_operatortype_append(PAINT_OT_mask_from_texture);
}
@@ -301,6 +320,19 @@ static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *UNUSED(path
RNA_float_set(kmi->ptr, "scalar", 10.0/9.0); // 1.1111....
}
+static void ed_keymap_paint_overlay(wmKeyMap *keymap)
+{
+ wmKeyMapItem *kmi;
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_overlay_manipulate", GKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "action", PAINT_MANIP_GRAB);
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_overlay_manipulate", SKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "action", PAINT_MANIP_SCALE);
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_overlay_manipulate", RKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "action", PAINT_MANIP_ROTATE);
+ kmi= WM_keymap_add_item(keymap, "WM_OT_context_toggle", IKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.paint_overlay.enabled");
+}
+
void ED_keymap_paint(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
@@ -318,6 +350,12 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", WM_BRUSHSTROKE_NORMAL);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_BRUSHSTROKE_INVERT);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_BRUSHSTROKE_SMOOTH);
+
+ WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", EVT_TWEAK_L, KM_ANY, KM_CTRL|KM_SHIFT, 0);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", EVT_TWEAK_L, KM_ANY, KM_CTRL|KM_ALT, 0)->ptr, "hide_inside", 1);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", LEFTMOUSE, KM_RELEASE, KM_CTRL|KM_SHIFT, 0)->ptr, "show_all", 1);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", LEFTMOUSE, KM_RELEASE, KM_CTRL|KM_ALT, 0)->ptr, "show_all", 1);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", HKEY, KM_PRESS, KM_ALT, 0)->ptr, "show_all", 1);
//stroke_mode_modal_keymap(keyconf);
@@ -394,16 +432,41 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH);
WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0);
-
WM_keymap_add_item(keymap,
"PAINT_OT_vertex_color_set",KKEY, KM_PRESS, KM_SHIFT, 0);
+ /* ptex edit mode */
+ WM_keymap_add_item(keymap, "PTEX_OT_subface_select", RIGHTMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_select", RIGHTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", 1);
+ WM_keymap_add_item(keymap, "PTEX_OT_select_all", AKEY, KM_PRESS, 0, 0);
+
+ /* ptex subface hiding */
+ kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", HKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_HIDDEN);
+ kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", HKEY, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_HIDDEN);
+ RNA_boolean_set(kmi->ptr, "ignore_unselected", 0);
+ RNA_boolean_set(kmi->ptr, "ignore_hidden", 0);
+ RNA_boolean_set(kmi->ptr, "set", 0);
+
+ /* ptex subface mask */
+ kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", MKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_MASKED);
+ kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", MKEY, KM_PRESS, KM_ALT, 0);
+ RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_MASKED);
+ RNA_boolean_set(kmi->ptr, "ignore_unselected", 0);
+ RNA_boolean_set(kmi->ptr, "ignore_hidden", 0);
+ RNA_boolean_set(kmi->ptr, "set", 0);
+
ed_keymap_paint_brush_switch(keymap, "tool_settings.vertex_paint.active_brush_index");
ed_keymap_paint_brush_size(keymap, "tool_settings.vertex_paint.brush.size");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
RNA_string_set(kmi->ptr, "data_path", "vertex_paint_object.data.use_paint_mask");
+ ed_keymap_paint_overlay(keymap);
+
/* Weight Paint mode */
keymap= WM_keymap_find(keyconf, "Weight Paint", 0, 0);
keymap->poll= weight_paint_mode_poll;
@@ -442,6 +505,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
RNA_string_set(kmi->ptr, "data_path", "texture_paint_object.data.use_paint_mask");
+ ed_keymap_paint_overlay(keymap);
+
/* face-mask mode */
keymap= WM_keymap_find(keyconf, "Face Mask", 0, 0);
keymap->poll= facemask_paint_poll;
diff --git a/source/blender/editors/sculpt_paint/paint_overlay.c b/source/blender/editors/sculpt_paint/paint_overlay.c
new file mode 100644
index 00000000000..c02e2c1fcd6
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_overlay.c
@@ -0,0 +1,427 @@
+/*
+ * $Id$
+ *
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2010 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): None
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+
+#include "BLI_math.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "UI_resources.h"
+
+#include "paint_intern.h"
+
+#include <math.h>
+
+int paint_sample_overlay(PaintStroke *stroke, float col[3], float co[2])
+{
+ ViewContext *vc = paint_stroke_view_context(stroke);
+ PaintOverlay *overlay = &vc->scene->toolsettings->paint_overlay;
+
+ col[0] = col[1] = col[2] = col[3] = 0;
+
+ if(overlay->use && overlay->img) {
+ ImBuf *ibuf = BKE_image_get_ibuf(overlay->img, NULL);
+
+ if(ibuf) {
+ int x, y;
+ int offset, trans[2];
+ float uco[3], proj[2];
+
+ paint_stroke_symmetry_unflip(stroke, uco, co);
+ paint_stroke_project(stroke, uco, proj);
+
+
+ paint_overlay_transform(overlay, vc->ar, ibuf,
+ trans, proj, 1, 1);
+ x = trans[0];
+ y = trans[1];
+
+ if(x >= 0 && x < ibuf->x && y >= 0 && y < ibuf->y) {
+ offset = y*ibuf->x + x;
+
+ if(ibuf->rect) {
+ char *ccol = ((char*)ibuf->rect) + offset*4;
+
+ col[0] = ccol[0] / 255.0;
+ col[1] = ccol[1] / 255.0;
+ col[2] = ccol[2] / 255.0;
+ col[3] = ccol[3] / 255.0;
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int paint_overlay_poll(bContext *C)
+{
+ PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
+
+ if(vertex_paint_poll(C) || image_texture_paint_poll(C))
+ return overlay->img && overlay->use;
+
+ return 0;
+}
+
+void ED_paint_update_overlay(PaintOverlay *overlay)
+{
+ if(overlay->gltex) {
+ glDeleteTextures(1, &overlay->gltex);
+ overlay->gltex = 0;
+ }
+}
+
+void ED_paint_overlay_draw(const bContext *C, ARegion *ar)
+{
+ PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
+ ImBuf *ibuf;
+ int center[2];
+ int sx, sy;
+
+ if(!paint_overlay_poll((bContext*)C))
+ return;
+
+ ibuf = BKE_image_get_ibuf(overlay->img, NULL);
+
+ if(!ibuf)
+ return;
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+
+ if(!overlay->gltex) {
+ /* update gl texture */
+
+ /* doing this manually because it looks like the GPU
+ Image stuff is customized on mesh tex? */
+
+ glGenTextures(1, (GLuint*)&overlay->gltex);
+ glBindTexture(GL_TEXTURE_2D, overlay->gltex);
+
+ if ((ibuf->rect==NULL) && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+
+ {
+ char *bc = (char*)ibuf->rect;
+ char transp[3] = {overlay->transp_col[0] * 255,
+ overlay->transp_col[1] * 255,
+ overlay->transp_col[2] * 255};
+ int i;
+
+ for(i = 0; i < ibuf->y*ibuf->x; ++i, bc+=4) {
+ float d[3] = {fabs(bc[2]-transp[0]),
+ fabs(bc[1]-transp[1]),
+ fabs(bc[0]-transp[2])};
+
+ if(d[0] < overlay->transp_tol &&
+ d[1] < overlay->transp_tol &&
+ d[2] < overlay->transp_tol)
+ bc[3] = 0;
+ else
+ bc[3] = 255;
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ibuf->x, ibuf->y,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, overlay->gltex);
+ glColor4f(1, 1, 1, 0.5);
+
+ glPushMatrix();
+ center[0] = ar->winx/2 + overlay->offset[0];
+ center[1] = ar->winy/2 + overlay->offset[1];
+ sx = overlay->size[0] / 2;
+ sy = overlay->size[1] / 2;
+
+ glTranslatef(center[0], center[1], 0);
+ glRotatef(overlay->angle * 180/M_PI, 0, 0, 1);
+
+ /* draw textured quad */
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(-sx, -sy);
+ glTexCoord2f(1, 0);
+ glVertex2f(+sx, -sy);
+ glTexCoord2f(1, 1);
+ glVertex2f(+sx, +sy);
+ glTexCoord2f(0, 1);
+ glVertex2f(-sx, +sy);
+ glEnd();
+ glPopMatrix();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+}
+
+
+/* convert screen-space coords to ibuf coords */
+void paint_overlay_transform(PaintOverlay *overlay, ARegion *ar, ImBuf *ibuf,
+ int out[2], float vec[2], int scale, int rotate)
+{
+ float center[2], size[2], org[2], t1[2], t2[2];
+ float sina, cosa;
+
+ center[0] = ar->winx/2 + overlay->offset[0];
+ center[1] = ar->winy/2 + overlay->offset[1];
+ size[0] = overlay->size[0];
+ size[1] = overlay->size[1];
+ org[0] = center[0] - size[0]/2;
+ org[1] = center[1] - size[1]/2;
+ sina = sin(overlay->angle);
+ cosa = cos(overlay->angle);
+
+ /* make overlay center origin */
+ sub_v2_v2v2(t1, vec, center);
+
+ /* apply rotation */
+ if(rotate) {
+ t2[0] = cosa*t1[0] + sina*t1[1];
+ t2[1] = -sina*t1[0] + cosa*t1[1];
+ }
+ else {
+ out[0] = t1[0];
+ out[1] = t1[1];
+ t2[0] = t1[0];
+ t2[1] = t1[1];
+ }
+
+ /* translation */
+ if(scale) {
+ out[0] = t2[0] + size[0]/2;
+ out[1] = t2[1] + size[1]/2;
+
+ /* scale */
+ out[0] *= (ibuf->x / size[0]);
+ out[1] *= (ibuf->y / size[1]);
+ }
+ else {
+ out[0] = t2[0];
+ out[1] = t2[1];
+ }
+}
+
+typedef struct {
+ int x, y;
+ int offset[2];
+ int size[2];
+ float orig_angle, start_angle;
+
+ ImBuf *ibuf;
+ int ibuf_mouse[2];
+
+ void *draw_cb_handle;
+ struct ARegionType *draw_cb_type;
+ /* data needed for manip draw */
+ PaintManipAction action;
+ int cur_mouse[2];
+} VPaintManipData;
+
+/* when rotating or scaling, draw hashed line to center */
+static void paint_overlay_manip_draw(const bContext *C, ARegion *ar, void *data_v)
+{
+ PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
+ VPaintManipData *data = data_v;
+
+ if(data->action != PAINT_MANIP_GRAB) {
+ UI_ThemeColor(TH_WIRE);
+ setlinestyle(3);
+
+ glBegin(GL_LINES);
+ glVertex2i(data->cur_mouse[0] - ar->winrct.xmin,
+ data->cur_mouse[1] - ar->winrct.ymin);
+ glVertex2i(ar->winx/2 + overlay->offset[0],
+ ar->winy/2 + overlay->offset[1]);
+ glEnd();
+
+ setlinestyle(0);
+ }
+}
+
+static int paint_overlay_manip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
+ ARegion *ar = CTX_wm_region(C);
+ VPaintManipData *data;
+ float mouse[2] = {event->x - ar->winrct.xmin,
+ mouse[1] = event->y - ar->winrct.ymin};
+ int angle_mouse[2];
+
+ op->customdata = data = MEM_callocN(sizeof(VPaintManipData), "VPaintManipData");
+
+ data->x = event->x;
+ data->y = event->y;
+ data->offset[0] = overlay->offset[0];
+ data->offset[1] = overlay->offset[1];
+ data->size[0] = overlay->size[0];
+ data->size[1] = overlay->size[1];
+ data->orig_angle = overlay->angle;
+ data->ibuf = BKE_image_get_ibuf(overlay->img, NULL);
+ data->action = RNA_enum_get(op->ptr, "action");
+ data->cur_mouse[0] = event->x;
+ data->cur_mouse[1] = event->y;
+
+ paint_overlay_transform(overlay, ar, data->ibuf, data->ibuf_mouse, mouse, 0, 1);
+
+ paint_overlay_transform(overlay, ar, data->ibuf, angle_mouse, mouse, 0, 0);
+ data->start_angle = atan2(angle_mouse[0], angle_mouse[1]);
+
+ data->draw_cb_type = ar->type;
+ data->draw_cb_handle = ED_region_draw_cb_activate(ar->type,
+ paint_overlay_manip_draw,
+ data,
+ REGION_DRAW_POST_PIXEL);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int paint_overlay_manip_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
+ ARegion *ar = CTX_wm_region(C);
+ float mouse[2] = {event->x - ar->winrct.xmin,
+ event->y - ar->winrct.ymin};
+ int ibuf_mouse[2];
+ int *co = overlay->offset;
+ int *size = overlay->size;
+ float *angle = &overlay->angle;
+ VPaintManipData *data = op->customdata;
+ int dx, dy;
+
+ dx = event->x - data->x;
+ dy = event->y - data->y;
+ data->cur_mouse[0] = event->x;
+ data->cur_mouse[1] = event->y;
+
+ switch(data->action) {
+ case PAINT_MANIP_GRAB:
+ co[0] = data->offset[0] + dx;
+ co[1] = data->offset[1] + dy;
+ break;
+ case PAINT_MANIP_SCALE:
+ {
+ float d[2];
+
+ paint_overlay_transform(overlay, ar, data->ibuf, ibuf_mouse, mouse, 0, 1);
+
+ d[0] = fabs(ibuf_mouse[0]) - fabs(data->ibuf_mouse[0]);
+ d[1] = fabs(ibuf_mouse[1]) - fabs(data->ibuf_mouse[1]);
+
+ size[0] = data->size[0] + d[0];
+ size[1] = data->size[1] + d[1];
+ }
+ break;
+ case PAINT_MANIP_ROTATE:
+ paint_overlay_transform(overlay, ar, data->ibuf, ibuf_mouse, mouse, 0, 0);
+ *angle = data->orig_angle + data->start_angle - atan2(ibuf_mouse[0], ibuf_mouse[1]);
+
+ break;
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ if(event->type == LEFTMOUSE) {
+ ED_region_draw_cb_exit(data->draw_cb_type, data->draw_cb_handle);
+ MEM_freeN(data);
+ return OPERATOR_FINISHED;
+ }
+ else if(event->type == RIGHTMOUSE) {
+ co[0] = data->offset[0];
+ co[1] = data->offset[1];
+ size[0] = data->size[0];
+ size[1] = data->size[1];
+ *angle = data->orig_angle;
+ ED_region_draw_cb_exit(data->draw_cb_type, data->draw_cb_handle);
+ MEM_freeN(data);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void PAINT_OT_overlay_manipulate(wmOperatorType *ot)
+{
+ static EnumPropertyItem action_items[]= {
+ {PAINT_MANIP_GRAB, "GRAB", 0, "Grab", ""},
+ {PAINT_MANIP_SCALE, "SCALE", 0, "Scale", ""},
+ {PAINT_MANIP_ROTATE, "Rotate", 0, "Rotate", ""},
+
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Paint Overlay Manipulate";
+ ot->idname= "PAINT_OT_overlay_manipulate";
+
+ /* api callbacks */
+ ot->invoke= paint_overlay_manip_invoke;
+ ot->modal= paint_overlay_manip_modal;
+ ot->poll= paint_overlay_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_BLOCKING;
+
+ /* properties */
+ ot->prop= RNA_def_enum(ot->srna, "action", action_items, 0, "Action", "");
+}
diff --git a/source/blender/editors/sculpt_paint/paint_ptex.c b/source/blender/editors/sculpt_paint/paint_ptex.c
new file mode 100644
index 00000000000..be669f4b911
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_ptex.c
@@ -0,0 +1,1414 @@
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
+#include "BKE_mesh.h"
+#include "BKE_paint.h"
+#include "BKE_ptex.h"
+#include "BKE_report.h"
+#include "BKE_subsurf.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "IMB_imbuf.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "ptex.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+static void paint_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
+{
+ if(BLI_pbvh_node_get_tmin(node) < *tmin) {
+ PaintStrokeRaycastData *data = data_v;
+
+ if(BLI_pbvh_node_raycast(data->ob->paint->pbvh, node, NULL,
+ data->ray_start, data->ray_normal,
+ &data->dist, NULL, NULL)) {
+ data->hit |= 1;
+ *tmin = data->dist;
+ }
+ }
+}
+
+static int ptex_paint_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2])
+{
+ // XXX: sculpt_stroke_modifiers_check(C, ss);
+ return paint_stroke_get_location(C, stroke, paint_raycast_cb, NULL, out, mouse, 0);
+}
+
+static int ptex_paint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
+{
+ if(paint_stroke_over_mesh(C, op->customdata, event->x, event->y)) {
+ Object *ob= CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ DerivedMesh *dm;
+ Mesh *me;
+
+ /* context checks could be a poll() */
+ me= get_mesh(ob);
+
+ dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH|CD_MASK_MCOL);
+ ob->paint->pbvh = dm->getPBVH(ob, dm);
+
+ pbvh_undo_push_begin("Vertex paint");
+
+ return 1;
+ }
+ return 0;
+}
+
+static void ptex_paint_blend(Brush *brush, PaintStroke *stroke, float col[4], float alpha, float co[2])
+{
+ float src_img[4], *src;
+ int tool = brush->vertexpaint_tool;
+
+ if(tool == IMB_BLEND_ADD_ALPHA &&
+ (brush->flag & BRUSH_DIR_IN))
+ tool = IMB_BLEND_ERASE_ALPHA;
+
+ if(paint_sample_overlay(stroke, src_img, co)) {
+ src = src_img;
+ alpha *= src_img[3];
+ }
+ else
+ src = brush->rgb;
+
+ IMB_blend_color_float(col, col, src, alpha, tool);
+}
+
+static void ptex_elem_to_float4(PtexDataType type, int channels, void *data, float fcol[4])
+{
+ int i;
+
+ /* default alpha */
+ fcol[3] = 1;
+
+ switch(type) {
+ case PTEX_DT_UINT8:
+ for(i = 0; i < channels; ++i)
+ fcol[i] = ((unsigned char*)data)[i] / 255.0;
+ break;
+ case PTEX_DT_UINT16:
+ for(i = 0; i < channels; ++i)
+ fcol[i] = ((unsigned char*)data)[i] / 65535.0;
+ break;
+ case PTEX_DT_FLOAT:
+ for(i = 0; i < channels; ++i)
+ fcol[i] = ((float*)data)[i];
+ break;
+ default:
+ break;
+ }
+
+ if(channels == 1) {
+ for(i = 1; i < 4; ++i)
+ fcol[i] = fcol[0];
+ }
+}
+
+static void ptex_elem_from_float4(PtexDataType type, int channels, void *data, float fcol[4])
+{
+ int i;
+
+ if(channels == 1) {
+ float avg = (fcol[0]+fcol[1]+fcol[2]) / 3.0f;
+ switch(type) {
+ case PTEX_DT_UINT8:
+ ((unsigned char*)data)[0] = avg * 255;
+ break;
+ case PTEX_DT_UINT16:
+ ((unsigned short*)data)[0] = avg * 65535;
+ break;
+ case PTEX_DT_FLOAT:
+ ((float*)data)[0] = avg;
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ switch(type) {
+ case PTEX_DT_UINT8:
+ for(i = 0; i < channels; ++i)
+ ((unsigned char*)data)[i] = fcol[i] * 255;
+ break;
+ case PTEX_DT_UINT16:
+ for(i = 0; i < channels; ++i)
+ ((unsigned short*)data)[i] = fcol[i] * 65535;
+ break;
+ case PTEX_DT_FLOAT:
+ for(i = 0; i < channels; ++i)
+ ((float*)data)[i] = fcol[i];
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void ptex_get_edge_iter(MPtex *mptex, GridToFace *gtf,
+ char *data,
+ int layersize, int edge, int border,
+ char **start, int *len, int *step)
+{
+ MPtexSubface *subface = &mptex[gtf->face].subfaces[gtf->offset];
+ int *res = subface->res;
+ int start_offset;
+ int x, y;
+
+ if(!data)
+ data = subface->data;
+
+ switch(edge) {
+ case 0:
+ x = border;
+ y = 0;
+ *len = res[0];
+ *step = layersize;
+ break;
+ case 2:
+ x = border;
+ y = res[1] + border + border - 1;
+ *len = res[0];
+ *step = layersize;
+ break;
+ case 1:
+ x = -1;
+ y = border + 1;
+ *len = res[1];
+ *step = layersize * (res[0] + border + border);
+ break;
+ case 3:
+ x = 0;
+ y = border;
+ *len = res[1];
+ *step = layersize * (res[0] + border + border);
+ break;
+ }
+
+ start_offset = y * (res[0] + border + border) + x;
+ *start = data + layersize * start_offset;
+}
+
+
+
+/* build a ptex grid that includes borders filled with neighbor data,
+ or repeated data if at a mesh boundary. this could be done more efficient
+ by not allocating a full grid here, but simpler to get this working first */
+static void *ptex_paint_build_blur_input(DMGridAdjacency *grid_adj, MPtex *mptex,
+ int grid_index, GridToFace *grid_face_map,
+ int layersize)
+{
+ GridToFace *gtf;
+ MPtexSubface *subface;
+ char *out;
+ int i, v;
+
+ gtf = &grid_face_map[grid_index];
+ subface = &mptex[gtf->face].subfaces[gtf->offset];
+
+ out = MEM_mallocN(layersize * (subface->res[0]+2) * (subface->res[1]+2), "blurred_data_input");
+
+ /* copy center */
+ for(v = 0; v < subface->res[1]; ++v) {
+ memcpy(out + layersize * ((v+1) * (subface->res[0]+2) + 1),
+ (char*)subface->data + layersize * v * subface->res[0],
+ layersize * subface->res[0]);
+ }
+
+ /* fill in borders with adjacent data */
+ for(i = 0; i < 4; ++i) {
+ DMGridAdjacency *adj = &grid_adj[grid_index];
+ char *t1, *t2;
+ float step2_fac;
+ int j, len1, len2, step1, step2;
+
+ ptex_get_edge_iter(mptex, &grid_face_map[grid_index], out,
+ layersize, i, 1, &t1, &len1, &step1);
+
+ if(adj->index[i] == -1) {
+ /* mesh boundary, just repeat existing border */
+ ptex_get_edge_iter(mptex, &grid_face_map[grid_index],
+ NULL, layersize, i, 0,
+ &t2, &len2, &step2);
+ }
+ else {
+ ptex_get_edge_iter(mptex, &grid_face_map[adj->index[i]],
+ NULL, layersize, adj->rotation[i], 0,
+ &t2, &len2, &step2);
+ }
+
+ step2_fac = (float)len2 / (float)len1;
+
+ for(j = 0; j < len1; ++j) {
+ memcpy(t1 + step1 * j,
+ t2 + step2*(int)(step2_fac*j),
+ layersize);
+ }
+ }
+
+ return out;
+}
+
+static void ptex_blur_texel(MPtex *pt, MPtexSubface *subface,
+ char *blur_input, int layersize,
+ int u_offset, int v_offset,
+ float avg[4])
+{
+ int i;
+
+ zero_v4(avg);
+
+ for(i = 0; i < 4; ++i) {
+ float col[4];
+ int u = u_offset;
+ int v = v_offset;
+
+ if(i == 0) u--;
+ else if(i == 1) v--;
+ else if(i == 2) u++;
+ else if(i == 3) v++;
+
+ ptex_elem_to_float4(pt->type,
+ pt->channels,
+ blur_input + layersize*((v+1)*(subface->res[0]+2) + u+1),
+ col);
+ avg[0] += col[0];
+ avg[1] += col[1];
+ avg[2] += col[2];
+ avg[3] += col[3];
+ }
+
+ mul_v4_fl(avg, 1.0f / i);
+}
+
+static void ptex_paint_ptex_from_quad(Brush *brush, PaintStroke *stroke, PaintStrokeTest *test,
+ MPtex *pt, MPtexSubface *subface, int res[2],
+ int u_offset, int v_offset, int layersize,
+ char *blur_input,
+ float v1[3], float v2[3], float v3[3], float v4[3])
+
+{
+ char *data = (char*)subface->data + layersize * (v_offset * subface->res[0] + u_offset);
+ float dtop[3], dbot[3], xoffset, yinterp, ustep, vstep;
+ float co_bot[3], co_top[3], start_top[3], start_bot[3];
+ int u, v;
+
+ /* start of top and bottom "rails" */
+ copy_v3_v3(start_top, v4);
+ copy_v3_v3(start_bot, v1);
+
+ /* direction of "rails" */
+ sub_v3_v3v3(dtop, v3, v4);
+ sub_v3_v3v3(dbot, v2, v1);
+
+ /* offset to use center of texel rather than corner */
+ xoffset = 1.0f / (2 * res[0]);
+ yinterp = 1.0f / (2 * res[1]);
+ madd_v3_v3fl(start_top, dtop, xoffset);
+ madd_v3_v3fl(start_bot, dbot, xoffset);
+
+ ustep = 1.0f / res[0];
+ vstep = 1.0f / res[1];
+
+ /* precalculate interpolation along "rails" */
+ mul_v3_fl(dtop, ustep);
+ mul_v3_fl(dbot, ustep);
+
+ for(v = 0; v < res[1]; ++v) {
+ copy_v3_v3(co_top, start_top);
+ copy_v3_v3(co_bot, start_bot);
+
+ for(u = 0; u < res[0]; ++u) {
+ float co[3];
+
+ interp_v3_v3v3(co, co_bot, co_top, yinterp);
+
+ if(paint_stroke_test(test, co)) {
+ float strength;
+ float fcol[4];
+ char *elem = data + layersize*(v*subface->res[0] + u);
+
+ strength = brush->alpha *
+ paint_stroke_combined_strength(stroke, test->dist, co, 0);
+
+ ptex_elem_to_float4(pt->type, pt->channels, elem, fcol);
+
+ if(blur_input) {
+ float blurcol[4];
+
+ ptex_blur_texel(pt, subface,
+ blur_input, layersize,
+ u_offset + u, v_offset + v,
+ blurcol);
+
+ interp_v4_v4v4(fcol, fcol, blurcol, strength);
+ }
+ else
+ ptex_paint_blend(brush, stroke, fcol, strength, co);
+
+ ptex_elem_from_float4(pt->type, pt->channels, elem, fcol);
+ }
+
+ add_v3_v3(co_bot, dbot);
+ add_v3_v3(co_top, dtop);
+ }
+
+ yinterp += vstep;
+ }
+}
+
+static void ptex_paint_node_grids(Brush *brush, PaintStroke *stroke,
+ DMGridData **grids, GridKey *gridkey,
+ GridToFace *grid_face_map,
+ DMGridAdjacency *grid_adj,
+ CustomData *fdata,
+ int *grid_indices,
+ int totgrid, int gridsize)
+{
+ PaintStrokeTest test;
+ MPtex *mptex;
+ int i;
+
+ mptex = CustomData_get_layer(fdata, CD_MPTEX);
+
+ paint_stroke_test_init(&test, stroke);
+
+ for(i = 0; i < totgrid; ++i) {
+ int g = grid_indices[i];
+ DMGridData *grid = grids[g];
+ GridToFace *gtf = &grid_face_map[g];
+ MPtex *pt = &mptex[gtf->face];
+ MPtexSubface *subface = &pt->subfaces[gtf->offset];
+ char *blur_input = NULL;
+ int u, v, x, y, layersize, res[2];
+
+ /* ignore hidden and masked subfaces */
+ if(subface->flag & (MPTEX_SUBFACE_HIDDEN|MPTEX_SUBFACE_MASKED))
+ continue;
+
+ layersize = pt->channels * ptex_data_size(pt->type);
+
+ if(brush->vertexpaint_tool == VERTEX_PAINT_BLUR) {
+ blur_input = ptex_paint_build_blur_input(grid_adj, mptex,
+ g, grid_face_map,
+ layersize);
+ }
+
+ res[0] = MAX2(subface->res[0] / (gridsize - 1), 1);
+ res[1] = MAX2(subface->res[1] / (gridsize - 1), 1);
+
+ for(v = 0, y = 0; v < subface->res[1]; v += res[1], ++y) {
+ for(u = 0, x = 0; u < subface->res[0]; u += res[0], ++x) {
+ float *co[4] = {
+ GRIDELEM_CO_AT(grid, y*gridsize+x, gridkey),
+ GRIDELEM_CO_AT(grid, y*gridsize+(x+1), gridkey),
+
+ GRIDELEM_CO_AT(grid, (y+1)*gridsize+(x+1), gridkey),
+ GRIDELEM_CO_AT(grid, (y+1)*gridsize+x, gridkey),
+ };
+
+ ptex_paint_ptex_from_quad(brush, stroke, &test,
+ pt, subface, res, u, v,
+ layersize, blur_input,
+ co[0], co[1], co[2], co[3]);
+ }
+ }
+
+ if(blur_input)
+ MEM_freeN(blur_input);
+ }
+}
+
+static void ptex_paint_nodes(VPaint *vp, PaintStroke *stroke,
+ Scene *scene, Object *ob,
+ PBVHNode **nodes, int totnode)
+{
+ PBVH *pbvh = ob->paint->pbvh;
+ Brush *brush = paint_brush(&vp->paint);
+ CustomData *vdata = NULL;
+ CustomData *fdata = NULL;
+ GridToFace *grid_face_map;
+ int n;
+
+ assert(BLI_pbvh_uses_grids(pbvh));
+
+ BLI_pbvh_get_customdata(pbvh, &vdata, &fdata);
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+
+ for(n = 0; n < totnode; ++n) {
+ DMGridData **grids;
+ DMGridAdjacency *grid_adj;
+ GridKey *gridkey;
+ int *grid_indices;
+ int totgrid, gridsize;
+
+ pbvh_undo_push_node(nodes[n], PBVH_UNDO_PTEX, ob, scene);
+
+ BLI_pbvh_node_get_grids(pbvh, nodes[n],
+ &grid_indices, &totgrid, NULL,
+ &gridsize, &grids, &grid_adj, &gridkey);
+
+ ptex_paint_node_grids(brush, stroke,
+ grids, gridkey,
+ grid_face_map,
+ grid_adj, fdata,
+ grid_indices,
+ totgrid, gridsize);
+
+ BLI_pbvh_node_set_flags(nodes[n],
+ SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|
+ PBVH_UpdateRedraw));
+ }
+}
+
+static void ptex_paint_restore_node(PBVH *pbvh, PBVHNode *node, PBVHUndoNode *unode,
+ CustomData *fdata, GridToFace *grid_face_map)
+{
+ MPtex *mptex;
+ int *grid_indices, totgrid, i;
+
+ mptex = CustomData_get_layer_named(fdata, CD_MPTEX,
+ (char*)pbvh_undo_node_mptex_name(unode));
+
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+
+ BLI_pbvh_node_get_grids(pbvh, node,
+ &grid_indices, &totgrid,
+ NULL, NULL, NULL, NULL, NULL);
+
+ for(i = 0; i < totgrid; i++) {
+ GridToFace *gtf = &grid_face_map[grid_indices[i]];
+ MPtex *pt = &mptex[gtf->face];
+ MPtexSubface *subface = &pt->subfaces[gtf->offset];
+ int layersize;
+
+ layersize = pt->channels * ptex_data_size(pt->type);
+
+ memcpy(subface->data, pbvh_undo_node_mptex_data(unode, i),
+ layersize * subface->res[0] * subface->res[1]);
+ }
+
+ BLI_pbvh_node_set_flags(node, SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|
+ PBVH_UpdateRedraw));
+}
+
+static void ptex_paint_restore(VPaint *vp, Object *ob)
+{
+ Brush *brush = paint_brush(&vp->paint);
+ PBVH *pbvh = ob->paint->pbvh;
+
+ /* Restore the mesh before continuing with anchored stroke */
+ if((brush->flag & BRUSH_ANCHORED) ||
+ (brush->flag & BRUSH_RESTORE_MESH))
+ {
+ PBVHNode **nodes;
+ CustomData *fdata;
+ GridToFace *grid_face_map;
+ int n, totnode;
+
+ BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+ BLI_pbvh_get_customdata(pbvh, NULL, &fdata);
+
+ for(n = 0; n < totnode; n++) {
+ PBVHUndoNode *unode;
+
+ unode= pbvh_undo_get_node(nodes[n]);
+ if(unode) {
+ ptex_paint_restore_node(pbvh, nodes[n], unode, fdata, grid_face_map);
+ }
+ }
+
+ if(nodes)
+ MEM_freeN(nodes);
+ }
+}
+
+static void ptex_stitch_subfaces()
+{
+
+}
+
+static void ptex_paint_stroke_update_step(bContext *C, PaintStroke *stroke,
+ PointerRNA *itemptr)
+{
+ VPaint *vp= CTX_data_tool_settings(C)->vpaint;
+ Object *ob = CTX_data_active_object(C);
+
+ ptex_paint_restore(vp, ob);
+
+ paint_stroke_apply_brush(C, stroke, &vp->paint);
+
+ if(paint_brush(&vp->paint)->vertexpaint_tool == VERTEX_PAINT_BLUR)
+ ptex_stitch_subfaces();
+
+ /* partial redraw */
+ paint_tag_partial_redraw(C, ob);
+}
+
+static void ptex_paint_stroke_brush_action(bContext *C, PaintStroke *stroke)
+{
+
+ VPaint *vp= CTX_data_tool_settings(C)->vpaint;
+ ViewContext *vc = paint_stroke_view_context(stroke);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = vc->obact;
+ PBVHSearchSphereData search_data;
+ PBVHNode **nodes;
+ int totnode;
+ float center[3], radius;
+
+ paint_stroke_symmetry_location(stroke, center);
+
+ search_data.center = center;
+
+ radius = paint_stroke_radius(stroke);
+ search_data.radius_squared = radius*radius;
+ search_data.original = 0;
+
+ BLI_pbvh_search_gather(ob->paint->pbvh, BLI_pbvh_search_sphere_cb,
+ &search_data, &nodes, &totnode);
+
+ ptex_paint_nodes(vp, stroke, scene, ob, nodes, totnode);
+
+ if(nodes)
+ MEM_freeN(nodes);
+}
+
+static void ptex_paint_stroke_done(bContext *C, struct PaintStroke *stroke)
+{
+ pbvh_undo_push_end();
+}
+
+static int ptex_paint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ op->customdata = paint_stroke_new(C,
+ ptex_paint_stroke_get_location,
+ ptex_paint_stroke_test_start,
+ ptex_paint_stroke_update_step,
+ NULL,
+ ptex_paint_stroke_brush_action,
+ ptex_paint_stroke_done);
+
+ /* add modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ op->type->modal(C, op, event);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void PAINT_OT_vertex_paint(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Paint";
+ ot->idname= "PAINT_OT_vertex_paint";
+
+ /* api callbacks */
+ ot->invoke= ptex_paint_invoke;
+ ot->modal= paint_stroke_modal;
+ ot->exec= paint_stroke_exec;
+ ot->poll= vertex_paint_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_BLOCKING;
+
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+}
+
+static EnumPropertyItem ptex_layer_type_items[]= {
+ {PTEX_DT_UINT8, "PTEX_DT_UINT8", 0, "8-bit channels", ""},
+ {PTEX_DT_UINT16, "PTEX_DT_UINT16", 0, "16-bit channels", ""},
+ {PTEX_DT_FLOAT, "PTEX_DT_FLOAT", 0, "32-bit floating-point channels", ""},
+
+ {0, NULL, 0, NULL, NULL}};
+
+static int ptex_active_layer_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if(ob) {
+ Mesh *me = get_mesh(ob);
+ if(me)
+ return !!CustomData_get_layer(&me->fdata, CD_MPTEX);
+ }
+ return 0;
+}
+
+static int ptex_layer_convert_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ MPtex *mptex;
+ PtexDataType new_type;
+ int i, j, x, y;
+
+ new_type = RNA_enum_get(op->ptr, "type");
+ mptex = CustomData_get_layer(&me->fdata, CD_MPTEX);
+
+ for(i = 0; i < me->totface; ++i) {
+ MPtex *pt = &mptex[i];
+
+ for(j = 0; j < mptex[i].totsubface; ++j) {
+ MPtexSubface *subface = &pt->subfaces[j];
+ int orig_layersize, new_layersize;
+ float *f;
+ char *orig_data, *new_data, *new_data_start;
+
+ orig_layersize = pt->channels * ptex_data_size(pt->type);
+ new_layersize = pt->channels * ptex_data_size(new_type);
+
+ f = MEM_callocN(sizeof(float) * pt->channels, "tmp ptex elem");
+ new_data_start = new_data =
+ MEM_callocN(new_layersize * subface->res[0] * subface->res[1],
+ "mptex converted data");
+ orig_data = subface->data;
+
+ for(y = 0; y < subface->res[1]; ++y) {
+ for(x = 0; x < subface->res[0]; ++x,
+ orig_data += orig_layersize,
+ new_data += new_layersize) {
+ ptex_elem_to_floats(pt->type, pt->channels, orig_data, f);
+ ptex_elem_from_floats(new_type, pt->channels, new_data, f);
+ }
+ }
+
+ MEM_freeN(subface->data);
+ subface->data = new_data_start;
+ MEM_freeN(f);
+ }
+
+ pt->type = new_type;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PTEX_OT_layer_convert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Convert Layer";
+ ot->description= "Convert Ptex data to another type";
+ ot->idname= "PTEX_OT_layer_convert";
+
+ /* api callbacks */
+ ot->exec= ptex_layer_convert_exec;
+ ot->poll= ptex_active_layer_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "type", ptex_layer_type_items, PTEX_DT_FLOAT, "Type", "Layer channels and data type");
+}
+
+static int next_power_of_two(int n)
+{
+ n--;
+ n = (n >> 1) | n;
+ n = (n >> 2) | n;
+ n = (n >> 4) | n;
+ n = (n >> 8) | n;
+ n = (n >> 16) | n;
+ n++;
+
+ return n;
+}
+
+static const void *ptex_default_data(PtexDataType type) {
+ static const unsigned char ptex_def_val_uc[] = {255, 255, 255, 255};
+ static const unsigned short ptex_def_val_us[] = {65535, 65535, 65535, 65535};
+ static const float ptex_def_val_f[] = {1, 1, 1, 1};
+
+ switch(type) {
+ case PTEX_DT_UINT8:
+ return ptex_def_val_uc;
+ case PTEX_DT_UINT16:
+ return ptex_def_val_us;
+ case PTEX_DT_FLOAT:
+ return ptex_def_val_f;
+ default:
+ return NULL;
+ };
+}
+
+/* add a new ptex layer
+ automatically sets resolution based on face area */
+static int ptex_layer_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ MPtex *mptex;
+ float (*limit_pos)[3], *face_area, totarea;
+ float density;
+ float largest_face_area = 0;
+ const void *def_val;
+ PtexDataType type;
+ int totchannel;
+ int layer_size;
+ int tottexel = 0;
+ int active_offset;
+ int i, j;
+
+ type = RNA_enum_get(op->ptr, "type");
+ totchannel = RNA_int_get(op->ptr, "channels");
+ layer_size = ptex_data_size(type) * totchannel;
+ def_val = ptex_default_data(type);
+
+ active_offset = CustomData_number_of_layers(&me->fdata, CD_MPTEX);
+ mptex = CustomData_add_layer(&me->fdata, CD_MPTEX, CD_CALLOC,
+ NULL, me->totface);
+ CustomData_set_layer_active(&me->fdata, CD_MPTEX, active_offset);
+
+ /* TODO: for now i'm allocating texels based on limit surface area;
+ according to ptex paper it's better to use surface derivatives */
+
+ limit_pos = MEM_callocN(sizeof(float)*3*me->totvert, "limit_pos");
+ face_area = MEM_callocN(sizeof(float)*me->totface, "face_area");
+ subsurf_calculate_limit_positions(me, limit_pos);
+ for(i = 0, totarea = 0; i < me->totface; ++i) {
+ MFace *f = &me->mface[i];
+ if(f->v4) {
+ face_area[i] = area_quad_v3(limit_pos[f->v1], limit_pos[f->v2],
+ limit_pos[f->v3], limit_pos[f->v4]);
+ }
+ else {
+ face_area[i] = area_tri_v3(limit_pos[f->v1], limit_pos[f->v2],
+ limit_pos[f->v3]);
+ }
+ largest_face_area = MAX2(largest_face_area, face_area[i]);
+ totarea += face_area[i];
+ }
+
+ /* try to make the density factor less dependent on mesh size */
+ density = RNA_float_get(op->ptr, "density") * 1000 / largest_face_area;
+
+ for(i = 0; i < me->totface; ++i) {
+ int S = me->mface[i].v4 ? 4 : 3;
+ int ures;
+ int vres;
+ int gridsize;
+ char *data;
+
+ if(S == 4) {
+ /* adjust u and v resolution by the ration
+ between the average edge size in u and v
+ directions */
+ float len1 = (len_v3v3(limit_pos[me->mface[i].v1],
+ limit_pos[me->mface[i].v2]) +
+ len_v3v3(limit_pos[me->mface[i].v3],
+ limit_pos[me->mface[i].v4])) * 0.5f;
+ float len2 = (len_v3v3(limit_pos[me->mface[i].v2],
+ limit_pos[me->mface[i].v3]) +
+ len_v3v3(limit_pos[me->mface[i].v4],
+ limit_pos[me->mface[i].v1])) * 0.5f;
+ float r = len2/len1;
+
+ ures = next_power_of_two(sqrtf((face_area[i] * density) * r)) / 2;
+ vres = next_power_of_two(sqrtf((face_area[i] * density) / r)) / 2;
+ }
+ else {
+ /* do triangles uniform (subfaces) */
+ ures = sqrtf(face_area[i] * (density / 3.0f));
+ vres = ures = next_power_of_two(ures);
+ }
+
+ ures = MAX2(ures, 1);
+ vres = MAX2(vres, 1);
+ gridsize = ures * vres;
+
+ mptex[i].totsubface = S;
+ mptex[i].type = type;
+ mptex[i].channels = totchannel;
+
+ for(j = 0; j < S; ++j) {
+ int texels, k;
+
+ mptex[i].subfaces[j].res[0] = ures;
+ mptex[i].subfaces[j].res[1] = vres;
+
+ texels = ures*vres;
+ data = mptex[i].subfaces[j].data =
+ MEM_callocN(layer_size * texels, "MptexSubface.data");
+ tottexel += texels;
+
+ for(k = 0; k < texels; ++k) {
+ memcpy(data, def_val, layer_size);
+ data += layer_size;
+ }
+ }
+ }
+
+ printf("total texels = %d, sqrt(texels)=%.1f\n", tottexel, sqrtf(tottexel));
+
+ MEM_freeN(face_area);
+ MEM_freeN(limit_pos);
+
+ return OPERATOR_FINISHED;
+}
+
+void PTEX_OT_layer_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Layer";
+ ot->description= "Add a new ptex layer";
+ ot->idname= "PTEX_OT_layer_add";
+
+ /* api callbacks */
+ ot->exec= ptex_layer_add_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "density", 10, 0, 6000, "Density", "Density of texels to generate", 0, 6000);
+ RNA_def_int(ot->srna, "channels", 3, 1, 4, "Channels", "", 1, 4);
+ RNA_def_enum(ot->srna, "type", ptex_layer_type_items, PTEX_DT_FLOAT, "Type", "Layer channels and data type");
+}
+
+static int ptex_layer_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+
+ CustomData_free_layer_active(&me->fdata, CD_MPTEX,
+ me->totface);
+
+ if((ob->mode & OB_MODE_VERTEX_PAINT) &&
+ !CustomData_number_of_layers(&me->fdata, CD_MPTEX))
+ ED_object_toggle_modes(C, OB_MODE_VERTEX_PAINT);
+
+ return OPERATOR_FINISHED;
+}
+
+void PTEX_OT_layer_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Remove Layer";
+ ot->description= "Remove active ptex layer";
+ ot->idname= "PTEX_OT_layer_remove";
+
+ /* api callbacks */
+ ot->exec= ptex_layer_remove_exec;
+ ot->poll= ptex_active_layer_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int ptex_layer_save_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ char str[FILE_MAX];
+
+ if(!me->totface)
+ return OPERATOR_CANCELLED;
+
+ RNA_string_get(op->ptr, "filepath", str);
+ if(!ptex_layer_save_file(me, str))
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+static int ptex_layer_save_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ /*Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ const char *name;
+ char buf[FILE_MAX];*/
+
+ if(RNA_property_is_set(op->ptr, "filepath"))
+ return ptex_layer_save_exec(C, op);
+
+ /*name = me->fdata.layers[CustomData_get_active_layer_index(&me->fdata, CD_MPTEX)].name;
+ BLI_snprintf(buf, FILE_MAX, "%s.ptx", name);
+
+ RNA_string_set(op->ptr, "filepath", buf);*/
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void PTEX_OT_layer_save(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Save Layer";
+ ot->description= "Save active ptex layer";
+ ot->idname= "PTEX_OT_layer_save";
+
+ /* api callbacks */
+ ot->invoke= ptex_layer_save_invoke;
+ ot->exec= ptex_layer_save_exec;
+ ot->poll= ptex_active_layer_poll;
+
+ WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH);
+}
+
+/* loads a .ptx file
+ makes some assumptions that could be relaxed
+ later as our ptex implementation is refined
+
+ on the other hand, some unsupported ptex features
+ are not checked for yet
+*/
+int ptex_open_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+
+ PtexTextureHandle *ptex_texture;
+ PtexDataType ptex_data_type;
+ int totchannel;
+
+ char *path;
+ int i, j;
+
+ path = RNA_string_get_alloc(op->ptr, "filepath", NULL, 0);
+
+ ptex_texture = ptex_open(path, 1, 0);
+ MEM_freeN(path);
+
+ /* check if loader worked */
+ if(!ptex_texture) {
+ BKE_report(op->reports, RPT_ERROR, "Error loading ptex file (see stdout for now, TODO)");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* data type */
+ ptex_data_type = ptex_texture_data_type(ptex_texture);
+ if(ptex_data_type == PTEX_DT_UNSUPPORTED) {
+ BKE_report(op->reports, RPT_ERROR, "Ptex format unsupported");
+ ptex_texture_release(ptex_texture);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* data channels */
+ totchannel = ptex_texture_num_channels(ptex_texture);
+ if(totchannel == 2 || totchannel > 4) {
+ BKE_report(op->reports, RPT_ERROR, "Ptex channel count unsupported");
+ ptex_texture_release(ptex_texture);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* check that ptex file matches mesh topology */
+ for(i = 0, j = 0; i < me->totface; ++i) {
+ MFace *f = &me->mface[i];
+ PtexFaceInfoHandle *ptex_face = ptex_texture_get_face_info(ptex_texture, j);
+ int subface;
+
+ if(!ptex_face) {
+ BKE_report(op->reports, RPT_ERROR, "Ptex/mesh topology mismatch");
+ ptex_texture_release(ptex_texture);
+ return OPERATOR_CANCELLED;
+ }
+
+ subface = ptex_face_info_is_subface(ptex_face);
+
+ if(subface != (f->v4 == 0)) {
+ BKE_report(op->reports, RPT_ERROR, "Ptex/mesh topology mismatch");
+ ptex_texture_release(ptex_texture);
+ return OPERATOR_CANCELLED;
+ }
+
+ j += (f->v4 ? 1 : 3);
+ }
+
+ ptex_layer_from_file(me, ptex_texture);
+
+ return OPERATOR_FINISHED;
+}
+
+static int ptex_open_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void PTEX_OT_open(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Open";
+ ot->idname= "PTEX_OT_open";
+
+ /* api callbacks */
+ ot->exec= ptex_open_exec;
+ ot->invoke= ptex_open_invoke;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
+}
+
+typedef enum {
+ RES_OP_NUMERIC,
+ RES_OP_DOUBLE,
+ RES_OP_HALF
+} PtexResOp;
+
+static void ptex_face_resolution_set(MPtex *pt, int offset, ToolSettings *ts, PtexResOp op)
+{
+ int i;
+
+ for(i = 0; i < pt->totsubface; ++i) {
+ int ures, vres;
+
+ if(i == offset || pt->totsubface == 4) {
+ MPtexSubface *subface = &pt->subfaces[i];
+
+ switch(op) {
+ case RES_OP_NUMERIC:
+ ures = ts->ptex_ures;
+ vres = ts->ptex_vres;
+ if(pt->totsubface == 4) {
+ ures >>= 1;
+ vres >>= 1;
+ }
+ break;
+ case RES_OP_DOUBLE:
+ ures = subface->res[0] << 1;
+ vres = subface->res[1] << 1;
+ break;
+ case RES_OP_HALF:
+ ures = subface->res[0] >> 1;
+ vres = subface->res[1] >> 1;
+ break;
+ }
+
+ if(ures < 1) ures = 1;
+ if(vres < 1) vres = 1;
+
+ ptex_subface_scale(pt, subface, ures, vres);
+ }
+ }
+}
+
+static void ptex_redraw_selected(PBVHNode *node, void *data)
+{
+ PBVH *pbvh = data;
+ MPtex *mptex;
+ GridToFace *grid_face_map;
+ CustomData *fdata;
+ int totgrid, *grid_indices, i;
+
+ BLI_pbvh_get_customdata(pbvh, NULL, &fdata);
+ mptex = CustomData_get_layer(fdata, CD_MPTEX);
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+ BLI_pbvh_node_get_grids(pbvh, node,
+ &grid_indices, &totgrid, NULL, NULL,
+ NULL, NULL, NULL);
+
+ for(i = 0; i < totgrid; ++i) {
+ GridToFace *gtf = &grid_face_map[grid_indices[i]];
+ if(mptex[gtf->face].subfaces[gtf->offset].flag & MPTEX_SUBFACE_SELECTED) {
+ BLI_pbvh_node_set_flags(node,
+ SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|
+ PBVH_UpdateRedraw));
+ }
+ }
+}
+
+static int ptex_face_resolution_set_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ MPtex *mptex = CustomData_get_layer(&me->fdata, CD_MPTEX);
+ PtexResOp operation = RNA_enum_get(op->ptr, "operation");
+ int i, j;
+
+ for(i = 0; i < me->totface; ++i) {
+ for(j = 0; j < mptex[i].totsubface; ++j) {
+ if(mptex[i].subfaces[j].flag & MPTEX_SUBFACE_SELECTED) {
+ ptex_face_resolution_set(mptex + i, j, ts, operation);
+ if(mptex[i].totsubface == 4)
+ break;
+ }
+ }
+ }
+
+ BLI_pbvh_search_callback(ob->paint->pbvh, NULL, NULL, ptex_redraw_selected, ob->paint->pbvh);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int ptex_face_resolution_set_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if(ob) {
+ Mesh *me = get_mesh(ob);
+ if(me && CustomData_get_layer(&me->fdata, CD_MPTEX))
+ return 1;
+ }
+ return 0;
+}
+
+void PTEX_OT_face_resolution_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem op_items[] = {
+ {RES_OP_NUMERIC, "NUMERIC", 0, "Numeric", ""},
+ {RES_OP_DOUBLE, "DOUBLE", 0, "Double", ""},
+ {RES_OP_HALF, "HALF", 0, "Half", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Set Face Resolution";
+ ot->idname= "PTEX_OT_face_resolution_set";
+
+ /* api callbacks */
+ ot->exec= ptex_face_resolution_set_exec;
+ ot->poll= ptex_face_resolution_set_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "operation", op_items, RES_OP_NUMERIC, "Operation", "How to modify the resolution");
+}
+
+typedef struct {
+ int grid_index;
+ PBVHNode *node;
+} PtexSelectData;
+
+static void select_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
+{
+ if(BLI_pbvh_node_get_tmin(node) < *tmin) {
+ PaintStrokeRaycastData *data = data_v;
+ PtexSelectData *mode_data = data->mode_data;
+
+ if(BLI_pbvh_node_raycast(data->ob->paint->pbvh, node, NULL,
+ data->ray_start, data->ray_normal,
+ &data->dist, &mode_data->grid_index, NULL)) {
+ data->hit |= 1;
+ *tmin = data->dist;
+ mode_data->node = node;
+ }
+ }
+}
+
+static int ptex_subface_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ ViewContext vc;
+ float out[3], mouse[2] = {event->x, event->y};
+ PtexSelectData mode_data;
+
+ view3d_set_viewcontext(C, &vc);
+ if(paint_util_raycast(&vc, select_raycast_cb, &mode_data, out, mouse, 0)) {
+ PBVH *pbvh = ob->paint->pbvh;
+ GridToFace *grid_face_map, *gtf;
+ CustomData *fdata;
+ MPtex *mptex, *pt;
+ int *grid_indices;
+ int i, j;
+
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+ BLI_pbvh_get_customdata(pbvh, NULL, &fdata);
+ BLI_pbvh_node_get_grids(pbvh, mode_data.node,
+ &grid_indices, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+
+ mptex = CustomData_get_layer(fdata, CD_MPTEX);
+
+ /* deselect everything */
+ if(!RNA_boolean_get(op->ptr, "extend")) {
+ for(i = 0; i < me->totface; ++i) {
+ for(j = 0; j < mptex[i].totsubface; ++j)
+ mptex[i].subfaces[j].flag &= ~MPTEX_SUBFACE_SELECTED;
+ }
+ }
+
+ gtf = &grid_face_map[grid_indices[mode_data.grid_index]];
+ pt = &mptex[gtf->face];
+
+ if(pt->totsubface == 4) {
+ for(i = 0; i < 4; ++i)
+ pt->subfaces[i].flag ^= MPTEX_SUBFACE_SELECTED;
+ }
+ else
+ pt->subfaces[gtf->offset].flag ^= MPTEX_SUBFACE_SELECTED;
+
+ me->act_face = gtf->face;
+ me->act_subface = gtf->offset;
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int ptex_edit_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if(ob && (ob->mode & OB_MODE_VERTEX_PAINT)) {
+ Mesh *me = get_mesh(ob);
+ return me && (me->editflag & ME_EDIT_PTEX);
+ }
+
+ return 0;
+}
+
+void PTEX_OT_subface_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Subface";
+ ot->idname= "PTEX_OT_subface_select";
+
+ /* api callbacks */
+ ot->invoke= ptex_subface_select_invoke;
+ ot->poll= ptex_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
+}
+
+static int ptex_select_all_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ MPtex *mptex;
+ int i, j, action = RNA_enum_get(op->ptr, "action");
+
+ mptex = CustomData_get_layer(&me->fdata, CD_MPTEX);
+
+ if(action == SEL_TOGGLE) {
+ for(i = 0; i < me->totface; ++i) {
+ for(j = 0; j < mptex[i].totsubface; ++j) {
+ if(mptex[i].subfaces[j].flag & MPTEX_SUBFACE_SELECTED) {
+ action = SEL_DESELECT;
+ break;
+ }
+ }
+ }
+ }
+
+ if(action == SEL_TOGGLE)
+ action = SEL_SELECT;
+
+ for(i = 0; i < me->totface; ++i) {
+ for(j = 0; j < mptex[i].totsubface; ++j) {
+ MPtexSubface *subface = &mptex[i].subfaces[j];
+ switch(action) {
+ case SEL_SELECT:
+ subface->flag |= MPTEX_SUBFACE_SELECTED;
+ break;
+ case SEL_DESELECT:
+ subface->flag &= ~MPTEX_SUBFACE_SELECTED;
+ break;
+ case SEL_INVERT:
+ subface->flag ^= MPTEX_SUBFACE_SELECTED;
+ break;
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PTEX_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select or Deselect All";
+ ot->description= "Change selection of all ptex faces";
+ ot->idname= "PTEX_OT_select_all";
+
+ /* api callbacks */
+ ot->exec= ptex_select_all_exec;
+ ot->poll= ptex_edit_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+int ptex_subface_flag_set_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ MPtex *mptex = CustomData_get_layer(&me->fdata, CD_MPTEX);
+ int flag = RNA_enum_get(op->ptr, "flag");
+ int set = RNA_boolean_get(op->ptr, "set");
+ int ignore_unselected = RNA_boolean_get(op->ptr, "ignore_unselected");
+ int ignore_hidden = RNA_boolean_get(op->ptr, "ignore_hidden");
+ int i, j;
+
+ for(i = 0; i < me->totface; ++i) {
+ for(j = 0; j < mptex[i].totsubface; ++j) {
+ MPtexSubface *subface = &mptex[i].subfaces[j];
+
+ if((!ignore_unselected || (subface->flag & MPTEX_SUBFACE_SELECTED)) &&
+ (!ignore_hidden || !(subface->flag & MPTEX_SUBFACE_HIDDEN))) {
+ if(set)
+ subface->flag |= flag;
+ else
+ subface->flag &= ~flag;
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PTEX_OT_subface_flag_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem flag_items[] = {
+ {MPTEX_SUBFACE_HIDDEN, "HIDDEN", 0, "Hidden", ""},
+ {MPTEX_SUBFACE_MASKED, "MASKED", 0, "Masked", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Set Subface Flags";
+ ot->description= "Set or clear a flag from ptex subfaces";
+ ot->idname= "PTEX_OT_subface_flag_set";
+
+ /* api callbacks */
+ ot->exec= ptex_subface_flag_set_exec;
+ ot->poll= ptex_active_layer_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "flag", flag_items, 0, "Flag", "");
+ RNA_def_boolean(ot->srna, "set", 1, "Set", "Set the flag if true, otherwise clear the flag");
+ RNA_def_boolean(ot->srna, "ignore_unselected", 1, "Ignore Unselected", "Don't change the flags of unselected faces");
+ RNA_def_boolean(ot->srna, "ignore_hidden", 1, "Ignore Hidden", "Don't change the flags of hidden faces");
+}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index ea99844bfac..50d1286042b 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -34,15 +34,19 @@
#include "RNA_access.h"
+#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_paint.h"
-#include "BKE_brush.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -57,28 +61,62 @@
#include <float.h>
#include <math.h>
-typedef struct PaintStroke {
+struct PaintStroke {
void *mode_data;
void *smooth_stroke_cursor;
wmTimer *timer;
/* Cached values */
ViewContext vc;
+ float project_mat[4][4];
bglMats mats;
Brush *brush;
-
- float last_mouse_position[2];
+ /* brush location (object space) */
+ float location[3], symmetry_location[3];
+ /* screen-space brush location */
+ float mouse[2], initial_mouse[2], last_mouse_position[2];
+ /* not always the same as brush_size() */
+ int pixel_radius;
+ /* tablet pressure, or 1 if using mouse */
+ float pressure;
+ /* 3d brush radius */
+ float radius, radius_squared, initial_radius;
+ /* previous location of updating rake rotation */
+ float last_rake[2];
+ /* this value is added to the brush's rotation in calculations */
+ float rotation;
+ /* mouse location used for texturing */
+ float tex_mouse[2];
+ /* symmetry */
+ /* current symmetry pass (0-7) */
+ int mirror_symmetry_pass;
+ int radial_symmetry_pass;
+ float symm_rot_mat[4][4];
+ float symm_rot_mat_inv[4][4];
+ /* decrease brush strength if symmetry overlaps */
+ float feather;
+
+ /* anything special that sculpt or other paint modes need
+ to do should go through these modifiers */
+ float modifier_initial_radius_factor;
+ int modifier_use_original_texture_coords;
+ int modifier_use_original_location;
/* Set whether any stroke step has yet occurred
e.g. in sculpt mode, stroke doesn't start until cursor
passes over the mesh */
int stroke_started;
+ /* 1 if this is the first paint dab, 0 otherwise */
+ int first_dab;
+ /* callbacks */
StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
+ StrokeUpdateSymmetry update_symmetry;
+ StrokeBrushAction brush_action;
StrokeDone done;
-} PaintStroke;
+};
/*** Cursor ***/
static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata)
@@ -323,7 +361,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "load_tex");
- #pragma omp parallel for schedule(static) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(static) if (sd->paint.flags & PAINT_USE_OPENMP)
for (j= 0; j < size; j++) {
int i;
float y;
@@ -436,7 +474,7 @@ static void projectf(bglMats *mats, const float v[3], float p[2])
p[1]= uy;
}
-static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
+int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
{
float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
@@ -476,8 +514,10 @@ static int project_brush_radius(RegionView3D* rv3d, float radius, float location
return len_v2v2(p1, p2);
}
+#if 0
int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, float location[3], float modelview[16], float projection[16], int viewport[4])
{
+ Object *ob = CTX_data_active_object(C);
struct PaintStroke *stroke;
float window[2];
int hit;
@@ -491,13 +531,13 @@ int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, floa
memcpy(projection, stroke->vc.rv3d->winmat, sizeof(float[16]));
memcpy(viewport, stroke->mats.viewport, sizeof(int[4]));
- if (stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) {
+ if (ob && ob->paint && ob->paint->sculpt && ob->paint->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) {
*pixel_radius = project_brush_radius(stroke->vc.rv3d, brush_unprojected_radius(stroke->brush), location, &stroke->mats);
if (*pixel_radius == 0)
*pixel_radius = brush_size(stroke->brush);
- mul_m4_v3(stroke->vc.obact->sculpt->ob->obmat, location);
+ mul_m4_v3(ob->obmat, location);
hit = 1;
}
@@ -513,6 +553,7 @@ int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, floa
return hit;
}
+#endif
// XXX duplicated from sculpt.c
float unproject_brush_radius(Object *ob, ViewContext *vc, float center[3], float offset)
@@ -543,14 +584,16 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
(void)unused;
view3d_set_viewcontext(C, &vc);
-
- if (vc.obact->sculpt) {
+
+// XXX
+#if 0
+ if (vc.obact->paint && vc.obact->paint->sculpt) {
Paint *paint = paint_get_active(CTX_data_scene(C));
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = paint_brush(paint);
- int pixel_radius, viewport[4];
- float location[3], modelview[16], projection[16];
+ int pixel_radius = 0, viewport[4];
+ float location[3]; // XXX: modelview[16], projection[16];
int hit;
@@ -585,7 +628,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
if(!brush_use_locked_size(brush) && !(paint->flags & PAINT_SHOW_BRUSH))
return;
- hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport);
+ hit = 0;
if (brush_use_locked_size(brush))
brush_set_size(brush, pixel_radius);
@@ -625,7 +668,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
-
+
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
glTranslatef(0.5f, 0.5f, 0);
@@ -767,7 +810,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
glPopAttrib();
}
- else {
+ //else
+#endif
+
+
+ {
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *brush = paint_brush(paint);
@@ -787,73 +834,271 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
}
}
-/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
-static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2])
+/**** Symmetry ****/
+
+float calc_overlap(PaintStroke *stroke, float location[3], char symm, char axis, float angle)
{
- Paint *paint = paint_get_active(CTX_data_scene(C)); // XXX
- Brush *brush = paint_brush(paint); // XXX
+ float mirror[3];
+ float distsq;
+ float mat[4][4];
+
+ //paint_flip_coord(mirror, cache->traced_location, symm);
+ paint_flip_coord(mirror, location, symm);
- float mouse[3];
+ unit_m4(mat);
+ rotate_m4(mat, axis, angle);
- PointerRNA itemptr;
+ mul_m4_v3(mat, mirror);
- float location[3];
+ //distsq = len_squared_v3v3(mirror, cache->traced_location);
+ distsq = len_squared_v3v3(mirror, location);
- float pressure;
- int pen_flip;
+ if (distsq <= 4*stroke->radius_squared)
+ return (2*stroke->radius - sqrt(distsq)) / (2*stroke->radius);
+ else
+ return 0;
+}
+
+static float calc_radial_symmetry_feather(PaintStroke *stroke, Paint *paint,
+ float location[3], char symm, char axis)
+{
+ int i;
+ float overlap;
+
+ overlap = 0;
+ for(i = 1; i < paint->radial_symm[axis-'X']; ++i) {
+ const float angle = 2*M_PI*i / paint->radial_symm[axis-'X'];
+ overlap += calc_overlap(stroke, location, symm, axis, angle);
+ }
+
+ return overlap;
+}
+
+static float calc_symmetry_feather(PaintStroke *stroke, Paint *paint, float location[3], char symm)
+{
+ if(paint->flags & PAINT_SYMMETRY_FEATHER) {
+ float overlap;
+ int i;
+
+ overlap = 0;
+ for (i = 0; i <= symm; i++) {
+ if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+
+ overlap += calc_overlap(stroke, location, i, 0, 0);
+
+ overlap += calc_radial_symmetry_feather(stroke, paint, location, i, 'X');
+ overlap += calc_radial_symmetry_feather(stroke, paint, location, i, 'Y');
+ overlap += calc_radial_symmetry_feather(stroke, paint, location, i, 'Z');
+ }
+ }
+
+ return 1/overlap;
+ }
+ else {
+ return 1;
+ }
+}
+
+/* flip data across the axes specified by symm */
+static void calc_symm(bContext *C, PaintStroke *stroke, float location[3], char symm,
+ char axis, float angle)
+{
+ /* radial symmetry */
+ unit_m4(stroke->symm_rot_mat);
+ rotate_m4(stroke->symm_rot_mat, axis, angle);
+
+ unit_m4(stroke->symm_rot_mat_inv);
+ rotate_m4(stroke->symm_rot_mat_inv, axis, -angle);
+
+ /* symmetry_location */
+ paint_flip_coord(location, location, symm);
+ mul_m4_v3(stroke->symm_rot_mat, location);
+ copy_v3_v3(stroke->symmetry_location, location);
+
+ /* callback */
+ if(stroke->update_symmetry) {
+ stroke->update_symmetry(C, stroke, symm, axis,
+ angle,
+ stroke->mirror_symmetry_pass,
+ stroke->radial_symmetry_pass,
+ stroke->symm_rot_mat);
+ }
+}
+
+static void do_radial_symmetry(bContext *C, PaintStroke *stroke, Paint *paint, char symm, int axis, float feather)
+{
+ int i;
+
+ for(i = 1; i < paint->radial_symm[axis-'X']; ++i) {
+ const float angle = 2*M_PI*i / paint->radial_symm[axis-'X'];
+ float location[3];
+
+ stroke->radial_symmetry_pass= i;
+ copy_v3_v3(location, stroke->location);
+ calc_symm(C, stroke, location, symm, axis, angle);
+
+ stroke->brush_action(C, stroke);
+ }
+}
+
+static void paint_stroke_update_cache(bContext *C, PaintStroke *stroke, Paint *paint)
+{
+ ViewContext *vc = &stroke->vc;
+
+ if(stroke->first_dab) {
+ copy_v2_v2(stroke->initial_mouse, stroke->mouse);
+ copy_v2_v2(stroke->tex_mouse, stroke->initial_mouse);
+
+ if(!brush_use_locked_size(stroke->brush)) {
+ stroke->initial_radius =
+ paint_calc_object_space_radius(vc,
+ stroke->location,
+ brush_size(stroke->brush));
+ brush_set_unprojected_radius(stroke->brush, stroke->initial_radius);
+ }
+ else
+ stroke->initial_radius= brush_unprojected_radius(stroke->brush);
+
+ stroke->initial_radius *= stroke->modifier_initial_radius_factor;
+ }
+
+ stroke->pixel_radius = brush_size(stroke->brush);
+ stroke->radius = stroke->initial_radius;
+ stroke->feather = calc_symmetry_feather(stroke, paint, stroke->location, paint->flags & 7);
+
+ if(brush_use_size_pressure(stroke->brush)) {
+ stroke->pixel_radius *= stroke->pressure;
+ stroke->radius *= stroke->pressure;
+ }
+
+ if(!((stroke->brush->flag & BRUSH_ANCHORED) ||
+ stroke->modifier_use_original_texture_coords)) {
+ copy_v2_v2(stroke->tex_mouse, stroke->mouse);
+
+ if((stroke->brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) &&
+ (stroke->brush->flag & BRUSH_RANDOM_ROTATION) &&
+ !(stroke->brush->flag & BRUSH_RAKE)) {
+ stroke->rotation = 2*M_PI*BLI_frand();
+ }
+ }
- ViewContext vc; // XXX
+ if(stroke->brush->flag & BRUSH_ANCHORED) {
+ int dx, dy;
+
+ dx = stroke->mouse[0] - stroke->initial_mouse[0];
+ dy = stroke->mouse[1] - stroke->initial_mouse[1];
+
+ stroke->pixel_radius = sqrt(dx*dx + dy*dy);
+
+ stroke->rotation = atan2(dx, dy) + M_PI;
+
+ if(stroke->brush->flag & BRUSH_EDGE_TO_EDGE) {
+ float d[3];
+ float halfway[3];
+ float out[3];
+
+ d[0] = dx;
+ d[1] = dy;
+ d[2] = 0;
+
+ mul_v3_v3fl(halfway, d, 0.5f);
+ add_v3_v3(halfway, stroke->initial_mouse);
+
+ if(stroke->get_location(C, stroke, out, halfway)) {
+ copy_v2_v2(stroke->tex_mouse, halfway);
+ copy_v3_v3(stroke->location, out);
+ stroke->pixel_radius /= 2.0f;
+ }
+ }
+
+ stroke->radius= paint_calc_object_space_radius(&stroke->vc,
+ stroke->location,
+ stroke->pixel_radius);
+ }
+ else if(stroke->brush->flag & BRUSH_RAKE) {
+ const float u = 0.5f;
+ const float r = 20;
+
+ const float dx = stroke->last_rake[0] - stroke->mouse[0];
+ const float dy = stroke->last_rake[1] - stroke->mouse[1];
+
+ if(stroke->first_dab) {
+ copy_v2_v2(stroke->last_rake, stroke->mouse);
+ }
+ else if (dx*dx + dy*dy >= r*r) {
+ stroke->rotation = atan2(dx, dy);
+ interp_v2_v2v2(stroke->last_rake, stroke->mouse, stroke->last_rake, u);
+ }
+ }
+
+ stroke->radius_squared = stroke->radius*stroke->radius;
+}
+
+/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
+static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2])
+{
+ Paint *paint = paint_get_active(CTX_data_scene(C));
PaintStroke *stroke = op->customdata;
+ PointerRNA itemptr;
+ int pen_flip;
- view3d_set_viewcontext(C, &vc); // XXX
+ view3d_get_object_project_mat(stroke->vc.rv3d, stroke->vc.obact, stroke->project_mat);
/* Tablet */
if(event->custom == EVT_DATA_TABLET) {
wmTabletData *wmtab= event->customdata;
- pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
+ stroke->pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
pen_flip = (wmtab->Active == EVT_TABLET_ERASER);
}
else {
- pressure = 1;
+ stroke->pressure = 1;
pen_flip = 0;
}
// XXX: temporary check for sculpt mode until things are more unified
- if (vc.obact->sculpt) {
+ if(stroke->vc.obact->paint && stroke->vc.obact->paint->sculpt) {
float delta[3];
- brush_jitter_pos(brush, mouse_in, mouse);
+ brush_jitter_pos(stroke->brush, mouse_in, stroke->mouse);
// XXX: meh, this is round about because brush_jitter_pos isn't written in the best way to be reused here
- if (brush->flag & BRUSH_JITTER_PRESSURE) {
- sub_v3_v3v3(delta, mouse, mouse_in);
- mul_v3_fl(delta, pressure);
- add_v3_v3v3(mouse, mouse_in, delta);
+ if(stroke->brush->flag & BRUSH_JITTER_PRESSURE) {
+ sub_v3_v3v3(delta, stroke->mouse, mouse_in);
+ mul_v3_fl(delta, stroke->pressure);
+ add_v3_v3v3(stroke->mouse, mouse_in, delta);
}
}
else
- copy_v3_v3(mouse, mouse_in);
+ copy_v2_v2(stroke->mouse, mouse_in);
- /* XXX: can remove the if statement once all modes have this */
- if(stroke->get_location)
- stroke->get_location(C, stroke, location, mouse);
- else
- zero_v3(location);
+ if(stroke->first_dab ||
+ !((stroke->brush->flag & BRUSH_ANCHORED) ||
+ stroke->modifier_use_original_location)) {
+
+ /* XXX: can remove the following if statement once all modes have this */
+ if(stroke->get_location)
+ stroke->get_location(C, stroke, stroke->location, stroke->mouse);
+ else
+ zero_v3(stroke->location);
+ }
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set_array(&itemptr, "location", location);
- RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_float_set_array(&itemptr, "location", stroke->location);
+ RNA_float_set_array(&itemptr, "mouse", stroke->mouse);
RNA_boolean_set (&itemptr, "pen_flip", pen_flip);
- RNA_float_set (&itemptr, "pressure", pressure);
+ RNA_float_set(&itemptr, "pressure", stroke->pressure);
+
+ copy_v2_v2(stroke->last_mouse_position, stroke->mouse);
- stroke->last_mouse_position[0] = mouse[0];
- stroke->last_mouse_position[1] = mouse[1];
+ paint_stroke_update_cache(C, stroke, paint);
stroke->update_step(C, stroke, &itemptr);
+
+ stroke->first_dab = 0;
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
@@ -862,7 +1107,7 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *ev
output[0] = event->x;
output[1] = event->y;
- if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
+ if((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
!ELEM4(stroke->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
!(stroke->brush->flag & BRUSH_RESTORE_MESH))
@@ -919,7 +1164,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
pressure = brush_use_size_pressure(stroke->brush) ? wmtab->Pressure : 1;
}
- scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length;
+ scale = (brush_size(stroke->brush) * pressure * stroke->brush->spacing/50.0f) / length;
mul_v2_fl(vec, scale);
steps = (int)(1.0f / scale);
@@ -937,20 +1182,25 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
/**** Public API ****/
PaintStroke *paint_stroke_new(bContext *C,
- StrokeGetLocation get_location,
- StrokeTestStart test_start,
- StrokeUpdateStep update_step,
- StrokeDone done)
+ StrokeGetLocation get_location,
+ StrokeTestStart test_start,
+ StrokeUpdateStep update_step,
+ StrokeUpdateSymmetry update_symmetry,
+ StrokeBrushAction brush_action,
+ 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.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
+ stroke->modifier_initial_radius_factor = 1;
stroke->get_location = get_location;
stroke->test_start = test_start;
stroke->update_step = update_step;
+ stroke->update_symmetry = update_symmetry;
+ stroke->brush_action = brush_action;
stroke->done = done;
return stroke;
@@ -965,7 +1215,6 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
{
PaintStroke *stroke = op->customdata;
float mouse[2];
- int first= 0;
if(!stroke->stroke_started) {
stroke->last_mouse_position[0] = event->x;
@@ -978,9 +1227,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
if(stroke->brush->flag & BRUSH_AIRBRUSH)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
+
+ stroke->first_dab = 1;
}
- first= 1;
//ED_region_tag_redraw(ar);
}
@@ -993,11 +1243,12 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
if(stroke->timer)
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
- stroke->done(C, stroke);
+ if(stroke->stroke_started)
+ stroke->done(C, stroke);
MEM_freeN(stroke);
return OPERATOR_FINISHED;
}
- else if(first || ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (event->type == TIMER && (event->customdata == stroke->timer))) {
+ else if(stroke->first_dab || ELEM(event->type, MOUSEMOVE, INBETWEEN_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)) {
@@ -1016,7 +1267,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
}
/* we want the stroke to have the first daub at the start location instead of waiting till we have moved the space distance */
- if(first &&
+ if(stroke->first_dab &&
stroke->stroke_started &&
paint_space_stroke_enabled(stroke->brush) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
@@ -1028,12 +1279,66 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
+void paint_stroke_apply_brush(bContext *C, PaintStroke *stroke, Paint *paint)
+{
+ char symm = paint->flags & 7;
+ float location[3];
+ int i;
+
+ /* symm is a bitwise combination of XYZ:
+ 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for(i = 0; i <= symm; ++i) {
+ if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ stroke->mirror_symmetry_pass= i;
+ stroke->radial_symmetry_pass= 0;
+
+ copy_v3_v3(location, stroke->location);
+ calc_symm(C, stroke, location, i, 0, 0);
+
+ stroke->brush_action(C, stroke);
+
+ do_radial_symmetry(C, stroke, paint, i, 'X', stroke->feather);
+ do_radial_symmetry(C, stroke, paint, i, 'Y', stroke->feather);
+ do_radial_symmetry(C, stroke, paint, i, 'Z', stroke->feather);
+ }
+ }
+}
+
+/* combines mask, curve, and texture strengths */
+float paint_stroke_combined_strength(PaintStroke *stroke, float dist, float co[3], float mask)
+{
+ float mco[3];
+
+ /* if the active area is being applied for symmetry, flip it
+ across the symmetry axis and rotate it back to the orignal
+ position in order to project it. This insures that the
+ brush texture will be oriented correctly. */
+ if(stroke->brush->mtex.tex) {
+ paint_stroke_symmetry_unflip(stroke, mco, co);
+ co = mco;
+ }
+
+ return brush_tex_strength(&stroke->vc,
+ stroke->project_mat, stroke->brush, co, mask, dist,
+ stroke->pixel_radius, stroke->radius,
+ stroke->rotation,
+ stroke->tex_mouse);
+}
+
int paint_stroke_exec(bContext *C, wmOperator *op)
{
+ Paint *paint = paint_get_active(CTX_data_scene(C));
PaintStroke *stroke = op->customdata;
RNA_BEGIN(op->ptr, itemptr, "stroke") {
+ RNA_float_get_array(&itemptr, "location", stroke->location);
+ RNA_float_get_array(&itemptr, "mouse", stroke->mouse);
+ stroke->pressure = RNA_float_get(&itemptr, "pressure");
+ paint_stroke_update_cache(C, stroke, paint);
+
stroke->update_step(C, stroke, &itemptr);
+
+ stroke->first_dab = 0;
}
RNA_END;
@@ -1043,10 +1348,7 @@ int paint_stroke_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-ViewContext *paint_stroke_view_context(PaintStroke *stroke)
-{
- return &stroke->vc;
-}
+/**** mode data ****/
void *paint_stroke_mode_data(struct PaintStroke *stroke)
{
@@ -1058,6 +1360,106 @@ void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
stroke->mode_data = mode_data;
}
+/**** cache access ***/
+
+ViewContext *paint_stroke_view_context(PaintStroke *stroke)
+{
+ return &stroke->vc;
+}
+
+float paint_stroke_feather(struct PaintStroke *stroke)
+{
+ return stroke->feather;
+}
+
+void paint_stroke_mouse_location(PaintStroke *stroke, float mouse[2])
+{
+ copy_v2_v2(mouse, stroke->mouse);
+}
+void paint_stroke_initial_mouse_location(PaintStroke *stroke, float initial_mouse[2])
+{
+ copy_v2_v2(initial_mouse, stroke->initial_mouse);
+}
+
+void paint_stroke_location(PaintStroke *stroke, float location[3])
+{
+ copy_v3_v3(location, stroke->location);
+}
+
+float paint_stroke_pressure(struct PaintStroke *stroke)
+{
+ return stroke->pressure;
+}
+
+void paint_stroke_symmetry_location(struct PaintStroke *stroke, float loc[3])
+{
+ copy_v3_v3(loc, stroke->symmetry_location);
+}
+
+float paint_stroke_radius(struct PaintStroke *stroke)
+{
+ return stroke->radius;
+}
+
+float paint_stroke_radius_squared(struct PaintStroke *stroke)
+{
+ return stroke->radius_squared;
+}
+
+int paint_stroke_first_dab(PaintStroke *stroke)
+{
+ return stroke->first_dab;
+}
+
+void paint_stroke_project(PaintStroke *stroke, float loc[3], float out[2])
+{
+ view3d_project_float(stroke->vc.ar, loc, out, stroke->project_mat);
+}
+
+void paint_stroke_symmetry_unflip(PaintStroke *stroke, float out[3], float vec[3])
+{
+ paint_flip_coord(out, vec, stroke->mirror_symmetry_pass);
+
+ if(stroke->radial_symmetry_pass)
+ mul_m4_v3(stroke->symm_rot_mat_inv, out);
+}
+
+/**** stroke modifiers ****/
+void paint_stroke_set_modifier_use_original_location(PaintStroke *stroke)
+{
+ stroke->modifier_use_original_location = 1;
+}
+
+void paint_stroke_set_modifier_initial_radius_factor(PaintStroke *stroke,
+ float initial_radius_factor)
+{
+ stroke->modifier_initial_radius_factor = initial_radius_factor;
+}
+
+void paint_stroke_set_modifier_use_original_texture_coords(PaintStroke *stroke)
+{
+ stroke->modifier_use_original_texture_coords = 1;
+}
+
+/* returns 1 if the mouse is over the mesh, 0 otherwise */
+int paint_stroke_over_mesh(bContext *C, PaintStroke *stroke, int x, int y)
+{
+ float mouse[2] = {x, y}, co[3];
+ return stroke->get_location(C, stroke, co, mouse);
+}
+
+/* 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 paint_stroke_get_location(bContext *C, PaintStroke *stroke,
+ BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
+ float out[3], float mouse[2], int original)
+{
+ ViewContext *vc = paint_stroke_view_context(stroke);
+ return paint_util_raycast(vc, hit_cb, mode_data, out, mouse, original);
+}
+
int paint_poll(bContext *C)
{
Paint *p = paint_get_active(CTX_data_scene(C));
@@ -1076,3 +1478,88 @@ void paint_cursor_start(bContext *C, int (*poll)(bContext *C))
p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL);
}
+/* Optimization for testing if a coord is within the brush area */
+
+void paint_stroke_test_init(PaintStrokeTest *test, PaintStroke *stroke)
+{
+ test->radius_squared= stroke->radius_squared;
+ copy_v3_v3(test->location, stroke->symmetry_location);
+}
+
+int paint_stroke_test(PaintStrokeTest *test, float co[3])
+{
+ float distsq = len_squared_v3v3(co, test->location);
+
+ if(distsq <= test->radius_squared) {
+ test->dist = sqrt(distsq);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+int paint_stroke_test_sq(PaintStrokeTest *test, float co[3])
+{
+ float distsq = len_squared_v3v3(co, test->location);
+
+ if(distsq <= test->radius_squared) {
+ test->dist = distsq;
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+int paint_stroke_test_fast(PaintStrokeTest *test, float co[3])
+{
+ return len_squared_v3v3(co, test->location) <= test->radius_squared;
+}
+
+int paint_stroke_test_cube(PaintStrokeTest *test, float co[3], float local[4][4])
+{
+ const static float side = 0.70710678118654752440084436210485; // sqrt(.5);
+
+ float local_co[3];
+
+ mul_v3_m4v3(local_co, local, co);
+
+ local_co[0] = fabs(local_co[0]);
+ local_co[1] = fabs(local_co[1]);
+ local_co[2] = fabs(local_co[2]);
+
+ if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
+ test->dist = MAX3(local_co[0], local_co[1], local_co[2]) / side;
+
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+#if 0
+
+static int paint_stroke_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
+{
+ if (paint_stroke_test_fast(test, co)) {
+ float t1[3], t2[3], t3[3], dist;
+
+ sub_v3_v3v3(t1, location, co);
+ sub_v3_v3v3(t2, x2, location);
+
+ cross_v3_v3v3(t3, an, t1);
+
+ dist = len_v3(t3)/len_v3(t2);
+
+ test->dist = dist;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index 643e2cd6915..72f42aa1d3c 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -27,13 +27,20 @@
#include "MEM_guardedalloc.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
+#include "BKE_mesh.h"
+#include "BLI_string.h"
#include "BKE_utildefines.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_global.h"
+#include "BKE_multires.h"
#include "ED_sculpt.h"
@@ -188,6 +195,242 @@ static void undo_stack_free(UndoStack *stack)
stack->current= NULL;
}
+/**** paint undo for layers (mcol, paintmask) ****/
+
+typedef enum {
+ LAYER_ADDED,
+ LAYER_REMOVED
+} PaintLayerUndoOp;
+
+struct PaintLayerUndoNode {
+ struct PaintLayerUndoNode *next, *prev;
+
+ /* customdata type */
+ int type;
+ /* add/remove */
+ PaintLayerUndoOp op;
+ /* only for restoring into its original location */
+ int layer_offset;
+ /* for identifying layer, don't use layer_offset for that */
+ char layer_name[32];
+ /* copy of a removed layer's data */
+ void *layer_data;
+ void **multires_layer_data;
+ float strength;
+ /* length of multires_layer_data array */
+ int totface;
+ /* whether layer has multires data */
+ int flag_multires;
+};
+
+void paint_layer_undo_set_add(PaintLayerUndoNode *unode, char *name)
+{
+ unode->op = LAYER_ADDED;
+
+ /* check for restore */
+ if(unode->layer_name != name) {
+ BLI_strncpy(unode->layer_name, name,
+ sizeof(unode->layer_name));
+ }
+
+ unode->totface = 0;
+}
+
+void paint_layer_undo_set_remove(PaintLayerUndoNode *unode, char *name,
+ CustomData *data, CustomData *fdata,
+ int totvert, int totface)
+{
+ CustomDataMultires *cdm;
+ int ndx;
+
+ unode->op = LAYER_REMOVED;
+ /* check for restore */
+ if(unode->layer_name != name) {
+ BLI_strncpy(unode->layer_name, name,
+ sizeof(unode->layer_name));
+ }
+
+ unode->totface = totface;
+
+ ndx = CustomData_get_named_layer_index(data, unode->type, name);
+ assert(ndx >= 0);
+
+ /* store the layer offset so we can re-insert layer at the
+ same location on undo */
+ unode->layer_offset =
+ ndx - CustomData_get_layer_index(data, unode->type);
+
+ /* backup layer data */
+ unode->layer_data = MEM_dupallocN(data->layers[ndx].data);
+
+ unode->strength = data->layers[ndx].strength;
+
+ unode->flag_multires = data->layers[ndx].flag & CD_FLAG_MULTIRES;
+ if(!unode->flag_multires)
+ return;
+
+ /* back multires data */
+ cdm = CustomData_get_layer(fdata, CD_GRIDS);
+ if(cdm && totface) {
+ int i;
+
+ /* check first cdm to see if this layer has multires data */
+ if(!CustomData_multires_get_data(cdm, unode->type, name))
+ return;
+
+ unode->multires_layer_data =
+ MEM_callocN(sizeof(void*) * totface,
+ "PaintLayerUndoNode.multires_layer_data");
+
+ for(i = 0; i < totface; ++i, ++cdm) {
+ float *f;
+
+ f = CustomData_multires_get_data(cdm, unode->type,
+ name);
+ assert(f);
+
+ unode->multires_layer_data[i] = MEM_dupallocN(f);
+ }
+ }
+}
+
+void paint_layer_undo_restore(bContext *C, ListBase *lb)
+{
+ PaintLayerUndoNode *unode = lb->first; /* only one undo node */
+ Object *ob;
+ Mesh *me;
+ CustomData *data, *fdata;
+ CustomDataMultires *cdm;
+ int i, ndx, offset, active, totelem;
+
+ ob = CTX_data_active_object(C);
+ me = get_mesh(ob);
+ fdata = &me->fdata;
+
+ switch(unode->type) {
+ case CD_MCOL:
+ data = &me->fdata;
+ totelem = me->totface;
+ break;
+ case CD_PAINTMASK:
+ data = &me->vdata;
+ totelem = me->totface;
+ break;
+ default:
+ assert(0);
+ }
+
+ /* update multires before making changes */
+ if(ED_paint_multires_active(CTX_data_scene(C), ob))
+ multires_force_update(ob);
+
+ switch(unode->op) {
+ case LAYER_ADDED:
+ /* backup current layer data for redo */
+ paint_layer_undo_set_remove(unode, unode->layer_name, data,
+ fdata, me->totvert, me->totface);
+
+ active = CustomData_get_active_layer(data, unode->type);
+
+ /* remove layer */
+ ndx = CustomData_get_named_layer_index(data, unode->type,
+ unode->layer_name);
+ CustomData_free_layer(data, unode->type, totelem, ndx);
+
+ /* set active layer */
+ offset = CustomData_number_of_layers(data, unode->type) - 1;
+ if(active > offset)
+ active = offset;
+ CustomData_set_layer_active(data, unode->type, active);
+
+ /* remove layer's multires data */
+ cdm = CustomData_get_layer(fdata, CD_GRIDS);
+ if(!cdm)
+ break;
+
+ CustomData_multires_remove_layers(cdm, me->totface,
+ unode->type,
+ unode->layer_name);
+
+ break;
+ case LAYER_REMOVED:
+ paint_layer_undo_set_add(unode, unode->layer_name);
+
+ /* add layer */
+ CustomData_add_layer_at_offset(data, unode->type, CD_ASSIGN,
+ unode->layer_data, totelem,
+ unode->layer_offset);
+
+ ndx = CustomData_get_named_layer_index(data, unode->type,
+ unode->layer_name);
+ offset = ndx - CustomData_get_layer_index(data, unode->type);
+
+ CustomData_set_layer_active(data, unode->type, offset);
+ BLI_strncpy(data->layers[ndx].name, unode->layer_name,
+ sizeof(data->layers[ndx].name));
+ data->layers[ndx].strength = unode->strength;
+
+ if(!unode->flag_multires)
+ break;
+
+ /* add multires layer */
+ CustomData_set_layer_offset_flag(data, unode->type,
+ offset, CD_FLAG_MULTIRES);
+
+ cdm = CustomData_get_layer(fdata, CD_GRIDS);
+ if(!cdm)
+ break;
+
+ for(i = 0; i < me->totface; ++i, ++cdm) {
+ void *griddata = unode->multires_layer_data[i];
+
+ CustomData_multires_add_layer_data(cdm, unode->type,
+ unode->layer_name,
+ griddata);
+ }
+
+ unode->layer_data = NULL;
+ if(unode->multires_layer_data)
+ MEM_freeN(unode->multires_layer_data);
+ unode->multires_layer_data = NULL;
+
+ break;
+ }
+}
+
+static void paint_layer_undo_node_free(ListBase *lb)
+{
+ PaintLayerUndoNode *unode = lb->first;
+
+ if(unode->layer_data)
+ MEM_freeN(unode->layer_data);
+
+ if(unode->multires_layer_data) {
+ int i;
+
+ for(i = 0; i < unode->totface; ++i)
+ MEM_freeN(unode->multires_layer_data[i]);
+ MEM_freeN(unode->multires_layer_data);
+ }
+}
+
+PaintLayerUndoNode *paint_layer_undo_push(int type, char *description)
+{
+ PaintLayerUndoNode *unode;
+
+ undo_paint_push_begin(UNDO_PAINT_MESH, description,
+ paint_layer_undo_restore,
+ paint_layer_undo_node_free);
+
+ unode = MEM_callocN(sizeof(PaintLayerUndoNode), "PaintLayerUndoNode");
+ unode->type = type;
+
+ BLI_addtail(undo_paint_push_get_list(UNDO_PAINT_MESH), unode);
+ undo_paint_push_end(UNDO_PAINT_MESH);
+
+ return unode;
+}
+
/* Exported Functions */
void undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free)
@@ -243,4 +486,3 @@ 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 e3a486a0fee..42c56424df4 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -4,6 +4,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -17,10 +18,13 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BIF_gl.h"
+#include "BIF_glutil.h"
#include "ED_view3d.h"
#include "ED_screen.h"
@@ -31,10 +35,21 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
+
#include "paint_intern.h"
/* 3D Paint */
+void ED_paint_force_update(bContext *C)
+{
+ Object *ob= CTX_data_active_object(C);
+
+ if(ob && (ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)))
+ multires_force_update(ob);
+}
+
static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
{
VECCOPY(pco, co);
@@ -296,3 +311,319 @@ void PAINT_OT_face_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
+
+float paint_calc_object_space_radius(ViewContext *vc, float center[3],
+ float pixel_radius)
+{
+ Object *ob = vc->obact;
+ float delta[3], scale, loc[3];
+
+ mul_v3_m4v3(loc, ob->obmat, center);
+
+ initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
+ window_to_3d_delta(vc->ar, delta, pixel_radius, 0);
+
+ scale= fabsf(mat4_to_scale(ob->obmat));
+ scale= (scale == 0.0f)? 1.0f: scale;
+
+ return len_v3(delta)/scale;
+}
+
+/* Paint modes can handle multires differently from regular meshes, but only
+ if it's the last modifier on the stack and it is not on level zero */
+struct MultiresModifierData *ED_paint_multires_active(Scene *scene, Object *ob)
+{
+ Mesh *me= (Mesh*)ob->data;
+ ModifierData *md, *nmd;
+
+ if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
+ /* multires can't work without displacement layer */
+ return NULL;
+ }
+
+ for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
+ if(md->type == eModifierType_Multires) {
+ MultiresModifierData *mmd= (MultiresModifierData*)md;
+
+ /* Check if any of the modifiers after multires are active
+ * if not it can use the multires struct */
+ for(nmd= md->next; nmd; nmd= nmd->next)
+ if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
+ break;
+
+ if(!nmd && mmd->sculptlvl > 0)
+ return mmd;
+ }
+ }
+
+ return NULL;
+}
+
+/*** BVH Tree ***/
+
+/* Get a screen-space rectangle of the modified area */
+static int paint_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
+ Object *ob, rcti *rect)
+{
+ PBVH *pbvh= ob->paint->pbvh;
+ float bb_min[3], bb_max[3], pmat[4][4];
+ int i, j, k;
+
+ view3d_get_object_project_mat(rv3d, ob, pmat);
+
+ if(!pbvh)
+ return 0;
+
+ BLI_pbvh_redraw_BB(pbvh, 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 paint_tag_partial_redraw(bContext *C, Object *ob)
+{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ rcti r;
+
+ if(paint_get_redraw_rect(ar, rv3d, ob, &r)) {
+ //rcti tmp;
+
+ r.xmin += ar->winrct.xmin + 1;
+ r.xmax += ar->winrct.xmin - 1;
+ r.ymin += ar->winrct.ymin + 1;
+ r.ymax += ar->winrct.ymin - 1;
+
+ //tmp = r;
+
+ //if (!BLI_rcti_is_empty(&ss->previous_r))
+ // BLI_union_rcti(&r, &ss->previous_r);
+
+ //ss->previous_r= tmp;
+
+ ob->paint->partial_redraw = 1;
+ ED_region_tag_redraw_partial(ar, &r);
+ }
+}
+
+void paint_get_redraw_planes(float planes[4][4], ARegion *ar,
+ RegionView3D *rv3d, Object *ob)
+{
+ PBVH *pbvh= ob->paint->pbvh;
+ BoundBox bb;
+ bglMats mats;
+ rcti rect;
+
+ memset(&bb, 0, sizeof(BoundBox));
+
+ view3d_get_transformation(ar, rv3d, ob, &mats);
+ paint_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);
+ mul_m4_fl(planes, -1.0f);
+
+ /* clear redraw flag from nodes */
+ if(pbvh)
+ BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
+}
+
+float get_tex_pixel(Brush* br, float u, float v)
+{
+ TexResult texres;
+ float co[3];
+ int hasrgb;
+
+ co[0] = u;
+ co[1] = v;
+ co[2] = 0;
+
+ memset(&texres, 0, sizeof(TexResult));
+ hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 1, &texres);
+
+ if (hasrgb & TEX_RGB)
+ texres.tin = (0.35*texres.tr + 0.45*texres.tg + 0.2*texres.tb)*texres.ta;
+
+ return texres.tin;
+}
+
+/* selectively flip any axis of a coordinate */
+void paint_flip_coord(float out[3], float in[3], const char symm)
+{
+ if(symm & PAINT_SYMM_X)
+ out[0]= -in[0];
+ else
+ out[0]= in[0];
+ if(symm & PAINT_SYMM_Y)
+ out[1]= -in[1];
+ else
+ out[1]= in[1];
+ if(symm & PAINT_SYMM_Z)
+ out[2]= -in[2];
+ else
+ out[2]= in[2];
+}
+
+/* return a multiplier for brush strength at a coordinate,
+ incorporating texture, curve control, and masking
+
+ TODO: pulled almost directly from sculpt, still needs
+ to be prettied up
+*/
+float brush_tex_strength(ViewContext *vc,
+ float pmat[4][4], Brush *br,
+ float co[3], float mask, const float len,
+ float pixel_radius, float radius3d,
+ float special_rotation, float tex_mouse[2])
+{
+ MTex *mtex = &br->mtex;
+ float avg= 1;
+
+ if(!mtex->tex) {
+ avg= 1;
+ }
+ else if(mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ float jnk;
+
+ /* Get strength by feeding the vertex
+ location directly into a texture */
+ externtex(mtex, co, &avg,
+ &jnk, &jnk, &jnk, &jnk, 0);
+ }
+ else {
+ float rotation = -mtex->rot;
+ float x, y, point_2d[3];
+ float radius;
+
+ view3d_project_float(vc->ar, co, point_2d, pmat);
+
+ /* if fixed mode, keep coordinates relative to mouse */
+ if(mtex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ rotation += special_rotation;
+
+ point_2d[0] -= tex_mouse[0];
+ point_2d[1] -= tex_mouse[1];
+
+ radius = pixel_radius; // use pressure adjusted size for fixed mode
+
+ x = point_2d[0];
+ y = point_2d[1];
+ }
+ else /* else (mtex->brush_map_mode == MTEX_MAP_MODE_TILED),
+ leave the coordinates relative to the screen */
+ {
+ radius = brush_size(br); // use unadjusted size for tiled mode
+
+ x = point_2d[0] - vc->ar->winrct.xmin;
+ y = point_2d[1] - vc->ar->winrct.ymin;
+ }
+
+ x /= vc->ar->winx;
+ y /= vc->ar->winy;
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ x -= 0.5f;
+ y -= 0.5f;
+ }
+
+ x *= vc->ar->winx / radius;
+ y *= vc->ar->winy / radius;
+
+ /* it is probably worth optimizing for those cases where
+ the texture is not rotated by skipping the calls to
+ atan2, sqrtf, sin, and cos. */
+ if (rotation > 0.001 || rotation < -0.001) {
+ const float angle = atan2(y, x) + rotation;
+ const float flen = sqrtf(x*x + y*y);
+
+ x = flen * cos(angle);
+ y = flen * sin(angle);
+ }
+
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
+
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
+
+ avg = get_tex_pixel(br, x, y);
+ }
+
+ avg += br->texture_sample_bias;
+
+ avg *= brush_curve_strength(br, len, radius3d); /* Falloff curve */
+ avg*= 1 - mask;
+
+ return avg;
+}
+
+int paint_util_raycast(ViewContext *vc,
+ BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
+ float out[3], float mouse[2], int original)
+{
+ float ray_start[3], ray_end[3], ray_normal[3], dist;
+ float obimat[4][4];
+ float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
+ mouse[1] - vc->ar->winrct.ymin};
+ PaintStrokeRaycastData hit_data;
+
+ viewline(vc->ar, vc->v3d, mval, ray_start, ray_end);
+
+ invert_m4_m4(obimat, vc->obact->obmat);
+ mul_m4_v3(obimat, ray_start);
+ mul_m4_v3(obimat, ray_end);
+
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist= normalize_v3(ray_normal);
+
+ hit_data.mode_data = mode_data;
+ hit_data.ob = vc->obact;
+ hit_data.ray_start = ray_start;
+ hit_data.ray_normal = ray_normal;
+ hit_data.dist = dist;
+ hit_data.hit = 0;
+ hit_data.original = original;
+ BLI_pbvh_raycast(vc->obact->paint->pbvh, hit_cb, &hit_data,
+ ray_start, ray_normal, original);
+
+ copy_v3_v3(out, ray_normal);
+ mul_v3_fl(out, hit_data.dist);
+ add_v3_v3(out, ray_start);
+
+ return hit_data.hit;
+}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 3c25d861d2f..b12767d46ad 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -22,7 +22,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Nicholas Bishop
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -62,30 +62,29 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_dmgrid.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "BKE_subsurf.h"
+#include "BKE_utildefines.h"
#include "WM_api.h"
#include "WM_types.h"
-
#include "ED_armature.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "paint_intern.h"
+#include "ptex.h"
-/* brush->vertexpaint_tool */
-#define VP_MIX 0
-#define VP_ADD 1
-#define VP_SUB 2
-#define VP_MUL 3
-#define VP_BLUR 4
-#define VP_LIGHTEN 5
-#define VP_DARKEN 6
+#include "paint_intern.h"
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -102,8 +101,10 @@ int vertex_paint_poll(bContext *C)
{
if(vertex_paint_mode_poll(C) &&
paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
+ Object *ob = CTX_data_active_object(C);
ScrArea *sa= CTX_wm_area(C);
- if(sa->spacetype==SPACE_VIEW3D) {
+ if(!(get_mesh(ob)->editflag & ME_EDIT_PTEX) &&
+ sa->spacetype==SPACE_VIEW3D) {
ARegion *ar= CTX_wm_region(C);
if(ar->regiontype==RGN_TYPE_WINDOW)
return 1;
@@ -187,72 +188,6 @@ unsigned int vpaint_get_current_col(VPaint *vp)
return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
}
-static void do_shared_vertexcol(Mesh *me)
-{
- /* if no mcol: do not do */
- /* if tface: only the involved faces, otherwise all */
- MFace *mface;
- MTFace *tface;
- int a;
- short *scolmain, *scol;
- char *mcol;
-
- if(me->mcol==0 || me->totvert==0 || me->totface==0) return;
-
- scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain");
-
- tface= me->mtface;
- mface= me->mface;
- mcol= (char *)me->mcol;
- for(a=me->totface; a>0; a--, mface++, mcol+=16) {
- if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
- scol= scolmain+4*mface->v1;
- scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3];
- scol= scolmain+4*mface->v2;
- scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7];
- scol= scolmain+4*mface->v3;
- scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11];
- if(mface->v4) {
- scol= scolmain+4*mface->v4;
- scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15];
- }
- }
- if(tface) tface++;
- }
-
- a= me->totvert;
- scol= scolmain;
- while(a--) {
- if(scol[0]>1) {
- scol[1]/= scol[0];
- scol[2]/= scol[0];
- scol[3]/= scol[0];
- }
- scol+= 4;
- }
-
- tface= me->mtface;
- mface= me->mface;
- mcol= (char *)me->mcol;
- for(a=me->totface; a>0; a--, mface++, mcol+=16) {
- if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
- scol= scolmain+4*mface->v1;
- mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3];
- scol= scolmain+4*mface->v2;
- mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3];
- scol= scolmain+4*mface->v3;
- mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3];
- if(mface->v4) {
- scol= scolmain+4*mface->v4;
- mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3];
- }
- }
- if(tface) tface++;
- }
-
- MEM_freeN(scolmain);
-}
-
static void make_vertexcol(Object *ob) /* single ob */
{
Mesh *me;
@@ -272,24 +207,6 @@ static void make_vertexcol(Object *ob) /* single ob */
//else
memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
-
- DAG_id_flush_update(&me->id, OB_RECALC_DATA);
-
-}
-
-static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
-{
- if(vp->vpaint_prev) {
- MEM_freeN(vp->vpaint_prev);
- vp->vpaint_prev= NULL;
- }
- vp->tot= tot;
-
- if(mcol==NULL || tot==0) return;
-
- vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
- memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
-
}
static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
@@ -494,197 +411,6 @@ void vpaint_dogamma(Scene *scene)
}
*/
-static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
-{
- char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col=0;
-
- if(fac==0) return col1;
- if(fac>=255) return col2;
-
- mfac= 255-fac;
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- cp[0]= 255;
- cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
- cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
- cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
-
- return col;
-}
-
-static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
-{
- char *cp1, *cp2, *cp;
- int temp;
- unsigned int col=0;
-
- if(fac==0) return col1;
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- cp[0]= 255;
- temp= cp1[1] + ((fac*cp2[1])/255);
- if(temp>254) cp[1]= 255; else cp[1]= temp;
- temp= cp1[2] + ((fac*cp2[2])/255);
- if(temp>254) cp[2]= 255; else cp[2]= temp;
- temp= cp1[3] + ((fac*cp2[3])/255);
- if(temp>254) cp[3]= 255; else cp[3]= temp;
-
- return col;
-}
-
-static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
-{
- char *cp1, *cp2, *cp;
- int temp;
- unsigned int col=0;
-
- if(fac==0) return col1;
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- cp[0]= 255;
- temp= cp1[1] - ((fac*cp2[1])/255);
- if(temp<0) cp[1]= 0; else cp[1]= temp;
- temp= cp1[2] - ((fac*cp2[2])/255);
- if(temp<0) cp[2]= 0; else cp[2]= temp;
- temp= cp1[3] - ((fac*cp2[3])/255);
- if(temp<0) cp[3]= 0; else cp[3]= temp;
-
- return col;
-}
-
-static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
-{
- char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col=0;
-
- if(fac==0) return col1;
-
- mfac= 255-fac;
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- /* first mul, then blend the fac */
- cp[0]= 255;
- cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255) )/255;
- cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255) )/255;
- cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255) )/255;
-
-
- return col;
-}
-
-static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
-{
- char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col=0;
-
- if(fac==0) return col1;
- if(fac>=255) return col2;
-
- mfac= 255-fac;
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- /* See if are lighter, if so mix, else dont do anything.
- if the paint col is darker then the original, then ignore */
- if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3])
- return col1;
-
- cp[0]= 255;
- cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
- cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
- cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
-
- return col;
-}
-
-static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
-{
- char *cp1, *cp2, *cp;
- int mfac;
- unsigned int col=0;
-
- if(fac==0) return col1;
- if(fac>=255) return col2;
-
- mfac= 255-fac;
-
- cp1= (char *)&col1;
- cp2= (char *)&col2;
- cp= (char *)&col;
-
- /* See if were darker, if so mix, else dont do anything.
- if the paint col is brighter then the original, then ignore */
- if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3])
- return col1;
-
- cp[0]= 255;
- cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
- cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
- cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
- return col;
-}
-
-static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
-{
- Brush *brush = paint_brush(&vp->paint);
-
- if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_SUB) *col= mcol_sub( *col, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_MUL) *col= mcol_mul( *col, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha);
-
- /* if no spray, clip color adding with colorig & orig alpha */
- if((vp->flag & VP_SPRAY)==0) {
- unsigned int testcol=0, a;
- char *cp, *ct, *co;
-
- alpha= (int)(255.0*brush_alpha(brush));
-
- if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_LIGHTEN) testcol= mcol_lighten( *colorig, paintcol, alpha);
- else if(brush->vertexpaint_tool==VP_DARKEN) testcol= mcol_darken( *colorig, paintcol, alpha);
-
- cp= (char *)col;
- ct= (char *)&testcol;
- co= (char *)colorig;
-
- for(a=0; a<4; a++) {
- if( ct[a]<co[a] ) {
- if( cp[a]<ct[a] ) cp[a]= ct[a];
- else if( cp[a]>co[a] ) cp[a]= co[a];
- }
- else {
- if( cp[a]<co[a] ) cp[a]= co[a];
- else if( cp[a]>ct[a] ) cp[a]= ct[a];
- }
- }
- }
-}
-
-
static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
{
struct ImBuf *ibuf;
@@ -774,32 +500,32 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
if (flip) {
switch(tool) {
- case VP_MIX:
+ case IMB_BLEND_MIX:
paintval = 1.f - paintval; break;
- case VP_ADD:
- tool= VP_SUB; break;
- case VP_SUB:
- tool= VP_ADD; break;
- case VP_LIGHTEN:
- tool= VP_DARKEN; break;
- case VP_DARKEN:
- tool= VP_LIGHTEN; break;
+ case IMB_BLEND_ADD:
+ tool= IMB_BLEND_SUB; break;
+ case IMB_BLEND_SUB:
+ tool= IMB_BLEND_ADD; break;
+ case IMB_BLEND_LIGHTEN:
+ tool= IMB_BLEND_DARKEN; break;
+ case IMB_BLEND_DARKEN:
+ tool= IMB_BLEND_LIGHTEN; break;
}
}
- if(tool==VP_MIX || tool==VP_BLUR)
+ if(tool==IMB_BLEND_MIX || tool==VERTEX_PAINT_BLUR)
dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
- else if(tool==VP_ADD)
+ else if(tool==IMB_BLEND_ADD)
dw->weight += paintval*alpha;
- else if(tool==VP_SUB)
+ else if(tool==IMB_BLEND_SUB)
dw->weight -= paintval*alpha;
- else if(tool==VP_MUL)
+ else if(tool==IMB_BLEND_MUL)
/* first mul, then blend the fac */
dw->weight = ((1.0-alpha) + alpha*paintval)*dw->weight;
- else if(tool==VP_LIGHTEN) {
+ else if(tool==IMB_BLEND_LIGHTEN) {
if (dw->weight < paintval)
dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
- } else if(tool==VP_DARKEN) {
+ } else if(tool==IMB_BLEND_DARKEN) {
if (dw->weight > paintval)
dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
}
@@ -810,21 +536,21 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
float testw=0.0f;
alpha= brush_alpha(brush);
- if(tool==VP_MIX || tool==VP_BLUR)
+ if(tool==IMB_BLEND_MIX || tool==VERTEX_PAINT_BLUR)
testw = paintval*alpha + uw->weight*(1.0-alpha);
- else if(tool==VP_ADD)
+ else if(tool==IMB_BLEND_ADD)
testw = uw->weight + paintval*alpha;
- else if(tool==VP_SUB)
+ else if(tool==IMB_BLEND_SUB)
testw = uw->weight - paintval*alpha;
- else if(tool==VP_MUL)
+ else if(tool==IMB_BLEND_MUL)
/* first mul, then blend the fac */
testw = ((1.0-alpha) + alpha*paintval)*uw->weight;
- else if(tool==VP_LIGHTEN) {
+ else if(tool==IMB_BLEND_LIGHTEN) {
if (uw->weight < paintval)
testw = paintval*alpha + uw->weight*(1.0-alpha);
else
testw = uw->weight;
- } else if(tool==VP_DARKEN) {
+ } else if(tool==IMB_BLEND_DARKEN) {
if (uw->weight > paintval)
testw = paintval*alpha + uw->weight*(1.0-alpha);
else
@@ -1413,7 +1139,7 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED
wpd->vgroup_mirror= actdef;
}
}
-
+
return 1;
}
@@ -1496,7 +1222,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* make sure each vertex gets treated only once */
/* and calculate filter weight */
totw= 0;
- if(brush->vertexpaint_tool==VP_BLUR)
+ if(brush->vertexpaint_tool==VERTEX_PAINT_BLUR)
paintweight= 0.0f;
else
paintweight= ts->vgroup_weight;
@@ -1510,7 +1236,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
(me->dvert+mface->v3)->flag= 1;
if(mface->v4) (me->dvert+mface->v4)->flag= 1;
- if(brush->vertexpaint_tool==VP_BLUR) {
+ if(brush->vertexpaint_tool==VERTEX_PAINT_BLUR) {
MDeformWeight *dw, *(*dw_func)(MDeformVert *, int);
if(wp->flag & VP_ONLYVGROUP)
@@ -1532,7 +1258,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
}
- if(brush->vertexpaint_tool==VP_BLUR)
+ if(brush->vertexpaint_tool==VERTEX_PAINT_BLUR)
paintweight/= (float)totw;
for(index=0; index<totindex; index++) {
@@ -1633,7 +1359,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
- wpaint_stroke_update_step,
+ wpaint_stroke_update_step, NULL, NULL,
wpaint_stroke_done);
/* add modal handler */
@@ -1689,6 +1415,10 @@ void PAINT_OT_weight_set(wmOperatorType *ot)
/* ************ set / clear vertex paint mode ********** */
+struct VPaintSession {
+ unsigned int src_image_gltex;
+};
+
static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
{
@@ -1704,11 +1434,10 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
return OPERATOR_PASS_THROUGH;
}
- if(me && me->mcol==NULL) make_vertexcol(ob);
-
/* toggle: end vpaint */
if(ob->mode & OB_MODE_VERTEX_PAINT) {
-
+ free_paintsession(ob);
+
ob->mode &= ~OB_MODE_VERTEX_PAINT;
}
else {
@@ -1716,18 +1445,25 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
/* Turn off weight painting */
if (ob->mode & OB_MODE_WEIGHT_PAINT)
set_wpaint(C, op);
-
- if(vp==NULL)
- vp= scene->toolsettings->vpaint= new_vpaint(0);
-
+
+ if(me->mcol==NULL)
+ make_vertexcol(ob);
+
+ if(!CustomData_get_layer(&me->fdata, CD_MPTEX))
+ WM_operator_name_call(C, "PTEX_OT_layer_add", WM_OP_INVOKE_REGION_WIN, NULL);
+
+ create_paintsession(ob);
+
paint_cursor_start(C, vertex_paint_poll);
paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
}
- if (me)
- /* update modifier stack for mapping requirements */
- DAG_id_flush_update(&me->id, OB_RECALC_DATA);
+ /* create pbvh */
+ if(ob->mode & OB_MODE_VERTEX_PAINT) {
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH|CD_MASK_MCOL);
+ ob->paint->pbvh = dm->getPBVH(ob, dm);
+ }
WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
@@ -1749,211 +1485,6 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-
-
-/* ********************** vertex paint operator ******************* */
-
-/* Implementation notes:
-
-Operator->invoke()
- - validate context (add mcol)
- - create customdata storage
- - call paint once (mouse click)
- - add modal handler
-
-Operator->modal()
- - for every mousemove, apply vertex paint
- - exit on mouse release, free customdata
- (return OPERATOR_FINISHED also removes handler and operator)
-
-For future:
- - implement a stroke event (or mousemove with past positons)
- - revise whether op->customdata should be added in object, in set_vpaint
-
-*/
-
-typedef struct VPaintData {
- ViewContext vc;
- unsigned int paintcol;
- int *indexar;
- float *vertexcosnos;
- float vpimat[3][3];
-} VPaintData;
-
-static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- struct PaintStroke *stroke = op->customdata;
- VPaint *vp= ts->vpaint;
- struct VPaintData *vpd;
- Object *ob= CTX_data_active_object(C);
- Mesh *me;
- float mat[4][4], imat[4][4];
-
- /* context checks could be a poll() */
- me= get_mesh(ob);
- if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
-
- if(me->mcol==NULL) make_vertexcol(ob);
- if(me->mcol==NULL) return OPERATOR_CANCELLED;
-
- /* make mode data storage */
- vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
- paint_stroke_set_mode_data(stroke, vpd);
- view3d_set_viewcontext(C, &vpd->vc);
-
- vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
- vpd->indexar= get_indexarray(me);
- vpd->paintcol= vpaint_get_current_col(vp);
-
- /* for filtering */
- copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
-
- /* some old cruft to sort out later */
- mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
- invert_m4_m4(imat, mat);
- copy_m3_m4(vpd->vpimat, imat);
-
- return 1;
-}
-
-static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, float mval[2], float pressure, int UNUSED(flip))
-{
- ViewContext *vc = &vpd->vc;
- Brush *brush = paint_brush(&vp->paint);
- Mesh *me = get_mesh(ob);
- MFace *mface= ((MFace*)me->mface) + index;
- unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index;
- unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index;
- float alpha;
- int i;
-
- if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) ||
- ((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL)))
- return;
-
- if(brush->vertexpaint_tool==VP_BLUR) {
- unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
- if(mface->v4) {
- unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
- vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
- }
- else {
- vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
- }
-
- }
-
- for(i = 0; i < (mface->v4 ? 4 : 3); ++i) {
- alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval, pressure);
- if(alpha)
- vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0));
- }
-}
-
-static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- struct VPaintData *vpd = paint_stroke_mode_data(stroke);
- VPaint *vp= ts->vpaint;
- Brush *brush = paint_brush(&vp->paint);
- ViewContext *vc= &vpd->vc;
- Object *ob= vc->obact;
- Mesh *me= ob->data;
- float mat[4][4];
- int *indexar= vpd->indexar;
- int totindex, index, flip;
- float pressure, mval[2];
-
- RNA_float_get_array(itemptr, "mouse", mval);
- flip = RNA_boolean_get(itemptr, "pen_flip");
- pressure = RNA_float_get(itemptr, "pressure");
-
- view3d_operator_needs_opengl(C);
-
- /* load projection matrix */
- mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
-
- mval[0]-= vc->ar->winrct.xmin;
- mval[1]-= vc->ar->winrct.ymin;
-
-
- /* which faces are involved */
- if(vp->flag & VP_AREA) {
- totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
- }
- else {
- indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
- if(indexar[0]) totindex= 1;
- else totindex= 0;
- }
-
- swap_m4m4(vc->rv3d->persmat, mat);
-
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface)
- vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
- }
-
- swap_m4m4(vc->rv3d->persmat, mat);
-
- /* was disabled because it is slow, but necessary for blur */
- if(brush->vertexpaint_tool == VP_BLUR)
- do_shared_vertexcol(me);
-
- ED_region_tag_redraw(vc->ar);
-
- DAG_id_flush_update(ob->data, OB_RECALC_DATA);
-}
-
-static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- struct VPaintData *vpd= paint_stroke_mode_data(stroke);
-
- if(vpd->vertexcosnos)
- MEM_freeN(vpd->vertexcosnos);
- MEM_freeN(vpd->indexar);
-
- /* frees prev buffer */
- copy_vpaint_prev(ts->vpaint, NULL, 0);
-
- MEM_freeN(vpd);
-}
-
-static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-
- op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
- vpaint_stroke_update_step,
- vpaint_stroke_done);
-
- /* add modal handler */
- WM_event_add_modal_handler(C, op);
-
- op->type->modal(C, op, event);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-void PAINT_OT_vertex_paint(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Vertex Paint";
- ot->idname= "PAINT_OT_vertex_paint";
-
- /* api callbacks */
- ot->invoke= vpaint_invoke;
- ot->modal= paint_stroke_modal;
- /* ot->exec= vpaint_exec; <-- needs stroke property */
- ot->poll= vertex_paint_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
-
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
-}
-
/* ********************** weight from bones operator ******************* */
static int weight_from_bones_poll(bContext *C)
@@ -2001,4 +1532,3 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* properties */
ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights.");
}
-
diff --git a/source/blender/editors/sculpt_paint/pbvh_undo.c b/source/blender/editors/sculpt_paint/pbvh_undo.c
new file mode 100644
index 00000000000..793f5e79676
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/pbvh_undo.c
@@ -0,0 +1,570 @@
+/*
+ * $Id$
+ *
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "BLI_math.h"
+#include "BLI_ghash.h"
+#include "BLI_threads.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_dmgrid.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_paint.h"
+#include "BKE_mesh.h"
+#include "BKE_key.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+#include "ptex.h"
+
+/************************** Undo *************************/
+
+struct PBVHUndoNode {
+ struct PBVHUndoNode *next, *prev;
+
+ /* object id name */
+ char idname[MAX_ID_NAME];
+ /* only during push, not valid afterwards! */
+ struct PBVHNode *node;
+
+ /* total unique verts in node */
+ int totvert;
+
+ /* actual undo data */
+ float (*co)[3];
+ /* paint mask */
+ float *pmask;
+ char pmask_name[32];
+ /* ptex */
+ void **mptex_data;
+ char mptex_name[32];
+
+ /* non-multires */
+ /* to verify if me->totvert it still the same */
+ int maxvert;
+ /* to restore into the right location */
+ int *vert_indices;
+ int *face_indices;
+ /* multires */
+ /* to verify total number of grids is still the same */
+ int maxgrid;
+ int gridsize;
+ int totgrid;
+ /* to restore into the right location */
+ int *grid_indices;
+
+ /* shape keys */
+ char *shapeName[32]; /* keep size in sync with keyblock dna */
+
+ /* only during push, not stored */
+ short (*no)[3];
+ /* layer brush */
+ float *layer_disp;
+};
+
+static void pbvh_undo_restore_mesh_co(PBVHUndoNode *unode, bContext *C, Scene *scene, Object *ob)
+{
+ SculptSession *ss = ob->paint->sculpt;
+ Mesh *me = ob->data;
+ MVert *mvert;
+ char *shapeName= (char*)unode->shapeName;
+ int *index, i;
+
+ if(ss && ss->kb && strcmp(ss->kb->name, shapeName)) {
+ /* shape key has been changed before calling undo operator */
+
+ Key *key= ob_get_key(ob);
+ KeyBlock *kb= key_get_named_keyblock(key, shapeName);
+
+ if (kb) {
+ ob->shapenr= BLI_findindex(&key->block, kb) + 1;
+ ob->shapeflag|= OB_SHAPE_LOCK;
+
+ sculpt_update_mesh_elements(scene, ob, 0);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
+ } else {
+ /* key has been removed -- skip this undo node */
+ return;
+ }
+ }
+
+ mvert= me->mvert;
+ index= unode->vert_indices;
+
+ if(ss && ss->kb) {
+ float (*vertCos)[3];
+ vertCos= key_to_vertcos(ob, ss->kb);
+
+ for(i=0; i<unode->totvert; i++)
+ swap_v3_v3(vertCos[index[i]], unode->co[i]);
+
+ /* propagate new coords to keyblock */
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+
+ /* pbvh uses it's own mvert array, so coords should be */
+ /* propagated to pbvh here */
+ BLI_pbvh_apply_vertCos(ob->paint->pbvh, vertCos);
+
+ MEM_freeN(vertCos);
+ }
+ else {
+ 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;
+ }
+
+ }
+}
+
+static void pbvh_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);
+ PBVH *pbvh;
+ PBVHUndoNode *unode;
+ MultiresModifierData *mmd;
+ GridToFace *grid_face_map;
+ int i, j, update_co= 0, update_ptex= 0, update_mask= 0;
+
+ // XXX: sculpt_update_mesh_elements(scene, ob, 0);
+
+ pbvh = dm->getPBVH(ob, dm);
+ grid_face_map = dm->getGridFaceMap(dm);
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ CustomData *vdata, *fdata;
+
+ if(!(strcmp(unode->idname, ob->id.name)==0))
+ continue;
+
+ BLI_pbvh_get_customdata(pbvh, &vdata, &fdata);
+
+ if(unode->maxvert) {
+ /* regular mesh restore */
+ if(dm->getNumVerts(dm) != unode->maxvert)
+ continue;
+
+ update_co |= !!unode->co;
+ update_ptex |= !!unode->mptex_data;
+ update_mask |= !!unode->pmask;
+
+ if(unode->co) {
+ pbvh_undo_restore_mesh_co(unode, C, scene, ob);
+ }
+ if(unode->pmask) {
+ float *pmask;
+
+ pmask = CustomData_get_layer_named(vdata,
+ CD_PAINTMASK,
+ unode->pmask_name);
+
+ for(i=0; i<unode->totvert; i++)
+ SWAP(float, pmask[unode->vert_indices[i]],
+ unode->pmask[i]);
+ }
+ }
+ else if(unode->maxgrid && dm->getGridData) {
+ /* multires restore */
+ DMGridData **grids, *grid;
+ GridKey *gridkey;
+ float (*co)[3] = NULL, *pmask = NULL;
+ int gridsize, active_pmask;
+
+ if(dm->getNumGrids(dm) != unode->maxgrid)
+ continue;
+
+ /* do ptex restore before checking gridsize */
+ for(j=0; j<unode->totgrid; j++) {
+ if(unode->mptex_data) {
+ GridToFace *gtf = &grid_face_map[unode->grid_indices[j]];
+ MPtex *mptex;
+
+ mptex = CustomData_get_layer_named(fdata,
+ CD_MPTEX,
+ unode->mptex_name);
+ SWAP(void*, unode->mptex_data[j],
+ mptex[gtf->face].subfaces[gtf->offset].data);
+ }
+ }
+
+ update_ptex |= !!unode->mptex_data;
+
+ if(dm->getGridSize(dm) != unode->gridsize)
+ continue;
+
+ update_co |= !!unode->co;
+ update_mask |= !!unode->pmask;
+
+ grids= dm->getGridData(dm);
+ gridsize= dm->getGridSize(dm);
+ gridkey= dm->getGridKey(dm);
+
+ if(unode->co) {
+ co = unode->co;
+ }
+ if(unode->pmask) {
+ pmask = unode->pmask;
+ active_pmask = gridelem_active_offset(vdata, gridkey, CD_PAINTMASK);
+ }
+
+ for(j=0; j<unode->totgrid; j++) {
+ grid= grids[unode->grid_indices[j]];
+
+ for(i=0; i<gridsize*gridsize; i++) {
+ DMGridData *elem = GRIDELEM_AT(grid, i, gridkey);
+
+ if(co) {
+ swap_v3_v3(GRIDELEM_CO(elem, gridkey), co[0]);
+ ++co;
+ }
+ if(pmask) {
+ SWAP(float, GRIDELEM_MASK(elem, gridkey)[active_pmask],
+ *pmask);
+ ++pmask;
+ }
+ }
+ }
+ }
+ }
+
+ if(update_co || update_ptex || update_mask) {
+ SculptSession *ss = ob->paint->sculpt;
+ int update_flags = PBVH_UpdateRedraw;
+
+ /* 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(ob->paint->pbvh, NULL, NULL, BLI_pbvh_node_set_flags,
+ SET_INT_IN_POINTER(PBVH_UpdateAll));
+
+ if(update_co)
+ update_flags |= PBVH_UpdateBB|PBVH_UpdateOriginalBB;
+ if(update_ptex || update_mask)
+ update_flags |= PBVH_UpdateColorBuffers|PBVH_UpdateRedraw;
+
+ BLI_pbvh_update(ob->paint->pbvh, update_flags, NULL);
+
+ if((mmd=ED_paint_multires_active(scene, ob)))
+ multires_mark_as_modified(ob);
+
+ /* TODO: should work with other paint modes too */
+ if(ss && (ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1))
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ }
+}
+
+static void pbvh_undo_free(ListBase *lb)
+{
+ PBVHUndoNode *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->pmask)
+ MEM_freeN(unode->pmask);
+ if(unode->mptex_data) {
+ int i;
+ for(i = 0; i < unode->totgrid; ++i)
+ MEM_freeN(unode->mptex_data[i]);
+ MEM_freeN(unode->mptex_data);
+ }
+ if(unode->vert_indices)
+ MEM_freeN(unode->vert_indices);
+ if(unode->face_indices)
+ MEM_freeN(unode->face_indices);
+ if(unode->grid_indices)
+ MEM_freeN(unode->grid_indices);
+ if(unode->layer_disp)
+ MEM_freeN(unode->layer_disp);
+ }
+}
+
+PBVHUndoNode *pbvh_undo_get_node(PBVHNode *node)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ PBVHUndoNode *unode;
+
+ if(!lb)
+ return NULL;
+
+ for(unode=lb->first; unode; unode=unode->next)
+ if(unode->node == node)
+ return unode;
+
+ return NULL;
+}
+
+PBVHUndoNode *pbvh_undo_push_node(PBVHNode *node, PBVHUndoFlag flag,
+ Object *ob, Scene *scene)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ PBVHUndoNode *unode;
+ PBVH *pbvh = ob->paint->pbvh;
+ PBVHVertexIter vd;
+ int totbytes= 0;
+
+ CustomData *vdata, *fdata;
+ SculptSession *ss = NULL; /* for shapekey */
+
+ GridKey *gridkey;
+ int uses_grids, totgrid, *grid_indices;
+ GridToFace *grid_face_map;
+
+ /* list is manipulated by multiple threads, so we lock */
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ if((unode= pbvh_undo_get_node(node))) {
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return unode;
+ }
+
+ unode= MEM_callocN(sizeof(PBVHUndoNode), "PBVHUndoNode");
+ strcpy(unode->idname, ob->id.name);
+ unode->node= node;
+
+ /* XXX: changed this to just use unique verts rather than all,
+ seems like only unique are restored from anyway? -nicholas */
+ BLI_pbvh_node_num_verts(pbvh, node, &unode->totvert, NULL);
+
+ BLI_pbvh_get_customdata(pbvh, &vdata, &fdata);
+ uses_grids = BLI_pbvh_uses_grids(pbvh);
+
+ if(uses_grids) {
+ /* multires */
+ BLI_pbvh_node_get_grids(pbvh, node, &grid_indices,
+ &totgrid, &unode->maxgrid, &unode->gridsize,
+ NULL, NULL, &gridkey);
+
+ unode->totgrid= totgrid;
+ unode->grid_indices= MEM_mapallocN(sizeof(int)*totgrid, "PBVHUndoNode.grid_indices");
+ totbytes += sizeof(int) * totgrid;
+ }
+ else {
+ /* regular mesh */
+
+ if(scene) {
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
+ unode->maxvert= dm->getNumVerts(dm);
+ }
+ else
+ unode->maxvert= get_mesh(ob)->totvert;
+
+ if(flag & (PBVH_UNDO_CO_NO|PBVH_UNDO_PMASK)) {
+ unode->vert_indices= MEM_mapallocN(sizeof(int)*unode->totvert,
+ "PBVHUndoNode.vert_indices");
+ totbytes += sizeof(int) * unode->totvert;
+ }
+ }
+
+ /* allocate only the necessary undo data
+ XXX: we will use this while sculpting, is mapalloc slow to access then? */
+
+ if(flag & PBVH_UNDO_CO_NO) {
+ unode->co= MEM_mapallocN(sizeof(float)*3*unode->totvert, "PBVHUndoNode.co");
+ unode->no= MEM_mapallocN(sizeof(short)*3*unode->totvert, "PBVHUndoNode.no");
+ totbytes += (sizeof(float)*3 + sizeof(short)*3) * unode->totvert;
+ }
+ if(flag & PBVH_UNDO_PMASK) {
+ int active;
+ active= CustomData_get_active_layer_index(vdata, CD_PAINTMASK);
+
+ if(active == -1)
+ flag &= ~PBVH_UNDO_PMASK;
+ else {
+ BLI_strncpy(unode->pmask_name,
+ vdata->layers[active].name,
+ sizeof(unode->pmask_name));
+ unode->pmask= MEM_mapallocN(sizeof(float)*unode->totvert, "PBVHUndoNode.pmask");
+ totbytes += sizeof(float) * unode->totvert;
+ }
+ }
+ if(flag & PBVH_UNDO_PTEX) {
+ int i, active;
+
+ active= CustomData_get_active_layer_index(fdata, CD_MPTEX);
+
+ if(active == -1)
+ flag &= ~PBVH_UNDO_PTEX;
+
+ assert(uses_grids);
+
+ BLI_strncpy(unode->mptex_name,
+ fdata->layers[active].name,
+ sizeof(unode->mptex_name));
+
+ grid_face_map= BLI_pbvh_get_grid_face_map(pbvh);
+
+ for(i = 0; i < unode->totgrid; ++i) {
+ GridToFace *gtf= &grid_face_map[grid_indices[i]];
+ MPtex *pt= ((MPtex*)fdata->layers[active].data) + gtf->face;
+ MPtexSubface *subface= &pt->subfaces[gtf->offset];
+
+ totbytes+= (pt->channels * ptex_data_size(pt->type) *
+ subface->res[0] * subface->res[1]);
+ }
+
+ unode->mptex_data= MEM_mapallocN(sizeof(void*)*unode->totgrid, "PBVHUndoNode.mptex_data");
+ totbytes+= sizeof(void*)*unode->totgrid;
+ }
+
+ /* push undo node onto paint undo list */
+ undo_paint_push_count_alloc(UNDO_PAINT_MESH, totbytes);
+ BLI_addtail(lb, unode);
+
+ BLI_unlock_thread(LOCK_CUSTOM1);
+
+ /* the rest is threaded, hopefully this is the performance critical part */
+
+ if(uses_grids || (flag & (PBVH_UNDO_CO_NO|PBVH_UNDO_PMASK))) {
+ BLI_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ if(flag & PBVH_UNDO_CO_NO) {
+ 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(flag & PBVH_UNDO_PMASK) {
+ if(vd.mask_active)
+ unode->pmask[vd.i]= *vd.mask_active;
+ }
+
+ if(vd.vert_indices)
+ unode->vert_indices[vd.i]= vd.vert_indices[vd.i];
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+
+ if(unode->grid_indices)
+ memcpy(unode->grid_indices, grid_indices, sizeof(int)*totgrid);
+
+ /* copy ptex data (doesn't handle res changes yet) */
+ if(flag & PBVH_UNDO_PTEX) {
+ MPtex *mptex;
+ int i;
+
+ mptex= CustomData_get_layer(fdata, CD_MPTEX);
+
+ for(i = 0; i < unode->totgrid; ++i) {
+ GridToFace *gtf= &grid_face_map[grid_indices[i]];
+ MPtex *pt= &mptex[gtf->face];
+ MPtexSubface *subface= &pt->subfaces[gtf->offset];
+
+ unode->mptex_data[i]= MEM_dupallocN(subface->data);
+ }
+ }
+
+ /* store active shape key */
+ ss= ob->paint->sculpt;
+ if(ss && ss->kb)
+ BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
+ else
+ unode->shapeName[0]= '\0';
+
+ return unode;
+}
+
+void pbvh_undo_push_begin(char *name)
+{
+ undo_paint_push_begin(UNDO_PAINT_MESH, name,
+ pbvh_undo_restore, pbvh_undo_free);
+}
+
+void pbvh_undo_push_end(void)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ PBVHUndoNode *unode;
+
+ if(!lb || !lb->first)
+ return;
+
+ /* remove data that's only used during stroke */
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->no) {
+ MEM_freeN(unode->no);
+ unode->no= NULL;
+ }
+
+ if(unode->layer_disp) {
+ MEM_freeN(unode->layer_disp);
+ unode->layer_disp= NULL;
+ }
+ }
+
+ undo_paint_push_end(UNDO_PAINT_MESH);
+}
+
+int pbvh_undo_node_totvert(PBVHUndoNode *unode)
+{
+ return unode->totvert;
+}
+
+pbvh_undo_f3 pbvh_undo_node_co(PBVHUndoNode *unode)
+{
+ return unode->co;
+}
+
+pbvh_undo_s3 pbvh_undo_node_no(PBVHUndoNode *unode)
+{
+ return unode->no;
+}
+
+float *pbvh_undo_node_layer_disp(PBVHUndoNode *unode)
+{
+ return unode->layer_disp;
+}
+
+void pbvh_undo_node_set_layer_disp(PBVHUndoNode *unode, float *layer_disp)
+{
+ unode->layer_disp = layer_disp;
+}
+
+const char *pbvh_undo_node_mptex_name(PBVHUndoNode *unode)
+{
+ return unode->mptex_name;
+}
+
+void *pbvh_undo_node_mptex_data(PBVHUndoNode *unode, int ndx)
+{
+ return unode->mptex_data[ndx];
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 505e37d95f6..7ddb42fa51a 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -50,6 +50,9 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_dmgrid.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
@@ -64,6 +67,7 @@
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -71,10 +75,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-
-#include "RE_render_ext.h"
-#include "RE_shader_ext.h"
-
#include "GPU_buffers.h"
#include <math.h>
@@ -89,49 +89,13 @@
*
*/
-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);
-}
-
-/* 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 */
-struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
-{
- Mesh *me= (Mesh*)ob->data;
- ModifierData *md, *nmd;
-
- if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
- /* multires can't work without displacement layer */
- return NULL;
- }
-
- for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
- if(md->type == eModifierType_Multires) {
- MultiresModifierData *mmd= (MultiresModifierData*)md;
-
- /* Check if any of the modifiers after multires are active
- * if not it can use the multires struct */
- for(nmd= md->next; nmd; nmd= nmd->next)
- if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
- break;
-
- if(!nmd && mmd->sculptlvl > 0)
- return mmd;
- }
- }
-
- return NULL;
-}
+static int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]);
/* Checks whether full update mode (slower) needs to be used to work with modifiers */
int sculpt_modifiers_active(Scene *scene, Object *ob)
{
ModifierData *md;
- MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
+ MultiresModifierData *mmd= ED_paint_multires_active(scene, ob);
/* check if there are any modifiers after what we are sculpting,
for a multires modifier with a deform modifier in front, we
@@ -142,11 +106,22 @@ int sculpt_modifiers_active(Scene *scene, Object *ob)
else
md= modifiers_getVirtualModifierList(ob);
- /* exception for shape keys because we can edit those */
for(; md; md= md->next) {
- if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
- if(md->type != eModifierType_ShapeKey)
+ if(modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+
+ /* exception for shape keys because we can edit those */
+ if(md->type == eModifierType_ShapeKey)
+ continue;
+
+ /*exception for multires on level zero, it's
+ not caught by the earlier multires check */
+ else if(md->type == eModifierType_Multires &&
+ ((MultiresModifierData*)md)->sculptlvl == 0)
+ continue;
+
+ else
return 1;
+ }
}
return 0;
@@ -169,44 +144,26 @@ typedef enum StrokeFlags {
*/
typedef struct StrokeCache {
/* Invariants */
- float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
- float initial_mouse[2];
/* Variants */
- float radius;
- float radius_squared;
- //float traced_location[3];
- float true_location[3];
- float location[3];
-
float pen_flip;
float invert;
- float pressure;
- float mouse[2];
float bstrength;
- float tex_mouse[2];
/* The rest is temporary storage that isn't saved as a property */
- int first_time; /* Beginning of stroke may do some things special */
-
- bglMats *mats;
-
/* Clean this up! */
+ PaintStroke *stroke;
ViewContext *vc;
Brush *brush;
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
- float special_rotation; /* Texture rotation (radians) for anchored and rake modes */
- int pixel_radius, previous_pixel_radius;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
- int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
- 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
float true_view_normal[3];
float view_normal[3];
@@ -214,8 +171,6 @@ typedef struct StrokeCache {
float last_center[3];
int radial_symmetry_pass;
float symm_rot_mat[4][4];
- float symm_rot_mat_inv[4][4];
- float last_rake[2]; /* Last location of updating rake rotation */
int original;
float vertex_rotation;
@@ -226,177 +181,6 @@ typedef struct StrokeCache {
float plane_trim_squared;
} StrokeCache;
-/* ===== OPENGL =====
- *
- * Simple functions to get data from the GL
- */
-
-/* Convert a point in model coordinates to 2D screen coordinates. */
-static void projectf(bglMats *mats, const float v[3], float p[2])
-{
- double ux, uy, uz;
-
- gluProject(v[0],v[1],v[2], mats->modelview, mats->projection,
- (GLint *)mats->viewport, &ux, &uy, &uz);
- p[0]= ux;
- p[1]= uy;
-}
-
-/*XXX: static void project(bglMats *mats, const float v[3], short p[2])
-{
- float f[2];
- projectf(mats, v, f);
-
- 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)
-{
- PBVH *pbvh= ob->sculpt->pbvh;
- float bb_min[3], bb_max[3], pmat[4][4];
- int i, j, k;
-
- view3d_get_object_project_mat(rv3d, ob, pmat);
-
- if(!pbvh)
- return 0;
-
- BLI_pbvh_redraw_BB(pbvh, 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)
-{
- PBVH *pbvh= ob->sculpt->pbvh;
- BoundBox bb;
- bglMats mats;
- rcti rect;
-
- memset(&bb, 0, sizeof(BoundBox));
-
- 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);
- mul_m4_fl(planes, -1.0f);
-
- /* clear redraw flag from nodes */
- if(pbvh)
- BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
-}
-
-/************************ 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_squared;
- copy_v3_v3(test->location, ss->cache->location);
-}
-
-static int sculpt_brush_test(SculptBrushTest *test, float co[3])
-{
- float distsq = len_squared_v3v3(co, test->location);
-
- if(distsq <= test->radius_squared) {
- test->dist = sqrt(distsq);
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
-{
- float distsq = len_squared_v3v3(co, test->location);
-
- if(distsq <= test->radius_squared) {
- test->dist = distsq;
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
-{
- return len_squared_v3v3(co, test->location) <= test->radius_squared;
-}
-
-static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
-{
- static const float side = 0.70710678118654752440084436210485; // sqrt(.5);
-
- float local_co[3];
-
- mul_v3_m4v3(local_co, local, co);
-
- local_co[0] = fabs(local_co[0]);
- local_co[1] = fabs(local_co[1]);
- local_co[2] = fabs(local_co[2]);
-
- if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
- test->dist = MAX3(local_co[0], local_co[1], local_co[2]) / side;
-
- return 1;
- }
- else {
- return 0;
- }
-}
-
static float frontface(Brush *brush, float sculpt_normal[3], short no[3], float fno[3])
{
if (brush->flag & BRUSH_FRONTFACE) {
@@ -419,30 +203,6 @@ static float frontface(Brush *brush, float sculpt_normal[3], short no[3], float
}
}
-#if 0
-
-static int sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
-{
- if (sculpt_brush_test_fast(test, co)) {
- float t1[3], t2[3], t3[3], dist;
-
- sub_v3_v3v3(t1, location, co);
- sub_v3_v3v3(t2, x2, location);
-
- cross_v3_v3v3(t3, an, t1);
-
- dist = len_v3(t3)/len_v3(t2);
-
- test->dist = dist;
-
- return 1;
- }
-
- return 0;
-}
-
-#endif
-
/* ===== Sculpting =====
*
*/
@@ -490,86 +250,6 @@ static float integrate_overlap(Brush* br)
return max;
}
-/* 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];
-}
-
-float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
-{
- float mirror[3];
- float distsq;
- float mat[4][4];
-
- //flip_coord(mirror, cache->traced_location, symm);
- flip_coord(mirror, cache->true_location, symm);
-
- unit_m4(mat);
- rotate_m4(mat, axis, angle);
-
- mul_m4_v3(mat, mirror);
-
- //distsq = len_squared_v3v3(mirror, cache->traced_location);
- distsq = len_squared_v3v3(mirror, cache->true_location);
-
- if (distsq <= 4*(cache->radius_squared))
- return (2*(cache->radius) - sqrt(distsq)) / (2*(cache->radius));
- else
- return 0;
-}
-
-static float calc_radial_symmetry_feather(Sculpt *sd, StrokeCache *cache, const char symm, const char axis)
-{
- int i;
- float overlap;
-
- overlap = 0;
- for(i = 1; i < sd->radial_symm[axis-'X']; ++i) {
- const float angle = 2*M_PI*i/sd->radial_symm[axis-'X'];
- overlap += calc_overlap(cache, symm, axis, angle);
- }
-
- return overlap;
-}
-
-static float calc_symmetry_feather(Sculpt *sd, StrokeCache* cache)
-{
- if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
- float overlap;
- int symm = cache->symmetry;
- int i;
-
- overlap = 0;
- for (i = 0; i <= symm; i++) {
- if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
-
- overlap += calc_overlap(cache, i, 0, 0);
-
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'X');
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y');
- overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z');
- }
- }
-
- return 1/overlap;
- }
- else {
- return 1;
- }
-}
-
/* Return modified brush strength. Includes the direction of the brush, positive
values pull vertices, negative values push. Uses tablet pressure and a
special multiplier found experimentally to scale the strength factor. */
@@ -581,7 +261,7 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
const float root_alpha = brush_alpha(brush);
float alpha = root_alpha*root_alpha;
float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
- float pressure = brush_use_alpha_pressure(brush) ? cache->pressure : 1;
+ float pressure = brush_use_alpha_pressure(brush) ? paint_stroke_pressure(cache->stroke) : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
float accum = integrate_overlap(brush);
@@ -649,25 +329,6 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
}
}
-float get_tex_pixel(Brush* br, float u, float v)
-{
- TexResult texres;
- float co[3];
- int hasrgb;
-
- co[0] = u;
- co[1] = v;
- co[2] = 0;
-
- memset(&texres, 0, sizeof(TexResult));
- hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 1, &texres);
-
- if (hasrgb & TEX_RGB)
- texres.tin = (0.35*texres.tr + 0.45*texres.tg + 0.2*texres.tb)*texres.ta;
-
- return texres.tin;
-}
-
#if 0
/* Get a pixel from the texcache at (px, py) */
@@ -709,131 +370,10 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
#endif
-/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
+static float tex_strength(SculptSession *ss, Brush *UNUSED(br), float *co,
+ float mask, float dist)
{
- MTex *mtex = &br->mtex;
- float avg= 1;
-
- if(!mtex->tex) {
- avg= 1;
- }
- else if(mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- float jnk;
-
- /* Get strength by feeding the vertex
- location directly into a texture */
- externtex(mtex, point, &avg,
- &jnk, &jnk, &jnk, &jnk, 0);
- }
- else if(ss->texcache) {
- float rotation = -mtex->rot;
- float x, y, point_2d[3];
- float radius;
-
- /* if the active area is being applied for symmetry, flip it
- across the symmetry axis and rotate it back to the orignal
- position in order to project it. This insures that the
- brush texture will be oriented correctly. */
-
- flip_coord(point_2d, point, ss->cache->mirror_symmetry_pass);
-
- if (ss->cache->radial_symmetry_pass)
- mul_m4_v3(ss->cache->symm_rot_mat_inv, point_2d);
-
- projectf(ss->cache->mats, point_2d, point_2d);
-
- /* if fixed mode, keep coordinates relative to mouse */
- if(mtex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
- rotation += ss->cache->special_rotation;
-
- point_2d[0] -= ss->cache->tex_mouse[0];
- point_2d[1] -= ss->cache->tex_mouse[1];
-
- radius = ss->cache->pixel_radius; // use pressure adjusted size for fixed mode
-
- x = point_2d[0];
- y = point_2d[1];
- }
- else /* else (mtex->brush_map_mode == MTEX_MAP_MODE_TILED),
- leave the coordinates relative to the screen */
- {
- radius = brush_size(br); // use unadjusted size for tiled mode
-
- x = point_2d[0] - ss->cache->vc->ar->winrct.xmin;
- y = point_2d[1] - ss->cache->vc->ar->winrct.ymin;
- }
-
- x /= ss->cache->vc->ar->winx;
- y /= ss->cache->vc->ar->winy;
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- x -= 0.5f;
- y -= 0.5f;
- }
-
- x *= ss->cache->vc->ar->winx / radius;
- y *= ss->cache->vc->ar->winy / radius;
-
- /* it is probably worth optimizing for those cases where
- the texture is not rotated by skipping the calls to
- atan2, sqrtf, sin, and cos. */
- if (rotation > 0.001 || rotation < -0.001) {
- const float angle = atan2(y, x) + rotation;
- const float flen = sqrtf(x*x + y*y);
-
- x = flen * cos(angle);
- y = flen * sin(angle);
- }
-
- x *= br->mtex.size[0];
- y *= br->mtex.size[1];
-
- x += br->mtex.ofs[0];
- y += br->mtex.ofs[1];
-
- avg = get_tex_pixel(br, x, y);
- }
-
- avg += br->texture_sample_bias;
-
- avg *= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
-
- return avg;
-}
-
-typedef struct {
- Sculpt *sd;
- SculptSession *ss;
- float radius_squared;
- int original;
-} 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;
-
- if(data->original)
- BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
- else
- 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 dot_v3v3(t, t) < data->radius_squared;
+ return paint_stroke_combined_strength(ss->cache->stroke, dist, co, mask);
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
@@ -842,7 +382,7 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float va
int i;
for(i=0; i<3; ++i) {
- if(sd->flags & (SCULPT_LOCK_X << i))
+ if(sd->paint.flags & (PAINT_LOCK_X << i))
continue;
if((ss->cache->flag & (CLIP_X << i)) && (fabs(co[i]) <= ss->cache->clip_tolerance[i]))
@@ -861,8 +401,9 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], floa
}
}
-static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode)
+static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
int n;
float out_flip[3] = {0.0f, 0.0f, 0.0f};
@@ -871,31 +412,31 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNod
zero_v3(an);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
+ PaintStrokeTest test;
+ PBVHUndoNode *unode;
float private_an[3] = {0.0f, 0.0f, 0.0f};
float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
- unode = sculpt_undo_push_node(ss, nodes[n]);
- sculpt_brush_test_init(ss, &test);
+ unode = pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ paint_stroke_test_init(&test, ss->cache->stroke);
if(ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test_fast(&test, pbvh_undo_node_co(unode)[vd.i])) {
float fno[3];
- normal_short_to_float_v3(fno, unode->no[vd.i]);
+ normal_short_to_float_v3(fno, pbvh_undo_node_no(unode)[vd.i]);
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
}
BLI_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test_fast(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test_fast(&test, vd.co)) {
if(vd.no) {
float fno[3];
@@ -925,13 +466,14 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNod
/* This initializes the faces to be moved for this sculpt for draw/layer/flatten; then it
finds average normal for all active vertices - note that this is called once for each mirroring direction */
-static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode)
+static void calc_sculpt_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
if (ss->cache->mirror_symmetry_pass == 0 &&
ss->cache->radial_symmetry_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
+ (paint_stroke_first_dab(ss->cache->stroke) || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
@@ -957,7 +499,7 @@ static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHN
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ss, an, nodes, totnode);
+ calc_area_normal(sd, ob, an, nodes, totnode);
default:
break;
@@ -967,7 +509,7 @@ static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHN
}
else {
copy_v3_v3(an, ss->cache->last_area_normal);
- flip_coord(an, an, ss->cache->mirror_symmetry_pass);
+ paint_flip_coord(an, an, ss->cache->mirror_symmetry_pass);
mul_m4_v3(ss->cache->symm_rot_mat, an);
}
}
@@ -975,8 +517,9 @@ static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHN
/* For the smooth brush, uses the neighboring vertices around vert to calculate
a smoothed location for vert. Skips corner vertices (used by only one
polygon.) */
-static void neighbor_average(SculptSession *ss, float avg[3], const unsigned vert)
+static void neighbor_average(Object *ob, float avg[3], const unsigned vert)
{
+ SculptSession *ss = ob->paint->sculpt;
int i, skip= -1, total=0;
IndexNode *node= ss->fmap[vert].first;
char ncount= BLI_countlist(&ss->fmap[vert]);
@@ -1016,22 +559,23 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
copy_v3_v3(avg, ss->mvert[vert].co);
}
-static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
+static void do_mesh_smooth_brush(Sculpt *sd, Object *ob, PBVHNode *node, float bstrength)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
CLAMP(bstrength, 0.0f, 1.0f);
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float avg[3], val[3];
- neighbor_average(ss, avg, vd.vert_indices[vd.i]);
+ neighbor_average(ob, avg, vd.vert_indices[vd.i]);
sub_v3_v3v3(val, avg, vd.co);
mul_v3_fl(val, fade);
@@ -1046,22 +590,24 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
BLI_pbvh_vertex_iter_end;
}
-static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
+static void do_multires_smooth_brush(Sculpt *sd, Object *ob, PBVHNode *node, float bstrength)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
- SculptBrushTest test;
+ PaintStrokeTest test;
DMGridData **griddata, *data;
DMGridAdjacency *gridadj, *adj;
+ GridKey *gridkey;
float (*tmpgrid)[3], (*tmprow)[3];
int v1, v2, v3, v4;
int *grid_indices, totgrid, gridsize, i, x, y;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
CLAMP(bstrength, 0.0f, 1.0f);
- BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata, &gridadj);
+ BLI_pbvh_node_get_grids(ob->paint->pbvh, node, &grid_indices, &totgrid,
+ NULL, &gridsize, &griddata, &gridadj, &gridkey);
#pragma omp critical
{
@@ -1079,7 +625,8 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
float tmp[3];
v1 = y*gridsize;
- add_v3_v3v3(tmprow[0], data[v1].co, data[v1+gridsize].co);
+ add_v3_v3v3(tmprow[0], GRIDELEM_CO_AT(data, v1, gridkey),
+ GRIDELEM_CO_AT(data, v1+gridsize, gridkey));
for (x= 0; x < gridsize-1; x++) {
v1 = x + y*gridsize;
@@ -1087,7 +634,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
v3 = v1 + gridsize;
v4 = v3 + 1;
- add_v3_v3v3(tmprow[x+1], data[v2].co, data[v4].co);
+ add_v3_v3v3(tmprow[x+1], GRIDELEM_CO_AT(data, v2, gridkey), GRIDELEM_CO_AT(data, v4, gridkey));
add_v3_v3v3(tmp, tmprow[x+1], tmprow[x]);
add_v3_v3(tmpgrid[v1], tmp);
@@ -1117,11 +664,13 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
continue;
index = x + y*gridsize;
- co= data[index].co;
- fno= data[index].no;
+ co= GRIDELEM_CO_AT(data, index, gridkey);
+ fno= GRIDELEM_NO_AT(data, index, gridkey);
- if(sculpt_brush_test(&test, co)) {
- const float fade = bstrength*tex_strength(ss, brush, co, test.dist)*frontface(brush, ss->cache->view_normal, NULL, fno);
+ if(paint_stroke_test(&test, co)) {
+ float mask = (gridkey->mask ?
+ *GRIDELEM_MASK_AT(data, x + y*gridsize, gridkey) : 0);
+ const float fade = bstrength*tex_strength(ss, brush, co, mask, test.dist)*frontface(brush, ss->cache->view_normal, NULL, fno);
float *avg, val[3];
float n;
@@ -1155,8 +704,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
}
}
-static void smooth(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float bstrength)
+static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength)
{
+ SculptSession *ss = ob->paint->sculpt;
const int max_iterations = 4;
const float fract = 1.0f/max_iterations;
int iteration, n, count;
@@ -1168,55 +718,57 @@ static void smooth(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode,
last = max_iterations*(bstrength - count*fract);
for(iteration = 0; iteration <= count; ++iteration) {
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
if(ss->multires) {
- do_multires_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
+ do_multires_smooth_brush(sd, ob, nodes[n], iteration != count ? 1.0f : last);
}
else if(ss->fmap)
- do_mesh_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
+ do_mesh_smooth_brush(sd, ob, nodes[n], iteration != count ? 1.0f : last);
}
if(ss->multires)
- multires_stitch_grids(ss->ob);
+ multires_stitch_grids(ob);
}
}
-static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- smooth(sd, ss, nodes, totnode, ss->cache->bstrength);
+ SculptSession *ss = ob->paint->sculpt;
+ smooth(sd, ob, nodes, totnode, ss->cache->bstrength);
}
-static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float offset[3], area_normal[3];
float bstrength= ss->cache->bstrength;
int n;
- calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
+ calc_sculpt_normal(sd, ob, area_normal, nodes, totnode);
/* offset with as much as possible factored in already */
- mul_v3_v3fl(offset, area_normal, ss->cache->radius);
+ mul_v3_v3fl(offset, area_normal, paint_stroke_radius(ss->cache->stroke));
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test(&test, vd.co)) {
- //if(sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, area_normal)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (paint_stroke_test(&test, vd.co)) {
+ //if(paint_stroke_test_cyl(&test, vd.co, ss->cache->location, area_normal)) {
/* offset vertex */
- float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ float fade = tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -1228,18 +780,19 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
}
}
-static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float offset[3], area_normal[3];
float bstrength= ss->cache->bstrength;
float flippedbstrength, crease_correction;
int n;
- calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
+ calc_sculpt_normal(sd, ob, area_normal, nodes, totnode);
/* offset with as much as possible factored in already */
- mul_v3_v3fl(offset, area_normal, ss->cache->radius);
+ mul_v3_v3fl(offset, area_normal, paint_stroke_radius(ss->cache->stroke));
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
@@ -1256,20 +809,20 @@ static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
if(brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
/* threaded loop over nodes */
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
/* offset vertex */
- const float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ const float fade = tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
float val1[3];
float val2[3];
@@ -1291,25 +844,26 @@ static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
int n;
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
+ float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float val[3];
sub_v3_v3v3(val, test.location, vd.co);
@@ -1323,8 +877,9 @@ static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush= paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
float grab_delta[3], an[3];
@@ -1332,7 +887,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
float len;
if (brush->normal_weight > 0)
- calc_sculpt_normal(sd, ss, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode);
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
@@ -1344,26 +899,26 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
add_v3_v3(grab_delta, an);
}
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode* unode;
- SculptBrushTest test;
+ PBVHUndoNode* unode;
+ PaintStrokeTest test;
float (*origco)[3];
short (*origno)[3];
float (*proxy)[3];
- unode= sculpt_undo_push_node(ss, nodes[n]);
- origco= unode->co;
- origno= unode->no;
+ unode= pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ origco= pbvh_undo_node_co(unode);
+ origno= pbvh_undo_node_no(unode);
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, origco[vd.i])) {
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], vd.mask_combined, test.dist)*frontface(brush, an, origno[vd.i], NULL);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1375,8 +930,9 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
}
}
-static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float grab_delta[3];
@@ -1386,24 +942,24 @@ static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- calc_sculpt_normal(sd, ss, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode);
cross_v3_v3v3(tmp, an, grab_delta);
cross_v3_v3v3(cono, tmp, an);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1415,8 +971,9 @@ static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float grab_delta[3], an[3];
@@ -1424,7 +981,7 @@ static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
float len;
if (brush->normal_weight > 0)
- calc_sculpt_normal(sd, ss, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode);
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
@@ -1439,19 +996,19 @@ static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
add_v3_v3(grab_delta, an);
}
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1463,8 +1020,9 @@ static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
}
}
-static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float grab_delta[3];
@@ -1474,31 +1032,31 @@ static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- calc_sculpt_normal(sd, ss, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode);
cross_v3_v3v3(tmp, an, grab_delta);
cross_v3_v3v3(cono, tmp, an);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode* unode;
- SculptBrushTest test;
+ PBVHUndoNode* unode;
+ PaintStrokeTest test;
float (*origco)[3];
short (*origno)[3];
float (*proxy)[3];
- unode= sculpt_undo_push_node(ss, nodes[n]);
- origco= unode->co;
- origno= unode->no;
+ unode= pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ origco= pbvh_undo_node_co(unode);
+ origno= pbvh_undo_node_no(unode);
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, origco[vd.i])) {
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], vd.mask_combined, test.dist)*frontface(brush, an, origno[vd.i], NULL);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1510,8 +1068,9 @@ static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush= paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
float an[3];
@@ -1520,30 +1079,30 @@ static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
- calc_sculpt_normal(sd, ss, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode);
axis_angle_to_mat3(m, an, angle);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode* unode;
- SculptBrushTest test;
+ PBVHUndoNode* unode;
+ PaintStrokeTest test;
float (*origco)[3];
short (*origno)[3];
float (*proxy)[3];
- unode= sculpt_undo_push_node(ss, nodes[n]);
- origco= unode->co;
- origno= unode->no;
+ unode= pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ origco= pbvh_undo_node_co(unode);
+ origno= pbvh_undo_node_no(unode);
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, origco[vd.i])) {
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], vd.mask_combined, test.dist)*frontface(brush, an, origno[vd.i], NULL);
mul_v3_m3v3(proxy[vd.i], m, origco[vd.i]);
sub_v3_v3(proxy[vd.i], origco[vd.i]);
@@ -1557,46 +1116,47 @@ static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
float area_normal[3], offset[3];
- float lim= ss->cache->radius / 4;
+ float lim= paint_stroke_radius(ss->cache->stroke) / 4;
int n;
if(bstrength < 0)
lim = -lim;
- calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
+ calc_sculpt_normal(sd, ob, area_normal, nodes, totnode);
mul_v3_v3v3(offset, ss->cache->scale, area_normal);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
+ PaintStrokeTest test;
+ PBVHUndoNode *unode;
float (*origco)[3], *layer_disp;
//float (*proxy)[3]; // XXX layer brush needs conversion to proxy but its more complicated
- //proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ //proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- unode= sculpt_undo_push_node(ss, nodes[n]);
- origco=unode->co;
- if(!unode->layer_disp)
- {
- #pragma omp critical
- unode->layer_disp= MEM_callocN(sizeof(float)*unode->totvert, "layer disp");
- }
+ unode= pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ origco= pbvh_undo_node_co(unode);
+ if(!pbvh_undo_node_layer_disp(unode)) {
+ #pragma omp critical
+ pbvh_undo_node_set_layer_disp(unode, MEM_callocN(sizeof(float)*
+ pbvh_undo_node_totvert(unode), "layer disp"));
+ }
- layer_disp= unode->layer_disp;
+ layer_disp= pbvh_undo_node_layer_disp(unode);
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*ss->cache->radius*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
+ const float fade = bstrength*paint_stroke_radius(ss->cache->stroke)*tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
float *disp= &layer_disp[vd.i];
float val[3];
@@ -1628,31 +1188,32 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
int n;
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test(&test, vd.co)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float val[3];
if(vd.fno) copy_v3_v3(val, vd.fno);
else normal_short_to_float_v3(val, vd.no);
- mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_fl(val, fade * paint_stroke_radius(ss->cache->stroke));
mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
if(vd.mvert)
@@ -1663,8 +1224,9 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
}
}
-static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float fc[3])
+static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float fc[3])
{
+ SculptSession *ss = ob->paint->sculpt;
int n;
float count = 0;
@@ -1673,20 +1235,20 @@ static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
zero_v3(fc);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
+ PaintStrokeTest test;
+ PBVHUndoNode *unode;
float private_fc[3] = {0.0f, 0.0f, 0.0f};
int private_count = 0;
- unode = sculpt_undo_push_node(ss, nodes[n]);
- sculpt_brush_test_init(ss, &test);
+ unode = pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ paint_stroke_test_init(&test, ss->cache->stroke);
if(ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test_fast(&test, pbvh_undo_node_co(unode)[vd.i])) {
add_v3_v3(private_fc, vd.co);
private_count++;
}
@@ -1694,8 +1256,8 @@ static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
BLI_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test_fast(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test_fast(&test, vd.co)) {
add_v3_v3(private_fc, vd.co);
private_count++;
}
@@ -1715,8 +1277,9 @@ static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
/* this calculates flatten center and area normal together,
amortizing the memory bandwidth and loop overhead to calculate both at the same time */
-static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
{
+ SculptSession *ss = ob->paint->sculpt;
int n;
// an
@@ -1733,26 +1296,26 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, P
// fc
zero_v3(fc);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
+ PaintStrokeTest test;
+ PBVHUndoNode *unode;
float private_an[3] = {0.0f, 0.0f, 0.0f};
float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
float private_fc[3] = {0.0f, 0.0f, 0.0f};
int private_count = 0;
- unode = sculpt_undo_push_node(ss, nodes[n]);
- sculpt_brush_test_init(ss, &test);
+ unode = pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ paint_stroke_test_init(&test, ss->cache->stroke);
if(ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test_fast(&test, pbvh_undo_node_co(unode)[vd.i])) {
// an
float fno[3];
- normal_short_to_float_v3(fno, unode->no[vd.i]);
+ normal_short_to_float_v3(fno, pbvh_undo_node_no(unode)[vd.i]);
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
// fc
@@ -1763,8 +1326,8 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, P
BLI_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test_fast(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(paint_stroke_test_fast(&test, vd.co)) {
// an
if(vd.no) {
float fno[3];
@@ -1811,13 +1374,14 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, P
}
}
-static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
if (ss->cache->mirror_symmetry_pass == 0 &&
ss->cache->radial_symmetry_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
+ (paint_stroke_first_dab(ss->cache->stroke) || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
@@ -1843,7 +1407,7 @@ static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, i
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_flatten_center(sd, ss, nodes, totnode, an, fc);
+ calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc);
default:
break;
@@ -1852,7 +1416,7 @@ static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, i
// fc
/* flatten center has not been calculated yet if we are not using the area normal */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
- calc_flatten_center(sd, ss, nodes, totnode, fc);
+ calc_flatten_center(sd, ob, nodes, totnode, fc);
// an
copy_v3_v3(ss->cache->last_area_normal, an);
@@ -1868,10 +1432,10 @@ static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, i
copy_v3_v3(fc, ss->cache->last_center);
// an
- flip_coord(an, an, ss->cache->mirror_symmetry_pass);
+ paint_flip_coord(an, an, ss->cache->mirror_symmetry_pass);
// fc
- flip_coord(fc, fc, ss->cache->mirror_symmetry_pass);
+ paint_flip_coord(fc, fc, ss->cache->mirror_symmetry_pass);
// an
mul_m4_v3(ss->cache->symm_rot_mat, an);
@@ -1891,7 +1455,8 @@ static void point_plane_project(float intr[3], float co[3], float plane_normal[3
static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
{
- return !(brush->flag & BRUSH_PLANE_TRIM) || (dot_v3v3(val, val) <= cache->radius_squared*cache->plane_trim_squared);
+ return !(brush->flag & BRUSH_PLANE_TRIM) ||
+ (dot_v3v3(val, val) <= paint_stroke_radius_squared(cache->stroke)*cache->plane_trim_squared);
}
static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
@@ -1922,18 +1487,19 @@ static float get_offset(Sculpt *sd, SculptSession *ss)
float rv = brush->plane_offset;
if (brush->flag & BRUSH_OFFSET_PRESSURE) {
- rv *= ss->cache->pressure;
+ rv *= paint_stroke_pressure(ss->cache->stroke);
}
return rv;
}
-static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
- const float radius = ss->cache->radius;
+ const float radius = paint_stroke_radius(ss->cache->stroke);
float an[3];
float fc[3];
@@ -1946,7 +1512,7 @@ static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
float temp[3];
- calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
displace = radius*offset;
@@ -1954,18 +1520,18 @@ static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (paint_stroke_test_sq(&test, vd.co)) {
float intr[3];
float val[3];
@@ -1974,7 +1540,7 @@ static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -1987,12 +1553,13 @@ static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
}
}
-static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
- float radius = ss->cache->radius;
+ float radius = paint_stroke_radius(ss->cache->stroke);
float offset = get_offset(sd, ss);
float displace;
@@ -2007,7 +1574,7 @@ static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
int flip;
- calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
flip = bstrength < 0;
@@ -2024,20 +1591,20 @@ static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
//add_v3_v3v3(p, ss->cache->location, an);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (paint_stroke_test_sq(&test, vd.co)) {
if (plane_point_side_flip(vd.co, an, fc, flip)) {
- //if (sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, p)) {
+ //if (paint_stroke_test_cyl(&test, vd.co, ss->cache->location, p)) {
float intr[3];
float val[3];
@@ -2046,7 +1613,7 @@ static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2060,12 +1627,13 @@ static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
}
}
-static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_clay_tubes_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
- float radius = ss->cache->radius;
+ float radius = paint_stroke_radius(ss->cache->stroke);
float offset = get_offset(sd, ss);
float displace;
@@ -2083,15 +1651,15 @@ static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
int flip;
- calc_sculpt_plane(sd, ss, nodes, totnode, sn, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
- calc_area_normal(sd, ss, an, nodes, totnode);
+ calc_area_normal(sd, ob, an, nodes, totnode);
else
copy_v3_v3(an, sn);
- if (ss->cache->first_time)
- return; // delay the first daub because grab delta is not setup
+ if(paint_stroke_first_dab(ss->cache->stroke))
+ return; // delay the first dab because grab delta is not setup
flip = bstrength < 0;
@@ -2109,24 +1677,25 @@ static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry); mat[0][3] = 0;
cross_v3_v3v3(mat[1], an, mat[0]); mat[1][3] = 0;
copy_v3_v3(mat[2], an); mat[2][3] = 0;
- copy_v3_v3(mat[3], ss->cache->location); mat[3][3] = 1;
+ paint_stroke_symmetry_location(ss->cache->stroke, mat[3]);
+ mat[3][3] = 1;
normalize_m4(mat);
- scale_m4_fl(scale, ss->cache->radius);
+ scale_m4_fl(scale, paint_stroke_radius(ss->cache->stroke));
mul_m4_m4m4(tmat, scale, mat);
invert_m4_m4(mat, tmat);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_cube(&test, vd.co, mat)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (paint_stroke_test_cube(&test, vd.co, mat)) {
if (plane_point_side_flip(vd.co, sn, fc, flip)) {
float intr[3];
float val[3];
@@ -2136,7 +1705,7 @@ static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, ss->cache->radius*test.dist)*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, paint_stroke_radius(ss->cache->stroke)*test.dist)*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2150,12 +1719,13 @@ static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes,
}
}
-static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
- const float radius = ss->cache->radius;
+ const float radius = paint_stroke_radius(ss->cache->stroke);
float an[3];
float fc[3];
@@ -2167,7 +1737,7 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
float temp[3];
- calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
displace = radius*offset;
@@ -2175,18 +1745,18 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (paint_stroke_test_sq(&test, vd.co)) {
if (plane_point_side(vd.co, an, fc)) {
float intr[3];
float val[3];
@@ -2196,7 +1766,7 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2210,12 +1780,13 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t
}
}
-static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
- const float radius = ss->cache->radius;
+ const float radius = paint_stroke_radius(ss->cache->stroke);
float an[3];
float fc[3];
@@ -2227,7 +1798,7 @@ static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
float temp[3];
- calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
displace = -radius*offset;
@@ -2235,18 +1806,18 @@ static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptBrushTest test;
+ PaintStrokeTest test;
float (*proxy)[3];
- proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy= BLI_pbvh_node_add_proxy(ob->paint->pbvh, nodes[n])->co;
- sculpt_brush_test_init(ss, &test);
+ paint_stroke_test_init(&test, ss->cache->stroke);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (paint_stroke_test_sq(&test, vd.co)) {
if (!plane_point_side(vd.co, an, fc)) {
float intr[3];
float val[3];
@@ -2256,7 +1827,7 @@ static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, vd.mask_combined, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2322,139 +1893,155 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
}
/* copy the modified vertices from bvh to the active key */
-static void sculpt_update_keyblock(SculptSession *ss)
+static void sculpt_update_keyblock(Object *ob)
{
- float (*vertCos)[3]= BLI_pbvh_get_vertCos(ss->pbvh);
+ SculptSession *ss = ob->paint->sculpt;
+ float (*vertCos)[3]= BLI_pbvh_get_vertCos(ob->paint->pbvh);
if (vertCos) {
- sculpt_vertcos_to_key(ss->ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
MEM_freeN(vertCos);
}
}
-static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush)
+static void sculpt_stroke_brush_action(bContext *C, PaintStroke *stroke)
{
- SculptSearchSphereData data;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->paint->sculpt;
+ Brush *brush = paint_brush(&sd->paint);
+ PBVHSearchSphereData data;
PBVHNode **nodes = NULL;
+ float location[3];
int n, totnode;
/* Build a list of all nodes that are potentially within the brush's area of influence */
- data.ss = ss;
- data.sd = sd;
- data.radius_squared = ss->cache->radius_squared;
+ paint_stroke_symmetry_location(ss->cache->stroke, location);
+ data.center = location;
+ data.radius_squared = paint_stroke_radius_squared(ss->cache->stroke);
data.original = ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER);
- BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ BLI_pbvh_search_gather(ob->paint->pbvh, BLI_pbvh_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
if (totnode) {
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
- for (n= 0; n < totnode; n++) {
- sculpt_undo_push_node(ss, nodes[n]);
- BLI_pbvh_node_mark_update(nodes[n]);
- }
-
/* Apply one type of brush action */
- switch(brush->sculpt_tool){
- case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_SMOOTH:
- do_smooth_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_CREASE:
- do_crease_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_BLOB:
- do_crease_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_ROTATE:
- do_rotate_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_SNAKE_HOOK:
- do_snake_hook_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_NUDGE:
- do_nudge_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_THUMB:
- do_thumb_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_FLATTEN:
- do_flatten_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_CLAY:
- do_clay_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_CLAY_TUBES:
- do_clay_tubes_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_FILL:
- do_fill_brush(sd, ss, nodes, totnode);
- break;
- case SCULPT_TOOL_SCRAPE:
- do_scrape_brush(sd, ss, nodes, totnode);
- break;
+ if(brush->flag & BRUSH_MASK)
+ paintmask_brush_apply(&sd->paint, stroke, nodes,
+ totnode,
+ ss->cache->bstrength);
+ else {
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ BLI_pbvh_node_mark_update(nodes[n]);
+ }
+
+ switch(brush->sculpt_tool){
+ case SCULPT_TOOL_DRAW:
+ do_draw_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SMOOTH:
+ do_smooth_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CREASE:
+ do_crease_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_BLOB:
+ do_crease_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_PINCH:
+ do_pinch_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_INFLATE:
+ do_inflate_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_GRAB:
+ do_grab_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_ROTATE:
+ do_rotate_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SNAKE_HOOK:
+ do_snake_hook_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_NUDGE:
+ do_nudge_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_THUMB:
+ do_thumb_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_LAYER:
+ do_layer_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_FLATTEN:
+ do_flatten_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CLAY:
+ do_clay_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CLAY_TUBES:
+ do_clay_tubes_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_FILL:
+ do_fill_brush(sd, ob, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SCRAPE:
+ do_scrape_brush(sd, ob, nodes, totnode);
+ break;
+ }
}
if (brush->sculpt_tool != SCULPT_TOOL_SMOOTH && brush->autosmooth_factor > 0) {
if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
- smooth(sd, ss, nodes, totnode, brush->autosmooth_factor*(1-ss->cache->pressure));
+ smooth(sd, ob, nodes, totnode, brush->autosmooth_factor *
+ (1 - paint_stroke_pressure(ss->cache->stroke)));
}
else {
- smooth(sd, ss, nodes, totnode, brush->autosmooth_factor);
+ smooth(sd, ob, nodes, totnode, brush->autosmooth_factor);
}
}
/* copy the modified vertices from mesh to the active key */
if(ss->kb)
- mesh_to_key(ss->ob->data, ss->kb);
+ mesh_to_key(ob->data, ss->kb);
/* optimization: we could avoid copying new coords to keyblock at each */
/* stroke step if there are no modifiers due to pbvh is used for displaying */
/* so to increase speed we'll copy new coords to keyblock when stroke is done */
- if(ss->kb && ss->modifiers_active) sculpt_update_keyblock(ss);
+ if(ss->kb && ss->modifiers_active) sculpt_update_keyblock(ob);
MEM_freeN(nodes);
}
}
-static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
+static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->paint->sculpt;
Brush *brush= paint_brush(&sd->paint);
PBVHNode** nodes;
int totnode;
int n;
- BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ BLI_pbvh_gather_proxies(ob->paint->pbvh, &nodes, &totnode);
switch (brush->sculpt_tool) {
case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_ROTATE:
case SCULPT_TOOL_THUMB:
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for (n= 0; n < totnode; n++) {
PBVHVertexIter vd;
PBVHProxyNode* proxies;
+ PBVHUndoNode *unode;
int proxy_count;
float (*origco)[3];
- origco= sculpt_undo_push_node(ss, nodes[n])->co;
+ unode= pbvh_undo_push_node(nodes[n], PBVH_UNDO_CO_NO, ob, NULL);
+ origco= pbvh_undo_node_co(unode);
BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
float val[3];
int p;
@@ -2484,7 +2071,7 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
case SCULPT_TOOL_PINCH:
case SCULPT_TOOL_SCRAPE:
case SCULPT_TOOL_SNAKE_HOOK:
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for (n= 0; n < totnode; n++) {
PBVHVertexIter vd;
PBVHProxyNode* proxies;
@@ -2492,7 +2079,7 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
float val[3];
int p;
@@ -2521,99 +2108,6 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
MEM_freeN(nodes);
}
-//static int max_overlap_count(Sculpt *sd)
-//{
-// int count[3];
-// int i, j;
-//
-// for (i= 0; i < 3; i++) {
-// count[i] = sd->radial_symm[i];
-//
-// for (j= 0; j < 3; j++) {
-// if (i != j && sd->flags & (SCULPT_SYMM_X<<i))
-// count[i] *= 2;
-// }
-// }
-//
-// return MAX3(count[0], count[1], count[2]);
-//}
-
-/* Flip all the editdata across the axis/axes specified by symm. Used to
- calculate multiple modifications to the mesh when symmetry is enabled. */
-static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, const char axis, const float angle, const float UNUSED(feather))
-{
- (void)sd; /* unused */
-
- flip_coord(cache->location, cache->true_location, symm);
- flip_coord(cache->grab_delta_symmetry, cache->grab_delta, symm);
- flip_coord(cache->view_normal, cache->true_view_normal, symm);
-
- // XXX This reduces the length of the grab delta if it approaches the line of symmetry
- // XXX However, a different approach appears to be needed
- //if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
- // float frac = 1.0f/max_overlap_count(sd);
- // float reduce = (feather-frac)/(1-frac);
-
- // printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
-
- // if (frac < 1)
- // mul_v3_fl(cache->grab_delta_symmetry, reduce);
- //}
-
- unit_m4(cache->symm_rot_mat);
- unit_m4(cache->symm_rot_mat_inv);
- rotate_m4(cache->symm_rot_mat, axis, angle);
- rotate_m4(cache->symm_rot_mat_inv, axis, -angle);
-
- mul_m4_v3(cache->symm_rot_mat, cache->location);
- mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
-}
-
-static void do_radial_symmetry(Sculpt *sd, SculptSession *ss, Brush *brush, const char symm, const int axis, const float feather)
-{
- int i;
-
- for(i = 1; i < sd->radial_symm[axis-'X']; ++i) {
- const float angle = 2*M_PI*i/sd->radial_symm[axis-'X'];
- ss->cache->radial_symmetry_pass= i;
- calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
- do_brush_action(sd, ss, brush);
- }
-}
-
-static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
-{
- Brush *brush = paint_brush(&sd->paint);
- StrokeCache *cache = ss->cache;
- const char symm = sd->flags & 7;
- int i;
-
- float feather = calc_symmetry_feather(sd, ss->cache);
-
- cache->bstrength= brush_strength(sd, cache, feather);
-
- cache->symmetry= symm;
-
- /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
- for(i = 0; i <= symm; ++i) {
- if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
- cache->mirror_symmetry_pass= i;
- cache->radial_symmetry_pass= 0;
-
- calc_brushdata_symm(sd, cache, i, 0, 0, feather);
- do_brush_action(sd, ss, brush);
-
- do_radial_symmetry(sd, ss, brush, i, 'X', feather);
- do_radial_symmetry(sd, ss, brush, i, 'Y', feather);
- do_radial_symmetry(sd, ss, brush, i, 'Z', feather);
- }
- }
-
- sculpt_combine_proxies(sd, ss);
-
- cache->first_time= 0;
-}
-
static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
{
Brush *brush = paint_brush(&sd->paint);
@@ -2635,10 +2129,10 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- SculptSession *ss = ob->sculpt;
- MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
+ SculptSession *ss = ob->paint->sculpt;
+ MultiresModifierData *mmd= ED_paint_multires_active(scene, ob);
- ss->ob= ob;
+ ob= ob;
ss->modifiers_active= sculpt_modifiers_active(scene, ob);
@@ -2663,16 +2157,16 @@ void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
ss->multires = NULL;
}
- ss->pbvh = dm->getPBVH(ob, dm);
+ ob->paint->pbvh = dm->getPBVH(ob, dm);
ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(ob, dm): NULL;
/* if pbvh is deformed, key block is already applied to it */
- if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) {
+ if (ss->kb && !BLI_pbvh_isDeformed(ob->paint->pbvh)) {
float (*vertCos)[3]= key_to_vertcos(ob, ss->kb);
if (vertCos) {
/* apply shape keys coordinates to PBVH */
- BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BLI_pbvh_apply_vertCos(ob->paint->pbvh, vertCos);
MEM_freeN(vertCos);
}
}
@@ -2791,27 +2285,10 @@ 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(Object *ob, ViewContext *vc, float center[3], float offset)
-{
- float delta[3], scale, loc[3];
-
- mul_v3_m4v3(loc, ob->obmat, center);
-
- initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
- window_to_3d_delta(vc->ar, delta, offset, 0);
-
- scale= fabsf(mat4_to_scale(ob->obmat));
- scale= (scale == 0.0f)? 1.0f: scale;
-
- return len_v3(delta)/scale;
-}
-
static void sculpt_cache_free(StrokeCache *cache)
{
if(cache->face_norms)
MEM_freeN(cache->face_norms);
- if(cache->mats)
- MEM_freeN(cache->mats);
MEM_freeN(cache);
}
@@ -2827,6 +2304,7 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
int mode;
ss->cache = cache;
+ ss->cache->stroke = op->customdata;
/* Set scaling adjustment */
ss->cache->scale[0] = 1.0f / ob->size[0];
@@ -2852,16 +2330,6 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
}
}
- /* Initial mouse location */
- if (event) {
- ss->cache->initial_mouse[0] = event->x;
- ss->cache->initial_mouse[1] = event->y;
- }
- else {
- ss->cache->initial_mouse[0] = 0;
- ss->cache->initial_mouse[1] = 0;
- }
-
mode = RNA_int_get(op->ptr, "mode");
cache->invert = mode == WM_BRUSHSTROKE_INVERT;
cache->alt_smooth = mode == WM_BRUSHSTROKE_SMOOTH;
@@ -2880,18 +2348,12 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
}
}
- 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->vc = vc;
cache->brush = brush;
- cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
- view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
-
viewvector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
/* Initialize layer brush displacements and persistent coords */
if(brush->sculpt_tool == SCULPT_TOOL_LAYER) {
@@ -2922,17 +2384,15 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
if(!(brush->flag & BRUSH_ACCUMULATE))
cache->original = 1;
- cache->special_rotation = (brush->flag & BRUSH_RAKE) ? sd->last_angle : 0;
//cache->last_rake[0] = sd->last_x;
//cache->last_rake[1] = sd->last_y;
- cache->first_time= 1;
-
cache->vertex_rotation= 0;
}
-static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brush)
+static void sculpt_update_brush_delta(Object *ob, Brush *brush)
{
+ SculptSession *ss = ob->paint->sculpt;
StrokeCache *cache = ss->cache;
int tool = brush->sculpt_tool;
@@ -2941,13 +2401,17 @@ static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brus
SCULPT_TOOL_CLAY_TUBES, SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_THUMB)) {
float grab_location[3], imat[4][4], delta[3];
+ float mouse[2], location[3];
+
+ paint_stroke_mouse_location(cache->stroke, mouse);
+ paint_stroke_location(cache->stroke, location);
- if(cache->first_time) {
+ if(paint_stroke_first_dab(cache->stroke)) {
copy_v3_v3(cache->orig_grab_location,
- cache->true_location);
+ location);
}
else if(tool == SCULPT_TOOL_SNAKE_HOOK)
- add_v3_v3(cache->true_location, cache->grab_delta);
+ add_v3_v3(location, cache->grab_delta);
/* compute 3d coordinate at same z from original location + mouse */
initgrabz(cache->vc->rv3d,
@@ -2956,27 +2420,27 @@ static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brus
cache->orig_grab_location[2]);
window_to_3d_delta(cache->vc->ar, grab_location,
- cache->mouse[0], cache->mouse[1]);
+ mouse[0], mouse[1]);
/* compute delta to move verts by */
- if(!cache->first_time) {
+ if(!paint_stroke_first_dab(cache->stroke)) {
switch(tool) {
case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_THUMB:
sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ss->ob->obmat);
+ invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, delta);
add_v3_v3(cache->grab_delta, delta);
break;
case SCULPT_TOOL_CLAY_TUBES:
case SCULPT_TOOL_NUDGE:
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ss->ob->obmat);
+ invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
break;
case SCULPT_TOOL_SNAKE_HOOK:
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ss->ob->obmat);
+ invert_m4_m4(imat, ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
break;
}
@@ -2987,18 +2451,9 @@ static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brus
copy_v3_v3(cache->old_grab_location, grab_location);
- if(tool == SCULPT_TOOL_GRAB)
- copy_v3_v3(sd->anchored_location, cache->true_location);
- else if(tool == SCULPT_TOOL_THUMB)
- copy_v3_v3(sd->anchored_location, cache->orig_grab_location);
-
if(ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) {
/* location stays the same for finding vertices in brush radius */
- copy_v3_v3(cache->true_location, cache->orig_grab_location);
-
- sd->draw_anchored = 1;
- copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
- sd->anchored_size = cache->pixel_radius;
+ copy_v3_v3(location, cache->orig_grab_location);
}
}
}
@@ -3006,221 +2461,74 @@ static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brus
/* Initialize the stroke cache variants from operator properties */
static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
{
+ Object *ob = CTX_data_active_object(C);
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
- int dx, dy;
-
- //RNA_float_get_array(ptr, "location", cache->traced_location);
-
- if (cache->first_time ||
- !((brush->flag & BRUSH_ANCHORED)||
- (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK)||
- (brush->sculpt_tool == SCULPT_TOOL_ROTATE))
- )
- {
- RNA_float_get_array(ptr, "location", cache->true_location);
- }
-
cache->pen_flip = RNA_boolean_get(ptr, "pen_flip");
- RNA_float_get_array(ptr, "mouse", cache->mouse);
-
- cache->pressure = RNA_float_get(ptr, "pressure");
/* Truly temporary data that isn't stored in properties */
- sd->draw_pressure= 1;
- sd->pressure_value= cache->pressure;
-
- cache->previous_pixel_radius = cache->pixel_radius;
- cache->pixel_radius = brush_size(brush);
-
- if(cache->first_time) {
- if (!brush_use_locked_size(brush)) {
- cache->initial_radius= unproject_brush_radius(ss->ob, cache->vc, cache->true_location, brush_size(brush));
- brush_set_unprojected_radius(brush, cache->initial_radius);
- }
- else {
- cache->initial_radius= brush_unprojected_radius(brush);
- }
-
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
- cache->initial_radius *= 2.0f;
- }
-
- if(brush_use_size_pressure(brush)) {
- cache->pixel_radius *= cache->pressure;
- cache->radius= cache->initial_radius * cache->pressure;
- }
- else
- cache->radius= cache->initial_radius;
-
- cache->radius_squared = cache->radius*cache->radius;
-
- if(!(brush->flag & BRUSH_ANCHORED || ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) {
- copy_v2_v2(cache->tex_mouse, cache->mouse);
-
- if ( (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) &&
- (brush->flag & BRUSH_RANDOM_ROTATION) &&
- !(brush->flag & BRUSH_RAKE))
- {
- cache->special_rotation = 2*M_PI*BLI_frand();
- }
- }
-
- if(brush->flag & BRUSH_ANCHORED) {
- int hit = 0;
-
- dx = cache->mouse[0] - cache->initial_mouse[0];
- dy = cache->mouse[1] - cache->initial_mouse[1];
-
- sd->anchored_size = cache->pixel_radius = sqrt(dx*dx + dy*dy);
-
- cache->special_rotation = atan2(dx, dy) + M_PI;
-
- if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- float halfway[2];
- float out[3];
-
- halfway[0] = dx*0.5 + cache->initial_mouse[0];
- halfway[1] = dy*0.5 + cache->initial_mouse[1];
-
- if (sculpt_stroke_get_location(C, stroke, out, halfway)) {
- copy_v3_v3(sd->anchored_location, out);
- copy_v2_v2(sd->anchored_initial_mouse, halfway);
- copy_v2_v2(cache->tex_mouse, halfway);
- copy_v3_v3(cache->true_location, sd->anchored_location);
- sd->anchored_size /= 2.0f;
- cache->pixel_radius /= 2.0f;
- hit = 1;
- }
- }
-
- if (!hit)
- copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
-
- cache->radius= unproject_brush_radius(ss->ob, paint_stroke_view_context(stroke), cache->true_location, cache->pixel_radius);
- cache->radius_squared = cache->radius*cache->radius;
+ sculpt_update_brush_delta(ob, brush);
- copy_v3_v3(sd->anchored_location, cache->true_location);
-
- sd->draw_anchored = 1;
- }
- else if(brush->flag & BRUSH_RAKE) {
- const float u = 0.5f;
- const float v = 1 - u;
- const float r = 20;
-
- const float dx = cache->last_rake[0] - cache->mouse[0];
- const float dy = cache->last_rake[1] - cache->mouse[1];
-
- if (cache->first_time) {
- copy_v2_v2(cache->last_rake, cache->mouse);
- }
- else if (dx*dx + dy*dy >= r*r) {
- cache->special_rotation = atan2(dx, dy);
-
- cache->last_rake[0] = u*cache->last_rake[0] + v*cache->mouse[0];
- cache->last_rake[1] = u*cache->last_rake[1] + v*cache->mouse[1];
- }
- }
+ if(brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
+ float mouse[2], initial_mouse[2];
+ float dx, dy;
- sculpt_update_brush_delta(sd, ss, brush);
+ paint_stroke_mouse_location(cache->stroke, mouse);
+ paint_stroke_initial_mouse_location(cache->stroke, initial_mouse);
- if(brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
- dx = cache->mouse[0] - cache->initial_mouse[0];
- dy = cache->mouse[1] - cache->initial_mouse[1];
+ dx = mouse[0] - initial_mouse[0];
+ dy = mouse[1] - initial_mouse[1];
cache->vertex_rotation = -atan2(dx, dy);
-
- sd->draw_anchored = 1;
- copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
- copy_v3_v3(sd->anchored_location, cache->true_location);
- sd->anchored_size = cache->pixel_radius;
}
-
- sd->special_rotation = cache->special_rotation;
}
-static void sculpt_stroke_modifiers_check(bContext *C, SculptSession *ss)
+static void sculpt_stroke_modifiers_check(bContext *C)
{
- if(ss->modifiers_active) {
+ Object *ob = CTX_data_active_object(C);
+
+ if(ob->paint->sculpt->modifiers_active) {
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = paint_brush(&sd->paint);
- sculpt_update_mesh_elements(CTX_data_scene(C), ss->ob, brush->sculpt_tool == SCULPT_TOOL_SMOOTH);
+ sculpt_update_mesh_elements(CTX_data_scene(C), ob, 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, float* tmin)
+static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float* tmin)
{
if (BLI_pbvh_node_get_tmin(node) < *tmin) {
- SculptRaycastData *srd = data_v;
+ PaintStrokeRaycastData *data = data_v;
+ SculptSession *ss = data->mode_data;
float (*origco)[3]= NULL;
- if(srd->original && srd->ss->cache) {
+ if(data->original && ss->cache) {
/* intersect with coordinates from before we started stroke */
- SculptUndoNode *unode= sculpt_undo_get_node(node);
- origco= (unode)? unode->co: NULL;
+ PBVHUndoNode *unode= pbvh_undo_get_node(node);
+ origco= (unode)? pbvh_undo_node_co(unode): NULL;
}
- if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) {
- srd->hit = 1;
- *tmin = srd->dist;
+ if(BLI_pbvh_node_raycast(data->ob->paint->pbvh, node, origco, data->ray_start, data->ray_normal, &data->dist, NULL, NULL)) {
+ data->hit = 1;
+ *tmin = data->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_end[3], ray_normal[3], dist;
- float obimat[4][4];
- float mval[2];
- SculptRaycastData srd;
-
- mval[0] = mouse[0] - vc->ar->winrct.xmin;
- mval[1] = mouse[1] - vc->ar->winrct.ymin;
-
- sculpt_stroke_modifiers_check(C, ss);
-
- viewline(vc->ar, vc->v3d, mval, ray_start, ray_end);
-
- invert_m4_m4(obimat, ss->ob->obmat);
- mul_m4_v3(obimat, ray_start);
- mul_m4_v3(obimat, ray_end);
-
- sub_v3_v3v3(ray_normal, ray_end, ray_start);
- dist= normalize_v3(ray_normal);
-
- srd.ss = vc->obact->sculpt;
- srd.ray_start = ray_start;
- srd.ray_normal = ray_normal;
- srd.dist = dist;
- srd.hit = 0;
- srd.original = (cache)? cache->original: 0;
- BLI_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
- ray_start, ray_normal, srd.original);
-
- copy_v3_v3(out, ray_normal);
- mul_v3_fl(out, srd.dist);
- add_v3_v3(out, ray_start);
+static 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->paint->sculpt;
+ StrokeCache *cache= ss->cache;
+ int original;
- return srd.hit;
+ sculpt_stroke_modifiers_check(C);
+ original = (cache)? cache->original: 0;
+
+ return paint_stroke_get_location(C, stroke, sculpt_raycast_cb, ss,
+ out, mouse, original);
}
static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
@@ -3228,7 +2536,7 @@ 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;
+ SculptSession *ss = CTX_data_active_object(C)->paint->sculpt;
Brush *brush = paint_brush(&sd->paint);
if(ob_get_key(ob) && !(ob->shapeflag & OB_SHAPE_LOCK)) {
@@ -3248,7 +2556,7 @@ static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
return 1;
}
-static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
+static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
Brush *brush = paint_brush(&sd->paint);
@@ -3257,26 +2565,27 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
(brush->sculpt_tool == SCULPT_TOOL_GRAB && brush_use_size_pressure(brush)) ||
(brush->flag & BRUSH_RESTORE_MESH))
{
+ SculptSession *ss = ob->paint->sculpt;
StrokeCache *cache = ss->cache;
int i;
PBVHNode **nodes;
int n, totnode;
- BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BLI_pbvh_search_gather(ob->paint->pbvh, NULL, NULL, &nodes, &totnode);
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ #pragma omp parallel for schedule(guided) if (sd->paint.flags & PAINT_USE_OPENMP)
for(n=0; n<totnode; n++) {
- SculptUndoNode *unode;
+ PBVHUndoNode *unode;
- unode= sculpt_undo_get_node(nodes[n]);
+ unode= pbvh_undo_get_node(nodes[n]);
if(unode) {
PBVHVertexIter vd;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, 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_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ copy_v3_v3(vd.co, pbvh_undo_node_co(unode)[vd.i]);
+ if(vd.no) VECCOPY(vd.no, pbvh_undo_node_no(unode)[vd.i])
+ else normal_short_to_float_v3(vd.fno, pbvh_undo_node_no(unode)[vd.i]);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@@ -3300,7 +2609,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
static void sculpt_flush_update(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
+ SculptSession *ss = ob->paint->sculpt;
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
@@ -3314,64 +2623,31 @@ static void sculpt_flush_update(bContext *C)
ED_region_tag_redraw(ar);
}
else {
- rcti r;
+ BLI_pbvh_update(ob->paint->pbvh, PBVH_UpdateBB, NULL);
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
-
- if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
- //rcti tmp;
-
- r.xmin += ar->winrct.xmin + 1;
- r.xmax += ar->winrct.xmin - 1;
- r.ymin += ar->winrct.ymin + 1;
- r.ymax += ar->winrct.ymin - 1;
-
- //tmp = r;
-
- //if (!BLI_rcti_is_empty(&ss->previous_r))
- // BLI_union_rcti(&r, &ss->previous_r);
-
- //ss->previous_r= tmp;
-
- ss->partial_redraw = 1;
- ED_region_tag_redraw_partial(ar, &r);
- }
+ paint_tag_partial_redraw(C, ob);
}
}
-/* Returns whether the mouse/stylus is over the mesh (1)
- or over the background (0) */
-static int over_mesh(bContext *C, struct wmOperator *op, float x, float y)
+static int sculpt_stroke_test_start(bContext *C, wmOperator *op, wmEvent *event)
{
- float mouse[2], co[3];
-
- mouse[0] = x;
- mouse[1] = y;
-
- return sculpt_stroke_get_location(C, op->customdata, co, mouse);
-}
-
-static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
- wmEvent *event)
-{
- /* Don't start the stroke until mouse goes over the mesh */
- if(over_mesh(C, op, event->x, event->y)) {
+ if(paint_stroke_over_mesh(C, op->customdata, event->x, event->y)) {
Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
+ SculptSession *ss = ob->paint->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
sculpt_update_cache_invariants(C, sd, ss, op, event);
- sculpt_undo_push_begin(sculpt_tool_name(sd));
+ pbvh_undo_push_begin(sculpt_tool_name(sd));
#ifdef _OPENMP
/* If using OpenMP then create a number of threads two times the
number of processor cores.
Justification: Empirically I've found that two threads per
processor gives higher throughput. */
- if (sd->flags & SCULPT_USE_OPENMP) {
+ if (sd->paint.flags & PAINT_USE_OPENMP) {
int num_procs;
num_procs = omp_get_num_procs();
@@ -3385,15 +2661,37 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
return 0;
}
+static void sculpt_stroke_update_symmetry(bContext *C, struct PaintStroke *stroke,
+ char symm, char axis, float angle,
+ int mirror_symmetry_pass, int radial_symmetry_pass,
+ float (*symmetry_rot_mat)[4])
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->paint->sculpt;
+ StrokeCache *cache = ss->cache;
+
+ paint_flip_coord(cache->grab_delta_symmetry, cache->grab_delta, symm);
+ paint_flip_coord(cache->view_normal, cache->true_view_normal, symm);
+
+ copy_m4_m4(cache->symm_rot_mat, symmetry_rot_mat);
+
+ mul_m4_v3(symmetry_rot_mat, cache->grab_delta_symmetry);
+}
+
static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->paint->sculpt;
+ StrokeCache *cache = ss->cache;
- sculpt_stroke_modifiers_check(C, ss);
+ sculpt_stroke_modifiers_check(C);
sculpt_update_cache_variants(C, sd, ss, stroke, itemptr);
- sculpt_restore_mesh(sd, ss);
- do_symmetrical_brush_actions(sd, ss);
+ sculpt_restore_mesh(sd, ob);
+
+ cache->bstrength= brush_strength(sd, cache, paint_stroke_feather(stroke));
+ paint_stroke_apply_brush(C, stroke, &sd->paint);
+ sculpt_combine_proxies(sd, ob);
/* Cleanup */
sculpt_flush_update(C);
@@ -3402,19 +2700,14 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused)
{
Object *ob= CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
+ SculptSession *ss = ob->paint->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
(void)unused;
- // reset values used to draw brush after completing the stroke
- sd->draw_anchored= 0;
- sd->draw_pressure= 0;
- sd->special_rotation= 0;
-
/* Finished */
if(ss->cache) {
- sculpt_stroke_modifiers_check(C, ss);
+ sculpt_stroke_modifiers_check(C);
/* Alt-Smooth */
if (ss->cache->alt_smooth) {
@@ -3428,16 +2721,16 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused)
sculpt_cache_free(ss->cache);
ss->cache = NULL;
- sculpt_undo_push_end();
+ pbvh_undo_push_end();
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+ BLI_pbvh_update(ob->paint->pbvh, PBVH_UpdateOriginalBB, NULL);
/* optimization: if there is locked key and active modifiers present in */
/* the stack, keyblock is updating at each step. otherwise we could update */
/* keyblock only when stroke is finished */
- if(ss->kb && !ss->modifiers_active) sculpt_update_keyblock(ss);
+ if(ss->kb && !ss->modifiers_active) sculpt_update_keyblock(ob);
- ss->partial_redraw = 0;
+ ob->paint->partial_redraw = 0;
/* try to avoid calling this, only for e.g. linked duplicates now */
if(((Mesh*)ob->data)->id.us > 1)
@@ -3447,8 +2740,22 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused)
}
}
+static void sculpt_stroke_set_modifiers(PaintStroke *stroke, Brush *brush)
+{
+ if(ELEM(brush->sculpt_tool, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ROTATE))
+ paint_stroke_set_modifier_use_original_location(stroke);
+
+ if(ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
+ paint_stroke_set_modifier_initial_radius_factor(stroke, 2.0f);
+
+ if(ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))
+ paint_stroke_set_modifier_use_original_texture_coords(stroke);
+}
+
static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
struct PaintStroke *stroke;
int ignore_background_click;
@@ -3458,15 +2765,18 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
stroke = paint_stroke_new(C, sculpt_stroke_get_location,
sculpt_stroke_test_start,
sculpt_stroke_update_step,
+ sculpt_stroke_update_symmetry,
+ sculpt_stroke_brush_action,
sculpt_stroke_done);
op->customdata = stroke;
+ sculpt_stroke_set_modifiers(stroke, paint_brush(&sd->paint));
/* For tablet rotation */
ignore_background_click = RNA_boolean_get(op->ptr,
"ignore_background_click");
- if(ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
+ if(ignore_background_click && !paint_stroke_over_mesh(C, stroke, event->x, event->y)) {
paint_stroke_free(stroke);
return OPERATOR_PASS_THROUGH;
}
@@ -3482,13 +2792,19 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ SculptSession *ss = CTX_data_active_object(C)->paint->sculpt;
if(!sculpt_brush_stroke_init(C, op->reports))
return OPERATOR_CANCELLED;
- op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, 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_update_symmetry,
+ sculpt_stroke_brush_action,
+ sculpt_stroke_done);
+
+ sculpt_stroke_set_modifiers(op->customdata, paint_brush(&sd->paint));
sculpt_update_cache_invariants(C, sd, ss, op, NULL);
@@ -3519,7 +2835,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
ot->exec= sculpt_brush_stroke_exec;
ot->poll= sculpt_poll;
- /* flags (sculpt does own undo? (ton) */
+ /* flags */
ot->flag= OPTYPE_BLOCKING;
/* properties */
@@ -3536,11 +2852,114 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
"Clicks on the background do not start the stroke");
}
+static void sculpt_area_hide_update(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ DerivedMesh *dm;
+
+ dm = mesh_get_derived_final(scene, ob, 0);
+ /* Force the removal of the old pbvh */
+ if(ob->paint->pbvh) {
+ BLI_pbvh_free(ob->paint->pbvh);
+ ob->paint->pbvh = NULL;
+ }
+ dm->getPBVH(NULL, dm);
+
+ /* Update */
+ sculpt_update_mesh_elements(scene, ob, 0);
+}
+
+static int sculpt_area_hide_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ int show_all = RNA_boolean_get(op->ptr, "show_all");
+
+ if(show_all) {
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->paint->sculpt;
+ ARegion *ar= CTX_wm_region(C);
+
+ if(ss->hidden_areas.first) {
+ /* Free all hidden areas */
+ BLI_freelistN(&ss->hidden_areas);
+ sculpt_area_hide_update(C);
+
+ /* Avoid cracks in multires */
+ if(ss->multires) {
+ BLI_pbvh_search_callback(ob->paint->pbvh, NULL, NULL,
+ BLI_pbvh_node_set_flags,
+ SET_INT_IN_POINTER(PBVH_UpdateAll));
+ multires_stitch_grids(ob);
+ }
+
+ ED_region_tag_redraw(ar);
+ }
+ return OPERATOR_FINISHED;
+ }
+ else
+ return WM_border_select_invoke(C, op, event);
+}
+
+static int sculpt_area_hide_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->paint->sculpt;
+ ViewContext vc;
+ bglMats mats;
+ BoundBox bb;
+ rcti rect;
+ HiddenArea *area;
+
+ memset(&mats, 0, sizeof(bglMats));
+ rect.xmin= RNA_int_get(op->ptr, "xmin");
+ rect.ymin= RNA_int_get(op->ptr, "ymin");
+ rect.xmax= RNA_int_get(op->ptr, "xmax");
+ rect.ymax= RNA_int_get(op->ptr, "ymax");
+
+ area = MEM_callocN(sizeof(HiddenArea), "hidden_area");
+ area->hide_inside = RNA_boolean_get(op->ptr, "hide_inside");
+
+ view3d_operator_needs_opengl(C);
+ view3d_set_viewcontext(C, &vc);
+ view3d_get_transformation(vc.ar, vc.rv3d, ob, &mats);
+ view3d_calculate_clipping(&bb, area->clip_planes, &mats, &rect);
+ mul_m4_fl(area->clip_planes, -1.0f);
+
+ BLI_addtail(&ss->hidden_areas, area);
+
+ sculpt_area_hide_update(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_area_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Hide Area";
+ ot->idname= "SCULPT_OT_area_hide";
+
+ /* api callbacks */
+ ot->invoke= sculpt_area_hide_invoke;
+ ot->modal= WM_border_select_modal;
+ ot->exec= sculpt_area_hide_exec;
+ ot->poll= sculpt_mode_poll;
+
+ ot->flag= OPTYPE_REGISTER;
+
+ /* rna */
+ RNA_def_boolean(ot->srna, "show_all", 0, "Show All", "");
+ RNA_def_boolean(ot->srna, "hide_inside", 0, "Hide Inside", "");
+ RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
+}
+
/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
static int sculpt_set_persistent_base(bContext *C, wmOperator *unused)
{
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ SculptSession *ss = CTX_data_active_object(C)->paint->sculpt;
(void)unused;
@@ -3570,8 +2989,9 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
static void sculpt_init_session(Scene *scene, Object *ob)
{
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->ob = ob;
+ create_paintsession(ob);
+
+ ob->paint->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
sculpt_update_mesh_elements(scene, ob, 0);
}
@@ -3581,7 +3001,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *unused)
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(scene, ob);
+ MultiresModifierData *mmd= ED_paint_multires_active(scene, ob);
int flush_recalc= 0;
(void)unused;
@@ -3601,7 +3021,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *unused)
/* Leave sculptmode */
ob->mode &= ~OB_MODE_SCULPT;
- free_sculptsession(ob);
+ free_paintsession(ob);
}
else {
/* Enter sculptmode */
@@ -3615,13 +3035,9 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *unused)
ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data");
/* Turn on X plane mirror symmetry by default */
- ts->sculpt->flags |= SCULPT_SYMM_X;
+ ts->sculpt->paint.flags |= PAINT_SYMM_X;
}
- /* Create sculpt mode session data */
- if(ob->sculpt)
- free_sculptsession(ob);
-
sculpt_init_session(scene, ob);
paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
@@ -3653,5 +3069,6 @@ void ED_operatortypes_sculpt()
WM_operatortype_append(SCULPT_OT_brush_stroke);
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_area_hide);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 254876d9b68..f8704f9c69b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -37,79 +37,18 @@
#include "BLI_pbvh.h"
struct bContext;
-struct Brush;
struct KeyBlock;
-struct Mesh;
-struct MultiresModifierData;
struct Object;
struct Scene;
-struct Sculpt;
-struct SculptStroke;
-
-/* Interface */
-void sculptmode_selectbrush_menu(void);
-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 Scene *scene, struct Object *ob);
-
-struct Brush *sculptmode_brush(void);
-//void do_symmetrical_brush_actions(struct Sculpt *sd, struct wmOperator *wm, struct BrushAction *a, short *, short *);
-
-void sculpt(Sculpt *sd);
+struct PBVHNode;
+struct SculptUndoNode;
int sculpt_poll(struct bContext *C);
void sculpt_update_mesh_elements(struct Scene *scene, struct Object *ob, int need_fmap);
-/* Stroke */
-struct SculptStroke *sculpt_stroke_new(const int max);
-void sculpt_stroke_free(struct SculptStroke *);
-void sculpt_stroke_add_point(struct SculptStroke *, const short x, const short y);
-void sculpt_stroke_apply(struct Sculpt *sd, struct SculptStroke *);
-void sculpt_stroke_apply_all(struct Sculpt *sd, struct SculptStroke *);
-int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]);
-
-/* Partial Mesh Visibility */
-void sculptmode_pmv(int mode);
-
-/* 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 */
-
- /* layer brush */
- float *layer_disp;
-
- /* shape keys */
- char *shapeName[32]; /* keep size in sync with keyblock dna */
-} SculptUndoNode;
-
-SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node);
-SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
-void sculpt_undo_push_begin(char *name);
-void sculpt_undo_push_end(void);
-
struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
-int sculpt_modifiers_active(Scene *scene, Object *ob);
-void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
+int sculpt_modifiers_active(struct Scene *scene, struct Object *ob);
+void sculpt_vertcos_to_key(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
void brush_jitter_pos(struct Brush *brush, float *pos, float *jitterpos);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
deleted file mode 100644
index e92740678fd..00000000000
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * $Id$
- *
- * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 by Nicholas Bishop
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- * Implements the Sculpt Mode tools
- *
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_ghash.h"
-#include "BLI_threads.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_mesh_types.h"
-
-#include "BKE_cdderivedmesh.h"
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_modifier.h"
-#include "BKE_multires.h"
-#include "BKE_paint.h"
-#include "BKE_key.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_sculpt.h"
-#include "paint_intern.h"
-#include "sculpt_intern.h"
-
-/************************** Undo *************************/
-
-static void update_cb(PBVHNode *node, void *unused)
-{
- (void)unused;
- 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) {
- char *shapeName= (char*)unode->shapeName;
-
- /* regular mesh restore */
- if(ss->totvert != unode->maxvert)
- continue;
-
- if (ss->kb && strcmp(ss->kb->name, shapeName)) {
- /* shape key has been changed before calling undo operator */
-
- Key *key= ob_get_key(ob);
- KeyBlock *kb= key_get_named_keyblock(key, shapeName);
-
- if (kb) {
- ob->shapenr= BLI_findindex(&key->block, kb) + 1;
- ob->shapeflag|= OB_SHAPE_LOCK;
-
- sculpt_update_mesh_elements(scene, ob, 0);
- WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
- } else {
- /* key has been removed -- skip this undo node */
- continue;
- }
- }
-
- index= unode->index;
- mvert= ss->mvert;
-
- if (ss->kb) {
- float (*vertCos)[3];
- vertCos= key_to_vertcos(ob, ss->kb);
-
- for(i=0; i<unode->totvert; i++)
- swap_v3_v3(vertCos[index[i]], unode->co[i]);
-
- /* propagate new coords to keyblock */
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
-
- /* pbvh uses it's own mvert array, so coords should be */
- /* propagated to pbvh here */
- BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
-
- MEM_freeN(vertCos);
- } else {
- 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 && dm->getGridData) {
- /* 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) {
- /* 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->pbvh, NULL, NULL, update_cb, NULL);
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
-
- if((mmd=sculpt_multires_active(scene, ob)))
- multires_mark_as_modified(ob);
-
- if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
- DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
- }
-}
-
-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);
- if(unode->layer_disp)
- MEM_freeN(unode->layer_disp);
- }
-}
-
-SculptUndoNode *sculpt_undo_get_node(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;
-}
-
-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(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->pbvh, node, &totvert, &allvert);
- BLI_pbvh_node_get_grids(ss->pbvh, 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->pbvh, 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);
-
- /* store active shape key */
- if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
- else unode->shapeName[0]= '\0';
-
- return unode;
-}
-
-void sculpt_undo_push_begin(char *name)
-{
- undo_paint_push_begin(UNDO_PAINT_MESH, name,
- sculpt_undo_restore, sculpt_undo_free);
-}
-
-void sculpt_undo_push_end(void)
-{
- 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;
- }
-
- if(unode->layer_disp) {
- MEM_freeN(unode->layer_disp);
- unode->layer_disp= NULL;
- }
- }
-
- undo_paint_push_end(UNDO_PAINT_MESH);
-}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 0df2888f4a0..6b166b470be 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -648,7 +648,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh);
} else if(faceselect) {
if(ob->mode & OB_MODE_WEIGHT_PAINT)
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material);
+ dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions, me, GPU_enable_material, DM_DRAW_VERTEX_COLORS);
else
dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index e7a69642e9f..5ac76719517 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -1872,7 +1872,7 @@ static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned
data.cols[2] = actCol;
data.efa_act = efa_act;
- dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material);
+ dm->drawMappedFaces(dm, NULL, draw_dm_faces_sel__setDrawOptions, &data, GPU_enable_material, 0);
}
static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
@@ -2292,7 +2292,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0, GPU_enable_material);
+ finalDM->drawMappedFaces(finalDM, NULL, draw_em_fancy__setFaceOpts, NULL, GPU_enable_material, 0);
glFrontFace(GL_CCW);
glDisable(GL_LIGHTING);
@@ -2425,7 +2425,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
drawFacesSolid() doesn't draw the transparent faces */
if(ob->dtx & OB_DRAWTRANSP) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, GPU_enable_material, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GPU_disable_material();
}
@@ -2454,6 +2454,9 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
int totvert, totedge, totface;
DispList *dl;
DerivedMesh *dm= mesh_get_derived_final(scene, ob, v3d->customdata_mask);
+ Paint *p;
+ float planes[4][4], (*paint_redraw_planes)[4] = NULL;
+ DMDrawFlags fast_navigate = 0;
if(!dm)
return;
@@ -2465,6 +2468,24 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
totface = dm->getNumFaces(dm);
+
+ /* setup for fast paint/sculpt drawing */
+ if((ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)) &&
+ (p=paint_get_active(scene))) {
+ /* drop down to a low multires level during navigation */
+ fast_navigate = ((p->flags & PAINT_FAST_NAVIGATE) &&
+ (rv3d->rflag & RV3D_NAVIGATING))? DM_DRAW_LOWEST_SUBDIVISION_LEVEL : 0;
+
+ if(ob->paint && ob->paint->partial_redraw) {
+ if(ar->do_draw & RGN_DRAW_PARTIAL) {
+ paint_get_redraw_planes(planes, ar, rv3d, ob);
+ paint_redraw_planes = planes;
+ ob->paint->partial_redraw = 0;
+ }
+
+ }
+ }
+
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
if(dt!=OB_SHADED)
@@ -2485,7 +2506,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
else if(dt==OB_WIRE || totface==0) {
draw_wire = 1; /* draw wire only, no depth buffer stuff */
}
- else if( (ob==OBACT && (ob->mode & OB_MODE_TEXTURE_PAINT || paint_facesel_test(ob))) ||
+ else if( (ob==OBACT && (ob->mode & OB_MODE_TEXTURE_PAINT)) ||
CHECK_OB_DRAWTEXTURE(v3d, dt))
{
int faceselect= (ob==OBACT && paint_facesel_test(ob));
@@ -2522,8 +2543,11 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* weight paint in solid mode, special case. focus on making the weights clear
* rather then the shading, this is also forced in wire view */
GPU_enable_material(0, NULL);
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material);
-
+
+ dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions,
+ me->mface, GPU_enable_material,
+ DM_DRAW_VERTEX_COLORS);
+
bglPolygonOffset(rv3d->dist, 1.0);
glDepthMask(0); // disable write in zbuffer, selected edge wires show better
@@ -2544,9 +2568,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_wire= 0;
}
else {
- Paint *p;
-
- if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
+ if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->paint)
draw_mesh_object_outline(v3d, ob, dm);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
@@ -2554,23 +2576,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
- if(ob->sculpt && (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) {
- if(ar->do_draw & RGN_DRAW_PARTIAL) {
- 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);
+ dm->drawFacesSolid(dm, paint_redraw_planes, GPU_enable_material, fast_navigate|DM_DRAW_PAINT_MASK);
GPU_disable_material();
@@ -2582,7 +2588,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
} else {
UI_ThemeColor(TH_WIRE);
}
- if(!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
+ if(!ob->paint && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
dm->drawLooseEdges(dm);
}
}
@@ -2605,18 +2611,36 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material);
+ dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions,
+ me->mface, GPU_enable_material,
+ DM_DRAW_VERTEX_COLORS);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
GPU_disable_material();
}
else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
- if(me->mcol)
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1, GPU_enable_material);
+ if(me->mcol) {
+ MFace *mface = get_mesh(ob)->mface;
+ DMDrawFlags dm_flags = DM_DRAW_PTEX;
+
+ /* XXX - temporary - set up nicer drawing for new vpaint */
+ GPU_enable_material(mface->mat_nr+1, NULL);
+ glEnable(GL_LIGHTING);
+ dm_flags |= fast_navigate;
+ if(me->editflag & ME_EDIT_PTEX)
+ dm_flags |= DM_DRAW_PTEX_TEXELS;
+
+ dm->drawMappedFaces(dm, paint_redraw_planes,
+ wpaint__setSolidDrawOptions, NULL,
+ GPU_enable_material,
+ dm_flags);
+ glDisable(GL_LIGHTING);
+ }
else {
glColor3f(1.0f, 1.0f, 1.0f);
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0, GPU_enable_material);
+
+ dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions, NULL, GPU_enable_material, 0);
}
}
else do_draw= 1;
@@ -3082,7 +3106,7 @@ static int drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, B
if(!glsl) {
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
glEnable(GL_LIGHTING);
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, GPU_enable_material, 0);
glDisable(GL_LIGHTING);
}
else
@@ -6334,7 +6358,7 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh
cpack(0);
if (facecol) {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0, GPU_enable_material);
+ dm->drawMappedFaces(dm, NULL, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, GPU_enable_material, 0);
if(check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
@@ -6345,7 +6369,7 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh
}
} else {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0, GPU_enable_material);
+ dm->drawMappedFaces(dm, NULL, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, GPU_enable_material, 0);
}
}
@@ -6375,8 +6399,14 @@ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob)
glColor3ub(0, 0, 0);
- if(face_sel_mode) dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, me, 0, GPU_enable_material);
- else dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0, GPU_enable_material);
+ if(face_sel_mode)
+ dm->drawMappedFaces(dm, NULL, bbs_mesh_solid_hide__setDrawOpts,
+ me, GPU_enable_material,
+ DM_DRAW_BACKBUF_SELECTION);
+ else
+ dm->drawMappedFaces(dm, NULL, bbs_mesh_solid__setDrawOpts,
+ me, GPU_enable_material,
+ DM_DRAW_BACKBUF_SELECTION);
dm->release(dm);
}
@@ -6479,11 +6509,11 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
glEnable(GL_LIGHTING);
if(dm) {
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, GPU_enable_material, 0);
GPU_end_object_materials();
}
else if(edm)
- edm->drawMappedFaces(edm, NULL, NULL, 0, GPU_enable_material);
+ edm->drawMappedFaces(edm, NULL, NULL, NULL, GPU_enable_material, 0);
glDisable(GL_LIGHTING);
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 67c2a4f1c56..ef3894a02e0 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -74,6 +74,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_screen_types.h"
+#include "ED_sculpt.h"
#include "ED_transform.h"
#include "UI_interface.h"
@@ -2205,6 +2206,37 @@ static void draw_viewport_fps(Scene *scene, ARegion *ar)
BLF_draw_default(22, ar->winy-17, 0.0f, printable);
}
+
+void debug_draw_redraw_area(ARegion *ar)
+{
+ rcti winrct;
+
+ if(G.rt != 444)
+ return;
+
+ /* do nothing if it looks like this isn't a partial redraw */
+ region_scissor_winrct(ar, &winrct);
+ if(ar->drawrct.xmin == winrct.xmin &&
+ ar->drawrct.xmax == winrct.xmax &&
+ ar->drawrct.ymin == winrct.ymin &&
+ ar->drawrct.ymax == winrct.ymax)
+ return;
+
+ /* choose a nice pastel color so that debugging is kept cheerful */
+ glColor3f((rand() / (float)RAND_MAX) * 0.3 + 0.7,
+ (rand() / (float)RAND_MAX) * 0.3 + 0.7,
+ (rand() / (float)RAND_MAX) * 0.3 + 0.7);
+
+ /* draw the redraw area, pull in by 2px so it doesn't get
+ clipped by the scissor */
+ glBegin(GL_LINE_LOOP);
+ glVertex2i(ar->drawrct.xmin-winrct.xmin+2, ar->drawrct.ymin-winrct.ymin+2);
+ glVertex2i(ar->drawrct.xmax-winrct.xmin-2, ar->drawrct.ymin-winrct.ymin+2);
+ glVertex2i(ar->drawrct.xmax-winrct.xmin-2, ar->drawrct.ymax-winrct.ymin-2);
+ glVertex2i(ar->drawrct.xmin-winrct.xmin+2, ar->drawrct.ymax-winrct.ymin-2);
+ glEnd();
+}
+
void view3d_main_area_draw(const bContext *C, ARegion *ar)
{
Scene *scene= CTX_data_scene(C);
@@ -2404,12 +2436,12 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
}
ED_region_pixelspace(ar);
-
-// retopo_paint_view_update(v3d);
-// retopo_draw_paint_lines();
-
- /* Draw particle edit brush XXX (removed) */
-
+
+ debug_draw_redraw_area(ar);
+
+ /* would be nicer to have as a region callback, but
+ can't get the right context then? -nicholas */
+ ED_paint_overlay_draw(C, ar);
if(rv3d->persp==RV3D_CAMOB)
drawviewborder(scene, ar, v3d);
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 5ca8843b658..c8a24acd582 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -471,7 +471,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
PointerRNA meshptr;
RNA_pointer_create(&ob->id, &RNA_Mesh, ob->data, &meshptr);
- uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", 0);
+ uiItemR(layout, &meshptr, "ptex_edit_mode", UI_ITEM_R_ICON_ONLY, "", 0);
} else {
char *str_menu;
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index a4f661e9511..40bd5792e4f 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -140,7 +140,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
if(!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname)
do_glob_undo= 1;
}
- else if(obact && obact->mode & OB_MODE_SCULPT) {
+ else if(obact && obact->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)) {
if(!ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname) && undoname)
do_glob_undo= 1;
}