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
path: root/source
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2016-06-01 15:34:11 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-06-01 15:34:11 +0300
commit11af9e9a5bd1caff1ec46794bda2934a01ce5035 (patch)
treed4f76f59c5f6398a07a36eb8e99558e6f4a84b8d /source
parentfaec4309147988fbab7b7d7ec661f5130358d169 (diff)
parentb08473680e141ab6f28f99fc3b1dbbc4add89bed (diff)
Merge branch 'master' into blender2.8
Conflicts: intern/cycles/blender/blender_curves.cpp intern/cycles/blender/blender_particles.cpp source/blender/depsgraph/intern/builder/deg_builder_relations.h source/blender/depsgraph/intern/depsgraph_build.cc
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h8
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c26
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c4
-rw-r--r--source/blender/blenkernel/intern/colortools.c301
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c13
-rw-r--r--source/blender/blenkernel/intern/image.c4
-rw-r--r--source/blender/blenkernel/intern/material.c3
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c471
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c4
-rw-r--r--source/blender/blenlib/BLI_array_store.h66
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h12
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c4
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c21
-rw-r--r--source/blender/blenlib/intern/array_store.c1731
-rw-r--r--source/blender/blenlib/intern/noise.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c8
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c406
-rw-r--r--source/blender/collada/ArmatureExporter.cpp54
-rw-r--r--source/blender/collada/ArmatureExporter.h2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp222
-rw-r--r--source/blender/collada/ArmatureImporter.h24
-rw-r--r--source/blender/collada/ExportSettings.h1
-rw-r--r--source/blender/collada/ExtraTags.cpp23
-rw-r--r--source/blender/collada/ExtraTags.h11
-rw-r--r--source/blender/collada/MeshImporter.cpp39
-rw-r--r--source/blender/collada/collada.cpp6
-rw-r--r--source/blender/collada/collada.h1
-rw-r--r--source/blender/collada/collada_utils.cpp211
-rw-r--r--source/blender/collada/collada_utils.h51
-rw-r--r--source/blender/depsgraph/CMakeLists.txt53
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h8
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h143
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc129
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h46
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc (renamed from source/blender/depsgraph/util/depsgraph_util_cycle.cc)42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.h (renamed from source/blender/depsgraph/util/depsgraph_util_cycle.h)11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc (renamed from source/blender/depsgraph/intern/depsgraph_build_nodes.cc)43
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h153
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc (renamed from source/blender/depsgraph/util/depsgraph_util_pchanmap.cc)28
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h (renamed from source/blender/depsgraph/util/depsgraph_util_pchanmap.h)15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc (renamed from source/blender/depsgraph/intern/depsgraph_build_relations.cc)72
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h (renamed from source/blender/depsgraph/intern/depsgraph_build.h)170
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc (renamed from source/blender/depsgraph/util/depsgraph_util_transitive.cc)58
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.h (renamed from source/blender/depsgraph/util/depsgraph_util_transitive.h)10
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc588
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc115
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h47
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc314
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc1054
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc380
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h95
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc156
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.cc177
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.h91
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc194
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc123
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h252
-rw-r--r--source/blender/depsgraph/intern/depsnode_opcodes.h145
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc409
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h52
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.cc249
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.h (renamed from source/blender/depsgraph/intern/depsgraph_debug.h)28
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc224
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h49
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc (renamed from source/blender/depsgraph/intern/depsnode.cc)158
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h (renamed from source/blender/depsgraph/intern/depsnode.h)41
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc (renamed from source/blender/depsgraph/intern/depsnode_component.cc)216
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h (renamed from source/blender/depsgraph/intern/depsnode_component.h)85
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc (renamed from source/blender/depsgraph/intern/depsnode_operation.cc)31
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h (renamed from source/blender/depsgraph/intern/depsnode_operation.h)42
-rw-r--r--source/blender/depsgraph/util/deg_util_foreach.h68
-rw-r--r--source/blender/depsgraph/util/deg_util_function.h (renamed from source/blender/depsgraph/util/depsgraph_util_function.h)8
-rw-r--r--source/blender/depsgraph/util/deg_util_hash.h (renamed from source/blender/depsgraph/util/depsgraph_util_set.h)43
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_hash.h72
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_map.h67
-rw-r--r--source/blender/editors/animation/anim_deps.c8
-rw-r--r--source/blender/editors/animation/drivers.c5
-rw-r--r--source/blender/editors/animation/keyframing.c24
-rw-r--r--source/blender/editors/armature/armature_utils.c9
-rw-r--r--source/blender/editors/interface/interface_regions.c8
-rw-r--r--source/blender/editors/io/io_collada.c10
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c726
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c136
-rw-r--r--source/blender/editors/transform/transform.c2
-rw-r--r--source/blender/editors/transform/transform.h13
-rw-r--r--source/blender/editors/transform/transform_generics.c61
-rw-r--r--source/blender/editors/transform/transform_snap.c12
-rw-r--r--source/blender/gpu/GPU_buffers.h5
-rw-r--r--source/blender/gpu/GPU_shader.h1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c6
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c4
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c8
-rw-r--r--source/blender/gpu/intern/gpu_material.c3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl130
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl1045
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl62
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl2
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h8
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h2
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_access.c66
-rw-r--r--source/blender/makesrna/intern/rna_camera.c4
-rw-r--r--source/blender/makesrna/intern/rna_curve.c18
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c1
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c36
-rw-r--r--source/blender/python/intern/bpy_rna.c18
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h2
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c11
-rw-r--r--source/blender/windowmanager/wm_event_types.h23
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c1
129 files changed, 8064 insertions, 4797 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 2b13a847e14..8ccc4a6eb0e 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -757,22 +757,22 @@ void DM_update_weight_mcol(
typedef struct DMVertexAttribs {
struct {
struct MLoopUV *array;
- int em_offset, gl_index, gl_texco;
+ int em_offset, gl_index, gl_texco, gl_info_index;
} tface[MAX_MTFACE];
struct {
struct MLoopCol *array;
- int em_offset, gl_index;
+ int em_offset, gl_index, gl_info_index;
} mcol[MAX_MCOL];
struct {
float (*array)[4];
- int em_offset, gl_index;
+ int em_offset, gl_index, gl_info_index;
} tang[MAX_MTFACE];
struct {
float (*array)[3];
- int em_offset, gl_index, gl_texco;
+ int em_offset, gl_index, gl_texco, gl_info_index;
} orco;
int tottface, totmcol, tottang, totorco;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index bcc3b60b34e..d590a35bb57 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2003,15 +2003,10 @@ static void mesh_calc_modifiers(
DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= BKE_MESH_OMP_LIMIT)
- {
-#pragma omp section
- { range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); }
-#pragma omp section
- { range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); }
-#pragma omp section
- { range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); }
- }
+ /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
+ range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
+ range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
+ range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
}
}
@@ -3269,17 +3264,18 @@ void DM_calc_loop_tangents_step_0(
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
/* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
ract_uv_name[0] = 0;
if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
}
/* Active tangent in render */
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
rren_uv_name[0] = 0;
if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
}
/* If active tangent not in tangent_names we take it into account */
@@ -3677,6 +3673,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->tface[a].gl_index = gattribs->layer[b].glindex;
+ attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
}
else if (type == CD_MCOL) {
@@ -3700,6 +3697,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
+ attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
}
else if (type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
@@ -3722,6 +3720,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
+ attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
}
else if (type == CD_ORCO) {
/* original coordinates */
@@ -3741,6 +3740,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->orco.gl_index = gattribs->layer[b].glindex;
attribs->orco.gl_texco = gattribs->layer[b].gltexco;
+ attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
}
}
}
@@ -3769,6 +3769,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord3fv(orco);
else
glVertexAttrib3fv(attribs->orco.gl_index, orco);
+ glUniform1i(attribs->orco.gl_info_index, 0);
}
/* uv texture coordinates */
@@ -3787,6 +3788,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord2fv(uv);
else
glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
+ glUniform1i(attribs->tface[b].gl_info_index, 0);
}
/* vertex colors */
@@ -3802,6 +3804,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
}
glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
+ glUniform1i(attribs->mcol[b].gl_info_index, GPU_ATTR_INFO_SRGB);
}
/* tangent for normal mapping */
@@ -3811,6 +3814,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
const float *tang = (array) ? array[a * 4 + vert] : zero;
glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
}
+ glUniform1i(attribs->tang[b].gl_info_index, 0);
}
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 9c163990dd2..249e4ccd89c 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -1020,6 +1020,7 @@ static void cdDM_drawMappedFacesGLSL(
if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
matconv[a].datatypes[numdata].size = 3;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1027,6 +1028,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.tottface; b++) {
if (matconv[a].attribs.tface[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
matconv[a].datatypes[numdata].size = 2;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1035,6 +1037,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.totmcol; b++) {
if (matconv[a].attribs.mcol[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
numdata++;
@@ -1043,6 +1046,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index bac59c8c62d..c1f1f0128f5 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BKE_colortools.h"
@@ -53,10 +54,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
-
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
@@ -1089,31 +1086,170 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
}
/* if view_settings, it also applies this to byte buffers */
+typedef struct ScopesUpdateData {
+ Scopes *scopes;
+ const ImBuf *ibuf;
+ struct ColormanageProcessor *cm_processor;
+ const unsigned char *display_buffer;
+ const int ycc_mode;
+
+ unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
+} ScopesUpdateData;
+
+typedef struct ScopesUpdateDataChunk {
+ unsigned int bin_lum[256];
+ unsigned int bin_r[256];
+ unsigned int bin_g[256];
+ unsigned int bin_b[256];
+ unsigned int bin_a[256];
+ float min[3], max[3];
+} ScopesUpdateDataChunk;
+
+static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+{
+ const ScopesUpdateData *data = userdata;
+
+ Scopes *scopes = data->scopes;
+ const ImBuf *ibuf = data->ibuf;
+ struct ColormanageProcessor *cm_processor = data->cm_processor;
+ const unsigned char *display_buffer = data->display_buffer;
+ const int ycc_mode = data->ycc_mode;
+
+ ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+ unsigned int *bin_lum = data_chunk->bin_lum;
+ unsigned int *bin_r = data_chunk->bin_r;
+ unsigned int *bin_g = data_chunk->bin_g;
+ unsigned int *bin_b = data_chunk->bin_b;
+ unsigned int *bin_a = data_chunk->bin_a;
+ float *min = data_chunk->min;
+ float *max = data_chunk->max;
+
+ const float *rf = NULL;
+ const unsigned char *rc = NULL;
+ const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
+ const int savedlines = y / rows_per_sample_line;
+ const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
+ const bool is_float = (ibuf->rect_float != NULL);
+
+ if (is_float)
+ rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
+ else {
+ rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
+ }
+
+ for (int x = 0; x < ibuf->x; x++) {
+ float rgba[4], ycc[3], luma;
+
+ if (is_float) {
+ switch (ibuf->channels) {
+ case 4:
+ copy_v4_v4(rgba, rf);
+ IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
+ break;
+ case 3:
+ copy_v3_v3(rgba, rf);
+ IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
+ rgba[3] = 1.0f;
+ break;
+ case 2:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = rf[1];
+ break;
+ case 1:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = 1.0f;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ else {
+ for (int c = 4; c--;)
+ rgba[c] = rc[c] * INV_255;
+ }
+
+ /* we still need luma for histogram */
+ luma = IMB_colormanagement_get_luminance(rgba);
+
+ /* check for min max */
+ if (ycc_mode == -1) {
+ minmax_v3v3_v3(min, max, rgba);
+ }
+ else {
+ rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
+ mul_v3_fl(ycc, INV_255);
+ minmax_v3v3_v3(min, max, ycc);
+ }
+ /* increment count for histo*/
+ bin_lum[get_bin_float(luma)]++;
+ bin_r[get_bin_float(rgba[0])]++;
+ bin_g[get_bin_float(rgba[1])]++;
+ bin_b[get_bin_float(rgba[2])]++;
+ bin_a[get_bin_float(rgba[3])]++;
+
+ /* save sample if needed */
+ if (do_sample_line) {
+ const float fx = (float)x / (float)ibuf->x;
+ const int idx = 2 * (ibuf->x * savedlines + x);
+ save_sample_line(scopes, idx, fx, rgba, ycc);
+ }
+
+ rf += ibuf->channels;
+ rc += ibuf->channels;
+ }
+}
+
+static void scopes_update_finalize(void *userdata, void *userdata_chunk)
+{
+ const ScopesUpdateData *data = userdata;
+ const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+
+ unsigned int *bin_lum = data->bin_lum;
+ unsigned int *bin_r = data->bin_r;
+ unsigned int *bin_g = data->bin_g;
+ unsigned int *bin_b = data->bin_b;
+ unsigned int *bin_a = data->bin_a;
+ const unsigned int *bin_lum_c = data_chunk->bin_lum;
+ const unsigned int *bin_r_c = data_chunk->bin_r;
+ const unsigned int *bin_g_c = data_chunk->bin_g;
+ const unsigned int *bin_b_c = data_chunk->bin_b;
+ const unsigned int *bin_a_c = data_chunk->bin_a;
+
+ float (*minmax)[2] = data->scopes->minmax;
+ const float *min = data_chunk->min;
+ const float *max = data_chunk->max;
+
+ for (int b = 256; b--;) {
+ bin_lum[b] += bin_lum_c[b];
+ bin_r[b] += bin_r_c[b];
+ bin_g[b] += bin_g_c[b];
+ bin_b[b] += bin_b_c[b];
+ bin_a[b] += bin_a_c[b];
+ }
+
+ for (int c = 3; c--;) {
+ if (min[c] < minmax[c][0])
+ minmax[c][0] = min[c];
+ if (max[c] > minmax[c][1])
+ minmax[c][1] = max[c];
+ }
+}
+
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
-#ifdef _OPENMP
- const int num_threads = BLI_system_thread_count();
-#endif
- int a, y;
+ int a;
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
- unsigned char *display_buffer;
+ const unsigned char *display_buffer = NULL;
unsigned int bin_lum[256] = {0},
bin_r[256] = {0},
bin_g[256] = {0},
bin_b[256] = {0},
bin_a[256] = {0};
- unsigned int bin_lum_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_r_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_g_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_b_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_a_t[BLENDER_MAX_THREADS][256] = {{0}};
int ycc_mode = -1;
- const bool is_float = (ibuf->rect_float != NULL);
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
- int rows_per_sample_line;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
@@ -1151,7 +1287,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes->sample_lines = ibuf->y;
/* scan the image */
- rows_per_sample_line = ibuf->y / scopes->sample_lines;
for (a = 0; a < 3; a++) {
scopes->minmax[a][0] = 25500.0f;
scopes->minmax[a][1] = -25500.0f;
@@ -1177,129 +1312,21 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
}
else {
- display_buffer = (unsigned char *)IMB_display_buffer_acquire(ibuf,
- view_settings,
- display_settings,
- &cache_handle);
+ display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
+ ibuf, view_settings, display_settings, &cache_handle);
}
/* Keep number of threads in sync with the merge parts below. */
-#pragma omp parallel for private(y) schedule(static) num_threads(num_threads) if (ibuf->y > 256)
- for (y = 0; y < ibuf->y; y++) {
-#ifdef _OPENMP
- const int thread_idx = omp_get_thread_num();
-#else
- const int thread_idx = 0;
-#endif
- const float *rf = NULL;
- const unsigned char *rc = NULL;
- const int savedlines = y / rows_per_sample_line;
- const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
- float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX},
- max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- int x, c;
- if (is_float)
- rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
- else {
- rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
- }
- for (x = 0; x < ibuf->x; x++) {
- float rgba[4], ycc[3], luma;
- if (is_float) {
-
- switch (ibuf->channels) {
- case 4:
- copy_v4_v4(rgba, rf);
- IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
- break;
- case 3:
- copy_v3_v3(rgba, rf);
- IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
- rgba[3] = 1.0f;
- break;
- case 2:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = rf[1];
- break;
- case 1:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = 1.0f;
- break;
- default:
- BLI_assert(0);
- }
- }
- else {
- for (c = 0; c < 4; c++)
- rgba[c] = rc[c] * INV_255;
- }
-
- /* we still need luma for histogram */
- luma = IMB_colormanagement_get_luminance(rgba);
-
- /* check for min max */
- if (ycc_mode == -1) {
- for (c = 0; c < 3; c++) {
- if (rgba[c] < min[c]) min[c] = rgba[c];
- if (rgba[c] > max[c]) max[c] = rgba[c];
- }
- }
- else {
- rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
- for (c = 0; c < 3; c++) {
- ycc[c] *= INV_255;
- if (ycc[c] < min[c]) min[c] = ycc[c];
- if (ycc[c] > max[c]) max[c] = ycc[c];
- }
- }
- /* increment count for histo*/
- bin_lum_t[thread_idx][get_bin_float(luma)] += 1;
- bin_r_t[thread_idx][get_bin_float(rgba[0])] += 1;
- bin_g_t[thread_idx][get_bin_float(rgba[1])] += 1;
- bin_b_t[thread_idx][get_bin_float(rgba[2])] += 1;
- bin_a_t[thread_idx][get_bin_float(rgba[3])] += 1;
-
- /* save sample if needed */
- if (do_sample_line) {
- const float fx = (float)x / (float)ibuf->x;
- const int idx = 2 * (ibuf->x * savedlines + x);
- save_sample_line(scopes, idx, fx, rgba, ycc);
- }
-
- rf += ibuf->channels;
- rc += ibuf->channels;
- }
-#pragma omp critical
- {
- for (c = 0; c < 3; c++) {
- if (min[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = min[c];
- if (max[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = max[c];
- }
- }
- }
-
-#ifdef _OPENMP
- if (ibuf->y > 256) {
- for (a = 0; a < num_threads; a++) {
- int b;
- for (b = 0; b < 256; b++) {
- bin_lum[b] += bin_lum_t[a][b];
- bin_r[b] += bin_r_t[a][b];
- bin_g[b] += bin_g_t[a][b];
- bin_b[b] += bin_b_t[a][b];
- bin_a[b] += bin_a_t[a][b];
- }
- }
- }
- else
-#endif
- {
- memcpy(bin_lum, bin_lum_t[0], sizeof(bin_lum));
- memcpy(bin_r, bin_r_t[0], sizeof(bin_r));
- memcpy(bin_g, bin_g_t[0], sizeof(bin_g));
- memcpy(bin_b, bin_b_t[0], sizeof(bin_b));
- memcpy(bin_a, bin_a_t[0], sizeof(bin_a));
- }
+ ScopesUpdateData data = {
+ .scopes = scopes, . ibuf = ibuf,
+ .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
+ .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
+ };
+ ScopesUpdateDataChunk data_chunk = {0};
+ INIT_MINMAX(data_chunk.min, data_chunk.max);
+
+ BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
+ scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false);
/* test for nicer distribution even - non standard, leave it out for a while */
#if 0
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index e57e9ffcd66..5fba6c253a3 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -57,6 +57,7 @@
#include "MEM_guardedalloc.h"
#include "GPU_glew.h"
+#include "GPU_buffers.h"
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
@@ -1427,6 +1428,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glTexCoord3fv(orco);
else
glVertexAttrib3fv(attribs->orco.gl_index, orco);
+ glUniform1i(attribs->orco.gl_info_index, 0);
}
for (i = 0; i < attribs->tottface; i++) {
const float *uv;
@@ -1443,17 +1445,19 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glTexCoord2fv(uv);
else
glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
}
for (i = 0; i < attribs->totmcol; i++) {
- GLubyte col[4];
+ float col[4];
if (attribs->mcol[i].em_offset != -1) {
const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
}
- glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
}
for (i = 0; i < attribs->tottang; i++) {
@@ -1465,6 +1469,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
tang = zero;
}
glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
}
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 1ae7ca189fb..0b2c844cb2c 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -109,8 +109,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
#define IMA_NO_INDEX 0x7FEFEFEF
/* quick lookup: supports 1 million frames, thousand passes */
-#define IMA_MAKE_INDEX(frame, index) ((frame) << 10) + index
-#define IMA_INDEX_FRAME(index) (index >> 10)
+#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
+#define IMA_INDEX_FRAME(index) ((index) >> 10)
/*
#define IMA_INDEX_PASS(index) (index & ~1023)
*/
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1fec725dbb7..30f82a50ed9 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1148,7 +1148,6 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
/* parses the geom+tex nodes */
ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
- basemat->nmap_tangent_names_count = 0;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->id) {
if (GS(node->id->name) == ID_MA) {
@@ -1199,7 +1198,7 @@ void init_render_material(Material *mat, int r_mode, float *amb)
* mode_l will have it set when all node materials are shadeless. */
mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS;
mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE;
-
+ mat->nmap_tangent_names_count = 0;
init_render_nodetree(mat->nodetree, mat, r_mode, amb);
if (!mat->nodetree->execdata)
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index e855f6faa22..518d8d68919 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BKE_shrinkwrap.h"
#include "BKE_DerivedMesh.h"
@@ -58,7 +59,7 @@
/* for timing... */
#if 0
-# include "PIL_time.h"
+# include "PIL_time_utildefines.h"
#else
# define TIMEIT_BENCH(expr, id) (expr)
#endif
@@ -66,16 +67,88 @@
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
+typedef struct ShrinkwrapCalcCBData {
+ ShrinkwrapCalcData *calc;
+
+ void *treeData;
+ void *auxData;
+ BVHTree *targ_tree;
+ BVHTree *aux_tree;
+ void *targ_callback;
+ void *aux_callback;
+
+ float *proj_axis;
+ SpaceTransform *local2aux;
+} ShrinkwrapCalcCBData;
+
/*
* Shrinkwrap to the nearest vertex
*
* it builds a kdtree of vertexs we can attach to and then
* for each vertex performs a nearest vertex search on the tree
*/
-static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+static void shrinkwrap_calc_nearest_vertex_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
{
- int i;
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeNearest *nearest = userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ if (nearest->dist_sq > FLT_EPSILON) {
+ const float dist = sqrtf(nearest->dist_sq);
+ weight *= (dist - calc->keepDist) / dist;
+ }
+
+ /* Convert the coordinates back to mesh coordinates */
+ copy_v3_v3(tmp_co, nearest->co);
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
+}
+static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+{
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
@@ -89,61 +162,11 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
-#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- continue;
- }
-
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest.index != -1)
- nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
- else
- nearest.dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
-
-
- /* Found the nearest vertex */
- if (nearest.index != -1) {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- if (nearest.dist_sq > FLT_EPSILON) {
- const float dist = sqrtf(nearest.dist_sq);
- weight *= (dist - calc->keepDist) / dist;
- }
- /* Convert the coordinates back to mesh coordinates */
- copy_v3_v3(tmp_co, nearest.co);
- BLI_space_transform_invert(&calc->local2target, tmp_co);
-
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
- }
+ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_vertex_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
free_bvhtree_from_mesh(&treeData);
}
@@ -230,13 +253,109 @@ bool BKE_shrinkwrap_project_normal(
return false;
}
+static void shrinkwrap_calc_normal_projection_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
+{
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ void *treeData = data->treeData;
+ void *auxData = data->auxData;
+ BVHTree *targ_tree = data->targ_tree;
+ BVHTree *aux_tree = data->aux_tree;
+ void *targ_callback = data->targ_callback;
+ void *aux_callback = data->aux_callback;
+
+ float *proj_axis = data->proj_axis;
+ SpaceTransform *local2aux = data->local2aux;
+
+ BVHTreeRayHit *hit = userdata_chunk;
+
+ const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
+ float *co = calc->vertexCos[i];
+ float tmp_co[3], tmp_no[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ if (calc->vert) {
+ /* calc->vert contains verts from derivedMesh */
+ /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
+ /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
+ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+
+
+ hit->index = -1;
+ hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+
+ /* Project over positive direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no,
+ local2aux, aux_tree, hit,
+ aux_callback, auxData);
+ }
+
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no,
+ &calc->local2target, targ_tree, hit,
+ targ_callback, treeData);
+ }
+
+ /* Project over negative direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, tmp_no);
+
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no,
+ local2aux, aux_tree, hit,
+ aux_callback, auxData);
+ }
+
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, inv_no,
+ &calc->local2target, targ_tree, hit,
+ targ_callback, treeData);
+ }
+
+ /* don't set the initial dist (which is more efficient),
+ * because its calculated in the targets space, we want the dist in our own space */
+ if (proj_limit_squared != 0.0f) {
+ if (len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ hit->index = -1;
+ }
+ }
+
+ if (hit->index != -1) {
+ madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist);
+ interp_v3_v3v3(co, co, hit->co, weight);
+ }
+}
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
{
- int i;
-
/* Options about projection direction */
- const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
/* Raycast and tree stuff */
@@ -305,7 +424,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
if (targ_tree) {
BVHTree *aux_tree = NULL;
- void *aux_callback;
+ void *aux_callback = NULL;
if (auxMesh != NULL) {
/* use editmesh to avoid array allocation */
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
@@ -316,99 +435,22 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
}
else {
- if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) {
+ if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, auxMesh, 0.0, 4, 6)) != NULL) {
aux_callback = dmauxdata_stack.raycast_callback;
auxData = &dmauxdata_stack;
}
}
}
/* After sucessufuly build the trees, start projection vertexs */
-
-#ifndef __APPLE__
-#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3], tmp_no[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- continue;
- }
-
- if (calc->vert) {
- /* calc->vert contains verts from derivedMesh */
- /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
- /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
- if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
-
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
-
- /* Project over positive direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
-
- if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, tmp_no,
- &local2aux, aux_tree, &hit,
- aux_callback, auxData);
- }
-
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, tmp_no,
- &calc->local2target, targ_tree, &hit,
- targ_callback, treeData);
- }
-
- /* Project over negative direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
- float inv_no[3];
- negate_v3_v3(inv_no, tmp_no);
-
- if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, inv_no,
- &local2aux, aux_tree, &hit,
- aux_callback, auxData);
- }
-
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, inv_no,
- &calc->local2target, targ_tree, &hit,
- targ_callback, treeData);
- }
-
- /* don't set the initial dist (which is more efficient),
- * because its calculated in the targets space, we want the dist in our own space */
- if (proj_limit_squared != 0.0f) {
- if (len_squared_v3v3(hit.co, co) > proj_limit_squared) {
- hit.index = -1;
- }
- }
-
- if (hit.index != -1) {
- madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist);
- interp_v3_v3v3(co, co, hit.co, weight);
- }
- }
+ ShrinkwrapCalcCBData data = {
+ .calc = calc,
+ .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback,
+ .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback,
+ .proj_axis = proj_axis, .local2aux = &local2aux,
+ };
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &hit, sizeof(hit), shrinkwrap_calc_normal_projection_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
}
/* free data structures */
@@ -428,10 +470,75 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* it builds a BVHTree from the target mesh and then performs a
* NN matches for each vertex
*/
-static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+static void shrinkwrap_calc_nearest_surface_point_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
{
- int i;
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeNearest *nearest = userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
+ /* Make the vertex stay on the front side of the face */
+ madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist);
+ }
+ else {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ const float dist = sasqrt(nearest->dist_sq);
+ if (dist > FLT_EPSILON) {
+ /* linear interpolation */
+ interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist);
+ }
+ else {
+ copy_v3_v3(tmp_co, nearest->co);
+ }
+ }
+ /* Convert the coordinates back to mesh coordinates */
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
+}
+
+static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+{
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
@@ -446,67 +553,11 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
-
/* Find the nearest vertex */
-#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) continue;
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest.index != -1)
- nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
- else
- nearest.dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
-
- /* Found the nearest vertex */
- if (nearest.index != -1) {
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
- /* Make the vertex stay on the front side of the face */
- madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist);
- }
- else {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- const float dist = sasqrt(nearest.dist_sq);
- if (dist > FLT_EPSILON) {
- /* linear interpolation */
- interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist);
- }
- else {
- copy_v3_v3(tmp_co, nearest.co);
- }
- }
-
- /* Convert the coordinates back to mesh coordinates */
- BLI_space_transform_invert(&calc->local2target, tmp_co);
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
- }
+ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_surface_point_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
free_bvhtree_from_mesh(&treeData);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 5b6adb3778a..b0d19320230 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2995,6 +2995,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
matconv[a].datatypes[numdata].size = 3;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3002,6 +3003,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.tottface; b++) {
if (matconv[a].attribs.tface[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
matconv[a].datatypes[numdata].size = 2;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3010,6 +3012,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.totmcol; b++) {
if (matconv[a].attribs.mcol[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
numdata++;
@@ -3018,6 +3021,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
new file mode 100644
index 00000000000..f4cbc07bf26
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -0,0 +1,66 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ARRAY_STORE_H__
+#define __BLI_ARRAY_STORE_H__
+
+/** \file BLI_array_store.h
+ * \ingroup bli
+ * \brief Efficient in-memory storage of multiple similar arrays.
+ */
+
+typedef struct BArrayStore BArrayStore;
+typedef struct BArrayState BArrayState;
+
+BArrayStore *BLI_array_store_create(
+ unsigned int stride, unsigned int chunk_count);
+void BLI_array_store_destroy(
+ BArrayStore *bs);
+void BLI_array_store_clear(
+ BArrayStore *bs);
+
+/* find the memory used by all states (expanded & real) */
+size_t BLI_array_store_calc_size_expanded_get(
+ const BArrayStore *bs);
+size_t BLI_array_store_calc_size_compacted_get(
+ const BArrayStore *bs);
+
+BArrayState *BLI_array_store_state_add(
+ BArrayStore *bs,
+ const void *data, const size_t data_len,
+ const BArrayState *state_reference);
+void BLI_array_store_state_remove(
+ BArrayStore *bs,
+ BArrayState *state);
+
+size_t BLI_array_store_state_size_get(
+ BArrayState *state);
+void BLI_array_store_state_data_get(
+ BArrayState *state,
+ void *data);
+void *BLI_array_store_state_data_get_alloc(
+ BArrayState *state,
+ size_t *r_data_len);
+
+/* only for tests */
+bool BLI_array_store_is_valid(
+ BArrayStore *bs);
+
+#endif /* __BLI_ARRAY_STORE_H__ */
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
index b26dc3e26aa..42b11eb9a2b 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -31,28 +31,28 @@
/* only validate array-bounds in debug mode */
#ifdef DEBUG
# define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_totalloc
-# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = tot))
-# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + off <= _##stack##_totalloc))
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = (tot)))
+# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + (off) <= _##stack##_totalloc))
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc)
#else
# define STACK_DECLARE(stack) unsigned int _##stack##_index
-# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0))
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? (tot) : 0))
# define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off)
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b)
#endif
-#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)index < _##stack##_index))
+#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)(index) < _##stack##_index))
#define STACK_SIZE(stack) ((void)stack, (_##stack##_index))
#define STACK_CLEAR(stack) {(void)stack; _##stack##_index = 0; } ((void)0)
/** add item to stack */
-#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = val))
+#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = (val)))
#define STACK_PUSH_RET(stack) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++]))
#define STACK_PUSH_RET_PTR(stack) ((void)stack, _STACK_SIZETEST(stack, 1), &((stack)[(_##stack##_index)++]))
/** take last item from stack */
#define STACK_POP(stack) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : NULL)
#define STACK_POP_PTR(stack) ((_##stack##_index) ? &((stack)[--(_##stack##_index)]) : NULL)
-#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : r)
+#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : (r))
/** look at last item (assumes non-empty stack) */
#define STACK_PEEK(stack) (BLI_assert(_##stack##_index), ((stack)[_##stack##_index - 1]))
#define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1]))
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 944ba60eb58..42d958774d8 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRC
intern/BLI_memarena.c
intern/BLI_mempool.c
intern/DLRB_tree.c
+ intern/array_store.c
intern/array_utils.c
intern/astar.c
intern/boxpack2d.c
@@ -120,6 +121,7 @@ set(SRC
BLI_alloca.h
BLI_args.h
BLI_array.h
+ BLI_array_store.h
BLI_array_utils.h
BLI_astar.h
BLI_bitmap.h
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 06946e520a8..0b5adab3929 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -441,7 +441,7 @@ static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
gh->flag = flag;
ghash_buckets_reset(gh, nentries_reserve);
- gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 64, 64, BLI_MEMPOOL_NOP);
+ gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 0, 64, BLI_MEMPOOL_NOP);
return gh;
}
@@ -1287,7 +1287,7 @@ bool BLI_ghashutil_paircmp(const void *a, const void *b)
const GHashPair *A = a;
const GHashPair *B = b;
- return (BLI_ghashutil_ptrcmp(A->first, B->first) ||
+ return (BLI_ghashutil_ptrcmp(A->first, B->first) &&
BLI_ghashutil_ptrcmp(A->second, B->second));
}
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 7338804c685..38d15750761 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -57,12 +57,29 @@
#ifdef __BIG_ENDIAN__
/* Big Endian */
# define MAKE_ID(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) )
+# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
+ ((int64_t)(a) << 56 | (int64_t)(b) << 48 | (int64_t)(c) << 40 | (int64_t)(d) << 32 | \
+ (int64_t)(e) << 24 | (int64_t)(f) << 16 | (int64_t)(g) << 8 | (h) )
#else
/* Little Endian */
# define MAKE_ID(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) )
+# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
+ ((int64_t)(h) << 56 | (int64_t)(g) << 48 | (int64_t)(f) << 40 | (int64_t)(e) << 32 | \
+ (int64_t)(d) << 24 | (int64_t)(c) << 16 | (int64_t)(b) << 8 | (a) )
#endif
-#define FREEWORD MAKE_ID('f', 'r', 'e', 'e')
+/**
+ * Important that this value is an is _not_ aligned with ``sizeof(void *)``.
+ * So having a pointer to 2/4/8... aligned memory is enough to ensure the freeword will never be used.
+ * To be safe, use a word thats the same in both directions.
+ */
+#define FREEWORD ((sizeof(void *) > sizeof(int32_t)) ? \
+ MAKE_ID_8('e', 'e', 'r', 'f', 'f', 'r', 'e', 'e') : \
+ MAKE_ID('e', 'f', 'f', 'e'))
+
+/**
+ * The 'used' word just needs to be set to something besides FREEWORD.
+ */
#define USEDWORD MAKE_ID('u', 's', 'e', 'd')
/* currently totalloc isnt used */
@@ -87,7 +104,7 @@ static bool mempool_debug_memset = false;
*/
typedef struct BLI_freenode {
struct BLI_freenode *next;
- int freeword; /* used to identify this as a freed node */
+ intptr_t freeword; /* used to identify this as a freed node */
} BLI_freenode;
/**
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
new file mode 100644
index 00000000000..7f657f4a048
--- /dev/null
+++ b/source/blender/blenlib/intern/array_store.c
@@ -0,0 +1,1731 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/array_store.c
+ * \ingroup bli
+ * \brief Array storage to minimize duplication.
+ *
+ * This is done by splitting arrays into chunks and using copy-on-write (COW),
+ * to de-duplicate chunks,
+ * from the users perspective this is an implementation detail.
+ *
+ *
+ * Overview
+ * ========
+ *
+ *
+ * Data Structure
+ * --------------
+ *
+ * This diagram is an overview of the structure of a single array-store.
+ *
+ * \note The only 2 structues here which are referenced externally are the.
+ *
+ * - BArrayStore: The whole array store.
+ * - BArrayState: Represents a single state (array) of data.
+ * These can be add using a reference state, while this could be considered the previous or parent state.
+ * no relationship is kept, so the caller is free to add any state from the same BArrayStore as a reference.
+ *
+ * <pre>
+ * <+> BArrayStore: root data-structure,
+ * | can store many 'states', which share memory.
+ * |
+ * | This can store many arrays, however they must share the same 'stride'.
+ * | Arrays of different types will need to use a new BArrayStore.
+ * |
+ * +- <+> states (Collection of BArrayState's):
+ * | | Each represents an array added by the user of this API.
+ * | | and references a chunk_list (each state is a chunk_list user).
+ * | | Note that the list order has no significance.
+ * | |
+ * | +- <+> chunk_list (BChunkList):
+ * | | The chunks that make up this state.
+ * | | Each state is a chunk_list user,
+ * | | avoids duplicating lists when there is no change between states.
+ * | |
+ * | +- chunk_refs (List of BChunkRef): Each chunk_ref links to a a BChunk.
+ * | Each reference is a chunk user,
+ * | avoids duplicating smaller chunks of memory found in multiple states.
+ * |
+ * +- info (BArrayInfo):
+ * | Sizes and offsets for this array-store.
+ * | Also caches some variables for reuse.
+ * |
+ * +- <+> memory (BArrayMemory):
+ * | Memory pools for storing BArrayStore data.
+ * |
+ * +- chunk_list (Pool of BChunkList):
+ * | All chunk_lists, (reference counted, used by BArrayState).
+ * |
+ * +- chunk_ref (Pool of BChunkRef):
+ * | All chunk_refs (link between BChunkList & BChunk).
+ * |
+ * +- chunks (Pool of BChunk):
+ * All chunks, (reference counted, used by BChunkList).
+ * These have their headers hashed for reuse so we can quickly check for duplicates.
+ * </pre>
+ *
+ *
+ * De-Duplication
+ * --------------
+ *
+ * When creating a new state, a previous state can be given as a reference,
+ * matching chunks from this state are re-used in the new state.
+ *
+ * First matches at either end of the array are detected.
+ * For identical arrays this is all thats needed.
+ *
+ * De-duplication is performed on any remaining chunks, by hasing the first few bytes of the chunk
+ * (see: BCHUNK_HASH_TABLE_ACCUMULATE_STEPS).
+ *
+ * \note This is cached for reuse since the referenced data never changes.
+ *
+ * An array is created to store hash values at every 'stride',
+ * then stepped over to search for matching chunks.
+ *
+ * Once a match is found, there is a high chance next chunks match too,
+ * so this is checked to avoid performing so many hash-lookups.
+ * Otherwise new chunks are created.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+
+#include "BLI_strict_flags.h"
+
+#include "BLI_array_store.h" /* own include */
+
+/* only for BLI_array_store_is_valid */
+#include "BLI_ghash.h"
+
+/** \name Defines
+ *
+ * Some of the logic for merging is quite involved,
+ * support disabling some parts of this.
+ * \{ */
+
+/* Scan first chunks (happy path when beginning of the array matches).
+ * When the array is a perfect match, we can re-use the entire list.
+ *
+ * Note that disabling makes some tests fail that check for output-size.
+ */
+#define USE_FASTPATH_CHUNKS_FIRST
+
+/* Scan last chunks (happy path when end of the array matches).
+ * When the end of the array matches, we can quickly add these chunks.
+ * note that we will add contiguous matching chunks
+ * so this isn't as useful as USE_FASTPATH_CHUNKS_FIRST,
+ * however it avoids adding matching chunks into the lookup table,
+ * so creating the lookup table won't be as expensive.
+ */
+#ifdef USE_FASTPATH_CHUNKS_FIRST
+# define USE_FASTPATH_CHUNKS_LAST
+#endif
+
+/* For arrays of matching length, test that *enough* of the chunks are aligned,
+ * and simply step over both arrays, using matching chunks.
+ * This avoids overhead of using a lookup table for cases when we can assume they're mostly aligned.
+ */
+#define USE_ALIGN_CHUNKS_TEST
+
+/* Accumulate hashes from right to left so we can create a hash for the chunk-start.
+ * This serves to increase uniqueness and will help when there is many values which are the same.
+ */
+#define USE_HASH_TABLE_ACCUMULATE
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+/* Number of times to propagate hashes back.
+ * Effectively a 'triangle-number'.
+ * so 4 -> 7, 5 -> 10, 6 -> 15... etc.
+ */
+# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS 4
+#else
+/* How many items to hash (multiplied by stride)
+ */
+# define BCHUNK_HASH_LEN 4
+#endif
+
+/* Calculate the key once and reuse it
+ */
+#define USE_HASH_TABLE_KEY_CACHE
+#ifdef USE_HASH_TABLE_KEY_CACHE
+# define HASH_TABLE_KEY_UNSET ((uint64_t)-1)
+# define HASH_TABLE_KEY_FALLBACK ((uint64_t)-2)
+#endif
+
+/* How much larger the table is then the total number of chunks.
+ */
+#define BCHUNK_HASH_TABLE_MUL 3
+
+/* Merge too small/large chunks:
+ *
+ * Using this means chunks below a threshold will be merged together.
+ * Even though short term this uses more memory,
+ * long term the overhead of maintaining many small chunks is reduced.
+ * This is defined by setting the minimum chunk size (as a fraction of the regular chunk size).
+ *
+ * Chunks may also become too large (when incrementally growing an array),
+ * this also enables chunk splitting.
+ */
+#define USE_MERGE_CHUNKS
+
+#ifdef USE_MERGE_CHUNKS
+/* Merge chunks smaller then: (chunk_size / BCHUNK_MIN_SIZE_DIV)
+ */
+# define BCHUNK_SIZE_MIN_DIV 8
+
+/* Disallow chunks bigger then the regular chunk size scaled by this value
+ * note: must be at least 2!
+ * however, this code runs wont run in tests unless its ~1.1 ugh.
+ * so lower only to check splitting works.
+ */
+# define BCHUNK_SIZE_MAX_MUL 2
+#endif /* USE_MERGE_CHUNKS */
+
+/* slow (keep disabled), but handy for debugging */
+// #define USE_VALIDATE_LIST_SIZE
+
+// #define USE_VALIDATE_LIST_DATA_PARTIAL
+
+// #define USE_PARANOID_CHECKS
+
+/** \} */
+
+
+/** \name Internal Structs
+ * \{ */
+
+typedef unsigned int uint;
+typedef unsigned char ubyte;
+
+typedef uint64_t hash_key;
+
+
+typedef struct BArrayInfo {
+ size_t chunk_stride;
+ uint chunk_count;
+
+ /* pre-calculated */
+ size_t chunk_byte_size;
+ size_t chunk_byte_size_min;
+
+ size_t accum_read_ahead_bytes;
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ size_t accum_steps;
+ size_t accum_read_ahead_len;
+#endif
+} BArrayInfo;
+
+typedef struct BArrayMemory {
+ BLI_mempool *chunk_list; /* BChunkList */
+ BLI_mempool *chunk_ref; /* BChunkRef */
+ BLI_mempool *chunk; /* BChunk */
+} BArrayMemory;
+
+/**
+ * Main storage for all states
+ */
+typedef struct BArrayStore {
+ /* static */
+ BArrayInfo info;
+
+ /* memory storage */
+ BArrayMemory memory;
+
+ /**
+ * #BArrayState may be in any order (logic should never depend on state order).
+ */
+ ListBase states;
+} BArrayStore;
+
+/**
+ * A single instance of an array.
+ *
+ * This is how external API's hold a reference to an in-memory state,
+ * although the struct is private.
+ *
+ * \note Currently each 'state' is allocated separately.
+ * While this could be moved to a memory pool,
+ * it makes it easier to trace invalid usage, so leave as-is for now.
+ */
+typedef struct BArrayState {
+ /** linked list in #BArrayStore.states */
+ struct BArrayState *next, *prev;
+
+ struct BChunkList *chunk_list; /* BChunkList's */
+
+} BArrayState;
+
+typedef struct BChunkList {
+ ListBase chunk_refs; /* BChunkRef's */
+ uint chunk_refs_len; /* BLI_listbase_count(chunks), store for reuse. */
+ size_t total_size; /* size of all chunks */
+
+ /** number of #BArrayState using this. */
+ int users;
+} BChunkList;
+
+/* a chunk of an array */
+typedef struct BChunk {
+ const ubyte *data;
+ size_t data_len;
+ /** number of #BChunkList using this. */
+ int users;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ hash_key key;
+#endif
+} BChunk;
+
+/**
+ * Links to store #BChunk data in #BChunkList.chunks.
+ */
+typedef struct BChunkRef {
+ struct BChunkRef *next, *prev;
+ BChunk *link;
+} BChunkRef;
+
+/**
+ * Single linked list used when putting chunks into a temporary table,
+ * used for lookups.
+ *
+ * Point to the #BChunkRef, not the #BChunk,
+ * to allow talking down the chunks in-order until a mis-match is found,
+ * this avoids having to do so many table lookups.
+ */
+typedef struct BTableRef {
+ struct BTableRef *next;
+ const BChunkRef *cref;
+} BTableRef;
+
+/** \} */
+
+
+static size_t bchunk_list_size(const BChunkList *chunk_list);
+
+
+/** \name Internal BChunk API
+ * \{ */
+
+static BChunk *bchunk_new(
+ BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+{
+ BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk);
+ chunk->data = data;
+ chunk->data_len = data_len;
+ chunk->users = 0;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ chunk->key = HASH_TABLE_KEY_UNSET;
+#endif
+ return chunk;
+}
+
+static BChunk *bchunk_new_copydata(
+ BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+{
+ ubyte *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return bchunk_new(bs_mem, data_copy, data_len);
+}
+
+static void bchunk_decref(
+ BArrayMemory *bs_mem, BChunk *chunk)
+{
+ BLI_assert(chunk->users > 0);
+ if (chunk->users == 1) {
+ MEM_freeN((void *)chunk->data);
+ BLI_mempool_free(bs_mem->chunk, chunk);
+ }
+ else {
+ chunk->users -= 1;
+ }
+}
+
+static bool bchunk_data_compare(
+ const BChunk *chunk,
+ const ubyte *data_base, const size_t data_base_len,
+ const size_t offset)
+{
+ if (offset + (size_t)chunk->data_len <= data_base_len) {
+ return (memcmp(&data_base[offset], chunk->data, chunk->data_len) == 0);
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+/** \name Internal BChunkList API
+ * \{ */
+
+static BChunkList *bchunk_list_new(
+ BArrayMemory *bs_mem, size_t total_size)
+{
+ BChunkList *chunk_list = BLI_mempool_alloc(bs_mem->chunk_list);
+
+ BLI_listbase_clear(&chunk_list->chunk_refs);
+ chunk_list->chunk_refs_len = 0;
+ chunk_list->total_size = total_size;
+ chunk_list->users = 0;
+ return chunk_list;
+}
+
+static void bchunk_list_decref(
+ BArrayMemory *bs_mem, BChunkList *chunk_list)
+{
+ BLI_assert(chunk_list->users > 0);
+ if (chunk_list->users == 1) {
+ for (BChunkRef *cref = chunk_list->chunk_refs.first, *cref_next; cref; cref = cref_next) {
+ cref_next = cref->next;
+ bchunk_decref(bs_mem, cref->link);
+ BLI_mempool_free(bs_mem->chunk_ref, cref);
+ }
+
+ BLI_mempool_free(bs_mem->chunk_list, chunk_list);
+ }
+ else {
+ chunk_list->users -= 1;
+ }
+}
+
+#ifdef USE_VALIDATE_LIST_SIZE
+# ifndef NDEBUG
+# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) BLI_assert(bchunk_list_size(chunk_list) == n)
+# endif
+#endif
+#ifndef ASSERT_CHUNKLIST_SIZE
+# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) (EXPR_NOP(chunk_list), EXPR_NOP(n))
+#endif
+
+
+#ifdef USE_VALIDATE_LIST_DATA_PARTIAL
+static size_t bchunk_list_data_check(
+ const BChunkList *chunk_list, const ubyte *data)
+{
+ size_t total_size = 0;
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ if (memcmp(&data[total_size], cref->link->data, cref->link->data_len) != 0) {
+ return false;
+ }
+ total_size += cref->link->data_len;
+ }
+ return true;
+}
+# define ASSERT_CHUNKLIST_DATA(chunk_list, data) BLI_assert(bchunk_list_data_check(chunk_list, data))
+#else
+# define ASSERT_CHUNKLIST_DATA(chunk_list, data) (EXPR_NOP(chunk_list), EXPR_NOP(data))
+#endif
+
+
+#ifdef USE_MERGE_CHUNKS
+static void bchunk_list_ensure_min_size_last(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list)
+{
+ BChunkRef *cref = chunk_list->chunk_refs.last;
+ if (cref && cref->prev) {
+ /* both are decref'd after use (end of this block) */
+ BChunk *chunk_curr = cref->link;
+ BChunk *chunk_prev = cref->prev->link;
+
+ if (MIN2(chunk_prev->data_len, chunk_curr->data_len) < info->chunk_byte_size_min) {
+ const size_t data_merge_len = chunk_prev->data_len + chunk_curr->data_len;
+ /* we could pass, but no need */
+ if (data_merge_len <= (info->chunk_byte_size * BCHUNK_SIZE_MAX_MUL)) {
+ /* we have enough space to merge */
+
+ /* remove last from linklist */
+ BLI_assert(chunk_list->chunk_refs.last != chunk_list->chunk_refs.first);
+ cref->prev->next = NULL;
+ chunk_list->chunk_refs.last = cref->prev;
+ chunk_list->chunk_refs_len -= 1;
+
+ ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len);
+
+ cref->prev->link = bchunk_new(bs_mem, data_merge, data_merge_len);
+ cref->prev->link->users += 1;
+
+ BLI_mempool_free(bs_mem->chunk_ref, cref);
+ }
+ else {
+ /* If we always merge small slices, we should _almost_ never end up having very large chunks.
+ * Gradual expanding on contracting will cause this.
+ *
+ * if we do, the code below works (test by setting 'BCHUNK_SIZE_MAX_MUL = 1.2') */
+
+ /* keep chunk on the left hand side a regular size */
+ const size_t split = info->chunk_byte_size;
+
+ /* merge and split */
+ const size_t data_prev_len = split;
+ const size_t data_curr_len = data_merge_len - split;
+ ubyte *data_prev = MEM_mallocN(data_prev_len, __func__);
+ ubyte *data_curr = MEM_mallocN(data_curr_len, __func__);
+
+ if (data_prev_len <= chunk_prev->data_len) {
+ const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len;
+
+ /* setup 'data_prev' */
+ memcpy(data_prev, chunk_prev->data, data_prev_len);
+
+ /* setup 'data_curr' */
+ memcpy(data_curr, &chunk_prev->data[data_prev_len], data_curr_shrink_len);
+ memcpy(&data_curr[data_curr_shrink_len], chunk_curr->data, chunk_curr->data_len);
+ }
+ else {
+ BLI_assert(data_curr_len <= chunk_curr->data_len);
+ BLI_assert(data_prev_len >= chunk_prev->data_len);
+
+ const size_t data_prev_grow_len = data_prev_len - chunk_prev->data_len;
+
+ /* setup 'data_prev' */
+ memcpy(data_prev, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_prev[chunk_prev->data_len], chunk_curr->data, data_prev_grow_len);
+
+ /* setup 'data_curr' */
+ memcpy(data_curr, &chunk_curr->data[data_prev_grow_len], data_curr_len);
+ }
+
+ cref->prev->link = bchunk_new(bs_mem, data_prev, data_prev_len);
+ cref->prev->link->users += 1;
+
+ cref->link = bchunk_new(bs_mem, data_curr, data_curr_len);
+ cref->link->users += 1;
+ }
+
+ /* free zero users */
+ bchunk_decref(bs_mem, chunk_curr);
+ bchunk_decref(bs_mem, chunk_prev);
+ }
+ }
+}
+#endif /* USE_MERGE_CHUNKS */
+
+/**
+ * Append and don't manage merging small chunks.
+ */
+static bool bchunk_list_append_only(
+ BArrayMemory *bs_mem,
+ BChunkList *chunk_list, BChunk *chunk)
+{
+ BChunkRef *cref = BLI_mempool_alloc(bs_mem->chunk_ref);
+ BLI_addtail(&chunk_list->chunk_refs, cref);
+ cref->link = chunk;
+ chunk_list->chunk_refs_len += 1;
+ chunk->users += 1;
+ return chunk;
+}
+
+static void bchunk_list_append_data(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data, const size_t data_len)
+{
+ BLI_assert(data_len != 0);
+ // printf("data_len: %d\n", data_len);
+#ifdef USE_MERGE_CHUNKS
+ if (!BLI_listbase_is_empty(&chunk_list->chunk_refs)) {
+ BChunkRef *cref = chunk_list->chunk_refs.last;
+ BChunk *chunk_prev = cref->link;
+
+ if (MIN2(chunk_prev->data_len, data_len) < info->chunk_byte_size_min) {
+ const size_t data_merge_len = chunk_prev->data_len + data_len;
+ /* realloc for single user */
+ if (cref->link->users == 1) {
+ ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
+ memcpy(&data_merge[chunk_prev->data_len], data, data_len);
+ cref->link->data = data_merge;
+ cref->link->data_len = data_merge_len;
+ }
+ else {
+ ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_merge[chunk_prev->data_len], data, data_len);
+ cref->link = bchunk_new(bs_mem, data_merge, data_merge_len);
+ cref->link->users += 1;
+ bchunk_decref(bs_mem, chunk_prev);
+ }
+ return;
+ }
+ }
+#else
+ UNUSED_VARS(info);
+#endif /* USE_MERGE_CHUNKS */
+
+ BChunk *chunk = bchunk_new_copydata(bs_mem, data, data_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+
+ /* don't run this, instead preemptively avoid creating a chunk only to merge it (above). */
+#if 0
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list, chunk_size_min);
+#endif
+#endif
+}
+
+static void bchunk_list_append(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ BChunk *chunk)
+{
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
+#else
+ UNUSED_VARS(info);
+#endif
+}
+
+static void bchunk_list_fill_from_array(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data,
+ const size_t data_len)
+{
+ BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs));
+
+ size_t data_last_chunk_len = 0;
+ size_t data_trim_len = data_len;
+
+#ifdef USE_MERGE_CHUNKS
+ /* avoid creating too-small chunks
+ * more efficient then merging after */
+ if (data_len > info->chunk_byte_size) {
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+ if (data_last_chunk_len) {
+ if (data_last_chunk_len < info->chunk_byte_size_min) {
+ /* may be zero and thats OK */
+ data_trim_len -= info->chunk_byte_size;
+ data_last_chunk_len += info->chunk_byte_size;
+ }
+ }
+ }
+ else {
+ data_trim_len = 0;
+ data_last_chunk_len = data_len;
+ }
+#else
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+#endif
+
+
+ BLI_assert(data_trim_len + data_last_chunk_len == data_len);
+
+ size_t i_prev = 0;
+ while (i_prev < data_trim_len) {
+ const size_t i = i_prev + info->chunk_byte_size;
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ i_prev = i;
+ }
+
+ if (data_last_chunk_len) {
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ // i_prev = data_len;
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ if (data_len > info->chunk_byte_size) {
+ BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min);
+ }
+#endif
+
+ /* works but better avoid redundant re-alloc */
+#if 0
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
+#endif
+#endif
+
+ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+}
+
+
+/* ---------------------------------------------------------------------------
+ * Internal Table Lookup Functions
+ */
+
+/** \name Internal Hashing/De-Duplication API
+ *
+ * Only used by #bchunk_list_from_data_merge
+ * \{ */
+
+#define HASH_INIT (5381)
+
+BLI_INLINE uint hash_data_single(const ubyte p)
+{
+ return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p;
+}
+
+/* hash bytes, from BLI_ghashutil_strhash_n */
+static uint hash_data(const ubyte *key, size_t n)
+{
+ const signed char *p;
+ unsigned int h = HASH_INIT;
+
+ for (p = (const signed char *)key; n--; p++) {
+ h = (h << 5) + h + (unsigned int)*p;
+ }
+
+ return h;
+}
+
+#undef HASH_INIT
+
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+static void hash_array_from_data(
+ const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len,
+ hash_key *hash_array)
+{
+ if (info->chunk_stride != 1) {
+ for (size_t i = 0, i_step = 0; i_step < data_slice_len; i++, i_step += info->chunk_stride) {
+ hash_array[i] = hash_data(&data_slice[i_step], info->chunk_stride);
+ }
+ }
+ else {
+ /* fast-path for bytes */
+ for (size_t i = 0; i < data_slice_len; i++) {
+ hash_array[i] = hash_data_single(data_slice[i]);
+ }
+ }
+}
+
+/*
+ * Similar to hash_array_from_data,
+ * but able to step into the next chunk if we run-out of data.
+ */
+static void hash_array_from_cref(
+ const BArrayInfo *info, const BChunkRef *cref, const size_t data_len,
+ hash_key *hash_array)
+{
+ const size_t hash_array_len = data_len / info->chunk_stride;
+ size_t i = 0;
+ do {
+ size_t i_next = hash_array_len - i;
+ size_t data_trim_len = i_next * info->chunk_stride;
+ if (data_trim_len > cref->link->data_len) {
+ data_trim_len = cref->link->data_len;
+ i_next = data_trim_len / info->chunk_stride;
+ }
+ BLI_assert(data_trim_len <= cref->link->data_len);
+ hash_array_from_data(info, cref->link->data, data_trim_len, &hash_array[i]);
+ i += i_next;
+ cref = cref->next;
+ } while ((i < hash_array_len) && (cref != NULL));
+
+ /* If this isn't equal, the caller didn't properly check
+ * that there was enough data left in all chunks */
+ BLI_assert(i == hash_array_len);
+}
+
+static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
+{
+ /* _very_ unlikely, can happen if you select a chunk-size of 1 for example. */
+ if (UNLIKELY((iter_steps > hash_array_len))) {
+ iter_steps = hash_array_len;
+ }
+
+ const size_t hash_array_search_len = hash_array_len - iter_steps;
+ while (iter_steps != 0) {
+ const size_t hash_offset = iter_steps;
+ for (uint i = 0; i < hash_array_search_len; i++) {
+ hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
+ }
+ iter_steps -= 1;
+ }
+}
+
+/**
+ * When we only need a single value, can use a small optimization.
+ * we can avoid accumulating the tail of the array a little, each iteration.
+ */
+static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
+{
+ BLI_assert(iter_steps <= hash_array_len);
+ if (UNLIKELY(!(iter_steps <= hash_array_len))) {
+ /* while this shouldn't happen, avoid crashing */
+ iter_steps = hash_array_len;
+ }
+ /* We can increase this value each step to avoid accumulating quite as much
+ * while getting the same results as hash_accum */
+ size_t iter_steps_sub = iter_steps;
+
+ while (iter_steps != 0) {
+ const size_t hash_array_search_len = hash_array_len - iter_steps_sub;
+ const size_t hash_offset = iter_steps;
+ for (uint i = 0; i < hash_array_search_len; i++) {
+ hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
+ }
+ iter_steps -= 1;
+ iter_steps_sub += iter_steps;
+ }
+}
+
+static hash_key key_from_chunk_ref(
+ const BArrayInfo *info, const BChunkRef *cref,
+ /* avoid reallicating each time */
+ hash_key *hash_store, const size_t hash_store_len)
+{
+ /* in C, will fill in a reusable array */
+ BChunk *chunk = cref->link;
+ BLI_assert(info->accum_read_ahead_bytes * info->chunk_stride);
+
+ if (info->accum_read_ahead_bytes <= chunk->data_len) {
+ hash_key key;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ key = chunk->key;
+ if (key != HASH_TABLE_KEY_UNSET) {
+ /* Using key cache!
+ * avoids calculating every time */
+ }
+ else {
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ key = hash_store[0];
+
+ /* cache the key */
+ if (key == HASH_TABLE_KEY_UNSET) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+ chunk->key = key;
+ }
+#else
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ key = hash_store[0];
+#endif
+ return key;
+ }
+ else {
+ /* corner case - we're too small, calculate the key each time. */
+
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ hash_key key = hash_store[0];
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (UNLIKELY(key == HASH_TABLE_KEY_UNSET)) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+#endif
+ return key;
+ }
+}
+
+static const BChunkRef *table_lookup(
+ const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start,
+ const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
+{
+ size_t size_left = data_len - offset;
+ hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)];
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ const BChunkRef *cref = tref->cref;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (cref->link->key == key)
+#endif
+ {
+ BChunk *chunk_test = cref->link;
+ if (chunk_test->data_len <= size_left) {
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ /* we could remove the chunk from the table, to avoid multiple hits */
+ return cref;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#else /* USE_HASH_TABLE_ACCUMULATE */
+
+/* NON USE_HASH_TABLE_ACCUMULATE code (simply hash each chunk) */
+
+static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref)
+{
+ const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride;
+ hash_key key;
+ BChunk *chunk = cref->link;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ key = chunk->key;
+ if (key != HASH_TABLE_KEY_UNSET) {
+ /* Using key cache!
+ * avoids calculating every time */
+ }
+ else {
+ /* cache the key */
+ key = hash_data(chunk->data, data_hash_len);
+ if (key == HASH_TABLE_KEY_UNSET) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+ chunk->key = key;
+ }
+#else
+ key = hash_data(chunk->data, data_hash_len);
+#endif
+
+ return key;
+}
+
+static const BChunkRef *table_lookup(
+ const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start),
+ const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
+{
+ const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */
+
+ size_t size_left = data_len - offset;
+ hash_key key = hash_data(&data[offset], MIN2(data_hash_len, size_left));
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ const BChunkRef *cref = tref->cref;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (cref->link->key == key)
+#endif
+ {
+ BChunk *chunk_test = cref->link;
+ if (chunk_test->data_len <= size_left) {
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ /* we could remove the chunk from the table, to avoid multiple hits */
+ return cref;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#endif /* USE_HASH_TABLE_ACCUMULATE */
+
+/* End Table Lookup
+ * ---------------- */
+
+/** \} */
+
+/**
+ * \param data: Data to store in the returned value.
+ * \param data_len_original: Length of data in bytes.
+ * \param chunk_list_reference: Reuse this list or chunks within it, don't modify its content.
+ * \note Caller is responsible for adding the user.
+ */
+static BChunkList *bchunk_list_from_data_merge(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ const ubyte *data, const size_t data_len_original,
+ const BChunkList *chunk_list_reference)
+{
+ ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
+
+ /* -----------------------------------------------------------------------
+ * Fast-Path for exact match
+ * Check for exact match, if so, return the current list.
+ */
+
+ const BChunkRef *cref_match_first = NULL;
+
+ uint chunk_list_reference_skip_len = 0;
+ size_t chunk_list_reference_skip_bytes = 0;
+ size_t i_prev = 0;
+
+#ifdef USE_FASTPATH_CHUNKS_FIRST
+ bool full_match = false;
+
+ {
+ full_match = true;
+
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
+ while (i_prev < data_len_original) {
+ if (cref != NULL && bchunk_data_compare(cref->link, data, data_len_original, i_prev)) {
+ cref_match_first = cref;
+ chunk_list_reference_skip_len += 1;
+ chunk_list_reference_skip_bytes += cref->link->data_len;
+ i_prev += cref->link->data_len;
+ cref = cref->next;
+ }
+ else {
+ full_match = false;
+ break;
+ }
+ }
+
+ if (full_match) {
+ if (chunk_list_reference->total_size == data_len_original) {
+ return (BChunkList *)chunk_list_reference;
+ }
+ }
+ }
+
+ /* End Fast-Path (first)
+ * --------------------- */
+
+#endif /* USE_FASTPATH_CHUNKS_FIRST */
+
+ /* Copy until we have a mismatch */
+ BChunkList *chunk_list = bchunk_list_new(bs_mem, data_len_original);
+ if (cref_match_first != NULL) {
+ size_t chunk_size_step = 0;
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
+ while (true) {
+ BChunk *chunk = cref->link;
+ chunk_size_step += chunk->data_len;
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, chunk_size_step);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ if (cref == cref_match_first) {
+ break;
+ }
+ else {
+ cref = cref->next;
+ }
+ }
+ /* happens when bytes are removed from the end of the array */
+ if (chunk_size_step == data_len_original) {
+ return chunk_list;
+ }
+
+ i_prev = chunk_size_step;
+ }
+ else {
+ i_prev = 0;
+ }
+
+ /* ------------------------------------------------------------------------
+ * Fast-Path for end chunks
+ *
+ * Check for trailing chunks
+ */
+
+ /* In this case use 'chunk_list_reference_last' to define the last index
+ * index_match_last = -1 */
+
+ /* warning, from now on don't use len(data)
+ * since we want to ignore chunks already matched */
+ size_t data_len = data_len_original;
+#define data_len_original invalid_usage
+#ifdef data_len_original /* quiet warning */
+#endif
+
+ const BChunkRef *chunk_list_reference_last = NULL;
+
+#ifdef USE_FASTPATH_CHUNKS_LAST
+ if (!BLI_listbase_is_empty(&chunk_list_reference->chunk_refs)) {
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.last;
+ while ((cref->prev != NULL) &&
+ (cref != cref_match_first) &&
+ (cref->link->data_len <= data_len - i_prev))
+ {
+ BChunk *chunk_test = cref->link;
+ size_t offset = data_len - chunk_test->data_len;
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ data_len = offset;
+ chunk_list_reference_last = cref;
+ chunk_list_reference_skip_len += 1;
+ chunk_list_reference_skip_bytes += cref->link->data_len;
+ cref = cref->prev;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ /* End Fast-Path (last)
+ * -------------------- */
+#endif /* USE_FASTPATH_CHUNKS_LAST */
+
+ /* -----------------------------------------------------------------------
+ * Check for aligned chunks
+ *
+ * This saves a lot of searching, so use simple heuristics to detect aligned arrays.
+ * (may need to tweak exact method).
+ */
+
+ bool use_aligned = false;
+
+#ifdef USE_ALIGN_CHUNKS_TEST
+ if (chunk_list->total_size == chunk_list_reference->total_size) {
+ /* if we're already a quarter aligned */
+ if (data_len - i_prev <= chunk_list->total_size / 4) {
+ use_aligned = true;
+ }
+ else {
+ /* TODO, walk over chunks and check if some arbitrary amount align */
+ }
+ }
+#endif /* USE_ALIGN_CHUNKS_TEST */
+
+ /* End Aligned Chunk Case
+ * ----------------------- */
+
+ if (use_aligned) {
+ /* Copy matching chunks, creates using the same 'layout' as the reference */
+ const BChunkRef *cref = cref_match_first ? cref_match_first->next : chunk_list_reference->chunk_refs.first;
+ while (i_prev != data_len) {
+ const size_t i = i_prev + cref->link->data_len;
+ BLI_assert(i != i_prev);
+
+ if ((cref != chunk_list_reference_last) &&
+ bchunk_data_compare(cref->link, data, data_len, i_prev))
+ {
+ bchunk_list_append(info, bs_mem, chunk_list, cref->link);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+ else {
+ bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+
+ cref = cref->next;
+
+ i_prev = i;
+ }
+ }
+ else if ((data_len - i_prev >= info->chunk_byte_size) &&
+ (chunk_list_reference->chunk_refs_len >= chunk_list_reference_skip_len) &&
+ (chunk_list_reference->chunk_refs.first != NULL))
+ {
+
+ /* --------------------------------------------------------------------
+ * Non-Aligned Chunk De-Duplication */
+
+ /* only create a table if we have at least one chunk to search
+ * otherwise just make a new one.
+ *
+ * Support re-arranged chunks */
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ size_t i_table_start = i_prev;
+ const size_t table_hash_array_len = (data_len - i_prev) / info->chunk_stride;
+ hash_key *table_hash_array = MEM_mallocN(sizeof(*table_hash_array) * table_hash_array_len, __func__);
+ hash_array_from_data(info, &data[i_prev], data_len - i_prev, table_hash_array);
+
+ hash_accum(table_hash_array, table_hash_array_len, info->accum_steps);
+#else
+ /* dummy vars */
+ uint i_table_start = 0;
+ hash_key *table_hash_array = NULL;
+#endif
+
+ const uint chunk_list_reference_remaining_len =
+ (chunk_list_reference->chunk_refs_len - chunk_list_reference_skip_len) + 1;
+ BTableRef *table_ref_stack = MEM_mallocN(chunk_list_reference_remaining_len * sizeof(BTableRef), __func__);
+ uint table_ref_stack_n = 0;
+
+ const size_t table_len = chunk_list_reference_remaining_len * BCHUNK_HASH_TABLE_MUL;
+ BTableRef **table = MEM_callocN(table_len * sizeof(*table), __func__);
+
+ /* table_make - inline
+ * include one matching chunk, to allow for repeating values */
+ {
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ const size_t hash_store_len = info->accum_read_ahead_len;
+ hash_key *hash_store = MEM_mallocN(sizeof(hash_key) * hash_store_len, __func__);
+#endif
+
+ const BChunkRef *cref;
+ size_t chunk_list_reference_bytes_remaining =
+ chunk_list_reference->total_size - chunk_list_reference_skip_bytes;
+
+ if (cref_match_first) {
+ cref = cref_match_first;
+ chunk_list_reference_bytes_remaining += cref->link->data_len;
+ }
+ else {
+ cref = chunk_list_reference->chunk_refs.first;
+ }
+
+#ifdef USE_PARANOID_CHECKS
+ {
+ size_t test_bytes_len = 0;
+ const BChunkRef *cr = cref;
+ while (cr != chunk_list_reference_last) {
+ test_bytes_len += cr->link->data_len;
+ cr = cr->next;
+ }
+ BLI_assert(test_bytes_len == chunk_list_reference_bytes_remaining);
+ }
+#endif
+
+ while ((cref != chunk_list_reference_last) &&
+ (chunk_list_reference_bytes_remaining >= info->accum_read_ahead_bytes))
+ {
+ hash_key key = key_from_chunk_ref(info, cref
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ , hash_store, hash_store_len
+#endif
+ );
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ BTableRef *tref_prev = table[key_index];
+ BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len);
+ BTableRef *tref = &table_ref_stack[table_ref_stack_n++];
+ tref->cref = cref;
+ tref->next = tref_prev;
+ table[key_index] = tref;
+
+ chunk_list_reference_bytes_remaining -= cref->link->data_len;
+ cref = cref->next;
+ }
+
+ BLI_assert(table_ref_stack_n <= chunk_list_reference_remaining_len);
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ MEM_freeN(hash_store);
+#endif
+ }
+ /* done making the table */
+
+ BLI_assert(i_prev <= data_len);
+ for (size_t i = i_prev; i < data_len; ) {
+ /* Assumes exiting chunk isnt a match! */
+
+ const BChunkRef *cref_found = table_lookup(
+ info,
+ table, table_len, i_table_start,
+ data, data_len, i, table_hash_array);
+ if (cref_found != NULL) {
+ BLI_assert(i < data_len);
+ if (i != i_prev) {
+ size_t i_step = MIN2(i_prev + info->chunk_byte_size, data_len);
+ BLI_assert(i_step <= data_len);
+
+ while (i_prev != i) {
+ i_step = MIN2(i_step, i);
+ const ubyte *data_slice = &data[i_prev];
+ const size_t data_slice_len = i_step - i_prev;
+ /* First add all previous chunks! */
+ i_prev += data_slice_len;
+ bchunk_list_append_data(info, bs_mem, chunk_list, data_slice, data_slice_len);
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ i_step += info->chunk_byte_size;
+ }
+ }
+
+ /* now add the reference chunk */
+ {
+ BChunk *chunk_found = cref_found->link;
+ i += chunk_found->data_len;
+ bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
+ }
+ i_prev = i;
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ /* its likely that the next chunk in the list will be a match, so check it! */
+ while ((cref_found->next != NULL) &&
+ (cref_found->next != chunk_list_reference_last))
+ {
+ cref_found = cref_found->next;
+ BChunk *chunk_found = cref_found->link;
+
+ if (bchunk_data_compare(chunk_found, data, data_len, i_prev)) {
+ /* may be useful to remove table data, assuming we dont have repeating memory
+ * where it would be useful to re-use chunks. */
+ i += chunk_found->data_len;
+ bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
+ /* chunk_found may be freed! */
+ i_prev = i;
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ else {
+ i = i + info->chunk_stride;
+ }
+ }
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ MEM_freeN(table_hash_array);
+#endif
+ MEM_freeN(table);
+ MEM_freeN(table_ref_stack);
+
+ /* End Table Lookup
+ * ---------------- */
+ }
+
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ /* -----------------------------------------------------------------------
+ * No Duplicates to copy, write new chunks
+ *
+ * Trailing chunks, no matches found in table lookup above.
+ * Write all new data. */
+ BLI_assert(i_prev <= data_len);
+ while (i_prev != data_len) {
+ size_t i = i_prev + info->chunk_byte_size;
+ i = MIN2(i, data_len);
+ BLI_assert(i != i_prev);
+ bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ i_prev = i;
+ }
+
+ BLI_assert(i_prev == data_len);
+
+#ifdef USE_FASTPATH_CHUNKS_LAST
+ if (chunk_list_reference_last != NULL) {
+ /* write chunk_list_reference_last since it hasn't been written yet */
+ const BChunkRef *cref = chunk_list_reference_last;
+ while (cref != NULL) {
+ BChunk *chunk = cref->link;
+ // BLI_assert(bchunk_data_compare(chunk, data, data_len, i_prev));
+ i_prev += chunk->data_len;
+ /* use simple since we assume the references chunks have already been sized correctly. */
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ cref = cref->next;
+ }
+ }
+#endif
+
+#undef data_len_original
+
+ BLI_assert(i_prev == data_len_original);
+
+ /* check we're the correct size and that we didn't accidentally modify the reference */
+ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len_original);
+ ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
+
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ return chunk_list;
+}
+/* end private API */
+
+/** \} */
+
+
+/** \name Main Array Storage API
+ * \{ */
+
+
+/**
+ * Create a new array store, which can store any number of arrays
+ * as long as their stride matches.
+ *
+ * \param stride: ``sizeof()`` each element,
+ *
+ * \note while a stride of ``1`` will always work,
+ * its less efficient since duplicate chunks of memory will be searched
+ * at positions unaligned with the array data.
+ *
+ * \param chunk_count: Number of elements to split each chunk into.
+ * - A small value increases the ability to de-duplicate chunks,
+ * but adds overhead by increasing the number of chunks to look-up when searching for duplicates,
+ * as well as some overhead constructing the original array again, with more calls to ``memcpy``.
+ * - Larger values reduce the *book keeping* overhead,
+ * but increase the chance a small, isolated change will cause a larger amount of data to be duplicated.
+ *
+ * \return A new array store, to be freed with #BLI_array_store_destroy.
+ */
+BArrayStore *BLI_array_store_create(
+ uint stride,
+ uint chunk_count)
+{
+ BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
+
+ bs->info.chunk_stride = stride;
+ bs->info.chunk_count = chunk_count;
+
+ bs->info.chunk_byte_size = chunk_count * stride;
+#ifdef USE_MERGE_CHUNKS
+ bs->info.chunk_byte_size_min = MAX2(1u, chunk_count / BCHUNK_SIZE_MIN_DIV) * stride;
+#endif
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS - 1;
+ /* Triangle number, identifying now much read-ahead we need:
+ * https://en.wikipedia.org/wiki/Triangular_number (+ 1) */
+ bs->info.accum_read_ahead_len = (uint)((((bs->info.accum_steps * (bs->info.accum_steps + 1))) / 2) + 1);
+ bs->info.accum_read_ahead_bytes = bs->info.accum_read_ahead_len * stride;
+#else
+ bs->info.accum_read_ahead_bytes = BCHUNK_HASH_LEN * stride;
+#endif
+
+ bs->memory.chunk_list = BLI_mempool_create(sizeof(BChunkList), 0, 512, BLI_MEMPOOL_NOP);
+ bs->memory.chunk_ref = BLI_mempool_create(sizeof(BChunkRef), 0, 512, BLI_MEMPOOL_NOP);
+ /* allow iteration to simplify freeing, otherwise its not needed
+ * (we could loop over all states as an alternative). */
+ bs->memory.chunk = BLI_mempool_create(sizeof(BChunk), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+
+ return bs;
+}
+
+static void array_store_free_data(BArrayStore *bs)
+{
+ /* free chunk data */
+ {
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ BLI_assert(chunk->users > 0);
+ MEM_freeN((void *)chunk->data);
+ }
+ }
+
+ /* free states */
+ for (BArrayState *state = bs->states.first, *state_next; state; state = state_next) {
+ state_next = state->next;
+ MEM_freeN(state);
+ }
+}
+
+/**
+ * Free the #BArrayStore, including all states and chunks.
+ */
+void BLI_array_store_destroy(
+ BArrayStore *bs)
+{
+ array_store_free_data(bs);
+
+ BLI_mempool_destroy(bs->memory.chunk_list);
+ BLI_mempool_destroy(bs->memory.chunk_ref);
+ BLI_mempool_destroy(bs->memory.chunk);
+
+ MEM_freeN(bs);
+}
+
+/**
+ * Clear all contents, allowing reuse of \a bs.
+ */
+void BLI_array_store_clear(
+ BArrayStore *bs)
+{
+ array_store_free_data(bs);
+
+ BLI_listbase_clear(&bs->states);
+
+ BLI_mempool_clear(bs->memory.chunk_list);
+ BLI_mempool_clear(bs->memory.chunk_ref);
+ BLI_mempool_clear(bs->memory.chunk);
+}
+
+/** \name BArrayStore Statistics
+ * \{ */
+
+/**
+ * \return the total amount of memory that would be used by getting the arrays for all states.
+ */
+size_t BLI_array_store_calc_size_expanded_get(
+ const BArrayStore *bs)
+{
+ size_t size_accum = 0;
+ for (const BArrayState *state = bs->states.first; state; state = state->next) {
+ size_accum += state->chunk_list->total_size;
+ }
+ return size_accum;
+}
+
+/**
+ * \return the amount of memory used by all #BChunk.data
+ * (duplicate chunks are only counted once).
+ */
+size_t BLI_array_store_calc_size_compacted_get(
+ const BArrayStore *bs)
+{
+ size_t size_total = 0;
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ BLI_assert(chunk->users > 0);
+ size_total += (size_t)chunk->data_len;
+ }
+ return size_total;
+}
+
+/** \} */
+
+
+/** \name BArrayState Access
+ * \{ */
+
+/**
+ *
+ * \param data: Data used to create
+ * \param state_reference: The state to use as a reference when adding the new state,
+ * typically this is the previous state,
+ * however it can be any previously created state from this \a bs.
+ *
+ * \return The new state, which is used by the caller as a handle to get back the contents of \a data.
+ * This may be removed using #BLI_array_store_state_remove,
+ * otherwise it will be removed with #BLI_array_store_destroy.
+ */
+BArrayState *BLI_array_store_state_add(
+ BArrayStore *bs,
+ const void *data, const size_t data_len,
+ const BArrayState *state_reference)
+{
+ /* ensure we're aligned to the stride */
+ BLI_assert((data_len % bs->info.chunk_stride) == 0);
+
+#ifdef USE_PARANOID_CHECKS
+ if (state_reference) {
+ BLI_assert(BLI_findindex(&bs->states, state_reference) != -1);
+ }
+#endif
+
+ BChunkList *chunk_list;
+ if (state_reference) {
+ chunk_list = bchunk_list_from_data_merge(
+ &bs->info, &bs->memory,
+ (const ubyte *)data, data_len,
+ /* re-use reference chunks */
+ state_reference->chunk_list);
+ }
+ else {
+ chunk_list = bchunk_list_new(&bs->memory, data_len);
+ bchunk_list_fill_from_array(
+ &bs->info, &bs->memory,
+ chunk_list,
+ (const ubyte *)data, data_len);
+ }
+
+ chunk_list->users += 1;
+
+ BArrayState *state = MEM_callocN(sizeof(BArrayState), __func__);
+ state->chunk_list = chunk_list;
+
+ BLI_addtail(&bs->states, state);
+
+#ifdef USE_PARANOID_CHECKS
+ {
+ size_t data_test_len;
+ void *data_test = BLI_array_store_state_data_get_alloc(state, &data_test_len);
+ BLI_assert(data_test_len == data_len);
+ BLI_assert(memcmp(data_test, data, data_len) == 0);
+ MEM_freeN(data_test);
+ }
+#endif
+
+ return state;
+}
+
+/**
+ * Remove a state and free any unused #BChunk data.
+ *
+ * The states can be freed in any order.
+ */
+void BLI_array_store_state_remove(
+ BArrayStore *bs,
+ BArrayState *state)
+{
+#ifdef USE_PARANOID_CHECKS
+ BLI_assert(BLI_findindex(&bs->states, state) != -1);
+#endif
+
+ bchunk_list_decref(&bs->memory, state->chunk_list);
+ BLI_remlink(&bs->states, state);
+
+ MEM_freeN(state);
+}
+
+/**
+ * \return the expanded size of the array,
+ * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
+ */
+size_t BLI_array_store_state_size_get(
+ BArrayState *state)
+{
+ return state->chunk_list->total_size;
+}
+
+/**
+ * Fill in existing allocated memory with the contents of \a state.
+ */
+void BLI_array_store_state_data_get(
+ BArrayState *state,
+ void *data)
+{
+#ifdef USE_PARANOID_CHECKS
+ size_t data_test_len = 0;
+ for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ data_test_len += cref->link->data_len;
+ }
+ BLI_assert(data_test_len == state->chunk_list->total_size);
+#endif
+
+ ubyte *data_step = (ubyte *)data;
+ for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ BLI_assert(cref->link->users > 0);
+ memcpy(data_step, cref->link->data, cref->link->data_len);
+ data_step += cref->link->data_len;
+ }
+}
+
+/**
+ * Allocate an array for \a state and return it.
+ */
+void *BLI_array_store_state_data_get_alloc(
+ BArrayState *state,
+ size_t *r_data_len)
+{
+ void *data = MEM_mallocN(state->chunk_list->total_size, __func__);
+ BLI_array_store_state_data_get(state, data);
+ *r_data_len = state->chunk_list->total_size;
+ return data;
+}
+
+/** \} */
+
+
+/** \name Debigging API (for testing).
+ * \{ */
+
+/* only for test validation */
+static size_t bchunk_list_size(const BChunkList *chunk_list)
+{
+ size_t total_size = 0;
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ total_size += cref->link->data_len;
+ }
+ return total_size;
+}
+
+bool BLI_array_store_is_valid(
+ BArrayStore *bs)
+{
+ bool ok = true;
+
+ /* Check Length
+ * ------------ */
+
+ for (BArrayState *state = bs->states.first; state; state = state->next) {
+ BChunkList *chunk_list = state->chunk_list;
+ if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) {
+ return false;
+ }
+ }
+
+ {
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ if (!(MEM_allocN_len(chunk->data) >= chunk->data_len)) {
+ return false;
+ }
+ }
+ }
+
+ /* Check User Count & Lost References
+ * ---------------------------------- */
+ {
+ GHashIterator gh_iter;
+
+#define GHASH_PTR_ADD_USER(gh, pt) \
+ { \
+ void **val; \
+ if (BLI_ghash_ensure_p((gh), (pt), &val)) { \
+ *((int *)val) += 1; \
+ } \
+ else { \
+ *((int *)val) = 1; \
+ } \
+ } ((void)0)
+
+
+ /* count chunk_list's */
+ int totrefs = 0;
+ GHash *chunk_list_map = BLI_ghash_ptr_new(__func__);
+ for (BArrayState *state = bs->states.first; state; state = state->next) {
+ GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list);
+ }
+ GHASH_ITER (gh_iter, chunk_list_map) {
+ const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
+ const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
+ if (!(chunk_list->users == users)) {
+ ok = false;
+ goto user_finally;
+ }
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk_list) == (int)BLI_ghash_size(chunk_list_map))) {
+ ok = false;
+ goto user_finally;
+ }
+
+ /* count chunk's */
+ GHash *chunk_map = BLI_ghash_ptr_new(__func__);
+ GHASH_ITER (gh_iter, chunk_list_map) {
+ const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
+ for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ GHASH_PTR_ADD_USER(chunk_map, cref->link);
+ totrefs += 1;
+ }
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk) == (int)BLI_ghash_size(chunk_map))) {
+ ok = false;
+ goto user_finally;
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk_ref) == totrefs)) {
+ ok = false;
+ goto user_finally;
+ }
+
+ GHASH_ITER (gh_iter, chunk_map) {
+ const struct BChunk *chunk = BLI_ghashIterator_getKey(&gh_iter);
+ const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
+ if (!(chunk->users == users)) {
+ ok = false;
+ goto user_finally;
+ }
+ }
+
+#undef GHASH_PTR_ADD_USER
+
+user_finally:
+ BLI_ghash_free(chunk_list_map, NULL, NULL);
+ BLI_ghash_free(chunk_map, NULL, NULL);
+ }
+
+
+ return ok;
+ /* TODO, dangling pointer checks */
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index c3a0c44d7c5..f834c5b4c74 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1048,8 +1048,8 @@ static float noise3_perlin(float vec[3])
b01 = p[i + by1];
b11 = p[j + by1];
-#define VALUE_AT(rx, ry, rz) (rx * q[0] + ry * q[1] + rz * q[2])
-#define SURVE(t) (t * t * (3.0f - 2.0f * t))
+#define VALUE_AT(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2])
+#define SURVE(t) ((t) * (t) * (3.0f - 2.0f * (t)))
/* lerp moved to improved perlin above */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 7b102c9283b..bb61f66e267 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -804,10 +804,10 @@ void BM_mesh_bm_to_me(
BMEditSelection *selected;
me->totselect = BLI_listbase_count(&(bm->selected));
- if (me->mselect) MEM_freeN(me->mselect);
-
- me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
-
+ MEM_SAFE_FREE(me->mselect);
+ if (me->totselect != 0) {
+ me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+ }
for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
if (selected->htype == BM_VERT) {
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 5a7788c0b62..f7e3622e53c 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -345,6 +345,36 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
return NULL;
}
+/* return count of edges between e1 and e2 when going around bv CCW */
+static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
+{
+ int cnt = 0;
+ EdgeHalf *e = e1;
+
+ do {
+ if (e == e2)
+ break;
+ e = e->next;
+ cnt++;
+ } while (e != e1);
+ return cnt;
+}
+
+/* Assume bme1 and bme2 both share some vert. Do they share a face?
+ * If they share a face then there is some loop around bme1 that is in a face
+ * where the next or previous edge in the face must be bme2. */
+static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2)
+{
+ BMLoop *l;
+ BMIter iter;
+
+ BM_ITER_ELEM(l, &iter, bme1, BM_LOOPS_OF_EDGE) {
+ if (l->prev->e == bme2 || l->next->e == bme2)
+ return true;
+ }
+ return false;
+}
+
/* Return a good representative face (for materials, etc.) for faces
* created around/near BoundVert v.
* Sometimes care about a second choice, if there is one.
@@ -1557,7 +1587,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
if (construct) {
v = add_new_bound_vert(bp->mem_arena, vm, co);
v->efirst = v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1637,7 +1667,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
v->efirst = e->prev;
v->elast = v->ebev = e;
e->leftv = v;
- e->prev->leftv = v;
+ e->prev->leftv = e->prev->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1648,7 +1678,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
e->prev->rightv = v;
}
else {
@@ -1661,7 +1691,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -3237,6 +3267,11 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
if (!weld)
create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
}
+ else if (n == 2 && !v->ebev && vm->mesh_kind != M_ADJ) {
+ /* case of one edge beveled and this is the v without ebev */
+ /* want to copy the verts from other v, in reverse order */
+ copy_mesh_vert(vm, i, 0, k, 1 - i, 0, ns - k);
+ }
}
} while ((v = v->next) != vm->boundstart);
@@ -3305,6 +3340,219 @@ static float edge_face_angle(EdgeHalf *e)
#define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE( (bme), _FLAG_OVERLAP)
#define BM_BEVEL_EDGE_TAG_TEST(bme) BM_ELEM_API_FLAG_TEST( (bme), _FLAG_OVERLAP)
+/* Try to extend the bv->edges[] array beyond i by finding more successor edges.
+ * This is a possibly exponential-time search, but it is only exponential in the number
+ * of "internal faces" at a vertex -- i.e., faces that bridge between the edges that naturally
+ * form a manifold cap around bv. It is rare to have more than one of these, so unlikely
+ * that the exponential time case will be hit in practice.
+ * Returns the new index i' where bv->edges[i'] ends the best path found.
+ * The path will have the tags of all of its edges set. */
+static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
+{
+ BMEdge *bme, *bme2, *nextbme;
+ BMLoop *l;
+ BMIter iter;
+ int j, tryj, bestj, nsucs, sucindex, k;
+ BMEdge **sucs = NULL;
+ BMEdge **save_path = NULL;
+ BLI_array_staticdeclare(sucs, 4); /* likely very few faces attached to same edge */
+ BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE);
+
+ bme = bv->edges[i].e;
+ /* fill sucs with all unmarked edges of bmes */
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ BLI_array_append(sucs, bme2);
+ }
+ }
+ nsucs = BLI_array_count(sucs);
+
+ bestj = j = i;
+ for (sucindex = 0; sucindex < nsucs; sucindex++) {
+ nextbme = sucs[sucindex];
+ BLI_assert(nextbme != NULL);
+ BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme));
+ BLI_assert(j + 1 < bv->edgecount);
+ bv->edges[j + 1].e = nextbme;
+ BM_BEVEL_EDGE_TAG_ENABLE(nextbme);
+ tryj = bevel_edge_order_extend(bm, bv, j + 1);
+ if (tryj > bestj || (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) {
+ bestj = tryj;
+ BLI_array_empty(save_path);
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_array_append(save_path, bv->edges[k].e);
+ }
+ }
+ /* now reset to path only-going-to-j state */
+ for (k = j + 1; k <= tryj; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ }
+ /* at this point we should be back at invariant on entrance: path up to j */
+ if (bestj > j) {
+ /* save_path should have from j + 1 to bestj inclusive edges to add to edges[] before returning */
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_assert(save_path[k - (j + 1)] != NULL);
+ bv->edges[k].e = save_path[k - (j + 1)];
+ BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e);
+ }
+ }
+ BLI_array_free(sucs);
+ BLI_array_free(save_path);
+ return bestj;
+}
+
+/* See if we have usual case for bevel edge order:
+ * there is an ordering such that all the faces are between
+ * successive edges and form a manifold "cap" at bv.
+ * If this is the case, set bv->edges to such an order
+ * and return true; else return unmark any partial path and return false.
+ * Assume the first edge is already in bv->edges[0].e and it is tagged. */
+#ifdef FASTER_FASTORDER
+/* The alternative older code is O(n^2) where n = # of edges incident to bv->v.
+ * This implementation is O(n * m) where m = average number of faces attached to an edge incident to bv->v,
+ * which is almost certainly a small constant except in very strange cases. But this code produces different
+ * choices of ordering than the legacy system, leading to differences in vertex orders etc. in user models,
+ * so for now will continue to use the legacy code. */
+static bool fast_bevel_edge_order(BevVert *bv)
+{
+ int j, k, nsucs;
+ BMEdge *bme, *bme2, *bmenext;
+ BMIter iter;
+ BMLoop *l;
+
+ for (j = 1; j < bv->edgecount; j++) {
+ bme = bv->edges[j - 1].e;
+ bmenext = NULL;
+ nsucs = 0;
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ nsucs++;
+ if (bmenext == NULL)
+ bmenext = bme2;
+ }
+ }
+ if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 ||
+ (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e)))
+ {
+ for (k = 1; k < j; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ bv->edges[j].e = bmenext;
+ BM_BEVEL_EDGE_TAG_ENABLE(bmenext);
+ }
+ return true;
+}
+#else
+static bool fast_bevel_edge_order(BevVert *bv)
+{
+ BMEdge *bme, *bme2, *first_suc;
+ BMIter iter, iter2;
+ BMFace *f;
+ EdgeHalf *e;
+ int i, k, ntot, num_shared_face;
+
+ ntot = bv->edgecount;
+
+ /* add edges to bv->edges in order that keeps adjacent edges sharing
+ * a unique face, if possible */
+ e = &bv->edges[0];
+ bme = e->e;
+ if (!bme->l)
+ return false;
+ for (i = 1; i < ntot; i++) {
+ /* find an unflagged edge bme2 that shares a face f with previous bme */
+ num_shared_face = 0;
+ first_suc = NULL; /* keep track of first successor to match legacy behavior */
+ BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme2))
+ continue;
+ BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
+ if (BM_face_edge_share_loop(f, bme)) {
+ num_shared_face++;
+ if (first_suc == NULL)
+ first_suc = bme2;
+ }
+ }
+ if (num_shared_face >= 3)
+ break;
+ }
+ if (num_shared_face == 1 || (i == 1 && num_shared_face == 2)) {
+ e = &bv->edges[i];
+ e->e = bme = first_suc;
+ BM_BEVEL_EDGE_TAG_ENABLE(bme);
+ }
+ else {
+ for (k = 1; k < i; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+#endif
+
+/* Fill in bv->edges with a good ordering of non-wire edges around bv->v.
+ * Use only edges where BM_BEVEL_EDGE_TAG is disabled so far
+ * (if edge beveling, others are wire).
+ * first_bme is a good edge to start with.*/
+static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
+{
+ BMEdge *bme, *bme2;
+ BMIter iter;
+ BMFace *f;
+ EdgeHalf *e;
+ EdgeHalf *e2;
+ BMLoop *l;
+ int i, ntot;
+
+ ntot = bv->edgecount;
+ i = 0;
+ for (;;) {
+ BLI_assert(first_bme != NULL);
+ bv->edges[i].e = first_bme;
+ BM_BEVEL_EDGE_TAG_ENABLE(first_bme);
+ if (fast_bevel_edge_order(bv))
+ break;
+ i = bevel_edge_order_extend(bm, bv, i);
+ i++;
+ if (i >= bv->edgecount)
+ break;
+ /* Not done yet: find a new first_bme */
+ first_bme = NULL;
+ BM_ITER_ELEM(bme, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme))
+ continue;
+ if (!first_bme)
+ first_bme = bme;
+ if (BM_edge_face_count(bme) == 1) {
+ first_bme = bme;
+ break;
+ }
+ }
+ }
+ /* now fill in the faces ... */
+ for (i = 0; i < ntot; i++) {
+ e = &bv->edges[i];
+ e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1];
+ bme = e->e;
+ bme2 = e2->e;
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ f = l->f;
+ if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev)
+ e->fnext = e2->fprev = f;
+ }
+ }
+}
+
/*
* Construction around the vertex
*/
@@ -3312,13 +3560,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
{
BMEdge *bme;
BevVert *bv;
- BMEdge *bme2, *unflagged_bme, *first_bme;
- BMFace *f;
+ BMEdge *first_bme;
BMVert *v1, *v2;
- BMIter iter, iter2;
+ BMIter iter;
EdgeHalf *e;
float weight, z;
- int i, found_shared_face, ccw_test_sum;
+ int i, ccw_test_sum;
int nsel = 0;
int ntot = 0;
int nwire = 0;
@@ -3398,47 +3645,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
BLI_ghash_insert(bp->vert_hash, v, bv);
- /* add edges to bv->edges in order that keeps adjacent edges sharing
- * a face, if possible */
- i = 0;
+ find_bevel_edge_order(bm, bv, first_bme);
- bme = first_bme;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
- e = &bv->edges[0];
- e->e = bme;
+ /* fill in other attributes of EdgeHalfs */
for (i = 0; i < ntot; i++) {
- if (i > 0) {
- /* find an unflagged edge bme2 that shares a face f with previous bme */
- found_shared_face = 0;
- unflagged_bme = NULL;
- BM_ITER_ELEM (bme2, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_BEVEL_EDGE_TAG_TEST(bme2))
- continue;
- if (!unflagged_bme)
- unflagged_bme = bme2;
- if (!bme->l)
- continue;
- BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
- if (BM_face_edge_share_loop(f, bme)) {
- found_shared_face = 1;
- break;
- }
- }
- if (found_shared_face)
- break;
- }
- e = &bv->edges[i];
- if (found_shared_face) {
- e->e = bme2;
- e->fprev = f;
- bv->edges[i - 1].fnext = f;
- }
- else {
- e->e = unflagged_bme;
- }
- }
+ e = &bv->edges[i];
bme = e->e;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
e->is_bev = true;
e->seg = bp->seg;
@@ -3449,16 +3661,6 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
e->is_rev = (bme->v2 == v);
}
- /* find wrap-around shared face */
- BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) {
- if (bv->edges[0].e->l && BM_face_edge_share_loop(f, bv->edges[0].e)) {
- if (bv->edges[0].fnext == f)
- continue; /* if two shared faces, want the other one now */
- bv->edges[ntot - 1].fnext = f;
- bv->edges[0].fprev = f;
- break;
- }
- }
/* now done with tag flag */
BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
@@ -3586,6 +3788,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
VMesh *vm;
int i, k, n;
bool do_rebuild = false;
+ bool go_ccw, corner3special;
BMVert *bmv;
BMEdge *bme, *bme_new, *bme_prev;
BMFace *f_new;
@@ -3600,47 +3803,88 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
lprev = l->prev;
bv = find_bevvert(bp, l->v);
+ vm = bv->vmesh;
e = find_edge_half(bv, l->e);
bme = e->e;
eprev = find_edge_half(bv, lprev->e);
BLI_assert(e != NULL && eprev != NULL);
- vstart = eprev->leftv;
- if (e->is_bev)
- vend = e->rightv;
- else
+
+ /* which direction around our vertex do we travel to match orientation of f? */
+ if (e->prev == eprev) {
+ if (eprev->prev == e) {
+ /* valence 2 vertex: use f is one of e->fnext or e->fprev to break tie */
+ go_ccw = (e->fnext != f);
+ }
+ else {
+ go_ccw = true; /* going ccw around bv to trace this corner */
+ }
+ }
+ else if (eprev->prev == e) {
+ go_ccw = false; /* going cw around bv to trace this corner */
+ }
+ else {
+ /* edges in face are non-contiguous in our ordering around bv.
+ * Which way should we go when going from eprev to e? */
+ if (count_ccw_edges_between(eprev, e) < count_ccw_edges_between(e, eprev)) {
+ /* go counterclockewise from eprev to e */
+ go_ccw = true;
+ }
+ else {
+ /* go clockwise from eprev to e */
+ go_ccw = false;
+ }
+ }
+ if (go_ccw) {
+ vstart = eprev->rightv;
vend = e->leftv;
+ }
+ else {
+ vstart = eprev->leftv;
+ vend = e->rightv;
+ }
+ BLI_assert(vstart != NULL && vend != NULL);
v = vstart;
- vm = bv->vmesh;
BLI_array_append(vv, v->nv.v);
BLI_array_append(ee, bme);
+ /* check for special case: multisegment 3rd face opposite a beveled edge with no vmesh */
+ corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev);
while (v != vend) {
- if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) {
- /* case of 3rd face opposite a beveled edge, with no vmesh */
- i = v->index;
- e = v->ebev;
- for (k = 1; k < e->seg; k++) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
- /* may want to merge UVs of these later */
- if (!e->is_seam)
- BLI_array_append(vv_fix, bmv);
+ if (go_ccw) {
+ if (vm->seg > 1) {
+ if (vm->mesh_kind == M_ADJ || bp->vertex_only || corner3special) {
+ i = v->index;
+ for (k = 1; k < vm->seg; k++) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme); /* TODO: maybe better edge here */
+ if (corner3special && v->ebev && !v->ebev->is_seam)
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
}
+ v = v->next;
}
- else if ((vm->mesh_kind == M_ADJ || bp->vertex_only) && vm->seg > 1 && !e->is_bev && !eprev->is_bev) {
- BLI_assert(v->prev == vend);
- i = vend->index;
- for (k = vm->seg - 1; k > 0; k--) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
+ else {
+ /* going cw */
+ if (vm->seg > 1) {
+ if (vm->mesh_kind == M_ADJ || bp->vertex_only ||
+ (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev))
+ {
+ i = v->prev->index;
+ for (k = vm->seg - 1; k > 0; k--) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme);
+ if (corner3special && v->ebev && !v->ebev->is_seam)
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
}
+ v = v->prev;
}
- v = v->prev;
BLI_array_append(vv, v->nv.v);
BLI_array_append(ee, bme);
}
-
do_rebuild = true;
}
else {
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 36ab85b9b5b..4f5cf83f5ca 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -67,12 +67,19 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
std::list<Object *>& child_objects)
{
// write bone nodes
+
+ bArmature * armature = (bArmature *)ob_arm->data;
+ ED_armature_to_edit(armature);
+
bArmature *arm = (bArmature *)ob_arm->data;
for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
// start from root bones
if (!bone->parent)
add_bone_node(bone, ob_arm, sce, se, child_objects);
}
+
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
@@ -167,12 +174,30 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
node.setNodeName(node_name);
node.setNodeSid(node_sid);
-#if 0
- if (BLI_listbase_is_empty(&bone->childbase) || BLI_listbase_count_ex(&bone->childbase, 2) == 2) {
- add_blender_leaf_bone( bone, ob_arm, node);
+ if (this->export_settings->use_blender_profile)
+ {
+ if (bone->parent) {
+ if (bone->flag & BONE_CONNECTED) {
+ node.addExtraTechniqueParameter("blender", "connect", true);
+ }
+ }
+ std::string layers = BoneExtended::get_bone_layers(bone->layer);
+ node.addExtraTechniqueParameter("blender", "layer", layers);
+
+ bArmature *armature = (bArmature *)ob_arm->data;
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ if (ebone && ebone->roll != 0)
+ {
+ node.addExtraTechniqueParameter("blender", "roll", ebone->roll);
+ }
+ if (bc_is_leaf_bone(bone))
+ {
+ node.addExtraTechniqueParameter("blender", "tip_x", bone->arm_tail[0] - bone->arm_head[0]);
+ node.addExtraTechniqueParameter("blender", "tip_y", bone->arm_tail[1] - bone->arm_head[1]);
+ node.addExtraTechniqueParameter("blender", "tip_z", bone->arm_tail[2] - bone->arm_head[2]);
+ }
}
- else {
-#endif
+
node.start();
add_bone_transform(ob_arm, bone, node);
@@ -227,25 +252,6 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
}
}
-//#if 1
-void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
-{
- node.start();
-
- add_bone_transform(ob_arm, bone, node);
-
- node.addExtraTechniqueParameter("blender", "tip_x", bone->tail[0]);
- node.addExtraTechniqueParameter("blender", "tip_y", bone->tail[1]);
- node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2]);
-
- /*for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(child, ob_arm, sce, se, child_objects);
- }*/
- node.end();
-
-}
-//#endif
-
void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
{
//bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 931cc5d2988..883a6aca847 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -92,8 +92,6 @@ private:
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
- void add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node);
-
std::string get_controller_id(Object *ob_arm, Object *ob);
void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index fd08e1ebfab..fca9b9ffa55 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -50,19 +50,6 @@ static const char *bc_get_joint_name(T *node)
return id.size() ? id.c_str() : node->getOriginalId().c_str();
}
-static EditBone *get_edit_bone(bArmature * armature, char *name) {
- EditBone *eBone;
-
- for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
- if (STREQ(name, eBone->name))
- return eBone;
- }
-
- return NULL;
-
-}
-
-
ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) :
import_settings(import_settings),
@@ -110,7 +97,7 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node);
#endif
int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[4][4], bArmature *arm)
+ float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels)
{
float mat[4][4];
float joint_inv_bind_mat[4][4];
@@ -157,22 +144,41 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
if (parent) bone->parent = parent;
float loc[3], size[3], rot[3][3];
- float angle;
- float vec[3] = {0.0f, 0.5f, 0.0f};
- mat4_to_loc_rot_size(loc, rot, size, mat);
- //copy_m3_m4(bonemat,mat);
- mat3_to_vec_roll(rot, vec, &angle);
-
- bone->roll = angle;
- // set head
- copy_v3_v3(bone->head, mat[3]);
- // set tail, don't set it to head because 0-length bones are not allowed
- add_v3_v3v3(bone->tail, bone->head, vec);
+ BoneExtended &be = add_bone_extended(bone, node, layer_labels);
+ int layer = be.get_bone_layers();
+ if (layer) bone->layer = layer;
+ arm->layer |= layer; // ensure that all populated bone layers are visible after import
+
+ float *tail = be.get_tail();
+ int use_connect = be.get_use_connect();
+
+ switch (use_connect) {
+ case 1: bone->flag |= BONE_CONNECTED;
+ break;
+ case 0: bone->flag &= ~BONE_CONNECTED;
+ case -1: break; // not defined
+ }
+
+ if (be.has_roll()) {
+ bone->roll = be.get_roll();
+ }
+ else {
+ float angle;
+ mat4_to_loc_rot_size(loc, rot, size, mat);
+ mat3_to_vec_roll(rot, NULL, &angle);
+ }
+
+ copy_v3_v3(bone->head, mat[3]);
+ add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
/* find smallest bone length in armature (used later for leaf bone length) */
if (parent) {
+ if (use_connect == 1) {
+ copy_v3_v3(parent->tail, bone->head);
+ }
+
/* guess reasonable leaf bone length */
float length = len_v3v3(parent->head, bone->head);
if ((length < leaf_bone_length || totbone == 0) && length > MINIMUM_BONE_LENGTH) {
@@ -182,11 +188,8 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
COLLADAFW::NodePointerArray& children = node->getChildNodes();
- BoneExtended &be = add_bone_extended(bone, node);
- be.set_leaf_bone(true);
-
for (unsigned int i = 0; i < children.getCount(); i++) {
- int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm);
+ int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm, layer_labels);
if (cl > chain_length)
chain_length = cl;
}
@@ -209,22 +212,23 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
**/
void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
{
- /* armature has no bones */
if (bone == NULL)
return;
- BoneExtended *be = extended_bones[bone->name];
- if (be != NULL && be->is_leaf_bone() ) {
- /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
- float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
+ if (bc_is_leaf_bone(bone)) {
+
+ BoneExtended *be = extended_bones[bone->name];
+ if (be == NULL || !be->has_tail()) {
- EditBone *ebone = get_edit_bone(armature, bone->name);
- float vec[3];
+ /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
+ float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
+
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ float vec[3];
- if (this->import_settings->fix_orientation) {
if (ebone->parent != NULL) {
EditBone *parent = ebone->parent;
- sub_v3_v3v3(vec, ebone->head, parent->tail);
+ sub_v3_v3v3(vec, ebone->head, parent->head);
if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH)
{
sub_v3_v3v3(vec, parent->tail, parent->head);
@@ -234,19 +238,31 @@ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
vec[2] = 0.1f;
sub_v3_v3v3(vec, ebone->tail, ebone->head);
}
- }
- else {
- sub_v3_v3v3(vec, ebone->tail, ebone->head);
- }
- normalize_v3_v3(vec, vec);
- mul_v3_fl(vec, leaf_length);
- add_v3_v3v3(ebone->tail, ebone->head, vec);
+ normalize_v3_v3(vec, vec);
+ mul_v3_fl(vec, leaf_length);
+ add_v3_v3v3(ebone->tail, ebone->head, vec);
+ }
}
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
fix_leaf_bones(armature, child);
}
+}
+
+void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone)
+{
+ /* armature has no bones */
+ if (bone == NULL)
+ return;
+
+ if (bone->parent && bone->flag & BONE_CONNECTED) {
+ copy_v3_v3(bone->parent->tail, bone->head);
+ }
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ fix_parent_connect(armature, child);
+ }
}
@@ -281,8 +297,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
BoneExtended *pbe = extended_bones[parentbone->name];
if (dominant_child != NULL) {
/* Found a valid chain. Now connect current bone with that chain.*/
- EditBone *pebone = get_edit_bone(armature, parentbone->name);
- EditBone *cebone = get_edit_bone(armature, dominant_child->get_name());
+ EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
+ EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
if (pebone && !(cebone->flag & BONE_CONNECTED)) {
float vec[3];
@@ -421,6 +437,7 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
void ArmatureImporter::create_armature_bones( )
{
std::vector<COLLADAFW::Node *>::iterator ri;
+ std::vector<std::string> layer_labels;
leaf_bone_length = FLT_MAX;
//if there is an armature created for root_joint next root_joint
@@ -445,8 +462,9 @@ void ArmatureImporter::create_armature_bones( )
clear_extended_boneset();
ED_armature_to_edit(armature);
+ armature->layer = 0; // layer is set according to imported bone set in create_bone()
- create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
+ create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
/* exit armature edit mode to populate the Armature object */
ED_armature_from_edit(armature);
@@ -455,14 +473,23 @@ void ArmatureImporter::create_armature_bones( )
/* and step back to edit mode to fix the leaf nodes */
ED_armature_to_edit(armature);
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+ if (this->import_settings->fix_orientation || this->import_settings->find_chains) {
+
+ if (this->import_settings->find_chains)
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- // exit armature edit mode
- unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
+ if (this->import_settings->fix_orientation)
+ fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+
+ // exit armature edit mode
+ unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
+ }
+
+ fix_parent_connect(armature, (Bone *)armature->bonebase.first);
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
+
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
}
}
@@ -513,6 +540,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
SkinInfo *a = &skin;
Object *shared = NULL;
std::vector<COLLADAFW::Node *> skin_root_joints;
+ std::vector<std::string> layer_labels;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
@@ -578,7 +606,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
// since root_joints may contain joints for multiple controllers, we need to filter
if (skin.uses_joint_or_descendant(*ri)) {
- create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
+ create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]);
@@ -594,8 +622,8 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
if (armature->bonebase.first) {
/* Do this only if Armature has bones */
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+ //connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+ //fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
}
// exit armature edit mode
ED_armature_from_edit(armature);
@@ -894,70 +922,44 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
return found;
}
-
-/**
- * BoneExtended is a helper class needed for the Bone chain finder
- * See ArmatureImporter::fix_leaf_bones()
- * and ArmatureImporter::connect_bone_chains()
- **/
-
-BoneExtended::BoneExtended(EditBone *aBone)
-{
- this->set_name(aBone->name);
- this->chain_length = 0;
- this->is_leaf = false;
-}
-
-char *BoneExtended::get_name()
-{
- return name;
-}
-
-void BoneExtended::set_name(char *aName)
-{
- BLI_strncpy(name, aName, MAXBONENAME);
-}
-
-int BoneExtended::get_chain_length()
-{
- return chain_length;
-}
-
-void BoneExtended::set_chain_length(const int aLength)
-{
- chain_length = aLength;
-}
-
-
-void BoneExtended::set_leaf_bone(bool state)
-{
- is_leaf = state;
-}
-
-bool BoneExtended::is_leaf_bone()
-{
- return is_leaf;
-}
-
-BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node)
+BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, std::vector<std::string> &layer_labels)
{
+ BoneExtended *be = new BoneExtended(bone);
+ extended_bones[bone->name] = be;
TagsMap::iterator etit;
ExtraTags *et = 0;
etit = uid_tags_map.find(node->getUniqueId().toAscii());
if (etit != uid_tags_map.end()) {
- float x, y, z;
+
+ float tail[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
+ float roll = 0;
+ int use_connect = -1;
+ std::string layers;
et = etit->second;
- et->setData("tip_x", &x);
- et->setData("tip_y", &y);
- et->setData("tip_z", &z);
- float vec[3] = { x, y, z };
- copy_v3_v3(bone->tail, bone->head);
- add_v3_v3v3(bone->tail, bone->head, vec);
+
+ bool has_tail = false;
+ has_tail |= et->setData("tip_x", &tail[0]);
+ has_tail |= et->setData("tip_y", &tail[1]);
+ has_tail |= et->setData("tip_z", &tail[2]);
+
+ bool has_connect = et->setData("connect", &use_connect);
+ bool has_roll = et->setData("roll", &roll);
+
+ layers = et->setData("layer", layers);
+
+ if (has_tail && !has_connect)
+ {
+ use_connect = 0; // got a bone tail definition but no connect info -> bone is not connected
+ }
+
+ be->set_bone_layers(layers, layer_labels);
+ if (has_tail) be->set_tail(tail);
+ if (has_roll) be->set_roll(roll);
+ be->set_use_connect(use_connect);
}
+ be->set_leaf_bone(true);
- BoneExtended *be = new BoneExtended(bone);
- extended_bones[bone->name] = be;
return *be;
}
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index 732fda80ff1..f38bd1a6c66 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -59,25 +59,6 @@ extern "C" {
#define UNLIMITED_CHAIN_MAX INT_MAX
#define MINIMUM_BONE_LENGTH 0.000001f
-class BoneExtended {
-
-private:
- char name[MAXBONENAME];
- int chain_length;
- bool is_leaf;
-
-public:
-
- BoneExtended(EditBone *aBone);
- char *get_name();
- int get_chain_length();
-
- void set_name(char *aName);
- void set_chain_length(const int aLength);
- void set_leaf_bone(bool state);
- bool is_leaf_bone();
-};
-
class ArmatureImporter : private TransformReader
{
private:
@@ -125,12 +106,13 @@ private:
#endif
int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[4][4], bArmature *arm);
+ float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels);
- BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node);
+ BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, std::vector<std::string> &layer_labels);
void clear_extended_boneset();
void fix_leaf_bones(bArmature *armature, Bone *bone);
+ void fix_parent_connect(bArmature *armature, Bone *bone);
void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length);
void set_pose( Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]);
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 3dc7e74379e..9451cac9dae 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -48,6 +48,7 @@ public:
bool triangulate;
bool use_object_instantiation;
+ bool use_blender_profile;
bool sort_by_name;
BC_export_transformation_type export_transformation_type;
bool open_sim;
diff --git a/source/blender/collada/ExtraTags.cpp b/source/blender/collada/ExtraTags.cpp
index 6af61432fda..ea225d8a4ae 100644
--- a/source/blender/collada/ExtraTags.cpp
+++ b/source/blender/collada/ExtraTags.cpp
@@ -85,32 +85,45 @@ std::string ExtraTags::asString(std::string tag, bool *ok)
}
-void ExtraTags::setData(std::string tag, short *data)
+bool ExtraTags::setData(std::string tag, short *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = (short)tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, int *data)
+
+bool ExtraTags::setData(std::string tag, int *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, float *data)
+
+bool ExtraTags::setData(std::string tag, float *data)
{
bool ok = false;
float tmp = asFloat(tag, &ok);
if (ok)
*data = tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, char *data)
+
+bool ExtraTags::setData(std::string tag, char *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = (char)tmp;
+ return ok;
+}
+
+std::string ExtraTags::setData(std::string tag, std::string &data)
+{
+ bool ok = false;
+ std::string tmp = asString(tag, &ok);
+ return (ok) ? tmp : data;
}
-
diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h
index 03a311a7e86..ad272dcba65 100644
--- a/source/blender/collada/ExtraTags.h
+++ b/source/blender/collada/ExtraTags.h
@@ -43,17 +43,18 @@ public:
bool addTag(std::string tag, std::string data);
/** Set given short pointer to value of tag, if it exists. */
- void setData(std::string tag, short *data);
+ bool setData(std::string tag, short *data);
/** Set given int pointer to value of tag, if it exists. */
- void setData(std::string tag, int *data);
+ bool setData(std::string tag, int *data);
/** Set given float pointer to value of tag, if it exists. */
- void setData(std::string tag, float *data);
+ bool setData(std::string tag, float *data);
/** Set given char pointer to value of tag, if it exists. */
- void setData(std::string tag, char *data);
-
+ bool setData(std::string tag, char *data);
+ std::string setData(std::string tag, std::string &data);
+
/** Return true if the extra tags is for specified profile. */
bool isProfile(std::string profile);
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index a884268fd5e..76f24545248 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -259,7 +259,8 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
const std::string &name = bc_get_dae_name(mesh);
-
+ int hole_count = 0;
+
for (unsigned i = 0; i < prim_arr.getCount(); i++) {
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
@@ -275,13 +276,21 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
for (unsigned int j = 0; j < vca.getCount(); j++) {
int count = vca[j];
- if (count < 3) {
- fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
+ if (abs(count) < 3) {
+ fprintf(stderr, "ERROR: Primitive %s in %s has at least one face with vertex count < 3\n",
type_str, name.c_str());
return false;
}
+ if (count < 0)
+ {
+ hole_count ++;
+ }
+ }
+
+ if (hole_count > 0)
+ {
+ fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count);
}
-
}
else if (type == COLLADAFW::MeshPrimitive::LINES) {
@@ -289,13 +298,13 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
}
else if (type != COLLADAFW::MeshPrimitive::TRIANGLES && type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
- fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
+ fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str);
return false;
}
}
if (mesh->getPositions().empty()) {
- fprintf(stderr, "Mesh %s has no vertices.\n", name.c_str());
+ fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str());
return false;
}
@@ -409,11 +418,18 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
size_t prim_poly_count = mpvc->getFaceCount();
size_t prim_loop_count = 0;
- for (int index=0; index < prim_poly_count; index++) {
- prim_loop_count += get_vertex_count(mpvc, index);
+ for (int index=0; index < prim_poly_count; index++)
+ {
+ int vcount = get_vertex_count(mpvc, index);
+ if (vcount > 0) {
+ prim_loop_count += vcount;
+ total_poly_count++;
+ }
+ else {
+ // TODO: this is a hole and not another polygon!
+ }
}
- total_poly_count += prim_poly_count;
total_loop_count += prim_loop_count;
break;
@@ -683,9 +699,12 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
COLLADAFW::IndexListArray& index_list_array_vcolor = mp->getColorIndicesArray();
for (unsigned int j = 0; j < prim_totpoly; j++) {
-
+
// Vertices in polygon:
int vcount = get_vertex_count(mpvc, j);
+ if (vcount < 0) {
+ continue; // TODO: add support for holes
+ }
set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index b64b10e0833..e1b8a2dd30a 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -81,8 +81,9 @@ int collada_export(Scene *sce,
int use_texture_copies,
int triangulate,
- int use_object_instantiation,
- int sort_by_name,
+ int use_object_instantiation,
+ int use_blender_profile,
+ int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim)
{
@@ -105,6 +106,7 @@ int collada_export(Scene *sce,
export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
+ export_settings.use_blender_profile = use_blender_profile != 0;
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
export_settings.open_sim = open_sim != 0;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 6819a62fdf0..db8ea884222 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -78,6 +78,7 @@ int collada_export(struct Scene *sce,
int triangulate,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f8feed8145c..f0984fbc127 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -54,6 +54,8 @@ extern "C" {
#include "BKE_scene.h"
#include "BKE_DerivedMesh.h"
+#include "ED_armature.h"
+
#include "WM_api.h" // XXX hrm, see if we can do without this
#include "WM_types.h"
@@ -366,3 +368,212 @@ void bc_triangulate_mesh(Mesh *me)
BM_mesh_bm_to_me(bm, me, &bm_to_me_params);
BM_mesh_free(bm);
}
+
+/*
+* A bone is a leaf when it has no children or all children are not connected.
+*/
+bool bc_is_leaf_bone(Bone *bone)
+{
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ if (child->flag & BONE_CONNECTED)
+ return false;
+ }
+ return true;
+}
+
+EditBone *bc_get_edit_bone(bArmature * armature, char *name) {
+ EditBone *eBone;
+
+ for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
+ if (STREQ(name, eBone->name))
+ return eBone;
+ }
+
+ return NULL;
+
+}
+int bc_set_layer(int bitfield, int layer)
+{
+ return bc_set_layer(bitfield, layer, true); /* enable */
+}
+
+int bc_set_layer(int bitfield, int layer, bool enable)
+{
+ int bit = 1u << layer;
+
+ if (enable)
+ bitfield |= bit;
+ else
+ bitfield &= ~bit;
+
+ return bitfield;
+}
+
+/**
+* BoneExtended is a helper class needed for the Bone chain finder
+* See ArmatureImporter::fix_leaf_bones()
+* and ArmatureImporter::connect_bone_chains()
+**/
+
+BoneExtended::BoneExtended(EditBone *aBone)
+{
+ this->set_name(aBone->name);
+ this->chain_length = 0;
+ this->is_leaf = false;
+ this->tail[0] = 0.0f;
+ this->tail[1] = 0.5f;
+ this->tail[2] = 0.0f;
+ this->use_connect = -1;
+ this->roll = 0;
+ this->bone_layers = 0;
+
+ this->has_custom_tail = false;
+ this->has_custom_roll = false;
+}
+
+char *BoneExtended::get_name()
+{
+ return name;
+}
+
+void BoneExtended::set_name(char *aName)
+{
+ BLI_strncpy(name, aName, MAXBONENAME);
+}
+
+int BoneExtended::get_chain_length()
+{
+ return chain_length;
+}
+
+void BoneExtended::set_chain_length(const int aLength)
+{
+ chain_length = aLength;
+}
+
+void BoneExtended::set_leaf_bone(bool state)
+{
+ is_leaf = state;
+}
+
+bool BoneExtended::is_leaf_bone()
+{
+ return is_leaf;
+}
+
+void BoneExtended::set_roll(float roll)
+{
+ this->roll = roll;
+ this->has_custom_roll = true;
+}
+
+bool BoneExtended::has_roll()
+{
+ return this->has_custom_roll;
+}
+
+float BoneExtended::get_roll()
+{
+ return this->roll;
+}
+
+void BoneExtended::set_tail(float vec[])
+{
+ this->tail[0] = vec[0];
+ this->tail[1] = vec[1];
+ this->tail[2] = vec[2];
+ this->has_custom_tail = true;
+}
+
+bool BoneExtended::has_tail()
+{
+ return this->has_custom_tail;
+}
+
+float *BoneExtended::get_tail()
+{
+ return this->tail;
+}
+
+inline bool isInteger(const std::string & s)
+{
+ if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
+
+ char * p;
+ strtol(s.c_str(), &p, 10);
+
+ return (*p == 0);
+}
+
+void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::string> &layer_labels)
+{
+ std::stringstream ss(layerString);
+ std::string layer;
+ int pos;
+
+ while (ss >> layer) {
+
+ /* Blender uses numbers to specify layers*/
+ if (isInteger(layer))
+ {
+ pos = atoi(layer.c_str());
+ if (pos >= 0 && pos < 32) {
+ this->bone_layers = bc_set_layer(this->bone_layers, pos);
+ continue;
+ }
+ }
+
+ /* layer uses labels (not supported by blender). Map to layer numbers:*/
+ pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin();
+ if (pos >= layer_labels.size()) {
+ layer_labels.push_back(layer); /* remember layer number for future usage*/
+ }
+
+ if (pos > 31)
+ {
+ fprintf(stderr, "Too many layers in Import. Layer %s mapped to Blender layer 31\n", layer.c_str());
+ pos = 31;
+ }
+
+ /* If numeric layers and labeled layers are used in parallel (unlikely),
+ we get a potential mixup. Just leave as is for now.
+ */
+ this->bone_layers = bc_set_layer(this->bone_layers, pos);
+
+ }
+}
+
+std::string BoneExtended::get_bone_layers(int bitfield)
+{
+ std::string result = "";
+ std::string sep = "";
+ int bit = 1u;
+
+ std::ostringstream ss;
+ for (int i = 0; i < 32; i++)
+ {
+ if (bit & bitfield)
+ {
+ ss << sep << i;
+ sep = " ";
+ }
+ bit = bit << 1;
+ }
+ return ss.str();
+}
+
+int BoneExtended::get_bone_layers()
+{
+ return (bone_layers == 0) ? 1 : bone_layers; // ensure that the bone is in at least one bone layer!
+}
+
+
+void BoneExtended::set_use_connect(int use_connect)
+{
+ this->use_connect = use_connect;
+}
+
+int BoneExtended::get_use_connect()
+{
+ return this->use_connect;
+}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 4bc2f55cf33..74f8dca1492 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -34,6 +34,7 @@
#include <vector>
#include <map>
+#include <algorithm>
extern "C" {
#include "DNA_object_types.h"
@@ -46,6 +47,7 @@ extern "C" {
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_object.h"
@@ -87,7 +89,10 @@ extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_sce
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
extern void bc_triangulate_mesh(Mesh *me);
-
+extern bool bc_is_leaf_bone(Bone *bone);
+extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
+extern int bc_set_layer(int bitfield, int layer, bool enable);
+extern int bc_set_layer(int bitfield, int layer);
class BCPolygonNormalsIndices
{
@@ -105,4 +110,48 @@ class BCPolygonNormalsIndices
};
+class BoneExtended {
+
+private:
+ char name[MAXBONENAME];
+ int chain_length;
+ bool is_leaf;
+ float tail[3];
+ float roll;
+
+ int bone_layers;
+ bool use_connect;
+ bool has_custom_tail;
+ bool has_custom_roll;
+
+public:
+
+ BoneExtended(EditBone *aBone);
+
+ void set_name(char *aName);
+ char *get_name();
+
+ void set_chain_length(const int aLength);
+ int get_chain_length();
+
+ void set_leaf_bone(bool state);
+ bool is_leaf_bone();
+
+ void set_bone_layers(std::string layers, std::vector<std::string> &layer_labels);
+ int get_bone_layers();
+ static std::string get_bone_layers(int bitfield);
+
+ void set_roll(float roll);
+ bool has_roll();
+ float get_roll();
+
+ void set_tail(float *vec);
+ float *get_tail();
+ bool has_tail();
+
+ void set_use_connect(int use_connect);
+ int get_use_connect();
+};
+
+
#endif
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 2b4df85f29c..fd2a521bec5 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -25,8 +25,6 @@
set(INC
.
- intern
- util
../blenkernel
../blenlib
../bmesh
@@ -42,45 +40,50 @@ set(INC_SYS
)
set(SRC
+ intern/builder/deg_builder.cc
+ intern/builder/deg_builder_cycle.cc
+ intern/builder/deg_builder_nodes.cc
+ intern/builder/deg_builder_pchanmap.cc
+ intern/builder/deg_builder_relations.cc
+ intern/builder/deg_builder_transitive.cc
+ intern/debug/deg_debug_graphviz.cc
+ intern/eval/deg_eval.cc
+ intern/eval/deg_eval_debug.cc
+ intern/eval/deg_eval_flush.cc
+ intern/nodes/deg_node.cc
+ intern/nodes/deg_node_component.cc
+ intern/nodes/deg_node_operation.cc
intern/depsgraph.cc
- intern/depsnode.cc
- intern/depsnode_component.cc
- intern/depsnode_operation.cc
intern/depsgraph_build.cc
- intern/depsgraph_build_nodes.cc
- intern/depsgraph_build_relations.cc
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
intern/depsgraph_query.cc
- intern/depsgraph_queue.cc
intern/depsgraph_tag.cc
intern/depsgraph_type_defines.cc
- util/depsgraph_util_cycle.cc
- util/depsgraph_util_pchanmap.cc
- util/depsgraph_util_transitive.cc
DEG_depsgraph.h
DEG_depsgraph_build.h
DEG_depsgraph_debug.h
DEG_depsgraph_query.h
+
+ intern/builder/deg_builder.h
+ intern/builder/deg_builder_cycle.h
+ intern/builder/deg_builder_nodes.h
+ intern/builder/deg_builder_pchanmap.h
+ intern/builder/deg_builder_relations.h
+ intern/builder/deg_builder_transitive.h
+ intern/eval/deg_eval.h
+ intern/eval/deg_eval_debug.h
+ intern/eval/deg_eval_flush.h
+ intern/nodes/deg_node.h
+ intern/nodes/deg_node_component.h
+ intern/nodes/deg_node_operation.h
intern/depsgraph.h
- intern/depsnode.h
- intern/depsnode_component.h
- intern/depsnode_operation.h
- intern/depsnode_opcodes.h
- intern/depsgraph_build.h
- intern/depsgraph_debug.h
intern/depsgraph_intern.h
- intern/depsgraph_queue.h
intern/depsgraph_types.h
- util/depsgraph_util_cycle.h
- util/depsgraph_util_function.h
- util/depsgraph_util_hash.h
- util/depsgraph_util_map.h
- util/depsgraph_util_pchanmap.h
- util/depsgraph_util_set.h
- util/depsgraph_util_transitive.h
+ util/deg_util_function.h
+ util/deg_util_hash.h
)
if(WITH_CXX11)
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index f37ba71ab65..d1de83ec8a9 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -131,9 +131,6 @@ void DEG_ids_clear_recalc(struct Main *bmain);
/* Update Flushing ------------------------------- */
-/* Flush updates */
-void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
-
/* Flush updates for all IDs */
void DEG_ids_flush_tagged(struct Main *bmain);
@@ -144,11 +141,6 @@ void DEG_ids_check_recalc(struct Main *bmain,
struct Scene *scene,
bool time);
-/* Clear all update tags
- * - For aborted updates, or after successful evaluation
- */
-void DEG_graph_clear_tags(Depsgraph *graph);
-
/* ************************************************ */
/* Evaluation Engine API */
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index f680c47247a..49b648c7dae 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -43,9 +43,6 @@ struct Depsgraph;
struct Main;
struct Scene;
-struct PointerRNA;
-struct PropertyRNA;
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index 374fad63c34..0d19b8e1e97 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -39,13 +39,10 @@
extern "C" {
#endif
-struct DepsgraphSettings;
struct GHash;
struct ID;
struct Depsgraph;
-struct DepsNode;
-struct DepsRelation;
/* ************************************************ */
/* Statistics */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 60d673d4c5b..ccd204a2083 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -19,7 +19,7 @@
* All rights reserved.
*
* Original Author: Joshua Leung
- * Contributor(s): None Yet
+ * Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -33,155 +33,14 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
-struct ListBase;
struct ID;
struct Depsgraph;
-struct DepsNode;
-struct DepsRelation;
#ifdef __cplusplus
extern "C" {
#endif
-/* ************************************************ */
-/* Type Defines */
-
-/* FilterPredicate Callback
- *
- * Defines a callback function which can be supplied to check whether a
- * node is relevant or not.
- *
- * < graph: Depsgraph that we're traversing
- * < node: The node to check
- * < userdata: FilterPredicate state data (as needed)
- * > returns: True if node is relevant
- */
-typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
-
-
-/* Node Operation
- *
- * Performs some action on the given node, provided that the node was
- * deemed to be relevant to operate on.
- *
- * < graph: Depsgraph that we're traversing
- * < node: The node to perform operation on/with
- * < userdata: Node Operation's state data (as needed)
- * > returns: True if traversal should be aborted at this point
- */
-typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
-
-/* ************************************************ */
-/* Low-Level Filtering API */
-
-/* Create a filtered copy of the given graph which contains only the
- * nodes which fulfill the criteria specified using the FilterPredicate
- * passed in.
- *
- * < graph: The graph to be copied and filtered
- * < filter: FilterPredicate used to check which nodes should be included
- * (If null, full graph is copied as-is)
- * < userdata: State data for filter (as necessary)
- *
- * > returns: a full copy of all the relevant nodes - the matching subgraph
- */
-// XXX: is there any need for extra settings/options for how the filtering goes?
-Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
-
-
-/* Traverse nodes in graph which are deemed relevant,
- * performing the provided operation on the nodes.
- *
- * < graph: The graph to perform operations on
- * < filter: FilterPredicate used to check which nodes should be included
- * (If null, all nodes are considered valid targets)
- * < filter_data: Custom state data for FilterPredicate
- * (Note: This can be the same as op_data, where appropriate)
- * < op: NodeOperation to perform on each node
- * (If null, no graph traversal is performed for efficiency)
- * < op_data: Custom state data for NodeOperation
- * (Note: This can be the same as filter_data, where appropriate)
- */
-void DEG_graph_traverse(const struct Depsgraph *graph,
- DEG_FilterPredicate *filter, void *filter_data,
- DEG_NodeOperation *op, void *op_data);
-
-/* ************************************************ */
-/* Node-Based Operations */
-// XXX: do we want to be able to attach conditional requirements here?
-
-/* Find an (outer) node matching given conditions
- * ! Assumes that there will only be one such node, or that only the first one matters
- *
- * < graph: a dependency graph which may or may not contain a node matching these requirements
- * < query: query conditions for the criteria that the node must satisfy
- */
-//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
-
-/* Topology Queries (Direct) ---------------------- */
-
-/* Get list of nodes which directly depend on given node
- *
- * > result: list to write results to
- * < node: the node to find the children/dependents of
- */
-void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
-
-
-/* Get list of nodes which given node directly depends on
- *
- * > result: list to write results to
- * < node: the node to find the dependencies of
- */
-void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
-
-
-/* Topology Queries (Subgraph) -------------------- */
-// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
-// just spit out a copy of the subgraph which matches. This works well for the cases
-// where these are used - mostly for efficient updating of subsets of the nodes.
-
-// XXX: allow supplying a filter predicate to provide further filtering/pruning?
-
-
-/* Get all descendants of a node
- *
- * That is, get the subgraph / subset of nodes which are dependent
- * on the results of the given node.
- */
-Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
-
-
-/* Get all ancestors of a node
- *
- * That is, get the subgraph / subset of nodes which the given node
- * is dependent on in order to be evaluated.
- */
-Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
-
-/* ************************************************ */
-/* Higher-Level Queries */
-
-/* Get ID-blocks which would be affected if specified ID is modified
- * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
- *
- * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
- * > returns: number of matching ID-blocks
- */
-size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
-
-
-/* Get ID-blocks which are needed to update/evaluate specified ID
- * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
- *
- * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
- * > returns: number of matching ID-blocks
- */
-size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
-
-/* ************************************************ */
-
/* Check if given ID type was tagged for update. */
bool DEG_id_type_tagged(struct Main *bmain, short idtype);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
new file mode 100644
index 00000000000..9f80c21a6a4
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -0,0 +1,129 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/build/deg_builder.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder.h"
+
+// TODO(sergey): Use own wrapper over STD.
+#include <stack>
+
+#include "DNA_anim_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_types.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+string deg_fcurve_id_name(const FCurve *fcu)
+{
+ char index_buf[32];
+ // TODO(sergey): Use int-to-string utility or so.
+ BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index);
+ return string(fcu->rna_path) + index_buf;
+}
+
+void deg_graph_build_finalize(Depsgraph *graph)
+{
+ std::stack<OperationDepsNode *> stack;
+
+ foreach (OperationDepsNode *node, graph->operations) {
+ IDDepsNode *id_node = node->owner->owner;
+ node->done = 0;
+ node->num_links_pending = 0;
+ foreach (DepsRelation *rel, node->outlinks) {
+ if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ if (node->num_links_pending == 0) {
+ stack.push(node);
+ node->done = 1;
+ }
+ node->owner->layers = id_node->layers;
+ id_node->id->tag |= LIB_TAG_DOIT;
+ }
+
+ while (!stack.empty()) {
+ OperationDepsNode *node = stack.top();
+ stack.pop();
+ /* Flush layers to parents. */
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ from->owner->layers |= node->owner->layers;
+ }
+ }
+ /* Schedule parent nodes. */
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(from->num_links_pending > 0);
+ --from->num_links_pending;
+ }
+ if (from->num_links_pending == 0 && from->done == 0) {
+ stack.push(from);
+ from->done = 1;
+ }
+ }
+ }
+ }
+
+ /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
+ {
+ id_node->layers |= comp->layers;
+ }
+ GHASH_FOREACH_END();
+
+ ID *id = id_node->id;
+ if (id->tag & LIB_TAG_ID_RECALC_ALL &&
+ id->tag & LIB_TAG_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ id_node->finalize_build();
+ }
+ GHASH_FOREACH_END();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
new file mode 100644
index 00000000000..7ecb4b20684
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -0,0 +1,46 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/build/deg_builder.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_types.h"
+
+struct FCurve;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu);
+
+void deg_graph_build_finalize(struct Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 5eae8c087ad..225cc64ae4d 100644
--- a/source/blender/depsgraph/util/depsgraph_util_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -23,28 +23,30 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_cycle.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_cycle.cc
* \ingroup depsgraph
*/
+#include "intern/builder/deg_builder_cycle.h"
+
+// TOO(sergey): Use some wrappers over those?
#include <cstdio>
#include <cstdlib>
#include <stack>
extern "C" {
#include "BLI_utildefines.h"
+}
-#include "DNA_ID.h"
+#include "util/deg_util_foreach.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
-}
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph_util_cycle.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+#include "intern/depsgraph.h"
+
+namespace DEG {
struct StackEntry {
OperationDepsNode *node;
@@ -62,17 +64,9 @@ void deg_graph_detect_cycles(Depsgraph *graph)
const int NODE_IN_STACK = 2;
std::stack<StackEntry> traversal_stack;
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (OperationDepsNode *node, graph->operations) {
bool has_inlinks = false;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ foreach (DepsRelation *rel, node->inlinks) {
if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
has_inlinks = true;
}
@@ -94,11 +88,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
StackEntry &entry = traversal_stack.top();
OperationDepsNode *node = entry.node;
bool all_child_traversed = true;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ foreach (DepsRelation *rel, node->outlinks) {
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
if (to->done == NODE_IN_STACK) {
@@ -138,3 +128,5 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
}
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
index fac38b61057..386fbd80d19 100644
--- a/source/blender/depsgraph/util/depsgraph_util_cycle.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
@@ -23,15 +23,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_cycle.h
+/** \file blender/depsgraph/intern/builder/deg_builder_cycle.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
-#define __DEPSGRAPH_UTIL_CYCLE_H__
+
+#pragma once
+
+namespace DEG {
struct Depsgraph;
+/* Detect and solve dependency cycles. */
void deg_graph_detect_cycles(Depsgraph *graph);
-#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index c29532a02c6..17b6acfd680 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -24,12 +24,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build_nodes.cc
+/** \file blender/depsgraph/intern/builder/deg_build_nodes.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
*/
+#include "intern/builder/deg_builder_nodes.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -95,12 +97,14 @@ extern "C" {
#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_types.h"
-#include "depsgraph_build.h"
-#include "depsgraph_intern.h"
+#include "intern/builder/deg_builder.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
/* ************ */
/* Node Builder */
@@ -215,6 +219,17 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
return add_operation_node(comp_node, optype, op, opcode, description);
}
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description)
+{
+ return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+}
+
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
eDepsNode_Type comp_type,
const string &comp_name,
@@ -235,6 +250,14 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
return comp_node->has_operation(opcode, description);
}
+OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string& description)
+{
+ return find_operation_node(id, comp_type, "", opcode, description);
+}
/* **** Build functions for entity nodes **** */
@@ -341,7 +364,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
return NULL;
/* create new subgraph's data */
- Depsgraph *subgraph = DEG_graph_new();
+ Depsgraph *subgraph = reinterpret_cast<Depsgraph *>(DEG_graph_new());
DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
@@ -379,11 +402,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
IDDepsNode *id_node = add_id_node(&ob->id);
id_node->layers = base->lay;
+ ob->customdata_mask = 0;
/* standard components */
build_object_transform(scene, ob);
-
/* object data */
if (ob->data) {
/* type-specific data... */
@@ -1187,3 +1210,5 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
*/
build_animdata(gpd_id);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
new file mode 100644
index 00000000000..6ee0b8406a1
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -0,0 +1,153 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_types.h"
+
+struct Base;
+struct bGPdata;
+struct ListBase;
+struct GHash;
+struct ID;
+struct FCurve;
+struct Group;
+struct Key;
+struct Main;
+struct Material;
+struct MTex;
+struct bNodeTree;
+struct Object;
+struct bPoseChannel;
+struct bConstraint;
+struct Scene;
+struct Tex;
+struct World;
+
+struct PropertyRNA;
+
+namespace DEG {
+
+struct Depsgraph;
+struct DepsNode;
+struct RootDepsNode;
+struct SubgraphDepsNode;
+struct IDDepsNode;
+struct TimeSourceDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+
+struct DepsgraphNodeBuilder {
+ DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
+ ~DepsgraphNodeBuilder();
+
+ RootDepsNode *add_root_node();
+ IDDepsNode *add_id_node(ID *id);
+ TimeSourceDepsNode *add_time_source(ID *id);
+
+ ComponentDepsNode *add_component_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name = "");
+
+ OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+ OperationDepsNode *add_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+ OperationDepsNode *add_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+
+ bool has_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ void build_scene(Main *bmain, Scene *scene);
+ SubgraphDepsNode *build_subgraph(Group *group);
+ void build_group(Scene *scene, Base *base, Group *group);
+ void build_object(Scene *scene, Base *base, Object *ob);
+ void build_object_transform(Scene *scene, Object *ob);
+ void build_object_constraints(Scene *scene, Object *ob);
+ void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Scene *scene, Object *ob);
+ void build_animdata(ID *id);
+ OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_ik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con);
+ void build_splineik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(Key *key);
+ void build_obdata_geom(Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
+ void build_material(DepsNode *owner_node, Material *ma);
+ void build_texture(DepsNode *owner_node, Tex *tex);
+ void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_world(World *world);
+ void build_compositor(Scene *scene);
+ void build_gpencil(bGPdata *gpd);
+
+protected:
+ Main *m_bmain;
+ Depsgraph *m_graph;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 80b37ec622d..0e78df52ff8 100644
--- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -24,11 +24,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_pchanmap.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h
* \ingroup depsgraph
*/
-#include "depsgraph_util_pchanmap.h"
+#include "intern/builder/deg_builder_pchanmap.h"
#include <stdio.h>
#include <string.h>
@@ -38,6 +38,8 @@ extern "C" {
#include "BLI_ghash.h"
}
+namespace DEG {
+
static void free_rootpchanmap_valueset(void *val)
{
/* Just need to free the set itself - the names stored are all references. */
@@ -48,13 +50,13 @@ static void free_rootpchanmap_valueset(void *val)
RootPChanMap::RootPChanMap()
{
/* Just create empty map. */
- m_map = BLI_ghash_str_new("RootPChanMap");
+ map_ = BLI_ghash_str_new("RootPChanMap");
}
RootPChanMap::~RootPChanMap()
{
/* Free the map, and all the value sets. */
- BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
+ BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset);
}
/* Debug contents of map */
@@ -64,7 +66,7 @@ void RootPChanMap::print_debug()
GSetIterator it2;
printf("Root PChan Map:\n");
- GHASH_ITER(it1, m_map) {
+ GHASH_ITER(it1, map_) {
const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
@@ -80,11 +82,11 @@ void RootPChanMap::print_debug()
/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
- if (BLI_ghash_haskey(m_map, bone)) {
+ if (BLI_ghash_haskey(map_, bone)) {
/* Add new entry, but only add the root if it doesn't already
* exist in there.
*/
- GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
+ GSet *values = (GSet *)BLI_ghash_lookup(map_, bone);
BLI_gset_add(values, (void *)root);
}
else {
@@ -92,7 +94,7 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
BLI_ghashutil_strcmp,
"RootPChanMap Value Set");
- BLI_ghash_insert(m_map, (void *)bone, (void *)values);
+ BLI_ghash_insert(map_, (void *)bone, (void *)values);
/* Add new entry now. */
BLI_gset_insert(values, (void *)root);
@@ -103,20 +105,20 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
{
/* Ensure that both are in the map... */
- if (BLI_ghash_haskey(m_map, bone1) == false) {
+ if (BLI_ghash_haskey(map_, bone1) == false) {
//fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
//print_debug();
return false;
}
- if (BLI_ghash_haskey(m_map, bone2) == false) {
+ if (BLI_ghash_haskey(map_, bone2) == false) {
//fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
//print_debug();
return false;
}
- GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
- GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
+ GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1);
+ GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2);
GSetIterator it1, it2;
GSET_ITER(it1, bone1_roots) {
@@ -134,3 +136,5 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
//fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
return false;
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index b7f4c495933..233d8602fce 100644
--- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -24,12 +24,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_pchanmap.h
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_PCHANMAP_H__
-#define __DEPSGRAPH_UTIL_PCHANMAP_H__
+#pragma once
+
+struct GHash;
+
+namespace DEG {
struct RootPChanMap {
/* ctor and dtor - Create and free the internal map respectively. */
@@ -45,7 +48,7 @@ struct RootPChanMap {
/* Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2);
-private:
+protected:
/* The actual map:
* - Keys are "strings" (const char *) - not dynamically allocated.
* - Values are "sets" (const char *) - not dynamically allocated.
@@ -53,7 +56,7 @@ private:
* We don't use the C++ maps here, as it's more convenient to use
* Blender's GHash and be able to compare by-value instead of by-ref.
*/
- struct GHash *m_map;
+ struct GHash *map_;
};
-#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 23d3b391f8a..6564292e7f4 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -24,12 +24,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build_relations.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph
*/
+#include "intern/builder/deg_builder_relations.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -91,15 +93,19 @@ extern "C" {
#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_build.h"
-#include "depsgraph_debug.h"
-#include "depsgraph_intern.h"
-#include "depsgraph_types.h"
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
+
+#include "util/deg_util_foreach.h"
-#include "depsgraph_util_pchanmap.h"
+namespace DEG {
/* ***************** */
/* Relations Builder */
@@ -302,6 +308,19 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
if (scene->gpd) {
build_gpencil(&scene->id, scene->gpd);
}
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
+ it_op != m_graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ object->customdata_mask |= node->customdata_mask;
+ }
+ }
}
void DepsgraphRelationBuilder::build_group(Main *bmain,
@@ -466,8 +485,12 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
{
ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+
/* XXX not sure what this is for or how you could be done properly - lukas */
- //parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+ OperationDepsNode *parent_node = find_operation_node(parent_key);
+ if (parent_node != NULL) {
+ parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+ }
ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
@@ -618,7 +641,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
if (ct->tar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
@@ -759,8 +785,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
if (arm_node && bone_name) {
/* find objects which use this, and make their eval callbacks depend on this */
- DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel)
- {
+ foreach (DepsRelation *rel, arm_node->outlinks) {
IDDepsNode *to_node = (IDDepsNode *)rel->to;
/* we only care about objects with pose data which use this... */
@@ -774,7 +799,6 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
}
}
- DEPSNODE_RELATIONS_ITER_END;
/* free temp data */
MEM_freeN(bone_name);
@@ -1067,7 +1091,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
if (data->tar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else {
@@ -1099,7 +1126,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
if (data->poletar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else {
@@ -1475,13 +1505,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(mod_key);
- mti->updateDepsgraph(md, bmain, scene, ob, &handle);
+ mti->updateDepsgraph(
+ md,
+ bmain,
+ scene,
+ ob,
+ reinterpret_cast< ::DepsNodeHandle* >(&handle));
}
if (BKE_object_modifier_use_time(ob, md)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
-
+
/* Hacky fix for T45633 (Animated modifiers aren't updated)
*
* This check works because BKE_object_modifier_use_time() tests
@@ -1791,3 +1826,4 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
return false;
}
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index af61ab4eb8b..c0bf82becda 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -24,12 +24,27 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build.h
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_BUILD_H__
-#define __DEPSGRAPH_BUILD_H__
+#pragma once
+
+#include <cstdio>
+
+#include "intern/depsgraph_types.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "intern/depsgraph_types.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_operation.h"
struct Base;
struct bGPdata;
@@ -52,6 +67,8 @@ struct World;
struct PropertyRNA;
+namespace DEG {
+
struct Depsgraph;
struct DepsNode;
struct DepsNodeHandle;
@@ -63,74 +80,6 @@ struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
-struct DepsgraphNodeBuilder {
- DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
- ~DepsgraphNodeBuilder();
-
- RootDepsNode *add_root_node();
- IDDepsNode *add_id_node(ID *id);
- TimeSourceDepsNode *add_time_source(ID *id);
-
- ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
-
- OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
- OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
- OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
- {
- return add_operation_node(id, comp_type, "", optype, op, opcode, description);
- }
-
- bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
- eDepsOperation_Code opcode, const string &description = "");
-
- OperationDepsNode *find_operation_node(ID *id,
- eDepsNode_Type comp_type,
- const string &comp_name,
- eDepsOperation_Code opcode,
- const string &description = "");
-
- OperationDepsNode *find_operation_node(ID *id,
- eDepsNode_Type comp_type,
- eDepsOperation_Code opcode,
- const string &description = "")
- {
- return find_operation_node(id, comp_type, "", opcode, description);
- }
-
- void build_scene(Main *bmain, Scene *scene);
- SubgraphDepsNode *build_subgraph(Group *group);
- void build_group(Scene *scene, Base *base, Group *group);
- void build_object(Scene *scene, Base *base, Object *ob);
- void build_object_transform(Scene *scene, Object *ob);
- void build_object_constraints(Scene *scene, Object *ob);
- void build_pose_constraints(Object *ob, bPoseChannel *pchan);
- void build_rigidbody(Scene *scene);
- void build_animdata(ID *id);
- OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
- void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
- void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
- void build_rig(Scene *scene, Object *ob);
- void build_proxy_rig(Object *ob);
- void build_shapekeys(Key *key);
- void build_obdata_geom(Scene *scene, Object *ob);
- void build_camera(Object *ob);
- void build_lamp(Object *ob);
- void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
- void build_material(DepsNode *owner_node, Material *ma);
- void build_texture(DepsNode *owner_node, Tex *tex);
- void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
- void build_world(World *world);
- void build_compositor(Scene *scene);
- void build_gpencil(bGPdata *gpd);
-
-private:
- Main *m_bmain;
- Depsgraph *m_graph;
-};
-
struct RootKey
{
RootKey() {}
@@ -163,7 +112,7 @@ struct ComponentKey
const char *idname = (id) ? id->name : "<None>";
char typebuf[5];
- sprintf(typebuf, "%d", type);
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
}
@@ -203,7 +152,7 @@ struct OperationKey
string identifier() const
{
char typebuf[5];
- sprintf(typebuf, "%d", component_type);
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type);
return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
}
@@ -244,29 +193,45 @@ struct DepsgraphRelationBuilder
DepsgraphRelationBuilder(Depsgraph *graph);
template <typename KeyFrom, typename KeyTo>
- void add_relation(const KeyFrom &key_from, const KeyTo &key_to,
- eDepsRelation_Type type, const char *description);
+ void add_relation(const KeyFrom& key_from,
+ const KeyTo& key_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyTo>
- void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to,
- eDepsRelation_Type type, const char *description);
+ void add_relation(const TimeSourceKey& key_from,
+ const KeyTo& key_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyType>
- void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle,
- eDepsRelation_Type type, const char *description);
+ void add_node_handle_relation(const KeyType& key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description);
void build_scene(Main *bmain, Scene *scene);
void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
void build_object(Main *bmain, Scene *scene, Object *ob);
void build_object_parent(Object *ob);
- void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
- ListBase *constraints, RootPChanMap *root_map);
+ void build_constraints(Scene *scene, ID *id,
+ eDepsNode_Type component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map);
void build_animdata(ID *id);
void build_driver(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
- void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
- void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_particles(Scene *scene, Object *ob);
+ void build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ void build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
void build_rig(Scene *scene, Object *ob);
void build_proxy_rig(Object *ob);
void build_shapekeys(ID *obdata, Key *key);
@@ -280,6 +245,9 @@ struct DepsgraphRelationBuilder
void build_compositor(Scene *scene);
void build_gpencil(ID *owner, bGPdata *gpd);
+ template <typename KeyType>
+ OperationDepsNode *find_operation_node(const KeyType &key);
+
protected:
RootDepsNode *find_node(const RootKey &key) const;
TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
@@ -288,12 +256,17 @@ protected:
DepsNode *find_node(const RNAPathKey &key) const;
OperationDepsNode *has_node(const OperationKey &key) const;
- void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
- void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
- eDepsRelation_Type type, const char *description);
+ void add_time_relation(TimeSourceDepsNode *timesrc,
+ DepsNode *node_to,
+ const char *description);
+ void add_operation_relation(OperationDepsNode *node_from,
+ OperationDepsNode *node_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyType>
- DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
+ DepsNodeHandle create_node_handle(const KeyType& key,
+ const string& default_name = "");
bool needs_animdata_node(ID *id);
@@ -318,8 +291,11 @@ struct DepsNodeHandle
/* Utilities for Builders ----------------------------------------------------- */
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu);
+template <typename KeyType>
+OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) {
+ DepsNode *node = find_node(key);
+ return node != NULL ? node->get_exit_operation() : NULL;
+}
template <typename KeyFrom, typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
@@ -375,10 +351,11 @@ void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
}
template <typename KeyType>
-void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
- const DepsNodeHandle *handle,
- eDepsRelation_Type type,
- const char *description)
+void DepsgraphRelationBuilder::add_node_handle_relation(
+ const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description)
{
DepsNode *node_from = find_node(key_from);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
@@ -397,10 +374,11 @@ void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
}
template <typename KeyType>
-DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
- const string &default_name)
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
+ const KeyType &key,
+ const string &default_name)
{
return DepsNodeHandle(this, find_node(key), default_name);
}
-#endif /* __DEPSGRAPH_BUILD_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 98192a9540f..0322ef7fa1d 100644
--- a/source/blender/depsgraph/util/depsgraph_util_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -24,26 +24,25 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_transitive.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_transitive.cc
* \ingroup depsgraph
*/
+#include "intern/builder/deg_builder_transitive.h"
+
extern "C" {
#include "MEM_guardedalloc.h"
+}
-#include "BLI_utildefines.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "DNA_ID.h"
+#include "intern/depsgraph.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
-}
+#include "util/deg_util_foreach.h"
-#include "depsgraph_util_transitive.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+namespace DEG {
/* -------------------------------------------------- */
@@ -67,16 +66,11 @@ enum {
static void deg_graph_tag_paths_recursive(DepsNode *node)
{
- if (node->done & OP_VISITED)
+ if (node->done & OP_VISITED) {
return;
+ }
node->done |= OP_VISITED;
-
- for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
- it != node->inlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
-
+ foreach (DepsRelation *rel, node->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
/* Do this only in inlinks loop, so the target node does not get
* flagged.
@@ -87,18 +81,9 @@ static void deg_graph_tag_paths_recursive(DepsNode *node)
void deg_graph_transitive_reduction(Depsgraph *graph)
{
- for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
- it_target != graph->operations.end();
- ++it_target)
- {
- OperationDepsNode *target = *it_target;
-
+ foreach (OperationDepsNode *target, graph->operations) {
/* Clear tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
+ foreach (OperationDepsNode *node, graph->operations) {
node->done = 0;
}
@@ -107,19 +92,14 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
* flagged.
*/
target->done |= OP_VISITED;
- for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
- it != target->inlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
-
+ foreach (DepsRelation *rel, target->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
}
- /* Eemove redundant paths to the target. */
+ /* Remove redundant paths to the target. */
for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
it_rel != target->inlinks.end();
- )
+ )
{
DepsRelation *rel = *it_rel;
/* Increment in advance, so we can safely remove the relation. */
@@ -137,3 +117,5 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
}
}
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
index a80a1d783d7..be9d7c3ca9c 100644
--- a/source/blender/depsgraph/util/depsgraph_util_transitive.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
@@ -24,15 +24,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_transitive.h
+/** \file blender/depsgraph/intern/builder/deg_builder_transitive.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
-#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
+#pragma once
+
+namespace DEG {
struct Depsgraph;
+/* Performs a transitive reduction to remove redundant relations. */
void deg_graph_transitive_reduction(Depsgraph *graph);
-#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
new file mode 100644
index 00000000000..5ce84ee29db
--- /dev/null
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -0,0 +1,588 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+extern "C" {
+#include "DNA_listBase.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+} /* extern "C" */
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+/* ****************** */
+/* Graphviz Debugging */
+
+namespace DEG {
+
+#define NL "\r\n"
+
+/* Only one should be enabled, defines whether graphviz nodes
+ * get colored by individual types or classes.
+ */
+#define COLOR_SCHEME_NODE_CLASS 1
+//#define COLOR_SCHEME_NODE_TYPE 2
+
+static const char *deg_debug_graphviz_fontname = "helvetica";
+static float deg_debug_graphviz_graph_label_size = 20.0f;
+static float deg_debug_graphviz_node_label_size = 14.0f;
+static const int deg_debug_max_colors = 12;
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const char *deg_debug_colors[] = {
+ "#a6cee3", "#1f78b4", "#b2df8a",
+ "#33a02c", "#fb9a99", "#e31a1c",
+ "#fdbf6f", "#ff7f00", "#cab2d6",
+ "#6a3d9a", "#ffff99", "#b15928",
+};
+#endif
+static const char *deg_debug_colors_light[] = {
+ "#8dd3c7", "#ffffb3", "#bebada",
+ "#fb8072", "#80b1d3", "#fdb462",
+ "#b3de69", "#fccde5", "#d9d9d9",
+ "#bc80bd", "#ccebc5", "#ffed6f",
+};
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const int deg_debug_node_type_color_map[][2] = {
+ {DEPSNODE_TYPE_ROOT, 0},
+ {DEPSNODE_TYPE_TIMESOURCE, 1},
+ {DEPSNODE_TYPE_ID_REF, 2},
+ {DEPSNODE_TYPE_SUBGRAPH, 3},
+
+ /* Outer Types */
+ {DEPSNODE_TYPE_PARAMETERS, 4},
+ {DEPSNODE_TYPE_PROXY, 5},
+ {DEPSNODE_TYPE_ANIMATION, 6},
+ {DEPSNODE_TYPE_TRANSFORM, 7},
+ {DEPSNODE_TYPE_GEOMETRY, 8},
+ {DEPSNODE_TYPE_SEQUENCER, 9},
+ {DEPSNODE_TYPE_SHADING, 10},
+ {-1, 0}
+};
+#endif
+
+static int deg_debug_node_color_index(const DepsNode *node)
+{
+#ifdef COLOR_SCHEME_NODE_CLASS
+ /* Some special types. */
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ return 5;
+ case DEPSNODE_TYPE_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->is_noop())
+ return 8;
+ break;
+ }
+
+ default:
+ break;
+ }
+ /* Do others based on class. */
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_OPERATION:
+ return 4;
+ case DEPSNODE_CLASS_COMPONENT:
+ return 1;
+ default:
+ return 9;
+ }
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == node->type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+#endif
+}
+
+struct DebugContext {
+ FILE *file;
+ bool show_tags;
+ bool show_eval_priority;
+};
+
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
+ const char *name,
+ const char *color)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+
+static void deg_debug_graphviz_legend(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "{" NL);
+ deg_debug_fprintf(ctx, "rank = sink;" NL);
+ deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
+ deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
+ deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
+
+#ifdef COLOR_SCHEME_NODE_CLASS
+ const char **colors = deg_debug_colors_light;
+ deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
+ deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
+ deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
+ deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ deg_debug_graphviz_legend_color(ctx,
+ nti->tname().c_str(),
+ deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
+ }
+#endif
+
+ deg_debug_fprintf(ctx, "</TABLE>" NL);
+ deg_debug_fprintf(ctx, ">" NL);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+static void deg_debug_graphviz_node_color(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *color_default = "black";
+ const char *color_modified = "orangered4";
+ const char *color_update = "dodgerblue3";
+ const char *color = color_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ color = color_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ color = color_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%s\"", color);
+}
+
+static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ float penwidth_default = 1.0f;
+ float penwidth_modified = 4.0f;
+ float penwidth_update = 4.0f;
+ float penwidth = penwidth_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ penwidth = penwidth_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ penwidth = penwidth_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%f\"", penwidth);
+}
+
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ int color_index = deg_debug_node_color_index(node);
+ const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
+}
+
+static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
+ const DepsRelation *rel)
+{
+ const char *color_default = "black";
+ const char *color_error = "red4";
+ const char *color = color_default;
+ if (rel->flag & DEPSREL_FLAG_CYCLIC) {
+ color = color_error;
+ }
+ deg_debug_fprintf(ctx, "%s", color);
+}
+
+static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
+{
+ const char *base_style = "filled"; /* default style */
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
+ base_style = "striped";
+ }
+ }
+ }
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_GENERIC:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_COMPONENT:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_OPERATION:
+ deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
+ break;
+ }
+}
+
+static void deg_debug_graphviz_node_single(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *shape = "box";
+ string name = node->identifier();
+ float priority = -1.0f;
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ priority = ((OperationDepsNode *)node)->eval_priority;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
+ if (priority >= 0.0f) {
+ deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
+ name.c_str(),
+ priority);
+ }
+ else {
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
+ }
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, ",shape=%s", shape);
+ deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
+ deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
+ deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ string name = node->identifier().c_str();
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
+ deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
+ deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16);
+ deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ /* dummy node, so we can add edges between clusters */
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "shape=%s", "point");
+ deg_debug_fprintf(ctx, ",style=%s", "invis");
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "}" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph);
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph);
+
+static void deg_debug_graphviz_node(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ if (BLI_ghash_size(id_node->components) == 0) {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ else {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp, id_node->components)
+ {
+ deg_debug_graphviz_node(ctx, comp);
+ }
+ GHASH_FOREACH_END();
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ case DEPSNODE_TYPE_SHADING:
+ case DEPSNODE_TYPE_EVAL_PARTICLES:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (!comp_node->operations.empty()) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ foreach (DepsNode *op_node, comp_node->operations) {
+ deg_debug_graphviz_node(ctx, op_node);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ default:
+ deg_debug_graphviz_node_single(ctx, node);
+ break;
+ }
+}
+
+static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ return BLI_ghash_size(id_node->components) > 0;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ return sub_node->graph != NULL;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ return !comp_node->operations.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+static bool deg_debug_graphviz_is_owner(const DepsNode *node,
+ const DepsNode *other)
+{
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_COMPONENT:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (comp_node->owner == other)
+ return true;
+ break;
+ }
+ case DEPSNODE_CLASS_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->owner == other)
+ return true;
+ else if (op_node->owner->owner == other)
+ return true;
+ break;
+ }
+ default: break;
+ }
+ return false;
+}
+
+static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ foreach (DepsRelation *rel, node->inlinks) {
+ float penwidth = 2.0f;
+
+ const DepsNode *tail = rel->to; /* same as node */
+ const DepsNode *head = rel->from;
+ deg_debug_fprintf(ctx, "// %s -> %s\n",
+ head->identifier().c_str(),
+ tail->identifier().c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", head);
+ deg_debug_fprintf(ctx, " -> ");
+ deg_debug_fprintf(ctx, "\"node_%p\"", tail);
+
+ deg_debug_fprintf(ctx, "[");
+ /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
+ deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
+ deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
+ /* NOTE: edge from node to own cluster is not possible and gives graphviz
+ * warning, avoid this here by just linking directly to the invisible
+ * placeholder node
+ */
+ if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
+ deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
+ }
+ if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
+ deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
+ }
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+ }
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ if (graph->root_node) {
+ deg_debug_graphviz_node(ctx, graph->root_node);
+ }
+ GHASH_FOREACH_BEGIN (DepsNode *, node, graph->id_hash)
+ {
+ deg_debug_graphviz_node(ctx, node);
+ }
+ GHASH_FOREACH_END();
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node(ctx, time_source);
+ }
+}
+
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ foreach (OperationDepsNode *op_node, comp_node->operations) {
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ GHASH_FOREACH_END();
+ }
+ GHASH_FOREACH_END();
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node_relations(ctx, time_source);
+ }
+}
+
+} // namespace DEG
+
+void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+{
+ if (!graph) {
+ return;
+ }
+
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
+ DEG::DebugContext ctx;
+ ctx.file = f;
+ ctx.show_tags = show_eval;
+ ctx.show_eval_priority = show_eval;
+
+ DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL);
+ DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL);
+ DEG::deg_debug_fprintf(ctx, "graph [");
+ DEG::deg_debug_fprintf(ctx, "compound=true");
+ DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\"");
+ DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size);
+ DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname);
+ DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label);
+ DEG::deg_debug_fprintf(ctx, ",splines=ortho");
+ DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
+ DEG::deg_debug_fprintf(ctx, "];" NL);
+
+ DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph);
+ DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph);
+
+ DEG::deg_debug_graphviz_legend(ctx);
+
+ DEG::deg_debug_fprintf(ctx, "}" NL);
+}
+
+#undef NL
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index d293d03f63d..2b7c63767ab 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -30,10 +30,14 @@
* Core routines for how the Depsgraph works.
*/
+#include "intern/depsgraph.h" /* own include */
+
#include <string.h>
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
extern "C" {
@@ -50,11 +54,15 @@ extern "C" {
}
#include "DEG_depsgraph.h"
-#include "depsgraph.h" /* own include */
-#include "depsnode.h"
-#include "depsnode_operation.h"
-#include "depsnode_component.h"
-#include "depsgraph_intern.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
@@ -66,6 +74,9 @@ Depsgraph::Depsgraph()
layers(0)
{
BLI_spin_init(&lock);
+ id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
+ subgraphs = BLI_gset_ptr_new("Depsgraph subgraphs");
+ entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
}
Depsgraph::~Depsgraph()
@@ -73,6 +84,9 @@ Depsgraph::~Depsgraph()
/* Free root node - it won't have been freed yet... */
clear_id_nodes();
clear_subgraph_nodes();
+ BLI_ghash_free(id_hash, NULL, NULL);
+ BLI_gset_free(subgraphs, NULL);
+ BLI_gset_free(entry_tags, NULL);
if (this->root_node != NULL) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
}
@@ -235,10 +249,16 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
/* Node Management ---------------------------- */
+static void id_node_deleter(void *value)
+{
+ IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value);
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+}
+
RootDepsNode *Depsgraph::add_root_node()
{
if (!root_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ROOT);
root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
}
return root_node;
@@ -267,12 +287,12 @@ TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
{
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
SubgraphDepsNode *subgraph_node =
(SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
/* Add to subnodes list. */
- this->subgraphs.insert(subgraph_node);
+ BLI_gset_insert(subgraphs, subgraph_node);
/* if there's an ID associated, add to ID-nodes lookup too */
if (id) {
@@ -289,37 +309,34 @@ SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
{
- subgraphs.erase(subgraph_node);
+ BLI_gset_remove(subgraphs, subgraph_node, NULL);
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
void Depsgraph::clear_subgraph_nodes()
{
- for (Subgraphs::iterator it = subgraphs.begin();
- it != subgraphs.end();
- ++it)
+ GSET_FOREACH_BEGIN(SubgraphDepsNode *, subgraph_node, subgraphs)
{
- SubgraphDepsNode *subgraph_node = *it;
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
- subgraphs.clear();
+ GSET_FOREACH_END();
+ BLI_gset_clear(subgraphs, NULL);
}
IDDepsNode *Depsgraph::find_id_node(const ID *id) const
{
- IDNodeMap::const_iterator it = this->id_hash.find(id);
- return it != this->id_hash.end() ? it->second : NULL;
+ return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
}
IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
id->tag |= LIB_TAG_DOIT;
/* register */
- this->id_hash[id] = id_node;
+ BLI_ghash_insert(id_hash, id, id_node);
}
return id_node;
}
@@ -329,21 +346,14 @@ void Depsgraph::remove_id_node(const ID *id)
IDDepsNode *id_node = find_id_node(id);
if (id_node) {
/* unregister */
- this->id_hash.erase(id);
+ BLI_ghash_remove(id_hash, id, NULL, NULL);
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
}
void Depsgraph::clear_id_nodes()
{
- for (IDNodeMap::const_iterator it = id_hash.begin();
- it != id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
- }
- id_hash.clear();
+ BLI_ghash_clear(id_hash, NULL, id_node_deleter);
}
/* Add new relationship between two nodes. */
@@ -449,33 +459,52 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node)
/* Add to graph-level set of directly modified nodes to start searching from.
* NOTE: this is necessary since we have several thousand nodes to play with...
*/
- this->entry_tags.insert(node);
+ BLI_gset_insert(entry_tags, node);
}
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
clear_subgraph_nodes();
- id_hash.clear();
+ BLI_ghash_clear(id_hash, NULL, NULL);
if (this->root_node) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
root_node = NULL;
}
}
+void deg_editors_id_update(Main *bmain, ID *id)
+{
+ if (deg_editor_update_id_cb != NULL) {
+ deg_editor_update_id_cb(bmain, id);
+ }
+}
+
+void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+{
+ if (deg_editor_update_scene_cb != NULL) {
+ deg_editor_update_scene_cb(bmain, scene, updated);
+ }
+}
+
+} // namespace DEG
+
/* **************** */
/* Public Graph API */
/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new()
{
- return OBJECT_GUARDED_NEW(Depsgraph);
+ DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph);
+ return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
- OBJECT_GUARDED_DELETE(graph, Depsgraph);
+ using DEG::Depsgraph;
+ DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
/* Set callbacks which are being called when depsgraph changes. */
@@ -483,28 +512,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func,
DEG_EditorUpdateScenePreCb scene_pre_func)
{
- deg_editor_update_id_cb = id_func;
- deg_editor_update_scene_cb = scene_func;
- deg_editor_update_scene_pre_cb = scene_pre_func;
+ DEG::deg_editor_update_id_cb = id_func;
+ DEG::deg_editor_update_scene_cb = scene_func;
+ DEG::deg_editor_update_scene_pre_cb = scene_pre_func;
}
void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
{
- if (deg_editor_update_scene_pre_cb != NULL) {
- deg_editor_update_scene_pre_cb(bmain, scene, time);
- }
-}
-
-void deg_editors_id_update(Main *bmain, ID *id)
-{
- if (deg_editor_update_id_cb != NULL) {
- deg_editor_update_id_cb(bmain, id);
- }
-}
-
-void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
-{
- if (deg_editor_update_scene_cb != NULL) {
- deg_editor_update_scene_cb(bmain, scene, updated);
+ if (DEG::deg_editor_update_scene_pre_cb != NULL) {
+ DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 9533fbd10d5..213bb304d73 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -34,19 +34,20 @@
* in the graph.
*/
-#ifndef __DEPSGRAPH_H__
-#define __DEPSGRAPH_H__
+#pragma once
#include "BLI_threads.h" /* for SpinLock */
-#include "depsgraph_types.h"
-
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "intern/depsgraph_types.h"
+struct ID;
+struct GHash;
+struct GSet;
struct PointerRNA;
struct PropertyRNA;
+namespace DEG {
+
struct DepsNode;
struct RootDepsNode;
struct TimeSourceDepsNode;
@@ -94,9 +95,6 @@ struct DepsRelation {
/* Dependency Graph object */
struct Depsgraph {
- typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
- typedef unordered_set<SubgraphDepsNode *> Subgraphs;
- typedef unordered_set<OperationDepsNode *> EntryTags;
typedef vector<OperationDepsNode *> OperationNodes;
Depsgraph();
@@ -163,13 +161,13 @@ struct Depsgraph {
/* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
* (for quick lookups). */
- IDNodeMap id_hash;
+ GHash *id_hash;
/* "root" node - the one where all evaluation enters from. */
RootDepsNode *root_node;
/* Subgraphs referenced in tree. */
- Subgraphs subgraphs;
+ GSet *subgraphs;
/* Indicates whether relations needs to be updated. */
bool need_update;
@@ -177,7 +175,7 @@ struct Depsgraph {
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
- EntryTags entry_tags;
+ GSet *entry_tags;
/* Convenience Data ................... */
@@ -198,27 +196,4 @@ struct Depsgraph {
// XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
};
-/**
- * Helper macros for iterating over set of relationship links
- * incident on each node.
- *
- * \note it is safe to perform removal operations here...
- *
- * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
- * relation[out]: (DepsRelation *) identifier where DepsRelation that we're
- * currently accessing comes up
- */
-#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
- { \
- OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
- while (__rel_iter != relations_set_.end()) { \
- DepsRelation *relation_ = *__rel_iter; \
- ++__rel_iter; \
-
- /* ... code for iterator body can be written here ... */
-
-#define DEPSNODE_RELATIONS_ITER_END \
- } \
- } ((void)0)
-
-#endif /* __DEPSGRAPH_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 82f312c2171..b1271c39851 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -30,135 +30,128 @@
* Methods for constructing depsgraph.
*/
-#include <stack>
-
#include "MEM_guardedalloc.h"
extern "C" {
-#include "BLI_blenlib.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_action_types.h"
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_effect_types.h"
-#include "DNA_group_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_node_types.h"
#include "DNA_object_types.h"
-#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_world_types.h"
-
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_animsys.h"
-#include "BKE_constraint.h"
-#include "BKE_curve.h"
-#include "BKE_effect.h"
-#include "BKE_fcurve.h"
-#include "BKE_group.h"
-#include "BKE_key.h"
-#include "BKE_library.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_modifier.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_rigidbody.h"
-#include "BKE_sound.h"
-#include "BKE_texture.h"
-#include "BKE_tracking.h"
-#include "BKE_world.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsgraph_debug.h"
-#include "depsnode_operation.h"
-#include "depsgraph_types.h"
-#include "depsgraph_build.h"
-#include "depsgraph_intern.h"
+#include "builder/deg_builder.h"
+#include "builder/deg_builder_cycle.h"
+#include "builder/deg_builder_nodes.h"
+#include "builder/deg_builder_relations.h"
+#include "builder/deg_builder_transitive.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
-#include "depsgraph_util_cycle.h"
-#include "depsgraph_util_transitive.h"
+#include "util/deg_util_foreach.h"
/* ****************** */
/* External Build API */
-static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
+static DEG::eDepsNode_Type deg_build_scene_component_type(
+ eDepsSceneComponentType component)
{
switch (component) {
- case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
- case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
- case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
+ case DEG_SCENE_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEG::DEPSNODE_TYPE_SEQUENCER;
}
- return DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEPSNODE_TYPE_UNDEFINED;
}
-static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
+static DEG::eDepsNode_Type deg_build_object_component_type(
+ eDepsObjectComponentType component)
{
switch (component) {
- case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
- case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
- case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
- case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
- case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
- case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
- case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
- case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
- case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
+ case DEG_OB_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEG::DEPSNODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEG::DEPSNODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEG::DEPSNODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEG::DEPSNODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
}
- return DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEPSNODE_TYPE_UNDEFINED;
}
-void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
+static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle)
{
- eDepsNode_Type type = deg_build_scene_component_type(component);
- ComponentKey comp_key(&scene->id, type);
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+ return reinterpret_cast<DEG::DepsNodeHandle *>(handle);
}
-void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
+void DEG_add_scene_relation(DepsNodeHandle *handle,
+ Scene *scene,
+ eDepsSceneComponentType component,
+ const char *description)
{
- eDepsNode_Type type = deg_build_object_component_type(component);
- ComponentKey comp_key(&ob->id, type);
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+ DEG::eDepsNode_Type type = deg_build_scene_component_type(component);
+ DEG::ComponentKey comp_key(&scene->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
}
-void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
+void DEG_add_object_relation(DepsNodeHandle *handle,
+ Object *ob,
+ eDepsObjectComponentType component,
+ const char *description)
{
- eDepsNode_Type type = deg_build_object_component_type(component);
- ComponentKey comp_key(&ob->id, type, bone_name);
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&ob->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
+}
- // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+void DEG_add_bone_relation(DepsNodeHandle *handle,
+ Object *ob,
+ const char *bone_name,
+ eDepsObjectComponentType component,
+ const char *description)
+{
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&ob->id, type, bone_name);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ /* XXX: "Geometry Eval" might not always be true, but this only gets called
+ * from modifier building now.
+ */
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
}
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
if (graph == NULL) {
BLI_assert(!"Graph should always be valid");
return;
}
- IDDepsNode *id_node = graph->find_id_node(id);
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
BLI_assert(!"ID should always be valid");
return;
@@ -166,110 +159,21 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
id_node->eval_flags |= flag;
}
-/* ********************** */
-/* Utilities for Builders */
-
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu)
-{
- char index_buf[32];
- sprintf(index_buf, "[%d]", fcu->array_index);
-
- return string(fcu->rna_path) + index_buf;
-}
-
-static void deg_graph_build_finalize(Depsgraph *graph)
-{
- std::stack<OperationDepsNode *> stack;
-
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- node->done = 0;
- node->num_links_pending = 0;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- ++node->num_links_pending;
- }
- }
- if (node->num_links_pending == 0) {
- stack.push(node);
- }
- IDDepsNode *id_node = node->owner->owner;
- id_node->id->tag |= LIB_TAG_DOIT;
- }
-
- while (!stack.empty()) {
- OperationDepsNode *node = stack.top();
- if (node->done == 0 && node->outlinks.size() != 0) {
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(to->num_links_pending > 0);
- --to->num_links_pending;
- }
- if (to->num_links_pending == 0) {
- stack.push(to);
- }
- }
- }
- node->done = 1;
- }
- else {
- stack.pop();
- IDDepsNode *id_node = node->owner->owner;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- IDDepsNode *id_to = to->owner->owner;
- id_node->layers |= id_to->layers;
- }
- }
- }
- }
-
- /* Re-tag IDs for update if it was tagged before the relations update tag. */
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- ID *id = id_node->id;
- if (id->tag & LIB_TAG_ID_RECALC_ALL &&
- id->tag & LIB_TAG_DOIT)
- {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
- }
-}
-
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene, and dump results in given graph container */
-// XXX: assume that this is called from outside, given the current scene as the "main" scene
+/* Build depsgraph for the given scene, and dump results in given
+ * graph container.
+ */
+/* XXX: assume that this is called from outside, given the current scene as
+ * the "main" scene.
+ */
void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+
/* 1) Generate all the nodes in the graph first */
- DepsgraphNodeBuilder node_builder(bmain, graph);
+ DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
/* create root node for scene first
* - this way it should be the first in the graph,
* reflecting its role as the entrypoint
@@ -277,29 +181,40 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
node_builder.add_root_node();
node_builder.build_scene(bmain, scene);
- /* 2) Hook up relationships between operations - to determine evaluation order */
- DepsgraphRelationBuilder relation_builder(graph);
- /* hook scene up to the root node as entrypoint to graph */
+ /* 2) Hook up relationships between operations - to determine evaluation
+ * order.
+ */
+ DEG::DepsgraphRelationBuilder relation_builder(deg_graph);
+ /* Hook scene up to the root node as entrypoint to graph. */
/* XXX what does this relation actually mean?
- * it doesnt add any operations anyway and is not clear what part of the scene is to be connected.
+ * it doesnt add any operations anyway and is not clear what part of the
+ * scene is to be connected.
*/
- //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
+#if 0
+ relation_builder.add_relation(RootKey(),
+ IDKey(scene),
+ DEPSREL_TYPE_ROOT_TO_ACTIVE,
+ "Root to Active Scene");
+#endif
relation_builder.build_scene(bmain, scene);
/* Detect and solve cycles. */
- deg_graph_detect_cycles(graph);
+ DEG::deg_graph_detect_cycles(deg_graph);
- /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
- // TODO: it would be useful to have an option to disable this in cases where it is causing trouble
+ /* 3) Simplify the graph by removing redundant relations (to optimize
+ * traversal later). */
+ /* TODO: it would be useful to have an option to disable this in cases where
+ * it is causing trouble.
+ */
if (G.debug_value == 799) {
- deg_graph_transitive_reduction(graph);
+ DEG::deg_graph_transitive_reduction(deg_graph);
}
/* 4) Flush visibility layer and re-schedule nodes for update. */
- deg_graph_build_finalize(graph);
+ DEG::deg_graph_build_finalize(deg_graph);
#if 0
- if (!DEG_debug_consistency_check(graph)) {
+ if (!DEG_debug_consistency_check(deg_graph)) {
printf("Consistency validation failed, ABORTING!\n");
abort();
}
@@ -309,7 +224,8 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
- graph->need_update = true;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ deg_graph->need_update = true;
}
/* Tag all relations for update. */
@@ -337,7 +253,7 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
return;
}
- Depsgraph *graph = scene->depsgraph;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
if (!graph->need_update) {
/* Graph is up to date, nothing to do. */
return;
@@ -346,10 +262,12 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
/* Clear all previous nodes and operations. */
graph->clear_all_nodes();
graph->operations.clear();
- graph->entry_tags.clear();
+ BLI_gset_clear(graph->entry_tags, NULL);
/* Build new nodes and relations. */
- DEG_graph_build_from_scene(graph, bmain, scene);
+ DEG_graph_build_from_scene(reinterpret_cast< ::Depsgraph * >(graph),
+ bmain,
+ scene);
graph->need_update = false;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index efb3e330857..d3b48930779 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -30,956 +30,39 @@
* Implementation of tools for debugging the depsgraph
*/
-//#include <stdlib.h>
-#include <string.h>
-
-extern "C" {
#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_string.h"
+extern "C" {
#include "DNA_scene_types.h"
-#include "DNA_userdef_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
} /* extern "C" */
-#include "depsgraph_debug.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
-
-/* ****************** */
-/* Graphviz Debugging */
-
-#define NL "\r\n"
-
-/* Only one should be enabled, defines whether graphviz nodes
- * get colored by individual types or classes.
- */
-#define COLOR_SCHEME_NODE_CLASS 1
-//#define COLOR_SCHEME_NODE_TYPE 2
-
-static const char *deg_debug_graphviz_fontname = "helvetica";
-static float deg_debug_graphviz_graph_label_size = 20.0f;
-static float deg_debug_graphviz_node_label_size = 14.0f;
-static const int deg_debug_max_colors = 12;
-#if 0
-static const char *deg_debug_colors_dark[] = {
- "#6e8997", "#144f77", "#76945b",
- "#216a1d", "#a76665", "#971112",
- "#a87f49", "#0a9540", "#86768e",
- "#462866", "#a9a965", "#753b1a",
-};
-#endif
-#ifdef COLOR_SCHEME_NODE_TYPE
-static const char *deg_debug_colors[] = {
- "#a6cee3", "#1f78b4", "#b2df8a",
- "#33a02c", "#fb9a99", "#e31a1c",
- "#fdbf6f", "#ff7f00", "#cab2d6",
- "#6a3d9a", "#ffff99", "#b15928",
-};
-#endif
-static const char *deg_debug_colors_light[] = {
- "#8dd3c7", "#ffffb3", "#bebada",
- "#fb8072", "#80b1d3", "#fdb462",
- "#b3de69", "#fccde5", "#d9d9d9",
- "#bc80bd", "#ccebc5", "#ffed6f",
-};
-
-#ifdef COLOR_SCHEME_NODE_TYPE
-static const int deg_debug_node_type_color_map[][2] = {
- {DEPSNODE_TYPE_ROOT, 0},
- {DEPSNODE_TYPE_TIMESOURCE, 1},
- {DEPSNODE_TYPE_ID_REF, 2},
- {DEPSNODE_TYPE_SUBGRAPH, 3},
-
- /* Outer Types */
- {DEPSNODE_TYPE_PARAMETERS, 4},
- {DEPSNODE_TYPE_PROXY, 5},
- {DEPSNODE_TYPE_ANIMATION, 6},
- {DEPSNODE_TYPE_TRANSFORM, 7},
- {DEPSNODE_TYPE_GEOMETRY, 8},
- {DEPSNODE_TYPE_SEQUENCER, 9},
- {DEPSNODE_TYPE_SHADING, 10},
- {-1, 0}
-};
-#endif
-
-#if 0 /* unused */
-static const int deg_debug_relation_type_color_map[][2] = {
- {DEPSREL_TYPE_STANDARD, 0},
- {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1},
- {DEPSREL_TYPE_DATABLOCK, 2},
- {DEPSREL_TYPE_TIME, 3},
- {DEPSREL_TYPE_COMPONENT_ORDER, 4},
- {DEPSREL_TYPE_OPERATION, 5},
- {DEPSREL_TYPE_DRIVER, 6},
- {DEPSREL_TYPE_DRIVER_TARGET, 7},
- {DEPSREL_TYPE_TRANSFORM, 8},
- {DEPSREL_TYPE_GEOMETRY_EVAL, 9},
- {DEPSREL_TYPE_UPDATE, 10},
- {DEPSREL_TYPE_UPDATE_UI, 11},
- {-1, 0}
-};
-#endif
-
-static int deg_debug_node_color_index(const DepsNode *node)
-{
-#ifdef COLOR_SCHEME_NODE_CLASS
- /* Some special types. */
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- return 5;
- case DEPSNODE_TYPE_OPERATION:
- {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->is_noop())
- return 8;
- break;
- }
-
- default:
- break;
- }
- /* Do others based on class. */
- switch (node->tclass) {
- case DEPSNODE_CLASS_OPERATION:
- return 4;
- case DEPSNODE_CLASS_COMPONENT:
- return 1;
- default:
- return 9;
- }
-#endif
-
-#ifdef COLOR_SCHEME_NODE_TYPE
- const int (*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- if ((*pair)[0] == node->type) {
- return (*pair)[1];
- }
- }
- return -1;
-#endif
-}
-
-struct DebugContext {
- FILE *file;
- bool show_tags;
- bool show_eval_priority;
-};
-
-static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
-static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vfprintf(ctx.file, fmt, args);
- va_end(args);
-}
-
-static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
- const char *name,
- const char *color)
-{
- deg_debug_fprintf(ctx, "<TR>");
- deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
- deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
- deg_debug_fprintf(ctx, "</TR>" NL);
-}
-
-#if 0
-static void deg_debug_graphviz_legend_line(const DebugContext &ctx,
- const char *name,
- const char *color,
- const char *style)
-{
- /* XXX TODO */
- deg_debug_fprintf(ctx, "" NL);
-}
-
-static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx,
- const char *name,
- const char *color,
- const char *style)
-{
- deg_debug_fprintf(ctx, "<TR>");
- deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
- deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
- deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color);
- deg_debug_fprintf(ctx, "</TABLE></TD>");
- deg_debug_fprintf(ctx, "</TR>" NL);
-}
-#endif
-
-static void deg_debug_graphviz_legend(const DebugContext &ctx)
-{
- deg_debug_fprintf(ctx, "{" NL);
- deg_debug_fprintf(ctx, "rank = sink;" NL);
- deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
- deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
- deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
-
-#ifdef COLOR_SCHEME_NODE_CLASS
- const char **colors = deg_debug_colors_light;
- deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
- deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
- deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
- deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
-#endif
-
-#ifdef COLOR_SCHEME_NODE_TYPE
- const int (*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
- deg_debug_graphviz_legend_color(ctx,
- nti->tname().c_str(),
- deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
- }
-#endif
-
- deg_debug_fprintf(ctx, "</TABLE>" NL);
- deg_debug_fprintf(ctx, ">" NL);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, "}" NL);
-}
-
-#if 0 /* unused */
-static int deg_debug_relation_type_color_index(eDepsRelation_Type type)
-{
- const int (*pair)[2];
- for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) {
- if ((*pair)[0] == type) {
- return (*pair)[1];
- }
- }
- return -1;
-}
-#endif
-
-static void deg_debug_graphviz_node_color(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *color_default = "black";
- const char *color_modified = "orangered4";
- const char *color_update = "dodgerblue3";
- const char *color = color_default;
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
- color = color_modified;
- }
- else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- color = color_update;
- }
- }
- }
- deg_debug_fprintf(ctx, "\"%s\"", color);
-}
-
-static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
- const DepsNode *node)
-{
- float penwidth_default = 1.0f;
- float penwidth_modified = 4.0f;
- float penwidth_update = 4.0f;
- float penwidth = penwidth_default;
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
- penwidth = penwidth_modified;
- }
- else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- penwidth = penwidth_update;
- }
- }
- }
- deg_debug_fprintf(ctx, "\"%f\"", penwidth);
-}
-
-static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *defaultcolor = "gainsboro";
- int color_index = deg_debug_node_color_index(node);
- const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
- deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
-}
-
-#if 0 /* implementation using stripes, a bit too noisy ... */
-static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *defaultcolor = "gainsboro";
- const char *color_needs_update = "orange";
- const int num_stripes = 10;
- int color_index = deg_debug_node_color_index(node);
- const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
- if (ctx.show_tags &&
- (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE)))
- {
- deg_debug_fprintf(ctx, "\"");
- for (int i = 0; i < num_stripes; ++i) {
- if (i > 0) {
- deg_debug_fprintf(ctx, ":");
- }
- deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update);
- }
- deg_debug_fprintf(ctx, "\"");
- }
- else {
- deg_debug_fprintf(ctx, "\"%s\"", base_color);
- }
-}
-#endif
-
-static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
- const DepsRelation *rel)
-{
- const char *color_default = "black";
- const char *color_error = "red4";
- const char *color = color_default;
-#if 0 /* disabled for now, edge colors are hardly distinguishable */
- int color = deg_debug_relation_type_color_index(rel->type);
- if (color < 0) {
- deg_debug_fprintf(ctx, "%s", defaultcolor);
- }
- else {
- deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]);
- }
-#else
- if (rel->flag & DEPSREL_FLAG_CYCLIC)
- color = color_error;
-
- deg_debug_fprintf(ctx, "%s", color);
-#endif
-}
-
-static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
-{
- const char *base_style = "filled"; /* default style */
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
- base_style = "striped";
- }
- }
- }
- switch (node->tclass) {
- case DEPSNODE_CLASS_GENERIC:
- deg_debug_fprintf(ctx, "\"%s\"", base_style);
- break;
- case DEPSNODE_CLASS_COMPONENT:
- deg_debug_fprintf(ctx, "\"%s\"", base_style);
- break;
- case DEPSNODE_CLASS_OPERATION:
- deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
- break;
- }
-}
-
-static void deg_debug_graphviz_node_single(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *shape = "box";
- string name = node->identifier();
- float priority = -1.0f;
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
- name += buf;
- }
- if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
- priority = ((OperationDepsNode *)node)->eval_priority;
- }
- deg_debug_fprintf(ctx, "// %s\n", name.c_str());
- deg_debug_fprintf(ctx, "\"node_%p\"", node);
- deg_debug_fprintf(ctx, "[");
-// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
- if (priority >= 0.0f) {
- deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
- name.c_str(),
- priority);
- }
- else {
- deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
- }
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
- deg_debug_fprintf(ctx, ",shape=%s", shape);
- deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
- deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
- deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
- deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
- const DepsNode *node)
-{
- string name = node->identifier().c_str();
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
- name += buf;
- }
- deg_debug_fprintf(ctx, "// %s\n", name.c_str());
- deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
-// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
- deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
- deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
- deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16);
- deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- /* dummy node, so we can add edges between clusters */
- deg_debug_fprintf(ctx, "\"node_%p\"", node);
- deg_debug_fprintf(ctx, "[");
- deg_debug_fprintf(ctx, "shape=%s", "point");
- deg_debug_fprintf(ctx, ",style=%s", "invis");
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
-{
- deg_debug_fprintf(ctx, "}" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
- const Depsgraph *graph);
-static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
- const Depsgraph *graph);
-
-static void deg_debug_graphviz_node(const DebugContext &ctx,
- const DepsNode *node)
-{
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- if (id_node->components.empty()) {
- deg_debug_graphviz_node_single(ctx, node);
- }
- else {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- const ComponentDepsNode *comp = it->second;
- deg_debug_graphviz_node(ctx, comp);
- }
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- break;
- }
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- case DEPSNODE_TYPE_SHADING:
- case DEPSNODE_TYPE_EVAL_PARTICLES:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- if (!comp_node->operations.empty()) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- const DepsNode *op_node = it->second;
- deg_debug_graphviz_node(ctx, op_node);
- }
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- default:
- deg_debug_graphviz_node_single(ctx, node);
- break;
- }
-}
-
-static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
-{
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- return !id_node->components.empty();
- }
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- return sub_node->graph != NULL;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- return !comp_node->operations.empty();
- }
- default:
- return false;
- }
-}
-
-static bool deg_debug_graphviz_is_owner(const DepsNode *node,
- const DepsNode *other)
-{
- switch (node->tclass) {
- case DEPSNODE_CLASS_COMPONENT:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- if (comp_node->owner == other)
- return true;
- break;
- }
- case DEPSNODE_CLASS_OPERATION:
- {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->owner == other)
- return true;
- else if (op_node->owner->owner == other)
- return true;
- break;
- }
- default: break;
- }
- return false;
-}
-
-static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
- const DepsNode *node)
-{
- DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
- {
- float penwidth = 2.0f;
-
- const DepsNode *tail = rel->to; /* same as node */
- const DepsNode *head = rel->from;
- deg_debug_fprintf(ctx, "// %s -> %s\n",
- head->identifier().c_str(),
- tail->identifier().c_str());
- deg_debug_fprintf(ctx, "\"node_%p\"", head);
- deg_debug_fprintf(ctx, " -> ");
- deg_debug_fprintf(ctx, "\"node_%p\"", tail);
-
- deg_debug_fprintf(ctx, "[");
- /* XXX labels on relations are not very helpful:
- * - they tend to appear too far away to be associated with the edge lines
- * - names are mostly redundant, reflecting simply their from/to nodes
- * - no behavior or typing of relations themselves to justify labels
- */
-#if 0
- deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
-#else
- /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
- deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
-#endif
- deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
- deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
- /* NOTE: edge from node to own cluster is not possible and gives graphviz
- * warning, avoid this here by just linking directly to the invisible
- * placeholder node
- */
- if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
- deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
- }
- if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
- deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
- }
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
- }
- DEPSNODE_RELATIONS_ITER_END;
-
-#if 0
- if (node->tclass == DEPSNODE_CLASS_COMPONENT) {
- const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
- deg_debug_graphviz_node_relations(ctx, op_node);
- }
- }
- else if (node->type == DEPSNODE_TYPE_ID_REF) {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- const ComponentDepsNode *comp = it->second;
- deg_debug_graphviz_node_relations(ctx, comp);
- }
- }
- else if (node->type == DEPSNODE_TYPE_SUBGRAPH) {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_graph_relations(ctx, sub_node->graph);
- }
- }
-#endif
-}
-
-static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
- const Depsgraph *graph)
-{
- if (graph->root_node) {
- deg_debug_graphviz_node(ctx, graph->root_node);
- }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- DepsNode *node = it->second;
- deg_debug_graphviz_node(ctx, node);
- }
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
- if (time_source != NULL) {
- deg_debug_graphviz_node(ctx, time_source);
- }
-}
-
-static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
- const Depsgraph *graph)
-{
-#if 0
- if (graph->root_node) {
- deg_debug_graphviz_node_relations(ctx, graph->root_node);
- }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- DepsNode *id_node = it->second;
- deg_debug_graphviz_node_relations(ctx, id_node);
- }
-#else
- /* XXX not in use yet */
-// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin();
-// it != graph->all_opnodes.end();
-// ++it)
-// {
-// OperationDepsNode *op_node = *it;
-// deg_debug_graphviz_node_relations(ctx, op_node);
-// }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- ComponentDepsNode *comp_node = it->second;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
- deg_debug_graphviz_node_relations(ctx, op_node);
- }
- }
- }
-
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
- if (time_source != NULL) {
- deg_debug_graphviz_node_relations(ctx, time_source);
- }
-#endif
-}
-
-void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
-{
-#if 0 /* generate shaded color set */
- static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c},
- {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00},
- {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}};
- int i;
- const float factor = 0.666f;
- for (i=0; i < 12; ++i)
- printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor));
-#endif
-
- if (!graph) {
- return;
- }
-
- DebugContext ctx;
- ctx.file = f;
- ctx.show_tags = show_eval;
- ctx.show_eval_priority = show_eval;
-
- deg_debug_fprintf(ctx, "digraph depgraph {" NL);
- deg_debug_fprintf(ctx, "rankdir=LR;" NL);
- deg_debug_fprintf(ctx, "graph [");
- deg_debug_fprintf(ctx, "compound=true");
- deg_debug_fprintf(ctx, ",labelloc=\"t\"");
- deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, ",label=\"%s\"", label);
- deg_debug_fprintf(ctx, ",splines=ortho");
- deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
- deg_debug_fprintf(ctx, "];" NL);
-
- deg_debug_graphviz_graph_nodes(ctx, graph);
- deg_debug_graphviz_graph_relations(ctx, graph);
-
- deg_debug_graphviz_legend(ctx);
-
- deg_debug_fprintf(ctx, "}" NL);
-}
-
-#undef NL
+#include "intern/eval/deg_eval_debug.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
/* ************************************************ */
-static string get_component_name(eDepsNode_Type type, const string &name = "")
-{
- DepsNodeFactory *factory = DEG_get_node_factory(type);
- if (name.empty()) {
- return string(factory->tname());
- }
- else {
- return string(factory->tname()) + " | " + name;
- }
-}
-
-static void times_clear(DepsgraphStatsTimes &times)
-{
- times.duration_last = 0.0f;
-}
-
-static void times_add(DepsgraphStatsTimes &times, float time)
-{
- times.duration_last += time;
-}
-
-void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
-{
- /* TODO(sergey): Stats are currently globally disabled. */
- /* verify_stats(); */
- reset_stats();
-}
-
-void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
-{
- WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-}
-
-void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
- const char *message)
-{
-#ifdef DEG_DEBUG_BUILD
- if (deg_debug_eval_cb)
- deg_debug_eval_cb(deg_debug_eval_userdata, message);
-#else
- (void)message; /* Ignored. */
-#endif
-}
-
-void DepsgraphDebug::task_started(Depsgraph *graph,
- const OperationDepsNode *node)
-{
- if (stats) {
- BLI_spin_lock(&graph->lock);
-
- ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
-
- DepsgraphStatsID *id_stats = get_id_stats(id, true);
- times_clear(id_stats->times);
-
- /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
- if (0) {
- /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
- DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
- times_clear(comp_stats->times);
- }
-
- BLI_spin_unlock(&graph->lock);
- }
-}
-
-void DepsgraphDebug::task_completed(Depsgraph *graph,
- const OperationDepsNode *node,
- double time)
-{
- if (stats) {
- BLI_spin_lock(&graph->lock);
-
- ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
-
- DepsgraphStatsID *id_stats = get_id_stats(id, true);
- times_add(id_stats->times, time);
-
- /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
- if (0) {
- /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
- DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
- times_add(comp_stats->times, time);
- }
-
- BLI_spin_unlock(&graph->lock);
- }
-}
-
-/* ********** */
-/* Statistics */
-
-DepsgraphStats *DepsgraphDebug::stats = NULL;
-
-/* GHash callback */
-static void deg_id_stats_free(void *val)
-{
- DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
-
- if (id_stats) {
- BLI_freelistN(&id_stats->components);
- MEM_freeN(id_stats);
- }
-}
-
-void DepsgraphDebug::stats_init()
-{
- if (!stats) {
- stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats");
- stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash");
- }
-}
-
-void DepsgraphDebug::stats_free()
-{
- if (stats) {
- BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
- MEM_freeN(stats);
- stats = NULL;
- }
-}
-
-void DepsgraphDebug::verify_stats()
-{
- stats_init();
-}
-
-void DepsgraphDebug::reset_stats()
-{
- if (!stats) {
- return;
- }
-
- /* XXX this doesn't work, will immediately clear all info,
- * since most depsgraph updates have none or very few updates to handle.
- *
- * Could consider clearing only zero-user ID blocks here
- */
-// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
-}
-
-DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
-{
- DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
-
- if (!id_stats && create) {
- id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats");
- id_stats->id = id;
-
- BLI_ghash_insert(stats->id_stats, id, id_stats);
- }
-
- return id_stats;
-}
-
-DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
- DepsgraphStatsID *id_stats,
- const string &name,
- bool create)
-{
- DepsgraphStatsComponent *comp_stats;
- for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
- comp_stats != NULL;
- comp_stats = comp_stats->next)
- {
- if (STREQ(comp_stats->name, name.c_str()))
- break;
- }
- if (!comp_stats && create) {
- comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats");
- BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
- BLI_addtail(&id_stats->components, comp_stats);
- }
- return comp_stats;
-}
-
-/* ------------------------------------------------ */
-
DepsgraphStats *DEG_stats(void)
{
- return DepsgraphDebug::stats;
+ return DEG::DepsgraphDebug::stats;
}
void DEG_stats_verify()
{
- DepsgraphDebug::verify_stats();
+ DEG::DepsgraphDebug::verify_stats();
}
DepsgraphStatsID *DEG_stats_id(ID *id)
{
- if (!DepsgraphDebug::stats) {
+ if (!DEG::DepsgraphDebug::stats) {
return NULL;
}
- return DepsgraphDebug::get_id_stats(id, false);
+ return DEG::DepsgraphDebug::get_id_stats(id, false);
}
bool DEG_debug_compare(const struct Depsgraph *graph1,
@@ -987,7 +70,9 @@ bool DEG_debug_compare(const struct Depsgraph *graph1,
{
BLI_assert(graph1 != NULL);
BLI_assert(graph2 != NULL);
- if (graph1->operations.size() != graph2->operations.size()) {
+ const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1);
+ const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2);
+ if (deg_graph1->operations.size() != deg_graph2->operations.size()) {
return false;
}
/* TODO(sergey): Currently we only do real stupid check,
@@ -1017,34 +102,21 @@ bool DEG_debug_scene_relations_validate(Main *bmain,
bool DEG_debug_consistency_check(Depsgraph *graph)
{
- /* Validate links exists in both directions. */
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ /* Validate links exists in both directions. */
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
+ foreach (DEG::DepsRelation *rel, node->outlinks) {
int counter1 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin();
- tmp_rel != node->outlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, node->outlinks) {
+ if (tmp_rel == rel) {
++counter1;
}
}
int counter2 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin();
- tmp_rel != rel->to->inlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, rel->to->inlinks) {
+ if (tmp_rel == rel) {
++counter2;
}
}
@@ -1057,33 +129,18 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
}
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
-
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
+ foreach (DEG::DepsRelation *rel, node->inlinks) {
int counter1 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin();
- tmp_rel != node->inlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, node->inlinks) {
+ if (tmp_rel == rel) {
++counter1;
}
}
int counter2 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin();
- tmp_rel != rel->from->outlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, rel->from->outlinks) {
+ if (tmp_rel == rel) {
++counter2;
}
}
@@ -1096,32 +153,20 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
}
/* Validate node valency calculated in both directions. */
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
node->num_links_pending = 0;
node->done = 0;
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
if (node->done) {
printf("Node %s is twice in the operations!\n",
node->identifier().c_str());
return false;
}
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ foreach (DEG::DepsRelation *rel, node->outlinks) {
+ if (rel->to->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ DEG::OperationDepsNode *to = (DEG::OperationDepsNode *)rel->to;
BLI_assert(to->num_links_pending < to->inlinks.size());
++to->num_links_pending;
}
@@ -1129,18 +174,10 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
node->done = 1;
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
int num_links_pending = 0;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ foreach (DEG::DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEG::DEPSNODE_TYPE_OPERATION) {
++num_links_pending;
}
}
@@ -1166,12 +203,14 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
size_t *r_operations, size_t *r_relations)
{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
/* number of operations */
if (r_operations) {
/* All operations should be in this list, allowing us to count the total
* number of nodes.
*/
- *r_operations = graph->operations.size();
+ *r_operations = deg_graph->operations.size();
}
/* Count number of outer nodes and/or relations between these. */
@@ -1179,29 +218,21 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
size_t tot_outer = 0;
size_t tot_rels = 0;
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, deg_graph->id_hash)
{
- IDDepsNode *id_node = it->second;
tot_outer++;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp_node, id_node->components)
{
- ComponentDepsNode *comp_node = it->second;
tot_outer++;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
+ foreach (DEG::OperationDepsNode *op_node, comp_node->operations) {
tot_rels += op_node->inlinks.size();
}
}
+ GHASH_FOREACH_END();
}
+ GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source(NULL);
if (time_source != NULL) {
tot_rels += time_source->inlinks.size();
}
@@ -1210,4 +241,3 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
if (r_outer) *r_outer = tot_outer;
}
}
-
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 66535f5214b..f8d40d0e6a8 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,11 +32,9 @@
#include "MEM_guardedalloc.h"
-#include "PIL_time.h"
-
extern "C" {
#include "BLI_utildefines.h"
-#include "BLI_task.h"
+#include "BLI_ghash.h"
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
@@ -44,13 +42,13 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "atomic_ops.h"
+#include "intern/eval/deg_eval.h"
+#include "intern/eval/deg_eval_flush.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_debug.h"
+#include "intern/depsgraph.h"
#ifdef WITH_LEGACY_DEPSGRAPH
static bool use_legacy_depsgraph = true;
@@ -118,359 +116,16 @@ void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
MEM_freeN(eval_ctx);
}
-/* ********************** */
-/* Evaluation Entrypoints */
-
-/* Forward declarations. */
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationDepsNode *node,
- const int layers,
- const int thread_id);
-
-struct DepsgraphEvalState {
- EvaluationContext *eval_ctx;
- Depsgraph *graph;
- int layers;
-};
-
-static void deg_task_run_func(TaskPool *pool,
- void *taskdata,
- int thread_id)
-{
- DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
- OperationDepsNode *node = (OperationDepsNode *)taskdata;
-
- BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
-
- /* Should only be the case for NOOPs, which never get to this point. */
- BLI_assert(node->evaluate);
-
- while (true) {
- /* Get context. */
- // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
- /* TODO(sergey): We don't use component contexts at this moment. */
- /* ComponentDepsNode *comp = node->owner; */
- BLI_assert(node->owner != NULL);
-
- /* Since we're not leaving the thread for until the graph branches it is
- * possible to have NO-OP on the way. for which evaluate() will be NULL.
- * but that's all fine, we'll just scheduler it's children.
- */
- if (node->evaluate) {
- /* Take note of current time. */
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
-
- /* Perform operation. */
- node->evaluate(state->eval_ctx);
-
- /* Note how long this took. */
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
- }
-
- /* If there's only one outgoing link we try to immediately switch to
- * that node evaluation, without leaving the thread.
- *
- * It's only doable if the child don't have extra relations or all they
- * are satisfied.
- *
- * TODO(sergey): Checks here can be de-duplicated with the ones from
- * schedule_node(), however, how to do it nicely?
- */
- if (node->outlinks.size() == 1) {
- DepsRelation *rel = node->outlinks[0];
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (!child->scheduled) {
- int id_layers = child->owner->owner->layers;
- if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & state->layers) != 0))
- {
- /* Node does not need an update, so can;t continue with the
- * chain and need to switch to another one by leaving the
- * thread.
- */
- break;
- }
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
- }
- if (child->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&child->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- /* Node was not scheduled, switch to it! */
- node = child;
- }
- else {
- /* Someone else scheduled the node, leaving us
- * unemployed in this thread, we're leaving.
- */
- break;
- }
- }
- else {
- /* There are other dependencies on the child, can't do
- * anything in the current thread.
- */
- break;
- }
- }
- else {
- /* Happens when having cyclic dependencies.
- *
- * Nothing to do here, single child was already scheduled, we
- * can leave the thread now.
- */
- break;
- }
- }
- else {
- /* TODO(sergey): It's possible to use one of the outgoing relations
- * as a chain which we'll try to keep alive, but it's a bit more
- * involved change.
- */
- schedule_children(pool, state->graph, node, state->layers, thread_id);
- break;
- }
- }
-}
-
-typedef struct CalculatePengindData {
- Depsgraph *graph;
- int layers;
-} CalculatePengindData;
-
-static void calculate_pending_func(void *data_v, int i)
-{
- CalculatePengindData *data = (CalculatePengindData *)data_v;
- Depsgraph *graph = data->graph;
- int layers = data->layers;
- OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
-
- node->num_links_pending = 0;
- node->scheduled = false;
-
- /* count number of inputs that need updates */
- if ((id_node->layers & layers) != 0 &&
- (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
- {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- IDDepsNode *id_from_node = from->owner->owner;
- if ((id_from_node->layers & layers) != 0 &&
- (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- ++node->num_links_pending;
- }
- }
- }
- DEPSNODE_RELATIONS_ITER_END;
- }
-}
-
-static void calculate_pending_parents(Depsgraph *graph, int layers)
-{
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- CalculatePengindData data;
- data.graph = graph;
- data.layers = layers;
- BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, do_threads);
-}
-
-#ifdef USE_EVAL_PRIORITY
-static void calculate_eval_priority(OperationDepsNode *node)
-{
- if (node->done) {
- return;
- }
- node->done = 1;
-
- if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- /* XXX standard cost of a node, could be estimated somewhat later on */
- const float cost = 1.0f;
- /* NOOP nodes have no cost */
- node->eval_priority = node->is_noop() ? cost : 0.0f;
-
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
- calculate_eval_priority(to);
- node->eval_priority += to->eval_priority;
- }
- }
- else {
- node->eval_priority = 0.0f;
- }
-}
-#endif
-
-/* Schedule a node if it needs evaluation.
- * dec_parents: Decrement pending parents count, true when child nodes are scheduled
- * after a task has been completed.
- */
-static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
- OperationDepsNode *node, bool dec_parents,
- const int thread_id)
-{
- int id_layers = node->owner->owner->layers;
-
- if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & layers) != 0)
- {
- if (dec_parents) {
- BLI_assert(node->num_links_pending > 0);
- atomic_sub_uint32(&node->num_links_pending, 1);
- }
-
- if (node->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- if (node->is_noop()) {
- /* skip NOOP node, schedule children right away */
- schedule_children(pool, graph, node, layers, thread_id);
- }
- else {
- /* children are scheduled once this task is completed */
- BLI_task_pool_push_from_thread(pool,
- deg_task_run_func,
- node,
- false,
- TASK_PRIORITY_LOW,
- thread_id);
- }
- }
- }
- }
-}
-
-static void schedule_graph(TaskPool *pool,
- Depsgraph *graph,
- const int layers)
-{
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- schedule_node(pool, graph, layers, node, false, 0);
- }
-}
-
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationDepsNode *node,
- const int layers,
- const int thread_id)
-{
- DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
- {
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (child->scheduled) {
- /* Happens when having cyclic dependencies. */
- continue;
- }
- schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, thread_id);
- }
- DEPSNODE_RELATIONS_ITER_END;
-}
-
-/**
- * Evaluate all nodes tagged for updating,
- * \warning This is usually done as part of main loop, but may also be
- * called from frame-change update.
- *
- * \note Time sources should be all valid!
- */
-void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const int layers)
-{
- /* Generate base evaluation context, upon which all the others are derived. */
- // TODO: this needs both main and scene access...
-
- /* Nothing to update, early out. */
- if (graph->entry_tags.size() == 0) {
- return;
- }
-
- /* Set time for the current graph evaluation context. */
- TimeSourceDepsNode *time_src = graph->find_time_source();
- eval_ctx->ctime = time_src->cfra;
-
- /* XXX could use a separate pool for each eval context */
- DepsgraphEvalState state;
- state.eval_ctx = eval_ctx;
- state.graph = graph;
- state.layers = layers;
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
- }
-
- calculate_pending_parents(graph, layers);
-
- /* Clear tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- node->done = 0;
- }
-
- /* Calculate priority for operation nodes. */
-#ifdef USE_EVAL_PRIORITY
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- calculate_eval_priority(node);
- }
-#endif
-
- DepsgraphDebug::eval_begin(eval_ctx);
-
- schedule_graph(task_pool, graph, layers);
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- DepsgraphDebug::eval_end(eval_ctx);
-
- /* Clear any uncleared tags - just in case. */
- DEG_graph_clear_tags(graph);
-}
-
/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
Scene *scene)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
- TimeSourceDepsNode *tsrc = graph->find_time_source();
+ DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = BKE_scene_frame_get(scene);
-
- DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, deg_graph->layers);
}
/* Frame-change happened for root scene that graph belongs to. */
@@ -480,19 +135,18 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
float ctime,
const int layers)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
- TimeSourceDepsNode *tsrc = graph->find_time_source();
+ DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = ctime;
-
- tsrc->tag_update(graph);
-
- DEG_graph_flush_updates(bmain, graph);
-
+ tsrc->tag_update(deg_graph);
+ DEG::deg_graph_flush_updates(bmain, deg_graph);
/* Perform recalculation updates. */
- DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
}
bool DEG_needs_eval(Depsgraph *graph)
{
- return graph->entry_tags.size() != 0;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ return BLI_gset_size(deg_graph->entry_tags) != 0;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index 7fdc2454564..e5d3d1f5861 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -31,65 +31,26 @@
* - Also, defines for "Node Type Info"
*/
-#ifndef __DEPSGRAPH_INTERN_H__
-#define __DEPSGRAPH_INTERN_H__
+#pragma once
#include <cstdlib>
#include "MEM_guardedalloc.h"
-#include "depsgraph.h"
-#include "depsnode.h"
+extern "C" {
+#include "BKE_global.h"
+}
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph.h"
struct Main;
struct Group;
struct Scene;
-/* Graph Building ======================================================== */
-
-/**
- * Build depsgraph for the given group, and dump results in given graph container
- * This is usually used for building subgraphs for groups to use...
- */
-void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
-
-/* Build subgraph for group */
-DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
-
-/* Graph Copying ========================================================= */
-/* (Part of the Filtering API) */
-
-/**
- * Depsgraph Copying Context (dcc)
- *
- * Keeps track of node relationships/links/etc. during the copy
- * operation so that they can be safely remapped...
- */
-typedef struct DepsgraphCopyContext {
- struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
- struct GHash *rels_hash; // XXX: same for relationships?
-
- // XXX: filtering criteria...
-} DepsgraphCopyContext;
-
-/* Internal Filtering API ---------------------------------------------- */
-
-/* Create filtering context */
-// XXX: needs params for conditions?
-DepsgraphCopyContext *DEG_filter_init(void);
-
-/* Free filtering context once filtering is done */
-void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
-
-
-/* Data Copy Operations ------------------------------------------------ */
-
-/**
- * Make a (deep) copy of provided node and it's little subgraph
- * \warning Newly created node is not added to the existing graph
- * \param dcc: Context info for helping resolve links
- */
-DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
+namespace DEG {
/* Node Types Handling ================================================= */
@@ -101,8 +62,9 @@ struct DepsNodeFactory {
virtual eDepsNode_Class tclass() const = 0;
virtual const char *tname() const = 0;
- virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
- virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
+ virtual DepsNode *create_node(const ID *id,
+ const string &subdata,
+ const string &name) const = 0;
};
template <class NodeType>
@@ -130,34 +92,18 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
return node;
}
-
- virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
- {
- BLI_assert(copy->type == type());
- DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
-
- /* populate base node settings */
- node->type = type();
- node->tclass = tclass();
- // XXX: need to review the name here, as we can't have exact duplicates...
- node->name = copy->name;
-
- node->copy(dcc, static_cast<const NodeType *>(copy));
-
- return node;
- }
};
/* Typeinfo Management -------------------------------------------------- */
/* Register typeinfo */
-void DEG_register_node_typeinfo(DepsNodeFactory *factory);
+void deg_register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
-DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
+DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type);
/* Get typeinfo for provided node */
-DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
+DepsNodeFactory *deg_node_get_factory(const DepsNode *node);
/* Editors Integration -------------------------------------------------- */
@@ -165,4 +111,11 @@ void deg_editors_id_update(struct Main *bmain, struct ID *id);
void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
-#endif /* __DEPSGRAPH_INTERN_H__ */
+#define DEG_DEBUG_PRINTF(...) \
+ do { \
+ if (G.debug & G_DEBUG_DEPSGRAPH) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
+ } while (0)
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 73193747b93..cac4eaae215 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -33,162 +33,12 @@
#include "MEM_guardedalloc.h"
extern "C" {
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
#include "BKE_main.h"
#include "DEG_depsgraph_query.h"
} /* extern "C" */
-#include "depsgraph_queue.h"
-#include "depsnode.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
-
-/* ************************* */
-/* Low-Level Graph Traversal */
-
-#if 0
-/* Prepare for graph traversal, by tagging nodes, etc. */
-static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
-{
- /* go over all nodes, initialising the valence counts */
- // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
-}
-
-/* Perform a traversal of graph from given starting node (in execution order) */
-// TODO: additional flags for controlling the process?
-void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
- DEG_FilterPredicate filter, void *filter_data,
- DEG_NodeOperation op, void *operation_data)
-{
- DepsgraphQueue *q;
-
- /* sanity checks */
- if (ELEM(NULL, graph, start_node, op))
- return;
-
- /* add node as starting node to be evaluated, with value of 0 */
- q = DEG_queue_new();
-
- start_node->num_links_pending = 0;
- DEG_queue_push(q, start_node, 0.0f);
-
- /* while we still have nodes in the queue, grab and work on next one */
- do {
- /* grab item at front of queue */
- // XXX: in practice, we may need to wait until one becomes available...
- OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
-
- /* perform operation on node */
- op(graph, node, operation_data);
-
- /* schedule up operations which depend on this */
- DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
- {
- /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
- // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
-
- /* only visit node if the filtering function agrees */
- if ((filter == NULL) || filter(graph, child_node, filter_data)) {
- /* schedule up node... */
- child_node->num_links_pending--;
- DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
- }
- }
- }
- DEPSNODE_RELATIONS_ITER_END;
- } while (DEG_queue_is_empty(q) == false);
-
- /* cleanup */
- DEG_queue_free(q);
-}
-#endif
-
-/* ************************************************************** */
-/* Filtering API - Basically, making a copy of the existing graph */
-
-/* Create filtering context */
-// TODO: allow passing in a number of criteria?
-DepsgraphCopyContext *DEG_filter_init()
-{
- DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
-
- /* init hashes for easy lookups */
- dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
- dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
-
- /* store filtering criteria? */
- // xxx...
-
- return dcc;
-}
-
-/* Cleanup filtering context */
-void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
-{
- /* sanity check */
- if (dcc == NULL)
- return;
-
- /* free hashes - contents are weren't copied, so are ok... */
- BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
- BLI_ghash_free(dcc->rels_hash, NULL, NULL);
-
- /* clear filtering criteria */
- // ...
-
- /* free dcc itself */
- MEM_freeN(dcc);
-}
-
-/* -------------------------------------------------- */
-
-/* Create a copy of provided node */
-// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
-// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
-DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
-{
- /* sanity check */
- if (src == NULL)
- return NULL;
-
- DepsNodeFactory *factory = DEG_get_node_factory(src->type);
- BLI_assert(factory != NULL);
- DepsNode *dst = factory->copy_node(dcc, src);
-
- /* add this node-pair to the hash... */
- BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
-
-#if 0 /* XXX TODO */
- /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
- * all others are derived from) that are now corrupt
- */
- {
- /* relationships to other nodes... */
- // FIXME: how to handle links? We may only have partial set of all nodes still?
- // XXX: the exact details of how to handle this are really part of the querying API...
-
- // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
- // (i.e. for resolving and patching over links that exist within subtree...)
- dst->inlinks.clear();
- dst->outlinks.clear();
-
- /* clear traversal data */
- dst->num_links_pending = 0;
- dst->lasttime = 0;
- }
-
- /* fix links */
- // XXX...
-#endif
-
- /* return copied node */
- return dst;
-}
+#include "intern/depsgraph_intern.h"
bool DEG_id_type_tagged(Main *bmain, short idtype)
{
@@ -207,7 +57,9 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return 0;
}
- IDDepsNode *id_node = graph->find_id_node(id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc
deleted file mode 100644
index da60d73bc46..00000000000
--- a/source/blender/depsgraph/intern/depsgraph_queue.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * ***** 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) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsgraph_queue.cc
- * \ingroup depsgraph
- *
- * Implementation of special queue type for use in Depsgraph traversals.
- */
-
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-extern "C" {
-#include "BLI_utildefines.h"
-#include "BLI_heap.h"
-#include "BLI_ghash.h"
-} /* extern "C" */
-
-#include "depsgraph_queue.h"
-
-/* ****************************** */
-/* Depsgraph Queue implementation */
-
-/* Data Management ----------------------------------------- */
-
-DepsgraphQueue *DEG_queue_new(void)
-{
- DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
-
- /* init data structures for use here */
- q->pending_heap = BLI_heap_new();
- q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
-
- q->ready_heap = BLI_heap_new();
-
- /* init settings */
- q->idx = 0;
- q->tot = 0;
-
- /* return queue */
- return q;
-}
-
-void DEG_queue_free(DepsgraphQueue *q)
-{
- /* free data structures */
- BLI_assert(BLI_heap_size(q->pending_heap) == 0);
- BLI_assert(BLI_heap_size(q->ready_heap) == 0);
- BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
-
- BLI_heap_free(q->pending_heap, NULL);
- BLI_heap_free(q->ready_heap, NULL);
- BLI_ghash_free(q->pending_hash, NULL, NULL);
-
- /* free queue itself */
- MEM_freeN(q);
-}
-
-/* Statistics --------------------------------------------- */
-
-/* Get the number of nodes which are we should visit, but are not able to yet */
-size_t DEG_queue_num_pending(DepsgraphQueue *q)
-{
- return BLI_heap_size(q->pending_heap);
-}
-
-/* Get the number of nodes which are now ready to be visited */
-size_t DEG_queue_num_ready(DepsgraphQueue *q)
-{
- return BLI_heap_size(q->ready_heap);
-}
-
-/* Get total size of queue */
-size_t DEG_queue_size(DepsgraphQueue *q)
-{
- return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
-}
-
-/* Check if queue has any items in it (still passing through) */
-bool DEG_queue_is_empty(DepsgraphQueue *q)
-{
- return DEG_queue_size(q) == 0;
-}
-
-/* Queue Operations --------------------------------------- */
-
-/**
- * Add DepsNode to the queue
- * \param dnode: ``(DepsNode *)`` node to add to the queue
- * Each node is only added once to the queue; Subsequent pushes
- * merely update its status (e.g. moving it from "pending" to "ready")
- * \param cost: new "num_links_pending" count for node *after* it has encountered
- * via an outlink from the node currently being visited
- * (i.e. we're one of the dependencies which may now be able to be processed)
- */
-void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
-{
- HeapNode *hnode = NULL;
-
- /* Shortcut: Directly add to ready if node isn't waiting on anything now... */
- if (cost == 0) {
- /* node is now ready to be visited - schedule it up for such */
- if (BLI_ghash_haskey(q->pending_hash, dnode)) {
- /* remove from pending queue - we're moving it to the scheduling queue */
- hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
- BLI_heap_remove(q->pending_heap, hnode);
-
- BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
- }
-
- /* schedule up node using latest count (of ready nodes) */
- BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
- q->idx++;
- }
- else {
- /* node is still waiting on some other ancestors,
- * so add it to the pending heap in the meantime...
- */
- // XXX: is this even necessary now?
- if (BLI_ghash_haskey(q->pending_hash, dnode)) {
- /* just update cost on pending node */
- hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
- BLI_heap_remove(q->pending_heap, hnode);
- BLI_heap_insert(q->pending_heap, cost, hnode);
- }
- else {
- /* add new node to pending queue, and increase size of overall queue */
- hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
- q->tot++;
- }
- }
-}
-
-/* Grab a "ready" node from the queue */
-void *DEG_queue_pop(DepsgraphQueue *q)
-{
- /* sanity check: if there are no "ready" nodes,
- * start pulling from "pending" to keep things moving,
- * but throw a warning so that we know that something's up here...
- */
- if (BLI_heap_is_empty(q->ready_heap)) {
- // XXX: this should never happen
- // XXX: if/when it does happen, we may want instead to just wait until something pops up here...
- printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
- (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
-
- return BLI_heap_popmin(q->pending_heap);
- }
- else {
- /* only grab "ready" nodes */
- return BLI_heap_popmin(q->ready_heap);
- }
-}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h
deleted file mode 100644
index b85d46bd173..00000000000
--- a/source/blender/depsgraph/intern/depsgraph_queue.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** 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) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsgraph_queue.h
- * \ingroup depsgraph
- *
- * Defines for special queue type for use in Depsgraph traversals.
- */
-
-#ifndef __DEPSGRAPH_QUEUE_H__
-#define __DEPSGRAPH_QUEUE_H__
-
-struct DepsNode;
-
-struct Heap;
-struct GHash;
-
-/* *********************************************** */
-/* Dependency Graph Traversal Queue
- *
- * There are two parts to this:
- * a) "Pending" Nodes - This part contains the set of nodes
- * which are related to those which have been visited
- * previously, but are not yet ready to actually be visited.
- * b) "Scheduled" Nodes - These are the nodes whose ancestors
- * have all been evaluated already, which means that any
- * or all of them can be picked (in practically in order) to
- * be visited immediately.
- *
- * Internally, the queue makes sure that each node in the graph
- * only gets added to the queue once. This is because there can
- * be multiple inlinks to each node given the way that the relations
- * work.
- */
-
-/* Depsgraph Queue Type */
-typedef struct DepsgraphQueue {
- /* Pending */
- struct Heap *pending_heap; /* (valence:int, DepsNode*) */
- struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
-
- /* Ready to be visited - fifo */
- struct Heap *ready_heap; /* (idx:int, DepsNode*) */
-
- /* Size/Order counts */
- size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
- size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
-} DepsgraphQueue;
-
-/* ************************** */
-/* Depsgraph Queue Operations */
-
-/* Data management */
-DepsgraphQueue *DEG_queue_new(void);
-void DEG_queue_free(DepsgraphQueue *q);
-
-/* Statistics */
-size_t DEG_queue_num_pending(DepsgraphQueue *q);
-size_t DEG_queue_num_ready(DepsgraphQueue *q);
-
-size_t DEG_queue_size(DepsgraphQueue *q);
-bool DEG_queue_is_empty(DepsgraphQueue *q);
-
-/* Operations */
-void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
-void *DEG_queue_pop(DepsgraphQueue *q);
-
-#endif /* DEPSGRAPH_QUEUE_H */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index f00bce29f64..7c048751869 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -54,11 +54,14 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "depsgraph_debug.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/eval/deg_eval_flush.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
/* *********************** */
/* Update Tagging/Flushing */
@@ -126,19 +129,21 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
*/
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
{
- IDDepsNode *node = graph->find_id_node(id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::IDDepsNode *node = deg_graph->find_id_node(id);
lib_id_recalc_tag(bmain, id);
if (node != NULL) {
- node->tag_update(graph);
+ node->tag_update(deg_graph);
}
}
/* Tag nodes related to a specific piece of data */
void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
{
- DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
- if (node) {
- node->tag_update(graph);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, NULL);
+ if (node != NULL) {
+ node->tag_update(deg_graph);
}
else {
printf("Missing node in %s\n", __func__);
@@ -151,9 +156,10 @@ void DEG_graph_property_tag_update(Depsgraph *graph,
const PointerRNA *ptr,
const PropertyRNA *prop)
{
- DepsNode *node = graph->find_node_from_pointer(ptr, prop);
- if (node) {
- node->tag_update(graph);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, prop);
+ if (node != NULL) {
+ node->tag_update(deg_graph);
}
else {
printf("Missing node in %s\n", __func__);
@@ -223,131 +229,6 @@ void DEG_id_type_tag(Main *bmain, short idtype)
bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
}
-/* Update Flushing ---------------------------------- */
-
-/* FIFO queue for tagged nodes that need flushing */
-/* XXX This may get a dedicated implementation later if needed - lukas */
-typedef std::queue<OperationDepsNode *> FlushQueue;
-
-static void flush_init_func(void *data_v, int i)
-{
- /* ID node's done flag is used to avoid multiple editors update
- * for the same ID.
- */
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
- id_node->done = 0;
- node->scheduled = false;
- node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
-}
-
-/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
-void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
-{
- /* sanity check */
- if (graph == NULL)
- return;
-
- /* Nothing to update, early out. */
- if (graph->entry_tags.size() == 0) {
- return;
- }
-
- /* TODO(sergey): With a bit of flag magic we can get rid of this
- * extra loop.
- */
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, flush_init_func, do_threads);
-
- FlushQueue queue;
- /* Starting from the tagged "entry" nodes, flush outwards... */
- /* NOTE: Also need to ensure that for each of these, there is a path back to
- * root, or else they won't be done.
- * NOTE: Count how many nodes we need to handle - entry nodes may be
- * component nodes which don't count for this purpose!
- */
- for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
- it != graph->entry_tags.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- IDDepsNode *id_node = node->owner->owner;
- queue.push(node);
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
- node->scheduled = true;
- }
-
- while (!queue.empty()) {
- OperationDepsNode *node = queue.front();
- queue.pop();
-
- IDDepsNode *id_node = node->owner->owner;
- lib_id_recalc_tag(bmain, id_node->id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_node->id);
-
- ID *id = id_node->id;
- /* This code is used to preserve those areas which does direct
- * object update,
- *
- * Plus it ensures visibility changes and relations and layers
- * visibility update has proper flags to work with.
- */
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- ComponentDepsNode *comp_node = node->owner;
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- object->recalc |= OB_RECALC_TIME;
- }
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
- }
- }
-
- /* Flush to nodes along links... */
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
- if (to_node->scheduled == false) {
- to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- queue.push(to_node);
- to_node->scheduled = true;
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
- }
- }
-
- /* TODO(sergey): For until incremental updates are possible
- * witin a component at least we tag the whole component
- * for update.
- */
- ComponentDepsNode *component = node->owner;
- if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
- for (ComponentDepsNode::OperationMap::iterator it = component->operations.begin();
- it != node->owner->operations.end();
- ++it)
- {
- OperationDepsNode *op = it->second;
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- component->flags |= DEPSCOMP_FULLY_SCHEDULED;
- }
- }
-}
-
/* Recursively push updates out to all nodes dependent on this,
* until all affected are tagged and/or scheduled up for eval
*/
@@ -359,34 +240,17 @@ void DEG_ids_flush_tagged(Main *bmain)
{
/* TODO(sergey): Only visible scenes? */
if (scene->depsgraph != NULL) {
- DEG_graph_flush_updates(bmain, scene->depsgraph);
+ DEG::deg_graph_flush_updates(
+ bmain,
+ reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
}
}
}
-static void graph_clear_func(void *data_v, int i)
-{
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationDepsNode *node = graph->operations[i];
- /* Clear node's "pending update" settings. */
- node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
-}
-
-/* Clear tags from all operation nodes. */
-void DEG_graph_clear_tags(Depsgraph *graph)
-{
- /* Go over all operation nodes, clearing tags. */
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
- /* Clear any entry tags which haven't been flushed. */
- graph->entry_tags.clear();
-}
-
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
- Depsgraph *graph = scene->depsgraph;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
int old_layers = graph->layers;
if (wm != NULL) {
@@ -414,11 +278,8 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
* This is mainly needed on file load only, after that updates of invisible objects
* will be stored in the pending list.
*/
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
{
- IDDepsNode *id_node = it->second;
ID *id = id_node->id;
if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 ||
(id_node->layers & scene->lay_updated) == 0)
@@ -436,14 +297,15 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
(object->recalc & OB_RECALC_ALL) != 0)
{
id_node->tag_update(graph);
- ComponentDepsNode *anim_comp =
- id_node->find_component(DEPSNODE_TYPE_ANIMATION);
+ DEG::ComponentDepsNode *anim_comp =
+ id_node->find_component(DEG::DEPSNODE_TYPE_ANIMATION);
if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
anim_comp->tag_update(graph);
}
}
}
}
+ GHASH_FOREACH_END();
}
scene->lay_updated |= graph->layers;
}
@@ -484,7 +346,7 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
}
}
- deg_editors_scene_update(bmain, scene, (updated || time));
+ DEG::deg_editors_scene_update(bmain, scene, (updated || time));
}
void DEG_ids_clear_recalc(Main *bmain)
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 5a3048a4aa3..97208939e57 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -30,6 +30,8 @@
* Defines and code for core node types.
*/
+#include <cstdlib> // for BLI_assert()
+
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -37,10 +39,13 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "depsgraph_intern.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
/* ************ */
/* External API */
@@ -59,44 +64,108 @@ static GHash *_depsnode_typeinfo_registry = NULL;
/* Registration ------------------------------------------- */
/* Register node type */
-void DEG_register_node_typeinfo(DepsNodeFactory *factory)
+void deg_register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != NULL);
BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
}
-/* Register all node types */
-void DEG_register_node_types(void)
-{
- /* initialise registry */
- _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
-
- /* register node types */
- DEG_register_base_depsnodes();
- DEG_register_component_depsnodes();
- DEG_register_operation_depsnodes();
-}
-
-/* Free registry on exit */
-void DEG_free_node_types(void)
-{
- BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
-}
-
/* Getters ------------------------------------------------- */
/* Get typeinfo for specified type */
-DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
+DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type)
{
/* look up type - at worst, it doesn't exist in table yet, and we fail */
return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
}
/* Get typeinfo for provided node */
-DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
+DepsNodeFactory *deg_node_get_factory(const DepsNode *node)
{
- if (!node)
+ if (node != NULL) {
return NULL;
+ }
+ return deg_get_node_factory(node->type);
+}
+
+/* Stringified opcodes ------------------------------------- */
+
+DepsOperationStringifier DEG_OPNAMES;
- return DEG_get_node_factory(node->type);
+static const char *stringify_opcode(eDepsOperation_Code opcode)
+{
+ switch (opcode) {
+#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
+ STRINGIFY_OPCODE(OPERATION);
+ STRINGIFY_OPCODE(PLACEHOLDER);
+ STRINGIFY_OPCODE(NOOP);
+ STRINGIFY_OPCODE(ANIMATION);
+ STRINGIFY_OPCODE(DRIVER);
+ //STRINGIFY_OPCODE(PROXY);
+ STRINGIFY_OPCODE(TRANSFORM_LOCAL);
+ STRINGIFY_OPCODE(TRANSFORM_PARENT);
+ STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_INIT);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINT);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_DONE);
+ STRINGIFY_OPCODE(RIGIDBODY_REBUILD);
+ STRINGIFY_OPCODE(RIGIDBODY_SIM);
+ STRINGIFY_OPCODE(TRANSFORM_RIGIDBODY);
+ STRINGIFY_OPCODE(TRANSFORM_FINAL);
+ STRINGIFY_OPCODE(OBJECT_UBEREVAL);
+ STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
+ STRINGIFY_OPCODE(GEOMETRY_MODIFIER);
+ STRINGIFY_OPCODE(GEOMETRY_PATH);
+ STRINGIFY_OPCODE(POSE_INIT);
+ STRINGIFY_OPCODE(POSE_DONE);
+ STRINGIFY_OPCODE(POSE_IK_SOLVER);
+ STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER);
+ STRINGIFY_OPCODE(BONE_LOCAL);
+ STRINGIFY_OPCODE(BONE_POSE_PARENT);
+ STRINGIFY_OPCODE(BONE_CONSTRAINTS);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINTS_INIT);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINT);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINTS_DONE);
+ STRINGIFY_OPCODE(BONE_READY);
+ STRINGIFY_OPCODE(BONE_DONE);
+ STRINGIFY_OPCODE(PSYS_EVAL);
+
+ case DEG_NUM_OPCODES: return "SpecialCase";
+#undef STRINGIFY_OPCODE
+ }
+ return "UNKNOWN";
+}
+
+DepsOperationStringifier::DepsOperationStringifier() {
+ for (int i = 0; i < DEG_NUM_OPCODES; ++i) {
+ names_[i] = stringify_opcode((eDepsOperation_Code)i);
+ }
+}
+
+const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) {
+ BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
+ if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
+ return names_[opcode];
+ }
+ return "UnknownOpcode";
+}
+
+} // namespace DEG
+
+/* Register all node types */
+void DEG_register_node_types(void)
+{
+ /* initialise registry */
+ DEG::_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
+
+ /* register node types */
+ DEG::deg_register_base_depsnodes();
+ DEG::deg_register_component_depsnodes();
+ DEG::deg_register_operation_depsnodes();
+}
+
+/* Free registry on exit */
+void DEG_free_node_types(void)
+{
+ BLI_ghash_free(DEG::_depsnode_typeinfo_registry, NULL, NULL);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index f5fbf0bcc76..7516ccbfdc2 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -34,10 +34,9 @@
* in the graph.
*/
-#ifndef __DEPSGRAPH_TYPES_H__
-#define __DEPSGRAPH_TYPES_H__
+#pragma once
-#include "depsgraph_util_function.h"
+#include "util/deg_util_function.h"
/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
* to avoid any possible overhead caused by string (re)allocation/formatting.
@@ -55,69 +54,232 @@ struct PointerRNA;
struct EvaluationContext;
struct FCurve;
+namespace DEG {
+
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
-/* Metatype of Nodes - The general "level" in the graph structure the node serves */
+/* Metatype of Nodes - The general "level" in the graph structure
+ * the node serves.
+ */
typedef enum eDepsNode_Class {
- DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
-
- DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
- DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
+ /* Types generally unassociated with user-visible entities,
+ * but needed for graph functioning.
+ */
+ DEPSNODE_CLASS_GENERIC = 0,
+ /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring
+ * certain types of evaluation behavior.
+ */
+ DEPSNODE_CLASS_COMPONENT = 1,
+ /* [Inner Node] A glorified function-pointer/callback for scheduling up
+ * evaluation operations for components, subject to relationship
+ * requirements.
+ */
+ DEPSNODE_CLASS_OPERATION = 2,
} eDepsNode_Class;
/* Types of Nodes */
typedef enum eDepsNode_Type {
- DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
+ /* Fallback type for invalid return value */
+ DEPSNODE_TYPE_UNDEFINED = -1,
+ /* Inner Node (Operation) */
+ DEPSNODE_TYPE_OPERATION = 0,
+
+ /* **** Generic Types **** */
+
+ /* "Current Scene" - basically whatever kicks off the evaluation process. */
+ DEPSNODE_TYPE_ROOT = 1,
+ /* Time-Source */
+ DEPSNODE_TYPE_TIMESOURCE = 2,
+ /* ID-Block reference - used as landmarks/collection point for components,
+ * but not usually part of main graph.
+ */
+ DEPSNODE_TYPE_ID_REF = 3,
+ /* Isolated sub-graph - used for keeping instanced data separate from
+ * instances using them.
+ */
+ DEPSNODE_TYPE_SUBGRAPH = 4,
- DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
+ /* **** Outer Types **** */
- /* Generic Types */
- DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
- DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEPSNODE_TYPE_PARAMETERS = 11,
+ /* Generic "Proxy-Inherit" Component
+ * XXX: Also for instancing of subgraphs?
+ */
+ DEPSNODE_TYPE_PROXY = 12,
+ /* Animation Component
+ *
+ * XXX: merge in with parameters?
+ */
+ DEPSNODE_TYPE_ANIMATION = 13,
+ /* Transform Component (Parenting/Constraints) */
+ DEPSNODE_TYPE_TRANSFORM = 14,
+ /* Geometry Component (DerivedMesh/Displist) */
+ DEPSNODE_TYPE_GEOMETRY = 15,
+ /* Sequencer Component (Scene Only) */
+ DEPSNODE_TYPE_SEQUENCER = 16,
+
+ /* **** Evaluation-Related Outer Types (with Subdata) **** */
+
+ /* Pose Component - Owner/Container of Bones Eval */
+ DEPSNODE_TYPE_EVAL_POSE = 21,
+ /* Bone Component - Child/Subcomponent of Pose */
+ DEPSNODE_TYPE_BONE = 22,
+ /* Particle Systems Component */
+ DEPSNODE_TYPE_EVAL_PARTICLES = 23,
+ /* Material Shading Component */
+ DEPSNODE_TYPE_SHADING = 24,
+} eDepsNode_Type;
- DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
- DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
+/* Identifiers for common operations (as an enum). */
+typedef enum eDepsOperation_Code {
+ /* Generic Operations ------------------------------ */
- /* Outer Types */
- DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
- DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
- DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
- DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
- DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
+ /* Placeholder for operations which don't need special mention */
+ DEG_OPCODE_OPERATION = 0,
- /* Evaluation-Related Outer Types (with Subdata) */
- DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
- DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
+ // XXX: Placeholder while porting depsgraph code
+ DEG_OPCODE_PLACEHOLDER,
- DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
- DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
-} eDepsNode_Type;
+ DEG_OPCODE_NOOP,
-/* Identifiers for common operations (as an enum) */
-typedef enum eDepsOperation_Code {
-#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
-#include "depsnode_opcodes.h"
-#undef DEF_DEG_OPCODE
+ /* Animation, Drivers, etc. ------------------------ */
+
+ /* NLA + Action */
+ DEG_OPCODE_ANIMATION,
+
+ /* Driver */
+ DEG_OPCODE_DRIVER,
+
+ /* Proxy Inherit? */
+ //DEG_OPCODE_PROXY,
+
+ /* Transform --------------------------------------- */
+
+ /* Transform entry point - local transforms only */
+ DEG_OPCODE_TRANSFORM_LOCAL,
+
+ /* Parenting */
+ DEG_OPCODE_TRANSFORM_PARENT,
+
+ /* Constraints */
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINTS_INIT,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINT,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINTS_DONE,
+
+ /* Rigidbody Sim - Perform Sim */
+ DEG_OPCODE_RIGIDBODY_REBUILD,
+ DEG_OPCODE_RIGIDBODY_SIM,
+
+ /* Rigidbody Sim - Copy Results to Object */
+ DEG_OPCODE_TRANSFORM_RIGIDBODY,
+
+ /* Transform exitpoint */
+ DEG_OPCODE_TRANSFORM_FINAL,
+
+ /* XXX: ubereval is for temporary porting purposes only */
+ DEG_OPCODE_OBJECT_UBEREVAL,
+
+ /* Geometry ---------------------------------------- */
+
+ /* XXX: Placeholder - UberEval */
+ DEG_OPCODE_GEOMETRY_UBEREVAL,
+
+ /* Modifier */
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+
+ /* Curve Objects - Path Calculation (used for path-following tools, */
+ DEG_OPCODE_GEOMETRY_PATH,
+
+ /* Pose -------------------------------------------- */
+
+ /* Init IK Trees, etc. */
+ DEG_OPCODE_POSE_INIT,
+
+ /* Free IK Trees + Compute Deform Matrices */
+ DEG_OPCODE_POSE_DONE,
+
+ /* IK/Spline Solvers */
+ DEG_OPCODE_POSE_IK_SOLVER,
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER,
+
+ /* Bone -------------------------------------------- */
+
+ /* Bone local transforms - Entrypoint */
+ DEG_OPCODE_BONE_LOCAL,
+
+ /* Pose-space conversion (includes parent + restpose, */
+ DEG_OPCODE_BONE_POSE_PARENT,
+
+ /* Constraints */
+ DEG_OPCODE_BONE_CONSTRAINTS,
+ //DEG_OPCODE_BONE_CONSTRAINTS_INIT,
+ //DEG_OPCODE_BONE_CONSTRAINT,
+ //DEG_OPCODE_BONE_CONSTRAINTS_DONE,
+
+ /* Bone transforms are ready
+ *
+ * - "READY" This (internal, noop is used to signal that all pre-IK
+ * operations are done. Its role is to help mediate situations
+ * where cyclic relations may otherwise form (i.e. one bone in
+ * chain targetting another in same chain,
+ *
+ * - "DONE" This noop is used to signal that the bone's final pose
+ * transform can be read by others
+ */
+ // TODO: deform mats could get calculated in the final_transform ops...
+ DEG_OPCODE_BONE_READY,
+ DEG_OPCODE_BONE_DONE,
+
+ /* Particles --------------------------------------- */
+
+ /* XXX: placeholder - Particle System eval */
+ DEG_OPCODE_PSYS_EVAL,
+
+ DEG_NUM_OPCODES,
} eDepsOperation_Code;
-/* String defines for these opcodes, defined in depsnode_operation.cpp */
-extern const char *DEG_OPNAMES[];
+/* Some magic to stringify operation codes. */
+class DepsOperationStringifier {
+public:
+ DepsOperationStringifier();
+ const char *operator[](eDepsOperation_Code opcodex);
+protected:
+ const char *names_[DEG_NUM_OPCODES];
+};
+/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */
+extern DepsOperationStringifier DEG_OPNAMES;
/* Type of operation */
typedef enum eDepsOperation_Type {
- /* Primary operation types */
- DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
- DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
- DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
-
- /* Additional operation types */
- DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
- DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
- DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
+ /* **** Primary operation types **** */
+
+ /* Initialise evaluation data */
+ DEPSOP_TYPE_INIT = 0,
+ /* Standard evaluation step */
+ DEPSOP_TYPE_EXEC = 1,
+ /* Cleanup evaluation data + flush results */
+ DEPSOP_TYPE_POST = 2,
+
+ /* **** Additional operation types **** */
+ /* Indicator for outputting a temporary result that other components
+ * can use. // XXX?
+ */
+ DEPSOP_TYPE_OUT = 3,
+ /* Indicator for things like IK Solvers and Rigidbody Sim steps which
+ * modify final results of separate entities at once.
+ */
+ DEPSOP_TYPE_SIM = 4,
+ /* Rebuild internal evaluation data - used for Rigidbody Reset and
+ * Armature Rebuild-On-Load.
+ */
+ DEPSOP_TYPE_REBUILD = 5,
} eDepsOperation_Type;
/* Types of relationships between nodes
@@ -170,4 +332,4 @@ typedef enum eDepsRelation_Type {
DEPSREL_TYPE_UPDATE_UI,
} eDepsRelation_Type;
-#endif /* __DEPSGRAPH_TYPES_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
deleted file mode 100644
index b81822c0ac5..00000000000
--- a/source/blender/depsgraph/intern/depsnode_opcodes.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * ***** 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) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsnode_opcodes.h
- * \ingroup depsgraph
- *
- * \par OpCodes for OperationDepsNodes
- *
- * This file defines all the "operation codes" (opcodes) used to identify
- * common operation node types. The intention of these defines is to have
- * a fast and reliable way of identifying the relevant nodes within a component
- * without having to use fragile dynamic strings.
- *
- * This file is meant to be used like UI_icons.h. That is, before including
- * the file, the host file must define the DEG_OPCODE(_label) macro, which
- * is responsible for converting the define into whatever form is suitable.
- * Therefore, it intentionally doesn't have header guards.
- */
-
-
-/* Example macro define: */
-/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
-
-/* Generic Operations ------------------------------ */
-
-/* Placeholder for operations which don't need special mention */
-DEF_DEG_OPCODE(OPERATION)
-
-// XXX: Placeholder while porting depsgraph code
-DEF_DEG_OPCODE(PLACEHOLDER)
-
-DEF_DEG_OPCODE(NOOP)
-
-/* Animation, Drivers, etc. ------------------------ */
-
-/* NLA + Action */
-DEF_DEG_OPCODE(ANIMATION)
-
-/* Driver */
-DEF_DEG_OPCODE(DRIVER)
-
-/* Proxy Inherit? */
-//DEF_DEG_OPCODE(PROXY)
-
-/* Transform --------------------------------------- */
-
-/* Transform entry point - local transforms only */
-DEF_DEG_OPCODE(TRANSFORM_LOCAL)
-
-/* Parenting */
-DEF_DEG_OPCODE(TRANSFORM_PARENT)
-
-/* Constraints */
-DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
-
-/* Rigidbody Sim - Perform Sim */
-DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
-DEF_DEG_OPCODE(RIGIDBODY_SIM)
-
-/* Rigidbody Sim - Copy Results to Object */
-DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
-
-/* Transform exitpoint */
-DEF_DEG_OPCODE(TRANSFORM_FINAL)
-
-/* XXX: ubereval is for temporary porting purposes only */
-DEF_DEG_OPCODE(OBJECT_UBEREVAL)
-
-/* Geometry ---------------------------------------- */
-
-/* XXX: Placeholder - UberEval */
-DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
-
-/* Modifier */
-DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
-
-/* Curve Objects - Path Calculation (used for path-following tools) */
-DEF_DEG_OPCODE(GEOMETRY_PATH)
-
-/* Pose -------------------------------------------- */
-
-/* Init IK Trees, etc. */
-DEF_DEG_OPCODE(POSE_INIT)
-
-/* Free IK Trees + Compute Deform Matrices */
-DEF_DEG_OPCODE(POSE_DONE)
-
-/* IK/Spline Solvers */
-DEF_DEG_OPCODE(POSE_IK_SOLVER)
-DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
-
-/* Bone -------------------------------------------- */
-
-/* Bone local transforms - Entrypoint */
-DEF_DEG_OPCODE(BONE_LOCAL)
-
-/* Pose-space conversion (includes parent + restpose) */
-DEF_DEG_OPCODE(BONE_POSE_PARENT)
-
-/* Constraints */
-DEF_DEG_OPCODE(BONE_CONSTRAINTS)
-//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
-//DEF_DEG_OPCODE(BONE_CONSTRAINT)
-//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
-
-/* Bone transforms are ready
- * - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
- * Its role is to help mediate situations where cyclic relations may otherwise form
- * (i.e. one bone in chain targetting another in same chain)
- * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
- */
-// TODO: deform mats could get calculated in the final_transform ops...
-DEF_DEG_OPCODE(BONE_READY)
-DEF_DEG_OPCODE(BONE_DONE)
-
-/* Particles --------------------------------------- */
-
-/* XXX: placeholder - Particle System eval */
-DEF_DEG_OPCODE(PSYS_EVAL)
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
new file mode 100644
index 00000000000..198cd349002
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -0,0 +1,409 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#include "intern/eval/deg_eval.h"
+
+#include "PIL_time.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_ghash.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "atomic_ops.h"
+
+#include "intern/eval/deg_eval_debug.h"
+#include "intern/eval/deg_eval_flush.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph.h"
+#include "util/deg_util_foreach.h"
+
+/* Unfinished and unused, and takes quite some pre-processing time. */
+#undef USE_EVAL_PRIORITY
+
+/* Use integrated debugger to keep track how much each of the nodes was
+ * evaluating.
+ */
+#undef USE_DEBUGGER
+
+namespace DEG {
+
+/* ********************** */
+/* Evaluation Entrypoints */
+
+/* Forward declarations. */
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers,
+ const int thread_id);
+
+struct DepsgraphEvalState {
+ EvaluationContext *eval_ctx;
+ Depsgraph *graph;
+ int layers;
+};
+
+static void deg_task_run_func(TaskPool *pool,
+ void *taskdata,
+ int thread_id)
+{
+ DepsgraphEvalState *state =
+ reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool));
+ OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata);
+
+ BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ while (true) {
+ /* Get context. */
+ /* TODO: Who initialises this? "Init" operations aren't able to
+ * initialise it!!!
+ */
+ /* TODO(sergey): We don't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Since we're not leaving the thread for until the graph branches it is
+ * possible to have NO-OP on the way. for which evaluate() will be NULL.
+ * but that's all fine, we'll just scheduler it's children.
+ */
+ if (node->evaluate) {
+ /* Take note of current time. */
+#ifdef USE_DEBUGGER
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+#endif
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+#ifdef USE_DEBUGGER
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+#endif
+ }
+
+ /* If there's only one outgoing link we try to immediately switch to
+ * that node evaluation, without leaving the thread.
+ *
+ * It's only doable if the child don't have extra relations or all they
+ * are satisfied.
+ *
+ * TODO(sergey): Checks here can be de-duplicated with the ones from
+ * schedule_node(), however, how to do it nicely?
+ */
+ if (node->outlinks.size() == 1) {
+ DepsRelation *rel = node->outlinks[0];
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (!child->scheduled) {
+ int id_layers = child->owner->owner->layers;
+ if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & state->layers) != 0))
+ {
+ /* Node does not need an update, so can;t continue with the
+ * chain and need to switch to another one by leaving the
+ * thread.
+ */
+ break;
+ }
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+ if (child->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&child->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ /* Node was not scheduled, switch to it! */
+ node = child;
+ }
+ else {
+ /* Someone else scheduled the node, leaving us
+ * unemployed in this thread, we're leaving.
+ */
+ break;
+ }
+ }
+ else {
+ /* There are other dependencies on the child, can't do
+ * anything in the current thread.
+ */
+ break;
+ }
+ }
+ else {
+ /* Happens when having cyclic dependencies.
+ *
+ * Nothing to do here, single child was already scheduled, we
+ * can leave the thread now.
+ */
+ break;
+ }
+ }
+ else {
+ /* TODO(sergey): It's possible to use one of the outgoing relations
+ * as a chain which we'll try to keep alive, but it's a bit more
+ * involved change.
+ */
+ schedule_children(pool, state->graph, node, state->layers, thread_id);
+ break;
+ }
+ }
+}
+
+typedef struct CalculatePengindData {
+ Depsgraph *graph;
+ int layers;
+} CalculatePengindData;
+
+static void calculate_pending_func(void *data_v, int i)
+{
+ CalculatePengindData *data = (CalculatePengindData *)data_v;
+ Depsgraph *graph = data->graph;
+ int layers = data->layers;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ }
+ }
+}
+
+static void calculate_pending_parents(Depsgraph *graph, int layers)
+{
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ CalculatePengindData data;
+ data.graph = graph;
+ data.layers = layers;
+ BLI_task_parallel_range(0,
+ num_operations,
+ &data,
+ calculate_pending_func,
+ do_threads);
+}
+
+#ifdef USE_EVAL_PRIORITY
+static void calculate_eval_priority(OperationDepsNode *node)
+{
+ if (node->done) {
+ return;
+ }
+ node->done = 1;
+
+ if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ /* XXX standard cost of a node, could be estimated somewhat later on */
+ const float cost = 1.0f;
+ /* NOOP nodes have no cost */
+ node->eval_priority = node->is_noop() ? cost : 0.0f;
+
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ calculate_eval_priority(to);
+ node->eval_priority += to->eval_priority;
+ }
+ }
+ else {
+ node->eval_priority = 0.0f;
+ }
+}
+#endif
+
+/* Schedule a node if it needs evaluation.
+ * dec_parents: Decrement pending parents count, true when child nodes are
+ * scheduled after a task has been completed.
+ */
+static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
+ OperationDepsNode *node, bool dec_parents,
+ const int thread_id)
+{
+ int id_layers = node->owner->owner->layers;
+
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & layers) != 0)
+ {
+ if (dec_parents) {
+ BLI_assert(node->num_links_pending > 0);
+ atomic_sub_uint32(&node->num_links_pending, 1);
+ }
+
+ if (node->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&node->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ if (node->is_noop()) {
+ /* skip NOOP node, schedule children right away */
+ schedule_children(pool, graph, node, layers, thread_id);
+ }
+ else {
+ /* children are scheduled once this task is completed */
+ BLI_task_pool_push_from_thread(pool,
+ deg_task_run_func,
+ node,
+ false,
+ TASK_PRIORITY_LOW,
+ thread_id);
+ }
+ }
+ }
+ }
+}
+
+static void schedule_graph(TaskPool *pool,
+ Depsgraph *graph,
+ const int layers)
+{
+ foreach (OperationDepsNode *node, graph->operations) {
+ schedule_node(pool, graph, layers, node, false, 0);
+ }
+}
+
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers,
+ const int thread_id)
+{
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (child->scheduled) {
+ /* Happens when having cyclic dependencies. */
+ continue;
+ }
+ schedule_node(pool,
+ graph,
+ layers,
+ child,
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
+ thread_id);
+ }
+}
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers)
+{
+ /* Generate base evaluation context, upon which all the others are derived. */
+ // TODO: this needs both main and scene access...
+
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
+
+ /* XXX could use a separate pool for each eval context */
+ DepsgraphEvalState state;
+ state.eval_ctx = eval_ctx;
+ state.graph = graph;
+ state.layers = layers;
+
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
+
+ calculate_pending_parents(graph, layers);
+
+ /* Clear tags. */
+ foreach (OperationDepsNode *node, graph->operations) {
+ node->done = 0;
+ }
+
+ /* Calculate priority for operation nodes. */
+#ifdef USE_EVAL_PRIORITY
+ foreach (OperationDepsNode *node, graph->operations) {
+ calculate_eval_priority(node);
+ }
+#endif
+
+ DepsgraphDebug::eval_begin(eval_ctx);
+
+ schedule_graph(task_pool, graph, layers);
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ DepsgraphDebug::eval_end(eval_ctx);
+
+ /* Clear any uncleared tags - just in case. */
+ deg_graph_clear_tags(graph);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
new file mode 100644
index 00000000000..0d42f63433f
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -0,0 +1,52 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#pragma once
+
+struct EvaluationContext;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
new file mode 100644
index 00000000000..67d64aae8bf
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
@@ -0,0 +1,249 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_debug.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+#include <cstring>
+
+#include "intern/eval/deg_eval_debug.h"
+
+extern "C" {
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph_debug.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+} /* extern "C" */
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
+
+DepsgraphStats *DepsgraphDebug::stats = NULL;
+
+static string get_component_name(eDepsNode_Type type, const string &name = "")
+{
+ DepsNodeFactory *factory = deg_get_node_factory(type);
+ if (name.empty()) {
+ return string(factory->tname());
+ }
+ else {
+ return string(factory->tname()) + " | " + name;
+ }
+}
+
+static void times_clear(DepsgraphStatsTimes &times)
+{
+ times.duration_last = 0.0f;
+}
+
+static void times_add(DepsgraphStatsTimes &times, float time)
+{
+ times.duration_last += time;
+}
+
+void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
+{
+ /* TODO(sergey): Stats are currently globally disabled. */
+ /* verify_stats(); */
+ reset_stats();
+}
+
+void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
+{
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+}
+
+void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
+ const char *message)
+{
+#ifdef DEG_DEBUG_BUILD
+ if (deg_debug_eval_cb)
+ deg_debug_eval_cb(deg_debug_eval_userdata, message);
+#else
+ (void)message; /* Ignored. */
+#endif
+}
+
+void DepsgraphDebug::task_started(Depsgraph *graph,
+ const OperationDepsNode *node)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_clear(id_stats->times);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier
+ * and description strings!
+ */
+ DepsgraphStatsComponent *comp_stats =
+ get_component_stats(id, get_component_name(comp->type,
+ comp->name),
+ true);
+ times_clear(comp_stats->times);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+void DepsgraphDebug::task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_add(id_stats->times, time);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier
+ * and description strings!
+ */
+ DepsgraphStatsComponent *comp_stats =
+ get_component_stats(id,
+ get_component_name(comp->type,
+ comp->name),
+ true);
+ times_add(comp_stats->times, time);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+/* ********** */
+/* Statistics */
+
+
+/* GHash callback */
+static void deg_id_stats_free(void *val)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
+
+ if (id_stats) {
+ BLI_freelistN(&id_stats->components);
+ MEM_freeN(id_stats);
+ }
+}
+
+void DepsgraphDebug::stats_init()
+{
+ if (!stats) {
+ stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats),
+ "Depsgraph Stats");
+ stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp,
+ "Depsgraph ID Stats Hash");
+ }
+}
+
+void DepsgraphDebug::stats_free()
+{
+ if (stats) {
+ BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
+ MEM_freeN(stats);
+ stats = NULL;
+ }
+}
+
+void DepsgraphDebug::verify_stats()
+{
+ stats_init();
+}
+
+void DepsgraphDebug::reset_stats()
+{
+ if (!stats) {
+ return;
+ }
+
+ /* XXX this doesn't work, will immediately clear all info,
+ * since most depsgraph updates have none or very few updates to handle.
+ *
+ * Could consider clearing only zero-user ID blocks here
+ */
+// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
+}
+
+DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
+
+ if (!id_stats && create) {
+ id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID),
+ "Depsgraph ID Stats");
+ id_stats->id = id;
+
+ BLI_ghash_insert(stats->id_stats, id, id_stats);
+ }
+
+ return id_stats;
+}
+
+DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
+ DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create)
+{
+ DepsgraphStatsComponent *comp_stats;
+ for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
+ comp_stats != NULL;
+ comp_stats = comp_stats->next)
+ {
+ if (STREQ(comp_stats->name, name.c_str()))
+ break;
+ }
+ if (!comp_stats && create) {
+ comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent),
+ "Depsgraph Component Stats");
+ BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_addtail(&id_stats->components, comp_stats);
+ }
+ return comp_stats;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
index 64b97855f57..9109019eb2d 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
@@ -24,27 +24,26 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_debug.h
+/** \file blender/depsgraph/intern/eval/deg_eval_debug.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_DEBUG_H__
-#define __DEPSGRAPH_DEBUG_H__
+#pragma once
-#include "depsgraph_types.h"
+#include "intern/depsgraph_types.h"
-extern "C" {
-#include "BKE_global.h"
-}
+struct ID;
+struct EvaluationContext;
struct DepsgraphStats;
struct DepsgraphStatsID;
struct DepsgraphStatsComponent;
-struct DepsgraphSettings;
-struct EvaluationContext;
-struct OperationDepsNode;
+
+namespace DEG {
struct Depsgraph;
+struct DepsgraphSettings;
+struct OperationDepsNode;
struct DepsgraphDebug {
static DepsgraphStats *stats;
@@ -77,11 +76,4 @@ struct DepsgraphDebug {
}
};
-#define DEG_DEBUG_PRINTF(...) \
- { \
- if (G.debug & G_DEBUG_DEPSGRAPH) { \
- fprintf(stderr, __VA_ARGS__); \
- } \
- } \
-
-#endif /* __DEPSGRAPH_DEBUG_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
new file mode 100644
index 00000000000..af68f5c55c4
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -0,0 +1,224 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_tag.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include "intern/eval/deg_eval_flush.h"
+
+// TODO(sergey): Use some sort of wrapper.
+#include <queue>
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+namespace {
+
+// TODO(sergey): De-duplicate with depsgraph_tag,cc
+void lib_id_recalc_tag(Main *bmain, ID *id)
+{
+ id->tag |= LIB_TAG_ID_RECALC;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_data_tag(Main *bmain, ID *id)
+{
+ id->tag |= LIB_TAG_ID_RECALC_DATA;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+} /* namespace */
+
+typedef std::queue<OperationDepsNode *> FlushQueue;
+
+static void flush_init_func(void *data_v, int i)
+{
+ /* ID node's done flag is used to avoid multiple editors update
+ * for the same ID.
+ */
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+ id_node->done = 0;
+ node->scheduled = false;
+ node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
+}
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ /* Sanity check. */
+ if (graph == NULL) {
+ return;
+ }
+
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+
+ /* TODO(sergey): With a bit of flag magic we can get rid of this
+ * extra loop.
+ */
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0,
+ num_operations,
+ graph,
+ flush_init_func,
+ do_threads);
+
+ FlushQueue queue;
+ /* Starting from the tagged "entry" nodes, flush outwards... */
+ /* NOTE: Also need to ensure that for each of these, there is a path back to
+ * root, or else they won't be done.
+ * NOTE: Count how many nodes we need to handle - entry nodes may be
+ * component nodes which don't count for this purpose!
+ */
+ GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
+ {
+ queue.push(node);
+ node->scheduled = true;
+ }
+ GSET_FOREACH_END();
+
+ while (!queue.empty()) {
+ OperationDepsNode *node = queue.front();
+ queue.pop();
+
+ for (;;) {
+ node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+
+ IDDepsNode *id_node = node->owner->owner;
+
+ if (id_node->done == 0) {
+ deg_editors_id_update(bmain, id_node->id);
+ id_node->done = 1;
+ }
+
+ lib_id_recalc_tag(bmain, id_node->id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_node->id);
+
+ ID *id = id_node->id;
+ /* This code is used to preserve those areas which does direct
+ * object update,
+ *
+ * Plus it ensures visibility changes and relations and layers
+ * visibility update has proper flags to work with.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ ComponentDepsNode *comp_node = node->owner;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ /* TODO(sergey): For until incremental updates are possible
+ * witin a component at least we tag the whole component
+ * for update.
+ */
+ ComponentDepsNode *component = node->owner;
+ if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
+ foreach (OperationDepsNode *op, component->operations) {
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ component->flags |= DEPSCOMP_FULLY_SCHEDULED;
+ }
+
+ /* Flush to nodes along links... */
+ if (node->outlinks.size() == 1) {
+ OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
+ if (to_node->scheduled == false) {
+ to_node->scheduled = true;
+ node = to_node;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ queue.push(to_node);
+ to_node->scheduled = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void graph_clear_func(void *data_v, int i)
+{
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+}
+
+/* Clear tags from all operation nodes. */
+void deg_graph_clear_tags(Depsgraph *graph)
+{
+ /* Go over all operation nodes, clearing tags. */
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
+ /* Clear any entry tags which haven't been flushed. */
+ BLI_gset_clear(graph->entry_tags, NULL);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
new file mode 100644
index 00000000000..8912aebee7d
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -0,0 +1,49 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#pragma once
+
+struct Main;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(struct Main *bmain, struct Depsgraph *graph);
+
+/* Clear tags from all operation nodes. */
+void deg_graph_clear_tags(struct Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 8aa1059d2dc..78293f7f483 100644
--- a/source/blender/depsgraph/intern/depsnode.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -28,10 +28,13 @@
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node.h"
+
#include <stdio.h>
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
extern "C" {
#include "DNA_ID.h"
@@ -42,10 +45,13 @@ extern "C" {
#include "DEG_depsgraph.h"
}
-#include "depsnode.h" /* own include */
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+#include "util/deg_util_hash.h"
+
+namespace DEG {
/* *************** */
/* Node Management */
@@ -66,7 +72,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
DepsNode::DepsNode()
{
- this->name[0] = '\0';
+ name[0] = '\0';
}
DepsNode::~DepsNode()
@@ -76,11 +82,9 @@ DepsNode::~DepsNode()
* when we're trying to free same link from both it's sides. We don't have
* dangling links so this is not a problem from memory leaks point of view.
*/
- DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
- {
+ foreach (DepsRelation *rel, inlinks) {
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
- DEPSNODE_RELATIONS_ITER_END;
}
@@ -100,11 +104,7 @@ string DepsNode::identifier() const
void TimeSourceDepsNode::tag_update(Depsgraph *graph)
{
- for (DepsNode::Relations::const_iterator it = outlinks.begin();
- it != outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
+ foreach (DepsRelation *rel, outlinks) {
DepsNode *node = rel->to;
node->tag_update(graph);
}
@@ -125,7 +125,7 @@ RootDepsNode::~RootDepsNode()
TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
{
if (!time_source) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
/*time_source->owner = this;*/ // XXX
}
@@ -142,6 +142,36 @@ static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
/* ID Node ================================================ */
+static unsigned int id_deps_node_hash_key(const void *key_v)
+{
+ const IDDepsNode::ComponentIDKey *key =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
+ return hash_combine(BLI_ghashutil_uinthash(key->type),
+ BLI_ghashutil_strhash_p(key->name.c_str()));
+}
+
+static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
+{
+ const IDDepsNode::ComponentIDKey *key_a =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a);
+ const IDDepsNode::ComponentIDKey *key_b =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void id_deps_node_hash_key_free(void *key_v)
+{
+ typedef IDDepsNode::ComponentIDKey ComponentIDKey;
+ ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, ComponentIDKey);
+}
+
+static void id_deps_node_hash_value_free(void *value_v)
+{
+ ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+}
+
/* Initialize 'id' node - from pointer data given. */
void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
{
@@ -151,6 +181,10 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
this->layers = (1 << 20) - 1;
this->eval_flags = 0;
+ components = BLI_ghash_new(id_deps_node_hash_key,
+ id_deps_node_hash_key_cmp,
+ "Depsgraph id components hash");
+
/* NOTE: components themselves are created if/when needed.
* This prevents problems with components getting added
* twice if an ID-Ref needs to be created to house it...
@@ -161,51 +195,27 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
IDDepsNode::~IDDepsNode()
{
clear_components();
-}
-
-/* Copy 'id' node. */
-void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
-{
- (void)src; /* Ignored. */
- /* Iterate over items in original hash, adding them to new hash. */
- for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
- it != this->components.end();
- ++it)
- {
- /* Get current <type : component> mapping. */
- ComponentIDKey c_key = it->first;
- DepsNode *old_component = it->second;
-
- /* Make a copy of component. */
- ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
-
- /* Add new node to hash... */
- this->components[c_key] = component;
- }
-
- // TODO: perform a second loop to fix up links?
- BLI_assert(!"Not expected to be used");
+ BLI_ghash_free(components, id_deps_node_hash_key_free, NULL);
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
const string &name) const
{
ComponentIDKey key(type, name);
- ComponentMap::const_iterator it = components.find(key);
- return it != components.end() ? it->second : NULL;
+ return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
}
ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
const string &name)
{
- ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(type);
+ DepsNodeFactory *factory = deg_get_node_factory(type);
comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
/* Register. */
- this->components[key] = comp_node;
+ ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
+ BLI_ghash_insert(components, key, comp_node);
comp_node->owner = this;
}
return comp_node;
@@ -213,34 +223,28 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
{
- ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (comp_node) {
/* Unregister. */
- this->components.erase(key);
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ ComponentIDKey key(type, name);
+ BLI_ghash_remove(components,
+ &key,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
}
void IDDepsNode::clear_components()
{
- for (ComponentMap::const_iterator it = components.begin();
- it != components.end();
- ++it)
- {
- ComponentDepsNode *comp_node = it->second;
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
- }
- components.clear();
+ BLI_ghash_clear(components,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
void IDDepsNode::tag_update(Depsgraph *graph)
{
- for (ComponentMap::const_iterator it = components.begin();
- it != components.end();
- ++it)
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
- ComponentDepsNode *comp_node = it->second;
/* TODO(sergey): What about drievrs? */
bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
@@ -254,6 +258,16 @@ void IDDepsNode::tag_update(Depsgraph *graph)
comp_node->tag_update(graph);
}
}
+ GHASH_FOREACH_END();
+}
+
+void IDDepsNode::finalize_build()
+{
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
+ {
+ comp_node->finalize_build();
+ }
+ GHASH_FOREACH_END();
}
DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
@@ -281,31 +295,21 @@ SubgraphDepsNode::~SubgraphDepsNode()
// XXX: prune these flags a bit...
if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
/* Free the referenced graph. */
- DEG_graph_free(this->graph);
- this->graph = NULL;
+ DEG_graph_free(reinterpret_cast< ::Depsgraph* >(graph));
+ graph = NULL;
}
}
-/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
-void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
- const SubgraphDepsNode * /*src*/)
-{
- //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
- //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
-
- /* for now, subgraph itself isn't copied... */
- BLI_assert(!"Not expected to be used");
-}
-
DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
-
-void DEG_register_base_depsnodes()
+void deg_register_base_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_ROOT);
- DEG_register_node_typeinfo(&DNTI_TIMESOURCE);
+ deg_register_node_typeinfo(&DNTI_ROOT);
+ deg_register_node_typeinfo(&DNTI_TIMESOURCE);
- DEG_register_node_typeinfo(&DNTI_ID_REF);
- DEG_register_node_typeinfo(&DNTI_SUBGRAPH);
+ deg_register_node_typeinfo(&DNTI_ID_REF);
+ deg_register_node_typeinfo(&DNTI_SUBGRAPH);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index 4a464955384..d79d3d2348d 100644
--- a/source/blender/depsgraph/intern/depsnode.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -28,21 +28,18 @@
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_H__
-#define __DEPSNODE_H__
+#pragma once
-#include "depsgraph_types.h"
-
-#include "depsgraph_util_hash.h"
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "intern/depsgraph_types.h"
struct ID;
+struct GHash;
struct Scene;
+namespace DEG {
+
struct Depsgraph;
struct DepsRelation;
-struct DepsgraphCopyContext;
struct OperationDepsNode;
/* *********************************** */
@@ -94,8 +91,6 @@ struct DepsNode {
virtual void init(const ID * /*id*/,
const string &/*subdata*/) {}
- virtual void copy(DepsgraphCopyContext * /*dcc*/,
- const DepsNode * /*src*/) {}
virtual void tag_update(Depsgraph * /*graph*/) {}
@@ -160,24 +155,7 @@ struct IDDepsNode : public DepsNode {
string name;
};
- /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
- * a nested type ...
- *
- * http://stackoverflow.com/a/951245
- */
- struct component_key_hash {
- bool operator() (const ComponentIDKey &key) const
- {
- return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
- }
- };
-
- typedef unordered_map<ComponentIDKey,
- ComponentDepsNode *,
- component_key_hash> ComponentMap;
-
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
~IDDepsNode();
ComponentDepsNode *find_component(eDepsNode_Type type,
@@ -189,11 +167,13 @@ struct IDDepsNode : public DepsNode {
void tag_update(Depsgraph *graph);
+ void finalize_build();
+
/* ID Block referenced. */
ID *id;
/* Hash to make it faster to look up components. */
- ComponentMap components;
+ GHash *components;
/* Layers of this node with accumulated layers of it's output relations. */
int layers;
@@ -210,7 +190,6 @@ struct IDDepsNode : public DepsNode {
/* Subgraph Reference. */
struct SubgraphDepsNode : public DepsNode {
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
~SubgraphDepsNode();
/* Instanced graph. */
@@ -243,6 +222,6 @@ typedef enum eSubgraphRef_Flag {
SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
} eSubgraphRef_Flag;
-void DEG_register_base_depsnodes();
+void deg_register_base_depsnodes();
-#endif /* __DEPSNODE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index a47a0d29228..7e49fec051f 100644
--- a/source/blender/depsgraph/intern/depsnode_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -28,6 +28,8 @@
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node_component.h"
+
#include <stdio.h>
#include <string.h>
@@ -39,20 +41,57 @@ extern "C" {
#include "BKE_action.h"
} /* extern "C" */
-#include "depsnode_component.h" /* own include */
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+#include "util/deg_util_hash.h"
+
+namespace DEG {
/* *********** */
/* Outer Nodes */
/* Standard Component Methods ============================= */
+static unsigned int comp_node_hash_key(const void *key_v)
+{
+ const ComponentDepsNode::OperationIDKey *key =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v);
+ return hash_combine(BLI_ghashutil_uinthash(key->opcode),
+ BLI_ghashutil_strhash_p(key->name.c_str()));
+}
+
+static bool comp_node_hash_key_cmp(const void *a, const void *b)
+{
+ const ComponentDepsNode::OperationIDKey *key_a =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(a);
+ const ComponentDepsNode::OperationIDKey *key_b =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void comp_node_hash_key_free(void *key_v)
+{
+ typedef ComponentDepsNode::OperationIDKey OperationIDKey;
+ OperationIDKey *key = reinterpret_cast<OperationIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, OperationIDKey);
+}
+
+static void comp_node_hash_value_free(void *value_v)
+{
+ OperationDepsNode *op_node = reinterpret_cast<OperationDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+}
+
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
exit_operation(NULL),
- flags(0)
+ flags(0),
+ layers(0)
{
+ operations_map = BLI_ghash_new(comp_node_hash_key,
+ comp_node_hash_key_cmp,
+ "Depsgraph id hash");
}
/* Initialize 'component' node - from pointer data given */
@@ -63,37 +102,15 @@ void ComponentDepsNode::init(const ID * /*id*/,
// XXX: maybe this needs a special API?
}
-/* Copy 'component' node */
-void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
- const ComponentDepsNode * /*src*/)
-{
-#if 0 // XXX: remove all this
- /* duplicate list of operation nodes */
- this->operations.clear();
-
- for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
- const string &pchan_name = it->first;
- OperationDepsNode *src_op = it->second;
-
- /* recursive copy */
- DepsNodeFactory *factory = DEG_node_get_factory(src_op);
- OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
- this->operations[pchan_name] = dst_op;
-
- /* fix links... */
- // ...
- }
-
- /* copy evaluation contexts */
- //
-#endif
- BLI_assert(!"Not expected to be called");
-}
-
/* Free 'component' node */
ComponentDepsNode::~ComponentDepsNode()
{
clear_operations();
+ if (operations_map != NULL) {
+ BLI_ghash_free(operations_map,
+ comp_node_hash_key_free,
+ comp_node_hash_value_free);
+ }
}
string ComponentDepsNode::identifier() const
@@ -103,15 +120,17 @@ string ComponentDepsNode::identifier() const
char typebuf[7];
sprintf(typebuf, "(%d)", type);
- return string(typebuf) + name + " : " + idname;
+ char layers[7];
+ sprintf(layers, "%d", this->layers);
+
+ return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")";
}
OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
{
- OperationMap::const_iterator it = this->operations.find(key);
-
- if (it != this->operations.end()) {
- return it->second;
+ OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key));
+ if (node != NULL) {
+ return node;
}
else {
fprintf(stderr, "%s: find_operation(%s) failed\n",
@@ -129,11 +148,7 @@ OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode,
OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
{
- OperationMap::const_iterator it = this->operations.find(key);
- if (it != this->operations.end()) {
- return it->second;
- }
- return NULL;
+ return reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key));
}
OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
@@ -147,12 +162,12 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
{
OperationDepsNode *op_node = has_operation(opcode, name);
if (!op_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
/* register opnode in this component's operation set */
- OperationIDKey key(opcode, name);
- this->operations[key] = op_node;
+ OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name);
+ BLI_ghash_insert(operations_map, key, op_node);
/* set as entry/exit node of component (if appropriate) */
if (optype == DEPSOP_TYPE_INIT) {
@@ -185,18 +200,22 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
{
- OperationDepsNode *op_node = find_operation(opcode, name);
- if (op_node) {
- /* unregister */
- this->operations.erase(OperationIDKey(opcode, name));
- OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
- }
+ /* unregister */
+ OperationIDKey key(opcode, name);
+ BLI_ghash_remove(operations_map,
+ &key,
+ comp_node_hash_key_free,
+ comp_node_hash_key_free);
}
void ComponentDepsNode::clear_operations()
{
- for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
- OperationDepsNode *op_node = it->second;
+ if (operations_map != NULL) {
+ BLI_ghash_clear(operations_map,
+ comp_node_hash_key_free,
+ comp_node_hash_value_free);
+ }
+ foreach (OperationDepsNode *op_node, operations) {
OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
}
operations.clear();
@@ -208,30 +227,79 @@ void ComponentDepsNode::tag_update(Depsgraph *graph)
if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
- for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
- OperationDepsNode *op_node = it->second;
+ foreach (OperationDepsNode *op_node, operations) {
op_node->tag_update(graph);
}
+ // It is possible that tag happens before finalization.
+ if (operations_map != NULL) {
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
+ {
+ op_node->tag_update(graph);
+ }
+ GHASH_FOREACH_END();
+ }
}
OperationDepsNode *ComponentDepsNode::get_entry_operation()
{
- if (entry_operation)
+ if (entry_operation) {
return entry_operation;
- else if (operations.size() == 1)
- return operations.begin()->second;
+ }
+ else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) {
+ OperationDepsNode *op_node = NULL;
+ /* TODO(sergey): This is somewhat slow. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map)
+ {
+ op_node = tmp;
+ }
+ GHASH_FOREACH_END();
+ /* Cache for the subsequent usage. */
+ entry_operation = op_node;
+ return op_node;
+ }
+ else if(operations.size() == 1) {
+ return operations[0];
+ }
return NULL;
}
OperationDepsNode *ComponentDepsNode::get_exit_operation()
{
- if (exit_operation)
+ if (exit_operation) {
return exit_operation;
- else if (operations.size() == 1)
- return operations.begin()->second;
+ }
+ else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) {
+ OperationDepsNode *op_node = NULL;
+ /* TODO(sergey): This is somewhat slow. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map)
+ {
+ op_node = tmp;
+ }
+ GHASH_FOREACH_END();
+ /* Cache for the subsequent usage. */
+ exit_operation = op_node;
+ return op_node;
+ }
+ else if(operations.size() == 1) {
+ return operations[0];
+ }
return NULL;
}
+void ComponentDepsNode::finalize_build()
+{
+ operations.reserve(BLI_ghash_size(operations_map));
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
+ {
+ operations.push_back(op_node);
+ }
+ GHASH_FOREACH_END();
+ BLI_ghash_free(operations_map,
+ comp_node_hash_key_free,
+ NULL);
+ operations_map = NULL;
+}
+
/* Parameter Component Defines ============================ */
DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
@@ -302,18 +370,20 @@ static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
/* Node Types Register =================================== */
-void DEG_register_component_depsnodes()
+void deg_register_component_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_PARAMETERS);
- DEG_register_node_typeinfo(&DNTI_PROXY);
- DEG_register_node_typeinfo(&DNTI_ANIMATION);
- DEG_register_node_typeinfo(&DNTI_TRANSFORM);
- DEG_register_node_typeinfo(&DNTI_GEOMETRY);
- DEG_register_node_typeinfo(&DNTI_SEQUENCER);
-
- DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
- DEG_register_node_typeinfo(&DNTI_BONE);
-
- DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
- DEG_register_node_typeinfo(&DNTI_SHADING);
+ deg_register_node_typeinfo(&DNTI_PARAMETERS);
+ deg_register_node_typeinfo(&DNTI_PROXY);
+ deg_register_node_typeinfo(&DNTI_ANIMATION);
+ deg_register_node_typeinfo(&DNTI_TRANSFORM);
+ deg_register_node_typeinfo(&DNTI_GEOMETRY);
+ deg_register_node_typeinfo(&DNTI_SEQUENCER);
+
+ deg_register_node_typeinfo(&DNTI_EVAL_POSE);
+ deg_register_node_typeinfo(&DNTI_BONE);
+
+ deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ deg_register_node_typeinfo(&DNTI_SHADING);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index 7f44c0ed03f..df321ea9299 100644
--- a/source/blender/depsgraph/intern/depsnode_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -28,21 +28,22 @@
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_COMPONENT_H__
-#define __DEPSNODE_COMPONENT_H__
+#pragma once
-#include "depsnode.h"
+#include "intern/nodes/deg_node.h"
-#include "depsgraph_util_hash.h"
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
struct ID;
struct bPoseChannel;
+struct GHash;
-struct Depsgraph;
-struct DepsgraphCopyContext;
struct EvaluationContext;
+
+namespace DEG {
+
+struct Depsgraph;
struct OperationDepsNode;
struct BoneComponentDepsNode;
@@ -75,7 +76,7 @@ struct ComponentDepsNode : public DepsNode {
string identifier() const
{
char codebuf[5];
- sprintf(codebuf, "%d", opcode);
+ BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
return string("OperationIDKey(") + codebuf + ", " + name + ")";
}
@@ -86,47 +87,41 @@ struct ComponentDepsNode : public DepsNode {
}
};
- /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
- * http://stackoverflow.com/a/951245
- */
- struct operation_key_hash {
- bool operator() (const OperationIDKey &key) const
- {
- return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
- }
- };
-
/* Typedef for container of operations */
- typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
-
-
ComponentDepsNode();
~ComponentDepsNode();
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
string identifier() const;
/* Find an existing operation, will throw an assert() if it does not exist. */
OperationDepsNode *find_operation(OperationIDKey key) const;
- OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
+ OperationDepsNode *find_operation(eDepsOperation_Code opcode,
+ const string &name) const;
/* Check operation exists and return it. */
OperationDepsNode *has_operation(OperationIDKey key) const;
- OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
+ OperationDepsNode *has_operation(eDepsOperation_Code opcode,
+ const string &name) const;
/**
* Create a new node for representing an operation and add this to graph
- * \warning If an existing node is found, it will be modified. This helps when node may
- * have been partially created earlier (e.g. parent ref before parent item is added)
+ * \warning If an existing node is found, it will be modified. This helps
+ * when node may have been partially created earlier (e.g. parent ref before
+ * parent item is added)
*
- * \param type: Operation node type (corresponding to context/component that it operates in)
- * \param optype: Role that operation plays within component (i.e. where in eval process)
+ * \param type: Operation node type (corresponding to context/component that
+ * it operates in)
+ * \param optype: Role that operation plays within component
+ * (i.e. where in eval process)
* \param op: The operation to perform
* \param name: Identifier for operation - used to find/locate it again
*/
- OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name);
+ OperationDepsNode *add_operation(eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &name);
void remove_operation(eDepsOperation_Code opcode, const string &name);
void clear_operations();
@@ -135,9 +130,13 @@ struct ComponentDepsNode : public DepsNode {
/* Evaluation Context Management .................. */
- /* Initialize component's evaluation context used for the specified purpose */
+ /* Initialize component's evaluation context used for the specified
+ * purpose.
+ */
virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
- /* Free data in component's evaluation context which is used for the specified purpose
+ /* Free data in component's evaluation context which is used for
+ * the specified purpose
+ *
* NOTE: this does not free the actual context in question
*/
virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
@@ -145,15 +144,31 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation();
OperationDepsNode *get_exit_operation();
+ void finalize_build();
+
IDDepsNode *owner;
- OperationMap operations; /* inner nodes for this component */
+ /* ** Inner nodes for this component ** */
+
+ /* Operations stored as a hash map, for faster build.
+ * This hash map will be freed when graph is fully built.
+ */
+ GHash *operations_map;
+
+ /* This is a "normal" list of operations, used by evaluation
+ * and other routines after construction.
+ */
+ vector<OperationDepsNode *> operations;
+
OperationDepsNode *entry_operation;
OperationDepsNode *exit_operation;
// XXX: a poll() callback to check if component's first node can be started?
int flags;
+
+ /* Temporary bitmask, used during graph construction. */
+ int layers;
};
/* ---------------------------------------- */
@@ -204,6 +219,6 @@ struct ShadingComponentDepsNode : public ComponentDepsNode {
};
-void DEG_register_component_depsnodes();
+void deg_register_component_depsnodes();
-#endif /* __DEPSNODE_COMPONENT_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 6aeb163356b..a9f9703bb3b 100644
--- a/source/blender/depsgraph/intern/depsnode_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -28,35 +28,27 @@
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node_operation.h"
+
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
} /* extern "C" */
-#include "depsnode_operation.h" /* own include */
-#include "depsnode_component.h"
-#include "depsgraph.h"
-#include "depsgraph_intern.h"
-
-/* ******************************************************************* */
-/* OpNode Identifiers Array - Exported to other depsgraph files too... */
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_hash.h"
-/* identifiers for operations */
-const char *DEG_OPNAMES[] = {
-#define DEF_DEG_OPCODE(label) #label,
-#include "depsnode_opcodes.h"
-#undef DEF_DEG_OPCODE
-
- "<Invalid>"
-};
+namespace DEG {
/* *********** */
/* Inner Nodes */
OperationDepsNode::OperationDepsNode() :
eval_priority(0.0f),
- flag(0)
+ flag(0),
+ customdata_mask(0)
{
}
@@ -66,7 +58,6 @@ OperationDepsNode::~OperationDepsNode()
string OperationDepsNode::identifier() const
{
- BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
}
@@ -98,7 +89,9 @@ void OperationDepsNode::tag_update(Depsgraph *graph)
DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
-void DEG_register_operation_depsnodes()
+void deg_register_operation_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_OPERATION);
+ deg_register_node_typeinfo(&DNTI_OPERATION);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index 1119e10805d..f03078fc3db 100644
--- a/source/blender/depsgraph/intern/depsnode_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -28,15 +28,15 @@
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_OPERATION_H__
-#define __DEPSNODE_OPERATION_H__
+#pragma once
-#include "depsnode.h"
+#include "intern/nodes/deg_node.h"
struct ID;
struct Depsgraph;
-struct DepsgraphCopyContext;
+
+namespace DEG {
/* Flags for Depsgraph Nodes */
typedef enum eDepsOperation_Flag {
@@ -44,10 +44,14 @@ typedef enum eDepsOperation_Flag {
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* node was directly modified, causing need for update */
- /* XXX: intention is to make it easier to tell when we just need to take subgraphs */
+ /* XXX: intention is to make it easier to tell when we just need to
+ * take subgraphs.
+ */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
- /* Operation is evaluated using CPython; has GIL and security implications... */
+ /* Operation is evaluated using CPython; has GIL and security
+ * implications...
+ */
DEPSOP_FLAG_USES_PYTHON = (1 << 2),
} eDepsOperation_Flag;
@@ -68,23 +72,33 @@ struct OperationDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation() { return this; }
OperationDepsNode *get_exit_operation() { return this; }
- ComponentDepsNode *owner; /* component that contains the operation */
+ /* Component that contains the operation. */
+ ComponentDepsNode *owner;
- DepsEvalOperationCb evaluate; /* callback for operation */
+ /* Callback for operation. */
+ DepsEvalOperationCb evaluate;
- uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
+ /* How many inlinks are we still waiting on before we can be evaluated. */
+ uint32_t num_links_pending;
float eval_priority;
bool scheduled;
- short optype; /* (eDepsOperation_Type) stage of evaluation */
- int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
+ /* Stage of evaluation */
+ eDepsOperation_Type optype;
+
+ /* Identifier for the operation being performed. */
+ eDepsOperation_Code opcode;
+
+ /* (eDepsOperation_Flag) extra settings affecting evaluation. */
+ int flag;
- int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
+ /* Extra customdata mask which needs to be evaluated for the object. */
+ uint64_t customdata_mask;
DEG_DEPSNODE_DECLARE;
};
-void DEG_register_operation_depsnodes();
+void deg_register_operation_depsnodes();
-#endif /* __DEPSNODE_OPERATION_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h
new file mode 100644
index 00000000000..14cf4fc11ed
--- /dev/null
+++ b/source/blender/depsgraph/util/deg_util_foreach.h
@@ -0,0 +1,68 @@
+/*
+ * ***** 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) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/deg_util_foreach.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# define foreach(x, y) for(x : y)
+#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
+# include <boost/foreach.hpp>
+# define foreach BOOST_FOREACH
+#else
+#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph")
+
+#ifndef WITH_LEGACY_DEPSGRAPH
+# error "Unable to build new depsgraph and legacy one is disabled."
+#endif
+
+#define DISABLE_NEW_DEPSGRAPH
+
+# define foreach(x, y) for (x; false; (void)y)
+#endif
+
+#define GHASH_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GHashIterator gh_iter##var; \
+ GHASH_ITER(gh_iter##var, what) { \
+ type var = reinterpret_cast<type>(BLI_ghashIterator_getValue(&gh_iter##var)); \
+
+#define GHASH_FOREACH_END() \
+ } \
+ } while(0)
+
+#define GSET_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GSetIterator gh_iter##var; \
+ GSET_ITER(gh_iter##var, what) { \
+ type var = reinterpret_cast<type>(BLI_gsetIterator_getKey(&gh_iter##var)); \
+
+#define GSET_FOREACH_END() \
+ } \
+ } while(0)
diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/deg_util_function.h
index a4301833408..1e34ae04d9a 100644
--- a/source/blender/depsgraph/util/depsgraph_util_function.h
+++ b/source/blender/depsgraph/util/deg_util_function.h
@@ -24,12 +24,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_function.h
+/** \file blender/depsgraph/util/deg_util_function.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
-#define __DEPSGRAPH_UTIL_FUNCTION_H__
+#pragma once
#if (__cplusplus > 199711L)
@@ -57,6 +56,7 @@ using boost::function;
#define DISABLE_NEW_DEPSGRAPH
+#include "BLI_utildefines.h"
#include <cstdlib>
template<typename T>
@@ -108,5 +108,3 @@ void *function_bind(T func,
#define _4 Wrap()
#endif
-
-#endif /* __DEPSGRAPH_UTIL_FUNCTION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/deg_util_hash.h
index 008ec6b74ca..e490be1a7a1 100644
--- a/source/blender/depsgraph/util/depsgraph_util_set.h
+++ b/source/blender/depsgraph/util/deg_util_hash.h
@@ -24,43 +24,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_set.h
+/** \file blender/depsgraph/util/deg_util_hash.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_SET_H__
-#define __DEPSGRAPH_UTIL_SET_H__
+#pragma once
-#include <set>
+#include "BLI_utildefines.h"
-#include "depsgraph_util_hash.h"
+#include "BLI_ghash.h"
-using std::set;
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# include <set>
-typedef std::set unordered_set;
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_set>
-using std::tr1::unordered_set;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_set>
-using std::unordered_set;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_set>
-using std::tr1::unordered_set;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#endif /* __DEPSGRAPH_UTIL_SET_H__ */
+/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
+BLI_INLINE size_t hash_combine(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h
deleted file mode 100644
index bc75627a026..00000000000
--- a/source/blender/depsgraph/util/depsgraph_util_hash.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * ***** 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) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/util/depsgraph_util_hash.h
- * \ingroup depsgraph
- */
-
-#ifndef __DEPSGRAPH_UTIL_HASH_H__
-#define __DEPSGRAPH_UTIL_HASH_H__
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# define DEG_HASH_NAMESPACE_BEGIN
-# define DEG_HASH_NAMESPACE_END
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
-# define DEG_HASH_NAMESPACE_END } }
-using std::tr1::hash;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std {
-# define DEG_HASH_NAMESPACE_END }
-using std::hash;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
-# define DEG_HASH_NAMESPACE_END } }
-using std::tr1::hash;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
-inline size_t hash_combine(size_t hash_a, size_t hash_b)
-{
- return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
-}
-
-#endif /* __DEPSGRAPH_UTIL_HASH_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h
deleted file mode 100644
index 0eae1d79e34..00000000000
--- a/source/blender/depsgraph/util/depsgraph_util_map.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ***** 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) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/util/depsgraph_util_map.h
- * \ingroup depsgraph
- */
-
-#ifndef __DEPSGRAPH_UTIL_MAP_H__
-#define __DEPSGRAPH_UTIL_MAP_H__
-
-#include <map>
-
-#include "depsgraph_util_hash.h"
-
-using std::map;
-using std::pair;
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# include <map>
-typedef std::map unordered_map;
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-using std::tr1::unordered_map;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_map>
-using std::unordered_map;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-using std::tr1::unordered_map;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#endif /* __DEPSGRAPH_UTIL_MAP_H__ */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 5665ce59783..437dd2b2de2 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -399,7 +399,13 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ANIM_list_elem_update(ac->scene, ale);
}
}
-
+ else if (ale->datatype == ALE_NLASTRIP) {
+ if (ale->update & ANIM_UPDATE_DEPS) {
+ ale->update &= ~ANIM_UPDATE_DEPS;
+ ANIM_list_elem_update(ac->scene, ale);
+ }
+ }
+
BLI_assert(ale->update == 0);
}
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index afc4e5c9e61..51f962d4a1e 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -866,7 +866,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
}
/* Show menu or create drivers */
-static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
@@ -877,7 +877,8 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
else {
/* Show menu */
// TODO: This should get filtered by the enum filter
- return WM_menu_invoke(C, op, event);
+ /* important to execute in the region we're currently in */
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
}
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 6a19cf679be..172f2b9069e 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2024,17 +2024,25 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id)
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_ON(scene) == 0)
return false;
-
- if (IS_AUTOKEY_MODE(scene, NORMAL)) {
- /* can insert anytime we like... */
- return true;
- }
- else { /* REPLACE */
- /* for whole block - only key if there's a keyframe on that frame already
- * this is a valid assumption when we're blocking + tweaking
+
+ if (IS_AUTOKEY_MODE(scene, EDITKEYS)) {
+ /* Replace Mode:
+ * For whole block, only key if there's a keyframe on that frame already
+ * This is a valid assumption when we're blocking + tweaking
*/
return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL);
}
+ else {
+ /* Normal Mode (or treat as being normal mode):
+ *
+ * Just in case the flags are't set properly (i.e. only on/off is set, without a mode)
+ * let's set the "normal" flag too, so that it will all be sane everywhere...
+ */
+ scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
+
+ /* Can insert anytime we like... */
+ return true;
+ }
}
/* ******************************************* */
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index d73536e5ba7..6306926e0b2 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -367,6 +367,8 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->tail[2] = ebo->tail[2];
eboflip->rad_tail = ebo->rad_tail;
eboflip->roll = -ebo->roll;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll2 = -ebo->roll2;
/* Also move connected children, in case children's name aren't mirrored properly */
for (children = arm->edbo->first; children; children = children->next) {
@@ -382,6 +384,8 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->head[2] = ebo->head[2];
eboflip->rad_head = ebo->rad_head;
eboflip->roll = -ebo->roll;
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->roll1 = -ebo->roll1;
/* Also move connected parent, in case parent's name isn't mirrored properly */
if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
@@ -395,6 +399,11 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->roll = -ebo->roll;
eboflip->xwidth = ebo->xwidth;
eboflip->zwidth = ebo->zwidth;
+
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll1 = -ebo->roll1;
+ eboflip->roll2 = -ebo->roll2;
}
}
}
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 9e49d7e7e90..d4d3e1af1fd 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -2327,6 +2327,12 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
RNA_property_float_get_array(ptr, prop, rgba);
+ /* when the softmax isn't defined in the RNA,
+ * using very large numbers causes sRGB/linear round trip to fail. */
+ if (softmax == FLT_MAX) {
+ softmax = 1.0f;
+ }
+
switch (U.color_picker_type) {
case USER_CP_SQUARE_SV:
ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
@@ -2418,7 +2424,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
- bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
+ bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
bt->custom_data = cpicker;
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index d4c976fb544..acb8e8e7512 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -94,6 +94,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int triangulate;
int use_object_instantiation;
+ int use_blender_profile;
int sort_by_name;
int export_transformation_type;
int open_sim;
@@ -142,6 +143,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate = RNA_boolean_get(op->ptr, "triangulate");
use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
+ use_blender_profile = RNA_boolean_get(op->ptr, "use_blender_profile");
sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
open_sim = RNA_boolean_get(op->ptr, "open_sim");
@@ -167,6 +169,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate,
use_object_instantiation,
+ use_blender_profile,
sort_by_name,
export_transformation_type,
open_sim);
@@ -256,6 +259,8 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "use_blender_profile", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
@@ -349,7 +354,10 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Export Polygons (Quads & NGons) as Triangles");
RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
- "Instantiate multiple Objects from same Data");
+ "Instantiate multiple Objects from same Data");
+
+ RNA_def_boolean(ot->srna, "use_blender_profile", 1, "Use Blender Profile",
+ "Export additional Blender specific information (for material, shaders, bones, etc.)");
RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 0280f662a26..8783367ef7e 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
editmesh_rip_edge.c
editmesh_select.c
editmesh_tools.c
+ editmesh_undo.c
editmesh_utils.c
mesh_data.c
mesh_ops.c
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
new file mode 100644
index 00000000000..b9d3fd6c8be
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -0,0 +1,726 @@
+/*
+ * ***** 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_undo.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_context.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+
+#include "ED_mesh.h"
+#include "ED_util.h"
+
+#define USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE
+// # define DEBUG_PRINT
+// # define DEBUG_TIME
+# ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+# endif
+
+# include "BLI_array_store.h"
+# include "BLI_math_base.h"
+ /* check on best size later... */
+# define ARRAY_CHUNK_SIZE 256
+
+# define USE_ARRAY_STORE_THREAD
+#endif
+
+#ifdef USE_ARRAY_STORE_THREAD
+# include "BLI_task.h"
+#endif
+
+
+#ifdef USE_ARRAY_STORE
+
+/* Single linked list of layers stored per type */
+typedef struct BArrayCustomData {
+ struct BArrayCustomData *next;
+ CustomDataType type;
+ int states_len; /* number of layers for each type */
+ BArrayState *states[0];
+} BArrayCustomData;
+
+#endif
+
+typedef struct UndoMesh {
+ Mesh me;
+ int selectmode;
+
+ /** \note
+ * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
+ * but editing shape keys, going into object mode, removing or changing their order,
+ * then go back into editmode and undo will give issues - where the old index will be out of sync
+ * with the new object index.
+ *
+ * There are a few ways this could be made to work but for now its a known limitation with mixing
+ * object and editmode operations - Campbell */
+ int shapenr;
+
+#ifdef USE_ARRAY_STORE
+ /* NULL arrays are considered empty */
+ struct {
+ /* most data is stored as 'custom' data */
+ BArrayCustomData *vdata, *edata, *ldata, *pdata;
+ BArrayState **keyblocks;
+ BArrayState *mselect;
+ } store;
+#endif /* USE_ARRAY_STORE */
+} UndoMesh;
+
+
+#ifdef USE_ARRAY_STORE
+
+/** \name Array Store
+ * \{ */
+
+static struct {
+ BArrayStore **bs_all;
+ int bs_all_len;
+ int users;
+
+ /* We could have the undo API pass in the previous state, for now store a local list */
+ ListBase local_links;
+
+#ifdef USE_ARRAY_STORE_THREAD
+ TaskPool *task_pool;
+#endif
+
+} um_arraystore = {NULL};
+
+static BArrayStore *array_store_at_size_ensure(const int stride)
+{
+ if (um_arraystore.bs_all_len < stride) {
+ um_arraystore.bs_all_len = stride;
+ um_arraystore.bs_all = MEM_recallocN(um_arraystore.bs_all, sizeof(*um_arraystore.bs_all) * stride);
+ }
+ BArrayStore **bs_p = &um_arraystore.bs_all[stride - 1];
+
+ if ((*bs_p) == NULL) {
+#if 0
+ unsigned int chunk_count = ARRAY_CHUNK_SIZE;
+#else
+ /* calculate best chunk-count to fit a power of two */
+ unsigned int chunk_count = ARRAY_CHUNK_SIZE;
+ {
+ unsigned int size = chunk_count * stride;
+ size = power_of_2_max_u(size);
+ size = MEM_SIZE_OPTIMAL(size);
+ chunk_count = size / stride;
+ }
+#endif
+
+ (*bs_p) = BLI_array_store_create(stride, chunk_count);
+ }
+ return *bs_p;
+}
+
+static BArrayStore *array_store_at_size_get(const int stride)
+{
+ BLI_assert(stride > 0 && stride <= um_arraystore.bs_all_len);
+ return um_arraystore.bs_all[stride - 1];
+}
+
+#ifdef DEBUG_PRINT
+static void um_arraystore_memory_usage(size_t *r_size_expanded, size_t *r_size_compacted)
+{
+ size_t size_compacted = 0;
+ size_t size_expanded = 0;
+ for (int i = 0; i < um_arraystore.bs_all_len; i++) {
+ BArrayStore *bs = um_arraystore.bs_all[i];
+ if (bs) {
+ size_compacted += BLI_array_store_calc_size_compacted_get(bs);
+ size_expanded += BLI_array_store_calc_size_expanded_get(bs);
+ }
+ }
+
+ *r_size_expanded = size_expanded;
+ *r_size_compacted = size_compacted;
+}
+#endif
+
+static void um_arraystore_cd_compact(
+ struct CustomData *cdata, const size_t data_len,
+ bool create,
+ const BArrayCustomData *bcd_reference,
+ BArrayCustomData **r_bcd_first)
+{
+ if (data_len == 0) {
+ if (create) {
+ *r_bcd_first = NULL;
+ }
+ }
+
+ const BArrayCustomData *bcd_reference_current = bcd_reference;
+ BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL;
+ for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) {
+ const CustomDataType type = cdata->layers[layer_start].type;
+
+ layer_end = layer_start + 1;
+ while ((layer_end < cdata->totlayer) &&
+ (type == cdata->layers[layer_end].type))
+ {
+ layer_end++;
+ }
+
+ const int stride = CustomData_sizeof(type);
+ BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ const int layer_len = layer_end - layer_start;
+
+ if (create) {
+ if (bcd_reference_current && (bcd_reference_current->type == type)) {
+ /* common case, the reference is aligned */
+ }
+ else {
+ bcd_reference_current = NULL;
+
+ /* do a full lookup when un-alligned */
+ if (bcd_reference) {
+ const BArrayCustomData *bcd_iter = bcd_reference;
+ while (bcd_iter) {
+ if (bcd_iter->type == type) {
+ bcd_reference_current = bcd_iter;
+ break;
+ }
+ bcd_iter = bcd_iter->next;
+ }
+ }
+ }
+ }
+
+ if (create) {
+ bcd = MEM_callocN(sizeof(BArrayCustomData) + (layer_len * sizeof(BArrayState *)), __func__);
+ bcd->next = NULL;
+ bcd->type = type;
+ bcd->states_len = layer_end - layer_start;
+
+ if (bcd_prev) {
+ bcd_prev->next = bcd;
+ bcd_prev = bcd;
+ }
+ else {
+ bcd_first = bcd;
+ bcd_prev = bcd;
+ }
+ }
+
+ CustomDataLayer *layer = &cdata->layers[layer_start];
+ for (int i = 0; i < layer_len; i++, layer++) {
+ if (create) {
+ if (layer->data) {
+ BArrayState *state_reference =
+ (bcd_reference_current && i < bcd_reference_current->states_len) ?
+ bcd_reference_current->states[i] : NULL;
+ bcd->states[i] = BLI_array_store_state_add(
+ bs, layer->data, (size_t)data_len * stride, state_reference);
+ }
+ else {
+ bcd->states[i] = NULL;
+ }
+ }
+
+ if (layer->data) {
+ MEM_freeN(layer->data);
+ layer->data = NULL;
+ }
+ }
+
+ if (create) {
+ if (bcd_reference_current) {
+ bcd_reference_current = bcd_reference_current->next;
+ }
+ }
+ }
+
+ if (create) {
+ *r_bcd_first = bcd_first;
+ }
+}
+
+/**
+ * \note There is no room for data going out of sync here.
+ * The layers and the states are stored together so this can be kept working.
+ */
+static void um_arraystore_cd_expand(
+ const BArrayCustomData *bcd, struct CustomData *cdata, const size_t data_len)
+{
+ CustomDataLayer *layer = cdata->layers;
+ while (bcd) {
+ const int stride = CustomData_sizeof(bcd->type);
+ for (int i = 0; i < bcd->states_len; i++) {
+ BLI_assert(bcd->type == layer->type);
+ if (bcd->states[i]) {
+ size_t state_len;
+ layer->data = BLI_array_store_state_data_get_alloc(bcd->states[i], &state_len);
+ BLI_assert(stride * data_len == state_len);
+ UNUSED_VARS_NDEBUG(stride, data_len);
+ }
+ else {
+ layer->data = NULL;
+ }
+ layer++;
+ }
+ bcd = bcd->next;
+ }
+}
+
+static void um_arraystore_cd_free(BArrayCustomData *bcd)
+{
+ while (bcd) {
+ BArrayCustomData *bcd_next = bcd->next;
+ const int stride = CustomData_sizeof(bcd->type);
+ BArrayStore *bs = array_store_at_size_get(stride);
+ for (int i = 0; i < bcd->states_len; i++) {
+ if (bcd->states[i]) {
+ BLI_array_store_state_remove(bs, bcd->states[i]);
+ }
+ }
+ MEM_freeN(bcd);
+ bcd = bcd_next;
+ }
+}
+
+/**
+ * \param create: When false, only free the arrays.
+ * This is done since when reading from an undo state, they must be temporarily expanded.
+ * then discarded afterwards, having this argument avoids having 2x code paths.
+ */
+static void um_arraystore_compact_ex(
+ UndoMesh *um, const UndoMesh *um_ref,
+ bool create)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_compact(&me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : NULL, &um->store.vdata);
+ um_arraystore_cd_compact(&me->edata, me->totedge, create, um_ref ? um_ref->store.edata : NULL, &um->store.edata);
+ um_arraystore_cd_compact(&me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : NULL, &um->store.ldata);
+ um_arraystore_cd_compact(&me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : NULL, &um->store.pdata);
+
+ if (me->key && me->key->totkey) {
+ const size_t stride = me->key->elemsize;
+ BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ if (create) {
+ um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__);
+ }
+ KeyBlock *keyblock = me->key->block.first;
+ for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) {
+ if (create) {
+ BArrayState *state_reference =
+ (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ?
+ um_ref->store.keyblocks[i] : NULL;
+ um->store.keyblocks[i] = BLI_array_store_state_add(
+ bs, keyblock->data, (size_t)keyblock->totelem * stride,
+ state_reference);
+ }
+
+ if (keyblock->data) {
+ MEM_freeN(keyblock->data);
+ keyblock->data = NULL;
+ }
+ }
+ }
+
+ if (me->mselect && me->totselect) {
+ BLI_assert(create == (um->store.mselect == NULL));
+ if (create) {
+ BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL;
+ const size_t stride = sizeof(*me->mselect);
+ BArrayStore *bs = array_store_at_size_ensure(stride);
+ um->store.mselect = BLI_array_store_state_add(
+ bs, me->mselect, (size_t)me->totselect * stride, state_reference);
+ }
+
+ /* keep me->totselect for validation */
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+
+ if (create) {
+ um_arraystore.users += 1;
+ }
+
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
+/**
+ * Move data from allocated arrays to de-duplicated states and clear arrays.
+ */
+static void um_arraystore_compact(UndoMesh *um, const UndoMesh *um_ref)
+{
+ um_arraystore_compact_ex(um, um_ref, true);
+}
+
+static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref)
+{
+#ifdef DEBUG_PRINT
+ size_t size_expanded_prev, size_compacted_prev;
+ um_arraystore_memory_usage(&size_expanded_prev, &size_compacted_prev);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(mesh_undo_compact);
+#endif
+
+ um_arraystore_compact(um, um_ref);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(mesh_undo_compact);
+#endif
+
+#ifdef DEBUG_PRINT
+ {
+ size_t size_expanded, size_compacted;
+ um_arraystore_memory_usage(&size_expanded, &size_compacted);
+
+ const double percent_total = size_expanded ?
+ (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
+
+ size_t size_expanded_step = size_expanded - size_expanded_prev;
+ size_t size_compacted_step = size_compacted - size_compacted_prev;
+ const double percent_step = size_expanded_step ?
+ (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0;
+
+ printf("overall memory use: %.8f%% of expanded size\n", percent_total);
+ printf("step memory use: %.8f%% of expanded size\n", percent_step);
+ }
+#endif
+}
+
+#ifdef USE_ARRAY_STORE_THREAD
+
+struct UMArrayData {
+ UndoMesh *um;
+ const UndoMesh *um_ref; /* can be NULL */
+};
+static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct UMArrayData *um_data = taskdata;
+ um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
+}
+
+#endif /* USE_ARRAY_STORE_THREAD */
+
+/**
+ * Remove data we only expanded for temporary use.
+ */
+static void um_arraystore_expand_clear(UndoMesh *um)
+{
+ um_arraystore_compact_ex(um, NULL, false);
+}
+
+static void um_arraystore_expand(UndoMesh *um)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_expand(um->store.vdata, &me->vdata, me->totvert);
+ um_arraystore_cd_expand(um->store.edata, &me->edata, me->totedge);
+ um_arraystore_cd_expand(um->store.ldata, &me->ldata, me->totloop);
+ um_arraystore_cd_expand(um->store.pdata, &me->pdata, me->totpoly);
+
+ if (um->store.keyblocks) {
+ const size_t stride = me->key->elemsize;
+ KeyBlock *keyblock = me->key->block.first;
+ for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) {
+ BArrayState *state = um->store.keyblocks[i];
+ size_t state_len;
+ keyblock->data = BLI_array_store_state_data_get_alloc(state, &state_len);
+ BLI_assert(keyblock->totelem == (state_len / stride));
+ UNUSED_VARS_NDEBUG(stride);
+ }
+ }
+
+ if (um->store.mselect) {
+ const size_t stride = sizeof(*me->mselect);
+ BArrayState *state = um->store.mselect;
+ size_t state_len;
+ me->mselect = BLI_array_store_state_data_get_alloc(state, &state_len);
+ BLI_assert(me->totselect == (state_len / stride));
+ UNUSED_VARS_NDEBUG(stride);
+ }
+
+ /* not essential, but prevents accidental dangling pointer access */
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
+static void um_arraystore_free(UndoMesh *um)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_free(um->store.vdata);
+ um_arraystore_cd_free(um->store.edata);
+ um_arraystore_cd_free(um->store.ldata);
+ um_arraystore_cd_free(um->store.pdata);
+
+ if (um->store.keyblocks) {
+ const size_t stride = me->key->elemsize;
+ BArrayStore *bs = array_store_at_size_get(stride);
+ for (int i = 0; i < me->key->totkey; i++) {
+ BArrayState *state = um->store.keyblocks[i];
+ BLI_array_store_state_remove(bs, state);
+ }
+ MEM_freeN(um->store.keyblocks);
+ um->store.keyblocks = NULL;
+ }
+
+ if (um->store.mselect) {
+ const size_t stride = sizeof(*me->mselect);
+ BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayState *state = um->store.mselect;
+ BLI_array_store_state_remove(bs, state);
+ um->store.mselect = NULL;
+ }
+
+ um_arraystore.users -= 1;
+
+ BLI_assert(um_arraystore.users >= 0);
+
+ if (um_arraystore.users == 0) {
+#ifdef DEBUG_PRINT
+ printf("mesh undo store: freeing all data!\n");
+#endif
+ for (int i = 0; i < um_arraystore.bs_all_len; i += 1) {
+ if (um_arraystore.bs_all[i]) {
+ BLI_array_store_destroy(um_arraystore.bs_all[i]);
+ }
+ }
+
+ MEM_freeN(um_arraystore.bs_all);
+ um_arraystore.bs_all = NULL;
+ um_arraystore.bs_all_len = 0;
+
+#ifdef USE_ARRAY_STORE_THREAD
+ BLI_task_pool_free(um_arraystore.task_pool);
+ um_arraystore.task_pool = NULL;
+#endif
+ }
+
+}
+
+/** \} */
+
+#endif /* USE_ARRAY_STORE */
+
+
+/* for callbacks */
+/* undo simply makes copies of a bmesh */
+static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+{
+
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ if (um_arraystore.task_pool) {
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+ }
+#endif
+
+ BMEditMesh *em = emv;
+ Mesh *obme = obdata;
+
+ UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
+
+ /* make sure shape keys work */
+ um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
+
+ /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
+
+ BM_mesh_bm_to_me(
+ em->bm, &um->me, (&(struct BMeshToMeshParams){
+ .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
+ }));
+
+ um->selectmode = em->selectmode;
+ um->shapenr = em->bm->shapenr;
+
+#ifdef USE_ARRAY_STORE
+ {
+ /* We could be more clever here,
+ * the previous undo state may be from a separate mesh. */
+ const UndoMesh *um_ref = um_arraystore.local_links.last ?
+ ((LinkData *)um_arraystore.local_links.last)->data : NULL;
+
+ /* add oursrlves */
+ BLI_addtail(&um_arraystore.local_links, BLI_genericNodeN(um));
+
+#ifdef USE_ARRAY_STORE_THREAD
+ if (um_arraystore.task_pool == NULL) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL);
+ }
+
+ struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
+ um_data->um = um;
+ um_data->um_ref = um_ref;
+
+ BLI_task_pool_push(
+ um_arraystore.task_pool,
+ um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW);
+#else
+ um_arraystore_compact_with_info(um, um_ref);
+#endif
+ }
+#endif
+
+ return um;
+}
+
+static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
+{
+ BMEditMesh *em = em_v, *em_tmp;
+ Object *ob = em->ob;
+ UndoMesh *um = um_v;
+ BMesh *bm;
+ Key *key = ((Mesh *) obdata)->key;
+
+#ifdef USE_ARRAY_STORE
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(mesh_undo_expand);
+#endif
+
+ um_arraystore_expand(um);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(mesh_undo_expand);
+#endif
+#endif /* USE_ARRAY_STORE */
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
+
+ em->bm->shapenr = um->shapenr;
+
+ EDBM_mesh_free(em);
+
+ bm = BM_mesh_create(&allocsize);
+
+ BM_mesh_bm_from_me(
+ bm, &um->me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true, .active_shapekey = um->shapenr,
+ }));
+
+ em_tmp = BKE_editmesh_create(bm, true);
+ *em = *em_tmp;
+
+ em->selectmode = um->selectmode;
+ bm->selectmode = um->selectmode;
+ em->ob = ob;
+
+ /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
+ * if the active is a basis for any other. */
+ if (key && (key->type == KEY_RELATIVE)) {
+ /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
+ * shapenr from restored bmesh and keyblock indices are in sync. */
+ const int kb_act_idx = ob->shapenr - 1;
+
+ /* If it is, let's patch the current mesh key block to its restored value.
+ * Else, the offsets won't be computed and it won't matter. */
+ if (BKE_keyblock_is_basis(key, kb_act_idx)) {
+ KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
+
+ if (kb_act->totelem != um->me.totvert) {
+ /* The current mesh has some extra/missing verts compared to the undo, adjust. */
+ MEM_SAFE_FREE(kb_act->data);
+ kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
+ kb_act->totelem = um->me.totvert;
+ }
+
+ BKE_keyblock_update_from_mesh(&um->me, kb_act);
+ }
+ }
+
+ ob->shapenr = um->shapenr;
+
+ MEM_freeN(em_tmp);
+
+#ifdef USE_ARRAY_STORE
+ um_arraystore_expand_clear(um);
+#endif
+}
+
+static void free_undo(void *um_v)
+{
+ UndoMesh *um = um_v;
+ Mesh *me = &um->me;
+
+#ifdef USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+#endif
+
+ /* we need to expand so any allocations in custom-data are freed with the mesh */
+ um_arraystore_expand(um);
+
+ {
+ LinkData *link = BLI_findptr(&um_arraystore.local_links, um, offsetof(LinkData, data));
+ BLI_remlink(&um_arraystore.local_links, link);
+ MEM_freeN(link);
+ }
+ um_arraystore_free(um);
+#endif
+
+ if (me->key) {
+ BKE_key_free(me->key);
+ MEM_freeN(me->key);
+ }
+
+ BKE_mesh_free(me, false);
+ MEM_freeN(me);
+}
+
+static void *getEditMesh(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_MESH) {
+ Mesh *me = obedit->data;
+ return me->edit_btmesh;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(bContext *C, const char *name)
+{
+ /* em->ob gets out of date and crashes on mesh undo,
+ * this is an easy way to ensure its OK
+ * though we could investigate the matter further. */
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ em->ob = obedit;
+
+ undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 82ec93c162f..99be37845ee 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -45,7 +45,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_depsgraph.h"
-#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -60,7 +59,6 @@
#include "ED_mesh.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "mesh_intern.h" /* own include */
@@ -491,140 +489,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
}
-/**************-------------- Undo ------------*****************/
-
-/* for callbacks */
-
-static void *getEditMesh(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_MESH) {
- Mesh *me = obedit->data;
- return me->edit_btmesh;
- }
- return NULL;
-}
-
-typedef struct UndoMesh {
- Mesh me;
- int selectmode;
-
- /** \note
- * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
- * but editing shape keys, going into object mode, removing or changing their order,
- * then go back into editmode and undo will give issues - where the old index will be out of sync
- * with the new object index.
- *
- * There are a few ways this could be made to work but for now its a known limitation with mixing
- * object and editmode operations - Campbell */
- int shapenr;
-} UndoMesh;
-
-/* undo simply makes copies of a bmesh */
-static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
-{
- BMEditMesh *em = emv;
- Mesh *obme = obdata;
-
- UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
-
- /* make sure shape keys work */
- um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
-
- /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
-
- BM_mesh_bm_to_me(
- em->bm, &um->me, (&(struct BMeshToMeshParams){
- .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
- }));
-
- um->selectmode = em->selectmode;
- um->shapenr = em->bm->shapenr;
-
- return um;
-}
-
-static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
-{
- BMEditMesh *em = em_v, *em_tmp;
- Object *ob = em->ob;
- UndoMesh *um = umv;
- BMesh *bm;
- Key *key = ((Mesh *) obdata)->key;
-
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
-
- em->bm->shapenr = um->shapenr;
-
- EDBM_mesh_free(em);
-
- bm = BM_mesh_create(&allocsize);
-
- BM_mesh_bm_from_me(
- bm, &um->me, (&(struct BMeshFromMeshParams){
- .calc_face_normal = true, .active_shapekey = um->shapenr,
- }));
-
- em_tmp = BKE_editmesh_create(bm, true);
- *em = *em_tmp;
-
- em->selectmode = um->selectmode;
- bm->selectmode = um->selectmode;
- em->ob = ob;
-
- /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
- * if the active is a basis for any other. */
- if (key && (key->type == KEY_RELATIVE)) {
- /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
- * shapenr from restored bmesh and keyblock indices are in sync. */
- const int kb_act_idx = ob->shapenr - 1;
-
- /* If it is, let's patch the current mesh key block to its restored value.
- * Else, the offsets won't be computed and it won't matter. */
- if (BKE_keyblock_is_basis(key, kb_act_idx)) {
- KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
-
- if (kb_act->totelem != um->me.totvert) {
- /* The current mesh has some extra/missing verts compared to the undo, adjust. */
- MEM_SAFE_FREE(kb_act->data);
- kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
- kb_act->totelem = um->me.totvert;
- }
-
- BKE_keyblock_update_from_mesh(&um->me, kb_act);
- }
- }
-
- ob->shapenr = um->shapenr;
-
- MEM_freeN(em_tmp);
-}
-
-static void free_undo(void *me_v)
-{
- Mesh *me = me_v;
- if (me->key) {
- BKE_key_free(me->key);
- MEM_freeN(me->key);
- }
-
- BKE_mesh_free(me, false);
- MEM_freeN(me);
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, const char *name)
-{
- /* em->ob gets out of date and crashes on mesh undo,
- * this is an easy way to ensure its OK
- * though we could investigate the matter further. */
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- em->ob = obedit;
-
- undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
-}
-
/**
* Return a new UVVertMap from the editmesh
*/
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index b6c026ebd37..20e159f4f51 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2863,7 +2863,7 @@ static void initBend(TransInfo *t)
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
- calculateCenterGlobal(t);
+ calculateCenterGlobal(t, t->center, t->center_global);
t->val = 0.0f;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index f4d93389776..4e8aa0cc20b 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -369,6 +369,11 @@ typedef struct TransCustomData {
unsigned int use_free : 1;
} TransCustomData;
+typedef struct TransCenterData {
+ float local[3], global[3];
+ unsigned int is_set : 1;
+} TransCenterData;
+
typedef struct TransInfo {
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
@@ -396,6 +401,9 @@ typedef struct TransInfo {
float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
+ /* Lazy initialize center data for when we need other center values.
+ * V3D_AROUND_ACTIVE + 1 (static assert checks this) */
+ TransCenterData center_cache[5];
short idx_max; /* maximum index on the input vector */
float snap[3]; /* Snapping Gears */
float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */
@@ -741,8 +749,11 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
-void calculateCenterGlobal(TransInfo *t);
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3]);
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around);
void calculateCenter(TransInfo *t);
/* API functions for getting center points */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 28202f21c0e..78cebbf2c6e 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1601,16 +1601,18 @@ void calculateCenter2D(TransInfo *t)
}
}
-void calculateCenterGlobal(TransInfo *t)
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3])
{
/* setting constraint center */
/* note, init functions may over-ride t->center */
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(t->center_global, ob->obmat, t->center);
+ mul_v3_m4v3(r_center_global, ob->obmat, center_local);
}
else {
- copy_v3_v3(t->center_global, t->center);
+ copy_v3_v3(r_center_global, center_local);
}
}
@@ -1785,43 +1787,55 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
return ok;
}
-
-void calculateCenter(TransInfo *t)
+static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
{
- switch (t->around) {
+ switch (around) {
case V3D_AROUND_CENTER_BOUNDS:
- calculateCenterBound(t, t->center);
+ calculateCenterBound(t, r_center);
break;
case V3D_AROUND_CENTER_MEAN:
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_CURSOR:
if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
- calculateCenterCursor2D(t, t->center);
+ calculateCenterCursor2D(t, r_center);
else if (t->spacetype == SPACE_IPO)
- calculateCenterCursorGraph2D(t, t->center);
+ calculateCenterCursorGraph2D(t, r_center);
else
- calculateCenterCursor(t, t->center);
+ calculateCenterCursor(t, r_center);
break;
case V3D_AROUND_LOCAL_ORIGINS:
/* Individual element center uses median center for helpline and such */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_ACTIVE:
{
- if (calculateCenterActive(t, false, t->center)) {
+ if (calculateCenterActive(t, false, r_center)) {
/* pass */
}
else {
/* fallback */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
}
break;
}
}
+}
+
+void calculateCenter(TransInfo *t)
+{
+ calculateCenter_FromAround(t, t->around, t->center);
+ calculateCenterGlobal(t, t->center, t->center_global);
+
+ /* avoid calculating again */
+ {
+ TransCenterData *cd = &t->center_cache[t->around];
+ copy_v3_v3(cd->local, t->center);
+ copy_v3_v3(cd->global, t->center_global);
+ cd->is_set = true;
+ }
calculateCenter2D(t);
- calculateCenterGlobal(t);
/* for panning from cameraview */
if (t->flag & T_OBJECT) {
@@ -1875,6 +1889,23 @@ void calculateCenter(TransInfo *t)
}
}
+BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size");
+
+/**
+ * Lazy initialize transform center data, when we need to access center values from other types.
+ */
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
+{
+ BLI_assert(around <= V3D_AROUND_ACTIVE);
+ TransCenterData *cd = &t->center_cache[around];
+ if (cd->is_set == false) {
+ calculateCenter_FromAround(t, around, cd->local);
+ calculateCenterGlobal(t, cd->local, cd->global);
+ cd->is_set = true;
+ }
+ return cd;
+}
+
void calculatePropRatio(TransInfo *t)
{
TransData *td = t->data;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 1bb8b768981..cb981bc4771 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1512,11 +1512,21 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
/* absolute snapping on grid based on global center */
if ((t->tsnap.snap_spatial_grid) && (t->mode == TFM_TRANSLATION)) {
+ const float *center_global = t->center_global;
+
+ /* use a fallback for cursor selection,
+ * this isn't useful as a global center for absolute grid snapping
+ * since its not based on the position of the selection. */
+ if (t->around == V3D_AROUND_CURSOR) {
+ const TransCenterData *cd = transformCenter_from_type(t, V3D_AROUND_CENTER_MEAN);
+ center_global = cd->global;
+ }
+
for (i = 0; i <= max_index; i++) {
/* do not let unconstrained axis jump to absolute grid increments */
if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) {
const float iter_fac = fac[action] * asp[i];
- val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i];
+ val[i] = iter_fac * roundf((val[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
}
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index a8656c05224..ee7abe08aba 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -147,6 +147,7 @@ typedef struct GPUVertPointLink {
/* used for GLSL materials */
typedef struct GPUAttrib {
int index;
+ int info_index;
int size;
int type;
} GPUAttrib;
@@ -179,6 +180,10 @@ typedef enum {
GPU_BINDING_INDEX = 1,
} GPUBindingType;
+typedef enum {
+ GPU_ATTR_INFO_SRGB = (1 << 0),
+} GPUAttrInfo;
+
/* called before drawing */
void GPU_vertex_setup(struct DerivedMesh *dm);
void GPU_normal_setup(struct DerivedMesh *dm);
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 4c674b460aa..762329ee077 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -104,6 +104,7 @@ typedef struct GPUVertexAttribs {
struct {
int type;
int glindex;
+ int glinfoindoex;
int gltexco;
int attribid;
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 6ff4a60610b..bd7a3b628c8 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -822,6 +822,12 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
for (i = 0; i < numdata; i++) {
glEnableVertexAttribArray(data[i].index);
+ int info = 0;
+ if (data[i].type == GL_UNSIGNED_BYTE) {
+ info |= GPU_ATTR_INFO_SRGB;
+ }
+ glUniform1i(data[i].info_index, info);
+
glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
GL_TRUE, elementsize, BUFFER_OFFSET(offset));
offset += data[i].size * GPU_typesize(data[i].type);
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index be5a0ab4173..9f41253b176 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -741,6 +741,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "%s %s att%d;\n",
GLEW_VERSION_3_0 ? "in" : "attribute",
GPU_DATATYPE_STR[input->type], input->attribid);
+ BLI_dynstr_appendf(ds, "uniform int att%d_info;\n", input->attribid);
BLI_dynstr_appendf(ds, "%s %s var%d;\n",
GLEW_VERSION_3_0 ? "out" : "varying",
GPU_DATATYPE_STR[input->type], input->attribid);
@@ -793,7 +794,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
- BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
+ BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n",
+ input->attribid, input->attribid, input->attribid);
#ifdef WITH_OPENSUBDIV
if (is_mtface) {
BLI_dynstr_appendf(ds, "#endif\n");
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index c15e49a8ed1..a6d120b8943 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -575,7 +575,7 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
glFramebufferTexture2DEXT(
GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
- status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
goto finally;
}
@@ -583,11 +583,11 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
/* write into new single-sample buffer */
glGenFramebuffersEXT(1, &fbo_blit);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
glFramebufferTexture2DEXT(
- GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
+ GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, tex_blit, 0);
- status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
goto finally;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 2bded95a1b5..b2e479043d2 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -207,6 +207,9 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
+ BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid);
+ attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name);
+
if (attribs->layer[a].glindex >= 0) {
attribs->layer[b] = attribs->layer[a];
b++;
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
index 2f501dfab05..ad4182340d6 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -91,7 +91,7 @@ void main()
discard;
}
else if (stipple_id == STIPPLE_CHECKER_8PX) {
- int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y) / 8, 2));
+ int result = int(mod(int(gl_FragCoord.x) / 8 + int(gl_FragCoord.y) / 8, 2));
if (result != 0)
discard;
}
@@ -165,7 +165,7 @@ void main()
/* diffuse light */
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf;
+ L_diffuse += light_diffuse * diffuse_bsdf;
#ifndef NO_SPECULAR
/* specular light */
@@ -173,7 +173,7 @@ void main()
vec3 H = gl_LightSource[i].halfVector.xyz;
float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf;
+ L_specular += light_specular * specular_bsdf;
#endif
}
#else
@@ -181,7 +181,7 @@ void main()
#ifndef NO_SPECULAR
/* view vector computation, depends on orthographics or perspective */
- vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position): vec3(0.0, 0.0, -1.0);
+ vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0);
#endif
for (int i = 0; i < NUM_SCENE_LIGHTS; i++) {
@@ -212,14 +212,14 @@ void main()
float distance = length(d);
intensity /= gl_LightSource[i].constantAttenuation +
- gl_LightSource[i].linearAttenuation * distance +
- gl_LightSource[i].quadraticAttenuation * distance * distance;
+ gl_LightSource[i].linearAttenuation * distance +
+ gl_LightSource[i].quadraticAttenuation * distance * distance;
}
/* diffuse light */
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+ L_diffuse += light_diffuse * diffuse_bsdf * intensity;
#ifndef NO_SPECULAR
/* specular light */
@@ -227,7 +227,7 @@ void main()
vec3 H = normalize(light_direction - V);
float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf*intensity;
+ L_specular += light_specular * specular_bsdf * intensity;
#endif
}
#endif
@@ -257,7 +257,7 @@ void main()
vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
#ifndef NO_SPECULAR
- L += L_specular*gl_FrontMaterial.specular.rgb;
+ L += L_specular * gl_FrontMaterial.specular.rgb;
#endif
/* write out fragment color */
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
index 674dd534352..a88681a5fd3 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -1,6 +1,6 @@
/*
-* Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
-*/
+ * Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
+ */
#define PASSTHROUGH 0
@@ -24,72 +24,72 @@ uniform int stipple_factor;
void main(void)
{
- vec2 window_size = viewport.zw;
- vec4 start = gl_in[0].gl_Position;
- vec4 end = gl_in[1].gl_Position;
+ vec2 window_size = viewport.zw;
+ vec4 start = gl_in[0].gl_Position;
+ vec4 end = gl_in[1].gl_Position;
#if PASSTHROUGH
- gl_Position = start; EmitVertex();
- gl_Position = end; EmitVertex();
- EndPrimitive();
- return;
+ gl_Position = start; EmitVertex();
+ gl_Position = end; EmitVertex();
+ EndPrimitive();
+ return;
#endif
-/* t = 0 t = ~(len(end - start) + 2*line_width)
- * A-------------------------------------B
- * | | | |
- * | side | |
- * | | | |
- * |--axis--*start--------------*end-----|
- * | | | |
- * | | | |
- * | | | |
- * D-------------------------------------C
- */
-
- /* Clip the line before homogenization.
- * Compute line start and end distances to nearplane in clipspace
- * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
- */
- float t0 = start.z + start.w;
- float t1 = end.z + end.w;
- if (t0 < 0.0) {
- if (t1 < 0.0) {
- return;
- }
- start = mix(start, end, (0 - t0) / (t1 - t0));
- }
- if (t1 < 0.0) {
- end = mix(start, end, (0 - t0) / (t1 - t0));
- }
-
- /* Compute line axis and side vector in screen space */
- vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
- vec2 endInNDC = end.xy / end.w;
- vec2 lineInNDC = endInNDC - startInNDC;
- vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
-
- vec2 axisInScreen = normalize(lineInScreen);
- vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
- vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
- vec2 sideInNDC = sideInScreen / window_size;
- vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
- vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
-
- vec4 A = (start + (side - axis) * start.w);
- vec4 B = (end + (side + axis) * end.w);
- vec4 C = (end - (side - axis) * end.w);
- vec4 D = (start - (side + axis) * start.w);
-
- /* There is no relation between lines yet */
- /* TODO Pass here t0 to make continuous pattern. */
- t0 = 0;
- t1 = (length(lineInScreen) + 2*line_width)/ (2*line_width * stipple_factor);
-
- gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- EndPrimitive();
+ /* t = 0 t = ~(len(end - start) + 2*line_width)
+ * A-------------------------------------B
+ * | | | |
+ * | side | |
+ * | | | |
+ * |--axis--*start--------------*end-----|
+ * | | | |
+ * | | | |
+ * | | | |
+ * D-------------------------------------C
+ */
+
+ /* Clip the line before homogenization.
+ * Compute line start and end distances to nearplane in clipspace
+ * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
+ */
+ float t0 = start.z + start.w;
+ float t1 = end.z + end.w;
+ if (t0 < 0.0) {
+ if (t1 < 0.0) {
+ return;
+ }
+ start = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+ if (t1 < 0.0) {
+ end = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+
+ /* Compute line axis and side vector in screen space */
+ vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
+ vec2 endInNDC = end.xy / end.w;
+ vec2 lineInNDC = endInNDC - startInNDC;
+ vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
+
+ vec2 axisInScreen = normalize(lineInScreen);
+ vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
+ vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
+ vec2 sideInNDC = sideInScreen / window_size;
+ vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
+ vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
+
+ vec4 A = (start + (side - axis) * start.w);
+ vec4 B = (end + (side + axis) * end.w);
+ vec4 C = (end - (side - axis) * end.w);
+ vec4 D = (start - (side + axis) * start.w);
+
+ /* There is no relation between lines yet */
+ /* TODO Pass here t0 to make continuous pattern. */
+ t0 = 0;
+ t1 = (length(lineInScreen) + 2 * line_width) / (2 * line_width * stipple_factor);
+
+ gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ EndPrimitive();
}
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
index e9dab04de5d..338ef6d51a7 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
@@ -115,9 +115,9 @@ void second_pass()
color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
- color += texture2D(colorbuffer, uvcoordsvar.xy -invrendertargetdim) * 0.234375;
- color += texture2D(colorbuffer, uvcoordsvar.xy -2.5 * invrendertargetdim) * 0.09375;
- color += texture2D(colorbuffer, uvcoordsvar.xy -4.5 * invrendertargetdim) * 0.015625;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625;
gl_FragColor = color;
}
@@ -128,7 +128,7 @@ void third_pass()
{
vec4 color = texture2D(colorbuffer, uvcoordsvar.xy);
vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
- float coc = 2.0 * max(color_blurred.a, color.a); - color.a;
+ float coc = 2.0 * max(color_blurred.a, color.a); -color.a;
gl_FragColor = vec4(color.rgb, coc);
}
@@ -146,7 +146,7 @@ void fourth_pass()
vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
{
- float weight = 1.0/ 17.0;
+ float weight = 1.0 / 17.0;
vec4 result = weight * color;
weight *= 4.0;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
index 7657fbb71ab..182113367d3 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -103,7 +103,7 @@ void accumulate_pass(void) {
r = 1.0;
else
r = cos(M_PI / dof_params.w) /
- (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
+ (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
if (dot(particlecoord, particlecoord) > r * r)
discard;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
index a2ef990c4e8..63b57d5775c 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
@@ -38,8 +38,12 @@ void vert_dof_first_pass()
void vert_dof_fourth_pass()
{
vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
- uvcoordsvar = gl_MultiTexCoord0.xxyy + halfpixel * vec4(invrendertargetdim.x,
- invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y);
+ uvcoordsvar = gl_MultiTexCoord0.xxyy +
+ halfpixel *
+ vec4(invrendertargetdim.x,
+ invrendertargetdim.x,
+ invrendertargetdim.y,
+ invrendertargetdim.y);
gl_Position = gl_Vertex;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index c2cd927898e..054a2f795ee 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -77,7 +77,7 @@ float calculate_ssao_factor(float depth)
/* use minor bias here to avoid self shadowing */
if (f > 0.05 * len + 0.0001)
- factor += f * 1.0/(len * (1.0 + len * len * ssao_params.z));
+ factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 16fba0dd055..1663915549c 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -49,7 +49,7 @@ void emit_flat(int index, vec3 normal)
varposition = outpt.v.position.xyz;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
@@ -70,7 +70,7 @@ void emit_smooth(int index)
varposition = outpt.v.position.xyz;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index a63e7b8dbf0..9914c4bb362 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -3,7 +3,7 @@
float convert_rgba_to_float(vec4 color)
{
#ifdef USE_NEW_SHADING
- return color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+ return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
#else
return (color.r + color.g + color.b) / 3.0;
#endif
@@ -39,11 +39,11 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
cmax = max(rgb[0], max(rgb[1], rgb[2]));
cmin = min(rgb[0], min(rgb[1], rgb[2]));
- cdelta = cmax-cmin;
+ cdelta = cmax - cmin;
v = cmax;
- if (cmax!=0.0)
- s = cdelta/cmax;
+ if (cmax != 0.0)
+ s = cdelta / cmax;
else {
s = 0.0;
h = 0.0;
@@ -53,15 +53,15 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
h = 0.0;
}
else {
- c = (vec3(cmax, cmax, cmax) - rgb.xyz)/cdelta;
+ c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
- if (rgb.x==cmax) h = c[2] - c[1];
- else if (rgb.y==cmax) h = 2.0 + c[0] - c[2];
+ if (rgb.x == cmax) h = c[2] - c[1];
+ else if (rgb.y == cmax) h = 2.0 + c[0] - c[2];
else h = 4.0 + c[1] - c[0];
h /= 6.0;
- if (h<0.0)
+ if (h < 0.0)
h += 1.0;
}
@@ -77,21 +77,21 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
s = hsv[1];
v = hsv[2];
- if (s==0.0) {
+ if (s == 0.0) {
rgb = vec3(v, v, v);
}
else {
- if (h==1.0)
+ if (h == 1.0)
h = 0.0;
-
+
h *= 6.0;
i = floor(h);
f = h - i;
rgb = vec3(f, f, f);
- p = v*(1.0-s);
- q = v*(1.0-(s*f));
- t = v*(1.0-(s*(1.0-f)));
-
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
if (i == 0.0) rgb = vec3(v, t, p);
else if (i == 1.0) rgb = vec3(q, v, p);
else if (i == 2.0) rgb = vec3(p, v, t);
@@ -106,17 +106,17 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
float srgb_to_linearrgb(float c)
{
if (c < 0.04045)
- return (c < 0.0) ? 0.0: c * (1.0 / 12.92);
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
else
- return pow((c + 0.055)*(1.0/1.055), 2.4);
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
}
float linearrgb_to_srgb(float c)
{
if (c < 0.0031308)
- return (c < 0.0) ? 0.0: c * 12.92;
+ return (c < 0.0) ? 0.0 : c * 12.92;
else
- return 1.055 * pow(c, 1.0/2.4) - 0.055;
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
}
void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
@@ -168,7 +168,7 @@ void vcol_attribute(vec4 attvcol, out vec4 vcol)
void uv_attribute(vec2 attuv, out vec3 uv)
{
- uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0);
+ uv = vec3(attuv * 2.0 - vec2(1.0, 1.0), 0.0);
}
void geom(
@@ -177,15 +177,15 @@ void geom(
out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
{
local = co;
- view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(local): vec3(0.0, 0.0, -1.0);
- global = (viewinvmat*vec4(local, 1.0)).xyz;
+ view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
+ global = (viewinvmat * vec4(local, 1.0)).xyz;
orco = attorco;
uv_attribute(attuv, uv);
- normal = -normalize(nor); /* blender render normal is negated */
+ normal = -normalize(nor); /* blender render normal is negated */
vcol_attribute(attvcol, vcol);
srgb_to_linearrgb(vcol, vcol);
vcol_alpha = attvcol.a;
- frontback = (gl_FrontFacing)? 1.0: 0.0;
+ frontback = (gl_FrontFacing) ? 1.0 : 0.0;
}
void particle_info(
@@ -210,12 +210,48 @@ void vect_normalize(vec3 vin, out vec3 vout)
void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
- vout = (mat*vec4(vin, 0.0)).xyz;
+ vout = (mat * vec4(vin, 0.0)).xyz;
}
void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
- vout = (mat*vec4(vin, 1.0)).xyz;
+ vout = (mat * vec4(vin, 1.0)).xyz;
+}
+
+void point_texco_remap_square(vec3 vin, out vec3 vout)
+{
+ vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0;
+}
+
+void point_map_to_sphere(vec3 vin, out vec3 vout)
+{
+ float len = length(vin);
+ float v, u;
+ if (len > 0.0) {
+ if (vin.x == 0.0 && vin.y == 0.0)
+ u = 0.0;
+ else
+ u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
+
+ v = 1.0 - acos(vin.z / len) / M_PI;
+ }
+ else
+ v = u = 0.0;
+
+ vout = vec3(u, v, 0.0);
+}
+
+void point_map_to_tube(vec3 vin, out vec3 vout)
+{
+ float u, v;
+ v = (vin.z + 1.0) * 0.5;
+ float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
+ if (len > 0.0)
+ u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
+ else
+ v = u = 0.0;
+
+ vout = vec3(u, v, 0.0);
}
void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
@@ -322,9 +358,9 @@ void math_pow(float val1, float val2, out float outval)
void math_log(float val1, float val2, out float outval)
{
if (val1 > 0.0 && val2 > 0.0)
- outval= log2(val1) / log2(val2);
+ outval = log2(val1) / log2(val2);
else
- outval= 0.0;
+ outval = 0.0;
}
void math_max(float val1, float val2, out float outval)
@@ -339,7 +375,7 @@ void math_min(float val1, float val2, out float outval)
void math_round(float val, out float outval)
{
- outval= floor(val + 0.5);
+ outval = floor(val + 0.5);
}
void math_less_than(float val1, float val2, out float outval)
@@ -377,19 +413,19 @@ void math_abs(float val1, out float outval)
void squeeze(float val, float width, float center, out float outval)
{
- outval = 1.0/(1.0 + pow(2.71828183, -((val-center)*width)));
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
}
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
}
void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 - v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
}
void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -400,7 +436,7 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
}
void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
{
- outvec = strength*v1 + (1 - strength) * v2;
+ outvec = strength * v1 + (1 - strength) * v2;
}
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -447,12 +483,12 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
{
- outvec.x = texture2D(curvemap, vec2((vec.x + 1.0)*0.5, 0.0)).x;
- outvec.y = texture2D(curvemap, vec2((vec.y + 1.0)*0.5, 0.0)).y;
- outvec.z = texture2D(curvemap, vec2((vec.z + 1.0)*0.5, 0.0)).z;
+ outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
+ outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
+ outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
if (fac != 1.0)
- outvec = (outvec*fac) + (vec*(1.0-fac));
+ outvec = (outvec * fac) + (vec * (1.0 - fac));
}
@@ -463,7 +499,7 @@ void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
if (fac != 1.0)
- outcol = (outcol*fac) + (col*(1.0-fac));
+ outcol = (outcol * fac) + (col * (1.0 - fac));
outcol.a = col.a;
}
@@ -516,11 +552,11 @@ void set_rgba_one(out vec4 outval)
void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
{
float a = 1.0 + contrast;
- float b = brightness - contrast*0.5;
+ float b = brightness - contrast * 0.5;
- outcol.r = max(a*col.r + b, 0.0);
- outcol.g = max(a*col.g + b, 0.0);
- outcol.b = max(a*col.b + b, 0.0);
+ outcol.r = max(a * col.r + b, 0.0);
+ outcol.g = max(a * col.g + b, 0.0);
+ outcol.b = max(a * col.b + b, 0.0);
outcol.a = col.a;
}
@@ -550,7 +586,7 @@ void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
- outcol = vec4(1.0) - (vec4(facm) + fac*(vec4(1.0) - col2))*(vec4(1.0) - col1);
+ outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
outcol.a = col1.a;
}
@@ -562,19 +598,19 @@ void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
if (outcol.r < 0.5)
- outcol.r *= facm + 2.0*fac*col2.r;
+ outcol.r *= facm + 2.0 * fac * col2.r;
else
- outcol.r = 1.0 - (facm + 2.0*fac*(1.0 - col2.r))*(1.0 - outcol.r);
+ outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
if (outcol.g < 0.5)
- outcol.g *= facm + 2.0*fac*col2.g;
+ outcol.g *= facm + 2.0 * fac * col2.g;
else
- outcol.g = 1.0 - (facm + 2.0*fac*(1.0 - col2.g))*(1.0 - outcol.g);
+ outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
if (outcol.b < 0.5)
- outcol.b *= facm + 2.0*fac*col2.b;
+ outcol.b *= facm + 2.0 * fac * col2.b;
else
- outcol.b = 1.0 - (facm + 2.0*fac*(1.0 - col2.b))*(1.0 - outcol.b);
+ outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
}
void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -591,9 +627,9 @@ void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if (col2.r != 0.0) outcol.r = facm*outcol.r + fac*outcol.r/col2.r;
- if (col2.g != 0.0) outcol.g = facm*outcol.g + fac*outcol.g/col2.g;
- if (col2.b != 0.0) outcol.b = facm*outcol.b + fac*outcol.b/col2.b;
+ if (col2.r != 0.0) outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
+ if (col2.g != 0.0) outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
+ if (col2.b != 0.0) outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
}
void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -606,14 +642,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = min(col1.rgb, col2.rgb*fac);
+ outcol.rgb = min(col1.rgb, col2.rgb * fac);
outcol.a = col1.a;
}
void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = max(col1.rgb, col2.rgb*fac);
+ outcol.rgb = max(col1.rgb, col2.rgb * fac);
outcol.a = col1.a;
}
@@ -623,28 +659,28 @@ void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
if (outcol.r != 0.0) {
- float tmp = 1.0 - fac*col2.r;
+ float tmp = 1.0 - fac * col2.r;
if (tmp <= 0.0)
outcol.r = 1.0;
- else if ((tmp = outcol.r/tmp) > 1.0)
+ else if ((tmp = outcol.r / tmp) > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
}
if (outcol.g != 0.0) {
- float tmp = 1.0 - fac*col2.g;
+ float tmp = 1.0 - fac * col2.g;
if (tmp <= 0.0)
outcol.g = 1.0;
- else if ((tmp = outcol.g/tmp) > 1.0)
+ else if ((tmp = outcol.g / tmp) > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
}
if (outcol.b != 0.0) {
- float tmp = 1.0 - fac*col2.b;
+ float tmp = 1.0 - fac * col2.b;
if (tmp <= 0.0)
outcol.b = 1.0;
- else if ((tmp = outcol.b/tmp) > 1.0)
+ else if ((tmp = outcol.b / tmp) > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -658,30 +694,30 @@ void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- tmp = facm + fac*col2.r;
+ tmp = facm + fac * col2.r;
if (tmp <= 0.0)
outcol.r = 0.0;
- else if ((tmp = (1.0 - (1.0 - outcol.r)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0)
outcol.r = 0.0;
else if (tmp > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
- tmp = facm + fac*col2.g;
+ tmp = facm + fac * col2.g;
if (tmp <= 0.0)
outcol.g = 0.0;
- else if ((tmp = (1.0 - (1.0 - outcol.g)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0)
outcol.g = 0.0;
else if (tmp > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
- tmp = facm + fac*col2.b;
+ tmp = facm + fac * col2.b;
if (tmp <= 0.0)
outcol.b = 0.0;
- else if ((tmp = (1.0 - (1.0 - outcol.b)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0)
outcol.b = 0.0;
else if (tmp > 1.0)
outcol.b = 1.0;
@@ -702,7 +738,7 @@ void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
- hsv_to_rgb(hsv, tmp);
+ hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
@@ -722,7 +758,7 @@ void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
if (hsv.y != 0.0) {
rgb_to_hsv(col2, hsv2);
- hsv.y = facm*hsv.y + fac*hsv2.y;
+ hsv.y = facm * hsv.y + fac * hsv2.y;
hsv_to_rgb(hsv, outcol);
}
}
@@ -736,7 +772,7 @@ void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
rgb_to_hsv(col1, hsv);
rgb_to_hsv(col2, hsv2);
- hsv.z = facm*hsv.z + fac*hsv2.z;
+ hsv.z = facm * hsv.z + fac * hsv2.z;
hsv_to_rgb(hsv, outcol);
}
@@ -754,7 +790,7 @@ void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv.y = hsv2.y;
- hsv_to_rgb(hsv, tmp);
+ hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
@@ -766,16 +802,16 @@ void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
- vec4 one= vec4(1.0);
- vec4 scr= one - (one - col2)*(one - col1);
- outcol = facm*col1 + fac*((one - col1)*col2*col1 + col1*scr);
+ vec4 one = vec4(1.0);
+ vec4 scr = one - (one - col2) * (one - col1);
+ outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
}
void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol = col1 + fac*(2.0*(col2 - vec4(0.5)));
+ outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
}
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
@@ -784,12 +820,12 @@ void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha
outalpha = outcol.a;
}
-void rgbtobw(vec4 color, out float outval)
+void rgbtobw(vec4 color, out float outval)
{
#ifdef USE_NEW_SHADING
- outval = color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+ outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
#else
- outval = color.r*0.35 + color.g*0.45 + color.b*0.2; /* keep these factors in sync with texture.h:RGBTOBW */
+ outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */
#endif
}
@@ -816,11 +852,11 @@ void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 ou
rgb_to_hsv(col, hsv);
hsv[0] += (hue - 0.5);
- if (hsv[0]>1.0) hsv[0]-=1.0; else if (hsv[0]<0.0) hsv[0]+= 1.0;
+ if (hsv[0] > 1.0) hsv[0] -= 1.0; else if (hsv[0] < 0.0) hsv[0] += 1.0;
hsv[1] *= sat;
- if (hsv[1]>1.0) hsv[1]= 1.0; else if (hsv[1]<0.0) hsv[1]= 0.0;
+ if (hsv[1] > 1.0) hsv[1] = 1.0; else if (hsv[1] < 0.0) hsv[1] = 0.0;
hsv[2] *= value;
- if (hsv[2]>1.0) hsv[2]= 1.0; else if (hsv[2]<0.0) hsv[2]= 0.0;
+ if (hsv[2] > 1.0) hsv[2] = 1.0; else if (hsv[2] < 0.0) hsv[2] = 0.0;
hsv_to_rgb(hsv, outcol);
@@ -880,19 +916,19 @@ void texture_flip_blend(vec3 vec, out vec3 outvec)
void texture_blend_lin(vec3 vec, out float outval)
{
- outval = (1.0+vec.x)/2.0;
+ outval = (1.0 + vec.x) / 2.0;
}
void texture_blend_quad(vec3 vec, out float outval)
{
- outval = max((1.0+vec.x)/2.0, 0.0);
+ outval = max((1.0 + vec.x) / 2.0, 0.0);
outval *= outval;
}
void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal)
{
- float a = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)*20.0;
- float wi = 0.5 + 0.5*sin(a);
+ float a = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) * 20.0;
+ float wi = 0.5 + 0.5 * sin(a);
value = wi;
color = vec4(wi, wi, wi, 1.0);
@@ -901,12 +937,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal
void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal)
{
- color = texture2D(ima, (vec.xy + vec2(1.0, 1.0))*0.5);
+ color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5);
value = color.a;
- normal.x = 2.0*(color.r - 0.5);
- normal.y = 2.0*(0.5 - color.g);
- normal.z = 2.0*(color.b - 0.5);
+ normal.x = 2.0 * (color.r - 0.5);
+ normal.y = 2.0 * (0.5 - color.g);
+ normal.z = 2.0 * (color.b - 0.5);
}
/************* MTEX *****************/
@@ -937,17 +973,17 @@ void texco_tangent(vec4 tangent, out vec3 outtangent)
void texco_global(mat4 viewinvmat, vec3 co, out vec3 global)
{
- global = (viewinvmat*vec4(co, 1.0)).xyz;
+ global = (viewinvmat * vec4(co, 1.0)).xyz;
}
void texco_object(mat4 viewinvmat, mat4 obinvmat, vec3 co, out vec3 object)
{
- object = (obinvmat*(viewinvmat*vec4(co, 1.0))).xyz;
+ object = (obinvmat * (viewinvmat * vec4(co, 1.0))).xyz;
}
void texco_refl(vec3 vn, vec3 view, out vec3 ref)
{
- ref = view - 2.0*dot(vn, view)*vn;
+ ref = view - 2.0 * dot(vn, view) * vn;
}
void shade_norm(vec3 normal, out vec3 outnormal)
@@ -966,9 +1002,9 @@ void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = fact*texcol + facm*outcol;
+ incol = fact * texcol + facm * outcol;
}
void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -976,9 +1012,9 @@ void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = (facm + fact*texcol)*outcol;
+ incol = (facm + fact * texcol) * outcol;
}
void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -986,9 +1022,9 @@ void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = vec3(1.0) - (vec3(facm) + fact*(vec3(1.0) - texcol))*(vec3(1.0) - outcol);
+ incol = vec3(1.0) - (vec3(facm) + fact * (vec3(1.0) - texcol)) * (vec3(1.0) - outcol);
}
void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -996,32 +1032,32 @@ void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
if (outcol.r < 0.5)
- incol.r = outcol.r*(facm + 2.0*fact*texcol.r);
+ incol.r = outcol.r * (facm + 2.0 * fact * texcol.r);
else
- incol.r = 1.0 - (facm + 2.0*fact*(1.0 - texcol.r))*(1.0 - outcol.r);
+ incol.r = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.r)) * (1.0 - outcol.r);
if (outcol.g < 0.5)
- incol.g = outcol.g*(facm + 2.0*fact*texcol.g);
+ incol.g = outcol.g * (facm + 2.0 * fact * texcol.g);
else
- incol.g = 1.0 - (facm + 2.0*fact*(1.0 - texcol.g))*(1.0 - outcol.g);
+ incol.g = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.g)) * (1.0 - outcol.g);
if (outcol.b < 0.5)
- incol.b = outcol.b*(facm + 2.0*fact*texcol.b);
+ incol.b = outcol.b * (facm + 2.0 * fact * texcol.b);
else
- incol.b = 1.0 - (facm + 2.0*fact*(1.0 - texcol.b))*(1.0 - outcol.b);
+ incol.b = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.b)) * (1.0 - outcol.b);
}
void mtex_rgb_sub(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- incol = -fact*facg*texcol + outcol;
+ incol = -fact * facg * texcol + outcol;
}
void mtex_rgb_add(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- incol = fact*facg*texcol + outcol;
+ incol = fact * facg * texcol + outcol;
}
void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1029,11 +1065,11 @@ void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if (texcol.r != 0.0) incol.r = facm*outcol.r + fact*outcol.r/texcol.r;
- if (texcol.g != 0.0) incol.g = facm*outcol.g + fact*outcol.g/texcol.g;
- if (texcol.b != 0.0) incol.b = facm*outcol.b + fact*outcol.b/texcol.b;
+ if (texcol.r != 0.0) incol.r = facm * outcol.r + fact * outcol.r / texcol.r;
+ if (texcol.g != 0.0) incol.g = facm * outcol.g + fact * outcol.g / texcol.g;
+ if (texcol.b != 0.0) incol.b = facm * outcol.b + fact * outcol.b / texcol.b;
}
void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1041,9 +1077,9 @@ void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = facm*outcol + fact*abs(texcol - outcol);
+ incol = facm * outcol + fact * abs(texcol - outcol);
}
void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1051,7 +1087,7 @@ void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm, col;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
incol.r = min(outcol.r, texcol.r) * fact + outcol.r * facm;
incol.g = min(outcol.g, texcol.g) * fact + outcol.g * facm;
@@ -1064,11 +1100,11 @@ void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
fact *= facg;
- col = fact*texcol.r;
+ col = fact * texcol.r;
if (col > outcol.r) incol.r = col; else incol.r = outcol.r;
- col = fact*texcol.g;
+ col = fact * texcol.g;
if (col > outcol.g) incol.g = col; else incol.g = outcol.g;
- col = fact*texcol.b;
+ col = fact * texcol.b;
if (col > outcol.b) incol.b = col; else incol.b = outcol.b;
}
@@ -1076,7 +1112,7 @@ void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_hue(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_hue(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1084,7 +1120,7 @@ void mtex_rgb_sat(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_sat(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_sat(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1092,7 +1128,7 @@ void mtex_rgb_val(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_val(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_val(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1100,7 +1136,7 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
{
vec4 col;
- mix_color(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_color(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1109,11 +1145,11 @@ void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
vec3 one = vec3(1.0);
- vec3 scr = one - (one - texcol)*(one - outcol);
- incol = facm*outcol + fact*((one - texcol)*outcol*texcol + outcol*scr);
+ vec3 scr = one - (one - texcol) * (one - outcol);
+ incol = facm * outcol + fact * ((one - texcol) * outcol * texcol + outcol * scr);
}
void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1121,25 +1157,25 @@ void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
fact *= facg;
if (texcol.r > 0.5)
- incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5));
+ incol.r = outcol.r + fact * (2.0 * (texcol.r - 0.5));
else
- incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0);
+ incol.r = outcol.r + fact * (2.0 * (texcol.r) - 1.0);
if (texcol.g > 0.5)
- incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5));
+ incol.g = outcol.g + fact * (2.0 * (texcol.g - 0.5));
else
- incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0);
+ incol.g = outcol.g + fact * (2.0 * (texcol.g) - 1.0);
if (texcol.b > 0.5)
- incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5));
+ incol.b = outcol.b + fact * (2.0 * (texcol.b - 0.5));
else
- incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0);
+ incol.b = outcol.b + fact * (2.0 * (texcol.b) - 1.0);
}
void mtex_value_vars(inout float fact, float facg, out float facm)
{
fact *= abs(facg);
- facm = 1.0-fact;
+ facm = 1.0 - fact;
if (facg < 0.0) {
float tmp = fact;
@@ -1153,7 +1189,7 @@ void mtex_value_blend(float outcol, float texcol, float fact, float facg, out fl
float facm;
mtex_value_vars(fact, facg, facm);
- incol = fact*texcol + facm*outcol;
+ incol = fact * texcol + facm * outcol;
}
void mtex_value_mul(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1162,7 +1198,7 @@ void mtex_value_mul(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
facm = 1.0 - facg;
- incol = (facm + fact*texcol)*outcol;
+ incol = (facm + fact * texcol) * outcol;
}
void mtex_value_screen(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1171,7 +1207,7 @@ void mtex_value_screen(float outcol, float texcol, float fact, float facg, out f
mtex_value_vars(fact, facg, facm);
facm = 1.0 - facg;
- incol = 1.0 - (facm + fact*(1.0 - texcol))*(1.0 - outcol);
+ incol = 1.0 - (facm + fact * (1.0 - texcol)) * (1.0 - outcol);
}
void mtex_value_sub(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1180,7 +1216,7 @@ void mtex_value_sub(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
fact = -fact;
- incol = fact*texcol + outcol;
+ incol = fact * texcol + outcol;
}
void mtex_value_add(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1189,7 +1225,7 @@ void mtex_value_add(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
fact = fact;
- incol = fact*texcol + outcol;
+ incol = fact * texcol + outcol;
}
void mtex_value_div(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1198,7 +1234,7 @@ void mtex_value_div(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
if (texcol != 0.0)
- incol = facm*outcol + fact*outcol/texcol;
+ incol = facm * outcol + fact * outcol / texcol;
else
incol = 0.0;
}
@@ -1208,7 +1244,7 @@ void mtex_value_diff(float outcol, float texcol, float fact, float facg, out flo
float facm;
mtex_value_vars(fact, facg, facm);
- incol = facm*outcol + fact*abs(texcol - outcol);
+ incol = facm * outcol + fact * abs(texcol - outcol);
}
void mtex_value_dark(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1216,7 +1252,7 @@ void mtex_value_dark(float outcol, float texcol, float fact, float facg, out flo
float facm;
mtex_value_vars(fact, facg, facm);
- incol = facm*outcol + fact*min(outcol, texcol);
+ incol = facm * outcol + fact * min(outcol, texcol);
}
void mtex_value_light(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1224,7 +1260,7 @@ void mtex_value_light(float outcol, float texcol, float fact, float facg, out fl
float facm;
mtex_value_vars(fact, facg, facm);
- float col = fact*texcol;
+ float col = fact * texcol;
if (col > outcol) incol = col; else incol = outcol;
}
@@ -1240,7 +1276,7 @@ void mtex_value_clamp(float fac, out float outfac)
void mtex_har_divide(float har, out float outhar)
{
- outhar = har/128.0;
+ outhar = har / 128.0;
}
void mtex_har_multiply_clamp(float har, out float outhar)
@@ -1285,15 +1321,15 @@ void mtex_rgb_invert(vec4 inrgb, out vec4 outrgb)
void mtex_value_stencil(float stencil, float intensity, out float outstencil, out float outintensity)
{
float fact = intensity;
- outintensity = intensity*stencil;
- outstencil = stencil*fact;
+ outintensity = intensity * stencil;
+ outstencil = stencil * fact;
}
void mtex_rgb_stencil(float stencil, vec4 rgb, out float outstencil, out vec4 outrgb)
{
float fact = rgb.a;
- outrgb = vec4(rgb.rgb, rgb.a*stencil);
- outstencil = stencil*fact;
+ outrgb = vec4(rgb.rgb, rgb.a * stencil);
+ outstencil = stencil * fact;
}
void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
@@ -1303,17 +1339,17 @@ void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco)
{
- outtexco = size*texco;
+ outtexco = size * texco;
}
void mtex_2d_mapping(vec3 vec, out vec3 outvec)
{
- outvec = vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+ outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
vec3 mtex_2d_mapping(vec3 vec)
{
- return vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+ return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
@@ -1347,10 +1383,10 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal)
// the normal used points inward.
// Should this ever change this negate must be removed.
vec4 color = texture2D(ima, texco.xy);
- normal = 2.0*(vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
+ normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
}
-void mtex_bump_normals_init( vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude )
+void mtex_bump_normals_init(vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude)
{
vNorg = vN;
vNacc = vN;
@@ -1376,20 +1412,20 @@ void mtex_bump_init_objspace(
{
mat3 obj2view = to_mat3(gl_ModelViewMatrix);
mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
-
- vec3 vSigmaS = view2obj * dFdx( surf_pos );
- vec3 vSigmaT = view2obj * dFdy( surf_pos );
- vec3 vN = normalize( surf_norm * obj2view );
- vR1 = cross( vSigmaT, vN );
- vR2 = cross( vN, vSigmaS ) ;
- fDet = dot ( vSigmaS, vR1 );
-
+ vec3 vSigmaS = view2obj * dFdx(surf_pos);
+ vec3 vSigmaT = view2obj * dFdy(surf_pos);
+ vec3 vN = normalize(surf_norm * obj2view);
+
+ vR1 = cross(vSigmaT, vN);
+ vR2 = cross(vN, vSigmaS);
+ fDet = dot(vSigmaS, vR1);
+
/* pretransform vNacc (in mtex_bump_apply) using the inverse transposed */
vR1 = vR1 * view2obj;
vR2 = vR2 * view2obj;
vN = vN * view2obj;
-
+
float fMagnitude = abs(fDet) * length(vN);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
@@ -1401,14 +1437,14 @@ void mtex_bump_init_texturespace(
out float fPrevMagnitude_out, out vec3 vNacc_out,
out vec3 vR1, out vec3 vR2, out float fDet)
{
- vec3 vSigmaS = dFdx( surf_pos );
- vec3 vSigmaT = dFdy( surf_pos );
+ vec3 vSigmaS = dFdx(surf_pos);
+ vec3 vSigmaT = dFdy(surf_pos);
vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = normalize( cross( vSigmaT, vN ) );
- vR2 = normalize( cross( vN, vSigmaS ) );
- fDet = sign( dot(vSigmaS, vR1) );
-
+
+ vR1 = normalize(cross(vSigmaT, vN));
+ vR2 = normalize(cross(vN, vSigmaS));
+ fDet = sign(dot(vSigmaS, vR1));
+
float fMagnitude = abs(fDet);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
@@ -1420,14 +1456,14 @@ void mtex_bump_init_viewspace(
out float fPrevMagnitude_out, out vec3 vNacc_out,
out vec3 vR1, out vec3 vR2, out float fDet)
{
- vec3 vSigmaS = dFdx( surf_pos );
- vec3 vSigmaT = dFdy( surf_pos );
+ vec3 vSigmaS = dFdx(surf_pos);
+ vec3 vSigmaT = dFdy(surf_pos);
vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = cross( vSigmaT, vN );
- vR2 = cross( vN, vSigmaS ) ;
- fDet = dot ( vSigmaS, vR1 );
-
+
+ vR1 = cross(vSigmaT, vN);
+ vR2 = cross(vN, vSigmaS);
+ fDet = dot(vSigmaS, vR1);
+
float fMagnitude = abs(fDet);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
@@ -1438,14 +1474,14 @@ void mtex_bump_tap3(
out float dBs, out float dBt)
{
vec2 STll = texco.xy;
- vec2 STlr = texco.xy + dFdx(texco.xy) ;
- vec2 STul = texco.xy + dFdy(texco.xy) ;
-
- float Hll,Hlr,Hul;
- rgbtobw( texture2D(ima, STll), Hll );
- rgbtobw( texture2D(ima, STlr), Hlr );
- rgbtobw( texture2D(ima, STul), Hul );
-
+ vec2 STlr = texco.xy + dFdx(texco.xy);
+ vec2 STul = texco.xy + dFdy(texco.xy);
+
+ float Hll, Hlr, Hul;
+ rgbtobw(texture2D(ima, STll), Hll);
+ rgbtobw(texture2D(ima, STlr), Hlr);
+ rgbtobw(texture2D(ima, STul), Hul);
+
dBs = hScale * (Hlr - Hll);
dBt = hScale * (Hul - Hll);
}
@@ -1460,83 +1496,82 @@ void mtex_bump_bicubic(
float Hr;
float Hd;
float Hu;
-
+
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
-
- vec2 STl = texco.xy - 0.5 * TexDx ;
- vec2 STr = texco.xy + 0.5 * TexDx ;
- vec2 STd = texco.xy - 0.5 * TexDy ;
- vec2 STu = texco.xy + 0.5 * TexDy ;
-
+
+ vec2 STl = texco.xy - 0.5 * TexDx;
+ vec2 STr = texco.xy + 0.5 * TexDx;
+ vec2 STd = texco.xy - 0.5 * TexDy;
+ vec2 STu = texco.xy + 0.5 * TexDy;
+
rgbtobw(texture2D(ima, STl), Hl);
rgbtobw(texture2D(ima, STr), Hr);
rgbtobw(texture2D(ima, STd), Hd);
rgbtobw(texture2D(ima, STu), Hu);
-
+
vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
- float fBlend = clamp(1.0-textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
- if (fBlend!=0.0)
- {
+ float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
+ if (fBlend != 0.0) {
// the derivative of the bicubic sampling of level 0
ivec2 vDim;
vDim = textureSize(ima, 0);
// taking the fract part of the texture coordinate is a hardcoded wrap mode.
- // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
+ // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
// this is done so that we can still get a valid texel with uvs outside the 0,1 range
// by texelFetch below, as coordinates are clamped when using this function.
- vec2 fTexLoc = vDim*fract(texco.xy) - vec2(0.5, 0.5);
+ vec2 fTexLoc = vDim * fract(texco.xy) - vec2(0.5, 0.5);
ivec2 iTexLoc = ivec2(floor(fTexLoc));
- vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
+ vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
/*******************************************************************************************
* This block will replace the one below when one channel textures are properly supported. *
*******************************************************************************************
- vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim );
+ vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim);
mat4 H = mat4(vSamplesUL.w, vSamplesUL.x, vSamplesLL.w, vSamplesLL.x,
- vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
- vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
- vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
-*/
+ vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
+ vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
+ vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
+ */
ivec2 iTexLocMod = iTexLoc + ivec2(-1, -1);
mat4 H;
-
+
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- ivec2 iTexTmp = iTexLocMod + ivec2(i,j);
-
+ ivec2 iTexTmp = iTexLocMod + ivec2(i, j);
+
// wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range.
// this is guaranteed to work since we take the fractional part of the uv above.
- iTexTmp.x = (iTexTmp.x < 0)? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x)? iTexTmp.x - vDim.x : iTexTmp.x);
- iTexTmp.y = (iTexTmp.y < 0)? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y)? iTexTmp.y - vDim.y : iTexTmp.y);
+ iTexTmp.x = (iTexTmp.x < 0) ? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x) ? iTexTmp.x - vDim.x : iTexTmp.x);
+ iTexTmp.y = (iTexTmp.y < 0) ? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y) ? iTexTmp.y - vDim.y : iTexTmp.y);
rgbtobw(texelFetch(ima, iTexTmp, 0), H[i][j]);
}
}
-
+
float x = t.x, y = t.y;
float x2 = x * x, x3 = x2 * x, y2 = y * y, y3 = y2 * y;
- vec4 X = vec4(-0.5*(x3+x)+x2, 1.5*x3-2.5*x2+1, -1.5*x3+2*x2+0.5*x, 0.5*(x3-x2));
- vec4 Y = vec4(-0.5*(y3+y)+y2, 1.5*y3-2.5*y2+1, -1.5*y3+2*y2+0.5*y, 0.5*(y3-y2));
- vec4 dX = vec4(-1.5*x2+2*x-0.5, 4.5*x2-5*x, -4.5*x2+4*x+0.5, 1.5*x2-x);
- vec4 dY = vec4(-1.5*y2+2*y-0.5, 4.5*y2-5*y, -4.5*y2+4*y+0.5, 1.5*y2-y);
-
+ vec4 X = vec4(-0.5 * (x3 + x) + x2, 1.5 * x3 - 2.5 * x2 + 1, -1.5 * x3 + 2 * x2 + 0.5 * x, 0.5 * (x3 - x2));
+ vec4 Y = vec4(-0.5 * (y3 + y) + y2, 1.5 * y3 - 2.5 * y2 + 1, -1.5 * y3 + 2 * y2 + 0.5 * y, 0.5 * (y3 - y2));
+ vec4 dX = vec4(-1.5 * x2 + 2 * x - 0.5, 4.5 * x2 - 5 * x, -4.5 * x2 + 4 * x + 0.5, 1.5 * x2 - x);
+ vec4 dY = vec4(-1.5 * y2 + 2 * y - 0.5, 4.5 * y2 - 5 * y, -4.5 * y2 + 4 * y + 0.5, 1.5 * y2 - y);
+
// complete derivative in normalized coordinates (mul by vDim)
vec2 dHdST = vDim * vec2(dot(Y, H * dX), dot(dY, H * X));
// transform derivative to screen-space
- vec2 dHdxy_bicubic = vec2( dHdST.x * TexDx.x + dHdST.y * TexDx.y,
- dHdST.x * TexDy.x + dHdST.y * TexDy.y );
+ vec2 dHdxy_bicubic = vec2(dHdST.x * TexDx.x + dHdST.y * TexDx.y,
+ dHdST.x * TexDy.x + dHdST.y * TexDy.y);
// blend between the two
- dHdxy = dHdxy*(1-fBlend) + dHdxy_bicubic*fBlend;
+ dHdxy = dHdxy * (1 - fBlend) + dHdxy_bicubic * fBlend;
}
dBs = hScale * dHdxy.x;
@@ -1553,18 +1588,18 @@ void mtex_bump_tap5(
vec2 TexDy = dFdy(texco.xy);
vec2 STc = texco.xy;
- vec2 STl = texco.xy - 0.5 * TexDx ;
- vec2 STr = texco.xy + 0.5 * TexDx ;
- vec2 STd = texco.xy - 0.5 * TexDy ;
- vec2 STu = texco.xy + 0.5 * TexDy ;
-
- float Hc,Hl,Hr,Hd,Hu;
- rgbtobw( texture2D(ima, STc), Hc );
- rgbtobw( texture2D(ima, STl), Hl );
- rgbtobw( texture2D(ima, STr), Hr );
- rgbtobw( texture2D(ima, STd), Hd );
- rgbtobw( texture2D(ima, STu), Hu );
-
+ vec2 STl = texco.xy - 0.5 * TexDx;
+ vec2 STr = texco.xy + 0.5 * TexDx;
+ vec2 STd = texco.xy - 0.5 * TexDy;
+ vec2 STu = texco.xy + 0.5 * TexDy;
+
+ float Hc, Hl, Hr, Hd, Hu;
+ rgbtobw(texture2D(ima, STc), Hc);
+ rgbtobw(texture2D(ima, STl), Hl);
+ rgbtobw(texture2D(ima, STr), Hr);
+ rgbtobw(texture2D(ima, STd), Hd);
+ rgbtobw(texture2D(ima, STu), Hu);
+
dBs = hScale * (Hr - Hl);
dBt = hScale * (Hu - Hd);
}
@@ -1573,27 +1608,27 @@ void mtex_bump_deriv(
vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
out float dBs, out float dBt)
{
- float s = 1.0; // negate this if flipped texture coordinate
+ float s = 1.0; // negate this if flipped texture coordinate
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
-
+
// this variant using a derivative map is described here
// http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
vec2 dim = vec2(ima_x, ima_y);
- vec2 dBduv = hScale*dim*(2.0*texture2D(ima, texco.xy).xy-1.0);
-
- dBs = dBduv.x*TexDx.x + s*dBduv.y*TexDx.y;
- dBt = dBduv.x*TexDy.x + s*dBduv.y*TexDy.y;
+ vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0);
+
+ dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y;
+ dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y;
}
void mtex_bump_apply(
float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
out vec3 vNacc_out, out vec3 perturbed_norm)
{
- vec3 vSurfGrad = sign(fDet) * ( dBs * vR1 + dBt * vR2 );
-
+ vec3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2);
+
vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize( vNacc_out );
+ perturbed_norm = normalize(vNacc_out);
}
void mtex_bump_apply_texspace(
@@ -1604,12 +1639,12 @@ void mtex_bump_apply_texspace(
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
- vec3 vSurfGrad = sign(fDet) * (
- dBs / length( vec2(ima_x*TexDx.x, ima_y*TexDx.y) ) * vR1 +
- dBt / length( vec2(ima_x*TexDy.x, ima_y*TexDy.y) ) * vR2 );
+ vec3 vSurfGrad = sign(fDet) * (
+ dBs / length(vec2(ima_x * TexDx.x, ima_y * TexDx.y)) * vR1 +
+ dBt / length(vec2(ima_x * TexDy.x, ima_y * TexDy.y)) * vR2);
vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize( vNacc_out );
+ perturbed_norm = normalize(vNacc_out);
}
void mtex_negate_texnormal(vec3 normal, out vec3 outnormal)
@@ -1621,13 +1656,13 @@ void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 out
{
vec3 B = tangent.w * cross(normal, tangent.xyz);
- outnormal = texnormal.x*tangent.xyz + texnormal.y*B + texnormal.z*normal;
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
outnormal = normalize(outnormal);
}
void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
{
- outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz);
+ outnormal = normalize((viewmat * vec4(texnormal, 0.0)).xyz);
}
void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
@@ -1637,7 +1672,7 @@ void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
{
- outnormal = (1.0 - norfac)*normal + norfac*newnormal;
+ outnormal = (1.0 - norfac) * normal + norfac * newnormal;
outnormal = normalize(outnormal);
}
@@ -1660,26 +1695,26 @@ void lamp_visibility_other(vec3 co, vec3 lampco, out vec3 lv, out float dist, ou
void lamp_falloff_invlinear(float lampdist, float dist, out float visifac)
{
- visifac = lampdist/(lampdist + dist);
+ visifac = lampdist / (lampdist + dist);
}
void lamp_falloff_invsquare(float lampdist, float dist, out float visifac)
{
- visifac = lampdist/(lampdist + dist*dist);
+ visifac = lampdist / (lampdist + dist * dist);
}
void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out float visifac)
{
- float lampdistkw = lampdist*lampdist;
+ float lampdistkw = lampdist * lampdist;
- visifac = lampdist/(lampdist + ld1*dist);
- visifac *= lampdistkw/(lampdistkw + ld2*dist*dist);
+ visifac = lampdist / (lampdist + ld1 * dist);
+ visifac *= lampdistkw / (lampdistkw + ld2 * dist * dist);
}
void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac)
{
vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad);
- vec3 d_coeff = vec3(1.0, dist, dist*dist);
+ vec3 d_coeff = vec3(1.0, dist, dist * dist);
float visifac_r = dot(coeff, d_coeff);
if (visifac_r > 0.0)
visifac = 1.0 / visifac_r;
@@ -1689,25 +1724,25 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef
void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
{
- visifac = texture2D(curvemap, vec2(dist/lampdist, 0.0)).x;
+ visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
}
void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
{
- float t= lampdist - dist;
+ float t = lampdist - dist;
- outvisifac= visifac*max(t, 0.0)/lampdist;
+ outvisifac = visifac * max(t, 0.0) / lampdist;
}
void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
{
if (dot(lv, lampvec) > 0.0) {
- vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz;
+ vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
/* without clever non-uniform scale, we could do: */
// float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z));
- inpr = 1.0/sqrt(1.0 + x*x);
+ inpr = 1.0 / sqrt(1.0 + x * x);
}
else
inpr = 0.0;
@@ -1742,15 +1777,15 @@ void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac,
/* soft area */
if (spotbl != 0.0)
- inpr *= smoothstep(0.0, 1.0, t/spotbl);
+ inpr *= smoothstep(0.0, 1.0, t / spotbl);
- outvisifac = visifac*inpr;
+ outvisifac = visifac * inpr;
}
}
void lamp_visibility_clamp(float visifac, out float outvisifac)
{
- outvisifac = (visifac < 0.001)? 0.0: visifac;
+ outvisifac = (visifac < 0.001) ? 0.0 : visifac;
}
void world_paper_view(vec3 vec, out vec3 outvec)
@@ -1790,7 +1825,7 @@ void world_blend(vec3 vec, out float blend)
void shade_view(vec3 co, out vec3 view)
{
/* handle perspective/orthographic */
- view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(co): vec3(0.0, 0.0, -1.0);
+ view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
}
void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn)
@@ -1813,14 +1848,14 @@ void shade_is_no_diffuse(out float is)
void shade_is_hemi(float inp, out float is)
{
- is = 0.5*inp + 0.5;
+ is = 0.5 * inp + 0.5;
}
float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
{
vec3 vec[4], c[4];
float rad[4], fac;
-
+
vec[0] = normalize(co - area[0].xyz);
vec[1] = normalize(co - area[1].xyz);
vec[2] = normalize(co - area[2].xyz);
@@ -1836,10 +1871,10 @@ float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
rad[2] = acos(dot(vec[2], vec[3]));
rad[3] = acos(dot(vec[3], vec[0]));
- fac= rad[0]*dot(vn, c[0]);
- fac+= rad[1]*dot(vn, c[1]);
- fac+= rad[2]*dot(vn, c[2]);
- fac+= rad[3]*dot(vn, c[3]);
+ fac = rad[0] * dot(vn, c[0]);
+ fac += rad[1] * dot(vn, c[1]);
+ fac += rad[2] * dot(vn, c[2]);
+ fac += rad[3] * dot(vn, c[3]);
return max(fac, 0.0);
}
@@ -1857,7 +1892,7 @@ void shade_inp_area(
else {
float intens = area_lamp_energy(area, co, vn);
- inp = pow(intens*areasize, k);
+ inp = pow(intens * areasize, k);
}
}
@@ -1879,8 +1914,8 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float Lit_A = acos(realnl);
float View_A = acos(nv);
- vec3 Lit_B = normalize(l - realnl*n);
- vec3 View_B = normalize(v - nv*n);
+ vec3 Lit_B = normalize(l - realnl * n);
+ vec3 View_B = normalize(v - nv * n);
float t = max(dot(Lit_B, View_B), 0.0);
@@ -1895,11 +1930,11 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
b = Lit_A;
}
- float A = 1.0 - (0.5*((rough*rough)/((rough*rough) + 0.33)));
- float B = 0.45*((rough*rough)/((rough*rough) + 0.09));
+ float A = 1.0 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33)));
+ float B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09));
b *= 0.95;
- is = nl*(A + (B * t * sin(a) * tan(b)));
+ is = nl * (A + (B * t * sin(a) * tan(b)));
}
}
@@ -1910,7 +1945,7 @@ void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out f
if (ang < size) is = 1.0;
else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
- else is = 1.0 - ((ang - size)/tsmooth);
+ else is = 1.0 - ((ang - size) / tsmooth);
}
void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is)
@@ -1922,9 +1957,9 @@ void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float
float nv = max(dot(n, v), 0.0);
if (darkness <= 1.0)
- is = nl*pow(max(nv*nl, 0.1), darkness - 1.0);
+ is = nl * pow(max(nv * nl, 0.1), darkness - 1.0);
else
- is = nl*pow(1.0001 - nv, darkness - 1.0);
+ is = nl * pow(1.0001 - nv, darkness - 1.0);
}
}
@@ -1933,18 +1968,18 @@ float fresnel_fac(vec3 view, vec3 vn, float grad, float fac)
float t1, t2;
float ffac;
- if (fac==0.0) {
+ if (fac == 0.0) {
ffac = 1.0;
}
else {
- t1= dot(view, vn);
- if (t1>0.0) t2= 1.0+t1;
- else t2= 1.0-t1;
+ t1 = dot(view, vn);
+ if (t1 > 0.0) t2 = 1.0 + t1;
+ else t2 = 1.0 - t1;
- t2= grad + (1.0-grad)*pow(t2, fac);
+ t2 = grad + (1.0 - grad) * pow(t2, fac);
- if (t2<0.0) ffac = 0.0;
- else if (t2>1.0) ffac = 1.0;
+ if (t2 < 0.0) ffac = 0.0;
+ else if (t2 > 1.0) ffac = 1.0;
else ffac = t2;
}
@@ -1958,18 +1993,18 @@ void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac,
void shade_cubic(float is, out float outis)
{
- if (is>0.0 && is<1.0)
- outis= smoothstep(0.0, 1.0, is);
+ if (is > 0.0 && is < 1.0)
+ outis = smoothstep(0.0, 1.0, is);
else
- outis= is;
+ outis = is;
}
void shade_visifac(float i, float visifac, float refl, out float outi)
{
/*if (i > 0.0)*/
- outi = max(i*visifac*refl, 0.0);
+ outi = max(i * visifac * refl, 0.0);
/*else
- outi = i;*/
+ outi = i;*/
}
void shade_tangent_v_spec(vec3 tang, out vec3 vn)
@@ -1980,7 +2015,7 @@ void shade_tangent_v_spec(vec3 tang, out vec3 vn)
void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol)
{
if (i > 0.0)
- outcol = i*lampcol*col;
+ outcol = i * lampcol * col;
else
outcol = vec3(0.0, 0.0, 0.0);
}
@@ -1991,9 +2026,9 @@ void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float
lv = normalize(lv);
t = dot(vn, lv);
- t = 0.5*t + 0.5;
+ t = 0.5 * t + 0.5;
- t = visifac*spec*pow(t, hard);
+ t = visifac * spec * pow(t, hard);
}
void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
@@ -2016,7 +2051,7 @@ void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
float nv = max(dot(n, v), 0.0);
float i = pow(nh, hard);
- i = i/(0.1+nv);
+ i = i / (0.1 + nv);
specfac = i;
}
}
@@ -2030,10 +2065,10 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou
specfac = 0.0;
}
else {
- if (spec_power<100.0)
- spec_power= sqrt(1.0/spec_power);
+ if (spec_power < 100.0)
+ spec_power = sqrt(1.0 / spec_power);
else
- spec_power= 10.0/spec_power;
+ spec_power = 10.0 / spec_power;
vec3 h = normalize(v + l);
float nh = dot(n, h);
@@ -2050,8 +2085,8 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou
float vh = max(dot(v, h), 0.01);
float a = 1.0;
- float b = (2.0*nh*nv)/vh;
- float c = (2.0*nh*nl)/vh;
+ float b = (2.0 * nh * nv) / vh;
+ float c = (2.0 * nh * nl) / vh;
float g = 0.0;
@@ -2065,7 +2100,7 @@ void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, ou
(((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0)))));
float ang = acos(nh);
- specfac = max(f*g*exp_blender((-(ang*ang)/(2.0*spec_power*spec_power))), 0.0);
+ specfac = max(f * g * exp_blender((-(ang * ang) / (2.0 * spec_power * spec_power))), 0.0);
}
}
}
@@ -2080,7 +2115,7 @@ void shade_wardiso_spec(vec3 n, vec3 l, vec3 v, float rms, out float specfac)
float angle = tan(acos(nh));
float alpha = max(rms, 0.001);
- specfac= nl * (1.0/(4.0*M_PI*alpha*alpha))*(exp_blender(-(angle*angle)/(alpha*alpha))/(sqrt(nv*nl)));
+ specfac = nl * (1.0 / (4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle) / (alpha * alpha)) / (sqrt(nv * nl)));
}
void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float specfac)
@@ -2091,24 +2126,24 @@ void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out floa
if (ang < size) rslt = 1.0;
else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
- else rslt = 1.0 - ((ang - size)/tsmooth);
+ else rslt = 1.0 - ((ang - size) / tsmooth);
specfac = rslt;
}
void shade_spec_area_inp(float specfac, float inp, out float outspecfac)
{
- outspecfac = specfac*inp;
+ outspecfac = specfac * inp;
}
void shade_spec_t(float shadfac, float spec, float visifac, float specfac, out float t)
{
- t = shadfac*spec*visifac*specfac;
+ t = shadfac * spec * visifac * specfac;
}
void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol)
{
- outcol = t*lampcol*speccol;
+ outcol = t * lampcol * speccol;
}
void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result)
@@ -2134,7 +2169,7 @@ void shade_add(vec4 col1, vec4 col2, out vec4 outcol)
void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col + col1*col2;
+ outcol = col + col1 * col2;
}
void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
@@ -2144,52 +2179,52 @@ void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col + max(col1*col2, vec4(0.0, 0.0, 0.0, 0.0));
+ outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
}
void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
{
- outcol = col + f*col1;
+ outcol = col + f * col1;
}
void shade_mul(vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col1*col2;
+ outcol = col1 * col2;
}
void shade_mul_value(float fac, vec4 col, out vec4 outcol)
{
- outcol = col*fac;
+ outcol = col * fac;
}
void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol)
{
- outcol = col*fac;
+ outcol = col * fac;
}
void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
- outcol = vec4(col.rgb*obcol.rgb, col.a);
+ outcol = vec4(col.rgb * obcol.rgb, col.a);
}
void ramp_rgbtobw(vec3 color, out float outval)
{
- outval = color.r*0.3 + color.g*0.58 + color.b*0.12;
+ outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
}
void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
{
- outshadrgb = i*energy*(1.0 - shadfac)*(vec3(1.0)-shadcol);
+ outshadrgb = i * energy * (1.0 - shadfac) * (vec3(1.0) - shadcol);
}
void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff)
{
- outdiff = diff - vec4(rgb*shadrgb, 0.0);
+ outdiff = diff - vec4(rgb * shadrgb, 0.0);
}
void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec)
{
- outspec = spec - vec4(specrgb*shadrgb, 0.0);
+ outspec = spec - vec4(specrgb * shadrgb, 0.0);
}
void shade_clamp_positive(vec4 col, out vec4 outcol)
@@ -2205,12 +2240,12 @@ void test_shadowbuf(
result = 0.0;
}
else {
- vec4 co = shadowpersmat*vec4(rco, 1.0);
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
//float bias = (1.5 - inp*inp)*shadowbias;
- co.z -= shadowbias*co.w;
-
- if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0)
+ co.z -= shadowbias * co.w;
+
+ if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0)
result = shadow2DProj(shadowmap, co).x;
else
result = 1.0;
@@ -2225,23 +2260,23 @@ void test_shadowbuf_vsm(
result = 0.0;
}
else {
- vec4 co = shadowpersmat*vec4(rco, 1.0);
- if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0) {
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
+ if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
vec2 moments = texture2DProj(shadowmap, co).rg;
- float dist = co.z/co.w;
+ float dist = co.z / co.w;
float p = 0.0;
-
+
if (dist <= moments.x)
p = 1.0;
- float variance = moments.y - (moments.x*moments.x);
- variance = max(variance, shadowbias/10.0);
+ float variance = moments.y - (moments.x * moments.x);
+ variance = max(variance, shadowbias / 10.0);
float d = moments.x - dist;
- float p_max = variance / (variance + d*d);
+ float p_max = variance / (variance + d * d);
// Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1]
- p_max = clamp((p_max-bleedbias)/(1.0-bleedbias), 0.0, 1.0);
+ p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0);
result = max(p, p_max);
}
@@ -2284,14 +2319,14 @@ void shadows_only_vsm(
void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result)
{
- vec4 co = shadowpersmat*vec4(rco, 1.0);
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
result = texture2DProj(cookie, co);
}
void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
{
- outcol = linfac*(1.0 - exp(col*logfac));
+ outcol = linfac * (1.0 - exp(col * logfac));
}
void shade_mist_factor(
@@ -2301,11 +2336,11 @@ void shade_mist_factor(
if (enable == 1.0) {
float fac, zcor;
- zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
-
+ zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
+
fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
if (misttype == 0.0) fac *= fac;
- else if (misttype == 1.0);
+ else if (misttype == 1.0) ;
else fac = sqrt(fac);
outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
@@ -2328,7 +2363,7 @@ void shade_alpha_opaque(vec4 col, out vec4 outcol)
void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
- outcol = vec4(col.rgb, col.a*obcol.a);
+ outcol = vec4(col.rgb, col.a * obcol.a);
}
/*********** NEW SHADER UTILITIES **************/
@@ -2343,9 +2378,9 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
if (g > 0.0) {
g = sqrt(g);
- float A =(g - c)/(g + c);
- float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0);
- result = 0.5 * A * A *(1.0 + B * B);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
+ result = 0.5 * A * A * (1.0 + B * B);
}
else {
result = 1.0; /* TIR (no refracted component) */
@@ -2356,7 +2391,7 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float hypot(float x, float y)
{
- return sqrt(x*x + y*y);
+ return sqrt(x * x + y * y);
}
void generated_from_orco(vec3 orco, out vec3 generated)
@@ -2364,6 +2399,17 @@ void generated_from_orco(vec3 orco, out vec3 generated)
generated = orco * 0.5 + vec3(0.5);
}
+int floor_to_int(float x)
+{
+ return int(floor(x));
+}
+
+int quick_floor(float x)
+{
+ return int(x) - ((x < 0) ? 1 : 0);
+}
+
+#ifdef BIT_OPERATIONS
float integer_noise(int n)
{
int nn;
@@ -2373,24 +2419,18 @@ float integer_noise(int n)
return 0.5 * (float(nn) / 1073741824.0);
}
-int floor_to_int(float x)
-{
- return int(floor(x));
-}
-
-#ifdef BIT_OPERATIONS
uint hash(uint kx, uint ky, uint kz)
{
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-#define final(a,b,c) \
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+#define final(a, b, c) \
{ \
- c ^= b; c -= rot(b,14); \
- a ^= c; a -= rot(c,11); \
- b ^= a; b -= rot(a,25); \
- c ^= b; c -= rot(b,16); \
- a ^= c; a -= rot(c,4); \
- b ^= a; b -= rot(a,14); \
- c ^= b; c -= rot(b,24); \
+ c ^= b; c -= rot(b, 14); \
+ a ^= c; a -= rot(c, 11); \
+ b ^= a; b -= rot(a, 25); \
+ c ^= b; c -= rot(b, 16); \
+ a ^= c; a -= rot(c, 4); \
+ b ^= a; b -= rot(a, 14); \
+ c ^= b; c -= rot(b, 24); \
}
// now hash the data!
uint a, b, c, len = 3u;
@@ -2399,7 +2439,7 @@ uint hash(uint kx, uint ky, uint kz)
c += kz;
b += ky;
a += kx;
- final(a, b, c);
+ final (a, b, c);
return c;
#undef rot
@@ -2419,9 +2459,9 @@ float bits_to_01(uint bits)
float cellnoise(vec3 p)
{
- int ix = floor_to_int(p.x);
- int iy = floor_to_int(p.y);
- int iz = floor_to_int(p.z);
+ int ix = quick_floor(p.x);
+ int iy = quick_floor(p.y);
+ int iz = quick_floor(p.z);
return bits_to_01(hash(uint(ix), uint(iy), uint(iz)));
}
@@ -2459,10 +2499,10 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float bsdf = max(dot(N, light_position), 0.0);
- L += light_diffuse*bsdf;
+ L += light_diffuse * bsdf;
}
- result = vec4(L*color.rgb, 1.0);
+ result = vec4(L * color.rgb, 1.0);
}
void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
@@ -2478,12 +2518,12 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 light_specular = gl_LightSource[i].specular.rgb;
/* we mix in some diffuse so low roughness still shows up */
- float bsdf = 0.5*pow(max(dot(N, H), 0.0), 1.0/roughness);
- bsdf += 0.5*max(dot(N, light_position), 0.0);
- L += light_specular*bsdf;
+ float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
+ bsdf += 0.5 * max(dot(N, light_position), 0.0);
+ L += light_specular * bsdf;
}
- result = vec4(L*color.rgb, 1.0);
+ result = vec4(L * color.rgb, 1.0);
}
void node_bsdf_anisotropic(
@@ -2548,7 +2588,7 @@ void node_ambient_occlusion(vec4 color, out vec4 result)
void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
{
- result = color*strength;
+ result = color * strength;
}
/* background */
@@ -2564,7 +2604,7 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
void node_background(vec4 color, float strength, vec3 N, out vec4 result)
{
- result = color*strength;
+ result = color * strength;
}
/* closures */
@@ -2584,10 +2624,10 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
void node_fresnel(float ior, vec3 N, vec3 I, out float result)
{
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing)? eta: 1.0/eta);
+ result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
}
/* layer_weight */
@@ -2596,15 +2636,15 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float
{
/* fresnel */
float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing)? 1.0/eta : eta );
+ fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
/* facing */
facing = abs(dot(I_view, N));
if (blend != 0.5) {
blend = clamp(blend, 0.0, 0.99999);
- blend = (blend < 0.5)? 2.0*blend: 0.5/(1.0 - blend);
+ blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
facing = pow(facing, blend);
}
facing = 1.0 - facing;
@@ -2628,12 +2668,9 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
- /* TODO(sergey): This needs linearization for vertex color.
- * But how to detect cases when input is linear and when it's srgb?
- */
outcol = vec4(attr, 1.0);
outvec = attr;
- outf = (attr.x + attr.y + attr.z)/3.0;
+ outf = (attr.x + attr.y + attr.z) / 3.0;
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2641,48 +2678,51 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec)
outvec = attr_uv;
}
-void node_geometry(vec3 I, vec3 N, mat4 toworld,
- out vec3 position, out vec3 normal, out vec3 tangent,
- out vec3 true_normal, out vec3 incoming, out vec3 parametric,
- out float backfacing, out float pointiness)
+void node_geometry(
+ vec3 I, vec3 N, mat4 toworld,
+ out vec3 position, out vec3 normal, out vec3 tangent,
+ out vec3 true_normal, out vec3 incoming, out vec3 parametric,
+ out float backfacing, out float pointiness)
{
- position = (toworld*vec4(I, 1.0)).xyz;
- normal = (toworld*vec4(N, 0.0)).xyz;
+ position = (toworld * vec4(I, 1.0)).xyz;
+ normal = (toworld * vec4(N, 0.0)).xyz;
tangent = vec3(0.0);
true_normal = normal;
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
- incoming = -(toworld*vec4(I_view, 0.0)).xyz;
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ incoming = -(toworld * vec4(I_view, 0.0)).xyz;
parametric = vec3(0.0);
- backfacing = (gl_FrontFacing)? 0.0: 1.0;
+ backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
pointiness = 0.0;
}
-void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
- vec3 attr_orco, vec3 attr_uv,
- out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
- out vec3 camera, out vec3 window, out vec3 reflection)
+void node_tex_coord(
+ vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
+ vec3 attr_orco, vec3 attr_uv,
+ out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
+ out vec3 camera, out vec3 window, out vec3 reflection)
{
generated = attr_orco * 0.5 + vec3(0.5);
- normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz);
+ normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz);
uv = attr_uv;
- object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz;
+ object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz;
camera = vec3(I.xy, -I.z);
vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
+ window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
vec3 shade_I;
shade_view(I, shade_I);
vec3 view_reflection = reflect(shade_I, normalize(N));
- reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz;
+ reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz;
}
-void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
- vec3 attr_orco, vec3 attr_uv,
- out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
- out vec3 camera, out vec3 window, out vec3 reflection)
+void node_tex_coord_background(
+ vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
+ vec3 attr_orco, vec3 attr_uv,
+ out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
+ out vec3 camera, out vec3 window, out vec3 reflection)
{
vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
@@ -2698,9 +2738,9 @@ void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, v
object = coords;
camera = vec3(co.xy, -co.z);
- window = (gl_ProjectionMatrix[3][3] == 0.0) ?
- vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
- vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
+ window = (gl_ProjectionMatrix[3][3] == 0.0) ?
+ vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
+ vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
reflection = -coords;
}
@@ -2718,12 +2758,12 @@ float calc_gradient(vec3 p, int gradient_type)
}
else if (gradient_type == 1) { /* quadratic */
float r = max(x, 0.0);
- return r*r;
+ return r * r;
}
else if (gradient_type == 2) { /* easing */
float r = min(max(x, 0.0), 1.0);
- float t = r*r;
- return (3.0*t - 2.0*t*r);
+ float t = r * r;
+ return (3.0 * t - 2.0 * t * r);
}
else if (gradient_type == 3) { /* diagonal */
return (x + y) * 0.5;
@@ -2732,9 +2772,9 @@ float calc_gradient(vec3 p, int gradient_type)
return atan(y, x) / (M_PI * 2) + 0.5;
}
else {
- float r = max(1.0 - sqrt(x*x + y*y + z*z), 0.0);
+ float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0);
if (gradient_type == 5) { /* quadratic sphere */
- return r*r;
+ return r * r;
}
else if (gradient_type == 6) { /* sphere */
return r;
@@ -2757,20 +2797,21 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
vec3 p = co * scale;
/* Prevent precision issues on unit coordinates. */
- p.x = (p.x + 0.000001)*0.999999;
- p.y = (p.y + 0.000001)*0.999999;
- p.z = (p.z + 0.000001)*0.999999;
+ p.x = (p.x + 0.000001) * 0.999999;
+ p.y = (p.y + 0.000001) * 0.999999;
+ p.z = (p.z + 0.000001) * 0.999999;
- int xi = abs(int(floor(p.x)));
- int yi = abs(int(floor(p.y)));
- int zi = abs(int(floor(p.z)));
+ int xi = int(abs(floor(p.x)));
+ int yi = int(abs(floor(p.y)));
+ int zi = int(abs(floor(p.z)));
- bool check = ((xi % 2 == yi % 2) == bool(zi % 2));
+ bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
color = check ? color1 : color2;
fac = check ? 1.0 : 0.0;
}
+#ifdef BIT_OPERATIONS
vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
float brick_width, float row_height,
float offset_amount, int offset_frequency,
@@ -2784,19 +2825,20 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
if (offset_frequency != 0 && squash_frequency != 0) {
brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
- offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width*offset_amount); /* offset */
+ offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
}
- bricknum = floor_to_int((p.x+offset) / brick_width);
+ bricknum = floor_to_int((p.x + offset) / brick_width);
- x = (p.x+offset) - brick_width*bricknum;
- y = p.y - row_height*rownum;
+ x = (p.x + offset) - brick_width * bricknum;
+ y = p.y - row_height * rownum;
return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0),
(x < mortar_size || y < mortar_size ||
x > (brick_width - mortar_size) ||
y > (row_height - mortar_size)) ? 1.0 : 0.0);
}
+#endif
void node_tex_brick(vec3 co,
vec4 color1, vec4 color2,
@@ -2807,7 +2849,8 @@ void node_tex_brick(vec3 co,
float squash_amount, float squash_frequency,
out vec4 color, out float fac)
{
- vec2 f2 = calc_brick_texture(co*scale,
+#ifdef BIT_OPERATIONS
+ vec2 f2 = calc_brick_texture(co * scale,
mortar_size, bias,
brick_width, row_height,
offset_amount, int(offset_frequency),
@@ -2820,6 +2863,10 @@ void node_tex_brick(vec3 co,
}
color = (f == 1.0) ? mortar : color1;
fac = f;
+#else
+ color = vec4(1.0);
+ fac = 1.0;
+#endif
}
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@ -2831,8 +2878,8 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color)
{
vec3 nco = normalize(co);
- float u = -atan(nco.y, nco.x)/(2.0*M_PI) + 0.5;
- float v = atan(nco.z, hypot(nco.x, nco.y))/M_PI + 0.5;
+ float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
color = texture2D(ima, vec2(u, v));
}
@@ -2843,12 +2890,12 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
nco.y -= 1.0;
- float div = 2.0*sqrt(max(-0.5*nco.y, 0.0));
+ float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
if (div > 0.0)
nco /= div;
- float u = 0.5*(nco.x + 1.0);
- float v = 0.5*(nco.z + 1.0);
+ float u = 0.5 * (nco.x + 1.0);
+ float v = 0.5 * (nco.z + 1.0);
color = texture2D(ima, vec2(u, v));
}
@@ -2864,6 +2911,82 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
alpha = color.a;
}
+void node_tex_image_box(vec3 texco,
+ vec3 nob,
+ sampler2D ima,
+ float blend,
+ out vec4 color,
+ out float alpha)
+{
+ /* project from direction vector to barycentric coordinates in triangles */
+ nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z));
+ nob /= (nob.x + nob.y + nob.z);
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * the Nxyz values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending, in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if () test for each zone */
+
+ vec3 weight = vec3(0.0, 0.0, 0.0);
+ float limit = 0.5 * (1.0 + blend);
+
+ /* first test for corners with single texture */
+ if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) {
+ weight.x = 1.0;
+ }
+ else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) {
+ weight.y = 1.0;
+ }
+ else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) {
+ weight.z = 1.0;
+ }
+ else if (blend > 0.0) {
+ /* in case of blending, test for mixes between two textures */
+ if (nob.z < (1.0 - limit) * (nob.y + nob.x)) {
+ weight.x = nob.x / (nob.x + nob.y);
+ weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.y = 1.0 - weight.x;
+ }
+ else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) {
+ weight.y = nob.y / (nob.y + nob.z);
+ weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.z = 1.0 - weight.y;
+ }
+ else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) {
+ weight.x = nob.x / (nob.x + nob.z);
+ weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.z = 1.0 - weight.x;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0);
+ }
+ }
+ else {
+ /* Desperate mode, no valid choice anyway, fallback to one side.*/
+ weight.x = 1.0;
+ }
+ color = vec4(0);
+ if (weight.x > 0.0) {
+ color += weight.x * texture2D(ima, texco.yz);
+ }
+ if (weight.y > 0.0) {
+ color += weight.y * texture2D(ima, texco.xz);
+ }
+ if (weight.z > 0.0) {
+ color += weight.z * texture2D(ima, texco.yx);
+ }
+
+ alpha = color.a;
+}
+
void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
{
color = vec4(0.0);
@@ -2873,42 +2996,42 @@ void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
{
vec3 p = co * scale;
- float x = sin((p.x + p.y + p.z)*5.0);
- float y = cos((-p.x + p.y - p.z)*5.0);
- float z = -cos((-p.x - p.y + p.z)*5.0);
+ float x = sin((p.x + p.y + p.z) * 5.0);
+ float y = cos((-p.x + p.y - p.z) * 5.0);
+ float z = -cos((-p.x - p.y + p.z) * 5.0);
if (depth > 0) {
x *= distortion;
y *= distortion;
z *= distortion;
- y = -cos(x-y+z);
+ y = -cos(x - y + z);
y *= distortion;
if (depth > 1) {
- x = cos(x-y-z);
+ x = cos(x - y - z);
x *= distortion;
if (depth > 2) {
- z = sin(-x-y-z);
+ z = sin(-x - y - z);
z *= distortion;
if (depth > 3) {
- x = -cos(-x+y-z);
+ x = -cos(-x + y - z);
x *= distortion;
if (depth > 4) {
- y = -sin(-x+y+z);
+ y = -sin(-x + y + z);
y *= distortion;
if (depth > 5) {
- y = -cos(-x+y+z);
+ y = -cos(-x + y + z);
y *= distortion;
if (depth > 6) {
- x = cos(x+y+z);
+ x = cos(x + y + z);
x *= distortion;
if (depth > 7) {
- z = sin(x+y-z);
+ z = sin(x + y - z);
z *= distortion;
if (depth > 8) {
- x = -cos(-x-y+z);
+ x = -cos(-x - y + z);
x *= distortion;
if (depth > 9) {
- y = -sin(x-y+z);
+ y = -sin(x - y + z);
y *= distortion;
}
}
@@ -2927,7 +3050,7 @@ void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec
z /= distortion;
}
- color = vec4(0.5 - x, 0.5 - y, 0.f - z, 1.0);
+ color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
fac = (color.x + color.y + color.z) / 3.0;
}
@@ -2968,14 +3091,14 @@ float noise_perlin(float x, float y, float z)
float result;
- result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz ),
- noise_grad(hash(X+1, Y, Z), fx-1.0, fy, fz)),
- noise_nerp(u, noise_grad(hash(X, Y+1, Z), fx, fy - 1.0, fz),
- noise_grad(hash(X+1, Y+1, Z), fx-1.0, fy-1.0, fz))),
- noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z+1), fx, fy, fz-1.0),
- noise_grad(hash(X+1, Y, Z+1), fx-1.0, fy, fz-1.0)),
- noise_nerp(u, noise_grad(hash(X, Y+1, Z+1), fx, fy-1.0, fz-1.0),
- noise_grad(hash(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0))));
+ result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz),
+ noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz)),
+ noise_nerp(u, noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz),
+ noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz))),
+ noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0),
+ noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)),
+ noise_nerp(u, noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0),
+ noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0))));
return noise_scale3(result);
}
@@ -2998,27 +3121,27 @@ float noise_turbulence(vec3 p, float octaves, int hard)
octaves = clamp(octaves, 0.0, 16.0);
n = int(octaves);
for (i = 0; i <= n; i++) {
- float t = noise(fscale*p);
+ float t = noise(fscale * p);
if (hard != 0) {
- t = abs(2.0*t - 1.0);
+ t = abs(2.0 * t - 1.0);
}
- sum += t*amp;
+ sum += t * amp;
amp *= 0.5;
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
- float t = noise(fscale*p);
+ float t = noise(fscale * p);
if (hard != 0) {
- t = abs(2.0*t - 1.0);
+ t = abs(2.0 * t - 1.0);
}
- float sum2 = sum + t*amp;
- sum *= (float(1 << n) / float((1 << (n+1)) - 1));
- sum2 *= (float(1 << (n+1)) / float((1 << (n+2)) - 1));
- return (1.0 - rmd)*sum + rmd*sum2;
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
}
else {
- sum *= (float(1 << n) / float((1 << (n+1)) - 1));
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
return sum;
}
}
@@ -3224,15 +3347,15 @@ float svm_musgrave(int type,
vec3 p)
{
if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
- return intensity*noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
+ return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
- return intensity*noise_musgrave_fBm(p, dimension, lacunarity, octaves);
+ return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
- return intensity*noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
- return intensity*noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
- return intensity*noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+ return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
return 0.0;
}
#endif // #ifdef BIT_OPERATIONS
@@ -3256,7 +3379,7 @@ void node_tex_musgrave(vec3 co,
offset,
1.0,
gain,
- co*scale);
+ co * scale);
#else
fac = 1.0;
#endif
@@ -3353,7 +3476,7 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int
n = length(p) * 20.0;
if (distortion != 0.0)
- n += distortion * noise_turbulence(p*detail_scale, detail, 0);
+ n += distortion * noise_turbulence(p * detail_scale, detail, 0);
if (wave_profile == 0) { /* profile sin */
return 0.5 + 0.5 * sin(n);
@@ -3361,7 +3484,7 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int
else { /* profile saw */
n /= 2.0 * M_PI;
n -= int(n);
- return (n < 0.0)? n + 1.0: n;
+ return (n < 0.0) ? n + 1.0 : n;
}
}
#endif // BIT_OPERATIONS
@@ -3372,7 +3495,7 @@ void node_tex_wave(
{
#ifdef BIT_OPERATIONS
float f;
- f = calc_wave(co*scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
+ f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
color = vec4(f, f, f, 1.0);
fac = f;
@@ -3451,12 +3574,12 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos,
float dHdx = dFdx(height);
float dHdy = dFdy(height);
- vec3 surfgrad = dHdx*Rx + dHdy*Ry;
+ vec3 surfgrad = dHdx * Rx + dHdy * Ry;
strength = max(strength, 0.0);
- result = normalize(absdet*N - dist*sign(det)*surfgrad);
- result = normalize(strength*result + (1.0 - strength)*N);
+ result = normalize(absdet * N - dist * sign(det) * surfgrad);
+ result = normalize(strength * result + (1.0 - strength) * N);
}
/* output */
@@ -3479,7 +3602,7 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v
vec2 tex;
#ifndef USE_OPENSUBDIV
- /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
+ /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
* between shader stages and we want the full range of the normal */
normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
if (normal.z < 0.0) {
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
index 5f406c959f1..b485d2cce86 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
@@ -4,13 +4,13 @@ uniform sampler2D textureSource;
void main()
{
vec4 color = vec4(0.0);
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y ) ) * 0.015625;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y ) ) * 0.09375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y ) ) * 0.234375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y ) ) * 0.234375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y ) ) * 0.09375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y ) ) * 0.015625;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625;
gl_FragColor = color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
index 9bb2e7ad469..5d00108b052 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
@@ -1,6 +1,6 @@
void main()
{
- gl_Position = ftransform();
- gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = ftransform();
+ gl_TexCoord[0] = gl_MultiTexCoord0;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 5824d5a80db..9a6537b4f09 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,6 +14,68 @@ varying vec3 varnormal;
varying float gl_ClipDistance[6];
#endif
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+ else
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+}
+
+void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+ col_to.a = col_from.a;
+}
+
+bool is_srgb(int info)
+{
+#ifdef USE_NEW_SHADING
+ return (info == 1)? true: false;
+#else
+ return false;
+#endif
+}
+
+void set_var_from_attr(float attr, int info, out float var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec2 attr, int info, out vec2 var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec3 attr, int info, out vec3 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+void set_var_from_attr(vec4 attr, int info, out vec4 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
void main()
{
#ifndef USE_OPENSUBDIV
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
index 4838289ff9e..3761bf350eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
@@ -15,7 +15,7 @@ void main()
// Adjusting moments using partial derivative
float dx = dFdx(depth);
float dy = dFdy(depth);
- moment2 += 0.25*(dx*dx+dy*dy);
+ moment2 += 0.25 * (dx * dx + dy * dy);
gl_FragColor = vec4(moment1, moment2, 0.0, 0.0);
}
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index f4763883489..d89393b9903 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -83,18 +83,10 @@
# include <libswscale/swscale.h>
#endif
-/* actually hard coded endianness */
-#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
-#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
-#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
-#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
-
/* more endianness... should move to a separate file... */
#ifdef __BIG_ENDIAN__
-# define GET_ID GET_BIG_LONG
# define LITTLE_LONG SWAP_LONG
#else
-# define GET_ID GET_LITTLE_LONG
# define LITTLE_LONG ENDIAN_NOP
#endif
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 321ff26f68f..5b533d1ec48 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -298,7 +298,7 @@ typedef struct View3D {
#define RV3D_VIEW_CAMERA 8
#define RV3D_VIEW_IS_AXIS(view) \
- ((view >= RV3D_VIEW_FRONT) && (view <= RV3D_VIEW_BOTTOM))
+ (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM))
/* View3d->flag2 (short) */
#define V3D_RENDER_OVERRIDE (1 << 2)
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 09f4ea1cf02..f623416f673 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -955,6 +955,7 @@ bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBas
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int array_dim, int index);
char *RNA_path_resolve_from_type_to_property(
struct PointerRNA *ptr, struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 97c71715349..c49a6197a4e 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -4642,7 +4642,47 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
return ptrpath;
}
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+static void rna_path_array_multi_from_flat_index(
+ const int dimsize[RNA_MAX_ARRAY_LENGTH], const int totdims,
+ const int index_dim, int index,
+ int r_index_multi[RNA_MAX_ARRAY_LENGTH])
+{
+ int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1];
+ int i = totdims - 1;
+ dimsize_step[i + 1] = 1;
+ dimsize_step[i] = dimsize[i];
+ while (--i != -1) {
+ dimsize_step[i] = dimsize[i] * dimsize_step[i + 1];
+ }
+ while (++i != index_dim) {
+ int index_round = index / dimsize_step[i + 1];
+ r_index_multi[i] = index_round;
+ index -= (index_round * dimsize_step[i + 1]);
+ }
+ BLI_assert(index == 0);
+}
+
+static void rna_path_array_multi_string_from_flat_index(
+ PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index,
+ char *index_str, int index_str_len)
+{
+ int dimsize[RNA_MAX_ARRAY_LENGTH];
+ int totdims = RNA_property_array_dimension(ptr, prop, dimsize);
+ int index_multi[RNA_MAX_ARRAY_LENGTH];
+
+ rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi);
+
+ for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) {
+ offset += BLI_snprintf_rlen(&index_str[offset], index_str_len - offset, "[%d]", index_multi[i]);
+ }
+}
+
+/**
+ * \param index_dim: The dimensiuon to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a ``index_dim > 0``,
+ * this is expanded when used with multi-dimensional arrays.
+ */
+char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
{
const bool is_rna = (prop->magic == RNA_MAGIC);
const char *propname;
@@ -4656,25 +4696,36 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
propname = RNA_property_identifier(prop);
+ /* support indexing w/ multi-dimensional arrays */
+ char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1];
+ if (index_dim == 0) {
+ index_str[0] = '\0';
+ }
+ else {
+ rna_path_array_multi_string_from_flat_index(
+ ptr, prop, index_dim, index,
+ index_str, sizeof(index_str));
+ }
+
if (ptrpath) {
if (is_rna) {
- path = BLI_sprintfN("%s.%s", ptrpath, propname);
+ path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str);
}
else {
char propname_esc[MAX_IDPROP_NAME * 2];
BLI_strescape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("%s[\"%s\"]", ptrpath, propname_esc);
+ path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str);
}
MEM_freeN(ptrpath);
}
else if (RNA_struct_is_ID(ptr->type)) {
if (is_rna) {
- path = BLI_strdup(propname);
+ path = BLI_sprintfN("%s%s", propname, index_str);
}
else {
char propname_esc[MAX_IDPROP_NAME * 2];
BLI_strescape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("[\"%s\"]", propname_esc);
+ path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str);
}
}
else {
@@ -4684,6 +4735,11 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
return path;
}
+char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+{
+ return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
+}
+
/**
* \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL).
*/
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index dcb4d65f3f9..678b0ac8f1f 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -131,8 +131,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 3);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1e4f, 1, 3);
RNA_def_property_ui_text(prop, "Interocular Distance",
"Set the distance between the eyes - the stereo plane distance / 30 should be fine");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index d28dd8f7607..cb7a40a9238 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1009,13 +1009,15 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xof");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "X Offset", "Horizontal offset from the object origin");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "yof");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Y Offset", "Vertical offset from the object origin");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
@@ -1117,25 +1119,29 @@ static void rna_def_textbox(BlenderRNA *brna)
/* number values */
prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "x");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox X Offset", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "y");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Y Offset", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "w");
- RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Width", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "h");
- RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Height", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index bd14f206665..dffdd7fe6c7 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -802,6 +802,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, ReportList *reports,
ntreeUpdateTree(G.main, ntree);
+ ED_node_tag_update_nodetree(G.main, ntree, ret->tonode);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 26cfc396cca..84360ba4386 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -649,7 +649,7 @@ void RNA_api_object(StructRNA *srna)
#endif /* NDEBUG */
func = RNA_def_function(srna, "update_from_editmode", "rna_Object_update_from_editmode");
- RNA_def_function_ui_description(func, "Load the objects edit-mode data intp the object data");
+ RNA_def_function_ui_description(func, "Load the objects edit-mode data into the object data");
parm = RNA_def_boolean(func, "result", 0, "", "Success");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 74fb4a08eda..e1216e3c85f 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -196,6 +196,7 @@ static void rna_Scene_collada_export(
int use_ngons,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
int export_transformation_type,
int open_sim)
@@ -203,7 +204,7 @@ static void rna_Scene_collada_export(
collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected,
include_children, include_armatures, include_shapekeys, deform_bones_only,
active_uv_only, include_uv_textures, include_material_textures,
- use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, export_transformation_type, open_sim);
+ use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim);
}
#endif
@@ -286,6 +287,7 @@ void RNA_api_scene(StructRNA *srna)
parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export");
parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data");
+ parm = RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)");
parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 68d4f7f7e51..c3a66058888 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2327,6 +2327,7 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "text_size");
RNA_def_property_ui_text(prop, "Size", "Size of the text");
+ RNA_def_property_range(prop, 0.0, 2000);
RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 41ebd865720..df94975e274 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -73,7 +73,7 @@ typedef struct ScrewVertIter {
#define SV_UNUSED (UINT_MAX)
#define SV_INVALID ((UINT_MAX) - 1)
-#define SV_IS_VALID(v) (v < SV_INVALID)
+#define SV_IS_VALID(v) ((v) < SV_INVALID)
static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, unsigned int v_init, unsigned int dir)
{
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c
index 49ebb15d7a4..3bdb5c36d69 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.c
@@ -54,7 +54,15 @@ static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSE
static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "camera", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ GPUNodeLink *viewvec;
+
+ viewvec = GPU_builtin(GPU_VIEW_POSITION);
+
+ /* Blender has negative Z, Cycles positive Z convention */
+ if (GPU_material_use_new_shading_nodes(mat))
+ GPU_link(mat, "invert_z", viewvec, &viewvec);
+
+ return GPU_stack_link(mat, "camera", in, out, viewvec);
}
void register_node_type_sh_camera(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index d2695609a88..85e2c77662d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -133,29 +133,33 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
/* **************** CYCLES ******************** */
- GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
-
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
- break;
+ GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link);
+ /* for uniform scale this is sufficient to match Cycles */
+ GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ return true;
case SHD_NORMAL_MAP_OBJECT:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
break;
case SHD_NORMAL_MAP_BLENDER_OBJECT:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm);
GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
break;
case SHD_NORMAL_MAP_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
break;
case SHD_NORMAL_MAP_BLENDER_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm);
break;
-
- GPU_link(mat, "vect_normalize", realnorm, &realnorm);
}
} else {
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index f0a8cda045e..71200dfe9d3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -59,17 +59,49 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
Image *ima = (Image *)node->id;
ImageUser *iuser = NULL;
NodeTexImage *tex = node->storage;
+
+ GPUNodeLink *norm;
+
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
+ float blend = tex->projection_blend;
if (!ima)
return GPU_stack_link(mat, "node_tex_image_empty", in, out);
-
+
if (!in[0].link)
in[0].link = GPU_attribute(CD_MTFACE, "");
node_shader_gpu_tex_mapping(mat, node, in, out);
- GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ switch (tex->projection) {
+ case SHD_PROJ_FLAT:
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ case SHD_PROJ_BOX:
+ GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ &norm);
+ GPU_link(mat, "direction_transform_m4v3", norm,
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ &norm);
+ GPU_link(mat, "node_tex_image_box", in[0].link,
+ norm,
+ GPU_image(ima, iuser, isdata),
+ GPU_uniform(&blend),
+ &out[0].link,
+ &out[1].link);
+ break;
+ case SHD_PROJ_SPHERE:
+ GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+ GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ case SHD_PROJ_TUBE:
+ GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+ GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ }
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 33ac58dadb1..49b806347d6 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -973,7 +973,9 @@ static PyObject *pyrna_prop_str(BPy_PropertyRNA *self)
RNA_property_identifier(self->prop));
}
-static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_repr_ex(
+ BPy_PropertyRNA *self,
+ const int index_dim, const int index)
{
ID *id = self->ptr.id.data;
PyObject *tmp_str;
@@ -987,7 +989,8 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
tmp_str = PyUnicode_FromString(id->name + 2);
- path = RNA_path_from_ID_to_property(&self->ptr, self->prop);
+ path = RNA_path_from_ID_to_property_index(&self->ptr, self->prop, index_dim, index);
+
if (path) {
const char *data_delim = (path[0] == '[') ? "" : ".";
if (GS(id->name) == ID_NT) { /* nodetree paths are not accurate */
@@ -1015,6 +1018,15 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
return ret;
}
+static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
+{
+ return pyrna_prop_repr_ex(self, 0, -1);
+}
+
+static PyObject *pyrna_prop_array_repr(BPy_PropertyArrayRNA *self)
+{
+ return pyrna_prop_repr_ex((BPy_PropertyRNA *)self, self->arraydim, self->arrayoffset);
+}
static PyObject *pyrna_func_repr(BPy_FunctionRNA *self)
{
@@ -5841,7 +5853,7 @@ PyTypeObject pyrna_prop_array_Type = {
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
- NULL, /* subclassed */ /* tp_repr */
+ (reprfunc)pyrna_prop_array_repr, /* tp_repr */
/* Method suites for standard classes */
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 9ae5a4bd61d..542a0e349c7 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -41,7 +41,7 @@ extern PyTypeObject matrix_access_Type;
# define MATRIX_ITEM_ASSERT(_mat, _row, _col) (void)0
#endif
-#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) ((_totrow * (_col)) + (_row))
+#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) (((_totrow) * (_col)) + (_row))
#define MATRIX_ITEM_INDEX(_mat, _row, _col) (MATRIX_ITEM_ASSERT(_mat, _row, _col),(((_mat)->num_row * (_col)) + (_row)))
#define MATRIX_ITEM_PTR( _mat, _row, _col) ((_mat)->matrix + MATRIX_ITEM_INDEX(_mat, _row, _col))
#define MATRIX_ITEM( _mat, _row, _col) ((_mat)->matrix [MATRIX_ITEM_INDEX(_mat, _row, _col)])
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index db2547e4fbe..388837af67a 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -220,6 +220,7 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *wi
/* invoke callback, uses enum property named "type" */
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
+int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, confirm menu + exec */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 6ef8965a408..b4295bb2607 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1068,7 +1068,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op)
}
/* invoke callback, uses enum property named "type" */
-int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
{
PropertyRNA *prop = op->type->prop;
uiPopupMenu *pup;
@@ -1090,8 +1090,8 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = UI_popup_menu_layout(pup);
/* set this so the default execution context is the same as submenus */
- uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
- uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0);
+ uiLayoutSetOperatorContext(layout, opcontext);
+ uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, opcontext, 0);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
@@ -1099,6 +1099,11 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
return OPERATOR_CANCELLED;
}
+int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
+}
+
/* generic enum search invoke popup */
static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 449612bc5fd..e2b95da29a1 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -343,37 +343,38 @@ enum {
/* *********** wmEvent.type helpers. ********** */
/* test whether the event is timer event */
-#define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF)
+#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF)
/* for event checks */
/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
/* UNUSED - see wm_eventmatch - BUG [#30479] */
-/* #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) */
+/* #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255) */
/* note, an alternative could be to check 'event->utf8_buf' */
/* test whether the event is a key on the keyboard */
#define ISKEYBOARD(event_type) \
- ((event_type >= 0x0020 && event_type <= 0x00ff) || \
- (event_type >= 0x012c && event_type <= 0x013f))
+ (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \
+ ((event_type) >= 0x012c && (event_type) <= 0x013f))
/* test whether the event is a modifier key */
-#define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY)
+#define ISKEYMODIFIER(event_type) \
+ (((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) || (event_type) == OSKEY)
/* test whether the event is a mouse button */
-#define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= BUTTON7MOUSE)
+#define ISMOUSE(event_type) ((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE)
/* test whether the event is tweak event */
-#define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE)
+#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_GESTURE)
/* test whether the event is a NDOF event */
-#define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST)
+#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST)
/* test whether event type is acceptable as hotkey, excluding modifiers */
#define ISHOTKEY(event_type) \
((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \
- (event_type != ESCKEY) && \
- (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \
- (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false)
+ ((event_type) != ESCKEY) && \
+ ((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) == false && \
+ ((event_type) >= UNKNOWNKEY && (event_type) <= GRLESSKEY) == false)
/* internal helpers*/
#define _VA_IS_EVENT_MOD2(v, a) (CHECK_TYPE_INLINE(v, wmEvent *), \
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index eb0289e6909..6762e6752b0 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -707,6 +707,7 @@ int collada_export(struct Scene *sce,
int triangulate,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim) RET_ZERO