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')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h37
-rw-r--r--source/blender/blenkernel/BKE_customdata.h82
-rw-r--r--source/blender/blenkernel/BKE_dmgrid.h59
-rw-r--r--source/blender/blenkernel/BKE_multires.h5
-rw-r--r--source/blender/blenkernel/BKE_paint.h38
-rw-r--r--source/blender/blenkernel/BKE_ptex.h42
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h3
-rw-r--r--source/blender/blenkernel/BKE_texture.h3
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c509
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h11
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c32
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c118
-rw-r--r--source/blender/blenkernel/intern/customdata.c400
-rw-r--r--source/blender/blenkernel/intern/multires.c502
-rw-r--r--source/blender/blenkernel/intern/object.c27
-rw-r--r--source/blender/blenkernel/intern/paint.c109
-rw-r--r--source/blender/blenkernel/intern/ptex.c445
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c590
-rw-r--r--source/blender/blenkernel/intern/texture.c19
-rw-r--r--source/blender/blenlib/BLI_ghash.h2
-rw-r--r--source/blender/blenlib/BLI_math_geom.h1
-rw-r--r--source/blender/blenlib/BLI_pbvh.h136
-rw-r--r--source/blender/blenlib/intern/pbvh.c487
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/SConscript1
-rw-r--r--source/blender/blenloader/intern/readfile.c57
-rw-r--r--source/blender/blenloader/intern/writefile.c49
-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
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/GPU_buffers.h49
-rw-r--r--source/blender/gpu/SConscript1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c1013
-rw-r--r--source/blender/makesdna/DNA_brush_types.h43
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h33
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h8
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h27
-rw-r--r--source/blender/makesdna/DNA_object_types.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h74
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c32
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c345
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene.c49
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c108
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c10
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c4
-rw-r--r--source/blender/modifiers/intern/MOD_util.c18
-rw-r--r--source/blender/modifiers/intern/MOD_util.h1
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c1
-rw-r--r--source/blender/windowmanager/intern/wm_files.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c1
82 files changed, 9806 insertions, 3315 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 5b33d9e1c53..441951da3ee 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -68,10 +68,7 @@ struct PBVH;
#define SUB_ELEMS_EDGE 2
#define SUB_ELEMS_FACE 4
-typedef struct DMGridData {
- float co[3];
- float no[3];
-} DMGridData;
+typedef struct DMGridData DMGridData;
typedef struct DMGridAdjacency {
int index[4];
@@ -84,6 +81,23 @@ typedef enum DerivedMeshType {
DM_TYPE_CCGDM
} DerivedMeshType;
+typedef enum DMDrawFlags {
+ /* fast navigation for multires */
+ DM_DRAW_LOWEST_SUBDIVISION_LEVEL = 1,
+ /* draw mask for sculpt mode */
+ DM_DRAW_PAINT_MASK = 2,
+ /* draw ptex textures */
+ DM_DRAW_PTEX = 4,
+ /* mcol, weight colors, etc. */
+ DM_DRAW_VERTEX_COLORS = 8,
+ /* visually show ptex texel density */
+ DM_DRAW_PTEX_TEXELS = 16,
+ /* mainly for sculpting, use smooth normals */
+ DM_DRAW_FULLY_SMOOTH = 32,
+ /* back-buffer selection mode */
+ DM_DRAW_BACKBUF_SELECTION = 64,
+} DMDrawFlags;
+
typedef struct DerivedMesh DerivedMesh;
struct DerivedMesh {
/* Private DerivedMesh data, only for internal DerivedMesh use */
@@ -158,6 +172,8 @@ struct DerivedMesh {
DMGridData **(*getGridData)(DerivedMesh *dm);
DMGridAdjacency *(*getGridAdjacency)(DerivedMesh *dm);
int *(*getGridOffset)(DerivedMesh *dm);
+ struct GridKey *(*getGridKey)(DerivedMesh *dm);
+ struct GridToFace *(*getGridFaceMap)(DerivedMesh *dm);
/* Iterate over each mapped vertex in the derived mesh, calling the
* given function with the original vert and the mapped vert's new
@@ -240,7 +256,8 @@ struct DerivedMesh {
* Also called for *final* editmode DerivedMeshes
*/
void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
- int fast, int (*setMaterial)(int, void *attribs));
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags);
/* Draw all faces
* o If useTwoSided, draw front and back using col arrays
@@ -278,10 +295,12 @@ struct DerivedMesh {
* smooth shaded.
*/
void (*drawMappedFaces)(DerivedMesh *dm,
- int (*setDrawOptions)(void *userData, int index,
- int *drawSmooth_r),
- void *userData, int useColors,
- int (*setMaterial)(int, void *attribs));
+ float (*partial_redraw_planes)[4],
+ int (*setDrawOptions)(void *userData, int index,
+ int *drawSmooth_r),
+ void *userData,
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags);
/* Draw mapped faces using MTFace
* o Drawing options too complicated to enumerate, look at code.
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 5d306e75db9..50e14fcbd9a 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -39,6 +39,7 @@ extern "C" {
struct ID;
struct CustomData;
struct CustomDataLayer;
+struct CustomDataMultires;
typedef unsigned int CustomDataMask;
extern const CustomDataMask CD_MASK_BAREMESH;
@@ -94,14 +95,18 @@ void *CustomData_add_layer(struct CustomData *data, int type, int alloctype,
void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype,
void *layer, int totelem, const char *name);
-/* frees the active or first data layer with the give type.
+/* adds a layer and puts it at the specified offset */
+void *CustomData_add_layer_at_offset(struct CustomData *data, int type, int alloctype,
+ void *layerdata, int totelem, int offset);
+
+/* frees the layer at index.
* returns 1 on succes, 0 if no layer with the given type is found
*
* in editmode, use EM_free_data_layer instead of this function
*/
int CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
-/* frees the layer index with the give type.
+/* frees the active layer of the give type.
* returns 1 on succes, 0 if no layer with the given type is found
*
* in editmode, use EM_free_data_layer instead of this function
@@ -189,20 +194,46 @@ void *CustomData_em_get_n(const struct CustomData *data, void *block, int type,
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
-/* gets a pointer to the active or first layer of type
- * returns NULL if there is no layer of type
- */
+/************************** Get layer data ***********************/
+/* return the data from the first layer matching the parameters */
+/* these all return NULL if no such layer is found */
+
+/* returns the data from the active layer matching type */
void *CustomData_get_layer(const struct CustomData *data, int type);
+
+/* returns the data from the nth layer matching type */
void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
+
+/* returns the data from the first layer matching type and name */
void *CustomData_get_layer_named(const struct CustomData *data, int type,
char *name);
+/********************************* Get layer index *********************************/
+/* return the index within data.layers of the first layer matching the parameters */
+/* these all return -1 if no such layer is found */
+
+/* returns the index of the first layer matching type */
int CustomData_get_layer_index(const struct CustomData *data, int type);
+
+/* returns the index of the first layer matching type and name */
int CustomData_get_named_layer_index(const struct CustomData *data, int type, char *name);
+
+/* returns the index of the active layer */
int CustomData_get_active_layer_index(const struct CustomData *data, int type);
+
+/* returns the index of the render layer */
int CustomData_get_render_layer_index(const struct CustomData *data, int type);
+
+/* returns the index of the clone layer */
int CustomData_get_clone_layer_index(const struct CustomData *data, int type);
+
+/* returns the index of the stencil/mask layer */
int CustomData_get_stencil_layer_index(const struct CustomData *data, int type);
+
+/************************************ Get layer offset ***********************************/
+/* return the offset of the layer from the first layer of the specified type */
+/* to find the index of that layer, add it to the index of the first layer of that type */
+/* these all return -1 if no layer of the specified type is found */
int CustomData_get_active_layer(const struct CustomData *data, int type);
int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type);
@@ -245,6 +276,7 @@ void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n
/* adds flag to the layer flags */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
+void CustomData_set_layer_offset_flag(struct CustomData *data, int type, int offset, int flag);
/* alloc/free a block of custom data attached to one element in editmode */
void CustomData_em_set_default(struct CustomData *data, void **block);
@@ -284,6 +316,45 @@ void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
+/* Subsurf grids */
+
+/* return the number of layers of type that have multires data */
+int CustomData_get_multires_count(struct CustomData *cd, int type);
+
+/* allocates a list of names of layers that have multires data */
+void *CustomData_get_multires_names(struct CustomData *cd, int type);
+
+/* number of floats used per-element for the multires of a customdata type */
+int CustomData_multires_type_totfloat(int type);
+
+/* returns the multires data for a layer matching name and type,
+ or NULL if no such layer found */
+float *CustomData_multires_get_data(struct CustomDataMultires *cdm, int type,
+ char *name);
+
+/* if layer matching type and name exists, free and replace its griddata
+ otherwise create the layer and set its griddata */
+void CustomData_multires_sync_layer(struct CustomDataMultires *cdm, int type,
+ char *name);
+
+/* insert a multires layer of the specified type and assign griddata */
+void CustomData_multires_add_layer_data(struct CustomDataMultires *cdm, int type,
+ char *name, float *griddata);
+
+/* insert a multires layer of the specified type int each
+ cdm in the array of length count */
+void CustomData_multires_add_layers(struct CustomDataMultires *cdm, int count,
+ int type, char *name);
+
+/* remove the multires layer with matching source name from the cdm
+ array of length count, returns 1 if succesful, 0 otherwise */
+int CustomData_multires_remove_layers(struct CustomDataMultires *cdm, int count,
+ int type, char *name);
+
+/* rename a layer matching type and old_name */
+void CustomData_multires_rename(struct CustomDataMultires *cdm, int type,
+ char *old_name, char *name);
+
/* External file storage */
void CustomData_external_add(struct CustomData *data,
@@ -304,4 +375,3 @@ void CustomData_external_reload(struct CustomData *data,
#endif
#endif
-
diff --git a/source/blender/blenkernel/BKE_dmgrid.h b/source/blender/blenkernel/BKE_dmgrid.h
new file mode 100644
index 00000000000..fc1aa04f34b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_dmgrid.h
@@ -0,0 +1,59 @@
+#ifndef BKE_DMGRID_H
+#define BKE_DMGRID_H
+
+struct CustomData;
+
+/* Each grid element can contain zero or more layers of coordinates,
+ paint masks, and normals; these numbers are stored in the GridKey
+
+ The name arrays are the unique names of the source customdata layer
+*/
+typedef struct GridKey {
+ int co;
+ int color;
+ int mask;
+ int no;
+
+ /* key to identify the source layer */
+ char (*color_names)[32];
+ char (*mask_names)[32];
+} GridKey;
+
+#define GRIDELEM_KEY_INIT(_key, _totco, _totcolor, _totmask, _totno) \
+ ((_key)->co = _totco, (_key)->color = _totcolor, \
+ (_key)->mask = _totmask, (_key)->no = _totno, \
+ (_key)->color_names = NULL, (_key)->mask_names = NULL)
+
+#define GRIDELEM_SIZE(_key) ((3*(_key)->co + 4*(_key)->color + (_key)->mask + 3*(_key)->no) * sizeof(float))
+#define GRIDELEM_INTERP_COUNT(_key) (3*(_key)->co + 4*(_key)->color + (_key)->mask)
+
+#define GRIDELEM_COLOR_OFFSET(_key) (3*(_key)->co*sizeof(float))
+#define GRIDELEM_MASK_OFFSET(_key) (GRIDELEM_COLOR_OFFSET(_key) + 4*(_key)->color*sizeof(float))
+#define GRIDELEM_NO_OFFSET(_key) (GRIDELEM_MASK_OFFSET(_key) + (_key)->mask*sizeof(float))
+
+#define GRIDELEM_AT(_grid, _elem, _key) ((struct DMGridData*)(((char*)(_grid)) + (_elem) * GRIDELEM_SIZE(_key)))
+#define GRIDELEM_INC(_grid, _inc, _key) ((_grid) = GRIDELEM_AT(_grid, _inc, _key))
+
+ /* I can't figure out how to cast this type without a typedef,
+ having the array length is useful to directly index layers */
+typedef float (*gridelem_f4)[4];
+#define GRIDELEM_CO(_grid, _key) ((float*)(_grid))
+#define GRIDELEM_COLOR(_grid, _key) ((gridelem_f4)((char*)(_grid) + GRIDELEM_COLOR_OFFSET(_key)))
+#define GRIDELEM_MASK(_grid, _key) ((float*)((char*)(_grid) + GRIDELEM_MASK_OFFSET(_key)))
+#define GRIDELEM_NO(_grid, _key) ((float*)((char*)(_grid) + GRIDELEM_NO_OFFSET(_key)))
+
+#define GRIDELEM_CO_AT(_grid, _elem, _key) GRIDELEM_CO(GRIDELEM_AT(_grid, _elem, _key), _key)
+#define GRIDELEM_COLOR_AT(_grid, _elem, _key) GRIDELEM_COLOR(GRIDELEM_AT(_grid, _elem, _key), _key)
+#define GRIDELEM_MASK_AT(_grid, _elem, _key) GRIDELEM_MASK(GRIDELEM_AT(_grid, _elem, _key), _key)
+#define GRIDELEM_NO_AT(_grid, _elem, _key) GRIDELEM_NO(GRIDELEM_AT(_grid, _elem, _key), _key)
+
+/* returns the active gridelem layer offset for either colors
+ or masks, -1 if not found */
+int gridelem_active_offset(struct CustomData *data, GridKey *gridkey, int type);
+
+typedef struct GridToFace {
+ int face;
+ char offset;
+} GridToFace;
+
+#endif
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index fc0ab2eea1e..6e76f2d0924 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -31,6 +31,7 @@
#define BKE_MULTIRES_H
struct DerivedMesh;
+struct GridKey;
struct Mesh;
struct MFace;
struct Multires;
@@ -46,8 +47,9 @@ void multires_force_external_reload(struct Object *ob);
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
+/* note: gridkey can be NULL, will provide a context-sensitive default */
struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*,
- int local_mmd, struct DerivedMesh*, struct Object *, int, int);
+ int local_mmd, struct DerivedMesh*, struct Object *, struct GridKey *, int, int);
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
@@ -63,6 +65,7 @@ int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierD
struct Object *ob, struct DerivedMesh *srcdm);
int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresModifierData *mmd,
struct Object *ob, struct ModifierData *md);
+void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
void multires_stitch_grids(struct Object *);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 20742033a2e..6e8cb769be8 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -31,6 +31,9 @@
#include "DNA_vec_types.h"
struct Brush;
+struct CustomData;
+struct DMGridData;
+struct GridKey;
struct MFace;
struct MultireModifierData;
struct MVert;
@@ -58,31 +61,26 @@ void paint_brush_set(struct Paint *paint, struct Brush *br);
* however hiding faces is useful */
int paint_facesel_test(struct Object *ob);
-/* Session data (mode-specific) */
+void paint_refresh_mask_display(struct Object *ob);
+float paint_mask_from_gridelem(struct DMGridData *elem, struct GridKey *gridkey,
+ struct CustomData *vdata);
+float paint_mask_from_vertex(struct CustomData *vdata, int vertex_index,
+ int pmask_totlayer, int pmask_first_layer);
typedef struct SculptSession {
- struct ProjVert *projverts;
-
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
struct MultiresModifierData *multires; /* Special handling for multires meshes */
struct MVert *mvert;
struct MFace *mface;
int totvert, totface;
float *face_normals;
- struct Object *ob;
struct KeyBlock *kb;
/* Mesh connectivity */
struct ListBase *fmap;
- /* PBVH acceleration structure */
- struct PBVH *pbvh;
-
- /* Used temporarily per-stroke */
- float *vertexcosnos;
-
- /* Partial redraw */
- int partial_redraw;
+ /* Area hiding */
+ ListBase hidden_areas;
/* Used to cache the render of the active texture */
unsigned int texcache_side, *texcache, texcache_actual;
@@ -93,13 +91,23 @@ typedef struct SculptSession {
struct SculptStroke *stroke;
struct StrokeCache *cache;
- struct GPUDrawObject *drawobject;
-
int modifiers_active;
rcti previous_r;
} SculptSession;
-void free_sculptsession(struct Object *ob);
+typedef struct PaintSession {
+ /* mode-specific data (just sculpt for now */
+ SculptSession *sculpt;
+
+ /* PBVH acceleration structure */
+ struct PBVH *pbvh;
+
+ /* Partial redraw */
+ int partial_redraw;
+} PaintSession;
+
+void create_paintsession(struct Object *ob);
+void free_paintsession(struct Object *ob);
#endif
diff --git a/source/blender/blenkernel/BKE_ptex.h b/source/blender/blenkernel/BKE_ptex.h
new file mode 100644
index 00000000000..6c3b197f202
--- /dev/null
+++ b/source/blender/blenkernel/BKE_ptex.h
@@ -0,0 +1,42 @@
+/*
+ * $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 yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+struct DerivedMesh;
+struct Mesh;
+struct MPtex;
+struct MPtexSubface;
+struct PtexTextureHandle;
+
+void ptex_elem_to_floats(int type, int channels, void *data, float *out);
+void ptex_elem_from_floats(int type, int channels, void *data, float *in);
+
+struct DerivedMesh *quad_dm_create_from_derived(struct DerivedMesh *dm);
+void ptex_subface_scale(struct MPtex *pt, struct MPtexSubface *subface, int ures, int vres);
+void ptex_layer_from_file(struct Mesh *me, struct PtexTextureHandle *ptex_texture);
+int ptex_layer_save_file(struct Mesh *me, const char *filename);
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 940a0027d0b..6eede8643c1 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -32,6 +32,7 @@ struct DMGridAdjacency;
struct DMGridData;
struct DerivedMesh;
struct EditMesh;
+struct GridKey;
struct IndexNode;
struct ListBase;
struct Mesh;
@@ -49,6 +50,7 @@ struct _CCGVert;
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct GridKey *gridkey,
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode);
@@ -80,6 +82,7 @@ typedef struct CCGDerivedMesh {
struct DMGridAdjacency *gridAdjacency;
int *gridOffset;
struct _CCGFace **gridFaces;
+ struct GridToFace *gridFaceMap;
struct {
struct MultiresModifierData *mmd;
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index cbae90f4c38..b6670541df0 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -48,6 +48,7 @@ struct PluginTex;
struct PointDensity;
struct Tex;
struct TexMapping;
+struct TexResult;
struct VoxelData;
struct World;
@@ -116,6 +117,8 @@ struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd);
int BKE_texture_dependsOnTime(const struct Tex *texture);
+void get_texture_value(struct Tex *texture, float *tex_co, struct TexResult *texres);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1b6411e4f64..6e4c831575d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -50,6 +50,7 @@ SET(INC
../../../intern/memutil
../../../intern/opennl/extern
../../../intern/smoke/extern
+ ../../../extern/ptex
../../../source/blender/windowmanager # XXX - BAD LEVEL CALL WM_api.h
${ZLIB_INC}
)
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 954b7759b46..ead08ca9b92 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -11,6 +11,7 @@ incs += ' #/intern/iksolver/extern ../blenloader'
incs += ' #/extern/bullet2/src'
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
incs += ' ../gpu #/extern/glew/include'
+incs += ' #/extern/ptex'
incs += ' #/intern/smoke/extern'
incs += ' #/intern/audaspace/intern'
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 1cd5ae381c4..241dfc72484 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -218,6 +218,8 @@ static CCGAllocatorIFC *_getStandardAllocatorIFC(void) {
static int VertDataEqual(float *a, float *b) {
return a[0]==b[0] && a[1]==b[1] && a[2]==b[2];
}
+
+#if 0
#define VertDataZero(av) { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
#define VertDataCopy(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
#define VertDataAdd(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
@@ -230,6 +232,51 @@ static int VertDataEqual(float *a, float *b) {
_t[1] = (_a[1]+_b[1]+_c[1]+_d[1])*.25; \
_t[2] = (_a[2]+_b[2]+_c[2]+_d[2])*.25; \
}
+#else
+
+CCG_INLINE void VertDataZero(void *a, const int n)
+{
+ int i;
+ for(i = 0; i < n; ++i)
+ ((float*)a)[i] = 0;
+}
+
+CCG_INLINE void VertDataCopy(void *a, void *b, int n)
+{
+ int i;
+ for(i = 0; i < n; ++i)
+ ((float*)a)[i] = ((float*)b)[i];
+}
+
+CCG_INLINE void VertDataAdd(void *a, void *b, int n)
+{
+ int i;
+ for(i = 0; i < n; ++i)
+ ((float*)a)[i] += ((float*)b)[i];
+}
+
+CCG_INLINE void VertDataSub(void *a, void *b, int n)
+{
+ int i;
+ for(i = 0; i < n; ++i)
+ ((float*)a)[i] -= ((float*)b)[i];
+}
+
+CCG_INLINE void VertDataMulN(void *a, float b, int n)
+{
+ int i;
+ for(i = 0; i < n; ++i)
+ ((float*)a)[i] *= b;
+}
+
+CCG_INLINE void VertDataAvg4(void *t, void *a, void *b, void *c, void *d, int n)
+{
+ int i;
+ for(i = 0; i < n; ++i)
+ ((float*)t)[i] = (((float*)a)[i] + ((float*)b)[i] + ((float*)c)[i] + ((float*)d)[i]) * 0.25f;
+}
+#endif
+
#define NormZero(av) { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
#define NormCopy(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
#define NormAdd(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
@@ -321,7 +368,7 @@ struct _CCGSubSurf {
void *q, *r;
- // data for calc vert normals
+ // data for calc vert normals
int calcVertNormals;
int normalDataOffset;
@@ -709,6 +756,15 @@ void ccgSubSurf_free(CCGSubSurf *ss) {
_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
+ /* free gridkey */
+ if(ss->meshIFC.gridkey.color_names)
+ MEM_freeN(ss->meshIFC.gridkey.color_names);
+ if(ss->meshIFC.gridkey.mask_names)
+ MEM_freeN(ss->meshIFC.gridkey.mask_names);
+
+ ss->meshIFC.gridkey.color_names = NULL;
+ ss->meshIFC.gridkey.mask_names = NULL;
+
CCGSUBSURF_free(ss, ss);
if (allocatorIFC.release) {
@@ -906,13 +962,13 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, in
v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
if (!v) {
v = _vert_new(vHDL, ss);
- VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
_ehash_insert(ss->vMap, (EHEntry*) v);
v->flags = Vert_eEffected|seamflag;
} else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
int i, j;
- VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
v->flags = Vert_eEffected|seamflag;
for (i=0; i<v->numEdges; i++) {
@@ -935,13 +991,13 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, in
v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
if (!v) {
v = _vert_new(vHDL, ss);
- VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
_ehash_insert(ss->vMap, (EHEntry*) v);
v->flags = Vert_eEffected|seamflag;
} else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
*prevp = v->next;
_ehash_insert(ss->vMap, (EHEntry*) v);
- VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
v->flags = Vert_eEffected|Vert_eChanged|seamflag;
} else {
*prevp = v->next;
@@ -1320,7 +1376,7 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
}
VertDataCopy((float*)((byte*)FACE_getCenterData(f) + normalDataOffset),
- FACE_getIFNo(f, lvl, S, 0, 0));
+ FACE_getIFNo(f, lvl, S, 0, 0), 3);
for (x=1; x<gridSize-1; x++)
NormCopy(FACE_getIENo(f, lvl, S, x),
@@ -1356,6 +1412,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
int nextLvl = curLvl+1;
int ptrIdx, cornerIdx, i;
int vertDataSize = ss->meshIFC.vertDataSize;
+ int finterpCount = ss->meshIFC.finterpCount;
void *q = ss->q, *r = ss->r;
#pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
@@ -1377,7 +1434,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
- VertDataAvg4(co, co0, co1, co2, co3);
+ VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
}
}
@@ -1395,7 +1452,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
void *co = FACE_getIECo(f, nextLvl, S, fx);
- VertDataAvg4(co, co0, co1, co2, co3);
+ VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
/* interior face interior edge midpoints
@@ -1414,7 +1471,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
- VertDataAvg4(co, co0, co1, co2, co3);
+ VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
}
@@ -1429,7 +1486,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
- VertDataAvg4(co, co0, co1, co2, co3);
+ VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
}
}
@@ -1451,9 +1508,9 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co1 = EDGE_getCo(e, curLvl, x+1);
void *co = EDGE_getCo(e, nextLvl, fx);
- VertDataCopy(co, co0);
- VertDataAdd(co, co1);
- VertDataMulN(co, 0.5);
+ VertDataCopy(co, co0, finterpCount);
+ VertDataAdd(co, co1, finterpCount);
+ VertDataMulN(co, 0.5, finterpCount);
}
} else {
for (x=0; x<edgeSize-1; x++) {
@@ -1463,25 +1520,25 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co = EDGE_getCo(e, nextLvl, fx);
int numFaces = 0;
- VertDataCopy(q, co0);
- VertDataAdd(q, co1);
+ VertDataCopy(q, co0, finterpCount);
+ VertDataAdd(q, co1, finterpCount);
for (j=0; j<e->numFaces; j++) {
CCGFace *f = e->faces[j];
- VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
+ VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize), finterpCount);
numFaces++;
}
- VertDataMulN(q, 1.0f/(2.0f+numFaces));
+ VertDataMulN(q, 1.0f/(2.0f+numFaces), finterpCount);
- VertDataCopy(r, co0);
- VertDataAdd(r, co1);
- VertDataMulN(r, 0.5);
+ VertDataCopy(r, co0, finterpCount);
+ VertDataAdd(r, co1, finterpCount);
+ VertDataMulN(r, 0.5, finterpCount);
- VertDataCopy(co, q);
- VertDataSub(r, q);
- VertDataMulN(r, sharpness);
- VertDataAdd(co, r);
+ VertDataCopy(co, q, finterpCount);
+ VertDataSub(r, q, finterpCount);
+ VertDataMulN(r, sharpness, finterpCount);
+ VertDataAdd(co, r, finterpCount);
}
}
}
@@ -1525,51 +1582,51 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
seam = 0;
if (!v->numEdges) {
- VertDataCopy(nCo, co);
+ VertDataCopy(nCo, co, finterpCount);
} else if (_vert_isBoundary(v)) {
int numBoundary = 0;
- VertDataZero(r);
+ VertDataZero(r, finterpCount);
for (j=0; j<v->numEdges; j++) {
CCGEdge *e = v->edges[j];
if (_edge_isBoundary(e)) {
- VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+ VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), finterpCount);
numBoundary++;
}
}
- VertDataCopy(nCo, co);
- VertDataMulN(nCo, 0.75);
- VertDataMulN(r, 0.25f/numBoundary);
- VertDataAdd(nCo, r);
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataMulN(nCo, 0.75, finterpCount);
+ VertDataMulN(r, 0.25f/numBoundary, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
} else {
int cornerIdx = (1 + (1<<(curLvl))) - 2;
int numEdges = 0, numFaces = 0;
- VertDataZero(q);
+ VertDataZero(q, finterpCount);
for (j=0; j<v->numFaces; j++) {
CCGFace *f = v->faces[j];
- VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
+ VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx), finterpCount);
numFaces++;
}
- VertDataMulN(q, 1.0f/numFaces);
- VertDataZero(r);
+ VertDataMulN(q, 1.0f/numFaces, finterpCount);
+ VertDataZero(r, finterpCount);
for (j=0; j<v->numEdges; j++) {
CCGEdge *e = v->edges[j];
- VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
+ VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize), finterpCount);
numEdges++;
}
- VertDataMulN(r, 1.0f/numEdges);
+ VertDataMulN(r, 1.0f/numEdges, finterpCount);
- VertDataCopy(nCo, co);
- VertDataMulN(nCo, numEdges-2.0f);
- VertDataAdd(nCo, q);
- VertDataAdd(nCo, r);
- VertDataMulN(nCo, 1.0f/numEdges);
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataMulN(nCo, numEdges-2.0f, finterpCount);
+ VertDataAdd(nCo, q, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
+ VertDataMulN(nCo, 1.0f/numEdges, finterpCount);
}
if ((sharpCount>1 && v->numFaces) || seam) {
- VertDataZero(q);
+ VertDataZero(q, finterpCount);
if (seam) {
avgSharpness = 1.0f;
@@ -1583,32 +1640,32 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
if (seam) {
if (_edge_isBoundary(e))
- VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+ VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), finterpCount);
} else if (sharpness != 0.0) {
- VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+ VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), finterpCount);
}
}
- VertDataMulN(q, (float) 1/sharpCount);
+ VertDataMulN(q, (float) 1/sharpCount, finterpCount);
if (sharpCount!=2 || allSharp) {
// q = q + (co-q)*avgSharpness
- VertDataCopy(r, co);
- VertDataSub(r, q);
- VertDataMulN(r, avgSharpness);
- VertDataAdd(q, r);
+ VertDataCopy(r, co, finterpCount);
+ VertDataSub(r, q, finterpCount);
+ VertDataMulN(r, avgSharpness, finterpCount);
+ VertDataAdd(q, r, finterpCount);
}
// r = co*.75 + q*.25
- VertDataCopy(r, co);
- VertDataMulN(r, .75);
- VertDataMulN(q, .25);
- VertDataAdd(r, q);
+ VertDataCopy(r, co, finterpCount);
+ VertDataMulN(r, .75, finterpCount);
+ VertDataMulN(q, .25, finterpCount);
+ VertDataAdd(r, q, finterpCount);
// nCo = nCo + (r-nCo)*avgSharpness
- VertDataSub(r, nCo);
- VertDataMulN(r, avgSharpness);
- VertDataAdd(nCo, r);
+ VertDataSub(r, nCo, finterpCount);
+ VertDataMulN(r, avgSharpness, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
}
}
@@ -1641,13 +1698,13 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
int fx = x*2;
void *co = EDGE_getCo(e, curLvl, x);
void *nCo = EDGE_getCo(e, nextLvl, fx);
- VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
- VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
- VertDataMulN(r, 0.5);
- VertDataCopy(nCo, co);
- VertDataMulN(nCo, 0.75);
- VertDataMulN(r, 0.25);
- VertDataAdd(nCo, r);
+ VertDataCopy(r, EDGE_getCo(e, curLvl, x-1), finterpCount);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x+1), finterpCount);
+ VertDataMulN(r, 0.5, finterpCount);
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataMulN(nCo, 0.75, finterpCount);
+ VertDataMulN(r, 0.25, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
}
} else {
for (x=1; x<edgeSize-1; x++) {
@@ -1656,37 +1713,37 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *nCo = EDGE_getCo(e, nextLvl, fx);
int numFaces = 0;
- VertDataZero(q);
- VertDataZero(r);
- VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
- VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
+ VertDataZero(q, finterpCount);
+ VertDataZero(r, finterpCount);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x-1), finterpCount);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x+1), finterpCount);
for (j=0; j<e->numFaces; j++) {
CCGFace *f = e->faces[j];
- VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
- VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
+ VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize), finterpCount);
+ VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize), finterpCount);
- VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
+ VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize), finterpCount);
numFaces++;
}
- VertDataMulN(q, 1.0/(numFaces*2.0f));
- VertDataMulN(r, 1.0/(2.0f + numFaces));
+ VertDataMulN(q, 1.0/(numFaces*2.0f), finterpCount);
+ VertDataMulN(r, 1.0/(2.0f + numFaces), finterpCount);
- VertDataCopy(nCo, co);
- VertDataMulN(nCo, (float) numFaces);
- VertDataAdd(nCo, q);
- VertDataAdd(nCo, r);
- VertDataMulN(nCo, 1.0f/(2+numFaces));
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataMulN(nCo, (float) numFaces, finterpCount);
+ VertDataAdd(nCo, q, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
+ VertDataMulN(nCo, 1.0f/(2+numFaces), finterpCount);
if (sharpCount==2) {
- VertDataCopy(q, co);
- VertDataMulN(q, 6.0f);
- VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
- VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
- VertDataMulN(q, 1/8.0f);
-
- VertDataSub(q, nCo);
- VertDataMulN(q, avgSharpness);
- VertDataAdd(nCo, q);
+ VertDataCopy(q, co, finterpCount);
+ VertDataMulN(q, 6.0f, finterpCount);
+ VertDataAdd(q, EDGE_getCo(e, curLvl, x-1), finterpCount);
+ VertDataAdd(q, EDGE_getCo(e, curLvl, x+1), finterpCount);
+ VertDataMulN(q, 1/8.0f, finterpCount);
+
+ VertDataSub(q, nCo, finterpCount);
+ VertDataMulN(q, avgSharpness, finterpCount);
+ VertDataAdd(nCo, q, finterpCount);
}
}
}
@@ -1712,21 +1769,21 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
* o old interior edge points
* o new interior face midpoints
*/
- VertDataZero(q);
+ VertDataZero(q, finterpCount);
for (S=0; S<f->numVerts; S++) {
- VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
+ VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1), finterpCount);
}
- VertDataMulN(q, 1.0f/f->numVerts);
- VertDataZero(r);
+ VertDataMulN(q, 1.0f/f->numVerts, finterpCount);
+ VertDataZero(r, finterpCount);
for (S=0; S<f->numVerts; S++) {
- VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
+ VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1), finterpCount);
}
- VertDataMulN(r, 1.0f/f->numVerts);
+ VertDataMulN(r, 1.0f/f->numVerts, finterpCount);
- VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
- VertDataAdd(FACE_getCenterData(f), q);
- VertDataAdd(FACE_getCenterData(f), r);
- VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
+ VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f, finterpCount);
+ VertDataAdd(FACE_getCenterData(f), q, finterpCount);
+ VertDataAdd(FACE_getCenterData(f), r, finterpCount);
+ VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts, finterpCount);
for (S=0; S<f->numVerts; S++) {
/* interior face shift
@@ -1742,19 +1799,19 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
- FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
- FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
- FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
+ FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
+ FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
+ FACE_getIFCo(f, nextLvl, S, fx-1, fy+1), finterpCount);
VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
- FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
- FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
- FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
-
- VertDataCopy(nCo, co);
- VertDataSub(nCo, q);
- VertDataMulN(nCo, 0.25f);
- VertDataAdd(nCo, r);
+ FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
+ FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
+ FACE_getIFCo(f, nextLvl, S, fx+0, fy+1), finterpCount);
+
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataSub(nCo, q, finterpCount);
+ VertDataMulN(nCo, 0.25f, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
}
}
@@ -1769,19 +1826,19 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *nCo = FACE_getIECo(f, nextLvl, S, fx);
VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
- FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
- FACE_getIFCo(f, nextLvl, S, fx+1, +1),
- FACE_getIFCo(f, nextLvl, S, fx-1, +1));
+ FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
+ FACE_getIFCo(f, nextLvl, S, fx+1, +1),
+ FACE_getIFCo(f, nextLvl, S, fx-1, +1), finterpCount);
VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
- FACE_getIECo(f, nextLvl, S, fx+1),
- FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
- FACE_getIFCo(f, nextLvl, S, fx, 1));
-
- VertDataCopy(nCo, co);
- VertDataSub(nCo, q);
- VertDataMulN(nCo, 0.25f);
- VertDataAdd(nCo, r);
+ FACE_getIECo(f, nextLvl, S, fx+1),
+ FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
+ FACE_getIFCo(f, nextLvl, S, fx, 1), finterpCount);
+
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataSub(nCo, q, finterpCount);
+ VertDataMulN(nCo, 0.25f, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
}
}
}
@@ -1801,8 +1858,8 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
#pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
- VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
- VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
+ VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), finterpCount);
+ VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl), finterpCount);
}
#pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
@@ -1814,19 +1871,19 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
- VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), finterpCount);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), finterpCount);
for (x=1; x<gridSize-1; x++) {
void *co = FACE_getIECo(f, nextLvl, S, x);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
- VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, finterpCount);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co, finterpCount);
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize), finterpCount);
}
}
}
@@ -1840,6 +1897,7 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
int numEffectedV, numEffectedE, numEffectedF;
int subdivLevels = ss->subdivLevels;
int vertDataSize = ss->meshIFC.vertDataSize;
+ int finterpCount = ss->meshIFC.finterpCount;
int i, j, ptrIdx, S;
int curLvl, nextLvl;
void *q = ss->q, *r = ss->r;
@@ -1879,11 +1937,11 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
CCGFace *f = effectedF[ptrIdx];
void *co = FACE_getCenterData(f);
- VertDataZero(co);
+ VertDataZero(co, finterpCount);
for (i=0; i<f->numVerts; i++) {
- VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl));
+ VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl), finterpCount);
}
- VertDataMulN(co, 1.0f/f->numVerts);
+ VertDataMulN(co, 1.0f/f->numVerts, finterpCount);
f->flags = 0;
}
@@ -1893,28 +1951,28 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
float sharpness = EDGE_getSharpness(e, curLvl);
if (_edge_isBoundary(e) || sharpness>=1.0) {
- VertDataCopy(co, VERT_getCo(e->v0, curLvl));
- VertDataAdd(co, VERT_getCo(e->v1, curLvl));
- VertDataMulN(co, 0.5f);
+ VertDataCopy(co, VERT_getCo(e->v0, curLvl), finterpCount);
+ VertDataAdd(co, VERT_getCo(e->v1, curLvl), finterpCount);
+ VertDataMulN(co, 0.5f, finterpCount);
} else {
int numFaces = 0;
- VertDataCopy(q, VERT_getCo(e->v0, curLvl));
- VertDataAdd(q, VERT_getCo(e->v1, curLvl));
+ VertDataCopy(q, VERT_getCo(e->v0, curLvl), finterpCount);
+ VertDataAdd(q, VERT_getCo(e->v1, curLvl), finterpCount);
for (i=0; i<e->numFaces; i++) {
CCGFace *f = e->faces[i];
- VertDataAdd(q, FACE_getCenterData(f));
+ VertDataAdd(q, FACE_getCenterData(f), finterpCount);
numFaces++;
}
- VertDataMulN(q, 1.0f/(2.0f+numFaces));
+ VertDataMulN(q, 1.0f/(2.0f+numFaces), finterpCount);
- VertDataCopy(r, VERT_getCo(e->v0, curLvl));
- VertDataAdd(r, VERT_getCo(e->v1, curLvl));
- VertDataMulN(r, 0.5f);
+ VertDataCopy(r, VERT_getCo(e->v0, curLvl), finterpCount);
+ VertDataAdd(r, VERT_getCo(e->v1, curLvl), finterpCount);
+ VertDataMulN(r, 0.5f, finterpCount);
- VertDataCopy(co, q);
- VertDataSub(r, q);
- VertDataMulN(r, sharpness);
- VertDataAdd(co, r);
+ VertDataCopy(co, q, finterpCount);
+ VertDataSub(r, q, finterpCount);
+ VertDataMulN(r, sharpness, finterpCount);
+ VertDataAdd(co, r, finterpCount);
}
// edge flags cleared later
@@ -1953,49 +2011,49 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
seam = 0;
if (!v->numEdges) {
- VertDataCopy(nCo, co);
+ VertDataCopy(nCo, co, finterpCount);
} else if (_vert_isBoundary(v)) {
int numBoundary = 0;
- VertDataZero(r);
+ VertDataZero(r, finterpCount);
for (i=0; i<v->numEdges; i++) {
CCGEdge *e = v->edges[i];
if (_edge_isBoundary(e)) {
- VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
+ VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), finterpCount);
numBoundary++;
}
}
- VertDataCopy(nCo, co);
- VertDataMulN(nCo, 0.75);
- VertDataMulN(r, 0.25f/numBoundary);
- VertDataAdd(nCo, r);
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataMulN(nCo, 0.75, finterpCount);
+ VertDataMulN(r, 0.25f/numBoundary, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
} else {
int numEdges = 0, numFaces = 0;
- VertDataZero(q);
+ VertDataZero(q, finterpCount);
for (i=0; i<v->numFaces; i++) {
CCGFace *f = v->faces[i];
- VertDataAdd(q, FACE_getCenterData(f));
+ VertDataAdd(q, FACE_getCenterData(f), finterpCount);
numFaces++;
}
- VertDataMulN(q, 1.0f/numFaces);
- VertDataZero(r);
+ VertDataMulN(q, 1.0f/numFaces, finterpCount);
+ VertDataZero(r, finterpCount);
for (i=0; i<v->numEdges; i++) {
CCGEdge *e = v->edges[i];
- VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
+ VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), finterpCount);
numEdges++;
}
- VertDataMulN(r, 1.0f/numEdges);
+ VertDataMulN(r, 1.0f/numEdges, finterpCount);
- VertDataCopy(nCo, co);
- VertDataMulN(nCo, numEdges-2.0f);
- VertDataAdd(nCo, q);
- VertDataAdd(nCo, r);
- VertDataMulN(nCo, 1.0f/numEdges);
+ VertDataCopy(nCo, co, finterpCount);
+ VertDataMulN(nCo, numEdges-2.0f, finterpCount);
+ VertDataAdd(nCo, q, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
+ VertDataMulN(nCo, 1.0f/numEdges, finterpCount);
}
if (sharpCount>1 || seam) {
- VertDataZero(q);
+ VertDataZero(q, finterpCount);
if (seam) {
avgSharpness = 1.0f;
@@ -2010,34 +2068,34 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
if (seam) {
if (_edge_isBoundary(e)) {
CCGVert *oV = _edge_getOtherVert(e, v);
- VertDataAdd(q, VERT_getCo(oV, curLvl));
+ VertDataAdd(q, VERT_getCo(oV, curLvl), finterpCount);
}
} else if (sharpness != 0.0) {
CCGVert *oV = _edge_getOtherVert(e, v);
- VertDataAdd(q, VERT_getCo(oV, curLvl));
+ VertDataAdd(q, VERT_getCo(oV, curLvl), finterpCount);
}
}
- VertDataMulN(q, (float) 1/sharpCount);
+ VertDataMulN(q, (float) 1/sharpCount, finterpCount);
if (sharpCount!=2 || allSharp) {
// q = q + (co-q)*avgSharpness
- VertDataCopy(r, co);
- VertDataSub(r, q);
- VertDataMulN(r, avgSharpness);
- VertDataAdd(q, r);
+ VertDataCopy(r, co, finterpCount);
+ VertDataSub(r, q, finterpCount);
+ VertDataMulN(r, avgSharpness, finterpCount);
+ VertDataAdd(q, r, finterpCount);
}
// r = co*.75 + q*.25
- VertDataCopy(r, co);
- VertDataMulN(r, .75);
- VertDataMulN(q, .25);
- VertDataAdd(r, q);
+ VertDataCopy(r, co, finterpCount);
+ VertDataMulN(r, .75, finterpCount);
+ VertDataMulN(q, .25, finterpCount);
+ VertDataAdd(r, q, finterpCount);
// nCo = nCo + (r-nCo)*avgSharpness
- VertDataSub(r, nCo);
- VertDataMulN(r, avgSharpness);
- VertDataAdd(nCo, r);
+ VertDataSub(r, nCo, finterpCount);
+ VertDataMulN(r, avgSharpness, finterpCount);
+ VertDataAdd(nCo, r, finterpCount);
}
// vert flags cleared later
@@ -2065,8 +2123,8 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
- VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
- VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl));
+ VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), finterpCount);
+ VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), finterpCount);
}
for (i=0; i<numEffectedF; i++) {
CCGFace *f = effectedF[i];
@@ -2074,13 +2132,13 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), finterpCount);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), finterpCount);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), finterpCount);
}
}
@@ -2188,6 +2246,7 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
int vertDataSize = ss->meshIFC.vertDataSize, freeF;
+ int finterpCount = ss->meshIFC.finterpCount;
subdivLevels = ss->subdivLevels;
lvl = (lvl)? lvl: subdivLevels;
@@ -2203,16 +2262,16 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
- VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
- VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
+ VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), finterpCount);
+ VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), finterpCount);
for (x=0; x<gridSize; x++)
- VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
+ VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), finterpCount);
for (x=0; x<gridSize; x++) {
int eI = gridSize-1-x;
- VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
- VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
+ VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x), finterpCount);
+ VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx), finterpCount);
}
}
}
@@ -2227,6 +2286,7 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
int vertDataSize = ss->meshIFC.vertDataSize, freeF;
+ int finterpCount = ss->meshIFC.finterpCount;
subdivLevels = ss->subdivLevels;
lvl = (lvl)? lvl: subdivLevels;
@@ -2245,17 +2305,17 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
for (x=0; x<gridSize; x++) {
int eI = gridSize-1-x;
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
+ VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
}
for (x=1; x<gridSize-1; x++) {
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), finterpCount);
}
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), finterpCount);
}
}
@@ -2273,6 +2333,7 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
int numEffectedV, numEffectedE, freeF;
int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
int vertDataSize = ss->meshIFC.vertDataSize;
+ int finterpCount = ss->meshIFC.finterpCount;
subdivLevels = ss->subdivLevels;
lvl = (lvl)? lvl: subdivLevels;
@@ -2287,47 +2348,47 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
/* zero */
for (i=0; i<numEffectedV; i++) {
CCGVert *v = effectedV[i];
- VertDataZero(VERT_getCo(v, lvl));
+ VertDataZero(VERT_getCo(v, lvl), finterpCount);
}
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
for (x=0; x<edgeSize; x++)
- VertDataZero(EDGE_getCo(e, lvl, x));
+ VertDataZero(EDGE_getCo(e, lvl, x), finterpCount);
}
/* add */
for (i=0; i<numEffectedF; i++) {
CCGFace *f = effectedF[i];
- VertDataZero(FACE_getCenterData(f));
+ VertDataZero(FACE_getCenterData(f), finterpCount);
for (S=0; S<f->numVerts; S++)
for (x=0; x<gridSize; x++)
- VertDataZero(FACE_getIECo(f, lvl, S, x));
+ VertDataZero(FACE_getIECo(f, lvl, S, x), finterpCount);
for (S=0; S<f->numVerts; S++) {
int prevS = (S+f->numVerts-1)%f->numVerts;
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[prevS];
- VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
+ VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), finterpCount);
if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
- VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
+ VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), finterpCount);
for (x=1; x<gridSize-1; x++) {
- VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
- VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x));
+ VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), finterpCount);
+ VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x), finterpCount);
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
- VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
+ VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x), finterpCount);
if (FACE_getEdges(f)[prevS]->flags&Edge_eEffected)
if(x != 0)
- VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
+ VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx), finterpCount);
}
}
}
@@ -2335,50 +2396,50 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
/* average */
for (i=0; i<numEffectedV; i++) {
CCGVert *v = effectedV[i];
- VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces);
+ VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces, finterpCount);
}
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
- VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl));
- VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl));
+ VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl), finterpCount);
+ VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl), finterpCount);
for (x=1; x<edgeSize-1; x++)
- VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces);
+ VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces, finterpCount);
}
/* copy */
for (i=0; i<numEffectedF; i++) {
CCGFace *f = effectedF[i];
- VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
+ VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts, finterpCount);
for (S=0; S<f->numVerts; S++)
for (x=1; x<gridSize-1; x++)
- VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f);
+ VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, finterpCount);
for (S=0; S<f->numVerts; S++) {
int prevS = (S+f->numVerts-1)%f->numVerts;
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[prevS];
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), finterpCount);
for (x=1; x<gridSize-1; x++) {
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), finterpCount);
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
+ VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
}
- VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f));
- VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0));
+ VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f), finterpCount);
+ VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0), finterpCount);
}
}
@@ -2510,6 +2571,10 @@ int ccgSubSurf_getGridLevelSize(CCGSubSurf *ss, int level) {
}
}
+struct GridKey *ccgSubSurf_getGridKey(CCGSubSurf *ss) {
+ return &ss->meshIFC.gridkey;
+}
+
/* Vert accessors */
CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v) {
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index 34d684221b0..b1238849404 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -1,5 +1,7 @@
/* $Id$ */
+#include "BKE_dmgrid.h"
+
typedef void* CCGMeshHDL;
typedef void* CCGVertHDL;
typedef void* CCGEdgeHDL;
@@ -12,8 +14,14 @@ typedef struct _CCGFace CCGFace;
typedef struct _CCGMeshIFC CCGMeshIFC;
struct _CCGMeshIFC {
int vertUserSize, edgeUserSize, faceUserSize;
-
int vertDataSize;
+
+ /* How many floats to interpolate per-vertex.
+ example: if interpolating coordinates and paint masks,
+ that would be (3+1) floats, so finterpCount would be 4. */
+ int finterpCount;
+
+ struct GridKey gridkey;
};
/***/
@@ -90,6 +98,7 @@ int ccgSubSurf_getEdgeSize (CCGSubSurf *ss);
int ccgSubSurf_getEdgeLevelSize (CCGSubSurf *ss, int level);
int ccgSubSurf_getGridSize (CCGSubSurf *ss);
int ccgSubSurf_getGridLevelSize (CCGSubSurf *ss, int level);
+struct GridKey* ccgSubSurf_getGridKey (CCGSubSurf *ss);
CCGVert* ccgSubSurf_getVert (CCGSubSurf *ss, CCGVertHDL v);
CCGVertHDL ccgSubSurf_getVertVertHandle (CCGVert *v);
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 2e8922dec1b..0f2aeeb0bf5 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -46,11 +46,14 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
#include "BKE_key.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "BKE_ptex.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@@ -628,7 +631,11 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use
}
/* note, material function is ignored for now. */
-static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int UNUSED(useColors), int (*setMaterial)(int, void *attribs))
+static void emDM_drawMappedFaces(DerivedMesh *dm, float (*partial_redraw_planes)[4],
+ int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
+ void *userData,
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags)
{
EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
EditFace *efa;
@@ -1960,6 +1967,13 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
add_weight_mcol_dm(ob, finaldm);
}
+ /* hack: for ptex paint use all quads */
+ if((ob->mode & OB_MODE_VERTEX_PAINT) && finaldm->type != DM_TYPE_CCGDM) {
+ dm = finaldm;
+ finaldm = quad_dm_create_from_derived(finaldm);
+ dm->release(dm);
+ }
+
/* add an orco layer if needed */
if(dataMask & CD_MASK_ORCO) {
add_orco_dm(ob, NULL, finaldm, orcodm, CD_ORCO);
@@ -2222,13 +2236,13 @@ static void clear_mesh_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform= NULL;
}
- /* we free pbvh on changes, except during sculpt since it can't deal with
+ /* we free pbvh on changes, except during paint since it can't deal with
changing PVBH node organization, we hope topology does not change in
the meantime .. weak */
- if(ob->sculpt && ob->sculpt->pbvh) {
- if(!ob->sculpt->cache) {
- BLI_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh= NULL;
+ if(ob->paint && ob->paint->pbvh) {
+ if(!ob->paint->sculpt || !ob->paint->sculpt->cache) {
+ BLI_pbvh_free(ob->paint->pbvh);
+ ob->paint->pbvh= NULL;
}
}
}
@@ -2238,7 +2252,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
Object *obact = scene->basact?scene->basact->object:NULL;
int editing = paint_facesel_test(ob);
/* weight paint and face select need original indicies because of selection buffer drawing */
- int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)));
+ int needMapping = (ob==obact) && (editing || (ob->mode & OB_MODE_WEIGHT_PAINT));
clear_mesh_caches(ob);
@@ -2251,6 +2265,10 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
ob->lastDataMask = dataMask;
+
+ /* update the pbvh for paint */
+ if((ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)) && ob->paint)
+ ob->paint->pbvh= ob->derivedFinal->getPBVH(ob, ob->derivedFinal);
}
static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask)
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index eb895d62f17..efbbd8f859c 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -37,6 +37,7 @@
#include "BIF_gl.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
@@ -191,13 +192,15 @@ static int can_pbvh_draw(Object *ob, DerivedMesh *dm)
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
Mesh *me= (ob)? ob->data: NULL;
- if(ob->sculpt->modifiers_active) return 0;
+ if(ob->paint->sculpt && ob->paint->sculpt->modifiers_active) return 0;
+ //if(paint_facesel_test(ob)) return 0;
- return (cddm->mvert == me->mvert) || ob->sculpt->kb;
+ return (cddm->mvert == me->mvert) || (ob->paint->sculpt && ob->paint->sculpt->kb) || (ob->mode & OB_MODE_VERTEX_PAINT);
}
static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
{
+ SculptSession *ss;
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
Mesh *me= (ob)? ob->data: NULL;
@@ -206,10 +209,12 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
return NULL;
}
- if(!ob->sculpt)
+ if(!ob->paint)
return NULL;
- if(ob->sculpt->pbvh) {
- cddm->pbvh= ob->sculpt->pbvh;
+ ss = ob->paint->sculpt;
+
+ if(ob->paint->pbvh) {
+ cddm->pbvh= ob->paint->pbvh;
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
}
@@ -217,10 +222,35 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
this derivedmesh is just original mesh. it's the multires subsurf dm
that this is actually for, to support a pbvh on a modified mesh */
if(!cddm->pbvh && ob->type == OB_MESH) {
- cddm->pbvh = BLI_pbvh_new();
+ MFace *mface;
+ MVert *mvert;
+ int totvert, totface;
+ int leaf_limit = PBVH_DEFAULT_LEAF_LIMIT;
+
+ /* TODO: set leaf limit more intelligently */
+ if(ob->mode & OB_MODE_VERTEX_PAINT)
+ leaf_limit = 1;
+
+ cddm->pbvh = BLI_pbvh_new(leaf_limit);
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
- BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert,
- me->totface, me->totvert);
+
+ if(ob->mode & OB_MODE_VERTEX_PAINT) {
+ mface = cddm->mface;
+ mvert = cddm->mvert;
+ totvert = cdDM_getNumVerts(&cddm->dm);
+ totface = cdDM_getNumFaces(&cddm->dm);
+ }
+ else {
+ mface = me->mface;
+ mvert = me->mvert;
+ totvert = me->totvert;
+ totface = me->totface;
+ }
+
+ BLI_pbvh_build_mesh(cddm->pbvh, mface, mvert,
+ &me->vdata, &me->fdata,
+ totface, totvert,
+ ss ? &ss->hidden_areas : NULL);
}
return cddm->pbvh;
@@ -416,9 +446,39 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
}
}
+/* draw using the PBVH; returns true if drawing is done,
+ false if regular drawing should be used */
+static int cddm_draw_pbvh(DerivedMesh *dm, float (*partial_redraw_planes)[4],
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ MFace *mface = cddm->mface;
+ float (*face_nors)[3];
+
+ if(!(flags & DM_DRAW_BACKBUF_SELECTION) && cddm->pbvh && cddm->pbvh_draw) {
+ if(dm->numFaceData) {
+ face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+
+ /* should be per face */
+ if(setMaterial && !setMaterial(mface->mat_nr+1, NULL))
+ return 1;
+ if(mface->flag & ME_SMOOTH)
+ flags |= DM_DRAW_FULLY_SMOOTH;
+
+ BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, flags);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
static void cdDM_drawFacesSolid(DerivedMesh *dm,
float (*partial_redraw_planes)[4],
- int UNUSED(fast), int (*setMaterial)(int, void *attribs))
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mvert = cddm->mvert;
@@ -426,29 +486,16 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
-#define PASSVERT(index) { \
- if(shademodel == GL_SMOOTH) { \
- short *no = mvert[index].no; \
- glNormal3sv(no); \
- } \
- glVertex3fv(mvert[index].co); \
-}
-
- if(cddm->pbvh && cddm->pbvh_draw) {
- if(dm->numFaceData) {
- float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
-
- /* should be per face */
- if(!setMaterial(mface->mat_nr+1, NULL))
- return;
-
- glShadeModel((mface->flag & ME_SMOOTH)? GL_SMOOTH: GL_FLAT);
- BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, (mface->flag & ME_SMOOTH));
- glShadeModel(GL_FLAT);
- }
+#define PASSVERT(index) { \
+ if(shademodel == GL_SMOOTH) { \
+ short *no = mvert[index].no; \
+ glNormal3sv(no); \
+ } \
+ glVertex3fv(mvert[index].co); \
+ }
+ if(cddm_draw_pbvh(dm, partial_redraw_planes, setMaterial, flags))
return;
- }
if( GPU_buffer_legacy(dm) ) {
DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
@@ -777,7 +824,9 @@ static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tfa
cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
-static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs))
+static void cdDM_drawMappedFaces(DerivedMesh *dm, float (*partial_redraw_planes)[4],
+ int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
+ void *userData, int (*setMaterial)(int, void *attribs), DMDrawFlags flags)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mv = cddm->mvert;
@@ -786,6 +835,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+ if(cddm_draw_pbvh(dm, partial_redraw_planes, NULL, flags))
+ return;
+
mc = DM_get_face_data_layer(dm, CD_ID_MCOL);
if(!mc)
mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
@@ -810,7 +862,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
if(draw) {
unsigned char *cp = NULL;
- if(useColors && mc)
+ if((flags & DM_DRAW_VERTEX_COLORS) && mc)
cp = (unsigned char *)&mc[i * 4];
glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
@@ -867,7 +919,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
int prevstart = 0;
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
- if( useColors && mc )
+ if((flags & DM_DRAW_VERTEX_COLORS) && mc )
GPU_color_setup(dm);
if( !GPU_buffer_legacy(dm) ) {
int tottri = dm->drawObject->nelements/3;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 9c4f0d790ca..414373742c7 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -51,6 +51,8 @@
#include "BKE_main.h"
#include "BKE_utildefines.h"
+#include "ptex.h"
+
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@@ -777,7 +779,7 @@ static void layerSwap_mcol(void *data, const int *corner_indices)
static void layerDefault_mcol(void *data, int count)
{
- static MCol default_mcol = {255, 255, 255, 255};
+ static MCol default_mcol = {0, 255, 255, 255}; /* abgr */
MCol *mcol = (MCol*)data;
int i;
@@ -785,9 +787,74 @@ static void layerDefault_mcol(void *data, int count)
mcol[i] = default_mcol;
}
+/* Grid */
+
+static void layerCopy_grid(const void *source_v, void *dest_v, int count)
+{
+ const CustomDataMultires *source = source_v;
+ CustomDataMultires *dest = dest_v;
+ int i, j;
+
+ for(i = 0; i < count; ++i) {
+ dest[i].totlayer = source[i].totlayer;
+ dest[i].layers = MEM_callocN(sizeof(CustomDataMultiresLayer) *
+ dest[i].totlayer,
+ "CustomDataMultiresLayers");
+
+ for(j = 0; j < source[i].totlayer; ++j) {
+ CustomDataMultiresLayer *dl = dest[i].layers + j;
+ CustomDataMultiresLayer *sl = source[i].layers + j;
+
+ dl->type = sl->type;
+ dl->griddata = MEM_dupallocN(sl->griddata);
+ BLI_strncpy(dl->name, sl->name, sizeof(dl->name));
+ }
+ }
+}
+
+static void layerFree_grid(void *data_v, int count, int size)
+{
+ CustomDataMultires *data = data_v;
+ int i, j;
+
+ for(i = 0; i < count; ++i) {
+ for(j = 0; j < data[i].totlayer; ++j) {
+ if(data[i].layers[j].griddata)
+ MEM_freeN(data[i].layers[j].griddata);
+ }
+ if(data[i].layers)
+ MEM_freeN(data[i].layers);
+ }
+}
+
+static void layerCopy_mptex(const void *source_v, void *dest_v, int count)
+{
+ const MPtex *source = source_v;
+ MPtex *dest = dest_v;
+ int i, j;
+
+ for(i = 0; i < count; ++i) {
+ dest[i] = source[i];
+ for(j = 0; j < source[i].totsubface; ++j)
+ dest[i].subfaces[j].data = MEM_dupallocN(source[i].subfaces[j].data);
+ }
+}
+
+static void layerFree_mptex(void *data_v, int count, int size)
+{
+ MPtex *data = data_v;
+ int i, j;
+ for(i = 0; i < count; ++i) {
+ for(j = 0; j < data[i].totsubface; ++j) {
+ if(data[i].subfaces[j].data)
+ MEM_freeN(data[i].subfaces[j].data);
+ }
+ }
+}
const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
+ /* 0 */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MSticky), "MSticky", 1, NULL, NULL, NULL, layerInterp_msticky, NULL,
NULL},
@@ -804,6 +871,8 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 3 floats per normal vector */
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+
+ /* 10 */
{sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
{sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
{sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL},
@@ -816,13 +885,22 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps},
+
+ /* 20 */
{sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
- {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
+ {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
- {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
+ {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
- {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}
+ /* CD_CLOTH_ORCO */
+ {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* CD_GRID */
+ {sizeof(CustomDataMultires), "CustomDataMultires", 1, "Grid", layerCopy_grid, layerFree_grid, NULL, NULL, NULL},
+ /* CD_PAINTMASK */
+ {sizeof(float), "", 0, "Mask", NULL, NULL, NULL, NULL, NULL},
+ /* CD_MPTEX */
+ {sizeof(MPtex), "MPtex", 1, "Ptex", layerCopy_mptex, layerFree_mptex, NULL, NULL, NULL},
};
const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -830,7 +908,8 @@ const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
/* 10-14 */ "CDMFloatProperty", "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco",
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
- /* 20-23 */"CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco"
+ /* 20-24 */ "CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDGrid",
+ /* 25-26 */ "CDPaintMask", "CD_PTEX"
};
const CustomDataMask CD_MASK_BAREMESH =
@@ -838,14 +917,17 @@ const CustomDataMask CD_MASK_BAREMESH =
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
- CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
+ CD_MASK_GRIDS | CD_MASK_PAINTMASK | CD_MASK_MPTEX;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
- CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+ CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
+ CD_MASK_MDISPS | CD_MASK_GRIDS | CD_MASK_PAINTMASK | CD_MASK_MPTEX;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
- CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL;
+ CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL |
+ CD_MASK_PAINTMASK;
const CustomDataMask CD_MASK_BMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
const CustomDataMask CD_MASK_FACECORNERS =
@@ -915,6 +997,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
newlayer->active_clone = lastclone;
newlayer->active_mask = lastmask;
newlayer->flag |= lastflag & (CD_FLAG_EXTERNAL|CD_FLAG_IN_MEMORY);
+ if(layer->flag & CD_FLAG_MULTIRES)
+ newlayer->flag |= CD_FLAG_MULTIRES;
}
}
}
@@ -1093,6 +1177,20 @@ int CustomData_get_stencil_layer(const CustomData *data, int type)
return -1;
}
+char *CustomData_get_layer_name_at_offset(const CustomData *data, int type, int offset)
+{
+ int first;
+
+ first = CustomData_get_layer_index(data, type);
+
+ if((first != -1) &&
+ (first + offset < data->totlayer) &&
+ (data->layers[first + offset].type == type))
+ return data->layers[first + offset].name;
+ else
+ return NULL;
+}
+
void CustomData_set_layer_active(CustomData *data, int type, int n)
{
int i;
@@ -1175,6 +1273,17 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
data->layers[i].flag |= flag;
}
+void CustomData_set_layer_offset_flag(struct CustomData *data, int type, int offset, int flag)
+{
+ int first = CustomData_get_layer_index(data, type);
+
+ if((first != -1) &&
+ (first+offset < data->totlayer) &&
+ (data->layers[first+offset].type == type)) {
+ data->layers[first+offset].flag |= flag;
+ }
+}
+
static int customData_resize(CustomData *data, int amount)
{
CustomDataLayer *tmp = MEM_callocN(sizeof(*tmp)*(data->maxlayer + amount),
@@ -1238,8 +1347,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
data->layers[index] = data->layers[index - 1];
data->layers[index].type = type;
- data->layers[index].flag = flag;
+ data->layers[index].flag = flag | CD_FLAG_ENABLED;
data->layers[index].data = newlayerdata;
+ data->layers[index].strength = 1;
if(name || (name=typeInfo->defaultname)) {
strcpy(data->layers[index].name, name);
@@ -1272,7 +1382,7 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
const LayerTypeInfo *typeInfo= layerType_getInfo(type);
layer = customData_add_layer__internal(data, type, alloctype, layerdata,
- totelem, typeInfo->defaultname);
+ totelem, typeInfo->defaultname);
if(layer)
return layer->data;
@@ -1280,6 +1390,32 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
return NULL;
}
+void *CustomData_add_layer_at_offset(CustomData *cd, int type, int alloctype,
+ void *layerdata, int totelem, int offset)
+{
+ int type_first_layer, type_totlayer, i;
+ CustomDataLayer copy_of_new;
+
+ /* add the new layer as normal */
+ CustomData_add_layer(cd, type, alloctype, layerdata, totelem);
+
+ type_first_layer = CustomData_get_layer_index(cd, type);
+ type_totlayer = CustomData_number_of_layers(cd, type);
+
+ /* make a copy of the new layer */
+ copy_of_new = cd->layers[type_first_layer + type_totlayer - 1];
+
+ /* move the old layers up to make room for the new layer */
+ for(i = type_first_layer + type_totlayer - 1;
+ i > type_first_layer + offset; --i)
+ cd->layers[i] = cd->layers[i-1];
+
+ /* copy the new layer into the correct offset */
+ cd->layers[type_first_layer + offset] = copy_of_new;
+
+ return copy_of_new.data;
+}
+
/*same as above but accepts a name*/
void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
void *layerdata, int totelem, const char *name)
@@ -2340,6 +2476,250 @@ int CustomData_verify_versions(struct CustomData *data, int index)
return keeplayer;
}
+/* Multires */
+
+int CustomData_multires_type_totfloat(int type)
+{
+ switch(type) {
+ case CD_MVERT:
+ return 3;
+ case CD_MCOL:
+ return 4;
+ case CD_PAINTMASK:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int customdata_multires_find_first_layer_index(CustomDataMultires *cdm, int type)
+{
+ int i;
+ for(i = 0; i < cdm->totlayer; ++i) {
+ if(cdm->layers[i].type == type)
+ return i;
+ }
+ return -1;
+}
+
+static int customdata_multires_find_named_layer_index(CustomDataMultires *cdm,
+ int type, char *name)
+{
+ int first, i;
+
+ first = customdata_multires_find_first_layer_index(cdm, type);
+
+ if(first != -1) {
+ for(i = first; first < cdm->totlayer; ++i) {
+ if(cdm->layers[i].type != type)
+ break;
+ else if(!strcmp(name, cdm->layers[i].name))
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int CustomData_get_multires_count(CustomData *cd, int type)
+{
+ int first, tot, i;
+
+ first = CustomData_get_layer_index(cd, type);
+ tot = 0;
+
+ if(first != -1) {
+ for(i = first; i < cd->totlayer; ++i) {
+ if(cd->layers[i].type != type)
+ break;
+ if(cd->layers[i].flag & CD_FLAG_MULTIRES)
+ ++tot;
+ }
+ }
+
+ return tot;
+}
+
+void *CustomData_get_multires_names(CustomData *cd, int type)
+{
+ char (*names)[32] = NULL;
+ int count, first;
+
+ count = CustomData_get_multires_count(cd, type);
+
+ if(count) {
+ int layer_ndx, names_ndx;
+
+ names = MEM_callocN(32*count, "CustomData_get_multires_names");
+ first = CustomData_get_layer_index(cd, type);
+ names_ndx = 0;
+
+ for(layer_ndx = first; layer_ndx < cd->totlayer; ++layer_ndx) {
+ CustomDataLayer *cdl = cd->layers + layer_ndx;
+
+ if(cdl->type != type)
+ break;
+ else if(cdl->flag & CD_FLAG_MULTIRES) {
+ BLI_strncpy(names[names_ndx], cdl->name, 32);
+ ++names_ndx;
+ }
+ }
+ }
+
+ return names;
+}
+
+float *CustomData_multires_get_data(CustomDataMultires *cdm, int type,
+ char *name)
+{
+ int layer;
+
+ layer = customdata_multires_find_named_layer_index(cdm, type, name);
+
+ if(layer == -1)
+ return NULL;
+ else
+ return cdm->layers[layer].griddata;
+}
+
+static float *customdata_multires_alloc_griddata(int type, int totelem)
+{
+ return MEM_callocN(sizeof(float) * totelem *
+ CustomData_multires_type_totfloat(type),
+ "CustomDataMultiresLayer.griddata");
+}
+
+void CustomData_multires_sync_layer(CustomDataMultires *cdm, int type,
+ char *name)
+{
+ int layer;
+
+ layer = customdata_multires_find_named_layer_index(cdm, type, name);
+
+ if(layer == -1)
+ CustomData_multires_add_layer_data(cdm, type, name, NULL);
+ else {
+ if(cdm->layers[layer].griddata)
+ MEM_freeN(cdm->layers[layer].griddata);
+ cdm->layers[layer].griddata =
+ customdata_multires_alloc_griddata(type, cdm->totelem);
+ }
+}
+
+void CustomData_multires_add_layer_data(CustomDataMultires *cdm, int type,
+ char *name, float *griddata)
+{
+ CustomDataMultiresLayer *old = cdm->layers;
+ int first, layer, i;
+
+ cdm->layers = MEM_callocN(sizeof(CustomDataMultiresLayer) *
+ (cdm->totlayer + 1),
+ "customdata multires add layer");
+
+ first = customdata_multires_find_first_layer_index(cdm, type);
+
+ /* if no layers of type yet, add new layer at end
+ otherwise add layer at the beginning of the type's segment */
+ if(first == -1)
+ layer = cdm->totlayer;
+ else
+ layer = first;
+
+ /* create griddata if none given */
+ if(!griddata) {
+ griddata =
+ customdata_multires_alloc_griddata(type, cdm->totelem);
+ }
+
+ for(i = 0; i <= cdm->totlayer; ++i) {
+ if(i < layer)
+ cdm->layers[i] = old[i];
+ else if(i == layer) {
+ cdm->layers[i].griddata = griddata;
+ cdm->layers[i].type = type;
+ BLI_strncpy(cdm->layers[i].name, name,
+ sizeof(cdm->layers[i].name));
+ }
+ else if(i > layer)
+ cdm->layers[i] = old[i-1];
+ }
+
+ ++cdm->totlayer;
+ if(old) MEM_freeN(old);
+}
+
+void CustomData_multires_add_layers(CustomDataMultires *cdm, int count,
+ int type, char *name)
+{
+ int i;
+
+ if(!cdm)
+ return;
+
+ for(i = 0; i < count; ++i, ++cdm)
+ CustomData_multires_add_layer_data(cdm, type, name, NULL);
+}
+
+static int CustomData_multires_layer_delete(CustomDataMultires *cdm, int type,
+ char *name)
+{
+ CustomDataMultiresLayer *old = cdm->layers;
+ int layer, i;
+
+ layer = customdata_multires_find_named_layer_index(cdm, type, name);
+
+ if(layer == -1)
+ return 0;
+
+ cdm->layers = MEM_callocN(sizeof(CustomDataMultiresLayer) *
+ (cdm->totlayer - 1),
+ "customdata multires remove layer");
+
+ /* copy over layer data, skipping the removed layer */
+ for(i = 0; i < cdm->totlayer; ++i) {
+ if(i < layer)
+ cdm->layers[i] = old[i];
+ else if(i == layer && old[i].griddata)
+ MEM_freeN(old[i].griddata);
+ else if(i > layer)
+ cdm->layers[i - 1] = old[i];
+ }
+
+ --cdm->totlayer;
+ MEM_freeN(old);
+
+ return 1;
+}
+
+int CustomData_multires_remove_layers(CustomDataMultires *cdm, int count,
+ int type, char *name)
+{
+ int i;
+
+ if(!cdm)
+ return 0;
+
+ for(i = 0; i < count; ++i, ++cdm) {
+ if(!CustomData_multires_layer_delete(cdm, type, name))
+ return 0;
+ }
+
+ return 1;
+}
+
+void CustomData_multires_rename(CustomDataMultires *cdm, int type,
+ char *old_name, char *name)
+{
+ int layer;
+
+ layer = customdata_multires_find_named_layer_index(cdm, type, old_name);
+
+ if(layer != -1) {
+ BLI_strncpy(cdm->layers[layer].name, name,
+ sizeof(cdm->layers[layer].name));
+ }
+}
+
/****************************** External Files *******************************/
static void customdata_external_filename(char filename[FILE_MAX], ID *id, CustomDataExternal *external)
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index b0ab947d478..56914dad6d7 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -57,8 +57,14 @@ static const int multires_max_levels = 13;
static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
static const int multires_side_tot[] = {0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
+typedef enum {
+ APPLY_DISPS,
+ CALC_DISPS,
+ ADD_DISPS,
+} DispOp;
+
static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert);
-static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
+static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DispOp op, DMGridData **oldGridData, int totlvl);
DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
{
@@ -93,7 +99,7 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render)
{
if(render)
return (mmd->modifier.scene)? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl): mmd->renderlvl;
- else if(ob->mode == OB_MODE_SCULPT)
+ else if(ob->mode & OB_MODE_SCULPT)
return mmd->sculptlvl;
else
return (mmd->modifier.scene)? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl): mmd->lvl;
@@ -118,8 +124,10 @@ static void multires_dm_mark_as_modified(DerivedMesh *dm)
void multires_mark_as_modified(Object *ob)
{
- if(ob && ob->derivedFinal)
- multires_dm_mark_as_modified(ob->derivedFinal);
+ DerivedMesh *dm = ob->derivedFinal;
+
+ if(ob && dm && dm->type == DM_TYPE_CCGDM)
+ multires_dm_mark_as_modified(dm);
}
void multires_force_update(Object *ob)
@@ -130,9 +138,9 @@ void multires_force_update(Object *ob)
ob->derivedFinal->release(ob->derivedFinal);
ob->derivedFinal = NULL;
}
- if(ob->sculpt && ob->sculpt->pbvh) {
- BLI_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh= NULL;
+ if(ob->paint && ob->paint->pbvh) {
+ BLI_pbvh_free(ob->paint->pbvh);
+ ob->paint->pbvh= NULL;
}
}
}
@@ -324,10 +332,43 @@ static void multires_set_tot_mdisps(Mesh *me, int lvl)
}
}
+/* ensure all the layers needed by the gridkey have
+ a matching multires layer
+
+ clear and resize the all griddata to match the level
+*/
+static void multires_sync_customdata(Mesh *me, GridKey *gridkey,
+ int lvl)
+{
+ CustomDataMultires *cd_grids;
+ int i, j;
+
+ cd_grids = CustomData_get_layer(&me->fdata, CD_GRIDS);
+ if(!cd_grids)
+ cd_grids = CustomData_add_layer(&me->fdata, CD_GRIDS,
+ CD_CALLOC, NULL, me->totface);
+
+ for(i = 0; i < me->totface; ++i) {
+ int nvert = (me->mface[i].v4)? 4: 3;
+ int totelem = multires_grid_tot[lvl]*nvert;
+
+ cd_grids[i].totelem = totelem;
+
+ for(j = 0; j < gridkey->mask; ++j) {
+ CustomData_multires_sync_layer(cd_grids+i,
+ CD_PAINTMASK,
+ gridkey->mask_names[j]);
+ }
+ }
+}
+
+/* TODO: removed this in favor of sync_customdata */
static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
{
int i;
+ /* This will be replaced when we do CD_DISPS */
+
/* reallocate displacements to be filled in */
for(i = 0; i < me->totface; ++i) {
int nvert = (me->mface[i].v4)? 4: 3;
@@ -369,23 +410,24 @@ static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], int sizeA,
}
}
-static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, int sizeA, int sizeB)
+static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, GridKey *gridkey, int sizeA, int sizeB)
{
int x, y, j, skip;
+ int size = sizeof(float)*GRIDELEM_INTERP_COUNT(gridkey);
if(sizeA > sizeB) {
skip = (sizeA-1)/(sizeB-1);
for(j = 0, y = 0; y < sizeB; y++)
for(x = 0; x < sizeB; x++, j++)
- copy_v3_v3(gridA[y*skip*sizeA + x*skip].co, gridB[j].co);
+ memcpy(GRIDELEM_AT(gridA, y*skip*sizeA + x*skip, gridkey), GRIDELEM_AT(gridB, j, gridkey), size);
}
else {
skip = (sizeB-1)/(sizeA-1);
for(j = 0, y = 0; y < sizeA; y++)
for(x = 0; x < sizeA; x++, j++)
- copy_v3_v3(gridA[j].co, gridB[y*skip*sizeB + x*skip].co);
+ memcpy(GRIDELEM_AT(gridA, j, gridkey), GRIDELEM_AT(gridB, y*skip*sizeB + x*skip, gridkey), size);
}
}
@@ -442,7 +484,9 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
multires_set_tot_level(ob, mmd, lvl);
}
-static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple)
+static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm,
+ GridKey *gridkey, int lvl,
+ int totlvl, int simple)
{
MultiresModifierData mmd;
@@ -453,13 +497,32 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
mmd.totlvl = totlvl;
mmd.simple = simple;
- return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0);
+ return multires_dm_create_from_derived(&mmd, 1, dm, ob, gridkey, 0, 0);
}
-static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm, int lvl, int simple, int optimal)
+static void init_gridkey_from_customdata(GridKey *gridkey,
+ CustomData *vdata,
+ CustomData *UNUSED(fdata))
{
+ GRIDELEM_KEY_INIT(gridkey, 1, 0,
+ CustomData_get_multires_count(vdata, CD_PAINTMASK),
+ 1);
+
+ gridkey->mask_names = CustomData_get_multires_names(vdata,
+ CD_PAINTMASK);
+
+}
+
+static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm,
+ GridKey *gridkey, int lvl,
+ int simple, int optimal)
+{
+ DerivedMesh *result;
+ Mesh *me = get_mesh(ob);
SubsurfModifierData smd;
+ GridKey default_gridkey;
+ memset(&default_gridkey, 0, sizeof(GridKey));
memset(&smd, 0, sizeof(SubsurfModifierData));
smd.levels = smd.renderLevels = lvl;
smd.flags |= eSubsurfModifierFlag_SubsurfUv;
@@ -468,7 +531,149 @@ static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm,
if(optimal)
smd.flags |= eSubsurfModifierFlag_ControlEdges;
- return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0);
+ if(!gridkey) {
+ init_gridkey_from_customdata(&default_gridkey,
+ &me->vdata, &me->fdata);
+ gridkey = &default_gridkey;
+ }
+
+ result = subsurf_make_derived_from_derived(dm, &smd, gridkey, 0, NULL, 0, 0);
+
+ if(default_gridkey.color_names) MEM_freeN(default_gridkey.color_names);
+ if(default_gridkey.mask_names) MEM_freeN(default_gridkey.mask_names);
+
+ return result;
+}
+
+/* assumes no is normalized; return value's sign is negative if v is on
+ the other side of the plane */
+static float v3_dist_from_plane(float v[3], float center[3], float no[3])
+{
+ float s[3];
+ sub_v3_v3v3(s, v, center);
+ return dot_v3v3(s, no);
+}
+
+void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
+{
+ DerivedMesh *cddm, *dispdm, *origdm;
+ GridKey gridkey;
+ Mesh *me;
+ ListBase *fmap;
+ float (*origco)[3];
+ int i, j, offset, totlvl;
+
+ multires_force_update(ob);
+
+ me = get_mesh(ob);
+ totlvl = mmd->totlvl;
+
+ /* only need vert/norm grid data */
+ GRIDELEM_KEY_INIT(&gridkey, 1, 0, 0, 1);
+
+ /* XXX - probably not necessary to regenerate the cddm so much? */
+
+ /* generate highest level with displacements */
+ cddm = CDDM_from_mesh(me, NULL);
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+ dispdm = multires_dm_create_local(ob, cddm, &gridkey, totlvl, totlvl, 0);
+ cddm->release(cddm);
+
+ /* copy the new locations of the base verts into the mesh */
+ offset = dispdm->getNumVerts(dispdm) - me->totvert;
+ for(i = 0; i < me->totvert; ++i) {
+ dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
+ }
+
+ /* heuristic to produce a better-fitting base mesh */
+ cddm = CDDM_from_mesh(me, NULL);
+ fmap = cddm->getFaceMap(ob, cddm);
+ origco = MEM_callocN(sizeof(float)*3*me->totvert, "multires apply base origco");
+ for(i = 0; i < me->totvert ;++i)
+ copy_v3_v3(origco[i], me->mvert[i].co);
+
+ for(i = 0; i < me->totvert; ++i) {
+ IndexNode *n;
+ float avg_no[3] = {0,0,0}, center[3] = {0,0,0}, push[3];
+ float dist;
+ int tot;
+
+ /* Don't adjust verts not used by at least one face */
+ if(!fmap[i].first)
+ continue;
+
+ /* find center */
+ for(n = fmap[i].first, tot = 0; n; n = n->next) {
+ MFace *f = &me->mface[n->index];
+ int S = f->v4 ? 4 : 3;
+
+ /* this double counts, not sure if that's bad or good */
+ for(j = 0; j < S; ++j) {
+ int vndx = (&f->v1)[j];
+ if(vndx != i) {
+ add_v3_v3(center, origco[vndx]);
+ ++tot;
+ }
+ }
+ }
+ mul_v3_fl(center, 1.0f / tot);
+
+ /* find normal */
+ for(n = fmap[i].first; n; n = n->next) {
+ MFace *f = &me->mface[n->index];
+ int S = f->v4 ? 4 : 3;
+ float v[4][3], no[3];
+
+ for(j = 0; j < S; ++j) {
+ int vndx = (&f->v1)[j];
+ if(vndx == i)
+ copy_v3_v3(v[j], center);
+ else
+ copy_v3_v3(v[j], origco[vndx]);
+ }
+
+ if(S == 4)
+ normal_quad_v3(no, v[0], v[1], v[2], v[3]);
+ else
+ normal_tri_v3(no, v[0], v[1], v[2]);
+ add_v3_v3(avg_no, no);
+ }
+ normalize_v3(avg_no);
+
+ /* push vertex away from the plane */
+ dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no);
+ copy_v3_v3(push, avg_no);
+ mul_v3_fl(push, dist);
+ add_v3_v3(me->mvert[i].co, push);
+
+ }
+
+ MEM_freeN(origco);
+ cddm->release(cddm);
+
+ /* subdivide the mesh to highest level without displacements */
+ cddm = CDDM_from_mesh(me, NULL);
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+ origdm = subsurf_dm_create_local(ob, cddm, &gridkey, totlvl, 0, 0);
+ cddm->release(cddm);
+
+ multiresModifier_disp_run(dispdm, me, CALC_DISPS, origdm->getGridData(origdm), totlvl);
+
+ origdm->release(origdm);
+ dispdm->release(dispdm);
+}
+
+static DMGridData **copy_grids(DMGridData **grids, int totgrid, int gridsize, GridKey *gridkey)
+{
+ DMGridData **grids_copy = MEM_callocN(sizeof(DMGridData*) * totgrid, "subgrids");
+ int i;
+
+ for(i = 0; i < totgrid; ++i) {
+ grids_copy[i] = MEM_callocN(GRIDELEM_SIZE(gridkey)*gridsize*gridsize, "subgrid");
+ memcpy(grids_copy[i], grids[i], GRIDELEM_SIZE(gridkey)*gridsize*gridsize);
+ }
+
+ return grids_copy;
}
void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
@@ -493,14 +698,16 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
DMGridData **highGridData, **lowGridData, **subGridData;
CCGSubSurf *ss;
int i, numGrids, highGridSize, lowGridSize;
+ GridKey *gridkey;
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0);
+ highdm = subsurf_dm_create_local(ob, cddm, NULL, totlvl, simple, 0);
+ gridkey = highdm->getGridKey(highdm);
/* create multires DM from original mesh at low level */
- lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple);
+ lowdm = multires_dm_create_local(ob, cddm, NULL, lvl, lvl, simple);
cddm->release(cddm);
/* copy subsurf grids and replace them with low displaced grids */
@@ -510,16 +717,12 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
lowGridSize = lowdm->getGridSize(lowdm);
lowGridData = lowdm->getGridData(lowdm);
- subGridData = MEM_callocN(sizeof(float*)*numGrids, "subGridData*");
-
- for(i = 0; i < numGrids; ++i) {
- /* backup subsurf grids */
- subGridData[i] = MEM_callocN(sizeof(DMGridData)*highGridSize*highGridSize, "subGridData");
- memcpy(subGridData[i], highGridData[i], sizeof(DMGridData)*highGridSize*highGridSize);
+ /* backup subsurf grids */
+ subGridData = copy_grids(highGridData, numGrids, highGridSize, gridkey);
- /* overwrite with current displaced grids */
- multires_copy_dm_grid(highGridData[i], lowGridData[i], highGridSize, lowGridSize);
- }
+ /* overwrite with current displaced grids */
+ for(i = 0; i < numGrids; ++i)
+ multires_copy_dm_grid(highGridData[i], lowGridData[i], gridkey, highGridSize, lowGridSize);
/* low lower level dm no longer needed at this point */
lowdm->release(lowdm);
@@ -531,9 +734,10 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
/* reallocate displacements */
multires_reallocate_mdisps(me, mdisps, totlvl);
+ multires_sync_customdata(me, gridkey, totlvl);
/* compute displacements */
- multiresModifier_disp_run(highdm, me, 1, 0, subGridData, totlvl);
+ multiresModifier_disp_run(highdm, me, CALC_DISPS, subGridData, totlvl);
/* free */
highdm->release(highdm);
@@ -542,48 +746,107 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
MEM_freeN(subGridData);
}
else {
+ /* XXX: I think this can be safely removed, we already check in
+ disp run for unallocated disps -- nicholas */
+
/* only reallocate, nothing to upsample */
- multires_reallocate_mdisps(me, mdisps, totlvl);
+ //multires_reallocate_mdisps(me, mdisps, totlvl);
}
multires_set_tot_level(ob, mmd, totlvl);
}
-static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
+static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, GridKey *gridkey, float t[3])
{
+ DMGridData *grid = gridData[index];
+
if(axis == 0) {
if(x == gridSize - 1) {
if(y == gridSize - 1)
- sub_v3_v3v3(t, gridData[index][x + gridSize*(y - 1)].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
+ sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*(y - 1), gridkey), GRIDELEM_CO_AT(grid, x - 1 + gridSize*(y - 1), gridkey));
else
- sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x - 1 + gridSize*y].co);
+ sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x - 1 + gridSize*y, gridkey));
}
else
- sub_v3_v3v3(t, gridData[index][x + 1 + gridSize*y].co, gridData[index][x + gridSize*y].co);
+ sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + 1 + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey));
}
else if(axis == 1) {
if(y == gridSize - 1) {
if(x == gridSize - 1)
- sub_v3_v3v3(t, gridData[index][x - 1 + gridSize*y].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
+ sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x - 1 + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x - 1 + gridSize*(y - 1), gridkey));
else
- sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x + gridSize*(y - 1)].co);
+ sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x + gridSize*(y - 1), gridkey));
}
else
- sub_v3_v3v3(t, gridData[index][x + gridSize*(y + 1)].co, gridData[index][x + gridSize*y].co);
+ sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*(y + 1), gridkey), GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey));
+ }
+}
+
+#if 0
+static void debug_print_paintmask_grids(CustomData *grids, int gridsize)
+{
+ float *pmask;
+ int x, y;
+
+ printf("debug_print_paintmask_grids:\n");
+ pmask = CustomData_get_layer(grids, CD_PAINTMASK);
+
+ for(y = 0; y < gridsize; ++y) {
+ for(x = 0; x < gridsize; ++x, ++pmask)
+ printf("%.2f ", *pmask);
+ printf("\n");
}
+
+ printf("\n");
+}
+#endif
+
+/* XXX - move these to blenlib? */
+void add_v4_v4v4(float v[4], float a[4], float b[4])
+{
+ v[0] = a[0] + b[0];
+ v[1] = a[1] + b[1];
+ v[2] = a[2] + b[2];
+ v[3] = a[3] + b[3];
+}
+
+void add_v4_v4(float v[4], float a[4])
+{
+ v[0] += a[0];
+ v[1] += a[1];
+ v[2] += a[2];
+ v[3] += a[3];
}
-static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl)
+void sub_v4_v4v4(float v[4], float a[4], float b[4])
+{
+ v[0] = a[0] - b[0];
+ v[1] = a[1] - b[1];
+ v[2] = a[2] - b[2];
+ v[3] = a[3] - b[3];
+}
+
+void clamp_v4_fl(float v[4], float min, float max)
+{
+ CLAMP(v[0], min, max);
+ CLAMP(v[1], min, max);
+ CLAMP(v[2], min, max);
+ CLAMP(v[3], min, max);
+}
+
+static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DispOp op, DMGridData **oldGridData, int totlvl)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
DMGridData **gridData, **subGridData;
MFace *mface = me->mface;
MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ CustomDataMultires *stored_grids;
int *gridOffset;
+ GridKey *gridkey;
int i, numGrids, gridSize, dGridSize, dSkip;
if(!mdisps) {
- if(invert)
+ if(op == CALC_DISPS)
mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
else
return;
@@ -594,15 +857,18 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
gridData = dm->getGridData(dm);
gridOffset = dm->getGridOffset(dm);
subGridData = (oldGridData)? oldGridData: gridData;
+ gridkey = dm->getGridKey(dm);
dGridSize = multires_side_tot[totlvl];
dSkip = (dGridSize-1)/(gridSize-1);
+ stored_grids = CustomData_get_layer(&me->fdata, CD_GRIDS);
+
#pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT)
for(i = 0; i < me->totface; ++i) {
const int numVerts = mface[i].v4 ? 4 : 3;
MDisps *mdisp = &mdisps[i];
- int S, x, y, gIndex = gridOffset[i];
+ int S, x, y, j, gIndex = gridOffset[i];
/* when adding new faces in edit mode, need to allocate disps */
if(!mdisp->disps)
@@ -610,56 +876,99 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
{
multires_reallocate_mdisps(me, mdisps, totlvl);
}
+
+ /* XXX: this doesn't cover all the cases */
+ if((gridkey->mask || gridkey->color) && !stored_grids)
+ #pragma omp critical
+ {
+ multires_sync_customdata(me, gridkey, totlvl);
+ stored_grids = CustomData_get_layer(&me->fdata, CD_GRIDS);
+ }
for(S = 0; S < numVerts; ++S, ++gIndex) {
DMGridData *grid = gridData[gIndex];
DMGridData *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = &mdisp->disps[S*dGridSize*dGridSize];
+ int stored_index = S*dGridSize*dGridSize;
+ float (*dispgrid)[3] = &mdisp->disps[stored_index];
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
- float *co = grid[x + y*gridSize].co;
- float *sco = subgrid[x + y*gridSize].co;
- float *no = subgrid[x + y*gridSize].no;
- float *data = dispgrid[dGridSize*y*dSkip + x*dSkip];
- float mat[3][3], tx[3], ty[3], disp[3], d[3];
+ int ccgdm_offset = x + y*gridSize;
+ int stored_offset = dGridSize*y*dSkip + x*dSkip;
+
+ float *co = GRIDELEM_CO_AT(grid, ccgdm_offset, gridkey);
+ float *sco = GRIDELEM_CO_AT(subgrid, ccgdm_offset, gridkey);
+ float *no = GRIDELEM_NO_AT(subgrid, ccgdm_offset, gridkey);
+ float *data = dispgrid[stored_offset];
+
+ float tan_to_ob_mat[3][3], tx[3], ty[3], disp[3], d[3];
/* construct tangent space matrix */
- grid_tangent(gridSize, gIndex, x, y, 0, subGridData, tx);
+ grid_tangent(gridSize, gIndex, x, y, 0, subGridData, gridkey, tx);
normalize_v3(tx);
- grid_tangent(gridSize, gIndex, x, y, 1, subGridData, ty);
+ grid_tangent(gridSize, gIndex, x, y, 1, subGridData, gridkey, ty);
normalize_v3(ty);
//mul_v3_fl(tx, 1.0f/(gridSize-1));
//mul_v3_fl(ty, 1.0f/(gridSize-1));
//cross_v3_v3v3(no, tx, ty);
- column_vectors_to_mat3(mat, tx, ty, no);
+ column_vectors_to_mat3(tan_to_ob_mat, tx, ty, no);
- if(!invert) {
- /* convert to object space and add */
- mul_v3_m3v3(disp, mat, data);
+ switch(op) {
+ case APPLY_DISPS:
+ /* Convert displacement to object space
+ and add to grid points */
+ mul_v3_m3v3(disp, tan_to_ob_mat, data);
add_v3_v3v3(co, sco, disp);
- }
- else if(!add) {
- /* convert difference to tangent space */
+ break;
+ case CALC_DISPS:
+ /* Calculate displacement between new and old
+ grid points and convert to tangent space. */
sub_v3_v3v3(disp, co, sco);
- invert_m3(mat);
- mul_v3_m3v3(data, mat, disp);
- }
- else {
- /* convert difference to tangent space */
- invert_m3(mat);
- mul_v3_m3v3(d, mat, co);
+ invert_m3(tan_to_ob_mat);
+ mul_v3_m3v3(data, tan_to_ob_mat, disp);
+ break;
+ case ADD_DISPS:
+ /* Convert subdivided displacements to tangent
+ space and add to the original displacements */
+ invert_m3(tan_to_ob_mat);
+ mul_v3_m3v3(d, tan_to_ob_mat, co);
add_v3_v3(data, d);
+ break;
+ }
+
+ /* Paint Masks */
+ for(j = 0; j < gridkey->mask; ++j) {
+ float *mask = &GRIDELEM_MASK_AT(grid, ccgdm_offset, gridkey)[j];
+ float *smask = &GRIDELEM_MASK_AT(subgrid, ccgdm_offset, gridkey)[j];
+ float *stored_mask_layer =
+ CustomData_multires_get_data(&stored_grids[i],
+ CD_PAINTMASK,
+ gridkey->mask_names[j]);
+ float *stored_mask = &stored_mask_layer[stored_index];
+
+ switch(op) {
+ case APPLY_DISPS:
+ *mask = *smask + stored_mask[stored_offset];
+ break;
+ case CALC_DISPS:
+ stored_mask[stored_offset] = *mask - *smask;
+ CLAMP(stored_mask[stored_offset], 0, 1);
+ break;
+ case ADD_DISPS:
+ stored_mask[stored_offset] += *mask;
+ CLAMP(stored_mask[stored_offset], 0, 1);
+ break;
+ }
}
}
}
}
}
- if(!invert) {
+ if(op == APPLY_DISPS) {
ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
}
@@ -672,6 +981,7 @@ static void multiresModifier_update(DerivedMesh *dm)
Mesh *me;
MDisps *mdisps;
MultiresModifierData *mmd;
+ GridKey *gridkey;
ob = ccgdm->multires.ob;
me = ccgdm->multires.ob->data;
@@ -680,6 +990,10 @@ static void multiresModifier_update(DerivedMesh *dm)
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ /* use the same gridkey as the dm so that we don't try
+ to update layers that didn't exist before */
+ gridkey = dm->getGridKey(dm);
+
if(mdisps) {
int lvl = ccgdm->multires.lvl;
int totlvl = ccgdm->multires.totlvl;
@@ -696,10 +1010,10 @@ static void multiresModifier_update(DerivedMesh *dm)
else cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0);
+ highdm = subsurf_dm_create_local(ob, cddm, gridkey, totlvl, mmd->simple, 0);
/* create multires DM from original mesh and displacements */
- lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple);
+ lowdm = multires_dm_create_local(ob, cddm, gridkey, lvl, totlvl, mmd->simple);
cddm->release(cddm);
/* gather grid data */
@@ -710,19 +1024,20 @@ static void multiresModifier_update(DerivedMesh *dm)
lowGridData = lowdm->getGridData(lowdm);
gridData = dm->getGridData(dm);
- subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
- diffGrid = MEM_callocN(sizeof(DMGridData)*lowGridSize*lowGridSize, "diff");
+ /* backup subsurf grids */
+ subGridData = copy_grids(highGridData, numGrids, highGridSize, gridkey);
- for(i = 0; i < numGrids; ++i) {
- /* backup subsurf grids */
- subGridData[i] = MEM_callocN(sizeof(DMGridData)*highGridSize*highGridSize, "subGridData");
- memcpy(subGridData[i], highGridData[i], sizeof(DMGridData)*highGridSize*highGridSize);
+ diffGrid = MEM_callocN(GRIDELEM_SIZE(gridkey)*lowGridSize*lowGridSize, "diff");
- /* write difference of subsurf and displaced low level into high subsurf */
- for(j = 0; j < lowGridSize*lowGridSize; ++j)
- sub_v3_v3v3(diffGrid[j].co, gridData[i][j].co, lowGridData[i][j].co);
+ /* write difference of subsurf and displaced low level into high subsurf */
+ for(i = 0; i < numGrids; ++i) {
+ for(j = 0; j < lowGridSize*lowGridSize; ++j) {
+ int k;
+ for(k = 0; k < GRIDELEM_INTERP_COUNT(gridkey); ++k)
+ ((float*)GRIDELEM_AT(diffGrid, j, gridkey))[k] = ((float*)GRIDELEM_AT(gridData[i], j, gridkey))[k] - ((float*)GRIDELEM_AT(lowGridData[i], j, gridkey))[k];
+ }
- multires_copy_dm_grid(highGridData[i], diffGrid, highGridSize, lowGridSize);
+ multires_copy_dm_grid(highGridData[i], diffGrid, gridkey, highGridSize, lowGridSize);
}
/* lower level dm no longer needed at this point */
@@ -735,7 +1050,7 @@ static void multiresModifier_update(DerivedMesh *dm)
ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
/* add to displacements */
- multiresModifier_disp_run(highdm, me, 1, 1, subGridData, mmd->totlvl);
+ multiresModifier_disp_run(highdm, me, ADD_DISPS, subGridData, mmd->totlvl);
/* free */
highdm->release(highdm);
@@ -750,10 +1065,10 @@ static void multiresModifier_update(DerivedMesh *dm)
else cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0);
+ subdm = subsurf_dm_create_local(ob, cddm, gridkey, mmd->totlvl, mmd->simple, 0);
cddm->release(cddm);
- multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
+ multiresModifier_disp_run(dm, me, CALC_DISPS, subdm->getGridData(subdm), mmd->totlvl);
subdm->release(subdm);
}
@@ -762,8 +1077,15 @@ static void multiresModifier_update(DerivedMesh *dm)
void multires_stitch_grids(Object *ob)
{
- /* utility for smooth brush */
- if(ob && ob->derivedFinal) {
+ DerivedMesh *dm;
+
+ if(!ob)
+ return;
+
+ dm = ob->derivedFinal;
+
+ /* utility for smooth/blur brushes */
+ if(dm && dm->type == DM_TYPE_CCGDM) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)ob->derivedFinal;
CCGFace **faces;
int totface;
@@ -772,6 +1094,7 @@ void multires_stitch_grids(Object *ob)
BLI_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void***)&faces, &totface);
if(totface) {
+ /* TODO: could improve performance by limiting to e.g. just coords or just colors */
ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
MEM_freeN(faces);
}
@@ -780,7 +1103,7 @@ void multires_stitch_grids(Object *ob)
}
DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
- int useRenderParams, int UNUSED(isFinalCalc))
+ GridKey *gridkey, int useRenderParams, int UNUSED(isFinalCalc))
{
Mesh *me= ob->data;
DerivedMesh *result;
@@ -792,7 +1115,7 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
if(lvl == 0)
return dm;
- result = subsurf_dm_create_local(ob, dm, lvl,
+ result = subsurf_dm_create_local(ob, dm, gridkey, lvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges);
if(!local_mmd) {
@@ -810,17 +1133,19 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
numGrids = result->getNumGrids(result);
gridSize = result->getGridSize(result);
gridData = result->getGridData(result);
+ /* null gridkey can be passed in, so update it here */
+ gridkey = result->getGridKey(result);
subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
for(i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_callocN(sizeof(DMGridData)*gridSize*gridSize, "subGridData");
- memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
+ subGridData[i] = MEM_callocN(GRIDELEM_SIZE(gridkey)*gridSize*gridSize, "subGridData");
+ memcpy(subGridData[i], gridData[i], GRIDELEM_SIZE(gridkey)*gridSize*gridSize);
}
multires_set_tot_mdisps(me, mmd->totlvl);
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
- multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
+ multiresModifier_disp_run(result, ob->data, APPLY_DISPS, subGridData, mmd->totlvl);
for(i = 0; i < numGrids; i++)
MEM_freeN(subGridData[i]);
@@ -829,6 +1154,7 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
return result;
}
+
/**** Old Multires code ****
***************************/
@@ -1109,13 +1435,13 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
vd= ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(vd->co, mvert[i].co);
+ copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
i++;
for(S = 0; S < numVerts; S++) {
for(x = 1; x < gridSize - 1; x++, i++) {
vd= ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
- copy_v3_v3(vd->co, mvert[i].co);
+ copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
}
}
@@ -1123,7 +1449,7 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
for(y = 1; y < gridSize - 1; y++) {
for(x = 1; x < gridSize - 1; x++, i++) {
vd= ccgSubSurf_getFaceGridData(ss, f, S, x, y);
- copy_v3_v3(vd->co, mvert[i].co);
+ copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
}
}
}
@@ -1136,7 +1462,7 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
for(x = 1; x < edgeSize - 1; x++, i++) {
vd= ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(vd->co, mvert[i].co);
+ copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
}
}
@@ -1145,7 +1471,7 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
CCGVert *v = ccgdm->vertMap[index].vert;
vd= ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(vd->co, mvert[i].co);
+ copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
i++;
}
@@ -1364,7 +1690,7 @@ void multires_load_old(Object *ob, Mesh *me)
mmd->lvl = mmd->totlvl;
orig = CDDM_from_mesh(me, NULL);
- dm = multires_dm_create_from_derived(mmd, 0, orig, ob, 0, 0);
+ dm = multires_dm_create_from_derived(mmd, 0, orig, ob, NULL, 0, 0);
multires_load_old_dm(dm, me, mmd->totlvl+1);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 5237335e8ca..40ba7db7305 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -228,29 +228,6 @@ void object_free_display(Object *ob)
freedisplist(&ob->disp);
}
-void free_sculptsession(Object *ob)
-{
- if(ob && ob->sculpt) {
- SculptSession *ss = ob->sculpt;
- DerivedMesh *dm= ob->derivedFinal;
-
- if(ss->pbvh)
- BLI_pbvh_free(ss->pbvh);
- if(dm && dm->getPBVH)
- dm->getPBVH(NULL, dm); /* signal to clear */
-
- if(ss->texcache)
- MEM_freeN(ss->texcache);
-
- if(ss->layer_co)
- MEM_freeN(ss->layer_co);
-
- MEM_freeN(ss);
-
- ob->sculpt = NULL;
- }
-}
-
/* do not free object itself */
void free_object(Object *ob)
{
@@ -305,7 +282,7 @@ void free_object(Object *ob)
if(ob->bsoft) bsbFree(ob->bsoft);
if(ob->gpulamp.first) GPU_lamp_free(ob);
- free_sculptsession(ob);
+ free_paintsession(ob);
if(ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
}
@@ -1319,7 +1296,7 @@ Object *copy_object(Object *ob)
copy_constraints(&obn->constraints, &ob->constraints, TRUE);
obn->mode = 0;
- obn->sculpt = NULL;
+ obn->paint = NULL;
/* increase user numbers */
id_us_plus((ID *)obn->data);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 116ed3c8ef2..dad835d531e 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -25,6 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
@@ -33,9 +34,16 @@
#include "BKE_utildefines.h"
#include "BKE_brush.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
#include "BKE_library.h"
#include "BKE_paint.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_listbase.h"
+#include "BLI_pbvh.h"
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -110,3 +118,104 @@ void copy_paint(Paint *src, Paint *tar)
{
tar->brush= src->brush;
}
+
+/* Update the mask without doing a full object recalc */
+void paint_refresh_mask_display(Object *ob)
+{
+ if(ob && ob->paint && ob->paint->pbvh) {
+ BLI_pbvh_search_callback(ob->paint->pbvh, NULL, NULL,
+ BLI_pbvh_node_set_flags,
+ SET_INT_IN_POINTER(PBVH_UpdateColorBuffers));
+ }
+}
+
+
+float paint_mask_from_gridelem(DMGridData *elem, GridKey *gridkey,
+ CustomData *vdata)
+{
+ CustomDataLayer *cdl;
+ float mask = 0;
+ int i, ndx;
+
+ for(i=0; i < gridkey->mask; ++i) {
+ ndx = CustomData_get_named_layer_index(vdata,
+ CD_PAINTMASK,
+ gridkey->mask_names[i]);
+ cdl = &vdata->layers[ndx];
+
+ if(!(cdl->flag & CD_FLAG_ENABLED))
+ continue;
+
+ mask += GRIDELEM_MASK(elem, gridkey)[i] * cdl->strength;
+ }
+
+ CLAMP(mask, 0, 1);
+
+ return mask;
+}
+
+float paint_mask_from_vertex(CustomData *vdata, int vertex_index,
+ int pmask_totlayer, int pmask_first_layer)
+{
+ float mask = 0;
+ int i;
+
+ for(i = 0; i < pmask_totlayer; ++i) {
+ CustomDataLayer *cdl= vdata->layers + pmask_first_layer + i;
+
+ if(!(cdl->flag & CD_FLAG_ENABLED))
+ continue;
+
+ mask += ((float*)cdl->data)[vertex_index] * cdl->strength;
+ }
+
+ CLAMP(mask, 0, 1);
+
+ return mask;
+}
+
+void create_paintsession(Object *ob)
+{
+ if(ob->paint)
+ free_paintsession(ob);
+
+ ob->paint = MEM_callocN(sizeof(PaintSession), "PaintSession");
+}
+
+static void free_sculptsession(PaintSession *ps)
+{
+ if(ps && ps->sculpt) {
+ SculptSession *ss = ps->sculpt;
+
+ BLI_freelistN(&ss->hidden_areas);
+
+ if(ss->texcache)
+ MEM_freeN(ss->texcache);
+
+ if(ss->layer_co)
+ MEM_freeN(ss->layer_co);
+
+ MEM_freeN(ss);
+
+ ps->sculpt = NULL;
+ }
+}
+
+void free_paintsession(Object *ob)
+{
+ if(ob && ob->paint) {
+ PaintSession *ps = ob->paint;
+ DerivedMesh *dm= ob->derivedFinal;
+
+ free_sculptsession(ps);
+
+ if(ps->pbvh)
+ BLI_pbvh_free(ps->pbvh);
+
+ if(dm && dm->getPBVH)
+ dm->getPBVH(NULL, dm); /* signal to clear PBVH */
+
+ MEM_freeN(ps);
+ ob->paint = NULL;
+ }
+}
diff --git a/source/blender/blenkernel/intern/ptex.c b/source/blender/blenkernel/intern/ptex.c
new file mode 100644
index 00000000000..72218830446
--- /dev/null
+++ b/source/blender/blenkernel/intern/ptex.c
@@ -0,0 +1,445 @@
+/*
+ * $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 yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
+#include "BKE_mesh.h"
+#include "BKE_subsurf.h"
+
+#include "BLI_math.h"
+
+#include "ptex.h"
+
+#include <assert.h>
+
+DerivedMesh *quad_dm_create_from_derived(DerivedMesh *dm)
+{
+ DerivedMesh *ccgdm;
+ SubsurfModifierData smd;
+ GridKey gridkey;
+
+ memset(&smd, 0, sizeof(SubsurfModifierData));
+ smd.levels = 1;
+ smd.subdivType = ME_SIMPLE_SUBSURF;
+ GRIDELEM_KEY_INIT(&gridkey, 1, 0, 0, 1);
+ ccgdm = subsurf_make_derived_from_derived(dm, &smd, &gridkey,
+ 0, NULL, 0, 0);
+
+ return ccgdm;
+}
+
+void ptex_elem_to_floats(int type, int channels, void *data, float *out)
+{
+ int i;
+
+ switch(type) {
+ case PTEX_DT_UINT8:
+ for(i = 0; i < channels; ++i)
+ out[i] = ((unsigned char*)data)[i] / 255.0;
+ break;
+ case PTEX_DT_UINT16:
+ for(i = 0; i < channels; ++i)
+ out[i] = ((unsigned char*)data)[i] / 65535.0;
+ break;
+ case PTEX_DT_FLOAT:
+ for(i = 0; i < channels; ++i)
+ out[i] = ((float*)data)[i];
+ break;
+ default:
+ break;
+ }
+}
+
+void ptex_elem_from_floats(int type, int channels, void *data, float *in)
+{
+ int i;
+
+ switch(type) {
+ case PTEX_DT_UINT8:
+ for(i = 0; i < channels; ++i)
+ ((unsigned char*)data)[i] = in[i] * 255;
+ break;
+ case PTEX_DT_UINT16:
+ for(i = 0; i < channels; ++i)
+ ((unsigned short*)data)[i] = in[i] * 65535;
+ break;
+ case PTEX_DT_FLOAT:
+ for(i = 0; i < channels; ++i)
+ ((float*)data)[i] = in[i];
+ break;
+ default:
+ break;
+ }
+}
+
+static void ptex_elem_to_floats_mul_add(MPtex *pt, void *data, float *out, float fac)
+{
+ int i;
+
+ switch(pt->type) {
+ case PTEX_DT_UINT8:
+ for(i = 0; i < pt->channels; ++i)
+ out[i] += (((unsigned char*)data)[i] / 255.0) * fac;
+ break;
+ case PTEX_DT_UINT16:
+ for(i = 0; i < pt->channels; ++i)
+ out[i] += (((unsigned char*)data)[i] / 65535.0) * fac;
+ break;
+ case PTEX_DT_FLOAT:
+ for(i = 0; i < pt->channels; ++i)
+ out[i] += ((float*)data)[i] * fac;
+ break;
+ default:
+ break;
+ }
+}
+
+/* get interpolated value for one texel */
+static void ptex_bilinear_interp(MPtex *pt, MPtexSubface *subface,
+ void *out, int layersize,
+ float x, float y, float *tmp)
+{
+ char *input_start = subface->data;
+ int rowlen = subface->res[0];
+ int xi = (int)x;
+ int yi = (int)y;
+ int xt = xi+1, yt = yi+1;
+ float s = x - xi;
+ float t = y - yi;
+ float u = 1 - s;
+ float v = 1 - t;
+
+ if(xt == subface->res[0])
+ --xt;
+ if(yt == subface->res[1])
+ --yt;
+
+ memset(tmp, 0, sizeof(float)*pt->channels);
+ ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yi*rowlen+xi), tmp, u*v);
+ ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yi*rowlen+xt), tmp, s*v);
+ ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yt*rowlen+xt), tmp, s*t);
+ ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yt*rowlen+xi), tmp, u*t);
+ ptex_elem_from_floats(pt->type, pt->channels, out, tmp);
+}
+
+/* interpolate subface to new resolution */
+void ptex_subface_scale(MPtex *pt, MPtexSubface *subface, int ures, int vres)
+{
+ float ui, vi, ui_step, vi_step;
+ float *tmp;
+ char *new_data, *new_data_start;
+ int u, v, layersize;
+
+ layersize = pt->channels * ptex_data_size(pt->type);
+
+ new_data_start = new_data =
+ MEM_callocN(layersize * ures * vres, "ptex_subface_scale.new_data");
+
+ /* tmp buffer used in interpolation */
+ tmp = MEM_callocN(sizeof(float) * pt->channels, "ptex_subface_scale.tmp");
+
+ ui_step = subface->res[0] / (float)ures;
+ vi_step = subface->res[1] / (float)vres;
+ for(v = 0, vi = 0; v < vres; ++v, vi += vi_step) {
+ for(u = 0, ui = 0; u < ures; ++u, ui += ui_step, new_data += layersize) {
+ ptex_bilinear_interp(pt, subface, new_data, layersize, ui, vi, tmp);
+ }
+ }
+
+ MEM_freeN(subface->data);
+ subface->data = new_data_start;
+
+ subface->res[0] = ures;
+ subface->res[1] = vres;
+
+ MEM_freeN(tmp);
+}
+
+/* copy data to/from ptex file format and internal MPtex format */
+static void ptex_transfer_filedata(MPtex *pt, int offset, char *file_data_start, int from_file)
+{
+ char *mptex_data, *file_data;
+ char **src, **dest;
+ int file_res[2], file_half_res[2];
+ int i, u, v, layersize;
+
+ layersize = pt->channels * ptex_data_size(pt->type);
+
+ if(pt->totsubface == 4) {
+ file_res[0] = pt->subfaces[1].res[0] << 1;
+ file_res[1] = pt->subfaces[1].res[1] << 1;
+ }
+ else {
+ file_res[0] = pt->subfaces[offset].res[1];
+ file_res[1] = pt->subfaces[offset].res[0];
+ }
+
+ file_half_res[0] = file_res[0] >> 1;
+ file_half_res[1] = file_res[1] >> 1;
+
+ if(from_file) {
+ src = &file_data;
+ dest = &mptex_data;
+ }
+ else {
+ src = &mptex_data;
+ dest = &file_data;
+ }
+
+ if(pt->totsubface == 4) {
+ /* save quad subfaces as one face */
+
+ for(i = 0; i < 4; ++i) {
+ MPtexSubface *subface = &pt->subfaces[i];
+ int file_center_offset[2], file_step, file_row_step;
+
+ switch(i) {
+ case 0:
+ file_center_offset[0] = -1;
+ file_center_offset[1] = -1;
+ file_step = -file_res[0];
+ file_row_step = file_res[0] * file_half_res[1] - 1;
+ break;
+ case 1:
+ file_center_offset[0] = 0;
+ file_center_offset[1] = -1;
+ file_step = 1;
+ file_row_step = -file_res[0] - file_half_res[0];
+ break;
+ case 2:
+ file_center_offset[0] = 0;
+ file_center_offset[1] = 0;
+ file_step = file_res[0];
+ file_row_step = -file_res[0] * file_half_res[1] + 1;
+ break;
+ case 3:
+ file_center_offset[0] = -1;
+ file_center_offset[1] = 0;
+ file_step = -1;
+ file_row_step = file_res[0] + file_half_res[0];
+ break;
+ }
+
+ mptex_data = subface->data;
+ file_data = file_data_start +
+ layersize * (file_res[0] * (file_half_res[1]+file_center_offset[1]) +
+ file_half_res[0]+file_center_offset[0]);
+
+ for(v = 0; v < subface->res[1]; ++v) {
+ for(u = 0; u < subface->res[0]; ++u) {
+ memcpy(*dest, *src, layersize);
+ mptex_data += layersize;
+ file_data += layersize * file_step;
+ }
+ file_data += layersize * file_row_step;
+ }
+ }
+ }
+ else {
+ mptex_data = pt->subfaces[offset].data;
+ file_data = file_data_start;
+
+ for(v = 0; v < file_res[1]; ++v) {
+ for(u = 0; u < file_res[0]; ++u) {
+ mptex_data = (char*)pt->subfaces[offset].data +
+ layersize * ((file_res[0] - u - 1) * file_res[1] +
+ (file_res[1] - v - 1));
+ file_data = file_data_start + layersize * (v*file_res[0]+u);
+
+ memcpy(*dest, *src, layersize);
+ }
+ }
+ }
+}
+
+/* creates a new CD_MPTEX layer and loads ptex_texture into it */
+void ptex_layer_from_file(Mesh *me, PtexTextureHandle *ptex_texture)
+{
+ MPtex *mptex;
+ PtexDataType ptex_data_type;
+ int channels;
+ int i, j, layersize, active_offset;
+
+ channels = ptex_texture_num_channels(ptex_texture);
+ ptex_data_type = ptex_texture_data_type(ptex_texture);
+
+ /* number of bytes for one ptex element */
+ layersize = ptex_data_size(ptex_data_type) * channels;
+
+ 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);
+
+ for(i = 0, j = 0; i < me->totface; ++i) {
+ int S = me->mface[i].v4 ? 4 : 3;
+ int k, file_totsubface;
+
+ mptex[i].type = ptex_data_type;
+ mptex[i].channels = channels;
+ mptex[i].totsubface = S;
+
+ /* quads don't have subfaces in ptex files */
+ file_totsubface = (S==4)? 1 : S;
+
+ for(k = 0; k < file_totsubface; ++k) {
+ PtexFaceInfoHandle *ptex_face;
+ PtexResHandle *ptex_res;
+ int l, file_res[2], file_half_res[2], faceid;
+ char *filedata;
+
+ faceid = j+k;
+
+ ptex_face = ptex_texture_get_face_info(ptex_texture, faceid);
+ ptex_res = ptex_face_info_get_res(ptex_face);
+
+ file_res[0] = ptex_res_u(ptex_res);
+ file_res[1] = ptex_res_v(ptex_res);
+ file_half_res[0] = file_res[0] >> 1;
+ file_half_res[1] = file_res[1] >> 1;
+
+ filedata = MEM_callocN(layersize * file_res[0] * file_res[1], "Ptex data from file");
+ ptex_texture_get_data(ptex_texture, faceid, filedata, 0, ptex_res);
+
+ /* allocate mem for ptex data, set subface resolutions */
+ if(S==4) {
+ int ures, vres;
+
+ /* use quarter resolution for quad subfaces */
+ ures = file_half_res[0];
+ vres = file_half_res[1];
+
+ /* TODO: handle 1xV and Ux1 inputs */
+ assert(ures > 0 && vres > 0);
+
+ for(l = 0; l < 4; ++l) {
+ SWAP(int, ures, vres);
+
+ mptex[i].subfaces[l].res[0] = ures;
+ mptex[i].subfaces[l].res[1] = vres;
+ mptex[i].subfaces[l].data =
+ MEM_callocN(layersize * ures * vres,
+ "Ptex quad data from file");
+ }
+
+
+ }
+ else {
+ mptex[i].subfaces[k].res[0] = file_res[1];
+ mptex[i].subfaces[k].res[1] = file_res[0];
+ mptex[i].subfaces[k].data =
+ MEM_callocN(layersize * file_res[0] * file_res[1],
+ "Ptex tri data from file");
+ }
+
+ ptex_transfer_filedata(&mptex[i], k, filedata, 1);
+ MEM_freeN(filedata);
+ }
+
+ j += file_totsubface;
+ }
+
+ /* data is all copied, can release ptex file */
+ ptex_texture_release(ptex_texture);
+}
+
+int ptex_layer_save_file(struct Mesh *me, const char *filename)
+{
+ MPtex *mptex;
+ PtexWriterHandle *ptex_writer;
+ char *file_data;
+ int i, j, totface, faceid;
+
+ mptex = CustomData_get_layer(&me->fdata, CD_MPTEX);
+
+ for(i = 0, totface = 0; i < me->totface; ++i)
+ totface += (me->mface[i].v4 ? 4 : 3);
+
+ ptex_writer = ptex_writer_open(filename, mptex->type, mptex->channels, 0, totface, 1);
+ if(!ptex_writer)
+ return -1;
+
+ for(i = 0, faceid = 0; i < me->totface; ++i, ++mptex) {
+ PtexFaceInfoHandle *face_info;
+ int adjfaces[4] = {0,0,0,0}, adjedges[4] = {0,0,0,0};
+ int layersize;
+
+ layersize = ptex_data_size(mptex->type) * mptex->channels;
+
+ /* TODO: adjacency data (needed for filtering) */
+
+ if(mptex->totsubface == 4) {
+ int res[2];
+
+ res[0] = mptex->subfaces[1].res[0]*2;
+ res[1] = mptex->subfaces[1].res[1]*2;
+
+ file_data = MEM_callocN(res[0] * res[1] * layersize,
+ "mptex save quad data");
+
+ ptex_transfer_filedata(mptex, 0, file_data, 0);
+
+ face_info = ptex_face_info_new(res[0], res[1],
+ adjfaces, adjedges, 0);
+ ptex_writer_write_face(ptex_writer, faceid, face_info, file_data, 0);
+ faceid += 1;
+
+ MEM_freeN(file_data);
+ }
+ else if(mptex->totsubface == 3) {
+ for(j = 0; j < mptex->totsubface; ++j, ++faceid) {
+ MPtexSubface *subface = &mptex->subfaces[j];
+
+ file_data =
+ MEM_callocN(subface->res[0] * subface->res[1] * layersize,
+ "mptex save subface data");
+
+ ptex_transfer_filedata(mptex, j, file_data, 0);
+
+ face_info = ptex_face_info_new(subface->res[1],
+ subface->res[0],
+ adjfaces, adjedges, 1);
+ ptex_writer_write_face(ptex_writer, faceid, face_info,
+ file_data, 0);
+
+ MEM_freeN(file_data);
+ }
+ }
+ }
+
+ ptex_writer_release(ptex_writer);
+
+ return 0;
+}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index f64854f90de..ceb693c4ecc 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -564,7 +564,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Scene *scene, Object
ssmd.subdivType = ME_CC_SUBSURF; //catmull clark
ssmd.levels = smd->subsurfLevels; //levels
- ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0);
+ ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, NULL, FALSE, NULL, 0, 0);
if(ss_mesh)
{
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 26bd981db4a..f056731d10e 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -27,6 +27,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -59,12 +60,45 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
#include "CCGSubSurf.h"
+/* From BKE_dmgrid.h */
+int gridelem_active_offset(CustomData *data, GridKey *gridkey, int type)
+{
+ char (*names)[32] = NULL;
+ int active, tot, i;
+
+ active = CustomData_get_active_layer_index(data, type);
+
+ if(active == -1)
+ return -1;
+
+ switch(type) {
+ case CD_MCOL:
+ tot = gridkey->color;
+ names = gridkey->color_names;
+ break;
+ case CD_PAINTMASK:
+ tot = gridkey->mask;
+ names = gridkey->mask_names;
+ break;
+ default:
+ return -1;
+ }
+
+ for(i = 0; i < tot; ++i) {
+ if(!strcmp(names[i], data->layers[active].name))
+ return i;
+ }
+
+ return -1;
+}
+
static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v);
static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e);
static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f);
@@ -89,7 +123,7 @@ static void arena_release(CCGAllocatorHDL a) {
BLI_memarena_free(a);
}
-static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAging, int useArena, int UNUSED(useFlatSubdiv)) {
+static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, GridKey *gridkey, int subdivLevels, int useAging, int useArena, int UNUSED(useFlatSubdiv)) {
CCGMeshIFC ifc;
CCGSubSurf *ccgSS;
@@ -116,7 +150,11 @@ static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAgin
} else {
ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8;
}
- ifc.vertDataSize = sizeof(DMGridData);
+ ifc.vertDataSize = GRIDELEM_SIZE(gridkey);
+ ifc.finterpCount = GRIDELEM_INTERP_COUNT(gridkey);
+ ifc.gridkey = *gridkey;
+ ifc.gridkey.color_names = MEM_dupallocN(gridkey->color_names);
+ ifc.gridkey.mask_names = MEM_dupallocN(gridkey->mask_names);
if (useArena) {
CCGAllocatorIFC allocatorIFC;
@@ -136,7 +174,7 @@ static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAgin
ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8);
}
- ccgSubSurf_setCalcVertexNormals(ccgSS, 1, BLI_STRUCT_OFFSET(DMGridData, no));
+ ccgSubSurf_setCalcVertexNormals(ccgSS, 1, GRIDELEM_NO_OFFSET(gridkey));
return ccgSS;
}
@@ -316,12 +354,15 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
int index, gridSize, gridFaces, edgeSize, totface, x, y, S;
MTFace *dmtface = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, n);
MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n);
+ GridKey gridkey;
if(!dmtface || !tface)
return;
+ GRIDELEM_KEY_INIT(&gridkey, 1, 0, 0, 0); /* TODO */
+
/* create a CCGSubSurf from uv's */
- uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 0, 1, 0);
+ uvss = _getSubSurf(NULL, &gridkey, ccgSubSurf_getSubdivisionLevels(ss), 0, 1, 0);
if(!ss_sync_from_uv(uvss, ss, dm, dmtface)) {
ccgSubSurf_free(uvss);
@@ -356,10 +397,10 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
for(y = 0; y < gridFaces; y++) {
for(x = 0; x < gridFaces; x++) {
- float *a = faceGridData[(y + 0)*gridSize + x + 0].co;
- float *b = faceGridData[(y + 0)*gridSize + x + 1].co;
- float *c = faceGridData[(y + 1)*gridSize + x + 1].co;
- float *d = faceGridData[(y + 1)*gridSize + x + 0].co;
+ float *a = GRIDELEM_CO_AT(faceGridData, (y + 0)*gridSize + x + 0, &gridkey);
+ float *b = GRIDELEM_CO_AT(faceGridData, (y + 0)*gridSize + x + 1, &gridkey);
+ float *c = GRIDELEM_CO_AT(faceGridData, (y + 1)*gridSize + x + 1, &gridkey);
+ float *d = GRIDELEM_CO_AT(faceGridData, (y + 1)*gridSize + x + 0, &gridkey);
tf->uv[0][0] = a[0]; tf->uv[0][1] = a[1];
tf->uv[1][0] = d[0]; tf->uv[1][1] = d[1];
@@ -421,14 +462,14 @@ static void calc_ss_weights(int gridFaces,
}
static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
- float (*vertexCos)[3], int useFlatSubdiv)
+ float (*vertexCos)[3], int useFlatSubdiv)
{
float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
CCGVertHDL fVerts[4];
int totvert = dm->getNumVerts(dm);
int totedge = dm->getNumEdges(dm);
int totface = dm->getNumFaces(dm);
- int i;
+ int i, j;
int *index;
MVert *mvert = dm->getVertArray(dm);
MEdge *medge = dm->getEdgeArray(dm);
@@ -436,23 +477,92 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
MVert *mv;
MEdge *me;
MFace *mf;
+ float *vertData;
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
+ float (*colors)[4] = NULL;
+ int pmask_layer_count, pmask_first_layer;
ccgSubSurf_initFullSync(ss);
mv = mvert;
index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+ pmask_layer_count = CustomData_number_of_layers(&dm->vertData, CD_PAINTMASK);
+ pmask_first_layer = CustomData_get_layer_index(&dm->vertData, CD_PAINTMASK);
+
+ assert(gridkey->mask == 0 || gridkey->mask == pmask_layer_count);
+
+ vertData = MEM_callocN(GRIDELEM_SIZE(gridkey), "vertData");
+
+ /* for editable subdivided colors, find the average mcol for each vert */
+ if(gridkey->color) {
+ int *users;
+ int k;
+
+ colors = MEM_callocN(sizeof(float)*4*gridkey->color*totvert,
+ "ss_sync_from_derivedmesh.colors");
+ users = MEM_callocN(sizeof(int)*totvert,
+ "ss_sync_from_derivedmesh.users");
+
+ for(i = 0; i < totface; ++i) {
+ MFace *f = mface + i;
+ int S = f->v4 ? 4 : 3;
+
+ for(j = 0; j < S; ++j) {
+ int vndx = (&f->v1)[j];
+
+ ++users[vndx];
+
+ for(k = 0; k < gridkey->color; ++k) {
+ MCol *mcol = CustomData_get_layer_named(&dm->faceData,
+ CD_MCOL,
+ gridkey->color_names[k]);
+
+ colors[vndx*gridkey->color + k][0] += mcol[i*4+j].b;
+ colors[vndx*gridkey->color + k][1] += mcol[i*4+j].g;
+ colors[vndx*gridkey->color + k][2] += mcol[i*4+j].r;
+ colors[vndx*gridkey->color + k][3] += mcol[i*4+j].a;
+
+ }
+ }
+ }
+
+ /* divide by number of faces sharing the corner
+ also convert from [0,255] to [0,1] */
+ for(i = 0; i < totvert; ++i) {
+ float inv = 1.0f / (users[i] * 255);
+ for(j = 0; j < gridkey->color; ++j) {
+ colors[i*gridkey->color + j][0] *= inv;
+ colors[i*gridkey->color + j][1] *= inv;
+ colors[i*gridkey->color + j][2] *= inv;
+ colors[i*gridkey->color + j][3] *= inv;
+ }
+ }
+
+ MEM_freeN(users);
+ }
+
for(i = 0; i < totvert; i++, mv++) {
CCGVert *v;
- if(vertexCos) {
- ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), vertexCos[i], 0, &v);
- } else {
- ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), mv->co, 0, &v);
- }
+ copy_v3_v3(vertData, vertexCos ? vertexCos[i] : mv->co);
+
+ /* copy color data */
+ for(j = 0; j < gridkey->color; ++j)
+ memcpy(&vertData[3 + 4*j], colors[i*gridkey->color + j], sizeof(float)*4);
+
+ /* copy paint mask data */
+ for(j = 0; j < gridkey->mask; ++j)
+ vertData[3 + gridkey->color*4 + j] = ((float*)dm->vertData.layers[pmask_first_layer+j].data)[i];
+
+ ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), vertData, 0, &v);
((int*)ccgSubSurf_getVertUserData(ss, v))[1] = (index)? *index++: i;
}
+ MEM_freeN(vertData);
+ if(colors) MEM_freeN(colors);
+
me = medge;
index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
for(i = 0; i < totedge; i++, me++) {
@@ -478,7 +588,7 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
fVerts[2] = SET_INT_IN_POINTER(mf->v3);
fVerts[3] = SET_INT_IN_POINTER(mf->v4);
- // this is very bad, means mesh is internally consistent.
+ // this is very bad, means mesh is internally inconsistent.
// it is not really possible to continue without modifying
// other parts of code significantly to handle missing faces.
// since this really shouldn't even be possible we just bail.
@@ -524,6 +634,7 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
if (!ccgSubSurf_getNumVerts(ss))
min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
@@ -540,7 +651,7 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
DMGridData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
for (i=0; i<edgeSize; i++)
- DO_MINMAX(edgeData[i].co, min_r, max_r);
+ DO_MINMAX(GRIDELEM_CO_AT(edgeData, i, gridkey), min_r, max_r);
}
for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
@@ -552,7 +663,7 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
for (y=0; y<gridSize; y++)
for (x=0; x<gridSize; x++)
- DO_MINMAX(faceGridData[y*gridSize + x].co, min_r, max_r);
+ DO_MINMAX(GRIDELEM_CO_AT(faceGridData, y*gridSize + x, gridkey), min_r, max_r);
}
}
@@ -580,6 +691,7 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
DMGridData *vd;
int i;
@@ -613,15 +725,15 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
offset = vertNum - ccgdm->faceMap[i].startVert;
if(offset < 1) {
vd = ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(mv->co, vd->co);
- normal_float_to_short_v3(mv->no, vd->no);
+ copy_v3_v3(mv->co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mv->no, GRIDELEM_NO(vd, gridkey));
} else if(offset < gridSideEnd) {
offset -= 1;
grid = offset / gridSideVerts;
x = offset % gridSideVerts + 1;
vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
- copy_v3_v3(mv->co, vd->co);
- normal_float_to_short_v3(mv->no, vd->no);
+ copy_v3_v3(mv->co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mv->no, GRIDELEM_NO(vd, gridkey));
} else if(offset < gridInternalEnd) {
offset -= gridSideEnd;
grid = offset / gridInternalVerts;
@@ -629,8 +741,8 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
y = offset / gridSideVerts + 1;
x = offset % gridSideVerts + 1;
vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
- copy_v3_v3(mv->co, vd->co);
- normal_float_to_short_v3(mv->no, vd->no);
+ copy_v3_v3(mv->co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mv->no, GRIDELEM_NO(vd, gridkey));
}
} else if((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
/* this vert comes from edge data */
@@ -646,8 +758,8 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
x = vertNum - ccgdm->edgeMap[i].startVert + 1;
vd = ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(mv->co, vd->co);
- normal_float_to_short_v3(mv->no, vd->no);
+ copy_v3_v3(mv->co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mv->no, GRIDELEM_NO(vd, gridkey));
} else {
/* this vert comes from vert data */
CCGVert *v;
@@ -655,8 +767,8 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
v = ccgdm->vertMap[i].vert;
vd = ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(mv->co, vd->co);
- normal_float_to_short_v3(mv->no, vd->no);
+ copy_v3_v3(mv->co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mv->no, GRIDELEM_NO(vd, gridkey));
}
}
@@ -808,6 +920,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
int totvert, totedge, totface;
int gridSize = ccgSubSurf_getGridSize(ss);
int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
int i = 0;
totface = ccgSubSurf_getNumFaces(ss);
@@ -816,15 +929,15 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
vd= ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(mvert[i].co, vd->co);
- normal_float_to_short_v3(mvert[i].no, vd->no);
+ copy_v3_v3(mvert[i].co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mvert[i].no, GRIDELEM_NO(vd, gridkey));
i++;
for(S = 0; S < numVerts; S++) {
for(x = 1; x < gridSize - 1; x++, i++) {
vd= ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
- copy_v3_v3(mvert[i].co, vd->co);
- normal_float_to_short_v3(mvert[i].no, vd->no);
+ copy_v3_v3(mvert[i].co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mvert[i].no, GRIDELEM_NO(vd, gridkey));
}
}
@@ -832,8 +945,8 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
for(y = 1; y < gridSize - 1; y++) {
for(x = 1; x < gridSize - 1; x++, i++) {
vd= ccgSubSurf_getFaceGridData(ss, f, S, x, y);
- copy_v3_v3(mvert[i].co, vd->co);
- normal_float_to_short_v3(mvert[i].no, vd->no);
+ copy_v3_v3(mvert[i].co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mvert[i].no, GRIDELEM_NO(vd, gridkey));
}
}
}
@@ -846,9 +959,9 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
for(x = 1; x < edgeSize - 1; x++, i++) {
vd= ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(mvert[i].co, vd->co);
+ copy_v3_v3(mvert[i].co, GRIDELEM_CO(vd, gridkey));
/* XXX, This gives errors with -fpe, the normals dont seem to be unit length - campbell */
- normal_float_to_short_v3(mvert[i].no, vd->no);
+ normal_float_to_short_v3(mvert[i].no, GRIDELEM_NO(vd, gridkey));
}
}
@@ -857,8 +970,8 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
CCGVert *v = ccgdm->vertMap[index].vert;
vd= ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(mvert[i].co, vd->co);
- normal_float_to_short_v3(mvert[i].no, vd->no);
+ copy_v3_v3(mvert[i].co, GRIDELEM_CO(vd, gridkey));
+ normal_float_to_short_v3(mvert[i].no, GRIDELEM_NO(vd, gridkey));
i++;
}
}
@@ -1070,6 +1183,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGVertIterator *vi = ccgSubSurf_getVertIterator(ccgdm->ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ccgdm->ss);
for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
CCGVert *v = ccgVertIterator_getCurrent(vi);
@@ -1077,7 +1191,7 @@ static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData
int index = ccgDM_getVertMapIndex(ccgdm->ss, v);
if (index!=-1)
- func(userData, index, vd->co, vd->no, NULL);
+ func(userData, index, GRIDELEM_CO(vd, gridkey), GRIDELEM_NO(vd, gridkey), NULL);
}
ccgVertIterator_free(vi);
@@ -1087,6 +1201,7 @@ static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData
CCGSubSurf *ss = ccgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
@@ -1095,7 +1210,7 @@ static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData
if (index!=-1) {
for (i=0; i<edgeSize-1; i++)
- func(userData, index, edgeData[i].co, edgeData[i+1].co);
+ func(userData, index, GRIDELEM_CO_AT(edgeData, i, gridkey), GRIDELEM_CO_AT(edgeData, i+1, gridkey));
}
}
@@ -1153,6 +1268,7 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int UNUSED(draw
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
int useAging;
ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
@@ -1171,8 +1287,8 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int UNUSED(draw
glBegin(GL_LINE_STRIP);
for (i=0; i<edgeSize-1; i++) {
- glVertex3fv(edgeData[i].co);
- glVertex3fv(edgeData[i+1].co);
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i, gridkey));
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i+1, gridkey));
}
glEnd();
}
@@ -1191,18 +1307,18 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int UNUSED(draw
glBegin(GL_LINE_STRIP);
for (x=0; x<gridSize; x++)
- glVertex3fv(faceGridData[x].co);
+ glVertex3fv(GRIDELEM_CO_AT(faceGridData, x, gridkey));
glEnd();
for (y=1; y<gridSize-1; y++) {
glBegin(GL_LINE_STRIP);
for (x=0; x<gridSize; x++)
- glVertex3fv(faceGridData[y*gridSize + x].co);
+ glVertex3fv(GRIDELEM_CO_AT(faceGridData, y*gridSize + x, gridkey));
glEnd();
}
for (x=1; x<gridSize-1; x++) {
glBegin(GL_LINE_STRIP);
for (y=0; y<gridSize; y++)
- glVertex3fv(faceGridData[y*gridSize + x].co);
+ glVertex3fv(GRIDELEM_CO_AT(faceGridData, y*gridSize + x, gridkey));
glEnd();
}
}
@@ -1217,6 +1333,7 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
CCGSubSurf *ss = ccgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
@@ -1225,8 +1342,8 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
if (!ccgSubSurf_getEdgeNumFaces(e)) {
glBegin(GL_LINE_STRIP);
for (i=0; i<edgeSize-1; i++) {
- glVertex3fv(edgeData[i].co);
- glVertex3fv(edgeData[i+1].co);
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i, gridkey));
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i+1, gridkey));
}
glEnd();
}
@@ -1264,31 +1381,49 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
}
}
- /* Only used by non-editmesh types */
-static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], int fast, int (*setMaterial)(int, void *attribs)) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGFaceIterator *fi;
- int gridSize = ccgSubSurf_getGridSize(ss);
+static int ccgdm_draw_pbvh(DerivedMesh *dm, float (*partial_redraw_planes)[4],
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
char *faceFlags = ccgdm->faceFlags;
- int step = (fast)? gridSize-1: 1;
ccgdm_pbvh_update(ccgdm);
- if(ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
+ if(ccgdm->pbvh && (ccgdm->multires.mmd || DM_DRAW_PTEX) && !(flags & DM_DRAW_LOWEST_SUBDIVISION_LEVEL)) {
if(dm->numFaceData) {
/* should be per face */
- if(!setMaterial(faceFlags[1]+1, NULL))
- return;
+ if(setMaterial && !setMaterial(faceFlags[1]+1, NULL))
+ return 1;
+ if(faceFlags[0] & ME_SMOOTH)
+ flags |= DM_DRAW_FULLY_SMOOTH;
- glShadeModel((faceFlags[0] & ME_SMOOTH)? GL_SMOOTH: GL_FLAT);
- BLI_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, (faceFlags[0] & ME_SMOOTH));
- glShadeModel(GL_FLAT);
+ BLI_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, flags);
}
- return;
+ return 1;
}
+ return 0;
+}
+
+/* Only used by non-editmesh types */
+static void ccgDM_drawFacesSolid(DerivedMesh *dm,
+ float (*partial_redraw_planes)[4],
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGFaceIterator *fi;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
+ char *faceFlags = ccgdm->faceFlags;
+ int step = (flags & DM_DRAW_LOWEST_SUBDIVISION_LEVEL)? gridSize-1: 1;
+
+ if(!(flags & DM_DRAW_BACKBUF_SELECTION) &&
+ ccgdm_draw_pbvh(dm, partial_redraw_planes, setMaterial, flags))
+ return;
+
fi = ccgSubSurf_getFaceIterator(ss);
for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
CCGFace *f = ccgFaceIterator_getCurrent(fi);
@@ -1316,13 +1451,13 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
for (y=0; y<gridSize-1; y+=step) {
glBegin(GL_QUAD_STRIP);
for (x=0; x<gridSize; x+=step) {
- DMGridData *a = &faceGridData[(y+0)*gridSize + x];
- DMGridData *b = &faceGridData[(y+step)*gridSize + x];
+ DMGridData *a = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ DMGridData *b = GRIDELEM_AT(faceGridData, (y+step)*gridSize + x, gridkey);
- glNormal3fv(a->no);
- glVertex3fv(a->co);
- glNormal3fv(b->no);
- glVertex3fv(b->co);
+ glNormal3fv(GRIDELEM_NO(a, gridkey));
+ glVertex3fv(GRIDELEM_CO(a, gridkey));
+ glNormal3fv(GRIDELEM_NO(b, gridkey));
+ glVertex3fv(GRIDELEM_CO(b, gridkey));
}
glEnd();
}
@@ -1330,10 +1465,10 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
glBegin(GL_QUADS);
for (y=0; y<gridSize-1; y+=step) {
for (x=0; x<gridSize-1; x+=step) {
- float *a = faceGridData[(y+0)*gridSize + x].co;
- float *b = faceGridData[(y+0)*gridSize + x + step].co;
- float *c = faceGridData[(y+step)*gridSize + x + step].co;
- float *d = faceGridData[(y+step)*gridSize + x].co;
+ float *a = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ float *b = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x + step, gridkey);
+ float *c = GRIDELEM_CO_AT(faceGridData, (y+step)*gridSize + x + step, gridkey);
+ float *d = GRIDELEM_CO_AT(faceGridData, (y+step)*gridSize + x, gridkey);
ccgDM_glNormalFast(a, b, c, d);
@@ -1362,6 +1497,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
int transp, orig_transp, new_transp;
char *faceFlags = ccgdm->faceFlags;
int a, b, i, doDraw, numVerts, matnr, new_matnr, totface;
@@ -1447,31 +1583,31 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
for (y=0; y<gridFaces; y++) {
glBegin(GL_QUAD_STRIP);
for (x=0; x<gridFaces; x++) {
- vda = &faceGridData[(y+0)*gridSize + x];
- vdb = &faceGridData[(y+1)*gridSize + x];
+ vda = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ vdb = GRIDELEM_AT(faceGridData, (y+1)*gridSize + x, gridkey);
PASSATTRIB(0, 0, 0);
- glNormal3fv(vda->no);
- glVertex3fv(vda->co);
+ glNormal3fv(GRIDELEM_NO(vda, gridkey));
+ glVertex3fv(GRIDELEM_CO(vda, gridkey));
PASSATTRIB(0, 1, 1);
- glNormal3fv(vdb->no);
- glVertex3fv(vdb->co);
+ glNormal3fv(GRIDELEM_NO(vdb, gridkey));
+ glVertex3fv(GRIDELEM_CO(vdb, gridkey));
if(x != gridFaces-1)
a++;
}
- vda = &faceGridData[(y+0)*gridSize + x];
- vdb = &faceGridData[(y+1)*gridSize + x];
+ vda = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ vdb = GRIDELEM_AT(faceGridData, (y+1)*gridSize + x, gridkey);
PASSATTRIB(0, 0, 3);
- glNormal3fv(vda->no);
- glVertex3fv(vda->co);
+ glNormal3fv(GRIDELEM_NO(vda, gridkey));
+ glVertex3fv(GRIDELEM_CO(vda, gridkey));
PASSATTRIB(0, 1, 2);
- glNormal3fv(vdb->no);
- glVertex3fv(vdb->co);
+ glNormal3fv(GRIDELEM_NO(vdb, gridkey));
+ glVertex3fv(GRIDELEM_CO(vdb, gridkey));
glEnd();
@@ -1481,10 +1617,10 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
glBegin(GL_QUADS);
for (y=0; y<gridFaces; y++) {
for (x=0; x<gridFaces; x++) {
- float *aco = faceGridData[(y+0)*gridSize + x].co;
- float *bco = faceGridData[(y+0)*gridSize + x + 1].co;
- float *cco = faceGridData[(y+1)*gridSize + x + 1].co;
- float *dco = faceGridData[(y+1)*gridSize + x].co;
+ float *aco = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ float *bco = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x + 1, gridkey);
+ float *cco = GRIDELEM_CO_AT(faceGridData, (y+1)*gridSize + x + 1, gridkey);
+ float *dco = GRIDELEM_CO_AT(faceGridData, (y+1)*gridSize + x, gridkey);
ccgDM_glNormalFast(aco, bco, cco, dco);
@@ -1519,6 +1655,7 @@ static void ccgDM_drawFacesColored(DerivedMesh *dm, int UNUSED(useTwoSided), uns
CCGSubSurf *ss = ccgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
unsigned char *cp1, *cp2;
int useTwoSide=1;
@@ -1545,10 +1682,10 @@ static void ccgDM_drawFacesColored(DerivedMesh *dm, int UNUSED(useTwoSided), uns
DMGridData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
for (y=0; y<gridSize-1; y++) {
for (x=0; x<gridSize-1; x++) {
- float *a = faceGridData[(y+0)*gridSize + x].co;
- float *b = faceGridData[(y+0)*gridSize + x + 1].co;
- float *c = faceGridData[(y+1)*gridSize + x + 1].co;
- float *d = faceGridData[(y+1)*gridSize + x].co;
+ float *a = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ float *b = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x + 1, gridkey);
+ float *c = GRIDELEM_CO_AT(faceGridData, (y+1)*gridSize + x + 1, gridkey);
+ float *d = GRIDELEM_CO_AT(faceGridData, (y+1)*gridSize + x, gridkey);
glColor3ub(cp1[3], cp1[2], cp1[1]);
glVertex3fv(d);
@@ -1592,6 +1729,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
char *faceFlags = ccgdm->faceFlags;
int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
int gridFaces = gridSize - 1;
ccgdm_pbvh_update(ccgdm);
@@ -1646,18 +1784,18 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
for (y=0; y<gridFaces; y++) {
glBegin(GL_QUAD_STRIP);
for (x=0; x<gridFaces; x++) {
- a = &faceGridData[(y+0)*gridSize + x];
- b = &faceGridData[(y+1)*gridSize + x];
+ a = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ b = GRIDELEM_AT(faceGridData, (y+1)*gridSize + x, gridkey);
if(tf) glTexCoord2fv(tf->uv[0]);
if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glNormal3fv(a->no);
- glVertex3fv(a->co);
+ glNormal3fv(GRIDELEM_NO(a, gridkey));
+ glVertex3fv(GRIDELEM_CO(a, gridkey));
if(tf) glTexCoord2fv(tf->uv[1]);
if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glNormal3fv(b->no);
- glVertex3fv(b->co);
+ glNormal3fv(GRIDELEM_NO(b, gridkey));
+ glVertex3fv(GRIDELEM_CO(b, gridkey));
if(x != gridFaces-1) {
if(tf) tf++;
@@ -1665,18 +1803,18 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
}
}
- a = &faceGridData[(y+0)*gridSize + x];
- b = &faceGridData[(y+1)*gridSize + x];
+ a = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ b = GRIDELEM_AT(faceGridData, (y+1)*gridSize + x, gridkey);
if(tf) glTexCoord2fv(tf->uv[3]);
if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glNormal3fv(a->no);
- glVertex3fv(a->co);
+ glNormal3fv(GRIDELEM_NO(a, gridkey));
+ glVertex3fv(GRIDELEM_CO(a, gridkey));
if(tf) glTexCoord2fv(tf->uv[2]);
if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glNormal3fv(b->no);
- glVertex3fv(b->co);
+ glNormal3fv(GRIDELEM_NO(b, gridkey));
+ glVertex3fv(GRIDELEM_CO(b, gridkey));
if(tf) tf++;
if(cp) cp += 16;
@@ -1688,10 +1826,10 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
glBegin(GL_QUADS);
for (y=0; y<gridFaces; y++) {
for (x=0; x<gridFaces; x++) {
- float *a_co = faceGridData[(y+0)*gridSize + x].co;
- float *b_co = faceGridData[(y+0)*gridSize + x + 1].co;
- float *c_co = faceGridData[(y+1)*gridSize + x + 1].co;
- float *d_co = faceGridData[(y+1)*gridSize + x].co;
+ float *a_co = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ float *b_co = GRIDELEM_CO_AT(faceGridData, (y+0)*gridSize + x + 1, gridkey);
+ float *c_co = GRIDELEM_CO_AT(faceGridData, (y+1)*gridSize + x + 1, gridkey);
+ float *d_co = GRIDELEM_CO_AT(faceGridData, (y+1)*gridSize + x, gridkey);
ccgDM_glNormalFast(a_co, b_co, c_co, d_co);
@@ -1764,18 +1902,47 @@ static void ccgDM_drawUVEdges(DerivedMesh *dm)
}
}
-static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) {
+/* TODO: unify with gpu_buffers.c */
+static void gl_color_from_grid(DMGridData *elem, GridKey *gridkey)
+{
+ float v[3] = {1, 1, 1};
+ int i;
+
+ for(i = 0; i < gridkey->color; ++i) {
+ float *col = GRIDELEM_COLOR(elem, gridkey)[i];
+ interp_v3_v3v3(v, v, col, col[3]);
+ }
+ glColor3fv(v);
+}
+
+static void ccgDM_drawMappedFaces(DerivedMesh *dm,
+ float (*partial_redraw_planes)[4],
+ int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
+ void *userData,
+ int (*setMaterial)(int, void *attribs),
+ DMDrawFlags flags) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
MCol *mcol= NULL;
int i, gridSize = ccgSubSurf_getGridSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
char *faceFlags = ccgdm->faceFlags;
int gridFaces = gridSize - 1, totface;
+ int step = (flags & DM_DRAW_LOWEST_SUBDIVISION_LEVEL)? gridSize-1: 1;
- if(useColors) {
- mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
- if(!mcol)
- mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ if(ccgdm_draw_pbvh(dm, partial_redraw_planes, NULL, flags))
+ return;
+
+ if(flags & DM_DRAW_VERTEX_COLORS) {
+ if(flags & DM_DRAW_LOWEST_SUBDIVISION_LEVEL) {
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+ }
+ else {
+ mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+ if(!mcol)
+ mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ }
}
totface = ccgSubSurf_getNumFaces(ss);
@@ -1812,36 +1979,41 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u
for (S=0; S<numVerts; S++) {
DMGridData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ DMGridData *a, *b, *c, *d;
+
if (drawSmooth) {
glShadeModel(GL_SMOOTH);
- for (y=0; y<gridFaces; y++) {
- DMGridData *a, *b;
+ for (y=0; y<gridFaces; y+=step) {
glBegin(GL_QUAD_STRIP);
- for (x=0; x<gridFaces; x++) {
- a = &faceGridData[(y+0)*gridSize + x];
- b = &faceGridData[(y+1)*gridSize + x];
+ for (x=0; x<gridFaces; x+=step) {
+ a = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ b = GRIDELEM_AT(faceGridData, (y+step)*gridSize + x, gridkey);
if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glNormal3fv(a->no);
- glVertex3fv(a->co);
+ else gl_color_from_grid(a, gridkey);
+ glNormal3fv(GRIDELEM_NO(a, gridkey));
+ glVertex3fv(GRIDELEM_CO(a, gridkey));
if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glNormal3fv(b->no);
- glVertex3fv(b->co);
+ else gl_color_from_grid(b, gridkey);
+ glNormal3fv(GRIDELEM_NO(b, gridkey));
+ glVertex3fv(GRIDELEM_CO(b, gridkey));
if(x != gridFaces-1) {
if(cp) cp += 16;
}
}
- a = &faceGridData[(y+0)*gridSize + x];
- b = &faceGridData[(y+1)*gridSize + x];
+ a = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ b = GRIDELEM_AT(faceGridData, (y+step)*gridSize + x, gridkey);
if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glNormal3fv(a->no);
- glVertex3fv(a->co);
+ else gl_color_from_grid(a, gridkey);
+ glNormal3fv(GRIDELEM_NO(a, gridkey));
+ glVertex3fv(GRIDELEM_CO(a, gridkey));
if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glNormal3fv(b->no);
- glVertex3fv(b->co);
+ else gl_color_from_grid(b, gridkey);
+ glNormal3fv(GRIDELEM_NO(b, gridkey));
+ glVertex3fv(GRIDELEM_CO(b, gridkey));
if(cp) cp += 16;
@@ -1850,23 +2022,37 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u
} else {
glShadeModel(GL_FLAT);
glBegin(GL_QUADS);
- for (y=0; y<gridFaces; y++) {
- for (x=0; x<gridFaces; x++) {
- float *a = faceGridData[(y+0)*gridSize + x].co;
- float *b = faceGridData[(y+0)*gridSize + x + 1].co;
- float *c = faceGridData[(y+1)*gridSize + x + 1].co;
- float *d = faceGridData[(y+1)*gridSize + x].co;
-
- ccgDM_glNormalFast(a, b, c, d);
+ for (y=0; y<gridFaces; y+=step) {
+ for (x=0; x<gridFaces; x+=step) {
+ float *a_co, *b_co, *c_co, *d_co;
+
+ a = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x, gridkey);
+ b = GRIDELEM_AT(faceGridData, (y+0)*gridSize + x + step, gridkey);
+ c = GRIDELEM_AT(faceGridData, (y+step)*gridSize + x + step, gridkey);
+ d = GRIDELEM_AT(faceGridData, (y+step)*gridSize + x, gridkey);
+
+ a_co = GRIDELEM_CO(a, gridkey);
+ b_co = GRIDELEM_CO(b, gridkey);
+ c_co = GRIDELEM_CO(c, gridkey);
+ d_co = GRIDELEM_CO(d, gridkey);
+
+ ccgDM_glNormalFast(a_co, b_co, c_co, d_co);
if(cp) glColor3ub(cp[7], cp[6], cp[5]);
- glVertex3fv(d);
+ else gl_color_from_grid(d, gridkey);
+ glVertex3fv(a_co);
+
if(cp) glColor3ub(cp[11], cp[10], cp[9]);
- glVertex3fv(c);
+ else gl_color_from_grid(c, gridkey);
+ glVertex3fv(b_co);
+
if(cp) glColor3ub(cp[15], cp[14], cp[13]);
- glVertex3fv(b);
+ else gl_color_from_grid(b, gridkey);
+ glVertex3fv(c_co);
+
if(cp) glColor3ub(cp[3], cp[2], cp[1]);
- glVertex3fv(a);
+ else gl_color_from_grid(a, gridkey);
+ glVertex3fv(d_co);
if(cp) cp += 16;
}
@@ -1879,12 +2065,16 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u
}
}
}
+
+ if(flags & DM_DRAW_LOWEST_SUBDIVISION_LEVEL)
+ glDisable(GL_COLOR_MATERIAL);
}
static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
@@ -1901,8 +2091,8 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *u
}
for (i=0; i<edgeSize-1; i++) {
- glVertex3fv(edgeData[i].co);
- glVertex3fv(edgeData[i+1].co);
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i, gridkey));
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i+1, gridkey));
}
}
glEnd();
@@ -1915,6 +2105,7 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(v
CCGSubSurf *ss = ccgdm->ss;
CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
@@ -1933,7 +2124,7 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(v
glColor3ub(0, ageCol>0?ageCol:0, 0);
}
- glVertex3fv(edgeData[i].co);
+ glVertex3fv(GRIDELEM_CO_AT(edgeData, i, gridkey));
}
}
glEnd();
@@ -1945,6 +2136,7 @@ static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *us
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+ GridKey *gridkey = ccgSubSurf_getGridKey(ss);
for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
CCGFace *f = ccgFaceIterator_getCurrent(fi);
@@ -1954,7 +2146,7 @@ static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *us
/* Face center data normal isn't updated atm. */
DMGridData *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
- func(userData, index, vd->co, vd->no);
+ func(userData, index, GRIDELEM_CO(vd, gridkey), GRIDELEM_NO(vd, gridkey));
}
}
@@ -1978,6 +2170,7 @@ static void ccgDM_release(DerivedMesh *dm) {
if(ccgdm->gridData) MEM_freeN(ccgdm->gridData);
if(ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
if(ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
+ if(ccgdm->gridFaceMap) MEM_freeN(ccgdm->gridFaceMap);
if(ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss);
if(ccgdm->fmap) MEM_freeN(ccgdm->fmap);
if(ccgdm->fmap_mem) MEM_freeN(ccgdm->fmap_mem);
@@ -2123,6 +2316,7 @@ static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int
adjf = ccgSubSurf_getEdgeFace(e, i);
if(adjf != f) {
+ /* within the adjacent face, find the side [0-3] */
numEdges = ccgSubSurf_getFaceNumVerts(adjf);
for(j = 0; j < numEdges; j++)
if(ccgSubSurf_getFaceEdge(ss, adjf, j) == e)
@@ -2135,6 +2329,7 @@ static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int
fIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, adjf));
+ /* offset to choose the subface (there are two subfaces per edge) */
return gridOffset[fIndex] + (j + offset)%numEdges;
}
@@ -2186,12 +2381,12 @@ static void ccgdm_create_grids(DerivedMesh *dm)
adj->index[0] = gIndex - S + nextS;
adj->rotation[0] = 3;
- adj->index[1] = ccgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
- adj->rotation[1] = 1;
- adj->index[2] = ccgdm_adjacent_grid(ss, gridOffset, f, S, 1);
- adj->rotation[2] = 3;
+ adj->index[1] = ccgdm_adjacent_grid(ss, gridOffset, f, S, 1);
+ adj->rotation[1] = 2;
+ adj->index[2] = ccgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
+ adj->rotation[2] = 1;
adj->index[3] = gIndex - S + prevS;
- adj->rotation[3] = 1;
+ adj->rotation[3] = 0;
}
}
@@ -2225,6 +2420,13 @@ static int *ccgDM_getGridOffset(DerivedMesh *dm)
return ccgdm->gridOffset;
}
+static GridKey *ccgDM_getGridKey(DerivedMesh *dm)
+{
+ CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+
+ return ccgSubSurf_getGridKey(ccgdm->ss);
+}
+
static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
@@ -2239,6 +2441,36 @@ static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
return ccgdm->fmap;
}
+static GridToFace *ccgDM_getGridFaceMap(DerivedMesh *dm)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ GridToFace *gtf = ccgdm->gridFaceMap;
+
+ if(!gtf) {
+ int totgrid, totface, i, j;
+
+ totgrid = dm->getNumGrids(dm);
+ totface = ccgSubSurf_getNumFaces(ss);
+
+ gtf = ccgdm->gridFaceMap =
+ MEM_callocN(sizeof(GridToFace) * totgrid,
+ "ccgdm.gridFaceMap");
+
+ for(i = 0; i < totface; ++i) {
+ CCGFace *f = ccgdm->faceMap[i].face;
+ int S = ccgSubSurf_getFaceNumVerts(f);
+
+ for(j = 0; j < S; ++j, ++gtf) {
+ gtf->face = i;
+ gtf->offset = j;
+ }
+ }
+ }
+
+ return ccgdm->gridFaceMap;
+}
+
static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm)
{
ModifierData *md;
@@ -2259,56 +2491,73 @@ static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm)
static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
{
+ SculptSession *ss;
CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
int gridSize, numGrids, grid_pbvh;
+ GridKey *gridkey;
+ Mesh *me;
if(!ob) {
ccgdm->pbvh= NULL;
return NULL;
}
- if(!ob->sculpt)
+ if(!ob->paint)
return NULL;
+ ss = ob->paint->sculpt;
- grid_pbvh = ccgDM_use_grid_pbvh(ccgdm);
+ grid_pbvh = (ob->mode & OB_MODE_VERTEX_PAINT) || ccgDM_use_grid_pbvh(ccgdm);
- if(ob->sculpt->pbvh) {
+ if(ob->paint->pbvh) {
if(grid_pbvh) {
/* pbvh's grids, gridadj and gridfaces points to data inside ccgdm
but this can be freed on ccgdm release, this updates the pointers
when the ccgdm gets remade, the assumption is that the topology
does not change. */
ccgdm_create_grids(dm);
- BLI_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void**)ccgdm->gridFaces);
+ BLI_pbvh_grids_update(ob->paint->pbvh, ccgdm->gridData,
+ ccgdm->gridAdjacency, (void**)ccgdm->gridFaces,
+ ccgDM_getGridKey(&ccgdm->dm));
}
- ccgdm->pbvh = ob->sculpt->pbvh;
+ ccgdm->pbvh = ob->paint->pbvh;
ccgdm->pbvh_draw = grid_pbvh;
}
if(ccgdm->pbvh)
return ccgdm->pbvh;
+ me = ob->data;
+
/* no pbvh exists yet, we need to create one. only in case of multires
we build a pbvh over the modified mesh, in other cases the base mesh
is being sculpted, so we build a pbvh from that. */
if(grid_pbvh) {
+ int leaf_limit = PBVH_DEFAULT_LEAF_LIMIT;
+
+ /* TODO: set leaf limit more intelligently */
+ if(ob->mode & OB_MODE_VERTEX_PAINT)
+ leaf_limit = 1;
+
ccgdm_create_grids(dm);
gridSize = ccgDM_getGridSize(dm);
numGrids = ccgDM_getNumGrids(dm);
+ gridkey = ccgDM_getGridKey(dm);
- ob->sculpt->pbvh= ccgdm->pbvh = BLI_pbvh_new();
+ ob->paint->pbvh= ccgdm->pbvh = BLI_pbvh_new(leaf_limit);
BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
- numGrids, gridSize, (void**)ccgdm->gridFaces);
+ numGrids, gridSize, gridkey, (void**)ccgdm->gridFaces,
+ dm->getGridFaceMap(dm),
+ &me->vdata, &me->fdata,
+ ss ? &ss->hidden_areas : NULL);
ccgdm->pbvh_draw = 1;
}
else if(ob->type == OB_MESH) {
- Mesh *me= ob->data;
-
- ob->sculpt->pbvh= ccgdm->pbvh = BLI_pbvh_new();
+ ob->paint->pbvh= ccgdm->pbvh = BLI_pbvh_new(PBVH_DEFAULT_LEAF_LIMIT);
BLI_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert,
- me->totface, me->totvert);
+ &me->vdata, &me->fdata, me->totface, me->totvert,
+ ss ? &ss->hidden_areas : NULL);
ccgdm->pbvh_draw = 0;
}
@@ -2369,7 +2618,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getGridData = ccgDM_getGridData;
ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency;
ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
+ ccgdm->dm.getGridKey = ccgDM_getGridKey;
ccgdm->dm.getFaceMap = ccgDM_getFaceMap;
+ ccgdm->dm.getGridFaceMap = ccgDM_getGridFaceMap;
ccgdm->dm.getPBVH = ccgDM_getPBVH;
ccgdm->dm.getVertCos = ccgdm_getVertCos;
@@ -2616,6 +2867,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct GridKey *gridkey,
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode)
{
@@ -2624,11 +2876,17 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
+ GridKey default_gridkey;
+
+ if(!gridkey) {
+ GRIDELEM_KEY_INIT(&default_gridkey, 1, 0, 0, 1);
+ gridkey = &default_gridkey;
+ }
if(editMode) {
int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
- smd->emCache = _getSubSurf(smd->emCache, levels, useAging, 0,
+ smd->emCache = _getSubSurf(smd->emCache, gridkey, levels, useAging, 0,
useSimple);
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
@@ -2643,7 +2901,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
if(levels == 0)
return dm;
- ss = _getSubSurf(NULL, levels, 0, 1, useSimple);
+ ss = _getSubSurf(NULL, gridkey, levels, 0, 1, useSimple);
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
@@ -2671,7 +2929,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
if(useIncremental && isFinalCalc) {
- smd->mCache = ss = _getSubSurf(smd->mCache, levels,
+ smd->mCache = ss = _getSubSurf(smd->mCache, gridkey, levels,
useAging, 0, useSimple);
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
@@ -2685,7 +2943,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
smd->mCache = NULL;
}
- ss = _getSubSurf(NULL, levels, 0, 1, useSimple);
+ ss = _getSubSurf(NULL, gridkey, levels, 0, 1, useSimple);
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
@@ -2707,11 +2965,15 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3])
* calculated vert positions is incorrect for the verts
* on the boundary of the mesh.
*/
- CCGSubSurf *ss = _getSubSurf(NULL, 1, 0, 1, 0);
+ CCGSubSurf *ss;
float edge_sum[3], face_sum[3];
CCGVertIterator *vi;
DerivedMesh *dm = CDDM_from_mesh(me, NULL);
+ GridKey gridkey;
+
+ GRIDELEM_KEY_INIT(&gridkey, 1, 0, 0, 1);
+ ss = _getSubSurf(NULL, &gridkey, 1, 0, 1, 0);
ss_sync_from_derivedmesh(ss, dm, NULL, 0);
vi = ccgSubSurf_getVertIterator(ss);
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 77416f4dd12..2c5912bb122 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -69,6 +69,8 @@
#include "BKE_node.h"
#include "BKE_animsys.h"
+#include "RE_shader_ext.h"
+
/* ------------------------------------------------------------------------- */
@@ -1348,3 +1350,20 @@ int BKE_texture_dependsOnTime(const struct Tex *texture)
}
/* ------------------------------------------------------------------------- */
+
+void get_texture_value(Tex *texture, float *tex_co, TexResult *texres)
+{
+ int result_type;
+
+ result_type = multitex_ext(texture, tex_co, NULL, NULL, 0, texres);
+
+ /* if the texture gave an RGB value, we assume it didn't give a valid
+ * intensity, so calculate one (formula from do_material_tex).
+ * if the texture didn't give an RGB value, copy the intensity across
+ */
+ if(result_type & TEX_RGB)
+ texres->tin = (0.35f * texres->tr + 0.45f * texres->tg
+ + 0.2f * texres->tb);
+ else
+ texres->tr = texres->tg = texres->tb = texres->tin;
+}
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 0e985184f7a..7c9433405ac 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -40,6 +40,8 @@ extern "C" {
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "BKE_utildefines.h"
#include "BLI_mempool.h"
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index d2b9e6caf96..5144939b619 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -96,7 +96,6 @@ int isect_ray_tri_epsilon_v3(float p1[3], float d[3],
float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float epsilon);
/* point in polygon */
-int isect_point_tri_v2(float p[2], float a[2], float b[2], float c[2]);
int isect_point_quad_v2(float p[2], float a[2], float b[2], float c[2], float d[2]);
int isect_point_tri_v2(float v1[2], float v2[2], float v3[2], float pt[2]);
diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h
index 4797aeb2364..fed1c2fafee 100644
--- a/source/blender/blenlib/BLI_pbvh.h
+++ b/source/blender/blenlib/BLI_pbvh.h
@@ -25,17 +25,29 @@
#ifndef BLI_PBVH_H
#define BLI_PBVH_H
+#include <assert.h>
+
+struct BoundBox;
+struct CustomData;
struct MFace;
struct MVert;
+struct GridKey;
struct DMGridAdjacency;
struct DMGridData;
struct PBVH;
struct PBVHNode;
+struct GridToFace;
struct ListBase;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
+typedef struct PBVHHiddenArea {
+ struct PBVHHiddenArea *next, *prev;
+ float clip_planes[4][4];
+ int hide_inside;
+} HiddenArea;
+
typedef struct {
float (*co)[3];
} PBVHProxyNode;
@@ -48,14 +60,26 @@ typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float* tmin);
-/* Building */
+/* test AABB against sphere */
+typedef struct {
+ float *center;
+ float radius_squared;
+ int original;
+} PBVHSearchSphereData;
+int BLI_pbvh_search_sphere_cb(PBVHNode *node, void *data);
-PBVH *BLI_pbvh_new(void);
+/* Building */
+#define PBVH_DEFAULT_LEAF_LIMIT 10000
+PBVH *BLI_pbvh_new(int leaf_limit);
void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts,
- int totface, int totvert);
+ struct CustomData *vdata, struct CustomData *fdata,
+ int totface, int totvert, ListBase *hidden_areas);
void BLI_pbvh_build_grids(PBVH *bvh, struct DMGridData **grids,
- struct DMGridAdjacency *gridadj, int totgrid,
- int gridsize, void **gridfaces);
+ struct DMGridAdjacency *gridadj, int totgrid,
+ int gridsize, struct GridKey *gridkey, void **gridfaces,
+ struct GridToFace *grid_face_map,
+ struct CustomData *vdata, struct CustomData *fdata,
+ ListBase *hidden_areas);
void BLI_pbvh_free(PBVH *bvh);
/* Hierarchical Search in the BVH, two methods:
@@ -78,13 +102,14 @@ void BLI_pbvh_search_gather(PBVH *bvh,
void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
float ray_start[3], float ray_normal[3], int original);
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
- float ray_start[3], float ray_normal[3], float *dist);
+ float ray_start[3], float ray_normal[3], float *dist,
+ int *hit_index, int *grid_hit_index);
/* Drawing */
void BLI_pbvh_node_draw(PBVHNode *node, void *data);
int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data);
-void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int smooth);
+void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int flags);
/* Node Access */
@@ -94,19 +119,44 @@ typedef enum {
PBVH_UpdateNormals = 2,
PBVH_UpdateBB = 4,
PBVH_UpdateOriginalBB = 8,
- PBVH_UpdateDrawBuffers = 16,
- PBVH_UpdateRedraw = 32
+
+ /* Update vertex data (coord + normal */
+ PBVH_UpdateVertBuffers = 16,
+
+ /* Update color data (used for masks) */
+ PBVH_UpdateColorBuffers = 32,
+
+ PBVH_UpdateRedraw = 64,
+
+ PBVH_UpdateAll = PBVH_UpdateNormals |
+ PBVH_UpdateBB |
+ PBVH_UpdateOriginalBB |
+ PBVH_UpdateVertBuffers |
+ PBVH_UpdateColorBuffers |
+ PBVH_UpdateRedraw,
} PBVHNodeFlags;
void BLI_pbvh_node_mark_update(PBVHNode *node);
+void BLI_pbvh_node_set_flags(PBVHNode *node, void *data);
+
+/* returns true if the pbvh is using grids rather than faces */
+int BLI_pbvh_uses_grids(PBVH *bvh);
+
+void BLI_pbvh_get_customdata(PBVH *pbvh, struct CustomData **vdata, struct CustomData **fdata);
+struct GridToFace *BLI_pbvh_get_grid_face_map(PBVH *pbvh);
+void BLI_pbvh_node_get_faces(PBVH *bvh, PBVHNode *node,
+ struct MFace **faces,
+ int **face_indices, int **face_vert_indices,
+ int *totface);
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node,
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize,
- struct DMGridData ***griddata, struct DMGridAdjacency **gridadj);
+ struct DMGridData ***griddata, struct DMGridAdjacency **gridadj,
+ struct GridKey **gridkey);
void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node,
int *uniquevert, int *totvert);
void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node,
- int **vert_indices, struct MVert **verts);
+ int **vert_indices, struct MVert **verts);
void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
@@ -119,7 +169,7 @@ void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface);
void BLI_pbvh_grids_update(PBVH *bvh, struct DMGridData **grids,
- struct DMGridAdjacency *gridadj, void **gridfaces);
+ struct DMGridAdjacency *gridadj, void **gridfaces, struct GridKey *gridkey);
/* vertex deformer */
float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3];
@@ -148,22 +198,30 @@ typedef struct PBVHVertexIter {
/* grid */
struct DMGridData **grids;
- struct DMGridData *grid;
+ struct DMGridData *grid, *elem;
int *grid_indices;
int totgrid;
int gridsize;
+ struct GridKey *gridkey;
/* mesh */
struct MVert *mverts;
int totvert;
int *vert_indices;
+ /* mask layers */
+ struct CustomData *vdata;
+ int pmask_first_layer, pmask_layer_count, pmask_active_layer;
+
/* result: these are all computed in the macro, but we assume
that compiler optimizations will skip the ones we don't use */
struct MVert *mvert;
float *co;
short *no;
float *fno;
+ float *mask_active;
+
+ float mask_combined; /* not editable */
} PBVHVertexIter;
#ifdef _MSC_VER
@@ -175,21 +233,20 @@ typedef struct PBVHVertexIter {
struct DMGridData **grids; \
struct MVert *verts; \
int *grid_indices, totgrid, gridsize, *vert_indices, uniq_verts, totvert; \
+ struct GridKey *gridkey; \
\
- vi.grid= 0; \
- vi.no= 0; \
- vi.fno= 0; \
- vi.mvert= 0; \
- vi.skip= 0; \
+ memset(&vi, 0, sizeof(PBVHVertexIter)); \
\
- BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); \
+ BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL, &gridkey); \
BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); \
BLI_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); \
+ BLI_pbvh_get_customdata(bvh, &vi.vdata, NULL); \
\
vi.grids= grids; \
vi.grid_indices= grid_indices; \
vi.totgrid= (grids)? totgrid: 1; \
vi.gridsize= gridsize; \
+ vi.gridkey= gridkey; \
\
if(mode == PBVH_ITER_ALL) \
vi.totvert = totvert; \
@@ -197,6 +254,16 @@ typedef struct PBVHVertexIter {
vi.totvert= uniq_verts; \
vi.vert_indices= vert_indices; \
vi.mverts= verts; \
+ vi.mask_active= NULL; \
+ assert(!gridkey || gridkey->mask == 0 || vi.vdata); \
+ vi.pmask_layer_count = CustomData_number_of_layers(vi.vdata, CD_PAINTMASK); \
+ assert(!gridkey || gridkey->mask == 0 || gridkey->mask == vi.pmask_layer_count); \
+ if(vi.pmask_layer_count) { \
+ vi.pmask_first_layer = CustomData_get_layer_index(vi.vdata, CD_PAINTMASK); \
+ vi.pmask_active_layer = CustomData_get_active_layer_index(vi.vdata, CD_PAINTMASK); \
+ if(vi.pmask_active_layer != -1 && !(vi.vdata->layers[vi.pmask_active_layer].flag & CD_FLAG_ENABLED)) \
+ vi.pmask_active_layer = -1; \
+ } \
}\
\
for(vi.i=0, vi.g=0; vi.g<vi.totgrid; vi.g++) { \
@@ -218,24 +285,45 @@ typedef struct PBVHVertexIter {
} \
\
for(vi.gy=0; vi.gy<vi.height; vi.gy++) { \
- if(vi.grid) vi.grid += vi.skip; \
+ if(vi.grid) GRIDELEM_INC(vi.grid, vi.skip, vi.gridkey); \
\
for(vi.gx=0; vi.gx<vi.width; vi.gx++, vi.i++) { \
if(vi.grid) { \
- vi.co= vi.grid->co; \
- vi.fno= vi.grid->no; \
- vi.grid++; \
+ vi.co= GRIDELEM_CO(vi.grid, vi.gridkey); \
+ vi.fno= GRIDELEM_NO(vi.grid, vi.gridkey); \
+ \
+ if(vi.gridkey->mask) { \
+ vi.mask_combined = \
+ paint_mask_from_gridelem(vi.grid, vi.gridkey, vi.vdata); \
+ \
+ if(vi.pmask_active_layer != -1) \
+ vi.mask_active= &GRIDELEM_MASK(vi.grid, \
+ vi.gridkey)[vi.pmask_active_layer - \
+ vi.pmask_first_layer]; \
+ } \
+ \
+ vi.elem= vi.grid; \
+ GRIDELEM_INC(vi.grid, 1, vi.gridkey); \
} \
else { \
vi.mvert= &vi.mverts[vi.vert_indices[vi.gx]]; \
vi.co= vi.mvert->co; \
vi.no= vi.mvert->no; \
+ if(vi.pmask_layer_count) { \
+ vi.mask_combined = \
+ paint_mask_from_vertex(vi.vdata, vi.vert_indices[vi.gx], \
+ vi.pmask_layer_count, \
+ vi.pmask_first_layer); \
+ \
+ if(vi.pmask_active_layer != -1) \
+ vi.mask_active = &((float*)vi.vdata->layers[vi.pmask_active_layer].data)[vi.vert_indices[vi.gx]]; \
+ } \
} \
#define BLI_pbvh_vertex_iter_end \
} \
} \
- }
+ } \
void BLI_pbvh_node_get_proxies(PBVHNode* node, PBVHProxyNode** proxies, int* proxy_count);
void BLI_pbvh_node_free_proxies(PBVHNode* node);
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index 9d126a4a931..1e4a2e89d06 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -20,9 +20,9 @@
* ***** END GPL LICENSE BLOCK *****
*/
-
-
#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
#include "MEM_guardedalloc.h"
@@ -31,12 +31,14 @@
#include "BLI_pbvh.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
#include "BKE_mesh.h" /* for mesh_calc_normals */
#include "BKE_global.h" /* for mesh_calc_normals */
+#include "BKE_paint.h"
#include "GPU_buffers.h"
-#define LEAF_LIMIT 10000
+static void pbvh_free_nodes(PBVH *bvh);
//#define PERFCNTRS
@@ -121,6 +123,14 @@ struct PBVH {
void **gridfaces;
int totgrid;
int gridsize;
+ struct GridKey *gridkey;
+ struct GridToFace *grid_face_map;
+
+ /* Used by both mesh and grid type */
+ CustomData *vdata;
+
+ /* For vertex paint */
+ CustomData *fdata;
/* Only used during BVH build and update,
don't need to remain valid after */
@@ -153,6 +163,62 @@ typedef struct PBVHIter {
int stackspace;
} PBVHIter;
+/* Test AABB against sphere */
+int BLI_pbvh_search_sphere_cb(PBVHNode *node, void *data_v)
+{
+ PBVHSearchSphereData *data = data_v;
+ float 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] > data->center[i])
+ nearest[i] = bb_min[i];
+ else if(bb_max[i] < data->center[i])
+ nearest[i] = bb_max[i];
+ else
+ nearest[i] = data->center[i];
+ }
+
+ sub_v3_v3v3(t, data->center, nearest);
+
+ return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
+}
+
+/* Adapted from:
+ http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
+ Returns true if the AABB is at least partially within the frustum
+ (ok, not a real frustum), false otherwise.
+*/
+static int pbvh_planes_contain_AABB(float bb_min[3], float bb_max[3], float (*planes)[4])
+{
+ int i, axis;
+ float vmin[3], vmax[3];
+
+ for(i = 0; i < 4; ++i) {
+ for(axis = 0; axis < 3; ++axis) {
+ if(planes[i][axis] > 0) {
+ vmin[axis] = bb_min[axis];
+ vmax[axis] = bb_max[axis];
+ }
+ else {
+ vmin[axis] = bb_max[axis];
+ vmax[axis] = bb_min[axis];
+ }
+ }
+
+ if(dot_v3v3(planes[i], vmin) + planes[i][3] > 0)
+ return 0;
+ }
+
+ return 1;
+}
+
static void BB_reset(BB *bb)
{
bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
@@ -372,13 +438,15 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
if(!G.background) {
node->draw_buffers =
GPU_build_mesh_buffers(map, bvh->verts, bvh->faces,
- node->prim_indices,
- node->totprim, node->vert_indices,
- node->uniq_verts,
- node->uniq_verts + node->face_verts);
+ bvh->vdata,
+ bvh->fdata,
+ node->prim_indices,
+ node->totprim, node->vert_indices,
+ node->uniq_verts,
+ node->uniq_verts + node->face_verts);
}
- node->flag |= PBVH_UpdateDrawBuffers;
+ node->flag |= PBVH_UpdateVertBuffers|PBVH_UpdateColorBuffers;
BLI_ghash_free(map, NULL, NULL);
}
@@ -387,10 +455,9 @@ static void build_grids_leaf_node(PBVH *bvh, PBVHNode *node)
{
if(!G.background) {
node->draw_buffers =
- GPU_build_grid_buffers(bvh->grids, node->prim_indices,
- node->totprim, bvh->gridsize);
+ GPU_build_grid_buffers(bvh->gridsize);
}
- node->flag |= PBVH_UpdateDrawBuffers;
+ node->flag |= PBVH_UpdateVertBuffers|PBVH_UpdateColorBuffers;
}
/* Recursively build a node in the tree
@@ -472,119 +539,175 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
prim_bbc, end, offset + count - end);
}
-static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
+/* Returns 0 if the primitive should be hidden, 1 otherwise */
+static int test_prim_against_hidden_areas(BBC *prim_bbc, ListBase *hidden_areas)
{
- int i;
+ HiddenArea *area;
+
+ for(area = hidden_areas->first; area; area = area->next) {
+ int prim_inside_planes = pbvh_planes_contain_AABB(prim_bbc->bmin, prim_bbc->bmax, area->clip_planes);
+ if((prim_inside_planes && area->hide_inside) || (!prim_inside_planes && !area->hide_inside))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Initially, the root node contains all primitives in
+ their original order.
+
+ If we are clipping, exclude primitives outside the
+ clip planes from the primitive list
+*/
+static int pbvh_initialize_prim_indices(PBVH *bvh, BBC *prim_bbc, int totprim, ListBase *hidden_areas)
+{
+ int prim, index;
+ int *prim_indices;
+
+ prim_indices = MEM_callocN(sizeof(int) * totprim, "bvh prim indices");
+
+ for(prim= 0, index = 0; prim < totprim; ++prim) {
+ if(!hidden_areas || test_prim_against_hidden_areas(&prim_bbc[prim], hidden_areas)) {
+ prim_indices[index] = prim;
+ ++index;
+ }
+ }
+
+ if(index == prim) {
+ bvh->prim_indices = prim_indices;
+ return totprim;
+ }
+ else {
+ bvh->prim_indices = MEM_callocN(sizeof(int) * index, "bvh prim indices");
+ memcpy(bvh->prim_indices, prim_indices, sizeof(int) * index);
+ MEM_freeN(prim_indices);
+ return index;
+ }
+}
+
+static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim, ListBase *hidden_areas)
+{
+ int max_prim_index;
if(totprim != bvh->totprim) {
+ /* Initialize the nodes */
bvh->totprim = totprim;
- if(bvh->nodes) MEM_freeN(bvh->nodes);
+ if(bvh->nodes)
+ pbvh_free_nodes(bvh);
if(bvh->prim_indices) MEM_freeN(bvh->prim_indices);
- bvh->prim_indices = MEM_callocN(sizeof(int) * totprim,
- "bvh prim indices");
- for(i = 0; i < totprim; ++i)
- bvh->prim_indices[i] = i;
+
+ max_prim_index = pbvh_initialize_prim_indices(bvh, prim_bbc, totprim, hidden_areas);
+
bvh->totnode = 0;
- if(bvh->node_mem_count < 100) {
+ if(bvh->node_mem_count < 100)
bvh->node_mem_count = 100;
- bvh->nodes = MEM_callocN(sizeof(PBVHNode) *
- bvh->node_mem_count,
- "bvh initial nodes");
- }
+
+ bvh->nodes = MEM_callocN(sizeof(PBVHNode) *
+ bvh->node_mem_count,
+ "bvh initial nodes");
}
bvh->totnode = 1;
- build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
+ build_sub(bvh, 0, cb, prim_bbc, 0, max_prim_index);
}
-/* Do a full rebuild with on Mesh data structure */
-void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert)
+void pbvh_begin_build(PBVH *bvh, int totprim, ListBase *hidden_areas)
{
- BBC *prim_bbc = NULL;
- BB cb;
int i, j;
+ int totgridelem;
+ BBC *prim_bbc;
+ BB cb;
- bvh->faces = faces;
- bvh->verts = verts;
- bvh->vert_bitmap = BLI_bitmap_new(totvert);
- bvh->totvert = totvert;
- bvh->leaf_limit = LEAF_LIMIT;
-
+ /* cb will be the bounding box around all primitives' centroids */
BB_reset(&cb);
- /* For each face, store the AABB and the AABB centroid */
- prim_bbc = MEM_mallocN(sizeof(BBC) * totface, "prim_bbc");
+ if(bvh->faces)
+ bvh->vert_bitmap = BLI_bitmap_new(bvh->totvert);
+ else
+ totgridelem = bvh->gridsize*bvh->gridsize;
+
+ /* For each primitive, store the AABB and the AABB centroid */
+ prim_bbc = MEM_mallocN(sizeof(BBC) * totprim, "prim_bbc");
- for(i = 0; i < totface; ++i) {
- MFace *f = faces + i;
- const int sides = f->v4 ? 4 : 3;
+ for(i = 0; i < totprim; ++i) {
BBC *bbc = prim_bbc + i;
BB_reset((BB*)bbc);
- for(j = 0; j < sides; ++j)
- BB_expand((BB*)bbc, verts[(&f->v1)[j]].co);
+ if(bvh->faces) {
+ /* For regular mesh */
+ MFace *f = bvh->faces + i;
+ const int sides = f->v4 ? 4 : 3;
+ for(j = 0; j < sides; ++j)
+ BB_expand((BB*)bbc, bvh->verts[(&f->v1)[j]].co);
+ }
+ else {
+ /* For multires */
+ DMGridData *grid= bvh->grids[i];
+ for(j = 0; j < totgridelem; ++j)
+ BB_expand((BB*)bbc, GRIDELEM_CO_AT(grid, j, bvh->gridkey));
+ }
BBC_update_centroid(bbc);
-
BB_expand(&cb, bbc->bcentroid);
}
- if(totface)
- pbvh_build(bvh, &cb, prim_bbc, totface);
+ pbvh_build(bvh, &cb, prim_bbc, totprim, hidden_areas);
MEM_freeN(prim_bbc);
- MEM_freeN(bvh->vert_bitmap);
+ if(bvh->faces)
+ MEM_freeN(bvh->vert_bitmap);
}
-/* Do a full rebuild with on Grids data structure */
-void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids, DMGridAdjacency *gridadj,
- int totgrid, int gridsize, void **gridfaces)
+/* Do a full rebuild with on Mesh data structure */
+void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts,
+ CustomData *vdata, CustomData *fdata,
+ int totface, int totvert,
+ ListBase *hidden_areas)
{
- BBC *prim_bbc = NULL;
- BB cb;
- int i, j;
+ bvh->faces = faces;
+ bvh->verts = verts;
+ bvh->vdata = vdata;
+ bvh->fdata = fdata;
+ bvh->totvert = totvert;
+ if(totface)
+ pbvh_begin_build(bvh, totface, hidden_areas);
+}
+
+/* Do a full rebuild with on Grids data structure */
+void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids,
+ DMGridAdjacency *gridadj,
+ int totgrid, int gridsize, GridKey *gridkey,
+ void **gridfaces, GridToFace *grid_face_map,
+ CustomData *vdata, CustomData *fdata,
+ ListBase *hidden_areas)
+{
bvh->grids= grids;
bvh->gridadj= gridadj;
bvh->gridfaces= gridfaces;
bvh->totgrid= totgrid;
bvh->gridsize= gridsize;
- bvh->leaf_limit = MAX2(LEAF_LIMIT/((gridsize-1)*(gridsize-1)), 1);
-
- BB_reset(&cb);
-
- /* For each grid, store the AABB and the AABB centroid */
- prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
-
- for(i = 0; i < totgrid; ++i) {
- DMGridData *grid= grids[i];
- BBC *bbc = prim_bbc + i;
-
- BB_reset((BB*)bbc);
-
- for(j = 0; j < gridsize*gridsize; ++j)
- BB_expand((BB*)bbc, grid[j].co);
-
- BBC_update_centroid(bbc);
-
- BB_expand(&cb, bbc->bcentroid);
- }
+ bvh->gridkey= gridkey;
+ bvh->vdata= vdata;
+ bvh->fdata= fdata;
+ bvh->leaf_limit = MAX2(bvh->leaf_limit/((gridsize-1)*(gridsize-1)), 1);
+ bvh->grid_face_map = grid_face_map;
if(totgrid)
- pbvh_build(bvh, &cb, prim_bbc, totgrid);
-
- MEM_freeN(prim_bbc);
+ pbvh_begin_build(bvh, totgrid, hidden_areas);
}
-PBVH *BLI_pbvh_new(void)
+PBVH *BLI_pbvh_new(int leaf_limit)
{
PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
+ bvh->leaf_limit = leaf_limit;
+
return bvh;
}
-void BLI_pbvh_free(PBVH *bvh)
+static void pbvh_free_nodes(PBVH *bvh)
{
PBVHNode *node;
int i;
@@ -612,6 +735,12 @@ void BLI_pbvh_free(PBVH *bvh)
}
MEM_freeN(bvh->nodes);
+}
+
+void BLI_pbvh_free(PBVH *bvh)
+{
+ pbvh_free_nodes(bvh);
+
MEM_freeN(bvh->prim_indices);
MEM_freeN(bvh);
}
@@ -1011,7 +1140,7 @@ static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes,
}
}
-static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, int smooth)
+static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, DMDrawFlags flags)
{
PBVHNode *node;
int n;
@@ -1020,24 +1149,55 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, i
for(n = 0; n < totnode; n++) {
node= nodes[n];
- if(node->flag & PBVH_UpdateDrawBuffers) {
+ if(node->flag & PBVH_UpdateVertBuffers) {
if(bvh->grids) {
- GPU_update_grid_buffers(node->draw_buffers,
- bvh->grids,
- node->prim_indices,
- node->totprim,
- bvh->gridsize,
- smooth);
+ GPU_update_grid_vert_buffers(node->draw_buffers,
+ bvh->grids,
+ node->prim_indices,
+ node->totprim,
+ bvh->gridsize,
+ bvh->gridkey,
+ flags & DM_DRAW_FULLY_SMOOTH);
}
else {
- GPU_update_mesh_buffers(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts +
- node->face_verts);
+ GPU_update_mesh_vert_buffers(node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts +
+ node->face_verts);
}
- node->flag &= ~PBVH_UpdateDrawBuffers;
+ node->flag &= ~PBVH_UpdateVertBuffers;
+ }
+
+ if(node->flag & PBVH_UpdateColorBuffers) {
+ if(bvh->grids) {
+ if(flags & DM_DRAW_PTEX) {
+ GPU_update_ptex(node->draw_buffers, bvh, node);
+ /* TODO: should only do this after ptex
+ res change */
+ GPU_update_grid_uv_buffer(node->draw_buffers,
+ bvh, node, flags);
+ }
+ else if(flags & DM_DRAW_PAINT_MASK) {
+ GPU_update_grid_color_buffers(node->draw_buffers,
+ bvh->grids,
+ node->prim_indices,
+ node->totprim,
+ bvh->gridsize,
+ bvh->gridkey,
+ bvh->vdata,
+ flags);
+ }
+ }
+ else {
+ if(flags & DM_DRAW_PAINT_MASK) {
+ GPU_update_mesh_color_buffers(node->draw_buffers,
+ bvh, node, flags);
+ }
+ }
+
+ node->flag &= ~PBVH_UpdateColorBuffers;
}
}
}
@@ -1093,6 +1253,8 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3])
if(nodes) MEM_freeN(nodes);
}
+/* get the object-space bounding box containing all the nodes that
+ have been marked with PBVH_UpdateRedraw */
void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
{
PBVHIter iter;
@@ -1128,7 +1290,7 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot
pbvh_iter_begin(&iter, bvh, NULL, NULL);
while((node=pbvh_iter_next(&iter))) {
- if(node->flag & PBVH_UpdateNormals) {
+ if(node->flag & (PBVH_UpdateNormals)) {
for(i = 0; i < node->totprim; ++i) {
face= bvh->gridfaces[node->prim_indices[i]];
if(!BLI_ghash_lookup(map, face))
@@ -1165,11 +1327,34 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot
*gridfaces= faces;
}
+/**** Access to mesh/grid data ****/
+int BLI_pbvh_uses_grids(PBVH *bvh)
+{
+ return !!bvh->grids;
+}
+
+void BLI_pbvh_get_customdata(PBVH *bvh, CustomData **vdata, CustomData **fdata)
+{
+ if(vdata) *vdata = bvh->vdata;
+ if(fdata) *fdata = bvh->fdata;
+}
+
+GridToFace *BLI_pbvh_get_grid_face_map(PBVH *pbvh)
+{
+ return pbvh->grid_face_map;
+}
+
+
/***************************** Node Access ***********************************/
void BLI_pbvh_node_mark_update(PBVHNode *node)
{
- node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw;
+ node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateVertBuffers|PBVH_UpdateRedraw;
+}
+
+void BLI_pbvh_node_set_flags(PBVHNode *node, void *data)
+{
+ node->flag |= GET_INT_FROM_POINTER(data);
}
void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts)
@@ -1182,7 +1367,7 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
{
if(bvh->grids) {
if(totvert) *totvert= node->totprim*bvh->gridsize*bvh->gridsize;
- if(uniquevert) *uniquevert= *totvert;
+ if(uniquevert) *uniquevert= node->totprim*bvh->gridsize*bvh->gridsize;
}
else {
if(totvert) *totvert= node->uniq_verts + node->face_verts;
@@ -1190,7 +1375,26 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
}
}
-void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, DMGridData ***griddata, DMGridAdjacency **gridadj)
+void BLI_pbvh_node_get_faces(PBVH *bvh, PBVHNode *node,
+ MFace **mface,
+ int **face_indices, int **face_vert_indices,
+ int *totnode)
+{
+ if(bvh->grids) {
+ if(mface) *mface= NULL;
+ if(face_indices) *face_indices= NULL;
+ if(face_vert_indices) *face_vert_indices= NULL;
+ if(totnode) *totnode= 0;
+ }
+ else {
+ if(mface) *mface= bvh->faces;
+ if(face_indices) *face_indices= node->prim_indices;
+ if(face_vert_indices) *face_vert_indices= node->face_vert_indices;
+ if(totnode) *totnode= node->totprim;
+ }
+}
+
+void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, DMGridData ***griddata, DMGridAdjacency **gridadj, GridKey **gridkey)
{
if(bvh->grids) {
if(grid_indices) *grid_indices= node->prim_indices;
@@ -1199,6 +1403,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if(gridsize) *gridsize= bvh->gridsize;
if(griddata) *griddata= bvh->grids;
if(gridadj) *gridadj= bvh->gridadj;
+ if(gridkey) *gridkey= bvh->gridkey;
}
else {
if(grid_indices) *grid_indices= NULL;
@@ -1207,6 +1412,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if(gridsize) *gridsize= 0;
if(griddata) *griddata= NULL;
if(gridadj) *gridadj= NULL;
+ if(gridkey) *gridkey= NULL;
}
}
@@ -1324,10 +1530,14 @@ static int ray_face_intersection(float ray_start[3], float ray_normal[3],
}
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
- float ray_start[3], float ray_normal[3], float *dist)
+ float ray_start[3], float ray_normal[3], float *dist,
+ int *hit_index, int *grid_hit_index)
{
int hit= 0;
+ if(hit_index) *hit_index = -1;
+ if(grid_hit_index) *grid_hit_index = -1;
+
if(bvh->faces) {
MVert *vert = bvh->verts;
int *faces= node->prim_indices;
@@ -1337,10 +1547,11 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
for(i = 0; i < totface; ++i) {
MFace *f = bvh->faces + faces[i];
+ int lhit = 0;
if(origco) {
/* intersect with backuped original coordinates */
- hit |= ray_face_intersection(ray_start, ray_normal,
+ lhit = ray_face_intersection(ray_start, ray_normal,
origco[face_verts[i*4+0]],
origco[face_verts[i*4+1]],
origco[face_verts[i*4+2]],
@@ -1349,13 +1560,18 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
}
else {
/* intersect with current coordinates */
- hit |= ray_face_intersection(ray_start, ray_normal,
+ lhit = ray_face_intersection(ray_start, ray_normal,
vert[f->v1].co,
vert[f->v2].co,
vert[f->v3].co,
f->v4 ? vert[f->v4].co : NULL,
dist);
}
+
+ if(lhit && hit_index)
+ *hit_index = i;
+
+ hit |= lhit;
}
}
else {
@@ -1365,13 +1581,16 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
for(i = 0; i < totgrid; ++i) {
DMGridData *grid= bvh->grids[node->prim_indices[i]];
+
if (!grid)
continue;
for(y = 0; y < gridsize-1; ++y) {
for(x = 0; x < gridsize-1; ++x) {
+ int lhit = 0;
+
if(origco) {
- hit |= ray_face_intersection(ray_start, ray_normal,
+ lhit |= ray_face_intersection(ray_start, ray_normal,
origco[y*gridsize + x],
origco[y*gridsize + x+1],
origco[(y+1)*gridsize + x+1],
@@ -1379,13 +1598,20 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
dist);
}
else {
- hit |= ray_face_intersection(ray_start, ray_normal,
- grid[y*gridsize + x].co,
- grid[y*gridsize + x+1].co,
- grid[(y+1)*gridsize + x+1].co,
- grid[(y+1)*gridsize + x].co,
+ lhit |= ray_face_intersection(ray_start, ray_normal,
+ GRIDELEM_CO_AT(grid, y*gridsize + x, bvh->gridkey),
+ GRIDELEM_CO_AT(grid, y*gridsize + x+1, bvh->gridkey),
+ GRIDELEM_CO_AT(grid, (y+1)*gridsize + x+1, bvh->gridkey),
+ GRIDELEM_CO_AT(grid, (y+1)*gridsize + x, bvh->gridkey),
dist);
}
+
+ if(lhit) {
+ if(hit_index) *hit_index = i;
+ if(grid_hit_index) *grid_hit_index = y*gridsize + x;
+ }
+
+ hit |= lhit;
}
}
@@ -1399,7 +1625,12 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
//#include <GL/glew.h>
-void BLI_pbvh_node_draw(PBVHNode *node, void *UNUSED(data))
+typedef struct {
+ PBVH *pbvh;
+ DMDrawFlags flags;
+} PBVHDrawData;
+
+void BLI_pbvh_node_draw(PBVHNode *node, void *data_v)
{
#if 0
/* XXX: Just some quick code to show leaf nodes in different colors */
@@ -1417,68 +1648,52 @@ void BLI_pbvh_node_draw(PBVHNode *node, void *UNUSED(data))
glColor3f(1, 0, 0);
#endif
- GPU_draw_buffers(node->draw_buffers);
+
+ PBVHDrawData *data = data_v;
+ GPU_draw_buffers(node->draw_buffers, data->pbvh, node, data->flags);
}
-/* Adapted from:
- http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
- Returns true if the AABB is at least partially within the frustum
- (ok, not a real frustum), false otherwise.
-*/
int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
{
- float (*planes)[4] = data;
- int i, axis;
- float vmin[3], vmax[3], bb_min[3], bb_max[3];
+ float bb_min[3], bb_max[3];
BLI_pbvh_node_get_BB(node, bb_min, bb_max);
- for(i = 0; i < 4; ++i) {
- for(axis = 0; axis < 3; ++axis) {
- if(planes[i][axis] > 0) {
- vmin[axis] = bb_min[axis];
- vmax[axis] = bb_max[axis];
- }
- else {
- vmin[axis] = bb_max[axis];
- vmax[axis] = bb_min[axis];
- }
- }
-
- if(dot_v3v3(planes[i], vmin) + planes[i][3] > 0)
- return 0;
- }
-
- return 1;
+ return pbvh_planes_contain_AABB(bb_min, bb_max, data);
}
-void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int smooth)
+void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int flags)
{
PBVHNode **nodes;
+ PBVHDrawData draw_data = {bvh, flags};
int totnode;
- BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals|PBVH_UpdateDrawBuffers),
+ BLI_pbvh_search_gather(bvh, update_search_cb,
+ SET_INT_IN_POINTER(PBVH_UpdateNormals|PBVH_UpdateVertBuffers|PBVH_UpdateColorBuffers),
&nodes, &totnode);
pbvh_update_normals(bvh, nodes, totnode, face_nors);
- pbvh_update_draw_buffers(bvh, nodes, totnode, smooth);
+ pbvh_update_draw_buffers(bvh, nodes, totnode, flags);
if(nodes) MEM_freeN(nodes);
if(planes) {
BLI_pbvh_search_callback(bvh, BLI_pbvh_node_planes_contain_AABB,
- planes, BLI_pbvh_node_draw, NULL);
+ planes, BLI_pbvh_node_draw, &draw_data);
}
else {
- BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, NULL);
+ BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, &draw_data);
}
}
-void BLI_pbvh_grids_update(PBVH *bvh, DMGridData **grids, DMGridAdjacency *gridadj, void **gridfaces)
+void BLI_pbvh_grids_update(PBVH *bvh, DMGridData **grids,
+ DMGridAdjacency *gridadj, void **gridfaces,
+ struct GridKey *gridkey)
{
bvh->grids= grids;
bvh->gridadj= gridadj;
bvh->gridfaces= gridfaces;
+ bvh->gridkey= gridkey;
}
float (*BLI_pbvh_get_vertCos(PBVH *pbvh))[3]
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index cc70d3355f2..511b3f5e408 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -35,6 +35,7 @@ SET(INC
../include
../makesrna
../render/extern/include
+ ../../../extern/ptex
../../../intern/guardedalloc
${ZLIB_INC}
)
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
index 88d345290e5..a68e773478a 100644
--- a/source/blender/blenloader/SConscript
+++ b/source/blender/blenloader/SConscript
@@ -6,6 +6,7 @@ sources = env.Glob('intern/*.c')
incs = '. #/intern/guardedalloc ../blenlib ../blenkernel'
incs += ' ../makesdna ../readblenfile ../editors/include'
incs += ' ../render/extern/include ../makesrna'
+incs += ' #/extern/ptex'
incs += ' ' + env['BF_ZLIB_INC']
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b6515863c2b..51d68560116 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3257,6 +3257,34 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
}
}
+static void direct_link_customdata_multires(FileData *fd, int count,
+ CustomDataMultires *cdm)
+{
+ if(cdm) {
+ int i, j;
+
+ for(i = 0; i < count; ++i, ++cdm) {
+ cdm->layers = newdataadr(fd, cdm->layers);
+ for(j = 0; j < cdm->totlayer; ++j) {
+ CustomDataMultiresLayer *l = cdm->layers + j;
+ l->griddata = newdataadr(fd, l->griddata);
+ }
+ }
+ }
+}
+
+static void direct_link_customdata_mptex(FileData *fd, int count, MPtex *mptex)
+{
+ if(mptex) {
+ int i, j;
+
+ for(i = 0; i < count; ++i, ++mptex) {
+ for(j = 0; j < mptex->totsubface; ++j)
+ mptex->subfaces[j].data = newdataadr(fd, mptex->subfaces[j].data);
+ }
+ }
+}
+
static void direct_link_customdata(FileData *fd, CustomData *data, int count)
{
int i = 0;
@@ -3274,6 +3302,10 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count)
layer->data = newdataadr(fd, layer->data);
if(layer->type == CD_MDISPS)
direct_link_mdisps(fd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ if(layer->type == CD_GRIDS)
+ direct_link_customdata_multires(fd, count, layer->data);
+ if(layer->type == CD_MPTEX)
+ direct_link_customdata_mptex(fd, count, layer->data);
i++;
}
}
@@ -4100,9 +4132,10 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->gpulamp.first= ob->gpulamp.last= NULL;
link_list(fd, &ob->pc_ids);
- if(ob->sculpt) {
- ob->sculpt= MEM_callocN(sizeof(SculptSession), "reload sculpt session");
- ob->sculpt->ob= ob;
+ if(ob->paint) {
+ ob->paint = MEM_callocN(sizeof(PaintSession), "PaintSession");
+ if(ob->mode & OB_MODE_SCULPT)
+ ob->paint->sculpt= MEM_callocN(sizeof(SculptSession), "reload sculpt session");
}
}
@@ -4137,6 +4170,8 @@ static void lib_link_scene(FileData *fd, Main *main)
sce= main->scene.first;
while(sce) {
if(sce->id.flag & LIB_NEEDLINK) {
+ ToolSettings *ts;
+
/*Link ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
@@ -4150,10 +4185,18 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima);
sce->gpd= newlibadr_us(fd, sce->id.lib, sce->gpd);
- link_paint(fd, sce, &sce->toolsettings->sculpt->paint);
- link_paint(fd, sce, &sce->toolsettings->vpaint->paint);
- link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
- link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
+ ts = sce->toolsettings;
+ link_paint(fd, sce, &ts->sculpt->paint);
+ link_paint(fd, sce, &ts->vpaint->paint);
+ link_paint(fd, sce, &ts->wpaint->paint);
+ link_paint(fd, sce, &ts->imapaint.paint);
+ if(ts) {
+ if(ts->paint_overlay.img)
+ ts->paint_overlay.img = newlibadr_us(fd, sce->id.lib, ts->paint_overlay.img);
+ ts->paint_overlay.gltex = 0;
+ if(!ts->ptex_ures) ts->ptex_ures = 128;
+ if(!ts->ptex_vres) ts->ptex_vres = 128;
+ }
sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index b5715353c6c..3ad3936cbed 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -150,6 +150,8 @@ Any case: direct data is ALWAYS after the lib block
#include "readfile.h"
+#include "ptex.h"
+
#include <errno.h>
/* ********* my write, buffered writing with minimum size chunks ************ */
@@ -1463,6 +1465,44 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
}
}
+static void write_customdata_multires(WriteData *wd, int count,
+ CustomDataMultires *grids)
+{
+ int i, j;
+
+ writestruct(wd, DATA, "CustomDataMultires", count, grids);
+
+ for(i = 0; i < count; ++i) {
+ writestruct(wd, DATA, "CustomDataMultiresLayer",
+ grids[i].totlayer, grids[i].layers);
+
+ for(j = 0; j < grids[i].totlayer; ++j) {
+ CustomDataMultiresLayer *l = &grids[i].layers[j];
+
+ writedata(wd, DATA, sizeof(float) * grids[i].totelem *
+ CustomData_multires_type_totfloat(l->type),
+ l->griddata);
+ }
+ }
+}
+
+static void write_customdata_mptex(WriteData *wd, int count,
+ MPtex *mptex)
+{
+ int i, j;
+
+ writestruct(wd, DATA, "MPtex", count, mptex);
+
+ for(i = 0; i < count; ++i, ++mptex) {
+ int layersize = mptex->channels * ptex_data_size(mptex->type);
+
+ for(j = 0; j < mptex->totsubface; ++j)
+ writedata(wd, DATA,
+ layersize * (mptex->subfaces[j].res[0] * mptex->subfaces[j].res[1]),
+ mptex->subfaces[j].data);
+ }
+}
+
static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, int partial_type, int partial_count)
{
int i;
@@ -1485,6 +1525,15 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
else if (layer->type == CD_MDISPS) {
write_mdisps(wd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
}
+ else if (layer->type == CD_PAINTMASK) {
+ writedata(wd, DATA, sizeof(float)*count, layer->data);
+ }
+ else if (layer->type == CD_GRIDS) {
+ write_customdata_multires(wd, count, layer->data);
+ }
+ else if (layer->type == CD_MPTEX) {
+ write_customdata_mptex(wd, count, layer->data);
+ }
else {
CustomData_file_write_info(layer->type, &structname, &structnum);
if (structnum) {
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;
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 5de7b0c5281..c3fff768486 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -35,6 +35,7 @@ SET(INC
../makesdna
../makesrna
../../../extern/glew/include
+ ../../../extern/ptex
../../../intern/guardedalloc
../../../intern/smoke/extern
)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 6f552e087d7..dcda5ccf391 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -51,7 +51,9 @@
struct DerivedMesh;
struct DMGridData;
struct GHash;
-struct DMGridData;
+struct GridKey;
+struct PBVH;
+struct PBVHNode;
/* V - vertex, N - normal, T - uv, C - color
F - float, UB - unsigned byte */
@@ -131,19 +133,38 @@ void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
void GPU_drawobject_free( struct DerivedMesh *dm );
-/* Buffers for non-DerivedMesh drawing */
-void *GPU_build_mesh_buffers(struct GHash *map, struct MVert *mvert,
- struct MFace *mface, int *face_indices,
- int totface, int *vert_indices, int uniq_verts,
- int totvert);
-void GPU_update_mesh_buffers(void *buffers, struct MVert *mvert,
- int *vert_indices, int totvert);
-void *GPU_build_grid_buffers(struct DMGridData **grids,
- int *grid_indices, int totgrid, int gridsize);
-void GPU_update_grid_buffers(void *buffers_v, struct DMGridData **grids,
- int *grid_indices, int totgrid, int gridsize, int smooth);
-void GPU_draw_buffers(void *buffers);
-void GPU_free_buffers(void *buffers);
+/* Buffers for PBVH drawing */
+typedef struct GPU_Buffers GPU_Buffers;
+enum DMDrawFlags;
+GPU_Buffers *GPU_build_mesh_buffers(struct GHash *map, struct MVert *mvert,
+ struct MFace *mface, struct CustomData *vdata,
+ struct CustomData *fdata, int *face_indices,
+ int totface, int *vert_indices, int uniq_verts,
+ int totvert);
+void GPU_update_mesh_vert_buffers(GPU_Buffers *buffers, struct MVert *mvert,
+ int *vert_indices, int totvert);
+void GPU_update_mesh_color_buffers(GPU_Buffers *buffers,
+ struct PBVH *bvh,
+ struct PBVHNode *node,
+ enum DMDrawFlags flags);
+GPU_Buffers *GPU_build_grid_buffers(int gridsize);
+void GPU_update_grid_vert_buffers(GPU_Buffers *buffersb, struct DMGridData **grids,
+ int *grid_indices, int totgrid, int gridsize,
+ struct GridKey *gridkey, int smooth);
+void GPU_update_grid_color_buffers(GPU_Buffers *buffers,
+ struct DMGridData **grids,
+ int *grid_indices, int totgrid,
+ int gridsize, struct GridKey *gridkey,
+ struct CustomData *vdata, enum DMDrawFlags flags);
+void GPU_update_grid_uv_buffer(GPU_Buffers *buffers,
+ struct PBVH *pbvh,
+ struct PBVHNode *node,
+ enum DMDrawFlags flags);
+
+void GPU_update_ptex(GPU_Buffers *buffers, struct PBVH *bvh, struct PBVHNode *node);
+void GPU_draw_buffers(GPU_Buffers *buffers, struct PBVH *bvh,
+ struct PBVHNode *node, enum DMDrawFlags flags);
+void GPU_free_buffers(GPU_Buffers *buffers);
/* called before drawing */
void GPU_vertex_setup( struct DerivedMesh *dm );
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index 4f1cdc2ce76..e68fd852929 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -7,6 +7,7 @@ defs = [ 'GLEW_STATIC' ]
incs = '../blenlib ../blenkernel ../makesdna ../include'
incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf .'
+incs += ' #/extern/ptex'
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 90c33f68c65..3c9648c33a5 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -35,16 +35,21 @@
#include <string.h>
#include "GL/glew.h"
+#include "ptex.h"
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_threads.h"
+#include "BLI_pbvh.h"
#include "DNA_meshdata_types.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_dmgrid.h"
+#include "BKE_paint.h"
+#include "BKE_utildefines.h"
#include "DNA_userdef_types.h"
@@ -398,36 +403,187 @@ void GPU_drawobject_free( DerivedMesh *dm )
dm->drawObject = 0;
}
+/* XXX: don't merge this to trunk
+
+ I'm having graphics problems with GL_SHORT normals;
+ this is on experimental drivers that I'm sure not
+ very many other people are using, so not worth really
+ fixing.
+*/
+#define VBO_FLOATS 1
+
/* Convenience struct for building the VBO. */
typedef struct {
float co[3];
+#ifdef VBO_FLOATS
+ float no[3];
+#else
short no[3];
+#endif
} VertexBufferFormat;
-typedef struct {
+struct GPU_Buffers {
/* opengl buffer handles */
- GLuint vert_buf, index_buf;
+ GLuint vert_buf, index_buf, color_buf, uv_buf;
GLenum index_type;
- /* mesh pointers in case buffer allocation fails */
- MFace *mface;
- MVert *mvert;
- int *face_indices;
- int totface;
+ GLuint *ptex;
+ int totptex;
- /* grid pointers */
- DMGridData **grids;
- int *grid_indices;
- int totgrid;
+ int use_grids;
+ unsigned int tot_tri;
int gridsize;
+};
+
+static void delete_buffer(GLuint *buf)
+{
+ glDeleteBuffersARB(1, buf);
+ *buf = 0;
+}
+
+static void gpu_colors_from_floats(unsigned char out[3],
+ float fcol[3],
+ float mask_strength)
+{
+ CLAMP(mask_strength, 0, 1);
+ /* avoid making the mask output completely black */
+ mask_strength = (1 - mask_strength) * 0.75 + 0.25;
+
+ out[0] = fcol[0] * mask_strength * 255;
+ out[1] = fcol[1] * mask_strength * 255;
+ out[2] = fcol[2] * mask_strength * 255;
+}
+
+/* create or destroy a buffer as needed, return a pointer to the buffer data.
+ if the return value is not null, it must be freed with glUnmapBuffer */
+static void *map_buffer(GPU_Buffers *buffers, GLuint *id, int needed, int totelem, int elemsize)
+{
+ void *data = NULL;
- unsigned int tot_tri, tot_quad;
-} GPU_Buffers;
+ if(needed && !(*id))
+ glGenBuffersARB(1, id);
+ else if(!needed && (*id))
+ delete_buffer(id);
+
+ if(needed && (*id)) {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, *id);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB,
+ elemsize * totelem,
+ NULL, GL_STATIC_DRAW_ARB);
+ data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ if(!data)
+ delete_buffer(id);
+ }
+
+ return data;
+}
-void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert,
- int *vert_indices, int totvert)
+static unsigned char *map_color_buffer(GPU_Buffers *buffers, int have_colors, int totelem)
+{
+ return map_buffer(buffers, &buffers->color_buf, have_colors, totelem, sizeof(char) * 3);
+}
+
+static void *map_uv_buffer(GPU_Buffers *buffers, int need_uvs, int totelem)
+{
+ return map_buffer(buffers, &buffers->uv_buf, need_uvs, totelem, sizeof(float) * 2);
+}
+
+static void color_from_face_corner(CustomData *fdata, int mcol_first_layer,
+ int mcol_totlayer, int cndx, float v[3])
+{
+ int i;
+
+ v[0] = v[1] = v[2] = 1;
+
+ for(i = mcol_first_layer; i < mcol_first_layer+mcol_totlayer; ++i) {
+ MCol *mcol;
+ float col[3];
+
+ mcol = fdata->layers[i].data;
+ mcol += cndx;
+
+ col[0] = mcol->b / 255.0f;
+ col[1] = mcol->g / 255.0f;
+ col[2] = mcol->r / 255.0f;
+
+ interp_v3_v3v3(v, v, col,
+ mcol->a / 255.0f);
+ }
+}
+
+void GPU_update_mesh_color_buffers(GPU_Buffers *buffers, PBVH *bvh,
+ PBVHNode *node, DMDrawFlags flags)
+{
+ unsigned char *color_data;
+ CustomData *vdata, *fdata;
+ MFace *mface;
+ int totvert, *vert_indices;
+ int totface, *face_indices, *face_vert_indices;
+ int mcol_totlayer, pmask_totlayer;
+ int color_needed;
+
+ if(!buffers->vert_buf)
+ return;
+
+ BLI_pbvh_get_customdata(bvh, &vdata, &fdata);
+ BLI_pbvh_node_num_verts(bvh, node, NULL, &totvert);
+ BLI_pbvh_node_get_verts(bvh, node, &vert_indices, NULL);
+ BLI_pbvh_node_get_faces(bvh, node, &mface, &face_indices,
+ &face_vert_indices, &totface);
+
+ mcol_totlayer = CustomData_number_of_layers(fdata, CD_MCOL);
+ pmask_totlayer = CustomData_number_of_layers(vdata, CD_PAINTMASK);
+
+ /* avoid creating color buffer if not needed */
+ color_needed = (flags & DM_DRAW_PAINT_MASK) && pmask_totlayer;
+
+ /* Make a color buffer if there's a mask layer and
+ get rid of any color buffer if there's no mask layer */
+ color_data = map_color_buffer(buffers, color_needed, totvert);
+
+ if(color_data) {
+ int i, j, mcol_first_layer, pmask_first_layer;
+
+ mcol_first_layer = CustomData_get_layer_index(fdata, CD_MCOL);
+ pmask_first_layer = CustomData_get_layer_index(vdata, CD_PAINTMASK);
+
+
+ for(i = 0; i < totface; ++i) {
+ int face_index = face_indices[i];
+ int S = mface[face_index].v4 ? 4 : 3;
+
+ /* for now this arbitrarily chooses one face's corner's
+ mcol to be assigned to a vertex; alternatives would
+ be to combine multiple colors through averaging or
+ draw separate quads so that mcols can abruptly
+ transition from one face to another */
+ for(j = 0; j < S; ++j) {
+ int node_vert_index = face_vert_indices[i*4 + j];
+ float col[3], mask;
+
+ color_from_face_corner(fdata,
+ mcol_first_layer,
+ mcol_totlayer,
+ face_index*4+j, col);
+
+ mask = paint_mask_from_vertex(vdata,
+ vert_indices[node_vert_index],
+ pmask_totlayer,
+ pmask_first_layer);
+
+ gpu_colors_from_floats(color_data +
+ node_vert_index*3,
+ col, mask);
+ }
+ }
+
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+ }
+}
+
+void GPU_update_mesh_vert_buffers(GPU_Buffers *buffers, MVert *mvert,
+ int *vert_indices, int totvert)
{
- GPU_Buffers *buffers = buffers_v;
VertexBufferFormat *vert_data;
int i;
@@ -445,26 +601,27 @@ void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert,
VertexBufferFormat *out = vert_data + i;
copy_v3_v3(out->co, v->co);
+#ifdef VBO_FLOATS
+ normal_short_to_float_v3(out->no, v->no);
+#else
memcpy(out->no, v->no, sizeof(short) * 3);
+#endif
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
}
- else {
- glDeleteBuffersARB(1, &buffers->vert_buf);
- buffers->vert_buf = 0;
- }
+ else
+ delete_buffer(&buffers->vert_buf);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
-
- buffers->mvert = mvert;
}
-void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
- int *face_indices, int totface,
- int *vert_indices, int tot_uniq_verts,
- int totvert)
+GPU_Buffers *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
+ CustomData *vdata, CustomData *fdata,
+ int *face_indices, int totface,
+ int *vert_indices, int tot_uniq_verts,
+ int totvert)
{
GPU_Buffers *buffers;
unsigned short *tri_data;
@@ -516,32 +673,238 @@ void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
}
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
}
- else {
- glDeleteBuffersARB(1, &buffers->index_buf);
- buffers->index_buf = 0;
- }
+ else
+ delete_buffer(&buffers->index_buf);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
if(buffers->index_buf)
glGenBuffersARB(1, &buffers->vert_buf);
- GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert);
buffers->tot_tri = tottri;
- buffers->mface = mface;
- buffers->face_indices = face_indices;
- buffers->totface = totface;
-
return buffers;
}
-void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
- int *grid_indices, int totgrid, int gridsize, int smooth)
+static void color_from_gridelem(DMGridData *elem, GridKey *gridkey, float col[3])
+{
+ int i;
+
+ col[0] = col[1] = col[2] = 1;
+
+ /* combine colors */
+ for(i = 0; i < gridkey->color; ++i) {
+ float *c = GRIDELEM_COLOR(elem, gridkey)[i];
+
+ /* TODO: check layer enabled/strength */
+
+ /* for now we just combine layers in order
+ interpolating using the alpha component
+ ("order" is ill-defined here since we
+ don't guarantee the order of cdm data) */
+ interp_v3_v3v3(col, col, c, c[3]);
+ }
+}
+
+void GPU_update_grid_color_buffers(GPU_Buffers *buffers, DMGridData **grids, int *grid_indices,
+ int totgrid, int gridsize, GridKey *gridkey, CustomData *vdata,
+ DMDrawFlags flags)
+{
+ unsigned char *color_data;
+ int totvert;
+ int color_needed;
+
+ if(!buffers->vert_buf)
+ return;
+
+ /* avoid creating color buffer if not needed */
+ color_needed = (flags & DM_DRAW_PAINT_MASK) && gridkey->mask;
+
+ totvert= gridsize*gridsize*totgrid;
+ color_data= map_color_buffer(buffers, color_needed, totvert);
+
+ if(color_data) {
+ int i, j;
+
+ for(i = 0; i < totgrid; ++i) {
+ DMGridData *grid= grids[grid_indices[i]];
+
+ for(j = 0; j < gridsize*gridsize; ++j, color_data += 3) {
+ DMGridData *elem = GRIDELEM_AT(grid, j, gridkey);
+ float col[3], mask;
+
+ color_from_gridelem(elem, gridkey, col);
+ mask = paint_mask_from_gridelem(elem, gridkey, vdata);
+
+ gpu_colors_from_floats(color_data, col, mask);
+ }
+ }
+
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+ }
+}
+
+void GPU_update_grid_uv_buffer(GPU_Buffers *buffers, PBVH *pbvh, PBVHNode *node, DMDrawFlags flags)
+{
+ CustomData *fdata;
+ GridToFace *grid_face_map;
+ MPtex *mptex;
+ float (*uv_data)[2];
+ int *grid_indices, totgrid, gridsize, totvert;
+
+ if(!buffers->vert_buf)
+ return;
+
+ 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, &gridsize,
+ NULL, NULL, NULL);
+
+ /* for now, pbvh is required to give one node per subface in ptex mode */
+ assert(totgrid == 1);
+
+ totvert= gridsize*gridsize*totgrid;
+ uv_data= map_uv_buffer(buffers, (flags & DM_DRAW_PTEX), totvert);
+
+ if(uv_data) {
+ GridToFace *gtf = &grid_face_map[grid_indices[0]];
+ MPtex *pt = &mptex[gtf->face];
+ MPtexSubface *subface = &pt->subfaces[gtf->offset];
+ float u, v, ustep, vstep, vstart = 0;
+ int x, y;
+
+ if(flags & DM_DRAW_PTEX_TEXELS) {
+ ustep = subface->res[0] >> 1;
+ vstep = subface->res[1] >> 1;
+ /* make quad texel pattern appear uniform across all four subfaces */
+ if(gtf->offset % 2)
+ vstart = 0.5;
+ }
+ else {
+ ustep = 1;
+ vstep = 1;
+ }
+
+ ustep /= gridsize - 1.0f;
+ vstep /= gridsize - 1.0f;
+
+ for(y = 0, v = vstart; y < gridsize; ++y, v += vstep) {
+ for(x = 0, u = 0; x < gridsize; ++x, u += ustep, ++uv_data) {
+ uv_data[0][0] = u;
+ uv_data[0][1] = v;
+ }
+ }
+
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+ }
+}
+
+GLenum gl_type_from_ptex(MPtex *pt)
+{
+ switch(pt->type) {
+ case PTEX_DT_UINT8:
+ return GL_UNSIGNED_BYTE;
+ case PTEX_DT_UINT16:
+ return GL_UNSIGNED_SHORT;
+ case PTEX_DT_FLOAT:
+ return GL_FLOAT;
+ default:
+ return 0;
+ }
+}
+
+GLenum gl_format_from_ptex(MPtex *pt)
{
- GPU_Buffers *buffers = buffers_v;
- DMGridData *vert_data;
+ switch(pt->channels) {
+ case 1:
+ return GL_LUMINANCE;
+ case 2:
+ return GL_LUMINANCE_ALPHA;
+ case 3:
+ return GL_RGB;
+ case 4:
+ return GL_RGBA;
+ default:
+ return 0;
+ }
+}
+
+static void gpu_create_ptex_textures(GPU_Buffers *buffers)
+{
+ buffers->ptex = MEM_callocN(sizeof(GLuint) * buffers->totptex, "PTex IDs");
+ glGenTextures(buffers->totptex, buffers->ptex);
+}
+
+static void gpu_init_ptex_texture(GLuint id, GLenum glformat, GLenum gltype,
+ int ures, int vres, void *data)
+{
+ glBindTexture(GL_TEXTURE_2D, id);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ 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, glformat, ures, vres,
+ 0, glformat, gltype, data);
+}
+
+void GPU_update_ptex(GPU_Buffers *buffers, PBVH *pbvh, PBVHNode *node)
+{
+ int *grid_indices, totgrid;
+ GridToFace *grid_face_map;
+ CustomData *fdata;
+ MPtex *mptex;
+ int i;
+
+ BLI_pbvh_get_customdata(pbvh, NULL, &fdata);
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+
+ assert(BLI_pbvh_uses_grids(pbvh));
+
+ BLI_pbvh_node_get_grids(pbvh, node,
+ &grid_indices, &totgrid,
+ NULL, NULL, NULL, NULL, NULL);
+
+ /* TODO: composite multiple layers */
+ mptex = CustomData_get_layer(fdata, CD_MPTEX);
+
+ /* one texture per grid
+ TODO: pack multiple textures together? */
+ if(!buffers->ptex) {
+ buffers->totptex = totgrid;
+ gpu_create_ptex_textures(buffers);
+ }
+
+ 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];
+
+ gpu_init_ptex_texture(buffers->ptex[i],
+ gl_format_from_ptex(pt),
+ gl_type_from_ptex(pt),
+ subface->res[0], subface->res[1],
+ subface->data);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+}
+
+typedef struct {
+ float co[3];
+ float no[3];
+} GridVBO;
+
+void GPU_update_grid_vert_buffers(GPU_Buffers *buffers, DMGridData **grids,
+ int *grid_indices, int totgrid, int gridsize, GridKey *gridkey, int smooth)
+{
+ GridVBO *vert_data;
int i, j, k, totvert;
totvert= gridsize*gridsize*totgrid;
@@ -550,13 +913,19 @@ void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
if(buffers->vert_buf) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
- sizeof(DMGridData) * totvert,
+ sizeof(GridVBO) * totvert,
NULL, GL_STATIC_DRAW_ARB);
vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
if(vert_data) {
for(i = 0; i < totgrid; ++i) {
DMGridData *grid= grids[grid_indices[i]];
- memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize);
+
+ for(j = 0; j < gridsize; ++j) {
+ for(k = 0; k < gridsize; ++k) {
+ copy_v3_v3(vert_data[k + j*gridsize].co, GRIDELEM_CO_AT(grid, k + j*gridsize, gridkey));
+ copy_v3_v3(vert_data[k + j*gridsize].no, GRIDELEM_NO_AT(grid, k + j*gridsize, gridkey));
+ }
+ }
if(!smooth) {
/* for flat shading, recalc normals and set the last vertex of
@@ -564,11 +933,13 @@ void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
that is what opengl will use */
for(j = 0; j < gridsize-1; ++j) {
for(k = 0; k < gridsize-1; ++k) {
- normal_quad_v3(vert_data[(j+1)*gridsize + (k+1)].no,
- vert_data[(j+1)*gridsize + k].co,
- vert_data[(j+1)*gridsize + k+1].co,
- vert_data[j*gridsize + k+1].co,
- vert_data[j*gridsize + k].co);
+ float norm[3];
+ normal_quad_v3(norm,
+ GRIDELEM_CO_AT(grid, (j+1)*gridsize + k, gridkey),
+ GRIDELEM_CO_AT(grid, (j+1)*gridsize + k+1, gridkey),
+ GRIDELEM_CO_AT(grid, j*gridsize + k+1, gridkey),
+ GRIDELEM_CO_AT(grid, j*gridsize + k, gridkey));
+ copy_v3_v3(vert_data[(j+1)*gridsize + (k+1)].no, norm);
}
}
}
@@ -577,194 +948,506 @@ void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
}
- else {
- glDeleteBuffersARB(1, &buffers->vert_buf);
- buffers->vert_buf = 0;
- }
+ else
+ delete_buffer(&buffers->vert_buf);
+
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
- buffers->grids = grids;
- buffers->grid_indices = grid_indices;
- buffers->totgrid = totgrid;
- buffers->gridsize = gridsize;
-
//printf("node updated %p\n", buffers_v);
}
-void *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
- int totgrid, int gridsize)
+static int gpu_build_grid_ibo(int gridsize)
+{
+ GLuint index_buf;
+ int totndx, use_ushorts, i, j;
+ unsigned short *quads_ushort;
+ unsigned int *quads_uint;
+
+ /* count the number of quads */
+ totndx = (gridsize-1)*(gridsize-1) * 4;
+
+ /* generate index buffer object */
+ if(GL_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
+ glGenBuffersARB(1, &index_buf);
+
+ /* bad failure */
+ if(!index_buf)
+ return 0;
+
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);
+
+ /* if possible, restrict indices to unsigned shorts to save space */
+ use_ushorts = totndx < USHRT_MAX;
+
+ /* allocate empty buffer data */
+ glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+ (use_ushorts ? sizeof(unsigned short) :
+ sizeof(unsigned int)) * totndx,
+ NULL, GL_STATIC_DRAW_ARB);
+
+ /* map the buffer into memory */
+ quads_ushort = (void*)(quads_uint =
+ glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+ GL_WRITE_ONLY_ARB));
+ if(!quads_ushort) {
+ delete_buffer(&index_buf);
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ return 0;
+ }
+
+ /* fill the quad buffer */
+ for(i = 0; i < gridsize-1; ++i) {
+ for(j = 0; j < gridsize-1; ++j) {
+#define IBO_ASSIGN(val) do { \
+ if(use_ushorts) \
+ *(quads_ushort++) = val; \
+ else \
+ *(quads_uint++) = val; \
+ } while(0)
+
+ IBO_ASSIGN(i*gridsize + j+1);
+ IBO_ASSIGN(i*gridsize + j);
+ IBO_ASSIGN((i+1)*gridsize + j);
+ IBO_ASSIGN((i+1)*gridsize + j+1);
+
+#undef IBO_ASSIGN
+ }
+ }
+
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+
+ return index_buf;
+}
+
+/* cache grid IBOs, uses reference counting to free them */
+static int gpu_grid_ibo(int gridsize, int release)
+{
+ /* {reference count, buffer id} */
+ static unsigned int grid_buffers[32][2], inited = 0;
+ int lvl, i;
+
+ if(!inited) {
+ memset(grid_buffers, 0, sizeof(int)*32*2);
+ inited = 1;
+ }
+
+ for(i = 0, --gridsize; i < 32; ++i) {
+ if(gridsize & (1 << i)) {
+ lvl = i;
+ break;
+ }
+ }
+
+ if(release) {
+ if(grid_buffers[lvl][0] > 0) {
+ --grid_buffers[lvl][0];
+ if(!grid_buffers[lvl][0])
+ delete_buffer(&grid_buffers[lvl][1]);
+ }
+ else
+ fprintf(stderr, "gpu_grid_ibo: bad reference count\n");
+ }
+ else {
+ ++grid_buffers[lvl][0];
+
+ if(!grid_buffers[lvl][1])
+ grid_buffers[lvl][1] = gpu_build_grid_ibo(gridsize + 1);
+ }
+
+ return grid_buffers[lvl][1];
+}
+
+GPU_Buffers *GPU_build_grid_buffers(int gridsize)
{
GPU_Buffers *buffers;
- int i, j, k, totquad, offset= 0;
buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
- /* Count the number of quads */
- totquad= (gridsize-1)*(gridsize-1)*totgrid;
+ buffers->index_buf = gpu_grid_ibo(gridsize, 0);
+ buffers->gridsize = gridsize;
+ buffers->use_grids = 1;
- /* Generate index buffer object */
- if(GL_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
- glGenBuffersARB(1, &buffers->index_buf);
+ /* Build VBO */
+ if(buffers->index_buf)
+ glGenBuffersARB(1, &buffers->vert_buf);
- if(buffers->index_buf) {
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
+ return buffers;
+}
- if(totquad < USHRT_MAX) {
- unsigned short *quad_data;
+/* create a global texture for visualizing ptex texels */
+static void gpu_bind_ptex_pattern()
+{
+ static int inited = 0;
+ static GLuint ptex_pattern_gltex = 0;
- buffers->index_type = GL_UNSIGNED_SHORT;
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
- sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
+ if(!inited) {
+ #define color1 64, 255, 255
+ #define color2 255, 128, 255
+ unsigned char pattern[2*2*3] = {
+ color1, color2,
+ color2, color1
+ };
+ unsigned char avg[3] = {160, 192, 255};
- /* Fill the quad buffer */
- quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
- if(quad_data) {
- for(i = 0; i < totgrid; ++i) {
- for(j = 0; j < gridsize-1; ++j) {
- for(k = 0; k < gridsize-1; ++k) {
- *(quad_data++)= offset + j*gridsize + k+1;
- *(quad_data++)= offset + j*gridsize + k;
- *(quad_data++)= offset + (j+1)*gridsize + k;
- *(quad_data++)= offset + (j+1)*gridsize + k+1;
- }
- }
+ glGenTextures(1, &ptex_pattern_gltex);
- offset += gridsize*gridsize;
- }
- glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+ glBindTexture(GL_TEXTURE_2D, ptex_pattern_gltex);
+
+ 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_NEAREST_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2,
+ 0, GL_RGB, GL_UNSIGNED_BYTE, pattern);
+
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, 1, 1,
+ 0, GL_RGB, GL_UNSIGNED_BYTE, avg);
+
+ inited = 1;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, ptex_pattern_gltex);
+}
+
+static void gpu_draw_node_without_vb(GPU_Buffers *buffers, PBVH *pbvh, PBVHNode *node, DMDrawFlags flags)
+{
+ DMGridData **grids;
+ GridKey *gridkey;
+ int *grid_indices, totgrid, gridsize;
+ CustomData *vdata = NULL, *fdata = NULL;
+ MPtex *mptex = NULL;
+ int mcol_first_layer, pmask_first_layer;
+ int i, use_grids, use_color, use_ptex, ptex_edit = 0;
+
+ use_grids = BLI_pbvh_uses_grids(pbvh);
+ BLI_pbvh_get_customdata(pbvh, &vdata, &fdata);
+
+ /* see if color data is needed */
+ if(use_grids) {
+ BLI_pbvh_node_get_grids(pbvh, node, &grid_indices,
+ &totgrid, NULL, &gridsize,
+ &grids, NULL, &gridkey);
+ use_color = gridkey->color || gridkey->mask;
+ if(use_color)
+ BLI_pbvh_get_customdata(pbvh, &vdata, NULL);
+ }
+ else {
+ mcol_first_layer = CustomData_get_layer_index(fdata, CD_MCOL);
+ pmask_first_layer = CustomData_get_layer_index(vdata, CD_PAINTMASK);
+
+ use_color = (flags & DM_DRAW_PAINT_MASK) && pmask_first_layer != -1;
+ }
+
+ if((use_ptex = (buffers->ptex && (flags & DM_DRAW_PTEX)))) {
+ mptex = CustomData_get_layer(fdata, CD_MPTEX);
+ glEnable(GL_TEXTURE_2D);
+ ptex_edit = flags & DM_DRAW_PTEX_TEXELS;
+ }
+
+ if(use_color || use_ptex) {
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+ }
+ if(use_grids) {
+ GridToFace *grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+ int x, y;
+
+ BLI_pbvh_node_get_grids(pbvh, node, &grid_indices,
+ &totgrid, NULL, &gridsize,
+ &grids, NULL, &gridkey);
+
+ if(ptex_edit)
+ gpu_bind_ptex_pattern();
+
+ for(i = 0; i < totgrid; ++i) {
+ DMGridData *grid = grids[grid_indices[i]];
+ GridToFace *gtf = &grid_face_map[grid_indices[i]];
+ MPtex *pt;
+ MPtexSubface *subface;
+ float u, v, ustep, vstep, vstart = 0;
+
+ if(mptex) {
+ pt = &mptex[gtf->face];
+ subface = &pt->subfaces[gtf->offset];
+
+ if(subface->flag & MPTEX_SUBFACE_HIDDEN)
+ continue;
+ }
+
+ if(ptex_edit) {
+ ustep = subface->res[0] >> 1;
+ vstep = subface->res[1] >> 1;
}
else {
- glDeleteBuffersARB(1, &buffers->index_buf);
- buffers->index_buf = 0;
+ ustep = 1;
+ vstep = 1;
}
- }
- else {
- unsigned int *quad_data;
- buffers->index_type = GL_UNSIGNED_INT;
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
- sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
+ if(gridsize > 1) {
+ ustep /= gridsize - 1;
+ vstep /= gridsize - 1;
+ }
- /* Fill the quad buffer */
- quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ /* make quad texel pattern appear uniform across all four subfaces */
+ if(ptex_edit && (gtf->offset % 2))
+ vstart = 0.5;
+
+ if(ptex_edit) {
+ if(subface->flag & MPTEX_SUBFACE_SELECTED)
+ glColor3ub(255, 255, 255);
+ else if(subface->flag & MPTEX_SUBFACE_MASKED)
+ glColor3ub(96, 96, 96);
+ else
+ glColor3ub(128, 128, 128);
+ }
+ else if(use_ptex) {
+ if(subface->flag & MPTEX_SUBFACE_MASKED)
+ glColor3ub(128, 128, 128);
+ else
+ glColor3ub(255, 255, 255);
+ glBindTexture(GL_TEXTURE_2D, buffers->ptex[i]);
+ }
- if(quad_data) {
- for(i = 0; i < totgrid; ++i) {
- for(j = 0; j < gridsize-1; ++j) {
- for(k = 0; k < gridsize-1; ++k) {
- *(quad_data++)= offset + j*gridsize + k+1;
- *(quad_data++)= offset + j*gridsize + k;
- *(quad_data++)= offset + (j+1)*gridsize + k;
- *(quad_data++)= offset + (j+1)*gridsize + k+1;
- }
+ for(y = 0, v = vstart; y < gridsize-1; y++, v += vstep) {
+ glBegin(GL_QUAD_STRIP);
+ for(x = 0, u = 0; x < gridsize; x++, u += ustep) {
+ DMGridData *a = GRIDELEM_AT(grid, y*gridsize + x, gridkey);
+ DMGridData *b = GRIDELEM_AT(grid, (y+1)*gridsize + x, gridkey);
+ float acol[3], bcol[3], amask, bmask;
+ unsigned char aglc[3], bglc[3];
+
+ color_from_gridelem(a, gridkey, acol);
+ color_from_gridelem(b, gridkey, bcol);
+ amask = paint_mask_from_gridelem(a, gridkey, vdata);
+ bmask = paint_mask_from_gridelem(b, gridkey, vdata);
+
+ if(use_color) {
+ gpu_colors_from_floats(aglc, acol, amask);
+ gpu_colors_from_floats(bglc, bcol, bmask);
}
- offset += gridsize*gridsize;
+ if(use_color)
+ glColor3ubv(aglc);
+ if(use_ptex)
+ glTexCoord2f(u, v);
+ glNormal3fv(GRIDELEM_NO(a, gridkey));
+ glVertex3fv(GRIDELEM_CO(a, gridkey));
+ if(use_color)
+ glColor3ubv(bglc);
+ if(use_ptex)
+ glTexCoord2f(u, v + vstep);
+ glNormal3fv(GRIDELEM_NO(b, gridkey));
+ glVertex3fv(GRIDELEM_CO(b, gridkey));
}
- glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
- }
- else {
- glDeleteBuffersARB(1, &buffers->index_buf);
- buffers->index_buf = 0;
+ glEnd();
}
}
+ }
+ else {
+ MFace *mface;
+ MVert *mvert;
+ int totface, *face_indices;
+ int j, mcol_totlayer, pmask_totlayer;
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ BLI_pbvh_node_get_verts(pbvh, node, NULL, &mvert);
+ BLI_pbvh_node_get_faces(pbvh, node, &mface, &face_indices, NULL, &totface);
+
+ if(mcol_first_layer)
+ mcol_totlayer = CustomData_number_of_layers(fdata, CD_MCOL);
+
+ if(pmask_first_layer)
+ pmask_totlayer = CustomData_number_of_layers(vdata, CD_PAINTMASK);
+
+ for(i = 0; i < totface; ++i) {
+ int face_index = face_indices[i];
+ MFace *f = mface + face_index;
+ int S = f->v4 ? 4 : 3;
+
+ glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
+
+ for(j = 0; j < S; ++j) {
+ int vndx = (&f->v1)[j];
+ float col[3], mask;
+ unsigned char glc[3];
+
+ color_from_face_corner(fdata,
+ mcol_first_layer,
+ mcol_totlayer,
+ face_index*4+j, col);
+
+ mask = paint_mask_from_vertex(vdata, vndx,
+ pmask_totlayer,
+ pmask_first_layer);
+
+ gpu_colors_from_floats(glc, col, mask);
+
+ glColor3ubv(glc);
+ glNormal3sv(mvert[vndx].no);
+ glVertex3fv(mvert[vndx].co);
+ }
+
+ glEnd();
+ }
}
- /* Build VBO */
- if(buffers->index_buf)
- glGenBuffersARB(1, &buffers->vert_buf);
+ if(use_color || use_ptex)
+ glDisable(GL_COLOR_MATERIAL);
+}
+
+static void gpu_draw_grids(GPU_Buffers *buffers, PBVH *pbvh, PBVHNode *node, DMDrawFlags flags)
+{
+ int g, totgrid, *grid_indices, gridsize, offset, totndx;
- buffers->tot_quad = totquad;
+ BLI_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
+ NULL, &gridsize, NULL, NULL, NULL);
- return buffers;
+ totndx = (gridsize-1)*(gridsize-1) * 4;
+
+ for(g = 0; g < totgrid; ++g) {
+ offset = gridsize * gridsize * g;
+
+ glVertexPointer(3, GL_FLOAT, sizeof(GridVBO),
+ (char*)0 + offset*sizeof(GridVBO) + offsetof(GridVBO, co));
+ glNormalPointer(GL_FLOAT, sizeof(GridVBO),
+ (char*)0 + offset*sizeof(GridVBO) + offsetof(GridVBO, no));
+
+ if(buffers->color_buf) {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->color_buf);
+ glColorPointer(3, GL_UNSIGNED_BYTE, 0, (char*)0 + (offset * 3));
+ }
+
+ if(buffers->uv_buf) {
+ CustomData *fdata;
+ GridToFace *gtf;
+ MPtex *mptex, *pt;
+ MPtexSubface *subface;
+ GridToFace *grid_face_map;
+
+ /* note: code here assumes there's only one
+ ptex subface per node */
+
+ BLI_pbvh_get_customdata(pbvh, NULL, &fdata);
+ mptex = CustomData_get_layer(fdata, CD_MPTEX);
+ grid_face_map = BLI_pbvh_get_grid_face_map(pbvh);
+
+ gtf = &grid_face_map[grid_indices[0]];
+ pt = &mptex[gtf->face];
+ subface = &pt->subfaces[gtf->offset];
+
+ glEnable(GL_TEXTURE_2D);
+ if(flags & DM_DRAW_PTEX_TEXELS) {
+ gpu_bind_ptex_pattern();
+ if(subface->flag & MPTEX_SUBFACE_SELECTED)
+ glColor3ub(255, 255, 255);
+ else if(subface->flag & MPTEX_SUBFACE_MASKED)
+ glColor3ub(96, 96, 96);
+ else
+ glColor3ub(128, 128, 128);
+ }
+ else {
+ glBindTexture(GL_TEXTURE_2D, buffers->ptex[0]);
+
+ if(subface->flag & MPTEX_SUBFACE_MASKED)
+ glColor3ub(128, 128, 128);
+ else
+ glColor3ub(255, 255, 255);
+ }
+
+ if(subface->flag & MPTEX_SUBFACE_HIDDEN)
+ continue;
+
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->uv_buf);
+ glTexCoordPointer(2, GL_FLOAT, 0, (void*)0);
+ }
+
+ glDrawElements(GL_QUADS, totndx,
+ (totndx < USHRT_MAX ?
+ GL_UNSIGNED_SHORT : GL_UNSIGNED_INT), 0);
+ }
}
-void GPU_draw_buffers(void *buffers_v)
+void GPU_draw_buffers(GPU_Buffers *buffers, PBVH *pbvh, PBVHNode *node, DMDrawFlags flags)
{
- GPU_Buffers *buffers = buffers_v;
+ glShadeModel((flags & DM_DRAW_FULLY_SMOOTH) ? GL_SMOOTH: GL_FLAT);
if(buffers->vert_buf && buffers->index_buf) {
+ GLboolean use_colmat, colmat;
+
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
+ if(buffers->color_buf)
+ glEnableClientState(GL_COLOR_ARRAY);
+ if(buffers->uv_buf)
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
- if(buffers->tot_quad) {
- glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, co));
- glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no));
+ use_colmat = buffers->color_buf || (flags & DM_DRAW_PTEX);
+ if(use_colmat) {
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glGetBooleanv(GL_COLOR_MATERIAL, &colmat);
+ glEnable(GL_COLOR_MATERIAL);
+ }
- glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0);
+ if(buffers->use_grids) {
+ gpu_draw_grids(buffers, pbvh, node, flags);
}
else {
glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, co));
+#ifdef VBO_FLOATS
+ glNormalPointer(GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
+#else
glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
+#endif
+ if(buffers->color_buf) {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->color_buf);
+ glColorPointer(3, GL_UNSIGNED_BYTE, 0, (void*)0);
+ }
glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
}
+ if(use_colmat && !colmat)
+ glDisable(GL_COLOR_MATERIAL);
+
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
- else if(buffers->totface) {
- /* fallback if we are out of memory */
- int i;
-
- for(i = 0; i < buffers->totface; ++i) {
- MFace *f = buffers->mface + buffers->face_indices[i];
-
- glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
- glNormal3sv(buffers->mvert[f->v1].no);
- glVertex3fv(buffers->mvert[f->v1].co);
- glNormal3sv(buffers->mvert[f->v2].no);
- glVertex3fv(buffers->mvert[f->v2].co);
- glNormal3sv(buffers->mvert[f->v3].no);
- glVertex3fv(buffers->mvert[f->v3].co);
- if(f->v4) {
- glNormal3sv(buffers->mvert[f->v4].no);
- glVertex3fv(buffers->mvert[f->v4].co);
- }
- glEnd();
- }
+ else {
+ /* fallback to regular drawing if out of memory or if VBO is switched off */
+ gpu_draw_node_without_vb(buffers, pbvh, node, flags);
}
- else if(buffers->totgrid) {
- int i, x, y, gridsize = buffers->gridsize;
- for(i = 0; i < buffers->totgrid; ++i) {
- DMGridData *grid = buffers->grids[buffers->grid_indices[i]];
-
- for(y = 0; y < gridsize-1; y++) {
- glBegin(GL_QUAD_STRIP);
- for(x = 0; x < gridsize; x++) {
- DMGridData *a = &grid[y*gridsize + x];
- DMGridData *b = &grid[(y+1)*gridsize + x];
-
- glNormal3fv(a->no);
- glVertex3fv(a->co);
- glNormal3fv(b->no);
- glVertex3fv(b->co);
- }
- glEnd();
- }
- }
- }
+ glShadeModel(GL_FLAT);
}
-void GPU_free_buffers(void *buffers_v)
+void GPU_free_buffers(GPU_Buffers *buffers_v)
{
if(buffers_v) {
GPU_Buffers *buffers = buffers_v;
if(buffers->vert_buf)
glDeleteBuffersARB(1, &buffers->vert_buf);
- if(buffers->index_buf)
- glDeleteBuffersARB(1, &buffers->index_buf);
+ if(buffers->index_buf) {
+ if(buffers->use_grids)
+ gpu_grid_ibo(buffers->gridsize, 1);
+ else
+ glDeleteBuffersARB(1, &buffers->index_buf);
+ }
+ if(buffers->ptex) {
+ glDeleteTextures(buffers->totptex, buffers->ptex);
+ MEM_freeN(buffers->ptex);
+ }
MEM_freeN(buffers);
}
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 1492319fe22..c34804ad16d 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -126,26 +126,33 @@ typedef struct Brush {
#define BRUSH_PLANE_TRIM (1<<26)
#define BRUSH_FRONTFACE (1<<27)
#define BRUSH_CUSTOM_ICON (1<<28)
+#define BRUSH_MASK (1<<29)
/* Brush.sculpt_tool */
-#define SCULPT_TOOL_DRAW 1
-#define SCULPT_TOOL_SMOOTH 2
-#define SCULPT_TOOL_PINCH 3
-#define SCULPT_TOOL_INFLATE 4
-#define SCULPT_TOOL_GRAB 5
-#define SCULPT_TOOL_LAYER 6
-#define SCULPT_TOOL_FLATTEN 7
-#define SCULPT_TOOL_CLAY 8
-#define SCULPT_TOOL_FILL 9
-#define SCULPT_TOOL_SCRAPE 10
-#define SCULPT_TOOL_NUDGE 11
-#define SCULPT_TOOL_THUMB 12
-#define SCULPT_TOOL_SNAKE_HOOK 13
-#define SCULPT_TOOL_ROTATE 14
-//#define SCULPT_TOOL_WAX 15 // XXX: reuse this slot later
-#define SCULPT_TOOL_CREASE 16
-#define SCULPT_TOOL_BLOB 17
-#define SCULPT_TOOL_CLAY_TUBES 18
+typedef enum {
+ SCULPT_TOOL_DRAW = 1,
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_INFLATE,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_FLATTEN,
+ SCULPT_TOOL_CLAY,
+ SCULPT_TOOL_FILL,
+ SCULPT_TOOL_SCRAPE,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_WAX, // XXX: reuse this slot later
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CLAY_TUBES
+} SculptTool;
+
+/* Brush.vertexpaint_tool */
+#define VERTEX_PAINT_BLUR 99
+/* The other vpaint tools are in IMB_BlendMode */
/* ImagePaintSettings.tool */
#define PAINT_TOOL_DRAW 0
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 6c0b4db221d..a0b1e30c7f8 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -43,7 +43,7 @@ typedef struct CustomDataLayer {
int active_rnd; /* number of the layer to render*/
int active_clone; /* number of the layer to render*/
int active_mask; /* number of the layer to render*/
- char pad[4];
+ float strength; /* for mixing a layer, strength between 0 and 1 */
char name[32]; /* layer name */
void *data; /* layer data */
} CustomDataLayer;
@@ -58,11 +58,28 @@ typedef struct CustomDataExternal {
typedef struct CustomData {
CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
int totlayer, maxlayer; /* number of layers, size of layers array */
- int totsize, pad; /* in editmode, total size of all data layers */
+ int totsize; /* in editmode, total size of all data layers */
+ int pad;
void *pool; /* Bmesh: Memory pool for allocation of blocks */
CustomDataExternal *external; /* external file storing customdata layers */
} CustomData;
+typedef struct CustomDataMultiresLayer {
+ float *griddata; /* storage for n grids, where n is face's number of corners */
+ char name[32]; /* source layer's name, should be kept in sync */
+ int type; /* customdata type */
+ int pad;
+} CustomDataMultiresLayer;
+
+/* some CustomData layers can be subdivided to store multires data, but since
+ multires data is always related to faces and the source layers might be
+ vertex data, the subdivided data is stored separately
+*/
+typedef struct CustomDataMultires {
+ CustomDataMultiresLayer *layers;
+ int totlayer, totelem;
+} CustomDataMultires;
+
/* CustomData.type */
#define CD_MVERT 0
#define CD_MSTICKY 1
@@ -88,7 +105,10 @@ typedef struct CustomData {
#define CD_ID_MCOL 21
#define CD_TEXTURE_MCOL 22
#define CD_CLOTH_ORCO 23
-#define CD_NUMTYPES 24
+#define CD_GRIDS 24
+#define CD_PAINTMASK 25
+#define CD_MPTEX 26
+#define CD_NUMTYPES 27
/* Bits for CustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
@@ -113,6 +133,9 @@ typedef struct CustomData {
#define CD_MASK_MDISPS (1 << CD_MDISPS)
#define CD_MASK_WEIGHT_MCOL (1 << CD_WEIGHT_MCOL)
#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO)
+#define CD_MASK_GRIDS (1 << CD_GRIDS)
+#define CD_MASK_PAINTMASK (1 << CD_PAINTMASK)
+#define CD_MASK_MPTEX (1 << CD_MPTEX)
/* CustomData.flag */
@@ -127,6 +150,10 @@ typedef struct CustomData {
#define CD_FLAG_EXTERNAL (1<<3)
/* indicates external data is read into memory */
#define CD_FLAG_IN_MEMORY (1<<4)
+/* used to enable/disable a layer */
+#define CD_FLAG_ENABLED (1<<5)
+/* indicates the layer is linked to subdivided data */
+#define CD_FLAG_MULTIRES (1<<6)
/* Limits */
#define MAX_MTFACE 8
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 4e41309cff4..6843b0aff50 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -82,7 +82,12 @@ typedef struct Mesh {
* this means the active face must always be selected, this is to keep track
* of the last selected face and is similar to the old active face flag where
* the face does not need to be selected, -1 is inactive */
- int act_face;
+ int act_face;
+
+ /* used for ptex selection */
+ int act_subface;
+
+ int pad;
short texflag, editflag;
@@ -125,6 +130,7 @@ typedef struct TFace {
#define ME_EDIT_PAINT_MASK (1 << 3)
#define ME_EDIT_MIRROR_TOPO (1 << 4) // unused so far
+#define ME_EDIT_PTEX (1 << 5)
/* me->flag */
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 450c56b0dec..47daa8abea4 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -125,6 +125,33 @@ typedef struct MDisps {
float (*disps)[3];
} MDisps;
+typedef struct MPtexSubface {
+ void *data;
+
+ /* resolution in U and V directions, always a power of two */
+ int res[2];
+
+ int flag, pad;
+} MPtexSubface;
+
+#define MPTEX_SUBFACE_SELECTED 1
+#define MPTEX_SUBFACE_HIDDEN 2
+#define MPTEX_SUBFACE_MASKED 4
+
+typedef struct MPtex {
+ struct MPtexSubface subfaces[4];
+
+ /* equal to face's number of vertices */
+ int totsubface;
+
+ /* enum PtexDataType */
+ char type;
+
+ char channels;
+
+ char pad[2];
+} MPtex;
+
/** Multires structs kept for compatibility with old files **/
typedef struct MultiresCol {
float a, r, g, b;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 60b4f6a51b6..92ba63b086a 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -53,7 +53,7 @@ struct SoftBody;
struct FluidsimSettings;
struct ParticleSystem;
struct DerivedMesh;
-struct SculptSession;
+struct PaintSession;
struct bGPdata;
@@ -97,7 +97,7 @@ typedef struct Object {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
- struct SculptSession *sculpt;
+ struct PaintSession *paint;
short type, partype;
int par1, par2, par3; /* can be vertexnrs */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 82eecca743c..4bfa617b306 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -508,12 +508,15 @@ typedef struct TimeMarker {
typedef struct Paint {
struct Brush *brush;
-
+
/* WM Paint cursor */
void *paint_cursor;
unsigned char paint_cursor_col[4];
int flags;
+ int radial_symm[3];
+
+ int pad;
} Paint;
typedef struct ImagePaintSettings {
@@ -566,33 +569,26 @@ typedef struct TransformOrientation {
typedef struct Sculpt {
Paint paint;
- /* For rotating around a pivot point */
- //float pivot[3]; XXX not used?
- int flags;
-
- /* Control tablet input */
- //char tablet_size, tablet_strength; XXX not used?
- int radial_symm[3];
-
- // all this below is used to communicate with the cursor drawing routine
-
/* record movement of mouse so that rake can start at an intuitive angle */
float last_x, last_y;
float last_angle;
- int draw_anchored;
- int anchored_size;
- float anchored_location[3];
- float anchored_initial_mouse[2];
-
- int draw_pressure;
- float pressure_value;
-
- float special_rotation;
-
int pad;
} Sculpt;
+typedef struct PaintOverlay {
+ struct Image *img;
+ int offset[2];
+ /* width, height in pixels */
+ int size[2];
+ float angle;
+ float transp_col[3];
+ float transp_tol;
+ int use;
+ unsigned int gltex;
+ int pad;
+} PaintOverlay;
+
typedef struct VPaint {
Paint paint;
@@ -613,11 +609,12 @@ typedef struct VPaint {
// #define VP_MIRROR_X 32 // depricated in 2.5x use (me->editflag & ME_EDIT_MIRROR_X)
#define VP_ONLYVGROUP 128
-
typedef struct ToolSettings {
VPaint *vpaint; /* vertex paint */
VPaint *wpaint; /* weight paint */
Sculpt *sculpt;
+
+ struct PaintOverlay paint_overlay;
/* Vertex groups */
float vgroup_weight;
@@ -727,11 +724,15 @@ typedef struct ToolSettings {
int auto_normalize; /*auto normalizing mode in wpaint*/
+ /* Sculpt */
short sculpt_paint_settings; /* user preferences for sculpt and paint */
short pad1;
int sculpt_paint_unified_size; /* unified radius of brush in pixels */
float sculpt_paint_unified_unprojected_radius;/* unified radius of brush in Blender units */
float sculpt_paint_unified_alpha; /* unified strength of brush */
+
+ /* Paint */
+ int ptex_ures, ptex_vres;
} ToolSettings;
typedef struct bStats {
@@ -1131,24 +1132,21 @@ typedef struct Scene {
/* Paint.flags */
typedef enum {
- PAINT_SHOW_BRUSH = (1<<0),
- PAINT_FAST_NAVIGATE = (1<<1),
- PAINT_SHOW_BRUSH_ON_SURFACE = (1<<2),
+ PAINT_SYMM_X = (1<<0),
+ PAINT_SYMM_Y = (1<<1),
+ PAINT_SYMM_Z = (1<<2),
+ PAINT_SYMMETRY_FEATHER = (1<<3),
+
+ PAINT_SHOW_BRUSH = (1<<4),
+ PAINT_FAST_NAVIGATE = (1<<5),
+ PAINT_SHOW_BRUSH_ON_SURFACE = (1<<6),
+
+ PAINT_LOCK_X = (1<<7),
+ PAINT_LOCK_Y = (1<<8),
+ PAINT_LOCK_Z = (1<<9),
+ PAINT_USE_OPENMP = (1<<10),
} PaintFlags;
-/* Sculpt.flags */
-/* These can eventually be moved to paint flags? */
-typedef enum SculptFlags {
- SCULPT_SYMM_X = (1<<0),
- SCULPT_SYMM_Y = (1<<1),
- SCULPT_SYMM_Z = (1<<2),
- SCULPT_LOCK_X = (1<<3),
- SCULPT_LOCK_Y = (1<<4),
- SCULPT_LOCK_Z = (1<<5),
- SCULPT_SYMMETRY_FEATHER = (1<<6),
- SCULPT_USE_OPENMP = (1<<7),
-} SculptFlags;
-
/* sculpt_paint_settings */
#define SCULPT_PAINT_USE_UNIFIED_SIZE (1<<0)
#define SCULPT_PAINT_USE_UNIFIED_ALPHA (1<<1)
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index ab1319653b8..f8f12506539 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -300,6 +300,8 @@ extern StructRNA RNA_MeshFloatProperty;
extern StructRNA RNA_MeshFloatPropertyLayer;
extern StructRNA RNA_MeshIntProperty;
extern StructRNA RNA_MeshIntPropertyLayer;
+extern StructRNA RNA_MeshPaintMaskLayer;
+extern StructRNA RNA_MeshPtexLayer;
extern StructRNA RNA_MeshSticky;
extern StructRNA RNA_MeshStringProperty;
extern StructRNA RNA_MeshStringPropertyLayer;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 83d40a3802b..1a814c33a33 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -66,13 +66,14 @@ EnumPropertyItem brush_sculpt_tool_items[] = {
EnumPropertyItem brush_vertexpaint_tool_items[] = {
- {0, "MIX", ICON_BRUSH_MIX, "Mix", "Use mix blending mode while painting"},
- {1, "ADD", ICON_BRUSH_ADD, "Add", "Use add blending mode while painting"},
- {2, "SUB", ICON_BRUSH_SUBTRACT, "Subtract", "Use subtract blending mode while painting"},
- {3, "MUL", ICON_BRUSH_MULTIPLY, "Multiply", "Use multiply blending mode while painting"},
- {4, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"},
- {5, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"},
- {6, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"},
+ {IMB_BLEND_MIX, "MIX", ICON_BRUSH_MIX, "Mix", "Use mix blending mode while painting"},
+ {IMB_BLEND_ADD, "ADD", ICON_BRUSH_ADD, "Add", "Use add blending mode while painting"},
+ {IMB_BLEND_SUB, "SUB", ICON_BRUSH_SUBTRACT, "Subtract", "Use subtract blending mode while painting"},
+ {IMB_BLEND_MUL, "MUL", ICON_BRUSH_MULTIPLY, "Multiply", "Use multiply blending mode while painting"},
+ {IMB_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"},
+ {IMB_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"},
+ {IMB_BLEND_ADD_ALPHA, "ALPHA", ICON_BRUSH_LIGHTEN /* TODO */, "Alpha", "Add or remove alpha from the active layer"},
+ {VERTEX_PAINT_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"},
{0, NULL, 0, NULL, NULL}};
EnumPropertyItem brush_imagepaint_tool_items[] = {
@@ -262,9 +263,10 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
{BRUSH_DIR_IN, "DEFLATE", 0, "Deflate", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
- Brush *me= (Brush*)(ptr->data);
+ Brush *br= (Brush*)(ptr->data);
- switch (me->sculpt_tool) {
+ if(br->ob_mode & OB_MODE_SCULPT) {
+ switch (br->sculpt_tool) {
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_CREASE:
case SCULPT_TOOL_BLOB:
@@ -289,7 +291,14 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
default:
return prop_default_items;
+ }
}
+ else if(br->ob_mode & OB_MODE_VERTEX_PAINT) {
+ if(br->vertexpaint_tool == IMB_BLEND_ADD_ALPHA)
+ return prop_direction_items;
+ }
+
+ return prop_default_items;
}
#else
@@ -622,6 +631,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ACCUMULATE);
RNA_def_property_ui_text(prop, "Accumulate", "Accumulate stroke dabs on top of each other");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "mask", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_MASK);
+ RNA_def_property_ui_text(prop, "Mask", "Mark areas as protected from brush editing");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_space_atten", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACE_ATTEN);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 95e17451e62..87936594bf9 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -46,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_paint.h"
#include "BKE_utildefines.h"
#include "ED_mesh.h" /* XXX Bad level call */
@@ -295,18 +296,21 @@ static CustomData *rna_mesh_fdata(Mesh *me)
return (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
}
-static int rna_CustomDataLayer_length(PointerRNA *ptr, int type)
+static CustomData *rna_mesh_vdata(Mesh *me)
{
- Mesh *me= (Mesh*)ptr->id.data;
- CustomData *fdata= rna_mesh_fdata(me);
- CustomDataLayer *layer;
- int i, length= 0;
+ return (me->edit_mesh)? &me->edit_mesh->vdata: &me->vdata;
+}
- for(layer=fdata->layers, i=0; i<fdata->totlayer; layer++, i++)
- if(layer->type == type)
- length++;
+static int rna_face_CustomDataLayer_count(PointerRNA *ptr, int type)
+{
+ CustomData *fdata= rna_mesh_fdata(ptr->id.data);
+ return CustomData_number_of_layers(fdata, type);
+}
- return length;
+static int rna_vert_CustomDataLayer_count(PointerRNA *ptr, int type)
+{
+ CustomData *vdata= rna_mesh_vdata(ptr->id.data);
+ return CustomData_number_of_layers(vdata, type);
}
static int rna_CustomDataLayer_active_get(PointerRNA *ptr, int type, int render)
@@ -368,7 +372,7 @@ static void rna_Mesh_uv_textures_begin(CollectionPropertyIterator *iter, Pointer
static int rna_Mesh_uv_textures_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_MTFACE);
+ return rna_face_CustomDataLayer_count(ptr, CD_MTFACE);
}
static PointerRNA rna_Mesh_active_uv_texture_get(PointerRNA *ptr)
@@ -691,7 +695,7 @@ static void rna_Mesh_vertex_colors_begin(CollectionPropertyIterator *iter, Point
static int rna_Mesh_vertex_colors_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_MCOL);
+ return rna_face_CustomDataLayer_count(ptr, CD_MCOL);
}
static PointerRNA rna_Mesh_active_vertex_color_get(PointerRNA *ptr)
@@ -788,6 +792,190 @@ static void rna_MeshColorLayer_name_set(PointerRNA *ptr, const char *value)
CustomData_set_layer_unique_name(fdata, cdl - fdata->layers);
}
+/* Paint mask layers */
+
+static void rna_MeshPaintMask_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ /* Hack: sculpt mesh is the active object, so find the active object
+ and compare it's mesh to see if the update is on the sculpt mesh,
+ only then pass the object to the real update function */
+ Object *ob = OBACT;
+
+ if(get_mesh(ob) == ptr->id.data)
+ paint_refresh_mask_display(ob);
+}
+
+static int rna_MeshPaintMaskLayer_data_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ Mesh *me= (Mesh*)ptr->id.data;
+
+ length[0] = me->totvert;
+
+ return length[0];
+}
+
+static void rna_MeshPaintMaskLayer_data_get(PointerRNA *ptr, float *values)
+{
+ Mesh *me= (Mesh*)ptr->id.data;
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+
+ memcpy(values, layer->data, me->totvert * sizeof(float));
+}
+
+static void rna_MeshPaintMaskLayer_data_set(PointerRNA *ptr, const float *values)
+{
+ Mesh *me= (Mesh*)ptr->id.data;
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+
+ memcpy(layer->data, values, me->totvert * sizeof(float));
+}
+
+static char *rna_MeshPaintMask_path(PointerRNA *ptr)
+{
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+
+ return BLI_sprintfN("paintmask[%d]", (float*)ptr->data - (float*)layer->data);
+}
+
+static int rna_mask_layer_check(CollectionPropertyIterator *iter, void *data)
+{
+ CustomDataLayer *layer= (CustomDataLayer*)data;
+ return (layer->type != CD_PAINTMASK);
+}
+
+
+static void rna_Mesh_mask_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *vdata= rna_mesh_vdata(me);
+ rna_iterator_array_begin(iter, (void*)vdata->layers,
+ sizeof(CustomDataLayer),
+ vdata->totlayer, 0,
+ rna_mask_layer_check);
+}
+
+static int rna_Mesh_mask_layers_length(PointerRNA *ptr)
+{
+ return rna_vert_CustomDataLayer_count(ptr, CD_PAINTMASK);
+}
+
+static int rna_Mesh_active_paint_mask_index_get(PointerRNA *ptr)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *vdata= rna_mesh_vdata(me);
+ return CustomData_get_active_layer(vdata, CD_PAINTMASK);
+}
+
+static void rna_Mesh_active_paint_mask_index_set(PointerRNA *ptr, int value)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *vdata= rna_mesh_vdata(me);
+
+ CustomData_set_layer_active(vdata, CD_PAINTMASK, value);
+}
+
+static void rna_Mesh_active_paint_mask_index_range(PointerRNA *ptr, int *min, int *max)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *vdata= rna_mesh_vdata(me);
+
+ *min= 0;
+ *max= CustomData_number_of_layers(vdata, CD_PAINTMASK)-1;
+ *max= MAX2(0, *max);
+}
+
+/* Ptex layers */
+
+static char *rna_MeshPtexLayer_path(PointerRNA *ptr)
+{
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+
+ return BLI_sprintfN("ptex[%d]", (MPtex*)ptr->data - (MPtex*)layer->data);
+}
+
+static int rna_ptex_layer_check(CollectionPropertyIterator *iter, void *data)
+{
+ CustomDataLayer *layer= (CustomDataLayer*)data;
+ return (layer->type != CD_MPTEX);
+}
+
+static void rna_Mesh_ptex_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *fdata= rna_mesh_fdata(me);
+ rna_iterator_array_begin(iter, (void*)fdata->layers,
+ sizeof(CustomDataLayer),
+ fdata->totlayer, 0,
+ rna_ptex_layer_check);
+}
+
+static int rna_Mesh_ptex_layers_length(PointerRNA *ptr)
+{
+ return rna_face_CustomDataLayer_count(ptr, CD_MPTEX);
+}
+
+
+static int rna_Mesh_active_ptex_index_get(PointerRNA *ptr)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *fdata= rna_mesh_fdata(me);
+ return CustomData_get_active_layer(fdata, CD_MPTEX);
+}
+
+static void rna_Mesh_active_ptex_index_set(PointerRNA *ptr, int value)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *fdata= rna_mesh_fdata(me);
+
+ CustomData_set_layer_active(fdata, CD_MPTEX, value);
+}
+
+static void rna_Mesh_active_ptex_index_range(PointerRNA *ptr, int *min, int *max)
+{
+ Mesh *me= (Mesh*)ptr->data;
+ CustomData *fdata= rna_mesh_fdata(me);
+
+ *min= 0;
+ *max= CustomData_number_of_layers(fdata, CD_MPTEX)-1;
+ *max= MAX2(0, *max);
+}
+
+static void rna_MeshPtexLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Mesh *me= (Mesh*)ptr->id.data;
+ CustomDataLayer *layer= (CustomDataLayer*)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(MPtex), (me->edit_mesh)? 0: me->totface, 0, NULL);
+}
+
+static int rna_MeshPtexLayer_data_length(PointerRNA *ptr)
+{
+ Mesh *me= (Mesh*)ptr->id.data;
+ return (me->edit_mesh)? 0: me->totface;
+}
+
+static void rna_MeshPtexSubface_resolution_get(PointerRNA *ptr, int *values)
+{
+ MPtexSubface *subface= (MPtexSubface*)ptr->data;
+ values[0] = subface->res[0];
+ values[1] = subface->res[1];
+}
+
+static void rna_MeshPtex_subfaces_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ MPtex *pt= (MPtex*)ptr->data;
+ rna_iterator_array_begin(iter, pt->subfaces,
+ sizeof(MPtexSubface),
+ pt->totsubface, 0, NULL);
+}
+
+static int rna_MeshPtex_subfaces_length(PointerRNA *ptr)
+{
+ MPtex *pt= (MPtex*)ptr->data;
+ return pt->totsubface;
+}
+
+/* Custom property layers */
+
static void rna_MeshFloatPropertyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me= (Mesh*)ptr->id.data;
@@ -816,7 +1004,7 @@ static void rna_Mesh_float_layers_begin(CollectionPropertyIterator *iter, Pointe
static int rna_Mesh_float_layers_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_PROP_FLT);
+ return rna_face_CustomDataLayer_count(ptr, CD_PROP_FLT);
}
static int rna_int_layer_check(CollectionPropertyIterator *iter, void *data)
@@ -847,7 +1035,7 @@ static void rna_Mesh_int_layers_begin(CollectionPropertyIterator *iter, PointerR
static int rna_Mesh_int_layers_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_PROP_INT);
+ return rna_face_CustomDataLayer_count(ptr, CD_PROP_INT);
}
static int rna_string_layer_check(CollectionPropertyIterator *iter, void *data)
@@ -878,7 +1066,7 @@ static void rna_Mesh_string_layers_begin(CollectionPropertyIterator *iter, Point
static int rna_Mesh_string_layers_length(PointerRNA *ptr)
{
- return rna_CustomDataLayer_length(ptr, CD_PROP_STR);
+ return rna_face_CustomDataLayer_count(ptr, CD_PROP_STR);
}
static void rna_TextureFace_image_set(PointerRNA *ptr, PointerRNA value)
@@ -1013,6 +1201,11 @@ static char *rna_MeshColor_path(PointerRNA *ptr)
return rna_CustomDataData_path(ptr, "vertex_colors", CD_MCOL);
}
+static char *rna_MeshPtex_path(PointerRNA *ptr)
+{
+ return rna_CustomDataData_path(ptr, "mesh_ptex", CD_MPTEX);
+}
+
static char *rna_MeshSticky_path(PointerRNA *ptr)
{
return BLI_sprintfN("sticky[%d]", (MSticky*)ptr->data - ((Mesh*)ptr->id.data)->msticky);
@@ -1509,6 +1702,11 @@ static void rna_def_mcol(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Render", "Sets the layer as active for rendering");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ prop= RNA_def_property(srna, "multiresolution", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CD_FLAG_MULTIRES);
+ RNA_def_property_ui_text(prop, "Multiresolution", "Sets whether the layer can be edited at multiple resolutions");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshColor");
RNA_def_property_ui_text(prop, "Data", "");
@@ -1548,6 +1746,83 @@ static void rna_def_mcol(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
+static void rna_def_ptex(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "MeshPtexLayer", NULL);
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_ui_text(srna, "Mesh Ptex Layer", "");
+ RNA_def_struct_path_func(srna, "rna_MeshPtexLayer_path");
+
+ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshPtex");
+ RNA_def_property_ui_text(prop, "Data", "");
+ RNA_def_property_collection_funcs(prop, "rna_MeshPtexLayer_data_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshPtexLayer_data_length", 0, 0);
+
+ srna= RNA_def_struct(brna, "MeshPtex", NULL);
+ RNA_def_struct_sdna(srna, "MPtex");
+ RNA_def_struct_ui_text(srna, "Mesh Ptex", "Variable-resolution multi-channel data");
+ RNA_def_struct_path_func(srna, "rna_MeshPtex_path");
+
+ prop= RNA_def_property(srna, "subfaces", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshPtexSubface");
+ RNA_def_property_ui_text(prop, "Subfaces", "");
+ RNA_def_property_collection_funcs(prop, "rna_MeshPtex_subfaces_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get", "rna_MeshPtex_subfaces_length", 0, 0);
+
+ srna= RNA_def_struct(brna, "MeshPtexSubface", NULL);
+ RNA_def_struct_sdna(srna, "MPtexSubface");
+ RNA_def_struct_ui_text(srna, "Mesh Ptex Subface", "");
+ RNA_def_struct_path_func(srna, "rna_MeshPtex_path");
+
+ prop= RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "res");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_range(prop, 0, 31);
+ RNA_def_property_int_funcs(prop, "rna_MeshPtexSubface_resolution_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Resolution", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
+static void rna_def_paintmask(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "MeshPaintMaskLayer", NULL);
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_ui_text(srna, "Mesh Paint Mask Layer", "");
+ RNA_def_struct_path_func(srna, "rna_MeshPaintMaskLayer_path");
+
+ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_float_array(srna, "data", 1, NULL, 0.0f, 1.0f, "Vertex Paint Masks", "", 0.0f, 1.0f);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_MeshPaintMaskLayer_data_get_length");
+ RNA_def_property_float_funcs(prop, "rna_MeshPaintMaskLayer_data_get",
+ "rna_MeshPaintMaskLayer_data_set", NULL);
+ RNA_def_struct_path_func(srna, "rna_MeshPaintMask_path");
+
+ prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Strength", "Opacity of the paint mask");
+ RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_MeshPaintMask_update_data");
+
+ prop= RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CD_FLAG_ENABLED);
+ RNA_def_property_ui_text(prop, "Enabled", "Enable the mask for display and affecting brushes.");
+ RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_MeshPaintMask_update_data");
+}
+
static void rna_def_mproperties(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1688,6 +1963,10 @@ static void rna_def_mesh_faces(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_int_sdna(prop, NULL, "act_face");
RNA_def_property_ui_text(prop, "Active Face", "The active face for this mesh");
+ prop= RNA_def_property(srna, "active_subface", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "act_subface");
+ RNA_def_property_ui_text(prop, "Active Subface", "The active subface of the active face");
+
prop= RNA_def_property(srna, "active_tface", PROP_POINTER, PROP_UNSIGNED);
RNA_def_property_struct_type(prop, "MeshTextureFace");
RNA_def_property_pointer_funcs(prop, "rna_Mesh_active_mtface_get", NULL, NULL, NULL);
@@ -1856,6 +2135,34 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertex Colors", "");
rna_def_vertex_colors(brna, prop);
+ prop= RNA_def_property(srna, "paint_mask_layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_mask_layers_begin",
+ 0, 0, 0, "rna_Mesh_mask_layers_length", 0, 0);
+ RNA_def_property_struct_type(prop, "MeshPaintMaskLayer");
+ RNA_def_property_ui_text(prop, "Paint Mask Layers", "Masked areas are not affected by paint brushes.");
+
+ prop= RNA_def_property(srna, "active_paint_mask_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_active_paint_mask_index_get",
+ "rna_Mesh_active_paint_mask_index_set",
+ "rna_Mesh_active_paint_mask_index_range");
+ RNA_def_property_ui_text(prop, "Active Paint Mask Index", "Active paint mask layer index");
+
+ /* Ptex */
+ prop= RNA_def_property(srna, "ptex_layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_ptex_layers_begin",
+ 0, 0, 0, "rna_Mesh_ptex_layers_length", 0, 0);
+ RNA_def_property_struct_type(prop, "MeshPtexLayer");
+ RNA_def_property_ui_text(prop, "Ptex Layers", "Variable-resolution mesh colors");
+
+ prop= RNA_def_property(srna, "active_ptex_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_Mesh_active_ptex_index_get",
+ "rna_Mesh_active_ptex_index_set",
+ "rna_Mesh_active_ptex_index_range");
+ RNA_def_property_ui_text(prop, "Active Ptex Index", "Active ptex layer index");
+
+ /* float layers */
prop= RNA_def_property(srna, "layers_float", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
RNA_def_property_collection_funcs(prop, "rna_Mesh_float_layers_begin", 0, 0, 0, "rna_Mesh_float_layers_length", 0, 0);
@@ -2015,7 +2322,13 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_PAINT_MASK);
RNA_def_property_ui_text(prop, "Paint Mask", "Face selection masking for painting");
RNA_def_property_ui_icon(prop, ICON_FACESEL_HLT, 0);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop= RNA_def_property(srna, "ptex_edit_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_PTEX);
+ RNA_def_property_ui_text(prop, "Ptex Edit Mode", "Edit faces' ptex resolution");
+ RNA_def_property_ui_icon(prop, ICON_FACESEL_HLT, 0);
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
/* readonly editmesh info - use for extrude menu */
@@ -2050,6 +2363,8 @@ void RNA_def_mesh(BlenderRNA *brna)
rna_def_mtface(brna);
rna_def_msticky(brna);
rna_def_mcol(brna);
+ rna_def_ptex(brna);
+ rna_def_paintmask(brna);
rna_def_mproperties(brna);
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index e83a17cc277..a31cbdd20c7 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -616,9 +616,9 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MultiresModifier_level_range");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop= RNA_def_property(srna, "sculpt_levels", PROP_INT, PROP_UNSIGNED);
+ prop= RNA_def_property(srna, "edit_levels", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "sculptlvl");
- RNA_def_property_ui_text(prop, "Sculpt Levels", "Number of subdivisions to use in sculpt mode");
+ RNA_def_property_ui_text(prop, "Edit Levels", "Number of subdivisions to use in sculpt and paint modes");
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MultiresModifier_level_range");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index bc778ff3256..4ee82903cea 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -35,6 +35,11 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
+#include "BLI_winstuff.h"
+
+#include <stdio.h>
+#include <string.h>
+
/* Include for Bake Options */
#include "RE_pipeline.h"
@@ -169,6 +174,7 @@ EnumPropertyItem image_type_items[] = {
#include "BLI_threads.h"
#include "BLI_editVert.h"
#include "BLI_blenlib.h"
+#include "BLI_winstuff.h"
#include "WM_api.h"
@@ -978,6 +984,33 @@ static void rna_def_transform_orientation(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL);
}
+static EnumPropertyItem *ptex_resolution_items()
+{
+#define PTEX_TOP_RES 20
+ static EnumPropertyItem items[PTEX_TOP_RES+1];
+ static char identifiers[PTEX_TOP_RES][14];
+ static int inited = 0;
+
+ if(!inited) {
+ int i;
+
+ memset(items, 0, sizeof(EnumPropertyItem) * (PTEX_TOP_RES+1));
+
+ for(i = 0; i < PTEX_TOP_RES; ++i) {
+ int x = 1 << i;
+ items[i].value = x;
+ items[i].identifier = identifiers[i];
+ items[i].name = identifiers[i] + 3;
+ snprintf(identifiers[i], 14, "RES%d", x);
+ }
+
+ inited = 1;
+ }
+
+ return items;
+#undef PTEX_TOP_RES
+}
+
static void rna_def_tool_settings(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1045,6 +1078,10 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "particle");
RNA_def_property_ui_text(prop, "Particle Edit", "");
+ prop= RNA_def_property(srna, "paint_overlay", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Paint Overlay", "Image overlay for paint");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+
/* Transform */
prop= RNA_def_property(srna, "proportional_edit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "proportional");
@@ -1235,6 +1272,18 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "sculpt_paint_use_unified_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_USE_UNIFIED_ALPHA);
RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Strength", "Instead of per brush strength, the strength is shared across brushes");
+
+ /* Ptex */
+
+ prop= RNA_def_property(srna, "ptex_u_resolution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "ptex_ures");
+ RNA_def_property_enum_items(prop, ptex_resolution_items());
+ RNA_def_property_ui_text(prop, "Ptex U Resolution", "");
+
+ prop= RNA_def_property(srna, "ptex_v_resolution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "ptex_vres");
+ RNA_def_property_enum_items(prop, ptex_resolution_items());
+ RNA_def_property_ui_text(prop, "Ptex V Resolution", "");
}
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 3b83ec2d3ad..6cd39cf78a9 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -52,11 +52,15 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = {
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_pointcache.h"
#include "BKE_particle.h"
#include "BKE_depsgraph.h"
+#include "IMB_imbuf_types.h"
+
#include "ED_particle.h"
+#include "ED_sculpt.h"
static EnumPropertyItem particle_edit_disconnected_hair_brush_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"},
@@ -74,6 +78,29 @@ static EnumPropertyItem particle_edit_cache_brush_items[] = {
{PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make paths longer or shorter"},
{0, NULL, 0, NULL, NULL}};
+static void rna_PaintOverlay_image_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ PaintOverlay *overlay = &scene->toolsettings->paint_overlay;
+ ED_paint_update_overlay(overlay);
+}
+
+static void rna_PaintOverlay_image_update_new(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ PaintOverlay *overlay = &scene->toolsettings->paint_overlay;
+
+ /* make sure size is reasonable */
+ if(overlay->size[0] < 4 || overlay->size[1] < 4) {
+ ImBuf *ibuf;
+
+ ibuf = BKE_image_get_ibuf(overlay->img, NULL);
+
+ overlay->size[0] = ibuf->x;
+ overlay->size[1] = ibuf->y;
+ }
+
+ ED_paint_update_overlay(overlay);
+}
+
static PointerRNA rna_ParticleEdit_brush_get(PointerRNA *ptr)
{
ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data;
@@ -181,6 +208,18 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Brush", "Active Brush");
RNA_def_property_update(prop, NC_BRUSH|NA_EDITED, NULL);
+ prop= RNA_def_property(srna, "symmetry_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMM_X);
+ RNA_def_property_ui_text(prop, "Symmetry X", "Mirror brush across the X axis");
+
+ prop= RNA_def_property(srna, "symmetry_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMM_Y);
+ RNA_def_property_ui_text(prop, "Symmetry Y", "Mirror brush across the Y axis");
+
+ prop= RNA_def_property(srna, "symmetry_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMM_Z);
+ RNA_def_property_ui_text(prop, "Symmetry Z", "Mirror brush across the Z axis");
+
prop= RNA_def_property(srna, "show_brush", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH);
RNA_def_property_ui_text(prop, "Show Brush", "");
@@ -192,15 +231,6 @@ static void rna_def_paint(BlenderRNA *brna)
prop= RNA_def_property(srna, "show_low_resolution", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_FAST_NAVIGATE);
RNA_def_property_ui_text(prop, "Fast Navigate", "For multires, show low resolution while navigating the view");
-}
-
-static void rna_def_sculpt(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna= RNA_def_struct(brna, "Sculpt", "Paint");
- RNA_def_struct_ui_text(srna, "Sculpt", "");
prop= RNA_def_property(srna, "radial_symmetry", PROP_INT, PROP_XYZ);
RNA_def_property_int_sdna(prop, NULL, "radial_symm");
@@ -210,38 +240,46 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis", "Number of times to copy strokes across the surface");
prop= RNA_def_property(srna, "use_symmetry_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMM_X);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMM_X);
RNA_def_property_ui_text(prop, "Symmetry X", "Mirror brush across the X axis");
prop= RNA_def_property(srna, "use_symmetry_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMM_Y);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMM_Y);
RNA_def_property_ui_text(prop, "Symmetry Y", "Mirror brush across the Y axis");
prop= RNA_def_property(srna, "use_symmetry_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMM_Z);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMM_Z);
RNA_def_property_ui_text(prop, "Symmetry Z", "Mirror brush across the Z axis");
prop= RNA_def_property(srna, "lock_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_X);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_LOCK_X);
RNA_def_property_ui_text(prop, "Lock X", "Disallow changes to the X axis of vertices");
prop= RNA_def_property(srna, "lock_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_Y);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_LOCK_Y);
RNA_def_property_ui_text(prop, "Lock Y", "Disallow changes to the Y axis of vertices");
prop= RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_Z);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_LOCK_Z);
RNA_def_property_ui_text(prop, "Lock Z", "Disallow changes to the Z axis of vertices");
prop= RNA_def_property(srna, "use_symmetry_feather", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMMETRY_FEATHER);
- RNA_def_property_ui_text(prop, "Symmetry Feathering", "Reduce the strength of the brush where it overlaps symmetrical daubs");
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SYMMETRY_FEATHER);
+ RNA_def_property_ui_text(prop, "Symmetry Feathering", "Reduce the strength of the brush where it overlaps symmetrical dabs");
prop= RNA_def_property(srna, "use_threaded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_USE_OPENMP);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_USE_OPENMP);
RNA_def_property_ui_text(prop, "Use OpenMP", "Take advantage of multiple CPU cores to improve sculpting performance");
}
+static void rna_def_sculpt(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna= RNA_def_struct(brna, "Sculpt", "Paint");
+ RNA_def_struct_ui_text(srna, "Sculpt", "");
+}
+
static void rna_def_vertex_paint(BlenderRNA *brna)
{
StructRNA *srna;
@@ -496,6 +534,39 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve", "");
}
+static void rna_def_paint_overlay(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna= RNA_def_struct(brna, "PaintOverlay", NULL);
+ RNA_def_struct_sdna(srna, "PaintOverlay");
+ RNA_def_struct_ui_text(srna, "Paint Overlay", "Properties of paint overlay");
+
+ prop= RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use", 1);
+ RNA_def_property_ui_text(prop, "Enable Overlay", "Overlay source image in viewport and sample brush color from it");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D|NA_EDITED, NULL);
+
+ prop= RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "img");
+ RNA_def_property_ui_text(prop, "Image", "Sample image for brush color");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, ND_SPACE_VIEW3D|NA_EDITED, "rna_PaintOverlay_image_update_new");
+
+ prop= RNA_def_property(srna, "transparency_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "transp_col");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Transparency Color", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D|NA_EDITED, "rna_PaintOverlay_image_update");
+
+ prop= RNA_def_property(srna, "transparency_tolerance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "transp_tol");
+ RNA_def_property_ui_range(prop, 0, 255, 100, 1);
+ RNA_def_property_ui_text(prop, "Tolerance", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D|NA_EDITED, "rna_PaintOverlay_image_update");
+}
+
void RNA_def_sculpt_paint(BlenderRNA *brna)
{
rna_def_paint(brna);
@@ -503,6 +574,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
rna_def_vertex_paint(brna);
rna_def_image_paint(brna);
rna_def_particle_edit(brna);
+ rna_def_paint_overlay(brna);
}
#endif
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 758809ff7ec..4c05f139b71 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -64,8 +64,6 @@ static void copyData(ModifierData *md, ModifierData *target)
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
int useRenderParams, int isFinalCalc)
{
- SculptSession *ss= ob->sculpt;
- int sculpting= (ob->mode & OB_MODE_SCULPT) && ss;
MultiresModifierData *mmd = (MultiresModifierData*)md;
DerivedMesh *result;
Mesh *me= (Mesh*)ob->data;
@@ -77,21 +75,17 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
}
}
- result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams, isFinalCalc);
+ result = multires_dm_create_from_derived(mmd, 0, dm, ob, NULL, useRenderParams, isFinalCalc);
if(result == dm)
return dm;
if(useRenderParams || !isFinalCalc) {
DerivedMesh *cddm= CDDM_copy(result);
+
result->release(result);
result= cddm;
}
- else if(sculpting) {
- /* would be created on the fly too, just nicer this
- way on first stroke after e.g. switching levels */
- ss->pbvh= result->getPBVH(ob, result);
- }
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 3264717c97a..a82b3af975b 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -92,7 +92,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
SubsurfModifierData *smd = (SubsurfModifierData*) md;
DerivedMesh *result;
- result = subsurf_make_derived_from_derived(derivedData, smd,
+ result = subsurf_make_derived_from_derived(derivedData, smd, NULL,
useRenderParams, NULL, isFinalCalc, 0);
if(useRenderParams || !isFinalCalc) {
@@ -111,7 +111,7 @@ static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob),
SubsurfModifierData *smd = (SubsurfModifierData*) md;
DerivedMesh *result;
- result = subsurf_make_derived_from_derived(derivedData, smd, 0,
+ result = subsurf_make_derived_from_derived(derivedData, smd, NULL, 0,
NULL, 0, 1);
return result;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index de96684a2dd..4ed5b22756b 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -39,6 +39,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "BKE_displist.h"
+#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_modifier.h"
@@ -49,23 +50,6 @@
#include "RE_shader_ext.h"
-void get_texture_value(Tex *texture, float *tex_co, TexResult *texres)
-{
- int result_type;
-
- result_type = multitex_ext(texture, tex_co, NULL, NULL, 0, texres);
-
- /* if the texture gave an RGB value, we assume it didn't give a valid
- * intensity, so calculate one (formula from do_material_tex).
- * if the texture didn't give an RGB value, copy the intensity across
- */
- if(result_type & TEX_RGB)
- texres->tin = (0.35f * texres->tr + 0.45f * texres->tg
- + 0.2f * texres->tb);
- else
- texres->tr = texres->tg = texres->tb = texres->tin;
-}
-
void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3])
{
while((md=md->next) && md->type==eModifierType_Armature) {
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index 6abc29417b5..6745d3ee564 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -37,7 +37,6 @@ struct Scene;
struct EditMesh;
struct ModifierData;
-void get_texture_value(struct Tex *texture, float *tex_co, struct TexResult *texres);
void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]);
void validate_layer_name(const struct CustomData *data, int type, char *name, char *outname);
struct DerivedMesh *get_cddm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]);
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index acd8c29a6dd..8c0e18f5248 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -41,6 +41,7 @@
#include "BKE_object.h"
#include "BKE_deform.h"
#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "depsgraph_private.h"
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 00a686c0d74..50d6c885022 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -616,7 +616,7 @@ int WM_write_file(bContext *C, const char *target, int fileflags, ReportList *re
}
ED_object_exit_editmode(C, EM_DO_UNDO);
- ED_sculpt_force_update(C);
+ ED_paint_force_update(C);
/* blend file thumbnail */
ibuf_thumb= blend_file_thumb(CTX_data_scene(C), &thumb);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index ccdb19adfce..ef0572d3a12 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3271,6 +3271,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "MARKER_OT_select_border");
WM_modalkeymap_assign(keymap, "NLA_OT_select_border");
WM_modalkeymap_assign(keymap, "NODE_OT_select_border");
+ WM_modalkeymap_assign(keymap, "SCULPT_OT_area_hide");
// WM_modalkeymap_assign(keymap, "SCREEN_OT_border_select"); // template
WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_border");
WM_modalkeymap_assign(keymap, "SEQUENCER_OT_view_ghost_border");