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:
authorBastien Montagne <montagne29@wanadoo.fr>2018-08-01 15:16:41 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2018-08-01 15:16:41 +0300
commit936d1cef6e6124a8f8f3ce50182afa2e1c947c6f (patch)
tree429a7503472bd8fe38ceb062086e447cb3a83423 /source/blender/blenkernel
parent4e6bcd10e559ab541df53a3d7b645faac1a7fe27 (diff)
parentddd62f1b1063d69df5171c7b3457ffcffcc6b0e4 (diff)
Merge branch 'blender2.8' into soc-2018-bevel
Conflicts: release/scripts/addons release/scripts/startup/bl_ui/space_view3d_toolbar.py source/blender/editors/space_outliner/outliner_draw.c
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_action.h1
-rw-r--r--source/blender/blenkernel/BKE_armature.h13
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h8
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h8
-rw-r--r--source/blender/blenkernel/BKE_context.h12
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h103
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h256
-rw-r--r--source/blender/blenkernel/BKE_icons.h7
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h4
-rw-r--r--source/blender/blenkernel/BKE_object.h12
-rw-r--r--source/blender/blenkernel/BKE_paint.h3
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h2
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h180
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h23
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c1
-rw-r--r--source/blender/blenkernel/intern/action.c61
-rw-r--r--source/blender/blenkernel/intern/anim.c16
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c6
-rw-r--r--source/blender/blenkernel/intern/armature.c6
-rw-r--r--source/blender/blenkernel/intern/armature_update.c70
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c1
-rw-r--r--source/blender/blenkernel/intern/brush.c380
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c79
-rw-r--r--source/blender/blenkernel/intern/camera.c5
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c4
-rw-r--r--source/blender/blenkernel/intern/collection.c2
-rw-r--r--source/blender/blenkernel/intern/colortools.c19
-rw-r--r--source/blender/blenkernel/intern/constraint.c8
-rw-r--r--source/blender/blenkernel/intern/context.c20
-rw-r--r--source/blender/blenkernel/intern/curve.c10
-rw-r--r--source/blender/blenkernel/intern/deform.c4
-rw-r--r--source/blender/blenkernel/intern/displist.c42
-rw-r--r--source/blender/blenkernel/intern/effect.c4
-rw-r--r--source/blender/blenkernel/intern/font.c6
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1383
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c677
-rw-r--r--source/blender/blenkernel/intern/icons.c44
-rw-r--r--source/blender/blenkernel/intern/key.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c30
-rw-r--r--source/blender/blenkernel/intern/layer.c16
-rw-r--r--source/blender/blenkernel/intern/library.c3
-rw-r--r--source/blender/blenkernel/intern/library_query.c25
-rw-r--r--source/blender/blenkernel/intern/material.c80
-rw-r--r--source/blender/blenkernel/intern/mball.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c24
-rw-r--r--source/blender/blenkernel/intern/object.c239
-rw-r--r--source/blender/blenkernel/intern/object_deform.c16
-rw-r--r--source/blender/blenkernel/intern/object_update.c4
-rw-r--r--source/blender/blenkernel/intern/paint.c13
-rw-r--r--source/blender/blenkernel/intern/particle_system.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c66
-rw-r--r--source/blender/blenkernel/intern/scene.c94
-rw-r--r--source/blender/blenkernel/intern/screen.c1
-rw-r--r--source/blender/blenkernel/intern/sequencer.c1
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c245
-rw-r--r--source/blender/blenkernel/intern/subdiv.c21
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c1913
-rw-r--r--source/blender/blenkernel/intern/subdiv_stats.c4
-rw-r--r--source/blender/blenkernel/intern/world.c1
64 files changed, 5136 insertions, 1159 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 106866aff0a..263a54eab4e 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -201,6 +201,7 @@ void BKE_pose_remove_group_index(struct bPose *pose, const int index);
void what_does_obaction(struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe);
/* for proxy */
+void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom);
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void BKE_pose_rest(struct bPose *pose);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 21d880cf2a7..17329beb325 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -100,7 +100,7 @@ void BKE_armature_where_is(struct bArmature *arm);
void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion);
void BKE_pose_clear_pointers(struct bPose *pose);
void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose);
-void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm);
+void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm, const bool do_id_user);
void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
@@ -231,9 +231,16 @@ void BKE_pose_eval_flush(
struct Scene *scene,
struct Object *ob);
-void BKE_pose_eval_proxy_copy(
+void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph,
+ struct Object *object);
+
+void BKE_pose_eval_proxy_pose_done(struct Depsgraph *depsgraph,
+ struct Object *object);
+
+void BKE_pose_eval_proxy_copy_bone(
struct Depsgraph *depsgraph,
- struct Object *ob);
+ struct Object *object,
+ int pchan_index);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 8707fe3e11b..79ae904c73d 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 20
+#define BLENDER_SUBVERSION 21
/* Several breakages with 280, e.g. collections vs layers */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index eda1c51bbc2..489746cbfd9 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -28,11 +28,14 @@
*/
enum eCurveMappingPreset;
+struct bContext;
struct Brush;
+struct Paint;
struct ImBuf;
struct ImagePool;
struct Main;
struct Scene;
+struct ToolSettings;
struct UnifiedPaintSettings;
// enum eCurveMappingPreset;
@@ -45,14 +48,17 @@ void BKE_brush_system_exit(void);
/* datablock functions */
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
+struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag);
struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
-void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
+void BKE_brush_gpencil_presets(struct bContext *C);
+struct Brush *BKE_brush_getactive_gpencil(struct ToolSettings *ts);
+struct Paint *BKE_brush_get_gpencil_paint(struct ToolSettings *ts);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index d79a7eae53e..a0780a5be54 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -102,7 +102,7 @@ typedef struct BVHTreeFromMesh {
*/
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache);
BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *mask, int verts_num_active,
@@ -115,7 +115,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache);
BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *edges_mask, int edges_num_active,
@@ -190,7 +190,9 @@ enum {
BVHTREE_FROM_LOOSEVERTS = 4,
BVHTREE_FROM_LOOSEEDGES = 5,
- BVHTREE_FROM_EM_LOOPTRI = 6,
+ BVHTREE_FROM_EM_VERTS = 6,
+ BVHTREE_FROM_EM_EDGES = 7,
+ BVHTREE_FROM_EM_LOOPTRI = 8,
};
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 9f57859d318..28dcf9cb127 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -65,9 +65,7 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
-struct bGPDpalette;
-struct bGPDpalettecolor;
-struct bGPDbrush;
+struct Brush;
struct wmWindow;
struct wmWindowManager;
struct RenderEngineType;
@@ -120,6 +118,10 @@ enum {
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
CTX_MODE_OBJECT,
+ CTX_MODE_GPENCIL_PAINT,
+ CTX_MODE_GPENCIL_EDIT,
+ CTX_MODE_GPENCIL_SCULPT,
+ CTX_MODE_GPENCIL_WEIGHT,
CTX_MODE_NUM /* must be last */
};
@@ -313,9 +315,7 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
struct bGPdata *CTX_data_gpencil_data(const bContext *C);
struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
-struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
-struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
-struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
+struct Brush *CTX_data_active_gpencil_brush(const bContext *C);
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 3a951b7860d..887a7f4f67b 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -31,25 +31,45 @@
* \author Joshua Leung
*/
+struct CurveMapping;
+struct Depsgraph;
+struct GpencilModifierData;
struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDspoint;
struct bGPDstroke;
+struct Material;
struct bGPDpalette;
struct bGPDpalettecolor;
struct Main;
+struct BoundBox;
+struct Brush;
+struct Object;
+struct bDeformGroup;
+struct SimplifyGpencilModifierData;
+struct InstanceGpencilModifierData;
+struct LatticeGpencilModifierData;
+
+struct MDeformVert;
+struct MDeformWeight;
/* ------------ Grease-Pencil API ------------------ */
+void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
+void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
void BKE_gpencil_free_layers(struct ListBase *list);
-void BKE_gpencil_free_brushes(struct ListBase *list);
-void BKE_gpencil_free_palettes(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
+bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf);
+void BKE_gpencil_free_derived_frames(struct bGPdata *gpd);
+void BKE_gpencil_free(struct bGPdata *gpd, bool free_all);
+
+void BKE_gpencil_batch_cache_dirty(struct bGPdata *gpd);
+void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
@@ -60,21 +80,36 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
+void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
+struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src);
+
void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
+struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd);
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
-struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
-struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
+/* materials */
+void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index);
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len);
-struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
-struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
-void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
+/* statistics functions */
+void BKE_gpencil_stats_update(struct bGPdata *gpd);
+/* Utilities for creating and populating GP strokes */
+/* - Number of values defining each point in the built-in data
+ * buffers for primitives (e.g. 2D Monkey)
+ */
+#define GP_PRIM_DATABUF_SIZE 5
+
+void BKE_gpencil_stroke_add_points(
+ struct bGPDstroke *gps,
+ const float *array, const int totpoints,
+ const float mat[4][4]);
+
+struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
@@ -103,20 +138,40 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
-struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
-void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
-void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush);
-
-struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
-void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
-void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
-void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
-
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
-void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
-void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
-void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
+struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush);
+struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob);
+
+/* object boundbox */
+bool BKE_gpencil_stroke_minmax(
+ const struct bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3]);
+
+struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+void BKE_gpencil_centroid_3D(struct bGPdata *gpd, float r_centroid[3]);
+
+/* vertex groups */
+float BKE_gpencil_vgroup_use_index(struct MDeformVert *dvert, int index);
+void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+struct MDeformWeight *BKE_gpencil_vgroup_add_point_weight(struct MDeformVert *dvert, int index, float weight);
+bool BKE_gpencil_vgroup_remove_point_weight(struct MDeformVert *dvert, int index);
+void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
+
+/* GPencil geometry evaluation */
+void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd);
+
+/* stroke geometry utilities */
+void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
+void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor);
+void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps);
+
+void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]);
+
+bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf);
+bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence);
+
+void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
+float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
#endif /* __BKE_GPENCIL_H__ */
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
new file mode 100644
index 00000000000..be27560bbf2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -0,0 +1,256 @@
+/*
+ * ***** 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: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_GPENCIL_MODIFIER_H__
+#define __BKE_GPENCIL_MODIFIER_H__
+
+/** \file BKE_gpencil_modifier.h
+ * \ingroup bke
+ */
+
+#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct GpencilModifierData;
+struct BMEditMesh;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \
+ ((_md->mode & eGpencilModifierMode_Render) && (_is_render == true)))
+#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None modifier type */
+ eGpencilModifierTypeType_None,
+
+ /* grease pencil modifiers */
+ eGpencilModifierTypeType_Gpencil,
+} GpencilModifierTypeType;
+
+typedef enum {
+ eGpencilModifierTypeFlag_SupportsMapping = (1 << 0),
+ eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1),
+
+ /* For modifiers that support editmode this determines if the
+ * modifier should be enabled by default in editmode. This should
+ * only be used by modifiers that are relatively speedy and
+ * also generally used in editmode, otherwise let the user enable
+ * it by hand.
+ */
+ eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* For modifiers that require original data and so cannot
+ * be placed after any non-deformative modifier.
+ */
+ eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3),
+
+ /* max one per type */
+ eGpencilModifierTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eGpencilModifierTypeFlag_NoUserAdd = (1 << 5),
+} GpencilModifierTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname);
+
+typedef struct GpencilModifierTypeInfo {
+ /* The user visible name for this modifier */
+ char name[32];
+
+ /* The DNA struct name for the modifier data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the modifier data type, used by allocation. */
+ int struct_size;
+
+ GpencilModifierType type;
+ GpencilModifierTypeFlag flags;
+
+
+ /********************* Non-optional functions *********************/
+
+ /* Copy instance data for this modifier type. Should copy all user
+ * level settings to the target modifier.
+ */
+ void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target);
+
+ /* Callback for GP "stroke" modifiers that operate on the
+ * shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.)
+ *
+ * The gpl parameter contains the GP layer that the strokes come from.
+ * While access is provided to this data, you should not directly access
+ * the gpl->frames data from the modifier. Instead, use the gpf parameter
+ * instead.
+ *
+ * The gps parameter contains the GP stroke to operate on. This is usually a copy
+ * of the original (unmodified and saved to files) stroke data.
+ */
+ void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps);
+
+ /* Callback for GP "geometry" modifiers that create extra geometry
+ * in the frame (e.g. Array)
+ *
+ * The gpf parameter contains the GP frame/strokes to operate on. This is
+ * usually a copy of the original (unmodified and saved to files) stroke data.
+ * Modifiers should only add any generated strokes to this frame (and not one accessed
+ * via the gpl parameter).
+ *
+ * The modifier_index parameter indicates where the modifier is
+ * in the modifier stack in relation to other modifiers.
+ */
+ void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+ /* Bake-down GP modifier's effects into the GP datablock.
+ *
+ * This gets called when the user clicks the "Apply" button in the UI.
+ * As such, this callback needs to go through all layers/frames in the
+ * datablock, mutating the geometry and/or creating new datablocks/objects
+ */
+ void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph,
+ struct GpencilModifierData *md, struct Object *ob);
+
+ /********************* Optional functions *********************/
+
+ /* Initialize new instance data for this modifier type, this function
+ * should set modifier variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct GpencilModifierData *md);
+
+ /* Free internal modifier data variables, this function should
+ * not free the md variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct GpencilModifierData *md);
+
+ /* Return a boolean value indicating if this modifier is able to be
+ * calculated based on the modifier data. This is *not* regarding the
+ * md->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct GpencilModifierData *md,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the modifier needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct GpencilModifierData *md);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the modifier data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the modifier data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilIDWalkFunc walk, void *userData);
+
+ /* Should call the given walk function for each texture that the
+ * modifier data stores. This is used for finding all textures in
+ * the context for the UI.
+ *
+ * This function is optional. If it is not present, it will be
+ * assumed the modifier has no textures.
+ */
+ void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilTexWalkFunc walk, void *userData);
+} GpencilModifierTypeInfo;
+
+void BKE_gpencil_instance_modifier_instance_tfm(struct InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4]);
+
+/* Initialize modifier's global data (type info and some common global storages). */
+void BKE_gpencil_modifier_init(void);
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
+void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
+void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst);
+void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target);
+void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag);
+void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData);
+void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData);
+
+bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
+
+void BKE_gpencil_stroke_modifiers(
+ struct Depsgraph *depsgraph, struct Object *ob,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, bool is_render);
+void BKE_gpencil_geometry_modifiers(
+ struct Depsgraph *depsgraph, struct Object *ob,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, bool is_render);
+
+void BKE_gpencil_lattice_init(struct Object *ob);
+void BKE_gpencil_lattice_clear(struct Object *ob);
+
+#endif /* __BKE_GPENCIL_MODIFIER_H__ */
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 22897d2ea80..7a5262e0a14 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -43,7 +43,10 @@ enum {
ICON_DATA_PREVIEW,
/** 2D triangles: obj is #Icon_Geom */
ICON_DATA_GEOM,
+ /** Studiolight */
ICON_DATA_STUDIOLIGHT,
+ /** GPencil Layer color preview (annotations): obj is #bGPDlayer */
+ ICON_DATA_GPLAYER,
};
struct Icon {
@@ -79,6 +82,7 @@ struct ImBuf;
struct PreviewImage;
struct ID;
struct StudioLight;
+struct bGPDlayer;
enum eIconSizes;
@@ -87,6 +91,9 @@ void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
int BKE_icon_id_ensure(struct ID *id);
+/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index c2ac5e98f76..67e6a32edfd 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -54,7 +54,6 @@ void BKE_lattice_free(struct Lattice *lt);
void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
-struct LatticeDeformData;
struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT;
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index c85017a2216..1ca8928c61d 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
+struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name);
void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *BKE_material_localize(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
+void BKE_material_init_gpencil_settings(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
@@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
+struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
+
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 79e4f1d448a..7d795c25a04 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -37,8 +37,11 @@ extern "C" {
struct Base;
struct Depsgraph;
+struct GpencilModifierData;
struct Scene;
+struct ShaderFxData;
struct ViewLayer;
+struct ID;
struct Object;
struct BoundBox;
struct View3D;
@@ -49,6 +52,7 @@ struct Mesh;
struct RigidBodyWorld;
struct HookModifierData;
struct ModifierData;
+struct HookGpencilModifierData;
#include "DNA_object_enums.h"
@@ -69,11 +73,16 @@ void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
+void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd);
+bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md);
+
+bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob, const int flag);
+void BKE_object_free_shaderfx(struct Object *ob, const int flag);
void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
@@ -108,6 +117,9 @@ struct Object *BKE_object_add_from(
struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
int type, const char *name, struct Object *ob_src)
ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add_for_data(
+ struct Main *bmain, struct ViewLayer *view_layer,
+ int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(
struct Main *bmain,
int type, const char *name)
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 6ade14b275c..c440a634c9f 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -77,7 +77,8 @@ typedef enum ePaintMode {
ePaintTextureProjective = 3,
ePaintTexture2D = 4,
ePaintSculptUV = 5,
- ePaintInvalid = 6
+ ePaintInvalid = 6,
+ ePaintGpencil = 7
} ePaintMode;
/* overlay invalidation */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index adccfda8e25..e2032e10833 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -130,6 +130,8 @@ int BKE_scene_camera_switch_update(struct Scene *scene);
char *BKE_scene_find_marker_name(struct Scene *scene, int frame);
char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame);
+int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int cfra);
+
/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 51f61c8352c..00fd4ded8c6 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -395,7 +395,7 @@ typedef struct SeqLoadInfo {
/* seq_dupli' flags */
-#define SEQ_DUPE_UNIQUE_NAME (1 << 0)
+#define SEQ_DUPE_UNIQUE_NAME (1 << 0) /* WARNING: does NOT work when duplicating Meta strips! */
#define SEQ_DUPE_CONTEXT (1 << 1)
#define SEQ_DUPE_ANIM (1 << 2)
#define SEQ_DUPE_ALL (1 << 3) /* otherwise only selected are copied */
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
new file mode 100644
index 00000000000..11c5983106a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -0,0 +1,180 @@
+/*
+ * ***** 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: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_SHADER_FX_H__
+#define __BKE_SHADER_FX_H__
+
+/** \file BKE_shader_fx.h
+ * \ingroup bke
+ */
+
+#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct ShaderFxData;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
+ ((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
+#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None type */
+ eShaderFxType_NoneType,
+
+ /* grease pencil effects */
+ eShaderFxType_GpencilType,
+} ShaderFxTypeType;
+
+typedef enum {
+ eShaderFxTypeFlag_SupportsEditmode = (1 << 0),
+
+ /* For effects that support editmode this determines if the
+ * effect should be enabled by default in editmode.
+ */
+ eShaderFxTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* max one per type */
+ eShaderFxTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eShaderFxTypeFlag_NoUserAdd = (1 << 5),
+} ShaderFxTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname);
+
+typedef struct ShaderFxTypeInfo {
+ /* The user visible name for this effect */
+ char name[32];
+
+ /* The DNA struct name for the effect data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the effect data type, used by allocation. */
+ int struct_size;
+
+ ShaderFxTypeType type;
+ ShaderFxTypeFlag flags;
+
+ /* Copy instance data for this effect type. Should copy all user
+ * level settings to the target effect.
+ */
+ void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target);
+
+ /* Initialize new instance data for this effect type, this function
+ * should set effect variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct ShaderFxData *fx);
+
+ /* Free internal effect data variables, this function should
+ * not free the fx variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct ShaderFxData *fx);
+
+ /* Return a boolean value indicating if this effect is able to be
+ * calculated based on the effect data. This is *not* regarding the
+ * fx->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct ShaderFxData *fx,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the effect needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct ShaderFxData *fx);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the effect data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the effect data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxIDWalkFunc walk, void *userData);
+} ShaderFxTypeInfo;
+
+/* Initialize global data (type info and some common global storages). */
+void BKE_shaderfx_init(void);
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_new(int type);
+void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
+void BKE_shaderfx_free(struct ShaderFxData *fx);
+bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
+bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
+struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
+void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
+void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
+void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag);
+void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+
+bool BKE_shaderfx_has_gpencil(struct Object *ob);
+
+#endif /* __BKE_SHADER_FX_H__ */
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index fee01fa8abb..4a7f29d7190 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -99,7 +99,7 @@ enum StudioLightFlag {
STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 10),
STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
STUDIOLIGHT_UI_EXPANDED = (1 << 13),
-} StudioLightFlag;
+};
#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
#define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_VIEWNORMAL)
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index a1792866255..ad829946db8 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -57,6 +57,7 @@ typedef struct SubdivSettings {
typedef enum eSubdivStatsValue {
SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0,
SUBDIV_STATS_SUBDIV_TO_MESH,
+ SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY,
SUBDIV_STATS_EVALUATOR_CREATE,
SUBDIV_STATS_EVALUATOR_REFINE,
@@ -73,6 +74,8 @@ typedef struct SubdivStats {
double topology_refiner_creation_time;
/* Total time spent in BKE_subdiv_to_mesh(). */
double subdiv_to_mesh_time;
+ /* Geometry (MVert and co) creation time during SUBDIV_TYO_MESH. */
+ double subdiv_to_mesh_geometry_time;
/* Time spent on evaluator creation from topology refiner. */
double evaluator_creation_time;
/* Time spent on evaluator->refine(). */
@@ -94,26 +97,6 @@ typedef struct Subdiv {
*/
SubdivSettings settings;
- /* Total number of ptex faces on subdivision level 0.
- *
- * Ptex face is what is internally used by OpenSubdiv for evaluator. It is
- * a quad face, which corresponds to Blender's legacy Catmull Clark grids.
- *
- * Basically, here is a correspondence between polygons and ptex faces:
- * - Triangle consists of 3 PTex faces.
- * - Quad is a single PTex face.
- * - N-gon is N PTex faces.
- *
- * This value is initialized in BKE_subdiv_new_from_FOO() and is read-only
- * after this.
- */
- int num_ptex_faces;
-
- /* Indexed by base face index, element indicates total number of ptex faces
- * created for preceding base faces.
- */
- int *face_ptex_offset;
-
/* Topology refiner includes all the glue logic to feed Blender side
* topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
* drawer.
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 01910bffdb0..7169597f100 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -38,6 +38,8 @@ set(INC
../makesrna
../bmesh
../modifiers
+ ../gpencil_modifiers
+ ../shader_fx
../nodes
../physics
../render/extern/include
@@ -115,6 +117,7 @@ set(SRC
intern/font.c
intern/freestyle.c
intern/gpencil.c
+ intern/gpencil_modifier.c
intern/icons.c
intern/icons_rasterize.c
intern/idcode.c
@@ -180,6 +183,7 @@ set(SRC
intern/seqeffects.c
intern/seqmodifier.c
intern/sequencer.c
+ intern/shader_fx.c
intern/shrinkwrap.c
intern/smoke.c
intern/softbody.c
@@ -259,6 +263,7 @@ set(SRC
BKE_freestyle.h
BKE_global.h
BKE_gpencil.h
+ BKE_gpencil_modifier.h
BKE_icons.h
BKE_idcode.h
BKE_idprop.h
@@ -306,6 +311,7 @@ set(SRC
BKE_scene.h
BKE_screen.h
BKE_sequencer.h
+ BKE_shader_fx.h
BKE_shrinkwrap.h
BKE_smoke.h
BKE_softbody.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 9c4aae7cda5..05253f7962a 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2098,6 +2098,7 @@ static void mesh_calc_modifiers(
/* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */
BLI_assert(!build_shapekey_layers);
+ UNUSED_VARS_NDEBUG(build_shapekey_layers);
//if (build_shapekey_layers)
// add_shapekey_layers(*r_deform_mesh, me, ob);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index cbdabe2c440..6f97187f1e3 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1328,6 +1328,37 @@ void BKE_pose_rest(bPose *pose)
}
}
+void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom)
+{
+ copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
+ copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
+
+ /* used for local constraints */
+ copy_v3_v3(pchanto->loc, pchanfrom->loc);
+ copy_qt_qt(pchanto->quat, pchanfrom->quat);
+ copy_v3_v3(pchanto->eul, pchanfrom->eul);
+ copy_v3_v3(pchanto->size, pchanfrom->size);
+
+ copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
+ copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->ease1 = pchanfrom->ease1;
+ pchanto->ease2 = pchanfrom->ease2;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
+ pchanto->rotmode = pchanfrom->rotmode;
+ pchanto->flag = pchanfrom->flag;
+ pchanto->protectflag = pchanfrom->protectflag;
+ pchanto->bboneflag = pchanfrom->bboneflag;
+}
+
/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
@@ -1346,34 +1377,8 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) {
pchanto = BKE_pose_channel_find_name(to, pchanfrom->name);
- if (pchanto) {
- copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
- copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
-
- /* used for local constraints */
- copy_v3_v3(pchanto->loc, pchanfrom->loc);
- copy_qt_qt(pchanto->quat, pchanfrom->quat);
- copy_v3_v3(pchanto->eul, pchanfrom->eul);
- copy_v3_v3(pchanto->size, pchanfrom->size);
-
- copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
- copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
-
- pchanto->roll1 = pchanfrom->roll1;
- pchanto->roll2 = pchanfrom->roll2;
- pchanto->curveInX = pchanfrom->curveInX;
- pchanto->curveInY = pchanfrom->curveInY;
- pchanto->curveOutX = pchanfrom->curveOutX;
- pchanto->curveOutY = pchanfrom->curveOutY;
- pchanto->ease1 = pchanfrom->ease1;
- pchanto->ease2 = pchanfrom->ease2;
- pchanto->scaleIn = pchanfrom->scaleIn;
- pchanto->scaleOut = pchanfrom->scaleOut;
-
- pchanto->rotmode = pchanfrom->rotmode;
- pchanto->flag = pchanfrom->flag;
- pchanto->protectflag = pchanfrom->protectflag;
- pchanto->bboneflag = pchanfrom->bboneflag;
+ if (pchanto != NULL) {
+ BKE_pose_copyesult_pchan_result(pchanto, pchanfrom);
}
}
return true;
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index eed8943cd5b..7df889d22b2 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -99,6 +99,8 @@ void animviz_settings_init(bAnimVizSettings *avs)
avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
avs->path_step = 1;
+
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
}
/* ------------------- */
@@ -535,18 +537,18 @@ void calc_curvepath(Object *ob, ListBase *nurbs)
return;
}
- if (ob->curve_cache->path) free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
+ if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
/* weak! can only use first curve */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (bl == NULL || !bl->nr) {
return;
}
nu = nurbs->first;
- ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
+ ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
/* if POLY: last vertice != first vertice */
cycl = (bl->poly != -1);
@@ -663,15 +665,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua
if (ob == NULL || ob->type != OB_CURVE) return 0;
cu = ob->data;
- if (ob->curve_cache == NULL || ob->curve_cache->path == NULL || ob->curve_cache->path->data == NULL) {
+ if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) {
printf("no path!\n");
return 0;
}
- path = ob->curve_cache->path;
+ path = ob->runtime.curve_cache->path;
pp = path->data;
/* test for cyclic */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (!bl) return 0;
if (!bl->nr) return 0;
if (bl->poly > -1) cycl = 1;
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index fd7497f9ba1..b02b6b6ce15 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -1150,6 +1150,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* grease pencil */
ANIMDATA_IDS_CB(bmain->gpencil.first);
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
+
/* cache files */
ANIMDATA_IDS_CB(bmain->cachefiles.first);
}
@@ -2925,6 +2928,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
+ /* palettes */
+ EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
+
/* cache files */
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 6be4574a62e..cea81a82f4b 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1960,7 +1960,7 @@ void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
*
* \param bmain May be NULL, only used to tag depsgraph as being dirty...
*/
-void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm)
+void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
Bone *bone;
bPose *pose;
@@ -1989,7 +1989,7 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm)
for (pchan = pose->chanbase.first; pchan; pchan = next) {
next = pchan->next;
if (pchan->bone == NULL) {
- BKE_pose_channel_free(pchan);
+ BKE_pose_channel_free_ex(pchan, do_id_user);
BKE_pose_channels_hash_free(pose);
BLI_freelinkN(&pose->chanbase, pchan);
}
@@ -2291,7 +2291,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
return;
if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) {
/* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */
- BKE_pose_rebuild(NULL, ob, arm);
+ BKE_pose_rebuild(NULL, ob, arm, true);
}
ctime = BKE_scene_frame_get(scene); /* not accurate... */
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 628f92c7803..d53c61255fe 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -201,7 +201,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
/* get the current length of the curve */
/* NOTE: this is assumed to be correct even after the curve was resized */
- splineLen = ikData->tar->curve_cache->path->totdist;
+ splineLen = ikData->tar->runtime.curve_cache->path->totdist;
/* calculate the scale factor to multiply all the path values by so that the
* bone chain retains its current length, such that
@@ -558,6 +558,17 @@ void BKE_splineik_execute_tree(
/* *************** Depsgraph evaluation callbacks ************ */
+static void pose_pchan_index_create(bPose *pose)
+{
+ const int num_channels = BLI_listbase_count(&pose->chanbase);
+ pose->chan_array = MEM_malloc_arrayN(
+ num_channels, sizeof(bPoseChannel *), "pose->chan_array");
+ int pchan_index = 0;
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pose->chan_array[pchan_index++] = pchan;
+ }
+}
+
BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index)
{
bPose *pose = ob->pose;
@@ -585,16 +596,12 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph,
/* imat is needed for solvers. */
invert_m4_m4(ob->imat, ob->obmat);
- const int num_channels = BLI_listbase_count(&pose->chanbase);
- pose->chan_array = MEM_malloc_arrayN(
- num_channels, sizeof(bPoseChannel *), "pose->chan_array");
-
/* clear flags */
- int pchan_index = 0;
for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
- pose->chan_array[pchan_index++] = pchan;
}
+
+ pose_pchan_index_create(pose);
}
void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph,
@@ -688,7 +695,8 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph,
invert_m4_m4(imat, pchan->bone->arm_mat);
mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
}
- if (DEG_is_active(depsgraph)) {
+ bArmature *arm = (bArmature *)ob->data;
+ if (DEG_is_active(depsgraph) && arm->edbo == NULL) {
bPoseChannel *pchan_orig = pchan->orig_pchan;
copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
@@ -751,12 +759,44 @@ void BKE_pose_eval_flush(struct Depsgraph *depsgraph,
pose->chan_array = NULL;
}
-void BKE_pose_eval_proxy_copy(struct Depsgraph *depsgraph, Object *ob)
+void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph, Object *object)
{
- BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
- if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
- printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
- ob->id.name + 2, ob->proxy_from->id.name + 2);
- }
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ pose_pchan_index_create(object->pose);
+}
+
+void BKE_pose_eval_proxy_pose_done(struct Depsgraph *depsgraph, Object *object)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ bPose *pose = object->pose;
+ BLI_assert(pose->chan_array != NULL);
+ MEM_freeN(pose->chan_array);
+ pose->chan_array = NULL;
+}
+
+void BKE_pose_eval_proxy_copy_bone(
+ struct Depsgraph *depsgraph,
+ Object *object,
+ int pchan_index)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept
+ * around for the time while proxies are evaluating.
+ */
+#if 0
+ bPoseChannel *pchan_from = pose_pchan_get_indexed(
+ object->proxy_from, pchan_index);
+#else
+ bPoseChannel *pchan_from = BKE_pose_channel_find_name(
+ object->proxy_from->pose, pchan->name);
+#endif
+ BLI_assert(pchan != NULL);
+ BLI_assert(pchan_from != NULL);
+ BKE_pose_copyesult_pchan_result(pchan, pchan_from);
}
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index 3ec46e23cd1..2c18de70e6d 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -89,6 +89,7 @@ bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
size = sizeof(bUserMenuItem_Prop);
}
else {
+ size = sizeof(bUserMenuItem);
BLI_assert(0);
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 42cd7968321..c769978f9bb 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -29,6 +29,7 @@
#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -36,6 +37,7 @@
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush)
brush->stencil_dimension[0] = 256;
brush->stencil_dimension[1] = 256;
+
}
/* Datablock add/copy/free/make_local */
@@ -164,6 +167,368 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
+/* add a new gp-brush */
+Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name)
+{
+ Brush *brush;
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT);
+
+ BKE_paint_brush_set(paint, brush);
+ id_us_min(&brush->id);
+
+ /* grease pencil basic settings */
+ brush->size = 3;
+
+ brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
+
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->flag = 0;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+
+ /* curves */
+ brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ /* return brush */
+ return brush;
+}
+
+Paint *BKE_brush_get_gpencil_paint(ToolSettings *ts)
+{
+ /* alloc paint session */
+ if (ts->gp_paint == NULL) {
+ ts->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint");
+ }
+
+ return &ts->gp_paint->paint;
+}
+
+/* grease pencil cumapping->preset */
+typedef enum eGPCurveMappingPreset {
+ GPCURVE_PRESET_PENCIL = 0,
+ GPCURVE_PRESET_INK = 1,
+ GPCURVE_PRESET_INKNOISE = 2,
+} eGPCurveMappingPreset;
+
+static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset)
+{
+ if (cuma->curve)
+ MEM_freeN(cuma->curve);
+
+ cuma->totpoint = 3;
+ cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
+
+ switch (preset) {
+ case GPCURVE_PRESET_PENCIL:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.75115f;
+ cuma->curve[1].y = 0.25f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INK:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63448f;
+ cuma->curve[1].y = 0.375f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INKNOISE:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63134f;
+ cuma->curve[1].y = 0.3625f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ }
+
+ if (cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table = NULL;
+ }
+}
+
+/* create a set of grease pencil presets */
+void BKE_brush_gpencil_presets(bContext *C)
+{
+#define SMOOTH_STROKE_RADIUS 40
+#define SMOOTH_STROKE_FACTOR 0.9f
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = BKE_brush_get_gpencil_paint(ts);
+ Main *bmain = CTX_data_main(C);
+
+ Brush *brush, *deft;
+ CurveMapping *custom_curve;
+
+ /* Pencil brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pen brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
+ deft = brush; /* save default brush */
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Ink brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.6f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK);
+
+ /* Ink Noise brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.7f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 2;
+ brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothlvl = 2;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE);
+
+ /* Block Basic brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.7f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Marker brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.374f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = M_PI_4; /* 45 degrees */
+ brush->gpencil_settings->draw_angle_factor = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Fill brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ brush->size = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->fill_leak = 3;
+ brush->gpencil_settings->fill_threshold = 0.1f;
+ brush->gpencil_settings->fill_simplylvl = 1;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_FILL;
+
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ /* Soft Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+
+ /* Hard Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
+ /* Stroke Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
+ /* set defaut brush */
+ BKE_paint_brush_set(paint, deft);
+
+}
+
+/* get the active gp-brush for editing */
+Brush *BKE_brush_getactive_gpencil(ToolSettings *ts)
+{
+ /* error checking */
+ if (ELEM(NULL, ts, ts->gp_paint)) {
+ return NULL;
+ }
+ Paint *paint = &ts->gp_paint->paint;
+
+ return paint->brush;
+}
+
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
Brush *brush;
@@ -197,6 +562,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru
}
brush_dst->curve = curvemapping_copy(brush_src->curve);
+ if (brush_src->gpencil_settings != NULL) {
+ brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
+ brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity);
+ brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength);
+ brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter);
+ }
/* enable fake user by default */
id_fake_user_set(&brush_dst->id);
@@ -215,11 +586,18 @@ void BKE_brush_free(Brush *brush)
if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
}
-
curvemapping_free(brush->curve);
+ if (brush->gpencil_settings != NULL) {
+ curvemapping_free(brush->gpencil_settings->curve_sensitivity);
+ curvemapping_free(brush->gpencil_settings->curve_strength);
+ curvemapping_free(brush->gpencil_settings->curve_jitter);
+ MEM_SAFE_FREE(brush->gpencil_settings);
+ }
+
MEM_SAFE_FREE(brush->gradient);
+
BKE_previewimg_free(&(brush->preview));
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 1a7c4e2a4a0..19ac81b4bb7 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -495,12 +495,39 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
{
- return bvhtree_from_editmesh_verts_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(
+ *bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -649,12 +676,39 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
{
- return bvhtree_from_editmesh_edges_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(
+ *bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -1407,6 +1461,11 @@ BVHTree *BKE_bvhtree_from_mesh_get(
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
+ case BVHTREE_FROM_EM_VERTS:
+ case BVHTREE_FROM_EM_EDGES:
+ case BVHTREE_FROM_EM_LOOPTRI:
+ BLI_assert(false);
+ break;
}
if (data_cp.tree != NULL) {
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 4203e0455f8..1b5995de4f0 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -70,12 +70,15 @@ void BKE_camera_init(Camera *cam)
cam->sensor_x = DEFAULT_SENSOR_WIDTH;
cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
cam->clipsta = 0.1f;
- cam->clipend = 100.0f;
+ cam->clipend = 1000.0f;
cam->drawsize = 0.5f;
cam->ortho_scale = 6.0;
cam->flag |= CAM_SHOWPASSEPARTOUT;
cam->passepartalpha = 0.5f;
+ cam->gpu_dof.fstop = 128.0f;
+ cam->gpu_dof.ratio = 1.0f;
+
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 72a1f941c26..3f50321b4d5 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -655,8 +655,8 @@ DerivedMesh *CDDM_from_curve(Object *ob)
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return CDDM_from_curve_displist(ob, &disp);
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 0c93f304218..04e09d06405 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -57,7 +57,7 @@
/******************************** Prototypes ********************************/
-static bool collection_child_add(Collection *parent, Collection *collection, int flag, const bool add_us);
+static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us);
static bool collection_child_remove(Collection *parent, Collection *collection);
static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us);
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index ff4795afe87..d18572a57f6 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
case CURVE_PRESET_MID9: cuma->totpoint = 9; break;
case CURVE_PRESET_ROUND: cuma->totpoint = 4; break;
case CURVE_PRESET_ROOT: cuma->totpoint = 4; break;
+ case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break;
}
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
@@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[3].x = 1;
cuma->curve[3].y = 0;
break;
+ case CURVE_PRESET_GAUSS:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 0.025f;
+ cuma->curve[1].x = 0.16f;
+ cuma->curve[1].y = 0.135f;
+ cuma->curve[2].x = 0.298f;
+ cuma->curve[2].y = 0.36f;
+
+ cuma->curve[3].x = 0.50f;
+ cuma->curve[3].y = 1.0f;
+
+ cuma->curve[4].x = 0.70f;
+ cuma->curve[4].y = 0.36f;
+ cuma->curve[5].x = 0.84f;
+ cuma->curve[5].y = 0.135f;
+ cuma->curve[6].x = 1.0f;
+ cuma->curve[6].y = 0.025f;
+ break;
}
/* mirror curve in x direction to have positive slope
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 5aa192d527a..ef412f0006e 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -496,7 +496,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
{
Lattice *lt = (Lattice *)ob->data;
- DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
BPoint *bp = lt->def;
@@ -1266,7 +1266,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
- if (ct->tar->curve_cache && ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
+ if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) {
float quat[4];
if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
/* animated position along curve depending on time */
@@ -2037,7 +2037,7 @@ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
#endif
if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->type == OB_CURVE && ct->tar->curve_cache == NULL) {
+ if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) {
unit_m4(ct->matrix);
return;
}
@@ -3104,7 +3104,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
BKE_object_minmax(ct->tar, curveMin, curveMax, true);
/* get targetmatrix */
- if (data->tar->curve_cache && data->tar->curve_cache->path && data->tar->curve_cache->path->data) {
+ if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) {
float vec[4], dir[3], totmat[4][4];
float curvetime;
short clamp_axis;
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 3dfe9732062..84ca143dc55 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -1014,6 +1014,10 @@ int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectM
else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT;
+ else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT;
+ else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT;
+ else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT;
}
}
@@ -1044,6 +1048,10 @@ static const char *data_mode_strings[] = {
"imagepaint",
"particlemode",
"objectmode",
+ "greasepencil_paint",
+ "greasepencil_edit",
+ "greasepencil_sculpt",
+ "greasepencil_weight",
NULL
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
@@ -1212,17 +1220,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_layer");
}
-bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palette");
-}
-
-bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
-}
-
-bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
+Brush *CTX_data_active_gpencil_brush(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_brush");
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 33a24f77937..39b28540205 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -1752,11 +1752,11 @@ void BKE_curve_bevel_make(
BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
dl = bevdisp.first;
}
- else if (cu->bevobj->curve_cache) {
- dl = cu->bevobj->curve_cache->disp.first;
+ else if (cu->bevobj->runtime.curve_cache) {
+ dl = cu->bevobj->runtime.curve_cache->disp.first;
}
else {
- BLI_assert(cu->bevobj->curve_cache != NULL);
+ BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
dl = NULL;
}
@@ -2669,14 +2669,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
- bev = &ob->curve_cache->bev;
+ bev = &ob->runtime.curve_cache->bev;
/* do we need to calculate the radius for each point? */
/* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
/* STEP 1: MAKE POLYS */
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
nu = nurbs->first;
if (cu->editnurb && ob->type != OB_FONT) {
is_editmode = 1;
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index d08e3643ca7..ddf9840a32e 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -74,7 +74,9 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
- BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ if (ob->type != OB_GPENCIL) {
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ }
return defgroup;
}
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 34fd32b2908..562e2257ea0 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -692,10 +692,10 @@ static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *tap
if (taperobj == NULL || taperobj->type != OB_CURVE)
return 1.0;
- dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL;
+ dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL;
if (dl == NULL) {
BKE_displist_make_curveTypes(depsgraph, scene, taperobj, 0);
- dl = taperobj->curve_cache->disp.first;
+ dl = taperobj->runtime.curve_cache->disp.first;
}
if (dl) {
float minx, dx, *fp;
@@ -738,17 +738,17 @@ void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
return;
if (ob == BKE_mball_basis_find(scene, ob)) {
- if (ob->curve_cache) {
- BKE_displist_free(&(ob->curve_cache->disp));
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
}
- BKE_mball_polygonize(depsgraph, scene, ob, &ob->curve_cache->disp);
+ BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
BKE_mball_texspace_calc(ob);
- object_deform_mball(ob, &ob->curve_cache->disp);
+ object_deform_mball(ob, &ob->runtime.curve_cache->disp);
/* NOP for MBALLs anyway... */
boundbox_displist_object(ob);
@@ -1314,7 +1314,7 @@ void BKE_displist_make_surf(
}
if (!for_orco) {
- BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final,
for_render, use_render_resolution);
}
@@ -1558,15 +1558,15 @@ static void do_makeDispListCurveTypes(
ListBase dlbev;
ListBase nubase = {NULL, NULL};
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
/* We only re-evaluate path if evaluation is not happening for orco.
* If the calculation happens for orco, we should never free data which
* was needed before and only not needed for orco calculation.
*/
if (!for_orco) {
- if (ob->curve_cache->path) free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
+ if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
}
if (ob->type == OB_FONT) {
@@ -1590,7 +1590,7 @@ static void do_makeDispListCurveTypes(
}
else {
float widfac = cu->width - 1.0f;
- BevList *bl = ob->curve_cache->bev.first;
+ BevList *bl = ob->runtime.curve_cache->bev.first;
Nurb *nu = nubase.first;
for (; bl && nu; bl = bl->next, nu = nu->next) {
@@ -1777,7 +1777,7 @@ static void do_makeDispListCurveTypes(
}
if (!for_orco) {
- BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
}
@@ -1801,11 +1801,11 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, Scene *scene, Object *ob
BKE_object_free_derived_caches(ob);
- if (!ob->curve_cache) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ if (!ob->runtime.curve_cache) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
}
- dispbase = &(ob->curve_cache->disp);
+ dispbase = &(ob->runtime.curve_cache->disp);
do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
@@ -1817,8 +1817,8 @@ void BKE_displist_make_curveTypes_forRender(
DerivedMesh **r_dm_final, const bool for_orco,
const bool use_render_resolution)
{
- if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
@@ -1827,8 +1827,8 @@ void BKE_displist_make_curveTypes_forRender(
void BKE_displist_make_curveTypes_forOrco(
Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1);
@@ -1903,7 +1903,7 @@ static void boundbox_displist_object(Object *ob)
float min[3], max[3];
INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->curve_cache->disp, min, max);
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
BKE_boundbox_init_from_minmax(ob->bb, min, max);
ob->bb->flag &= ~BOUNDBOX_DIRTY;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index b6eb26443ea..52ea4bf4a5e 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -163,10 +163,10 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef
if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) {
Curve *cu= eff->ob->data;
if (cu->flag & CU_PATH) {
- if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL)
+ if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path==NULL || eff->ob->runtime.curve_cache->path->data==NULL)
BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, 0);
- if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) {
+ if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) {
where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
mul_m4_v3(eff->ob->obmat, eff->guide_loc);
mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 36633663f9d..b5fba6d30e8 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -1075,8 +1075,8 @@ makebreak:
/* TEXT ON CURVE */
/* Note: Only OB_CURVE objects could have a path */
if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
- BLI_assert(cu->textoncurve->curve_cache != NULL);
- if (cu->textoncurve->curve_cache->path) {
+ BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
+ if (cu->textoncurve->runtime.curve_cache->path) {
float distfac, imat[4][4], imat3[3][3], cmat[3][3];
float minx, maxx, miny, maxy;
float timeofs, sizefac;
@@ -1106,7 +1106,7 @@ makebreak:
/* we put the x-coordinaat exact at the curve, the y is rotated */
/* length correction */
- distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx);
+ distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx);
timeofs = 0.0f;
if (distfac > 1.0f) {
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index e89508fd6c0..18817f20d1c 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,26 +39,83 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
#include "BLI_string_utils.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_userdef_types.h"
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "BKE_context.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_colortools.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+#include "DEG_depsgraph.h"
/* ************************************************** */
-/* GENERAL STUFF */
+/* Draw Engine */
-/* --------- Memory Management ------------ */
+void(*BKE_gpencil_batch_cache_dirty_cb)(bGPdata *gpd) = NULL;
+void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL;
+
+void BKE_gpencil_batch_cache_dirty(bGPdata *gpd)
+{
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ BKE_gpencil_batch_cache_dirty_cb(gpd);
+ }
+}
+
+void BKE_gpencil_batch_cache_free(bGPdata *gpd)
+{
+ if (gpd) {
+ BKE_gpencil_batch_cache_free_cb(gpd);
+ }
+}
+
+/* ************************************************** */
+/* Memory Management */
+
+/* clean vertex groups weights */
+void BKE_gpencil_free_point_weights(MDeformVert *dvert)
+{
+ if (dvert == NULL) {
+ return;
+ }
+ MEM_SAFE_FREE(dvert->dw);
+}
+
+void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+
+ if (gps->dvert == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+}
/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
@@ -66,10 +123,14 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
if (gps == NULL) {
return;
}
-
/* free stroke memory arrays, then stroke itself */
- if (gps->points)
+ if (gps->points) {
MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
if (gps->triangles)
MEM_freeN(gps->triangles);
@@ -92,6 +153,26 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf)
return changed;
}
+/* Free strokes and colors belonging to a gp-frame */
+bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf)
+{
+ bGPDstroke *gps_next;
+ if (!derived_gpf) {
+ return false;
+ }
+
+ /* free strokes */
+ for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
+ }
+ BLI_listbase_clear(&derived_gpf->strokes);
+
+ MEM_SAFE_FREE(derived_gpf);
+
+ return true;
+}
+
/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
@@ -111,101 +192,101 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl)
gpl->actframe = NULL;
}
-/* Free all of a gp-colors */
-static void free_gpencil_colors(bGPDpalette *palette)
-{
- /* error checking */
- if (palette == NULL) {
- return;
- }
- /* free colors */
- BLI_freelistN(&palette->colors);
-}
-/* Free all of the gp-palettes and colors */
-void BKE_gpencil_free_palettes(ListBase *list)
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
+void BKE_gpencil_free_layers(ListBase *list)
{
- bGPDpalette *palette_next;
+ bGPDlayer *gpl_next;
/* error checking */
- if (list == NULL) {
- return;
- }
+ if (list == NULL) return;
- /* delete palettes */
- for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
- palette_next = palette->next;
- /* free palette colors */
- free_gpencil_colors(palette);
+ /* delete layers */
+ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+ gpl_next = gpl->next;
- MEM_freeN(palette);
+ /* free layers and their data */
+ BKE_gpencil_free_frames(gpl);
+ BLI_freelinkN(list, gpl);
}
- BLI_listbase_clear(list);
}
-/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */
-void BKE_gpencil_free_brushes(ListBase *list)
+/* clear all runtime derived data */
+static void BKE_gpencil_clear_derived(bGPDlayer *gpl)
{
- bGPDbrush *brush_next;
+ GHashIterator gh_iter;
- /* error checking */
- if (list == NULL) {
+ if (gpl->runtime.derived_data == NULL) {
return;
}
- /* delete brushes */
- for (bGPDbrush *brush = list->first; brush; brush = brush_next) {
- brush_next = brush->next;
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
+ GHASH_ITER(gh_iter, gpl->runtime.derived_data) {
+ bGPDframe *gpf = (bGPDframe *)BLI_ghashIterator_getValue(&gh_iter);
+ if (gpf) {
+ BKE_gpencil_free_frame_runtime_data(gpf);
}
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
- }
-
- MEM_freeN(brush);
}
- BLI_listbase_clear(list);
}
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
-void BKE_gpencil_free_layers(ListBase *list)
+/* Free all of the gp-layers temp data*/
+static void BKE_gpencil_free_layers_temp_data(ListBase *list)
{
bGPDlayer *gpl_next;
/* error checking */
if (list == NULL) return;
-
/* delete layers */
for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
gpl_next = gpl->next;
+ BKE_gpencil_clear_derived(gpl);
- /* free layers and their data */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(list, gpl);
+ if (gpl->runtime.derived_data) {
+ BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
+ gpl->runtime.derived_data = NULL;
+ }
+ }
+}
+
+/* Free temp gpf derived frames */
+void BKE_gpencil_free_derived_frames(bGPdata *gpd)
+{
+ /* error checking */
+ if (gpd == NULL) return;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ BKE_gpencil_clear_derived(gpl);
+
+ if (gpl->runtime.derived_data) {
+ BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
+ gpl->runtime.derived_data = NULL;
+ }
}
}
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
-void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
+void BKE_gpencil_free(bGPdata *gpd, bool free_all)
{
+ /* clear animation data */
BKE_animdata_free(&gpd->id, false);
/* free layers */
+ if (free_all) {
+ BKE_gpencil_free_layers_temp_data(&gpd->layers);
+ }
BKE_gpencil_free_layers(&gpd->layers);
- /* free palettes */
- if (free_palettes) {
- BKE_gpencil_free_palettes(&gpd->palettes);
+ /* materials */
+ MEM_SAFE_FREE(gpd->mat);
+
+ /* free all data */
+ if (free_all) {
+ /* clear cache */
+ BKE_gpencil_batch_cache_free(gpd);
}
}
-/* -------- Container Creation ---------- */
+/* ************************************************** */
+/* Container Creation */
/* add a new gp-frame to the given layer */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
@@ -329,28 +410,31 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
/* add to datablock */
BLI_addtail(&gpd->layers, gpl);
- /* set basic settings */
- copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- /* Since GPv2 thickness must be 0 */
- gpl->thickness = 0;
-
- gpl->opacity = 1.0f;
+ /* annotation vs GP Object behaviour is slightly different */
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ /* set default color of new strokes for this layer */
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
+ gpl->opacity = 1.0f;
- /* onion-skinning settings */
- if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
- gpl->flag |= GP_LAYER_ONIONSKIN;
+ /* set default thickness of new strokes for this layer */
+ gpl->thickness = 3;
- gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
-
- ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
- ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
-
- /* high quality fill by default */
- gpl->flag |= GP_LAYER_HQ_FILL;
+ }
+ else {
+ /* thickness parameter represents "thickness change", not absolute thickness */
+ gpl->thickness = 0;
+ gpl->opacity = 1.0f;
+ /* onion-skinning settings */
+ gpl->onion_flag |= GP_LAYER_ONIONSKIN;
+ }
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
- BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+ BLI_uniquename(&gpd->layers, gpl,
+ (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl->info));
/* make this one the active one */
if (setactive)
@@ -360,292 +444,153 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
return gpl;
}
-/* add a new gp-palette and make it the active */
-bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive)
-{
- bGPDpalette *palette;
-
- /* check that list is ok */
- if (gpd == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
-
- /* add to datablock */
- BLI_addtail(&gpd->palettes, palette);
-
- /* set basic settings */
- /* auto-name */
- BLI_strncpy(palette->info, name, sizeof(palette->info));
- BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
- sizeof(palette->info));
-
- /* make this one the active one */
- /* NOTE: Always make this active if there's nothing else yet (T50123) */
- if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
- BKE_gpencil_palette_setactive(gpd, palette);
- }
-
- /* return palette */
- return palette;
-}
-
-/* create a set of default drawing brushes with predefined presets */
-void BKE_gpencil_brush_init_presets(ToolSettings *ts)
+/* add a new gp-datablock */
+bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
- bGPDbrush *brush;
- /* Basic brush */
- brush = BKE_gpencil_brush_addnew(ts, "Basic", true);
- brush->thickness = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 0;
- brush->draw_random_sub = 0.0f;
-
- /* Pencil brush */
- brush = BKE_gpencil_brush_addnew(ts, "Pencil", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.7f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
-
- /* Ink brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.6f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ bGPdata *gpd;
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ /* allocate memory for a new block */
+ gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
- /* Ink Noise brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false);
- brush->thickness = 6.0f;
- brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.611f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
+ /* initial settings */
+ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* general flags */
+ gpd->flag |= GP_DATA_VIEWALIGN;
- brush->draw_random_press = 1.0f;
+ /* GP object specific settings */
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ gpd->xray_mode = GP_XRAY_3DSPACE;
+ gpd->runtime.batch_cache_data = NULL;
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ /* onion-skinning settings (datablock level) */
+ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ gpd->onion_flag |= GP_ONION_FADE;
+ gpd->onion_mode = GP_ONION_MODE_RELATIVE;
+ gpd->onion_factor = 0.5f;
+ ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
+ ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ gpd->gstep = 1;
+ gpd->gstep_next = 1;
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ return gpd;
+}
- /* Marker brush */
- brush = BKE_gpencil_brush_addnew(ts, "Marker", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 2.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+/* ************************************************** */
+/* Primitive Creation */
+/* Utilities for easier bulk-creation of geometry */
- brush->draw_random_press = 0.0f;
+/**
+ * Populate stroke with point data from data buffers
+ *
+ * \param array Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values
+ * \param mat 4x4 transform matrix to transform points into the right coordinate space
+ */
+void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4])
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ const int x = GP_PRIM_DATABUF_SIZE * i;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ pt->x = array[x];
+ pt->y = array[x + 1];
+ pt->z = array[x + 2];
+ mul_m4_v3(mat, &pt->x);
- brush->draw_angle = M_PI_4; /* 45 degrees */
- brush->draw_angle_factor = 1.0f;
+ pt->pressure = array[x + 3];
+ pt->strength = array[x + 4];
+ }
+}
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+/* Create a new stroke, with pre-allocated data buffers */
+bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness)
+{
+ /* allocate memory for a new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- /* Crayon brush */
- brush = BKE_gpencil_brush_addnew(ts, "Crayon", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+ gps->thickness = thickness * 25;
+ gps->inittime = 0;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.140f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* enable recalculation flag by default */
+ gps->flag = GP_STROKE_RECALC_CACHES | GP_STROKE_3DSPACE;
- brush->draw_random_press = 0.0f;
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ gps->mat_nr = mat_idx;
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.5f;
+ /* add to frame */
+ BLI_addtail(&gpf->strokes, gps);
+ return gps;
}
-/* add a new gp-brush and make it the active */
-bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive)
-{
- bGPDbrush *brush;
-
- /* check that list is ok */
- if (ts == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush");
- /* add to datablock */
- BLI_addtail(&ts->gp_brushes, brush);
-
- /* set basic settings */
- brush->thickness = 3;
- brush->draw_smoothlvl = 1;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- /* curves */
- brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
-
- /* auto-name */
- BLI_strncpy(brush->info, name, sizeof(brush->info));
- BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
-
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_brush_setactive(ts, brush);
- }
-
- /* return brush */
- return brush;
-}
+/* ************************************************** */
+/* Data Duplication */
-/* add a new gp-palettecolor and make it the active */
-bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+/* make a copy of a given gpencil weights */
+void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
{
- bGPDpalettecolor *palcolor;
-
- /* check that list is ok */
- if (palette == NULL) {
- return NULL;
+ if (gps_src == NULL) {
+ return;
}
+ BLI_assert(gps_src->totpoints == gps_dst->totpoints);
- /* allocate memory and add to end of list */
- palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
-
- /* add to datablock */
- BLI_addtail(&palette->colors, palcolor);
-
- /* set basic settings */
- palcolor->flag |= PC_COLOR_HQ_FILL;
- copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
- ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
+ if ((gps_src->dvert == NULL) || (gps_dst->dvert == NULL)) {
+ return;
+ }
- /* auto-name */
- BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
- BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
- sizeof(palcolor->info));
+ for (int i = 0; i < gps_src->totpoints; i++) {
+ MDeformVert *dvert_src = &gps_src->dvert[i];
+ MDeformVert *dvert_dst = &gps_dst->dvert[i];
+ if (dvert_src->totweight > 0) {
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ }
+ else {
+ dvert_dst->dw = NULL;
+ }
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_palettecolor_setactive(palette, palcolor);
}
-
- /* return palette color */
- return palcolor;
}
-/* add a new gp-datablock */
-bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
+/* make a copy of a given gpencil stroke */
+bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src)
{
- bGPdata *gpd;
+ bGPDstroke *gps_dst = NULL;
- /* allocate memory for a new block */
- gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->prev = gps_dst->next = NULL;
- /* initial settings */
- gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
- /* for now, stick to view is also enabled by default
- * since this is more useful...
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+
+ /* Don't clear triangles, so that modifier evaluation can just use
+ * this without extra work first. Most places that need to force
+ * this data to get recalculated will destroy the data anyway though.
*/
- gpd->flag |= GP_DATA_VIEWALIGN;
+ gps_dst->triangles = MEM_dupallocN(gps_dst->triangles);
+ /* gps_dst->flag |= GP_STROKE_RECALC_CACHES; */
- return gpd;
+ /* return new stroke */
+ return gps_dst;
}
-/* -------- Data Duplication ---------- */
-
/* make a copy of a given gpencil frame */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps_dst;
+ bGPDstroke *gps_dst = NULL;
bGPDframe *gpf_dst;
/* error checking */
@@ -660,11 +605,8 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->points = MEM_dupallocN(gps_src->points);
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
@@ -672,55 +614,24 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
return gpf_dst;
}
-/* make a copy of a given gpencil brush */
-bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src)
+/* make a copy of strokes between gpencil frames */
+void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
- bGPDbrush *brush_dst;
-
+ bGPDstroke *gps_dst = NULL;
/* error checking */
- if (brush_src == NULL) {
- return NULL;
- }
-
- /* make a copy of source brush */
- brush_dst = MEM_dupallocN(brush_src);
- brush_dst->prev = brush_dst->next = NULL;
- /* make a copy of curves */
- brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity);
- brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength);
- brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter);
-
- /* return new brush */
- return brush_dst;
-}
-
-/* make a copy of a given gpencil palette */
-bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src)
-{
- bGPDpalette *palette_dst;
- const bGPDpalettecolor *palcolor_src;
- bGPDpalettecolor *palcolord_dst;
-
- /* error checking */
- if (palette_src == NULL) {
- return NULL;
+ if ((gpf_src == NULL) || (gpf_dst == NULL)) {
+ return;
}
- /* make a copy of source palette */
- palette_dst = MEM_dupallocN(palette_src);
- palette_dst->prev = palette_dst->next = NULL;
-
- /* copy colors */
- BLI_listbase_clear(&palette_dst->colors);
- for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) {
- /* make a copy of source */
- palcolord_dst = MEM_dupallocN(palcolor_src);
- BLI_addtail(&palette_dst->colors, palcolord_dst);
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
}
-
- /* return new palette */
- return palette_dst;
}
+
/* make a copy of a given gpencil layer */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
@@ -736,6 +647,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/* make a copy of source layer */
gpl_dst = MEM_dupallocN(gpl_src);
gpl_dst->prev = gpl_dst->next = NULL;
+ gpl_dst->runtime.derived_data = NULL;
/* copy frames */
BLI_listbase_clear(&gpl_dst->frames);
@@ -755,7 +667,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/**
* Only copy internal data of GreasePencil ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ * You probably never want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
*
* WARNING! This function will not handle ID user count!
*
@@ -763,6 +675,14 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
*/
void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
+ /* cache data is not duplicated */
+ gpd_dst->runtime.batch_cache_data = NULL;
+
+ /* duplicate material array */
+ if (gpd_src->mat) {
+ gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
+ }
+
/* copy layers */
BLI_listbase_clear(&gpd_dst->layers);
for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
@@ -771,45 +691,46 @@ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata
BLI_addtail(&gpd_dst->layers, gpl_dst);
}
- /* copy palettes */
- BLI_listbase_clear(&gpd_dst->palettes);
- for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
- bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */
- BLI_addtail(&gpd_dst->palettes, palette_dst);
- }
+}
+
+/* Standard API to make a copy of GP datablock, separate from copying its data */
+bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
+{
+ bGPdata *gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd->id, (ID **)&gpd_copy, 0, false);
+ return gpd_copy;
}
/* make a copy of a given gpencil datablock */
+// XXX: Should this be deprecated?
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
+ bGPdata *gpd_dst;
+
/* Yuck and super-uber-hyper yuck!!!
* Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
* so for now keep old code for that one. */
- if (internal_copy) {
- const bGPDlayer *gpl_src;
- bGPDlayer *gpl_dst;
- bGPdata *gpd_dst;
+ /* error checking */
+ if (gpd_src == NULL) {
+ return NULL;
+ }
+
+ if (internal_copy) {
/* make a straight copy for undo buffers used during stroke drawing */
gpd_dst = MEM_dupallocN(gpd_src);
-
- /* copy layers */
- BLI_listbase_clear(&gpd_dst->layers);
- for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- /* make a copy of source layer and its data */
- gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- }
-
- /* return new */
- return gpd_dst;
}
else {
BLI_assert(bmain != NULL);
- bGPdata *gpd_copy;
- BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false);
- return gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false);
+ gpd_dst->runtime.batch_cache_data = NULL;
}
+
+ /* Copy internal data (layers, etc.) */
+ BKE_gpencil_copy_data(bmain, gpd_dst, gpd_src, 0);
+
+ /* return new */
+ return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -817,7 +738,8 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
}
-/* -------- GP-Stroke API --------- */
+/* ************************************************** */
+/* GP Stroke API */
/* ensure selection status of stroke is in sync with its points */
void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
@@ -842,7 +764,8 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
}
}
-/* -------- GP-Frame API ---------- */
+/* ************************************************** */
+/* GP Frame API */
/* delete the last stroke of the given frame */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
@@ -855,7 +778,13 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
return;
/* free the stroke and its data */
- MEM_freeN(gps->points);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
@@ -866,7 +795,8 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
}
}
-/* -------- GP-Layer API ---------- */
+/* ************************************************** */
+/* GP Layer API */
/* Check if the given layer is able to be edited or not */
bool gpencil_layer_is_editable(const bGPDlayer *gpl)
@@ -1048,8 +978,6 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
*/
if (gpl->actframe == gpf)
gpl->actframe = gpf->prev;
- else
- gpl->actframe = NULL;
/* free the frame and its data */
changed = BKE_gpencil_free_strokes(gpf);
@@ -1103,255 +1031,602 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
/* free layer */
BKE_gpencil_free_frames(gpl);
+
+ /* free icon providing preview of icon color */
+ BKE_icon_delete(gpl->runtime.icon_id);
+
+ /* free derived data */
+ BKE_gpencil_clear_derived(gpl);
+ if (gpl->runtime.derived_data) {
+ BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL);
+ gpl->runtime.derived_data = NULL;
+ }
+
BLI_freelinkN(&gpd->layers, gpl);
}
-/* ************************************************** */
-/* get the active gp-brush for editing */
-bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts)
+Material *BKE_gpencil_get_material_from_brush(Brush *brush)
{
- bGPDbrush *brush;
+ Material *ma = NULL;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first)) {
- return NULL;
+ if ((brush != NULL) && (brush->gpencil_settings != NULL) &&
+ (brush->gpencil_settings->material != NULL))
+ {
+ ma = brush->gpencil_settings->material;
}
- /* loop over brushes until found (assume only one active) */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush->flag & GP_BRUSH_ACTIVE) {
- return brush;
+ return ma;
+}
+
+/* Get active color, and add all default settings if we don't find anything */
+Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob)
+{
+ Material *ma = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, bmain, ob))
+ return NULL;
+
+ ma = give_current_material(ob, ob->actcol);
+ if (ma == NULL) {
+ if (ob->totcol == 0) {
+ BKE_object_material_slot_add(bmain, ob);
}
+ ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING);
+ }
+ else if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
}
- /* no active brush found */
- return NULL;
+ return ma;
}
-/* set the active gp-brush */
-void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+/* ************************************************** */
+/* GP Object - Boundbox Support */
+
+/**
+ * Get min/max coordinate bounds for single stroke
+ * \return Returns whether we found any selected points
+ */
+bool BKE_gpencil_stroke_minmax(
+ const bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3])
{
- bGPDbrush *brush;
+ const bGPDspoint *pt;
+ int i;
+ bool changed = false;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
- return;
- }
+ if (ELEM(NULL, gps, r_min, r_max))
+ return false;
- /* loop over brushes deactivating all */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- brush->flag &= ~GP_BRUSH_ACTIVE;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
+ minmax_v3v3_v3(r_min, r_max, &pt->x);
+ changed = true;
+ }
}
-
- /* set as active one */
- active->flag |= GP_BRUSH_ACTIVE;
+ return changed;
}
-/* delete the active gp-brush */
-void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+/* get min/max bounds of all strokes in GP datablock */
+static void gpencil_minmax(bGPdata *gpd, float r_min[3], float r_max[3])
{
- /* error checking */
- if (ELEM(NULL, ts, brush)) {
+ INIT_MINMAX(r_min, r_max);
+
+ if (gpd == NULL)
return;
- }
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
+
+ if (gpf != NULL) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
+ }
+ }
}
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
+}
+
+/* compute center of bounding box */
+void BKE_gpencil_centroid_3D(bGPdata *gpd, float r_centroid[3])
+{
+ float min[3], max[3], tot[3];
+
+ gpencil_minmax(gpd, min, max);
+
+ add_v3_v3v3(tot, min, max);
+ mul_v3_v3fl(r_centroid, tot, 0.5f);
+}
+
+
+/* create bounding box values */
+static void boundbox_gpencil(Object *ob)
+{
+ BoundBox *bb;
+ bGPdata *gpd;
+ float min[3], max[3];
+
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
}
- /* free */
- BLI_freelinkN(&ts->gp_brushes, brush);
+ bb = ob->bb;
+ gpd = ob->data;
+
+ gpencil_minmax(gpd, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
-/* ************************************************** */
-/* get the active gp-palette for editing */
-bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd)
+/* get bounding box */
+BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
- bGPDpalette *palette;
+ bGPdata *gpd;
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first)) {
+ if (ELEM(NULL, ob, ob->data))
return NULL;
- }
- /* loop over palettes until found (assume only one active) */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- if (palette->flag & PL_PALETTE_ACTIVE)
- return palette;
+ gpd = ob->data;
+ if ((ob->bb) && ((ob->bb->flag & BOUNDBOX_DIRTY) == 0) &&
+ ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0))
+ {
+ return ob->bb;
}
- /* no active palette found */
- return NULL;
+ boundbox_gpencil(ob);
+
+ return ob->bb;
}
-/* set the active gp-palette */
-void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
-{
- bGPDpalette *palette;
+/* ************************************************** */
+/* Apply Transforms */
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
+void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
+{
+ if (gpd == NULL)
return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* FIXME: For now, we just skip parented layers.
+ * Otherwise, we have to update each frame to find
+ * the current parent position/effects.
+ */
+ if (gpl->parent) {
+ continue;
+ }
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
+ mul_m4_v3(mat, &pt->x);
+ }
+
+ /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+ }
}
- /* loop over palettes deactivating all */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- palette->flag &= ~PL_PALETTE_ACTIVE;
+}
+
+/* ************************************************** */
+/* GP Object - Vertex Groups */
+
+/* remove a vertex group */
+void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
+{
+ bGPdata *gpd = ob->data;
+ MDeformVert *dvert = NULL;
+ MDeformWeight *gpw = NULL;
+ const int def_nr = BLI_findindex(&ob->defbase, defgroup);
+
+ /* Remove points data */
+ if (gpd) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ for (int i2 = 0; i2 < dvert->totweight; i2++) {
+ gpw = &dvert->dw[i2];
+ if (gpw->def_nr == def_nr) {
+ BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr);
+ }
+ /* if index is greater, must be moved one back */
+ if (gpw->def_nr > def_nr) {
+ gpw->def_nr--;
+ }
+ }
+ }
+ }
+ }
+ }
}
- /* set as active one */
- active->flag |= PL_PALETTE_ACTIVE;
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
+ /* Remove the group */
+ BLI_freelinkN(&ob->defbase, defgroup);
}
-/* delete the active gp-palette */
-void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+/* add a new weight */
+MDeformWeight *BKE_gpencil_vgroup_add_point_weight(MDeformVert *dvert, int index, float weight)
{
- /* error checking */
- if (ELEM(NULL, gpd, palette)) {
- return;
+ MDeformWeight *new_gpw = NULL;
+ MDeformWeight *tmp_gpw;
+
+ /* need to verify if was used before to update */
+ for (int i = 0; i < dvert->totweight; i++) {
+ tmp_gpw = &dvert->dw[i];
+ if (tmp_gpw->def_nr == index) {
+ tmp_gpw->weight = weight;
+ return tmp_gpw;
+ }
+ }
+
+ dvert->totweight++;
+ if (dvert->totweight == 1) {
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight), "gp_weight");
+ }
+ else {
+ dvert->dw = MEM_reallocN(dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
}
+ new_gpw = &dvert->dw[dvert->totweight - 1];
+ new_gpw->def_nr = index;
+ new_gpw->weight = weight;
- /* free colors */
- free_gpencil_colors(palette);
- BLI_freelinkN(&gpd->palettes, palette);
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
+ return new_gpw;
}
-/* Set all strokes to recalc the palette color */
-void BKE_gpencil_palette_change_strokes(bGPdata *gpd)
+/* return the weight if use index or -1*/
+float BKE_gpencil_vgroup_use_index(MDeformVert *dvert, int index)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+ MDeformWeight *gpw;
+ for (int i = 0; i < dvert->totweight; i++) {
+ gpw = &dvert->dw[i];
+ if (gpw->def_nr == index) {
+ return gpw->weight;
+ }
+ }
+ return -1.0f;
+}
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- gps->flag |= GP_STROKE_RECALC_COLOR;
- }
+/* add a new weight */
+bool BKE_gpencil_vgroup_remove_point_weight(MDeformVert *dvert, int index)
+{
+ int e = 0;
+
+ if (BKE_gpencil_vgroup_use_index(dvert, index) < 0.0f) {
+ return false;
+ }
+
+ /* if the array get empty, exit */
+ if (dvert->totweight == 1) {
+ dvert->totweight = 0;
+ MEM_SAFE_FREE(dvert->dw);
+ return true;
+ }
+
+ /* realloc weights */
+ MDeformWeight *tmp = MEM_dupallocN(dvert->dw);
+ MEM_SAFE_FREE(dvert->dw);
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight - 1, "gp_weights");
+
+ for (int x = 0; x < dvert->totweight; x++) {
+ MDeformWeight *gpw = &tmp[e];
+ MDeformWeight *final_gpw = &dvert->dw[e];
+ if (gpw->def_nr != index) {
+ final_gpw->def_nr = gpw->def_nr;
+ final_gpw->weight = gpw->weight;
+ e++;
}
}
+ MEM_SAFE_FREE(tmp);
+ dvert->totweight--;
+
+ return true;
}
-/* get the active gp-palettecolor for editing */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette)
+/* ************************************************** */
+
+/**
+ * Apply smooth to stroke point
+ * \param gps Stroke to smooth
+ * \param i Point index
+ * \param inf Amount of smoothing to apply
+ */
+bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
{
- bGPDpalettecolor *palcolor;
+ bGPDspoint *pt = &gps->points[i];
+ // float pressure = 0.0f;
+ float sco[3] = { 0.0f };
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first)) {
- return NULL;
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
}
- /* loop over colors until found (assume only one active) */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- if (palcolor->flag & PC_COLOR_ACTIVE) {
- return palcolor;
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
+
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
+
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+
}
}
- /* no active color found */
- return NULL;
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+
+ return true;
}
-/* get the gp-palettecolor looking for name */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+
+/**
+ * Apply smooth for strength to stroke point */
+bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence)
{
- /* error checking */
- if (ELEM(NULL, palette, name)) {
- return NULL;
+ bGPDspoint *ptb = &gps->points[point_index];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
}
- return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the strength
+ * at the distance of point b
+ */
+ const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
+
+ return true;
}
-/* Change color name in all strokes */
-void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+/**
+ * Apply smooth for thickness to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, oldname, newname))
- return;
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (STREQ(gps->colorname, oldname)) {
- BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname));
- }
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ float optimal = interpf(ptc->pressure, pta->pressure, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = interpf(optimal, ptb->pressure, influence);
+
+ return true;
+}
+
+/**
+* Apply smooth for UV rotation to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence)
+{
+ bGPDspoint *ptb = &gps->points[point_index];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Compute theoretical optimal value */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
+ CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
+
+ return true;
+}
+
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl Layer
+ * \param r_initframe Number of first selected frame
+ * \param r_endframe Number of last selected frame
+ */
+void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
+{
+ *r_initframe = gpl->actframe->framenum;
+ *r_endframe = gpl->actframe->framenum;
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (gpf->framenum < *r_initframe) {
+ *r_initframe = gpf->framenum;
+ }
+ if (gpf->framenum > *r_endframe) {
+ *r_endframe = gpf->framenum;
}
}
}
+}
+
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf Frame
+ * \param actnum Number of active frame in layer
+ * \param f_init Number of first selected frame
+ * \param f_end Number of last selected frame
+ * \param cur_falloff Curve with falloff factors
+ */
+float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
+{
+ float fnum = 0.5f; /* default mid curve */
+ float value;
+
+ /* frames to the right of the active frame */
+ if (gpf->framenum < actnum) {
+ fnum = (float)(gpf->framenum - f_init) / (actnum - f_init);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum);
+ }
+ /* frames to the left of the active frame */
+ else if (gpf->framenum > actnum) {
+ fnum = (float)(gpf->framenum - actnum) / (f_end - actnum);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
+ }
+ else {
+ value = 1.0f;
+ }
+ return value;
}
-/* Delete all strokes of the color */
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+/* remove strokes using a material */
+void BKE_gpencil_material_index_remove(bGPdata *gpd, int index)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
bGPDstroke *gps, *gpsn;
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, name))
- return;
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- if (STREQ(gps->colorname, name)) {
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->mat_nr == index) {
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+ else {
+ /* reassign strokes */
+ if (gps->mat_nr > index) {
+ gps->mat_nr--;
+ }
+ }
}
}
}
- }
-
}
-/* set the active gp-palettecolor */
-void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len)
{
- bGPDpalettecolor *palcolor;
-
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first, active)) {
- return;
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* reassign strokes */
+ MAT_NR_REMAP(gps->mat_nr);
+ }
+ }
}
- /* loop over colors deactivating all */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_ACTIVE;
- }
+#undef MAT_NR_REMAP
- /* set as active one */
- active->flag |= PC_COLOR_ACTIVE;
}
-/* delete the active gp-palettecolor */
-void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+/* statistics functions */
+void BKE_gpencil_stats_update(bGPdata *gpd)
{
- /* error checking */
- if (ELEM(NULL, palette, palcolor)) {
- return;
+ gpd->totlayer = 0;
+ gpd->totframe = 0;
+ gpd->totstroke = 0;
+ gpd->totpoint = 0;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpd->totlayer++;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gpd->totframe++;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ gpd->totstroke++;
+ gpd->totpoint += gps->totpoints;
+ }
+ }
}
- /* free */
- BLI_freelinkN(&palette->colors, palcolor);
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
new file mode 100644
index 00000000000..3c2196afb18
--- /dev/null
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -0,0 +1,677 @@
+/*
+ * ***** 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/gpencil_modifier.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_lattice.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+
+static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Geometry Utilities */
+
+/* calculate stroke normal using some points */
+void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
+{
+ if (gps->totpoints < 3) {
+ zero_v3(r_normal);
+ return;
+ }
+
+ bGPDspoint *points = gps->points;
+ int totpoints = gps->totpoints;
+
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float vec1[3];
+ float vec2[3];
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(r_normal, vec1, vec2);
+
+ /* Normalize vector */
+ normalize_v3(r_normal);
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
+{
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ vec2f *point = &points2d[i];
+ point->x = dot_v3v3(loc, locx);
+ point->y = dot_v3v3(loc, locy);
+ }
+
+}
+
+/* Stroke Simplify ------------------------------------- */
+
+/* Reduce a series of points to a simplified version, but
+ * maintains the general shape of the series
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ */
+static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
+{
+ vec2f *old_points2d = points2d;
+ int totpoints = gps->totpoints;
+ char *marked = NULL;
+ char work;
+
+ int start = 1;
+ int end = gps->totpoints - 2;
+
+ marked = MEM_callocN(totpoints, "GP marked array");
+ marked[start] = 1;
+ marked[end] = 1;
+
+ work = 1;
+ int totmarked = 0;
+ /* while still reducing */
+ while (work) {
+ int ls, le;
+ work = 0;
+
+ ls = start;
+ le = start + 1;
+
+ /* while not over interval */
+ while (ls < end) {
+ int max_i = 0;
+ float v1[2];
+ /* divided to get more control */
+ float max_dist = epsilon / 10.0f;
+
+ /* find the next marked point */
+ while (marked[le] == 0) {
+ le++;
+ }
+
+ /* perpendicular vector to ls-le */
+ v1[1] = old_points2d[le].x - old_points2d[ls].x;
+ v1[0] = old_points2d[ls].y - old_points2d[le].y;
+
+ for (int i = ls + 1; i < le; i++) {
+ float mul;
+ float dist;
+ float v2[2];
+
+ v2[0] = old_points2d[i].x - old_points2d[ls].x;
+ v2[1] = old_points2d[i].y - old_points2d[ls].y;
+
+ if (v2[0] == 0 && v2[1] == 0) {
+ continue;
+ }
+
+ mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
+
+ dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
+
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_i = i;
+ }
+ }
+
+ if (max_i != 0) {
+ work = 1;
+ marked[max_i] = 1;
+ totmarked++;
+ }
+
+ ls = le;
+ le = ls + 1;
+ }
+ }
+
+ /* adding points marked */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = MEM_dupallocN(gps->dvert);
+
+ /* resize gps */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ MDeformVert *dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+
+ if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ j++;
+ }
+ else {
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+ MEM_SAFE_FREE(marked);
+}
+
+/* Simplify stroke using Ramer-Douglas-Peucker algorithm */
+void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
+{
+ /* first create temp data and convert points to 2D */
+ vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
+
+ gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
+
+ gpencil_rdp_stroke(gps, points2d, factor);
+
+ MEM_SAFE_FREE(points2d);
+}
+
+/* Simplify alternate vertex of stroke except extrems */
+void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
+{
+ if (gps->totpoints < 5) {
+ return;
+ }
+
+ /* save points */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = MEM_dupallocN(gps->dvert);
+
+ /* resize gps */
+ int newtot = (gps->totpoints - 2) / 2;
+ if (((gps->totpoints - 2) % 2) > 0) {
+ newtot++;
+ }
+ newtot += 2;
+
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ MDeformVert *dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+
+ if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ j++;
+ }
+ else {
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+}
+
+/* *************************************************** */
+/* Modifier Utilities */
+
+/* Lattice Modifier ---------------------------------- */
+/* Usually, evaluation of the lattice modifier is self-contained.
+ * However, since GP's modifiers operate on a per-stroke basis,
+ * we need to these two extra functions that called before/after
+ * each loop over all the geometry being evaluated.
+ */
+
+/* init lattice deform data */
+void BKE_gpencil_lattice_init(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ }
+
+ /* init deform data */
+ mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
+ }
+ }
+}
+
+/* clear lattice deform data */
+void BKE_gpencil_lattice_clear(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ }
+ }
+}
+
+/* *************************************************** */
+/* Modifier Methods - Evaluation Loops, etc. */
+
+/* check if exist geometry modifiers */
+bool BKE_gpencil_has_geometry_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->generateStrokes) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* apply stroke modifiers */
+void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti && mti->deformStroke) {
+ mti->deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+/* apply stroke geometry modifiers */
+void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti->generateStrokes) {
+ mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+ }
+}
+
+/* *************************************************** */
+
+void BKE_gpencil_eval_geometry(Depsgraph *depsgraph,
+ bGPdata *gpd)
+{
+ DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
+ int ctime = (int)DEG_get_ctime(depsgraph);
+
+ /* update active frame */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+
+ /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
+ * This would be better than inventing our own logic for this stuff...
+ */
+
+ /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
+ * later when there's more happening here. For now, let's just keep this in here to avoid
+ * needing to have one more node slowing down evaluation...
+ */
+ if (DEG_is_active(depsgraph)) {
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+
+ /* sync "actframe" changes back to main-db too,
+ * so that editing tools work with copy-on-write
+ * when the current frame changes
+ */
+ for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_init(void)
+{
+ /* Initialize modifier types */
+ gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
+}
+
+GpencilModifierData *BKE_gpencil_modifier_new(int type)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
+
+ md->type = type;
+ md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
+ md->flag = eGpencilModifierFlag_StaticOverride_Local;
+
+ if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
+ md->mode |= eGpencilModifierMode_Editmode;
+
+ if (mti->initData) mti->initData(md);
+
+ return md;
+}
+
+static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (mti->freeData) mti->freeData(md);
+ if (md->error) MEM_freeN(md->error);
+
+ MEM_freeN(md);
+}
+
+void BKE_gpencil_modifier_free(GpencilModifierData *md)
+{
+ BKE_gpencil_modifier_free_ex(md, 0);
+}
+
+/* check unique name */
+bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
+{
+ if (modifiers && gmd) {
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
+ }
+ return false;
+}
+
+bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ return mti->dependsOnTime && mti->dependsOnTime(md);
+}
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
+ return modifier_gpencil_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+
+ /* md_dst may have alredy be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (mti->freeData) {
+ mti->freeData(md_dst);
+ }
+
+ const size_t data_size = sizeof(GpencilModifierData);
+ const char *md_src_data = ((const char *)md_src) + data_size;
+ char *md_dst_data = ((char *)md_dst) + data_size;
+ BLI_assert(data_size <= (size_t)mti->struct_size);
+ memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
+}
+
+static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ target->mode = md->mode;
+ target->flag = md->flag;
+
+ if (mti->copyData) {
+ mti->copyData(md, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_ex(md, target, 0);
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next)
+ if (md->type == type)
+ break;
+
+ return md;
+}
+
+void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
+ else if (mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
+}
+
+void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachTexLink)
+ mti->foreachTexLink(md, ob, walk, userData);
+ }
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
+}
+
+/* helper function for per-instance positioning */
+void BKE_gpencil_instance_modifier_instance_tfm(InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4])
+{
+ float offset[3], rot[3], scale[3];
+ int ri = mmd->rnd[0];
+ float factor;
+
+ offset[0] = mmd->offset[0] * elem_idx[0];
+ offset[1] = mmd->offset[1] * elem_idx[1];
+ offset[2] = mmd->offset[2] * elem_idx[2];
+
+ /* rotation */
+ if (mmd->flag & GP_INSTANCE_RANDOM_ROT) {
+ factor = mmd->rnd_rot * mmd->rnd[ri];
+ mul_v3_v3fl(rot, mmd->rot, factor);
+ add_v3_v3(rot, mmd->rot);
+ }
+ else {
+ copy_v3_v3(rot, mmd->rot);
+ }
+
+ /* scale */
+ if (mmd->flag & GP_INSTANCE_RANDOM_SIZE) {
+ factor = mmd->rnd_size * mmd->rnd[ri];
+ mul_v3_v3fl(scale, mmd->scale, factor);
+ add_v3_v3(scale, mmd->scale);
+ }
+ else {
+ copy_v3_v3(scale, mmd->scale);
+ }
+
+ /* advance random index */
+ mmd->rnd[0]++;
+ if (mmd->rnd[0] > 19) {
+ mmd->rnd[0] = 1;
+ }
+
+ /* calculate matrix */
+ loc_eul_size_to_mat4(r_mat, offset, rot, scale);
+}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 1c2575dfa52..3a4bf53e22d 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -37,6 +37,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -45,7 +47,6 @@
#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "DNA_brush_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -127,6 +128,9 @@ static void icon_free_data(int icon_id, Icon *icon)
else if (icon->obj_type == ICON_DATA_PREVIEW) {
((PreviewImage *)(icon->obj))->icon_id = 0;
}
+ else if (icon->obj_type == ICON_DATA_GPLAYER) {
+ ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
+ }
else if (icon->obj_type == ICON_DATA_GEOM) {
((struct Icon_Geom *)(icon->obj))->icon_id = 0;
}
@@ -598,6 +602,44 @@ int BKE_icon_id_ensure(struct ID *id)
return icon_id_ensure_create_icon(id);
}
+
+static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ /* NOTE: The color previews for GP Layers don't really need
+ * to be "rendered" to image per se (as it will just be a plain
+ * colored rectangle), we need to define icon data here so that
+ * we can store a pointer to the layer data in icon->obj.
+ */
+ Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
+ icon->flag = ICON_FLAG_MANAGED;
+
+ return gpl->runtime.icon_id;
+}
+
+int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
+{
+ /* Never handle icons in non-main thread! */
+ BLI_assert(BLI_thread_is_main());
+
+ if (!gpl || G.background) {
+ return 0;
+ }
+
+ if (gpl->runtime.icon_id)
+ return gpl->runtime.icon_id;
+
+ gpl->runtime.icon_id = get_next_free_id();
+
+ if (!gpl->runtime.icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ return icon_gplayer_color_ensure_create_icon(gpl);
+}
+
/**
* Return icon id of given preview, or create new icon if not found.
*/
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 13f7716cd80..0d8e281fa06 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -1457,7 +1457,7 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
kb = MEM_callocN(sizeof(KeyBlock), "Keyblock");
BLI_addtail(&key->block, kb);
- kb->type = KEY_CARDINAL;
+ kb->type = KEY_LINEAR;
tot = BLI_listbase_count(&key->block);
if (name) {
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 78ff43c2981..04830eb1081 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -211,9 +211,9 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
/* works best if we force to linear type (endpoints match) */
lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
- if (ltOb->curve_cache) {
+ if (ltOb->runtime.curve_cache) {
/* prevent using deformed locations */
- BKE_displist_free(&ltOb->curve_cache->disp);
+ BKE_displist_free(&ltOb->runtime.curve_cache->disp);
}
copy_m4_m4(mat, ltOb->obmat);
@@ -349,7 +349,7 @@ LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
/* we make an array with all differences */
Lattice *lt = oblatt->data;
BPoint *bp;
- DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
float *fp, imat[4][4];
float fu, fv, fw;
@@ -558,7 +558,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
int cycl = 0;
/* test for cyclic */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (!bl->nr) return false;
if (bl->poly > -1) cycl = 1;
@@ -573,7 +573,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
if (cycl == 0) {
- Path *path = ob->curve_cache->path;
+ Path *path = ob->runtime.curve_cache->path;
float dvec[3];
if (ctime < 0.0f) {
@@ -610,12 +610,12 @@ static bool calc_curve_deform(Object *par, float co[3],
short index;
const bool is_neg_axis = (axis > 2);
- if (par->curve_cache == NULL) {
+ if (par->runtime.curve_cache == NULL) {
/* Happens with a cyclic dependencies. */
return false;
}
- if (par->curve_cache->path == NULL) {
+ if (par->runtime.curve_cache->path == NULL) {
return false; /* happens on append, cyclic dependencies and empty curves */
}
@@ -625,7 +625,7 @@ static bool calc_curve_deform(Object *par, float co[3],
if (cu->flag & CU_STRETCH)
fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
else
- fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist);
+ fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
}
else {
index = axis;
@@ -633,8 +633,8 @@ static bool calc_curve_deform(Object *par, float co[3],
fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
}
else {
- if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) {
- fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist);
+ if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
+ fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
}
else {
fac = 0.0f;
@@ -1035,11 +1035,11 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
int numVerts, editmode = (lt->editlatt != NULL);
const ModifierEvalContext mectx = {depsgraph, ob, 0};
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
}
else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
}
for (; md; md = md->next) {
@@ -1071,7 +1071,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
dl->nr = numVerts;
dl->verts = (float *) vertexCos;
- BLI_addtail(&ob->curve_cache->disp, dl);
+ BLI_addtail(&ob->runtime.curve_cache->disp, dl);
}
}
@@ -1145,7 +1145,7 @@ BoundBox *BKE_lattice_boundbox_get(Object *ob)
void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3])
{
- DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
if (!dl) {
BKE_lattice_minmax(lt, min, max);
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 2f5c8e7817e..1396ad1f97c 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -715,6 +715,14 @@ static int layer_collection_sync(
lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS;
}
+ /* Holdout and indirect only */
+ if (lc->flag & LAYER_COLLECTION_HOLDOUT) {
+ base->flag |= BASE_HOLDOUT;
+ }
+ if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
+ base->flag |= BASE_INDIRECT_ONLY;
+ }
+
lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
}
@@ -750,7 +758,13 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
/* Clear visible and selectable flags to be reset. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- base->flag &= ~(BASE_VISIBLE | BASE_ENABLED | BASE_SELECTABLE | BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER);
+ base->flag &= ~(BASE_VISIBLE |
+ BASE_ENABLED |
+ BASE_SELECTABLE |
+ BASE_ENABLED_VIEWPORT |
+ BASE_ENABLED_RENDER |
+ BASE_HOLDOUT |
+ BASE_INDIRECT_ONLY);
}
view_layer->runtime_flag = 0;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 351214ed72b..8922cd75618 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -1073,6 +1073,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_IP] = &(main->ipo);
lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
lb[INDEX_ID_KE] = &(main->key);
+ lb[INDEX_ID_PAL] = &(main->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
lb[INDEX_ID_NT] = &(main->nodetree);
lb[INDEX_ID_IM] = &(main->image);
@@ -2464,7 +2465,7 @@ void BKE_library_make_local(
* Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) {
- BKE_pose_rebuild(bmain, ob, ob->data);
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
}
}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 93fdd3349bf..473dd787a69 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -417,7 +417,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
SEQ_END
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
@@ -478,6 +477,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
+ if (toolsett->gp_paint) {
+ library_foreach_paint(&data, &toolsett->gp_paint->paint);
+ }
}
if (scene->rigidbody_world) {
@@ -641,6 +643,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
}
+ if (material->gp_style != NULL) {
+ CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
+ CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
+ }
break;
}
@@ -758,6 +764,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -941,10 +950,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
+ /* materials */
+ for (i = 0; i < gpencil->totcol; i++) {
+ CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
+ }
- for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
- CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP);
+ for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) {
+ CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
}
+
break;
}
@@ -1072,7 +1086,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return true;
#endif
case ID_BR:
- return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
case ID_PA:
return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
case ID_MC:
@@ -1083,6 +1097,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return (ELEM(id_type_used, ID_TE, ID_OB));
case ID_LP:
return ELEM(id_type_used, ID_IM);
+ case ID_GD:
+ return ELEM(id_type_used, ID_MA);
case ID_WS:
return ELEM(id_type_used, ID_SCR, ID_SCE);
case ID_IM:
@@ -1091,7 +1107,6 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_SO:
case ID_AR:
case ID_AC:
- case ID_GD:
case ID_WM:
case ID_PAL:
case ID_PC:
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index ab8c8695495..03ec26c07d0 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -43,6 +43,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_ID.h"
#include "DNA_meta_types.h"
#include "DNA_node_types.h"
@@ -58,6 +59,7 @@
#include "BKE_animsys.h"
#include "BKE_displist.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -103,10 +105,30 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
+ MEM_SAFE_FREE(ma->gp_style);
+
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
+void BKE_material_init_gpencil_settings(Material *ma)
+{
+ if ((ma) && (ma->gp_style == NULL)) {
+ ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* set basic settings */
+ gp_style->stroke_rgba[3] = 1.0f;
+ gp_style->pattern_gridsize = 0.1f;
+ gp_style->gradient_radius = 0.5f;
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
+ gp_style->texture_opacity = 1.0f;
+ gp_style->texture_pixsize = 100.0f;
+ }
+}
+
void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
@@ -124,6 +146,7 @@ void BKE_material_init(Material *ma)
ma->preview = NULL;
ma->alpha_threshold = 0.5f;
+
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -137,6 +160,19 @@ Material *BKE_material_add(Main *bmain, const char *name)
return ma;
}
+Material *BKE_material_add_gpencil(Main *bmain, const char *name)
+{
+ Material *ma;
+
+ ma = BKE_material_add(bmain, name);
+
+ /* grease pencil settings */
+ BKE_material_init_gpencil_settings(ma);
+
+ return ma;
+}
+
+
/**
* Only copy internal data of Material ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -164,6 +200,10 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
}
+ if (ma_src->gp_style != NULL) {
+ ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
+ }
+
BLI_listbase_clear(&ma_dst->gpumaterial);
/* TODO Duplicate Engine Settings and set runtime to NULL */
@@ -199,6 +239,7 @@ Material *BKE_material_localize(Material *ma)
man->texpaintslot = NULL;
man->preview = NULL;
+ /* man->gp_style = NULL; */ /* XXX: We probably don't want to clear here, or else we may get problems with COW later? */
BLI_listbase_clear(&man->gpumaterial);
/* TODO Duplicate Engine Settings and set runtime to NULL */
@@ -218,6 +259,7 @@ Material ***give_matarar(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -231,6 +273,10 @@ Material ***give_matarar(Object *ob)
mb = ob->data;
return &(mb->mat);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->mat);
+ }
return NULL;
}
@@ -239,6 +285,7 @@ short *give_totcolp(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -252,6 +299,10 @@ short *give_totcolp(Object *ob)
mb = ob->data;
return &(mb->totcol);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->totcol);
+ }
return NULL;
}
@@ -286,6 +337,8 @@ short *give_totcolp_id(ID *id)
return &(((Curve *)id)->totcol);
case ID_MB:
return &(((MetaBall *)id)->totcol);
+ case ID_GD:
+ return &(((bGPdata *)id)->totcol);
default:
break;
}
@@ -307,6 +360,9 @@ static void material_data_index_remove_id(ID *id, short index)
case ID_MB:
/* meta-elems don't have materials atm */
break;
+ case ID_GD:
+ BKE_gpencil_material_index_remove((bGPdata *)id, index);
+ break;
default:
break;
}
@@ -487,6 +543,21 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
+MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
+{
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
+
+ return ma->gp_style;
+ }
+ else {
+ return NULL;
+ }
+}
+
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@@ -727,6 +798,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_material_remap(ob->data, remap, ob->totcol);
}
+ if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
+ }
else {
/* add support for this object data! */
BLI_assert(matar == NULL);
@@ -924,10 +998,10 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from mesh */
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
material_data_index_remove_id((ID *)ob->data, actcol - 1);
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
}
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 2ff69c5ee6d..43b7eba2810 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -207,7 +207,7 @@ void BKE_mball_texspace_calc(Object *ob)
(min)[0] = (min)[1] = (min)[2] = 1.0e30f;
(max)[0] = (max)[1] = (max)[2] = -1.0e30f;
- dl = ob->curve_cache->disp.first;
+ dl = ob->runtime.curve_cache->disp.first;
while (dl) {
tot = dl->nr;
if (tot) do_it = true;
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 738f116310b..2e2afa6834b 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -217,8 +217,8 @@ int BKE_mesh_nurbs_to_mdata(
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return BKE_mesh_nurbs_displist_to_mdata(
@@ -537,8 +537,8 @@ Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
@@ -650,8 +650,8 @@ void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
@@ -871,11 +871,11 @@ Mesh *BKE_mesh_new_from_object(
*
* TODO(sergey): Look into more proper solution.
*/
- if (ob->curve_cache != NULL) {
- if (tmpobj->curve_cache == NULL) {
- tmpobj->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ if (ob->runtime.curve_cache != NULL) {
+ if (tmpobj->runtime.curve_cache == NULL) {
+ tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
}
- BKE_displist_copy(&tmpobj->curve_cache->disp, &ob->curve_cache->disp);
+ BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp);
}
/* if getting the original caged mesh, delete object modifiers */
@@ -953,8 +953,8 @@ Mesh *BKE_mesh_new_from_object(
}
else {
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
BKE_mesh_from_metaball(&disp, tmpmesh);
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 33ea13c9a38..41c23c46c44 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -41,6 +41,7 @@
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -53,6 +54,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
@@ -86,6 +88,7 @@
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_icons.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
@@ -110,12 +113,14 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_speaker.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
#include "BKE_material.h"
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "BKE_gpencil.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -170,26 +175,30 @@ void BKE_object_free_softbody(Object *ob)
void BKE_object_free_curve_cache(Object *ob)
{
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
- if (ob->curve_cache->path) {
- free_path(ob->curve_cache->path);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path) {
+ free_path(ob->runtime.curve_cache->path);
}
- BKE_nurbList_free(&ob->curve_cache->deformed_nurbs);
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
+ BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
}
}
void BKE_object_free_modifiers(Object *ob, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
modifier_free_ex(md, flag);
}
+ while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
+ BKE_gpencil_modifier_free_ex(gp_md, flag);
+ }
/* particle modifiers were freed, so free the particlesystems as well */
BKE_object_free_particlesystems(ob);
@@ -200,6 +209,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
BKE_object_free_derived_caches(ob);
}
+void BKE_object_free_shaderfx(Object *ob, const int flag)
+{
+ ShaderFxData *fx;
+
+ while ((fx = BLI_pophead(&ob->shader_fx))) {
+ BKE_shaderfx_free_ex(fx, flag);
+ }
+}
+
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
{
/* reset functionality */
@@ -222,6 +240,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
}
}
+void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
+{
+ if (hmd->object == NULL) {
+ return;
+ }
+ /* reset functionality */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
+
+ if (hmd->subtarget[0] && pchan) {
+ float imat[4][4], mat[4][4];
+
+ /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
+ mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ }
+ else {
+ invert_m4_m4(hmd->object->imat, hmd->object->obmat);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ }
+}
+
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
@@ -428,6 +469,7 @@ void BKE_object_free(Object *ob)
/* BKE_<id>_free shall never touch to ID->us. Never ever. */
BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
MEM_SAFE_FREE(ob->mat);
MEM_SAFE_FREE(ob->matbits);
@@ -460,12 +502,12 @@ void BKE_object_free(Object *ob)
BLI_freelistN(&ob->lodlevels);
/* Free runtime curves data. */
- if (ob->curve_cache) {
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
- if (ob->curve_cache->path)
- free_path(ob->curve_cache->path);
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
+ if (ob->runtime.curve_cache) {
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path)
+ free_path(ob->runtime.curve_cache->path);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
}
BKE_previewimg_free(&ob->preview);
@@ -653,6 +695,7 @@ static const char *get_obdata_defname(int type)
case OB_ARMATURE: return DATA_("Armature");
case OB_SPEAKER: return DATA_("Speaker");
case OB_EMPTY: return DATA_("Empty");
+ case OB_GPENCIL: return DATA_("GPencil");
default:
printf("get_obdata_defname: Internal error, bad type: %d\n", type);
return DATA_("Empty");
@@ -677,6 +720,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
case OB_ARMATURE: return BKE_armature_add(bmain, name);
case OB_SPEAKER: return BKE_speaker_add(bmain, name);
case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
+ case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name);
case OB_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@@ -810,7 +854,7 @@ Object *BKE_object_add(
/**
* Add a new object, using another one as a reference
*
- * /param ob_src object to use to determine the collections of the new object.
+ * \param ob_src object to use to determine the collections of the new object.
*/
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer,
@@ -828,6 +872,41 @@ Object *BKE_object_add_from(
return ob;
}
+/**
+ * Add a new object, but assign the given datablock as the ob->data
+ * for the newly created object.
+ *
+ * \param data The datablock to assign as ob->data for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user If true, id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
+Object *BKE_object_add_for_data(
+ Main *bmain, ViewLayer *view_layer,
+ int type, const char *name, ID *data, bool do_id_user)
+{
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
+
+ /* same as object_add_common, except we don't create new ob->data */
+ ob = BKE_object_add_only_object(bmain, type, name);
+ ob->data = data;
+ if (do_id_user) id_us_plus(data);
+
+ BKE_view_layer_base_deselect_all(view_layer);
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
+
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select(view_layer, base);
+
+ return ob;
+}
+
+
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
SoftBody *sb = ob_src->soft;
@@ -1153,6 +1232,11 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gmd;
+ ShaderFxData *fx;
+
+ /* Do not copy runtime data. */
+ BKE_object_runtime_reset(ob_dst);
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
@@ -1176,11 +1260,31 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BLI_addtail(&ob_dst->modifiers, nmd);
}
+ BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
+
+ for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
+ BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
+ BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ }
+
+ BLI_listbase_clear(&ob_dst->shader_fx);
+
+ for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
+ BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
+ BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BLI_addtail(&ob_dst->shader_fx, nfx);
+ }
+
if (ob_src->pose) {
copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
- if (ob_src->type == OB_ARMATURE)
- BKE_pose_rebuild(bmain, ob_dst, ob_dst->data);
+ if (ob_src->type == OB_ARMATURE) {
+ const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+ BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
+ }
}
defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
@@ -1204,18 +1308,18 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
ob_dst->derivedDeform = NULL;
ob_dst->derivedFinal = NULL;
- BLI_listbase_clear(&ob_dst->gpulamp);
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
+ /* grease pencil: clean derived data */
+ if (ob_dst->type == OB_GPENCIL)
+ BKE_gpencil_free_derived_frames(ob_dst->data);
+
ob_dst->avs = ob_src->avs;
ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
copy_object_lod(ob_dst, ob_src, flag_subdata);
- /* Do not copy runtime curve data. */
- ob_dst->curve_cache = NULL;
-
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
@@ -1434,7 +1538,7 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
if (target->type == OB_ARMATURE) {
copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
BKE_pose_rest(ob->pose); /* clear all transforms in channels */
- BKE_pose_rebuild(bmain, ob, ob->data); /* set all internal links */
+ BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */
armature_set_id_extern(ob);
}
@@ -1470,6 +1574,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
ob->empty_drawsize *= size;
break;
}
+ case OB_GPENCIL:
+ {
+ ob->empty_drawsize *= size;
+ break;
+ }
case OB_FONT:
{
Curve *cu = ob->data;
@@ -1726,7 +1835,7 @@ static bool ob_parcurve(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob,
}
#endif
- if (par->curve_cache->path == NULL) {
+ if (par->runtime.curve_cache->path == NULL) {
return false;
}
@@ -1945,10 +2054,10 @@ static void give_parvert(Object *par, int nr, float vec[3])
ListBase *nurb;
/* Unless there's some weird depsgraph failure the cache should exist. */
- BLI_assert(par->curve_cache != NULL);
+ BLI_assert(par->runtime.curve_cache != NULL);
- if (par->curve_cache->deformed_nurbs.first != NULL) {
- nurb = &par->curve_cache->deformed_nurbs;
+ if (par->runtime.curve_cache->deformed_nurbs.first != NULL) {
+ nurb = &par->runtime.curve_cache->deformed_nurbs;
}
else {
Curve *cu = par->data;
@@ -1959,7 +2068,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
else if (par->type == OB_LATTICE) {
Lattice *latt = par->data;
- DispList *dl = par->curve_cache ? BKE_displist_find(&par->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = par->runtime.curve_cache ? BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) : NULL;
float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL;
int tot;
@@ -2453,7 +2562,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us
float size[3];
copy_v3_v3(size, ob->size);
- if (ob->type == OB_EMPTY) {
+ if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) {
mul_v3_fl(size, ob->empty_drawsize);
}
@@ -2540,10 +2649,10 @@ void BKE_object_foreach_display_point(
func_cb(co, user_data);
}
}
- else if (ob->curve_cache && ob->curve_cache->disp.first) {
+ else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
DispList *dl;
- for (dl = ob->curve_cache->disp.first; dl; dl = dl->next) {
+ for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) {
const float *v3 = dl->verts;
int totvert = dl->nr;
int i;
@@ -2700,7 +2809,7 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
* on file load */
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
/* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
- BKE_pose_rebuild(NULL, ob, ob->data);
+ BKE_pose_rebuild(NULL, ob, ob->data, true);
}
}
}
@@ -3695,6 +3804,74 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
return false;
}
+bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
+{
+ if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
+
+ /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
+{
+ if (BKE_shaderfx_dependsOnTime(fx)) {
+ return true;
+ }
+
+ /* Check whether effect is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
+
+ /* action - check for F-Curves with paths containing string[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* set "ignore cache" flag for all caches on this object */
static void object_cacheIgnoreClear(Object *ob, int state)
{
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 5c9e53aaa56..a6b0e57e55c 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -53,6 +53,7 @@
#include "BKE_object.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil.h"
/** \name Misc helpers
* \{ */
@@ -402,12 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
- if (BKE_object_is_in_editmode_vgroup(ob))
- object_defgroup_remove_edit_mode(ob, defgroup);
- else
- object_defgroup_remove_object_mode(ob, defgroup);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ BKE_gpencil_vgroup_remove(ob, defgroup);
+ }
+ else {
+ if (BKE_object_is_in_editmode_vgroup(ob))
+ object_defgroup_remove_edit_mode(ob, defgroup);
+ else
+ object_defgroup_remove_object_mode(ob, defgroup);
- BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ }
}
/**
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 3e72de3909f..3641df26496 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -62,6 +62,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_gpencil.h"
#include "MEM_guardedalloc.h"
@@ -324,6 +325,9 @@ void BKE_object_eval_uber_data(Depsgraph *depsgraph,
case OB_MBALL:
BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
break;
+ case OB_GPENCIL:
+ BKE_gpencil_batch_cache_dirty(ob->data);
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 07aa21f44ff..cb26f7e9f3e 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -41,13 +41,19 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_workspace_types.h"
#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
@@ -55,6 +61,7 @@
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -151,6 +158,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return &ts->imapaint.paint;
case ePaintSculptUV:
return &ts->uvsculpt->paint;
+ case ePaintGpencil:
+ return &ts->gp_paint->paint;
case ePaintInvalid:
return NULL;
default:
@@ -176,6 +185,8 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
return &ts->wpaint->paint;
case OB_MODE_TEXTURE_PAINT:
return &ts->imapaint.paint;
+ case OB_MODE_GPENCIL_PAINT:
+ return &ts->gp_paint->paint;
case OB_MODE_EDIT:
if (ts->use_uv_sculpt)
return &ts->uvsculpt->paint;
@@ -430,13 +441,11 @@ PaletteColor *BKE_palette_color_add(Palette *palette)
return color;
}
-
bool BKE_palette_is_empty(const struct Palette *palette)
{
return BLI_listbase_is_empty(&palette->colors);
}
-
/* are we in vertex paint or weight pain face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 35c8761f671..cee1c9147b5 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -2941,7 +2941,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
skip = 1; /* only hair, keyed and baked stuff can have paths */
else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
skip = 1; /* particle visualization must be set as path */
- else {
+ else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) {
if (part->draw_as != PART_DRAW_REND)
skip = 1; /* draw visualization */
else if (psys->pointcache->flag & PTCACHE_BAKING)
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 59847b28785..c542c3f927d 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -716,6 +716,35 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* --------------------- */
+static void rigidbody_constraint_init_spring(
+ RigidBodyCon *rbc, void (*set_spring)(rbConstraint *, int, int),
+ void (*set_stiffness)(rbConstraint *, int, float), void (*set_damping)(rbConstraint *, int, float))
+{
+ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x);
+ set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x);
+
+ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y);
+ set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y);
+
+ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
+ set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
+
+ set_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
+ set_damping(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
+
+ set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
+ set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
+
+ set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
+ set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
+}
+
static void rigidbody_constraint_set_limits(
RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
{
@@ -841,35 +870,24 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper);
break;
case RBC_TYPE_6DOF_SPRING:
- rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2);
-
- RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X);
- RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x);
- RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x);
+ if (rbc->spring_type == RBC_SPRING_TYPE2) {
+ rbc->physics_constraint = RB_constraint_new_6dof_spring2(loc, rot, rb1, rb2);
- RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y);
- RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y);
- RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y);
+ rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring2, RB_constraint_set_stiffness_6dof_spring2, RB_constraint_set_damping_6dof_spring2);
- RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z);
- RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
- RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
+ RB_constraint_set_equilibrium_6dof_spring2(rbc->physics_constraint);
- RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
- RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
- RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
-
- RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
- RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
- RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring2);
+ }
+ else {
+ rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2);
- RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
- RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
- RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
+ rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring, RB_constraint_set_stiffness_6dof_spring, RB_constraint_set_damping_6dof_spring);
- RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
+ RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
- rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring);
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof);
+ }
break;
case RBC_TYPE_6DOF:
rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
@@ -1094,6 +1112,8 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty
rbc->flag |= RBC_FLAG_ENABLED;
rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS;
+ rbc->spring_type = RBC_SPRING_TYPE2;
+
rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */
rbc->num_solver_iterations = 10; /* 10 is Bullet default */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3650fa21c1c..ba25fc14ac9 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -173,6 +173,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
}
+ if (ts->gp_paint) {
+ ts->gp_paint = MEM_dupallocN(ts->gp_paint);
+ BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
+ }
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
ts->imapaint.paintcursor = NULL;
@@ -180,15 +184,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->particle.scene = NULL;
ts->particle.object = NULL;
- /* duplicate Grease Pencil Drawing Brushes */
- BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) {
- bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
- BLI_addtail(&ts->gp_brushes, newbrush);
- }
-
/* duplicate Grease Pencil interpolation curve */
ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ /* duplicate Grease Pencil multiframe fallof */
+ ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff);
return ts;
}
@@ -213,16 +212,20 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_paint_free(&toolsettings->uvsculpt->paint);
MEM_freeN(toolsettings->uvsculpt);
}
+ if (toolsettings->gp_paint) {
+ BKE_paint_free(&toolsettings->gp_paint->paint);
+ MEM_freeN(toolsettings->gp_paint);
+ }
BKE_paint_free(&toolsettings->imapaint.paint);
- /* free Grease Pencil Drawing Brushes */
- BKE_gpencil_free_brushes(&toolsettings->gp_brushes);
- BLI_freelistN(&toolsettings->gp_brushes);
-
/* free Grease Pencil interpolation curve */
if (toolsettings->gp_interpolate.custom_ipo) {
curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
}
+ /* free Grease Pencil multiframe falloff curve */
+ if (toolsettings->gp_sculpt.cur_falloff) {
+ curvemapping_free(toolsettings->gp_sculpt.cur_falloff);
+ }
MEM_freeN(toolsettings);
}
@@ -428,9 +431,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
/* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
- * are done outside of blenkernel with ED_objects_single_users! */
+ * are done outside of blenkernel with ED_object_single_users! */
- /* camera */
+ /* camera */
if (ELEM(type, SCE_COPY_LINK_DATA, SCE_COPY_FULL)) {
ID_NEW_REMAP(sce_copy->camera);
}
@@ -683,6 +686,19 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->imapaint.normal_angle = 80;
sce->toolsettings->imapaint.seam_bleed = 2;
+ /* alloc grease pencil drawing brushes */
+ sce->toolsettings->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint");
+
+ /* grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
+ curvemapping_set_defaults(gp_falloff_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+
sce->physics_settings.gravity[0] = 0.0f;
sce->physics_settings.gravity[1] = 0.0f;
sce->physics_settings.gravity[2] = -9.81f;
@@ -760,46 +776,65 @@ void BKE_scene_init(Scene *sce)
{
GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt;
GP_EditBrush_Data *gp_brush;
+ float curcolor_add[3], curcolor_sub[3];
+ ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
+ ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
gp_brush->size = 50;
gp_brush->strength = 0.3f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
gp_brush->size = 50;
gp_brush->strength = 0.5f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
/* GP Stroke Placement */
@@ -808,6 +843,10 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+ /* Annotations */
+ sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ sce->toolsettings->annotate_thickness = 3;
+
sce->orientation_index_custom = -1;
/* Master Collection */
@@ -878,7 +917,6 @@ void BKE_scene_init(Scene *sce)
sce->eevee.flag =
SCE_EEVEE_VOLUMETRIC_LIGHTS |
- SCE_EEVEE_VOLUMETRIC_COLORED |
SCE_EEVEE_GTAO_BENT_NORMALS |
SCE_EEVEE_GTAO_BOUNCE |
SCE_EEVEE_TAA_REPROJECTION |
@@ -1208,6 +1246,16 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame)
return best_marker ? best_marker->name : NULL;
}
+int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int cfra)
+{
+ const int fps = round_db_to_int(FPS * interval_in_seconds);
+ const int second_prev = cfra - mod_i(cfra, fps);
+ const int second_next = second_prev + fps;
+ const int delta_prev = cfra - second_prev;
+ const int delta_next = second_next - cfra;
+ return (delta_prev < delta_next) ? second_prev : second_next;
+}
+
void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob)
{
/* remove rigid body constraint from world before removing object */
@@ -1288,7 +1336,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgrap
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->type == OB_ARMATURE && ob->adt && ob->adt->recalc & ADT_RECALC_ANIM) {
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(bmain, ob, ob->data);
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
}
}
}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index f8d926a13ed..c107bb04e6e 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -869,6 +869,7 @@ void BKE_screen_view3d_shading_init(View3DShading *shading)
shading->cavity_valley_factor = 1.0f;
shading->cavity_ridge_factor = 1.0f;
copy_v3_fl(shading->single_color, 0.8f);
+ copy_v3_fl(shading->background_color, 0.05f);
}
/* magic zoom calculation, no idea what
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index d857db7e276..b5b4ec5cd41 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -5530,6 +5530,7 @@ static Sequence *seq_dupli(const Scene *scene_src, Scene *scene_dst, Sequence *s
if (scene_src == scene_dst) {
if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) {
+ /* TODO this is broken in case of Meta strips recursive duplication... Not trivial to fix. */
BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn);
}
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
new file mode 100644
index 00000000000..c028c2184fd
--- /dev/null
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -0,0 +1,245 @@
+/*
+ * ***** 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/shader_fx.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "FX_shader_types.h"
+
+static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Methods - Evaluation Loops, etc. */
+
+/* check if exist grease pencil effects */
+bool BKE_shaderfx_has_gpencil(Object *ob)
+{
+ ShaderFxData *fx;
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi->type == eShaderFxType_GpencilType) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BKE_shaderfx_init(void)
+{
+ /* Initialize shaders */
+ shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */
+}
+
+ShaderFxData *BKE_shaderfx_new(int type)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
+
+ fx->type = type;
+ fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
+ fx->flag = eShaderFxFlag_StaticOverride_Local;
+
+ if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode)
+ fx->mode |= eShaderFxMode_Editmode;
+
+ if (fxi->initData) fxi->initData(fx);
+
+ return fx;
+}
+
+static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (fxi->freeData) fxi->freeData(fx);
+ if (fx->error) MEM_freeN(fx->error);
+
+ MEM_freeN(fx);
+}
+
+void BKE_shaderfx_free(ShaderFxData *fx)
+{
+ BKE_shaderfx_free_ex(fx, 0);
+}
+
+/* check unique name */
+bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
+{
+ if (shaders && fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
+ }
+ return false;
+}
+
+bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ return fxi->dependsOnTime && fxi->dependsOnTime(fx);
+}
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
+ return shader_fx_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+
+ /* fx_dst may have alredy be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (fxi->freeData) {
+ fxi->freeData(fx_dst);
+ }
+
+ const size_t data_size = sizeof(ShaderFxData);
+ const char *fx_src_data = ((const char *)fx_src) + data_size;
+ char *fx_dst_data = ((char *)fx_dst) + data_size;
+ BLI_assert(data_size <= (size_t)fxi->struct_size);
+ memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size);
+}
+
+static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ target->mode = fx->mode;
+ target->flag = fx->flag;
+
+ if (fxi->copyData) {
+ fxi->copyData(fx, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_ex(fx, target, 0);
+}
+
+ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next)
+ if (fx->type == type)
+ break;
+
+ return fx;
+}
+
+void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData);
+ else if (fxi->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk;
+ fxi->foreachObjectLink(fx, ob, fp, userData);
+ }
+ }
+}
+
+ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
+}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 794da2d3477..d8e0c517d91 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -42,23 +42,6 @@
# include "opensubdiv_topology_refiner_capi.h"
#endif
-#ifdef WITH_OPENSUBDIV
-static void update_subdiv_after_topology_change(Subdiv *subdiv)
-{
- /* Count ptex faces. */
- subdiv->num_ptex_faces = subdiv->topology_refiner->getNumPtexFaces(
- subdiv->topology_refiner);
- /* Initialize offset of base faces in ptex indices. */
- MEM_SAFE_FREE(subdiv->face_ptex_offset);
- subdiv->face_ptex_offset = MEM_malloc_arrayN(subdiv->num_ptex_faces,
- sizeof(int),
- "subdiv ptex offset");
- subdiv->topology_refiner->fillFacePtexIndexOffset(
- subdiv->topology_refiner,
- subdiv->face_ptex_offset);
-}
-#endif
-
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
struct OpenSubdiv_Converter *converter)
{
@@ -79,7 +62,6 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
subdiv->settings = *settings;
subdiv->topology_refiner = osd_topology_refiner;
subdiv->evaluator = NULL;
- update_subdiv_after_topology_change(subdiv);
BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
subdiv->stats = stats;
return subdiv;
@@ -113,7 +95,8 @@ void BKE_subdiv_free(Subdiv *subdiv)
if (subdiv->topology_refiner != NULL) {
openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
}
- MEM_SAFE_FREE(subdiv->face_ptex_offset);
MEM_freeN(subdiv);
+#else
+ UNUSED_VARS(subdiv);
#endif
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 83f2069ea0f..db7366a2414 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -29,36 +29,61 @@
#include "BKE_subdiv.h"
+#include "atomic_ops.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
#include "BLI_math_vector.h"
#include "BLI_task.h"
#include "BKE_mesh.h"
-/* TODO(sergey): Somehow move this to subdiv code? */
-static int mpoly_ptex_faces_count_get(const MPoly *mp)
+#include "MEM_guardedalloc.h"
+
+/* =============================================================================
+ * General helpers.
+ */
+
+/* Number of ptex faces for a given polygon. */
+BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
{
- if (mp->totloop == 4) {
- return 1;
- }
- else {
- return mp->totloop;
- }
+ return (poly->totloop == 4) ? 1 : poly->totloop;
}
-static int num_edges_per_ptex_get(const int resolution)
+BLI_INLINE int num_edges_per_ptex_face_get(const int resolution)
{
return 2 * (resolution - 1) * resolution;
}
-static int num_polys_per_ptex_get(const int resolution)
+BLI_INLINE int num_inner_edges_per_ptex_face_get(const int resolution)
+{
+ if (resolution < 2) {
+ return 0;
+ }
+ return (resolution - 2) * resolution +
+ (resolution - 1) * (resolution - 1);
+}
+
+/* Number of subdivision polygons per ptex face. */
+BLI_INLINE int num_polys_per_ptex_get(const int resolution)
{
return (resolution - 1) * (resolution - 1);
}
+/* Subdivision resolution per given polygon's ptex faces. */
+BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
+{
+ return (poly->totloop == 4) ? (resolution)
+ : ((resolution >> 1) + 1);
+}
+
+/* =============================================================================
+ * Mesh subdivision context.
+ */
+
typedef struct SubdivMeshContext {
const Mesh *coarse_mesh;
Subdiv *subdiv;
@@ -72,8 +97,248 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
+ /* Counters of geometry in subdivided mesh, initialized as a part of
+ * offsets calculation.
+ */
+ int num_subdiv_vertices;
+ int num_subdiv_edges;
+ int num_subdiv_loops;
+ int num_subdiv_polygons;
+ /* Offsets of various geometry in the subdivision mesh arrays. */
+ int vertices_corner_offset;
+ int vertices_edge_offset;
+ int vertices_inner_offset;
+ int edge_boundary_offset;
+ int edge_inner_offset;
+ /* Indexed by coarse polygon index, indicates offset in subdivided mesh
+ * vertices, edges and polygons arrays, where first element of the poly
+ * begins.
+ */
+ int *subdiv_vertex_offset;
+ int *subdiv_edge_offset;
+ int *subdiv_polygon_offset;
+ /* Indexed by base face index, element indicates total number of ptex faces
+ * created for preceding base faces.
+ */
+ int *face_ptex_offset;
+ /* Bitmap indicating whether vertex was used already or not.
+ * - During patch evaluation indicates whether coarse vertex was already
+ * evaluated and its position on limit is already known.
+ */
+ BLI_bitmap *coarse_vertices_used_map;
+ /* Bitmap indicating whether edge was used already or not. This includes:
+ * - During context initialization it indicates whether subdivided verticies
+ * for corresponding edge were already calculated or not.
+ * - During patch evaluation it indicates whether vertices along this edge
+ * were already evaluated.
+ */
+ BLI_bitmap *coarse_edges_used_map;
} SubdivMeshContext;
+static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ ctx->num_uv_layers =
+ CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ ctx->uv_layers[layer_index] = CustomData_get_layer_n(
+ &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
+ }
+}
+
+static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ /* Pointers to original indices layers. */
+ ctx->vert_origindex = CustomData_get_layer(
+ &subdiv_mesh->vdata, CD_ORIGINDEX);
+ ctx->edge_origindex = CustomData_get_layer(
+ &subdiv_mesh->edata, CD_ORIGINDEX);
+ ctx->loop_origindex = CustomData_get_layer(
+ &subdiv_mesh->ldata, CD_ORIGINDEX);
+ ctx->poly_origindex = CustomData_get_layer(
+ &subdiv_mesh->pdata, CD_ORIGINDEX);
+ /* UV layers interpolation. */
+ subdiv_mesh_ctx_cache_uv_layers(ctx);
+}
+
+/* NOTE: Expects edge map to be zeroed. */
+static void subdiv_mesh_ctx_count(SubdivMeshContext *ctx)
+{
+ /* Reset counters. */
+ ctx->num_subdiv_vertices = 0;
+ ctx->num_subdiv_edges = 0;
+ ctx->num_subdiv_loops = 0;
+ ctx->num_subdiv_polygons = 0;
+ /* Static geometry counters. */
+ const int resolution = ctx->settings->resolution;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2);
+ const int num_inner_vertices_per_noquad_patch =
+ (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 2);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ ctx->num_subdiv_vertices = coarse_mesh->totvert;
+ ctx->num_subdiv_edges =
+ coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1);
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const bool is_edge_used =
+ BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e);
+ /* Edges which aren't counted yet. */
+ if (!is_edge_used) {
+ BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e);
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ /* Inner verticies of polygon. */
+ if (num_ptex_faces_per_poly == 1) {
+ ctx->num_subdiv_vertices += num_inner_vertices_per_quad;
+ ctx->num_subdiv_edges +=
+ num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ ctx->num_subdiv_vertices +=
+ 1 +
+ num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) +
+ num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch;
+ ctx->num_subdiv_edges +=
+ num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(
+ no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ ctx->num_subdiv_edges += coarse_poly->totloop;
+ }
+ ctx->num_subdiv_polygons +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+ ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4;
+}
+
+static void subdiv_mesh_ctx_init_offsets(SubdivMeshContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int resolution = ctx->settings->resolution;
+ const int resolution_2 = resolution - 2;
+ const int resolution_2_squared = resolution_2 * resolution_2;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_irregular_vertices_per_patch =
+ (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ /* Constant offsets in arrays. */
+ ctx->vertices_corner_offset = 0;
+ ctx->vertices_edge_offset = coarse_mesh->totvert;
+ ctx->vertices_inner_offset =
+ ctx->vertices_edge_offset +
+ coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge;
+ ctx->edge_boundary_offset = 0;
+ ctx->edge_inner_offset =
+ ctx->edge_boundary_offset +
+ coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge;
+ /* "Indexed" offsets. */
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ int vertex_offset = 0;
+ int edge_offset = 0;
+ int polygon_offset = 0;
+ int face_ptex_offset = 0;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ ctx->face_ptex_offset[poly_index] = face_ptex_offset;
+ ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
+ ctx->subdiv_edge_offset[poly_index] = edge_offset;
+ ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
+ face_ptex_offset += num_ptex_faces_per_poly;
+ if (num_ptex_faces_per_poly == 1) {
+ vertex_offset += resolution_2_squared;
+ edge_offset += num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ polygon_offset += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ vertex_offset +=
+ 1 +
+ num_ptex_faces_per_poly * num_irregular_vertices_per_patch;
+ edge_offset +=
+ num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(
+ no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ edge_offset += coarse_poly->totloop;
+ }
+ polygon_offset +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+}
+
+static void subdiv_mesh_ctx_init(SubdivMeshContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ /* Allocate maps and offsets. */
+ ctx->coarse_vertices_used_map =
+ BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map");
+ ctx->coarse_edges_used_map =
+ BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map");
+ ctx->subdiv_vertex_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_vertex_offset),
+ "vertex_offset");
+ ctx->subdiv_edge_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_edge_offset),
+ "subdiv_edge_offset");
+ ctx->subdiv_polygon_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_polygon_offset),
+ "subdiv_edge_offset");
+ ctx->face_ptex_offset = MEM_malloc_arrayN(coarse_mesh->totpoly,
+ sizeof(*ctx->face_ptex_offset),
+ "face_ptex_offset");
+ /* Initialize all offsets. */
+ subdiv_mesh_ctx_init_offsets(ctx);
+ /* Calculate number of geometry in the result subdivision mesh. */
+ subdiv_mesh_ctx_count(ctx);
+ /* Re-set maps which were used at this step. */
+ BLI_BITMAP_SET_ALL(ctx->coarse_edges_used_map, false, coarse_mesh->totedge);
+}
+
+static void subdiv_mesh_ctx_init_result(SubdivMeshContext *ctx)
+{
+ subdiv_mesh_ctx_cache_custom_data_layers(ctx);
+}
+
+static void subdiv_mesh_ctx_free(SubdivMeshContext *ctx)
+{
+ MEM_freeN(ctx->coarse_vertices_used_map);
+ MEM_freeN(ctx->coarse_edges_used_map);
+ MEM_freeN(ctx->subdiv_vertex_offset);
+ MEM_freeN(ctx->subdiv_edge_offset);
+ MEM_freeN(ctx->subdiv_polygon_offset);
+ MEM_freeN(ctx->face_ptex_offset);
+}
+
+/* =============================================================================
+ * Loop custom data copy helpers.
+ */
+
typedef struct LoopsOfPtex {
/* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
const MLoop *first_loop;
@@ -88,10 +353,11 @@ static void loops_of_ptex_get(
const SubdivMeshContext *ctx,
LoopsOfPtex *loops_of_ptex,
const MPoly *coarse_poly,
- const int ptex_face_index)
+ const int ptex_of_poly_index)
{
const MLoop *coarse_mloop = ctx->coarse_mesh->mloop;
- const int first_ptex_loop_index = coarse_poly->loopstart + ptex_face_index;
+ const int first_ptex_loop_index =
+ coarse_poly->loopstart + ptex_of_poly_index;
/* Loop which look in the (opposite) V direction of the current
* ptex face.
*
@@ -99,7 +365,8 @@ static void loops_of_ptex_get(
*/
const int last_ptex_loop_index =
coarse_poly->loopstart +
- (ptex_face_index + coarse_poly->totloop - 1) % coarse_poly->totloop;
+ (ptex_of_poly_index + coarse_poly->totloop - 1) %
+ coarse_poly->totloop;
loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index];
loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index];
if (coarse_poly->totloop == 4) {
@@ -112,6 +379,12 @@ static void loops_of_ptex_get(
}
}
+/* =============================================================================
+ * Edge custom data copy helpers.
+ */
+
+#if 0
+
typedef struct EdgesOfPtex {
/* First edge of the ptex, starts at ptex (0, 0) and goes in u direction. */
const MEdge *first_edge;
@@ -145,6 +418,12 @@ static void edges_of_ptex_get(
}
}
+#endif
+
+/* =============================================================================
+ * Vertex custom data interpolation helpers.
+ */
+
/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
* exception cases all over the code.
*/
@@ -215,7 +494,7 @@ static void vertex_interpolation_init(
int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
for (int i = 0; i < coarse_poly->totloop; ++i) {
weights[i] = weight;
- indices[i] = coarse_poly->loopstart + i;
+ indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
}
CustomData_interp(&coarse_mesh->vdata,
&vertex_interpolation->vertex_data_storage,
@@ -230,7 +509,7 @@ static void vertex_interpolation_from_ptex(
const SubdivMeshContext *ctx,
VerticesForInterpolation *vertex_interpolation,
const MPoly *coarse_poly,
- const int ptex_face_index)
+ const int ptex_of_poly_index)
{
if (coarse_poly->totloop == 4) {
/* Nothing to do, all indices and data is already assigned. */
@@ -240,12 +519,12 @@ static void vertex_interpolation_from_ptex(
const Mesh *coarse_mesh = ctx->coarse_mesh;
const MLoop *coarse_mloop = coarse_mesh->mloop;
LoopsOfPtex loops_of_ptex;
- loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, ptex_face_index);
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, ptex_of_poly_index);
/* Ptex face corner corresponds to a poly loop with same index. */
CustomData_copy_data(
vertex_data,
&vertex_interpolation->vertex_data_storage,
- coarse_mloop[coarse_poly->loopstart + ptex_face_index].v,
+ coarse_mloop[coarse_poly->loopstart + ptex_of_poly_index].v,
0,
1);
/* Interpolate remaining ptex face corners, which hits loops
@@ -255,13 +534,15 @@ static void vertex_interpolation_from_ptex(
* iteration.
*/
const float weights[2] = {0.5f, 0.5f};
+ const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
+ const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop;
const int first_indices[2] = {
- coarse_mloop[loops_of_ptex.first_loop - coarse_mloop].v,
- coarse_mloop[(loops_of_ptex.first_loop + 1 - coarse_mloop) %
- coarse_poly->totloop].v};
- const int last_indices[2] = {
- coarse_mloop[loops_of_ptex.last_loop - coarse_mloop].v,
- coarse_mloop[loops_of_ptex.first_loop - coarse_mloop].v};
+ coarse_mloop[first_loop_index].v,
+ coarse_mloop[coarse_poly->loopstart +
+ (first_loop_index - coarse_poly->loopstart + 1) %
+ coarse_poly->totloop].v};
+ const int last_indices[2] = {coarse_mloop[first_loop_index].v,
+ coarse_mloop[last_loop_index].v};
CustomData_interp(vertex_data,
&vertex_interpolation->vertex_data_storage,
first_indices,
@@ -285,6 +566,10 @@ static void vertex_interpolation_end(
}
}
+/* =============================================================================
+ * Loop custom data interpolation helpers.
+ */
+
typedef struct LoopsForInterpolation {
/* This field points to a loop data which is to be used for interpolation.
* The idea is to avoid unnecessary allocations for regular faces, where
@@ -413,13 +698,32 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
}
}
-static void subdiv_copy_vertex_data(
+/* =============================================================================
+ * Vertex subdivision process.
+ */
+
+/* Custom data interpolation helpers. */
+
+static void subdiv_vertex_data_copy(
+ const SubdivMeshContext *ctx,
+ const MVert *coarse_vertex,
+ MVert *subdiv_vertex)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert;
+ const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert;
+ CustomData_copy_data(&coarse_mesh->vdata,
+ &ctx->subdiv_mesh->vdata,
+ coarse_vertex_index,
+ subdiv_vertex_index,
+ 1);
+}
+
+static void subdiv_vertex_data_interpolate(
const SubdivMeshContext *ctx,
MVert *subdiv_vertex,
- const Mesh *coarse_mesh,
- const MPoly *coarse_poly,
const VerticesForInterpolation *vertex_interpolation,
- const int ptex_of_poly_index,
const float u, const float v)
{
const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert;
@@ -435,87 +739,395 @@ static void subdiv_copy_vertex_data(
subdiv_vertex_index);
if (ctx->vert_origindex != NULL) {
ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
- if (coarse_poly->totloop == 4) {
- if (u == 0.0f && v == 0.0f) {
- ctx->vert_origindex[subdiv_vertex_index] =
- vertex_interpolation->vertex_indices[0];
- }
- else if (u == 1.0f && v == 0.0f) {
- ctx->vert_origindex[subdiv_vertex_index] =
- vertex_interpolation->vertex_indices[1];
+ }
+}
+
+/* Evaluation of corner vertices. They are coming from coarse vertices. */
+
+static void subdiv_evaluate_corner_vertices_regular(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ const float weights[4][2] = {{0.0f, 0.0f},
+ {1.0f, 0.0f},
+ {1.0f, 1.0f},
+ {0.0f, 1.0f}};
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
+ coarse_loop->v))
+ {
+ continue;
+ }
+ const MVert *coarse_vert = &coarse_mvert[coarse_loop->v];
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_corner_offset + coarse_loop->v];
+ subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ weights[corner][0], weights[corner][1],
+ subdiv_vert->co, subdiv_vert->no);
+ }
+}
+
+static void subdiv_evaluate_corner_vertices_special(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
+ coarse_loop->v))
+ {
+ continue;
+ }
+ const MVert *coarse_vert = &coarse_mvert[coarse_loop->v];
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_corner_offset + coarse_loop->v];
+ subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ 0.0f, 0.0f,
+ subdiv_vert->co, subdiv_vert->no);
+ }
+}
+
+static void subdiv_evaluate_corner_vertices(SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_evaluate_corner_vertices_regular(ctx, coarse_poly);
+ }
+ else {
+ subdiv_evaluate_corner_vertices_special(ctx, coarse_poly);
+ }
+}
+
+/* Evaluation of edge vertices. They are coming from coarse edges. */
+
+static void subdiv_evaluate_edge_vertices_regular(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly,
+ VerticesForInterpolation *vertex_interpolation)
+{
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
+ coarse_loop->e))
+ {
+ continue;
+ }
+ vertex_interpolation_from_ptex(ctx,
+ vertex_interpolation,
+ coarse_poly,
+ corner);
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge];
+ for (int vertex_index = 0;
+ vertex_index < num_subdiv_vertices_per_coarse_edge;
+ vertex_index++, subdiv_vert++)
+ {
+ float fac = (vertex_index + 1) * inv_resolution_1;
+ if (flip) {
+ fac = 1.0f - fac;
}
- else if (u == 1.0f && v == 1.0f) {
- ctx->vert_origindex[subdiv_vertex_index] =
- vertex_interpolation->vertex_indices[2];
+ if (corner >= 2) {
+ fac = 1.0f - fac;
}
- else if (u == 0.0f && v == 1.0f) {
- ctx->vert_origindex[subdiv_vertex_index] =
- vertex_interpolation->vertex_indices[3];
+ float u, v;
+ if ((corner & 1) == 0) {
+ u = fac;
+ v = (corner == 2) ? 1.0f : 0.0f;
}
- } else {
- if (u == 0.0f && v == 0.0f) {
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- ctx->vert_origindex[subdiv_vertex_index] =
- coarse_mloop[coarse_poly->loopstart +
- ptex_of_poly_index].v;
+ else {
+ u = (corner == 1) ? 1.0f : 0.0f;
+ v = fac;
}
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ u, v);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
}
}
}
-static void subdiv_evaluate_vertices(SubdivMeshContext *ctx,
- const int poly_index)
+static void subdiv_evaluate_edge_vertices_special(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly,
+ VerticesForInterpolation *vertex_interpolation)
{
- Subdiv *subdiv = ctx->subdiv;
const int resolution = ctx->settings->resolution;
- const int resolution2 = resolution * resolution;
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- /* Base/coarse mesh information. */
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(num_vertices_per_ptex_edge - 1);
+ Subdiv *subdiv = ctx->subdiv;
const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_polyoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_polyoly[poly_index];
- const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly);
- /* Hi-poly subdivided mesh. */
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_vertex = subdiv_mesh->mvert;
- const int ptex_face_index = subdiv->face_ptex_offset[poly_index];
- /* Actual evaluation. */
- VerticesForInterpolation vertex_interpolation;
- vertex_interpolation_init(ctx, &vertex_interpolation, coarse_poly);
- MVert *subdiv_vert = &subdiv_vertex[ptex_face_index * resolution2];
- for (int ptex_of_poly_index = 0;
- ptex_of_poly_index < num_poly_ptex_faces;
- ptex_of_poly_index++)
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
+ int ptex_face_index = ptex_face_start_index;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
{
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
+ coarse_loop->e))
+ {
+ continue;
+ }
vertex_interpolation_from_ptex(ctx,
- &vertex_interpolation,
+ vertex_interpolation,
coarse_poly,
- ptex_of_poly_index);
- const int current_ptex_face_index =
- ptex_face_index + ptex_of_poly_index;
- BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
- subdiv,
- current_ptex_face_index,
- resolution,
- subdiv_vert, offsetof(MVert, co), sizeof(MVert),
- subdiv_vert, offsetof(MVert, no), sizeof(MVert));
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++, subdiv_vert++) {
- const float u = x * inv_resolution_1;
- subdiv_copy_vertex_data(ctx,
- subdiv_vert,
- coarse_mesh,
- coarse_poly,
- &vertex_interpolation,
- ptex_of_poly_index,
- u, v);
+ corner);
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge];
+ int veretx_delta = 1;
+ if (flip) {
+ subdiv_vert += num_subdiv_vertices_per_coarse_edge - 1;
+ veretx_delta = -1;
+ }
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge;
+ vertex_index++, subdiv_vert += veretx_delta)
+ {
+ float u = vertex_index * inv_ptex_resolution_1;
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ u, 0.0f);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, 0.0f,
+ subdiv_vert->co, subdiv_vert->no);
+ }
+ const int next_ptex_face_index =
+ ptex_face_start_index + (corner + 1) % coarse_poly->totloop;
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge - 1;
+ vertex_index++, subdiv_vert += veretx_delta)
+ {
+ float v = 1.0f - vertex_index * inv_ptex_resolution_1;
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ 0.0f, v);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ next_ptex_face_index,
+ 0.0f, v,
+ subdiv_vert->co, subdiv_vert->no);
+ }
+ }
+}
+
+static void subdiv_evaluate_edge_vertices(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly,
+ VerticesForInterpolation *vertex_interpolation)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_evaluate_edge_vertices_regular(
+ ctx, coarse_poly, vertex_interpolation);
+ }
+ else {
+ subdiv_evaluate_edge_vertices_special(
+ ctx, coarse_poly, vertex_interpolation);
+ }
+}
+
+/* Evaluation of inner vertices, they are coming from ptex patches. */
+
+static void subdiv_evaluate_inner_vertices_regular(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly,
+ VerticesForInterpolation *vertex_interpolation)
+{
+ const int resolution = ctx->settings->resolution;
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index];
+ MVert *subdiv_vert =
+ &subdiv_mvert[ctx->vertices_inner_offset + start_vertex_index];
+ vertex_interpolation_from_ptex(ctx,
+ vertex_interpolation,
+ coarse_poly,
+ 0);
+ for (int y = 1; y < resolution - 1; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 1; x < resolution - 1; x++, subdiv_vert++) {
+ const float u = x * inv_resolution_1;
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ u, v);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
+ }
+ }
+}
+
+static void subdiv_evaluate_inner_vertices_special(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly,
+ VerticesForInterpolation *vertex_interpolation)
+{
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution = ptex_face_resolution_get(
+ coarse_poly, resolution);
+ const float inv_ptex_face_resolution_1 =
+ 1.0f / (float)(ptex_face_resolution - 1);
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index];
+ MVert *subdiv_vert =
+ &subdiv_mvert[ctx->vertices_inner_offset + start_vertex_index];
+ vertex_interpolation_from_ptex(ctx,
+ vertex_interpolation,
+ coarse_poly,
+ 0);
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ 1.0f, 1.0f);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ 1.0f, 1.0f,
+ subdiv_vert->co, subdiv_vert->no);
+ subdiv_vert++;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ if (corner != 0) {
+ vertex_interpolation_from_ptex(ctx,
+ vertex_interpolation,
+ coarse_poly,
+ corner);
+ }
+ for (int y = 1; y < ptex_face_resolution - 1; y++) {
+ const float v = y * inv_ptex_face_resolution_1;
+ for (int x = 1; x < ptex_face_resolution; x++, subdiv_vert++) {
+ const float u = x * inv_ptex_face_resolution_1;
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ u, v);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
}
}
}
+}
+
+static void subdiv_evaluate_inner_vertices(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly,
+ VerticesForInterpolation *vertex_interpolation)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_evaluate_inner_vertices_regular(
+ ctx, coarse_poly, vertex_interpolation);
+ }
+ else {
+ subdiv_evaluate_inner_vertices_special(
+ ctx, coarse_poly, vertex_interpolation);
+ }
+}
+
+/* Evaluate all vertices which are emitted from given coarse polygon. */
+static void subdiv_evaluate_vertices(SubdivMeshContext *ctx,
+ const int poly_index)
+{
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ /* Initialize vertex interpolation, it is reused by corner vertices, coarse
+ * edges and patch evaluation.
+ */
+ VerticesForInterpolation vertex_interpolation;
+ vertex_interpolation_init(ctx, &vertex_interpolation, coarse_poly);
+ (void) vertex_interpolation;
+ subdiv_evaluate_corner_vertices(ctx, coarse_poly);
+ subdiv_evaluate_edge_vertices(ctx, coarse_poly, &vertex_interpolation);
+ subdiv_evaluate_inner_vertices(ctx, coarse_poly, &vertex_interpolation);
vertex_interpolation_end(&vertex_interpolation);
}
+/* =============================================================================
+ * Edge subdivision process.
+ */
+
static void subdiv_copy_edge_data(
SubdivMeshContext *ctx,
MEdge *subdiv_edge,
@@ -537,20 +1149,17 @@ static void subdiv_copy_edge_data(
coarse_edge_index,
subdiv_edge_index,
1);
- if (ctx->edge_origindex != NULL) {
- ctx->edge_origindex[subdiv_edge_index] = coarse_edge_index;
- }
}
static MEdge *subdiv_create_edges_row(SubdivMeshContext *ctx,
MEdge *subdiv_edge,
const MEdge *coarse_edge,
const int start_vertex_index,
- const int resolution)
+ const int num_edges_per_row)
{
int vertex_index = start_vertex_index;
for (int edge_index = 0;
- edge_index < resolution - 1;
+ edge_index < num_edges_per_row - 1;
edge_index++, subdiv_edge++)
{
subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
@@ -566,103 +1175,338 @@ static MEdge *subdiv_create_edges_column(SubdivMeshContext *ctx,
const MEdge *coarse_start_edge,
const MEdge *coarse_end_edge,
const int start_vertex_index,
- const int resolution)
+ const int num_edges_per_row)
{
int vertex_index = start_vertex_index;
for (int edge_index = 0;
- edge_index < resolution;
+ edge_index < num_edges_per_row;
edge_index++, subdiv_edge++)
{
const MEdge *coarse_edge = NULL;
if (edge_index == 0) {
coarse_edge = coarse_start_edge;
}
- else if (edge_index == resolution - 1) {
+ else if (edge_index == num_edges_per_row - 1) {
coarse_edge = coarse_end_edge;
}
subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
subdiv_edge->v1 = vertex_index;
- subdiv_edge->v2 = vertex_index + resolution;
+ subdiv_edge->v2 = vertex_index + num_edges_per_row;
vertex_index += 1;
}
return subdiv_edge;
}
-static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index)
+/* Create edges between inner vertices of patch, and also edges to the
+ * boundary.
+ */
+
+/* Consider a subdivision of base face at level 1:
+ *
+ * y
+ * ^
+ * | (6) ---- (7) ---- (8)
+ * | | | |
+ * | (3) ---- (4) ---- (5)
+ * | | | |
+ * | (0) ---- (1) ---- (2)
+ * o---------------------------> x
+ *
+ * This is illustrate which parts of geometry is created by code below.
+ */
+
+static void subdiv_create_edges_all_patches_regular(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
{
- Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
const int resolution = ctx->settings->resolution;
- const int resolution2 = resolution * resolution;
- const int ptex_face_index = subdiv->face_ptex_offset[poly_index];
- const int num_edges_per_ptex = num_edges_per_ptex_get(resolution);
- const int start_edge_index = ptex_face_index * num_edges_per_ptex;
- /* Base/coarse mesh information. */
+ const int start_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MEdge *subdiv_medge = subdiv_mesh->medge;
+ MEdge *subdiv_edge = &subdiv_medge[
+ ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index]];
+ /* Create bottom row of edges (0-1, 1-2). */
+ subdiv_edge = subdiv_create_edges_row(
+ ctx,
+ subdiv_edge,
+ NULL,
+ start_vertex_index,
+ resolution - 2);
+ /* Create remaining edges. */
+ for (int row = 0; row < resolution - 3; row++) {
+ const int start_row_vertex_index =
+ start_vertex_index + row * (resolution - 2);
+ /* Create vertical columns.
+ *
+ * At first iteration it will be edges (0-3. 1-4, 2-5), then it
+ * will be (3-6, 4-7, 5-8) and so on.
+ */
+ subdiv_edge = subdiv_create_edges_column(
+ ctx,
+ subdiv_edge,
+ NULL,
+ NULL,
+ start_row_vertex_index,
+ resolution - 2);
+ /* Create horizontal edge row.
+ *
+ * At first iteration it will be edges (3-4, 4-5), then it will be
+ * (6-7, 7-8) and so on.
+ */
+ subdiv_edge = subdiv_create_edges_row(
+ ctx,
+ subdiv_edge,
+ NULL,
+ start_row_vertex_index + resolution - 2,
+ resolution - 2);
+ }
+ /* Connect inner part of patch to boundary. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge - 1;
+ side_stride = -1;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_edge++) {
+ subdiv_copy_edge_data(ctx, subdiv_edge, NULL);
+ if (flip) {
+ subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ subdiv_edge->v1 = start_edge_vertex + i;
+ }
+ subdiv_edge->v2 = side_start_index + side_stride * i;
+ }
+ }
+}
+
+static void subdiv_create_edges_all_patches_special(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_polyoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_polyoly[poly_index];
- const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly);
- /* Hi-poly subdivided mesh. */
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const int num_inner_vertices_per_ptex =
+ (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int center_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MEdge *subdiv_medge = subdiv_mesh->medge;
- MEdge *subdiv_edge = &subdiv_medge[start_edge_index];
- const int start_poly_vertex_index = ptex_face_index * resolution2;
- /* Consider a subdivision of base face at level 1:
- *
- * y
- * ^
- * | (6) ---- (7) ---- (8)
- * | | | |
- * | (3) ---- (4) ---- (5)
- * | | | |
- * | (0) ---- (1) ---- (2)
- * o---------------------------> x
- *
- * This is illustrate which parts of geometry is created by code below.
- */
- for (int i = 0; i < num_poly_ptex_faces; i++) {
+ MEdge *subdiv_edge = &subdiv_medge[
+ ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index]];
+ /* Create inner ptex edges. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
const int start_ptex_face_vertex_index =
- start_poly_vertex_index + i * resolution2;
- EdgesOfPtex edges_of_ptex;
- edges_of_ptex_get(ctx, &edges_of_ptex, coarse_poly, i);
- /* Create bottom row of edges (0-1, 1-2). */
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ /* Similar steps to regular patch case. */
subdiv_edge = subdiv_create_edges_row(
ctx,
subdiv_edge,
- edges_of_ptex.first_edge,
+ NULL,
start_ptex_face_vertex_index,
- resolution);
- /* Create remaining edges. */
- for (int row = 0; row < resolution - 1; row++) {
+ ptex_face_inner_resolution + 1);
+ for (int row = 0; row < ptex_face_inner_resolution - 1; row++) {
const int start_row_vertex_index =
- start_ptex_face_vertex_index + row * resolution;
- /* Create vertical columns.
- *
- * At first iteration it will be edges (0-3. 1-4, 2-5), then it
- * will be (3-6, 4-7, 5-8) and so on.
- */
+ start_ptex_face_vertex_index +
+ row * (ptex_face_inner_resolution + 1);
subdiv_edge = subdiv_create_edges_column(
ctx,
subdiv_edge,
- edges_of_ptex.last_edge,
- edges_of_ptex.second_edge,
+ NULL,
+ NULL,
start_row_vertex_index,
- resolution);
- /* Create horizontal edge row.
- *
- * At first iteration it will be edges (3-4, 4-5), then it will be
- * (6-7, 7-8) and so on.
- */
+ ptex_face_inner_resolution + 1);
subdiv_edge = subdiv_create_edges_row(
ctx,
subdiv_edge,
- (row == resolution - 2) ? edges_of_ptex.third_edge
- : NULL,
- start_row_vertex_index + resolution,
- resolution);
+ NULL,
+ start_row_vertex_index + ptex_face_inner_resolution + 1,
+ ptex_face_inner_resolution + 1);
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ int current_patch_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index =
+ start_vertex_index + next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ for (int row = 0;
+ row < ptex_face_inner_resolution;
+ row++, subdiv_edge++)
+ {
+ subdiv_copy_edge_data(ctx, subdiv_edge, NULL);
+ subdiv_edge->v1 = current_patch_vertex_index;
+ subdiv_edge->v2 = next_path_vertex_index;
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ }
+ }
+ /* Create edges from center. */
+ if (ptex_face_resolution >= 3) {
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, subdiv_edge++)
+ {
+ const int current_patch_end_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ subdiv_copy_edge_data(ctx, subdiv_edge, NULL);
+ subdiv_edge->v1 = center_vertex_index;
+ subdiv_edge->v2 = current_patch_end_vertex_index;
}
}
+ /* Connect inner path of patch to boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ {
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index;
+ if (ptex_face_resolution >= 3) {
+ side_start_index =
+ start_vertex_index + num_inner_vertices_per_ptex * corner;
+ }
+ else {
+ side_start_index = center_vertex_index;
+ }
+ for (int i = 0; i < ptex_face_resolution - 1; i++, subdiv_edge++) {
+ subdiv_copy_edge_data(ctx, subdiv_edge, NULL);
+ if (flip) {
+ subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ subdiv_edge->v1 = start_edge_vertex + i;
+ }
+ subdiv_edge->v2 = side_start_index + i;
+ }
+ }
+ if (ptex_face_resolution >= 3) {
+ const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index =
+ start_vertex_index + num_inner_vertices_per_ptex * corner;
+ for (int i = 0; i < ptex_face_resolution - 2; i++, subdiv_edge++) {
+ subdiv_copy_edge_data(ctx, subdiv_edge, NULL);
+ if (flip) {
+ subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ subdiv_edge->v1 = start_edge_vertex + i;
+ }
+ subdiv_edge->v2 = side_start_index +
+ (ptex_face_inner_resolution + 1) * i;
+ }
+ }
+ prev_coarse_loop = coarse_loop;
+ }
}
+static void subdiv_create_edges_all_patches(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_create_edges_all_patches_regular(ctx, coarse_poly);
+ }
+ else {
+ subdiv_create_edges_all_patches_special(ctx, coarse_poly);
+ }
+}
+
+static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ subdiv_create_edges_all_patches(ctx, coarse_poly);
+}
+
+static void subdiv_create_boundary_edges(
+ SubdivMeshContext *ctx,
+ int edge_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MEdge *coarse_edge = &coarse_medge[edge_index];
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MEdge *subdiv_medge = subdiv_mesh->medge;
+ MEdge *subdiv_edge = &subdiv_medge[
+ ctx->edge_boundary_offset +
+ edge_index * num_subdiv_edges_per_coarse_edge];
+ int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1;
+ for (int i = 0;
+ i < num_subdiv_edges_per_coarse_edge - 1;
+ i++, subdiv_edge++)
+ {
+ subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
+ subdiv_edge->v1 = last_vertex_index;
+ subdiv_edge->v2 =
+ ctx->vertices_edge_offset +
+ edge_index * num_subdiv_vertices_per_coarse_edge +
+ i;
+ last_vertex_index = subdiv_edge->v2;
+ }
+ subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
+ subdiv_edge->v1 = last_vertex_index;
+ subdiv_edge->v2 = ctx->vertices_corner_offset + coarse_edge->v2;
+}
+
+/* =============================================================================
+ * Loops creation/interpolation.
+ */
+
static void subdiv_copy_loop_data(
const SubdivMeshContext *ctx,
MLoop *subdiv_loop,
@@ -687,15 +1531,13 @@ static void subdiv_eval_uv_layer(SubdivMeshContext *ctx,
MLoop *subdiv_loop,
const int ptex_face_index,
const float u, const float v,
- const float inv_resolution_1)
+ const float du, const float dv)
{
if (ctx->num_uv_layers == 0) {
return;
}
Subdiv *subdiv = ctx->subdiv;
const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
- const float du = inv_resolution_1;
- const float dv = inv_resolution_1;
for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index];
BKE_subdiv_eval_face_varying(subdiv,
@@ -721,100 +1563,620 @@ static void subdiv_eval_uv_layer(SubdivMeshContext *ctx,
}
}
-static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index)
+static void rotate_indices(const int rot, int *a, int *b, int *c, int *d)
+{
+ int values[4] = {*a, *b, *c, *d};
+ *a = values[(0 - rot + 4) % 4];
+ *b = values[(1 - rot + 4) % 4];
+ *c = values[(2 - rot + 4) % 4];
+ *d = values[(3 - rot + 4) % 4];
+}
+
+static void subdiv_create_loops_of_poly(
+ SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ MLoop *subdiv_loop_start,
+ const int ptex_face_index,
+ const int rotation,
+ /*const*/ int v0, /*const*/ int e0,
+ /*const*/ int v1, /*const*/ int e1,
+ /*const*/ int v2, /*const*/ int e2,
+ /*const*/ int v3, /*const*/ int e3,
+ const float u, const float v,
+ const float du, const float dv)
+{
+ rotate_indices(rotation, &v0, &v1, &v2, &v3);
+ rotate_indices(rotation, &e0, &e1, &e2, &e3);
+ subdiv_copy_loop_data(ctx,
+ &subdiv_loop_start[0],
+ loop_interpolation,
+ u, v);
+ subdiv_loop_start[0].v = v0;
+ subdiv_loop_start[0].e = e0;
+ subdiv_copy_loop_data(ctx,
+ &subdiv_loop_start[1],
+ loop_interpolation,
+ u + du, v);
+ subdiv_loop_start[1].v = v1;
+ subdiv_loop_start[1].e = e1;
+ subdiv_copy_loop_data(ctx,
+ &subdiv_loop_start[2],
+ loop_interpolation,
+ u + du, v + dv);
+ subdiv_loop_start[2].v = v2;
+ subdiv_loop_start[2].e = e2;
+ subdiv_copy_loop_data(ctx,
+ &subdiv_loop_start[3],
+ loop_interpolation,
+ u, v + dv);
+ subdiv_loop_start[3].v = v3;
+ subdiv_loop_start[3].e = e3;
+ /* Interpolate UV layers using OpenSubdiv. */
+ subdiv_eval_uv_layer(ctx,
+ subdiv_loop_start,
+ ptex_face_index,
+ u, v, du, dv);
+}
+
+static void subdiv_create_loops_regular(SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
{
- Subdiv *subdiv = ctx->subdiv;
const int resolution = ctx->settings->resolution;
- const int resolution2 = resolution * resolution;
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- const int ptex_face_index = subdiv->face_ptex_offset[poly_index];
- const int num_edges_per_ptex = num_edges_per_ptex_get(resolution);
- const int start_edge_index = ptex_face_index * num_edges_per_ptex;
- const int num_polys_per_ptex = num_polys_per_ptex_get(resolution);
- const int start_poly_index = ptex_face_index * num_polys_per_ptex;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_inner_resolution = ptex_resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1);
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ const int start_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int start_edge_index =
+ ctx->edge_inner_offset +
+ ctx->subdiv_edge_offset[poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
const int start_loop_index = 4 * start_poly_index;
- const int start_vert_index = ptex_face_index * resolution2;
- const float du = inv_resolution_1;
- const float dv = inv_resolution_1;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MLoop *subdiv_loopoop = subdiv_mesh->mloop;
+ MLoop *subdiv_loop = &subdiv_loopoop[start_loop_index];
+ LoopsForInterpolation loop_interpolation;
+ loop_interpolation_init(ctx, &loop_interpolation, coarse_poly);
+ loop_interpolation_from_ptex(ctx,
+ &loop_interpolation,
+ coarse_poly,
+ 0);
+ /* Loops for inner part of ptex. */
+ for (int y = 1; y < ptex_resolution - 2; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop += 4) {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indicies ordered counter-clockwise. */
+ const int v0 = start_vertex_index +
+ (inner_y * ptex_inner_resolution + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_inner_resolution + 1;
+ const int v3 = v0 + ptex_inner_resolution;
+ /* Edge indicies ordered counter-clockwise. */
+ const int e0 = start_edge_index +
+ (inner_y * (2 * ptex_inner_resolution - 1) + inner_x);
+ const int e1 = e0 + ptex_inner_resolution;
+ const int e2 = e0 + (2 * ptex_inner_resolution - 1);
+ const int e3 = e0 + ptex_inner_resolution - 1;
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop, ptex_face_index, 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ int e2_offset, e2_stride;
+ float u, v, delta_u, delta_v;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ e2_offset = 0;
+ e2_stride = 1;
+ u = 0.0f;
+ v = 0.0f;
+ delta_u = du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4;
+ e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3;
+ u = 1.0f - du;
+ v = 0;
+ delta_u = 0.0f;
+ delta_v = dv;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge - 1;
+ side_stride = -1;
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1;
+ e2_stride = -1;
+ u = 1.0f - du;
+ v = 1.0f - dv;
+ delta_u = -du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) -
+ (2 * num_subdiv_edges_per_coarse_edge - 3);
+ e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3);
+ u = 0.0f;
+ v = 1.0f - dv;
+ delta_u = 0.0f;
+ delta_v = -dv;
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_loop += 4) {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ const int v2 = side_start_index + side_stride * i;
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ i;
+ }
+ int e1 = start_edge_index +
+ num_edges_per_ptex_face_get(resolution - 2) +
+ corner * num_subdiv_vertices_per_coarse_edge +
+ i;
+ int e2;
+ if (i == 0) {
+ e2 = start_edge_index +
+ num_edges_per_ptex_face_get(resolution - 2) +
+ ((corner - 1 + coarse_poly->totloop) %
+ coarse_poly->totloop) *
+ num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ e2 = start_edge_index + e2_offset + e2_stride * (i - 1);
+ }
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop,
+ ptex_face_index, corner,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u + delta_u * i, v + delta_v * i, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+ loop_interpolation_end(&loop_interpolation);
+}
+
+static void subdiv_create_loops_special(SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
/* Base/coarse mesh information. */
const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_polyoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_polyoly[poly_index];
- const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly);
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(ptex_face_resolution - 1);
+ const int num_inner_vertices_per_ptex =
+ (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_inner_edges_per_ptex_face =
+ num_inner_edges_per_ptex_face_get(
+ ptex_face_inner_resolution + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ const int center_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ const int start_inner_vertex_index = center_vertex_index + 1;
+ const int start_edge_index = ctx->edge_inner_offset +
+ ctx->subdiv_edge_offset[poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
/* Hi-poly subdivided mesh. */
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MLoop *subdiv_loopoop = subdiv_mesh->mloop;
MLoop *subdiv_loop = &subdiv_loopoop[start_loop_index];
LoopsForInterpolation loop_interpolation;
loop_interpolation_init(ctx, &loop_interpolation, coarse_poly);
- for (int ptex_of_poly_index = 0;
- ptex_of_poly_index < num_poly_ptex_faces;
- ptex_of_poly_index++)
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++)
{
+ const int corner_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
loop_interpolation_from_ptex(ctx,
&loop_interpolation,
coarse_poly,
- ptex_of_poly_index);
- const int current_ptex_face_index =
- ptex_face_index + ptex_of_poly_index;
- for (int y = 0; y < resolution - 1; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution - 1; x++, subdiv_loop += 4) {
- const float u = x * inv_resolution_1;
+ corner);
+ for (int y = 1; y < ptex_face_inner_resolution; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1;
+ x < ptex_face_inner_resolution + 1;
+ x++, subdiv_loop += 4)
+ {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
/* Vertex indicies ordered counter-clockwise. */
- const int v0 = start_vert_index +
- (ptex_of_poly_index * resolution2) +
- (y * resolution + x);
+ const int v0 =
+ corner_vertex_index +
+ (inner_y * (ptex_face_inner_resolution + 1) + inner_x);
const int v1 = v0 + 1;
- const int v2 = v0 + resolution + 1;
- const int v3 = v0 + resolution;
+ const int v2 = v0 + ptex_face_inner_resolution + 2;
+ const int v3 = v0 + ptex_face_inner_resolution + 1;
/* Edge indicies ordered counter-clockwise. */
- const int e0 = start_edge_index +
- (ptex_of_poly_index * num_edges_per_ptex) +
- (y * (2 * resolution - 1) + x);
- const int e1 = e0 + resolution;
- const int e2 = e0 + (2 * resolution - 1);
- const int e3 = e0 + resolution - 1;
- /* Initialize 4 loops of corresponding hi-poly poly. */
- /* TODO(sergey): For ptex boundaries we should use loops from
- * coarse mesh.
- */
- subdiv_copy_loop_data(ctx,
- &subdiv_loop[0],
- &loop_interpolation,
- u, v);
- subdiv_loop[0].v = v0;
- subdiv_loop[0].e = e0;
- subdiv_copy_loop_data(ctx,
- &subdiv_loop[1],
- &loop_interpolation,
- u + du, v);
- subdiv_loop[1].v = v1;
- subdiv_loop[1].e = e1;
- subdiv_copy_loop_data(ctx,
- &subdiv_loop[2],
- &loop_interpolation,
- u + du, v + dv);
- subdiv_loop[2].v = v2;
- subdiv_loop[2].e = e2;
- subdiv_copy_loop_data(ctx,
- &subdiv_loop[3],
- &loop_interpolation,
- u, v + dv);
- subdiv_loop[3].v = v3;
- subdiv_loop[3].e = e3;
- /* Interpolate UV layers using OpenSubdiv. */
- subdiv_eval_uv_layer(ctx,
- subdiv_loop,
- current_ptex_face_index,
- u, v,
- inv_resolution_1);
+ const int e0 = corner_edge_index +
+ (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x);
+ const int e1 = e0 + ptex_face_inner_resolution + 1;
+ const int e2 = e0 + (2 * ptex_face_inner_resolution + 1);
+ const int e3 = e0 + ptex_face_inner_resolution;
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop,
+ ptex_face_index + corner, 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
}
}
}
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ const int next_corner_edge_index =
+ start_edge_index + next_corner * num_inner_edges_per_ptex_face;
+ int current_patch_vertex_index =
+ start_inner_vertex_index +
+ corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index =
+ start_inner_vertex_index +
+ next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ int v0 = current_patch_vertex_index;
+ int v1 = next_path_vertex_index;
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ int e0 = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ corner * (ptex_face_resolution - 2);
+ int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face -
+ ptex_face_resolution + 2;
+ int e3 = corner_edge_index + 2 * ptex_face_resolution - 4;
+ loop_interpolation_from_ptex(ctx,
+ &loop_interpolation,
+ coarse_poly,
+ next_corner);
+ for (int row = 1;
+ row < ptex_face_inner_resolution;
+ row++, subdiv_loop += 4)
+ {
+ const int v2 = next_path_vertex_index;
+ const int v3 = current_patch_vertex_index;
+ const int e2 = e0 + 1;
+ const float u = row * du;
+ const float v = 1.0f - dv;
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop,
+ ptex_face_index + next_corner, 3,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ v0 = v3;
+ v1 = v2;
+ e0 = e2;
+ e1 += 1;
+ e3 += 2 * ptex_face_resolution - 3;
+ }
+ }
+ /* Create loops from center. */
+ if (ptex_face_resolution >= 3) {
+ const int start_center_edge_index =
+ start_edge_index +
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution) * coarse_poly->totloop;
+ const int start_boundary_edge =
+ start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution - 1;
+ for (int corner = 0, prev_corner = coarse_poly->totloop - 1;
+ corner < coarse_poly->totloop;
+ prev_corner = corner, corner++, subdiv_loop += 4)
+ {
+ loop_interpolation_from_ptex(ctx,
+ &loop_interpolation,
+ coarse_poly,
+ corner);
+ const int corner_edge_index =
+ start_edge_index +
+ corner * num_inner_edges_per_ptex_face;
+ const int current_patch_end_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int prev_current_patch_end_vertex_index =
+ start_vertex_index + prev_corner *
+ num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v0 = center_vertex_index;
+ const int v1 = prev_current_patch_end_vertex_index;
+ const int v2 = current_patch_end_vertex_index - 1;
+ const int v3 = current_patch_end_vertex_index;
+ const int e0 = start_center_edge_index + prev_corner;
+ const int e1 = start_boundary_edge +
+ prev_corner * (ptex_face_inner_resolution);
+ const int e2 = corner_edge_index +
+ num_inner_edges_per_ptex_face - 1;
+ const int e3 = start_center_edge_index + corner;
+ const float u = 1.0f - du;
+ const float v = 1.0f - dv;
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop,
+ ptex_face_index + corner, 2,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int prev_corner = coarse_poly->totloop - 1, corner = 0;
+ corner < coarse_poly->totloop;
+ prev_corner = corner, corner++)
+ {
+ loop_interpolation_from_ptex(ctx,
+ &loop_interpolation,
+ coarse_poly,
+ corner);
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const int corner_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ /* Create loops for polygons along U axis. */
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ for (int i = 0;
+ i <= ptex_face_inner_resolution;
+ i++, subdiv_loop += 4)
+ {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ int v2;
+ if (ptex_face_inner_resolution >= 1) {
+ v2 = corner_vertex_index + i;
+ }
+ else {
+ v2 = center_vertex_index;
+ }
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ i;
+ }
+ int e1 = start_edge_index +
+ corner * (2 * ptex_face_inner_resolution + 1);
+ if (ptex_face_resolution >= 3) {
+ e1 += coarse_poly->totloop * (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ i;
+ }
+ int e2 = 0;
+ if (i == 0 && ptex_face_resolution >= 3) {
+ e2 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution + 1;
+ }
+ else if (i == 0 && ptex_face_resolution < 3) {
+ e2 = start_edge_index +
+ prev_corner * (2 * ptex_face_inner_resolution + 1);
+ }
+ else {
+ e2 = corner_edge_index + i - 1;
+ }
+ const float u = du * i;
+ const float v = 0.0f;
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop,
+ ptex_face_index + corner, 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ /* Create loops for polygons along V axis. */
+ const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v);
+ v0 = corner_vertex_index;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ }
+ e3 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution + 1;
+ for (int i = 0;
+ i <= ptex_face_inner_resolution - 1;
+ i++, subdiv_loop += 4)
+ {
+ int v1;
+ int e0, e1;
+ if (i == ptex_face_inner_resolution - 1) {
+ v1 = start_vertex_index +
+ prev_corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ e1 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ prev_corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution;
+ e0 = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ prev_corner * ptex_face_inner_resolution;
+ }
+ else {
+ v1 = v0 + ptex_face_inner_resolution + 1;
+ e0 = corner_edge_index + ptex_face_inner_resolution +
+ i * (2 * ptex_face_inner_resolution + 1);
+ e1 = e3 + 1;
+ }
+ int v2 = flip_prev ? v3 - 1 : v3 + 1;
+ int e2;
+ if (flip_prev) {
+ e2 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e *
+ num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 2 - i;
+ }
+ else {
+ e2 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e *
+ num_subdiv_edges_per_coarse_edge + 1 + i;
+ }
+ const float u = 0.0f;
+ const float v = du * (i + 1);
+ subdiv_create_loops_of_poly(
+ ctx, &loop_interpolation, subdiv_loop,
+ ptex_face_index + corner, 1,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
loop_interpolation_end(&loop_interpolation);
}
+static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_create_loops_regular(ctx, coarse_poly);
+ }
+ else {
+ subdiv_create_loops_special(ctx, coarse_poly);
+ }
+}
+
+/* =============================================================================
+ * Polygons subdivision process.
+ */
+
static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
MPoly *subdiv_poly,
const MPoly *coarse_poly)
@@ -826,31 +2188,29 @@ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
coarse_poly_index,
subdiv_poly_index,
1);
- if (ctx->poly_origindex != NULL) {
- ctx->poly_origindex[subdiv_poly_index] = coarse_poly_index;
- }
}
static void subdiv_create_polys(SubdivMeshContext *ctx, int poly_index)
{
- Subdiv *subdiv = ctx->subdiv;
const int resolution = ctx->settings->resolution;
- const int ptex_face_index = subdiv->face_ptex_offset[poly_index];
- const int num_polys_per_ptex = num_polys_per_ptex_get(resolution);
- const int num_loops_per_ptex = 4 * num_polys_per_ptex;
- const int start_poly_index = ptex_face_index * num_polys_per_ptex;
- const int start_loop_index = 4 * start_poly_index;
+ const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
/* Base/coarse mesh information. */
const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_polyoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_polyoly[poly_index];
- const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly);
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ const int ptex_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution);
+ const int num_loops_per_ptex = 4 * num_polys_per_ptex;
+ const int start_loop_index = 4 * start_poly_index;
/* Hi-poly subdivided mesh. */
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MPoly *subdiv_mpoly = subdiv_mesh->mpoly;
MPoly *subdiv_mp = &subdiv_mpoly[start_poly_index];
for (int ptex_of_poly_index = 0;
- ptex_of_poly_index < num_poly_ptex_faces;
+ ptex_of_poly_index < num_ptex_faces_per_poly;
ptex_of_poly_index++)
{
for (int subdiv_poly_index = 0;
@@ -866,45 +2226,31 @@ static void subdiv_create_polys(SubdivMeshContext *ctx, int poly_index)
}
}
+/* =============================================================================
+ * Subdivision process entry points.
+ */
+
static void subdiv_eval_task(
void *__restrict userdata,
const int poly_index,
const ParallelRangeTLS *__restrict UNUSED(tls))
{
- SubdivMeshContext *data = userdata;
+ SubdivMeshContext *ctx = userdata;
/* Evaluate hi-poly vertex coordinates and normals. */
- subdiv_evaluate_vertices(data, poly_index);
+ subdiv_evaluate_vertices(ctx, poly_index);
/* Create mesh geometry for the given base poly index. */
- subdiv_create_edges(data, poly_index);
- subdiv_create_loops(data, poly_index);
- subdiv_create_polys(data, poly_index);
-}
-
-static void cache_uv_layers(SubdivMeshContext *ctx)
-{
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- ctx->num_uv_layers =
- CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
- for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
- ctx->uv_layers[layer_index] = CustomData_get_layer_n(
- &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
- }
+ subdiv_create_edges(ctx, poly_index);
+ subdiv_create_loops(ctx, poly_index);
+ subdiv_create_polys(ctx, poly_index);
}
-static void cache_custom_data_layers(SubdivMeshContext *ctx)
+static void subdiv_create_boundary_edges_task(
+ void *__restrict userdata,
+ const int edge_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- /* Pointers to original indices layers. */
- ctx->vert_origindex = CustomData_get_layer(
- &subdiv_mesh->vdata, CD_ORIGINDEX);
- ctx->edge_origindex = CustomData_get_layer(
- &subdiv_mesh->edata, CD_ORIGINDEX);
- ctx->loop_origindex = CustomData_get_layer(
- &subdiv_mesh->ldata, CD_ORIGINDEX);
- ctx->poly_origindex = CustomData_get_layer(
- &subdiv_mesh->pdata, CD_ORIGINDEX);
- /* UV layers interpolation. */
- cache_uv_layers(ctx);
+ SubdivMeshContext *ctx = userdata;
+ subdiv_create_boundary_edges(ctx, edge_index);
}
Mesh *BKE_subdiv_to_mesh(
@@ -912,41 +2258,42 @@ Mesh *BKE_subdiv_to_mesh(
const SubdivToMeshSettings *settings,
const Mesh *coarse_mesh)
{
+ // printf("================ MESH SUBDIVISION ================\n");
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is is refined for the new positions of coarse vertices.
*/
BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh);
- const int resolution = settings->resolution;
- const int resolution2 = resolution * resolution;
- const int num_result_verts = subdiv->num_ptex_faces * resolution2;
- const int num_result_edges =
- subdiv->num_ptex_faces * num_edges_per_ptex_get(resolution);
- const int num_result_polys =
- subdiv->num_ptex_faces * num_polys_per_ptex_get(resolution);
- const int num_result_loops = 4 * num_result_polys;
- /* Create mesh and its arrays. */
+ SubdivMeshContext ctx = {0};
+ ctx.coarse_mesh = coarse_mesh;
+ ctx.subdiv = subdiv;
+ ctx.settings = settings;
+ subdiv_mesh_ctx_init(&ctx);
Mesh *result = BKE_mesh_new_nomain_from_template(
coarse_mesh,
- num_result_verts,
- num_result_edges,
+ ctx.num_subdiv_vertices,
+ ctx.num_subdiv_edges,
0,
- num_result_loops,
- num_result_polys);
- /* Evaluate subdivisions of base faces in threads. */
- SubdivMeshContext ctx;
- ctx.coarse_mesh = coarse_mesh;
- ctx.subdiv = subdiv;
+ ctx.num_subdiv_loops,
+ ctx.num_subdiv_polygons);
ctx.subdiv_mesh = result;
- ctx.settings = settings;
- cache_custom_data_layers(&ctx);
+ subdiv_mesh_ctx_init_result(&ctx);
/* Multi-threaded evaluation. */
ParallelRangeSettings parallel_range_settings;
+ BKE_subdiv_stats_begin(&subdiv->stats,
+ SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
BLI_parallel_range_settings_defaults(&parallel_range_settings);
BLI_task_parallel_range(0, coarse_mesh->totpoly,
&ctx,
subdiv_eval_task,
&parallel_range_settings);
+ BLI_task_parallel_range(0, coarse_mesh->totedge,
+ &ctx,
+ subdiv_create_boundary_edges_task,
+ &parallel_range_settings);
+ subdiv_mesh_ctx_free(&ctx);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ // BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c
index 5da63fdbacb..f2219961ab7 100644
--- a/source/blender/blenkernel/intern/subdiv_stats.c
+++ b/source/blender/blenkernel/intern/subdiv_stats.c
@@ -37,6 +37,7 @@ void BKE_subdiv_stats_init(SubdivStats *stats)
{
stats->topology_refiner_creation_time = 0.0;
stats->subdiv_to_mesh_time = 0.0;
+ stats->subdiv_to_mesh_geometry_time = 0.0;
stats->evaluator_creation_time = 0.0;
stats->evaluator_refine_time = 0.0;
}
@@ -70,6 +71,9 @@ void BKE_subdiv_stats_print(const SubdivStats *stats)
subdiv_to_mesh_time,
"Subdivision to mesh time");
STATS_PRINT_TIME(stats,
+ subdiv_to_mesh_geometry_time,
+ " Geometry time");
+ STATS_PRINT_TIME(stats,
evaluator_creation_time,
"Evaluator creation time");
STATS_PRINT_TIME(stats,
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 3e1a9a4f57b..a5a38a6dc12 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -168,4 +168,3 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
-