Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2022-03-24 00:24:46 +0300
committerJoseph Eagar <joeedh@gmail.com>2022-03-24 00:24:46 +0300
commit2f3ace40240797100161a659a12d995e1480b91b (patch)
tree89009e559a038b6788024076ed5e9743ed2b4c10 /source/blender
parentf42d3caecdde37bdc873a66fbdc5685bf7050fb1 (diff)
parentd84b4becd3bce34b75385155535b17d77f68578a (diff)
Merge branch 'master' into temp-sculpt-colors
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_image_format.h17
-rw-r--r--source/blender/blenkernel/BKE_image_save.h3
-rw-r--r--source/blender/blenkernel/BKE_key.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h15
-rw-r--r--source/blender/blenkernel/intern/armature.c4
-rw-r--r--source/blender/blenkernel/intern/curve.cc92
-rw-r--r--source/blender/blenkernel/intern/image_format.cc58
-rw-r--r--source/blender/blenkernel/intern/image_save.cc142
-rw-r--r--source/blender/blenkernel/intern/key.c113
-rw-r--r--source/blender/blenkernel/intern/mesh.cc1
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc32
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc1
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c1
-rw-r--r--source/blender/blenkernel/intern/object.cc6
-rw-r--r--source/blender/blenlib/BLI_math_geom.h24
-rw-r--r--source/blender/blenlib/intern/math_geom.c38
-rw-r--r--source/blender/blenlib/tests/BLI_math_vector_test.cc2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h13
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c2
-rw-r--r--source/blender/compositor/COM_compositor.h8
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.cc2
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h36
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc5
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc14
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc13
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cc5
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.cc3
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cc5
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc47
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h10
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc31
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h10
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c4
-rw-r--r--source/blender/draw/engines/overlay/shaders/background_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl2
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh2
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc7
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc18
-rw-r--r--source/blender/draw/intern/shaders/common_gpencil_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl4
-rw-r--r--source/blender/draw/intern/shaders/common_math_geom_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl4
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/keyingsets.c67
-rw-r--r--source/blender/editors/interface/interface_ops.c3
-rw-r--r--source/blender/editors/interface/interface_templates.c7
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c1
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1
-rw-r--r--source/blender/editors/object/object_modifier.c2
-rw-r--r--source/blender/editors/object/object_transform.cc2
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc232
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc367
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh23
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c4
-rw-r--r--source/blender/editors/space_image/image_buttons.c30
-rw-r--r--source/blender/editors/space_image/image_ops.c25
-rw-r--r--source/blender/editors/space_node/node_edit.cc19
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc20
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c451
-rw-r--r--source/blender/editors/transform/transform_snap_object.c67
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c235
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c1
-rw-r--r--source/blender/freestyle/CMakeLists.txt2
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp14
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.cpp1294
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.h89
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c1
-rw-r--r--source/blender/gpu/CMakeLists.txt70
-rw-r--r--source/blender/gpu/GPU_context.h15
-rw-r--r--source/blender/gpu/GPU_platform.h14
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh6
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_context.cc73
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc13
-rw-r--r--source/blender/gpu/intern/gpu_platform_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc10
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c6
-rw-r--r--source/blender/gpu/metal/mtl_backend.hh79
-rw-r--r--source/blender/gpu/metal/mtl_backend.mm408
-rw-r--r--source/blender/gpu/metal/mtl_capabilities.hh47
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc8
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh5
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc7
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.cc2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl9
-rw-r--r--source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl17
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h23
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h3
-rw-r--r--source/blender/imbuf/intern/colormanagement.c117
-rw-r--r--source/blender/io/alembic/ABC_alembic.h2
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc1
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.h2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h2
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc7
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp2
-rw-r--r--source/blender/io/collada/collada_utils.cpp1
-rw-r--r--source/blender/io/usd/intern/usd_reader_geom.h2
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h2
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc14
-rw-r--r--source/blender/makesdna/DNA_scene_types.h6
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_color.c5
-rw-r--r--source/blender/makesrna/intern/rna_curve_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c6
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c14
-rw-r--r--source/blender/makesrna/intern/rna_internal.h8
-rw-r--r--source/blender/makesrna/intern/rna_scene.c58
-rw-r--r--source/blender/makesrna/intern/rna_texture.c16
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c6
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c2
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc1
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c5
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.cc (renamed from source/blender/modifiers/intern/MOD_meshsequencecache.c)93
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c1
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_output_file.cc16
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.cc21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc10
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c23
-rw-r--r--source/blender/python/intern/bpy_props.c25
-rw-r--r--source/blender/render/RE_pipeline.h4
-rw-r--r--source/blender/render/RE_texture_margin.h2
-rw-r--r--source/blender/render/intern/pipeline.c31
-rw-r--r--source/blender/render/intern/render_result.c7
-rw-r--r--source/blender/sequencer/intern/strip_transform.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c5
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c38
184 files changed, 2890 insertions, 2572 deletions
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 394d97223e3..42897c59043 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -274,7 +274,7 @@ bool BKE_nurb_valid_message(int pnts,
short flag,
short type,
bool is_surf,
- const char *dir,
+ int dir,
char *message_dst,
size_t maxncpy);
diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h
index 189d2db1b4f..633af54ea4f 100644
--- a/source/blender/blenkernel/BKE_image_format.h
+++ b/source/blender/blenkernel/BKE_image_format.h
@@ -16,6 +16,7 @@ struct BlendWriter;
struct ImbFormatOptions;
struct ImageFormatData;
struct ImBuf;
+struct Scene;
/* Init/Copy/Free */
@@ -75,6 +76,22 @@ char BKE_imtype_from_arg(const char *arg);
void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf);
+/* Color Management */
+
+void BKE_image_format_color_management_copy(struct ImageFormatData *imf,
+ const struct ImageFormatData *imf_src);
+void BKE_image_format_color_management_copy_from_scene(struct ImageFormatData *imf,
+ const struct Scene *scene);
+
+/* Image Output
+ *
+ * Initialize an image format that can be used for file writing, including
+ * color management settings from the scene. */
+
+void BKE_image_format_init_for_write(struct ImageFormatData *imf,
+ const struct Scene *scene_src,
+ const struct ImageFormatData *imf_src);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h
index f9d07387463..b022e677845 100644
--- a/source/blender/blenkernel/BKE_image_save.h
+++ b/source/blender/blenkernel/BKE_image_save.h
@@ -47,7 +47,7 @@ bool BKE_image_save(struct ReportList *reports,
struct ImageUser *iuser,
struct ImageSaveOptions *opts);
-/* Lower level image writing. */
+/* Render saving. */
/* Save single or multilayer OpenEXR files from the render result.
* Optionally saves only a specific view or layer. */
@@ -55,6 +55,7 @@ bool BKE_image_render_write_exr(struct ReportList *reports,
const struct RenderResult *rr,
const char *filename,
const struct ImageFormatData *imf,
+ const bool save_as_render,
const char *view,
int layer);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index da436b7d33f..bf9e7651e36 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -13,6 +13,7 @@ struct Lattice;
struct ListBase;
struct Main;
struct Mesh;
+struct MVert;
struct Object;
/* Kernel prototypes */
@@ -119,7 +120,8 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb);
-void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct MVert *mvert, int totvert);
+
/**
* Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
*
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 2373bb289cd..0ba9713b96d 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -472,6 +472,21 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
float (*r_poly_normals)[3]);
/**
+ * Calculate face and vertex normals directly into result arrays.
+ *
+ * \note Usually #BKE_mesh_vertex_normals_ensure is the preferred way to access vertex normals,
+ * since they may already be calculated and cached on the mesh.
+ */
+void BKE_mesh_calc_normals_poly_and_vertex(const struct MVert *mvert,
+ int mvert_len,
+ const struct MLoop *mloop,
+ int mloop_len,
+ const struct MPoly *mpoly,
+ int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3]);
+
+/**
* Calculate vertex and face normals, storing the result in custom data layers on the mesh.
*
* \note It is usually preferable to calculate normals lazily with
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 5c2d77f20a8..0a6ef8f0f01 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2164,8 +2164,8 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m
const float y = nor[1];
const float z = nor[2];
- float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
- const float theta_alt = x * x + z * z; /* squared distance from origin in x,z plane. */
+ float theta = 1.0f + y; /* Remapping Y from [-1,+1] to [0,2]. */
+ const float theta_alt = x * x + z * z; /* Squared distance from origin in x,z plane. */
float rMatrix[3][3], bMatrix[3][3];
BLI_ASSERT_UNIT_V3(nor);
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 0b619c1a969..354ddd7d167 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -62,6 +62,14 @@ using blender::IndexRange;
/* local */
// static CLG_LogRef LOG = {"bke.curve"};
+enum class NURBSValidationStatus {
+ Valid,
+ AtLeastTwoPointsRequired,
+ MorePointsThanOrderRequired,
+ MoreRowsForBezierRequired,
+ MorePointsForBezierRequired
+};
+
static void curve_init_data(ID *id)
{
Curve *curve = (Curve *)id;
@@ -4700,56 +4708,94 @@ void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, const float *key)
}
}
-bool BKE_nurb_valid_message(const int pnts,
- const short order,
- const short flag,
- const short type,
- const bool is_surf,
- const char *dir,
- char *message_dst,
- const size_t maxncpy)
+static NURBSValidationStatus nurb_check_valid(const int pnts,
+ const short order,
+ const short flag,
+ const short type,
+ const bool is_surf,
+ int *r_points_needed)
{
- const char *msg_template = "";
- uint16_t points_needed = 0;
-
if (pnts <= 1) {
- msg_template = TIP_("At least two points required.");
+ return NURBSValidationStatus::AtLeastTwoPointsRequired;
}
else if (type == CU_NURBS) {
if (pnts < order) {
- msg_template = TIP_("Must have more control points than Order");
+ return NURBSValidationStatus::MorePointsThanOrderRequired;
}
else if (flag & CU_NURB_BEZIER) {
+ int points_needed = 0;
if (flag & CU_NURB_CYCLIC) {
- const uint16_t remainder = pnts % (order - 1);
+ const int remainder = pnts % (order - 1);
points_needed = remainder > 0 ? order - 1 - remainder : 0;
}
else if (((flag & CU_NURB_ENDPOINT) == 0) && pnts <= order) {
points_needed = order + 1 - pnts;
}
if (points_needed) {
- msg_template = is_surf ? TIP_("%d more %s row(s) needed for Bezier") :
- TIP_("%d more point(s) needed for Bezier");
+ *r_points_needed = points_needed;
+ return is_surf ? NURBSValidationStatus::MoreRowsForBezierRequired :
+ NURBSValidationStatus::MorePointsForBezierRequired;
}
}
}
+ return NURBSValidationStatus::Valid;
+}
+
+bool BKE_nurb_valid_message(const int pnts,
+ const short order,
+ const short flag,
+ const short type,
+ const bool is_surf,
+ const int dir,
+ char *message_dst,
+ const size_t maxncpy)
+{
+ int points_needed;
+ NURBSValidationStatus status = nurb_check_valid(
+ pnts, order, flag, type, is_surf, &points_needed);
- if (message_dst) {
- BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir);
+ const char *msg_template = nullptr;
+ switch (status) {
+ case NURBSValidationStatus::Valid:
+ message_dst[0] = 0;
+ return false;
+ case NURBSValidationStatus::AtLeastTwoPointsRequired:
+ if (dir == 1) {
+ /* Exception made for curves as their pntsv == 1. */
+ message_dst[0] = 0;
+ return false;
+ }
+ msg_template = TIP_("At least two points required.");
+ break;
+ case NURBSValidationStatus::MorePointsThanOrderRequired:
+ msg_template = TIP_("Must have more control points than Order");
+ break;
+ case NURBSValidationStatus::MoreRowsForBezierRequired:
+ msg_template = TIP_("%d more %s row(s) needed for Bezier");
+ break;
+ case NURBSValidationStatus::MorePointsForBezierRequired:
+ msg_template = TIP_("%d more point(s) needed for Bezier");
+ break;
}
- return msg_template[0];
+
+ BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir == 0 ? "U" : "V");
+ return true;
}
bool BKE_nurb_check_valid_u(const Nurb *nu)
{
- return !BKE_nurb_valid_message(
- nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, "U", nullptr, 0);
+ int points_needed;
+ return NURBSValidationStatus::Valid ==
+ nurb_check_valid(
+ nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, &points_needed);
}
bool BKE_nurb_check_valid_v(const Nurb *nu)
{
- return !BKE_nurb_valid_message(
- nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, "V", nullptr, 0);
+ int points_needed;
+ return NURBSValidationStatus::Valid ==
+ nurb_check_valid(
+ nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, &points_needed);
}
bool BKE_nurb_check_valid_uv(const Nurb *nu)
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
index f0400417ffc..44aa9e21195 100644
--- a/source/blender/blenkernel/intern/image_format.cc
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -14,6 +14,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -732,7 +733,7 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
}
#endif
else {
- /* R_IMF_IMTYPE_JPEG90, etc. default we save jpegs */
+ /* #R_IMF_IMTYPE_JPEG90, etc. default to JPEG. */
if (quality < 10) {
quality = 90;
}
@@ -872,3 +873,58 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
/* planes */
im_format->planes = imbuf->planes;
}
+
+/* Color Management */
+
+void BKE_image_format_color_management_copy(ImageFormatData *imf, const ImageFormatData *imf_src)
+{
+ BKE_color_managed_view_settings_free(&imf->view_settings);
+
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings,
+ &imf_src->linear_colorspace_settings);
+}
+
+void BKE_image_format_color_management_copy_from_scene(ImageFormatData *imf, const Scene *scene)
+{
+ BKE_color_managed_view_settings_free(&imf->view_settings);
+
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &scene->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &scene->view_settings);
+ STRNCPY(imf->linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR));
+}
+
+/* Output */
+
+void BKE_image_format_init_for_write(ImageFormatData *imf,
+ const Scene *scene_src,
+ const ImageFormatData *imf_src)
+{
+ *imf = (imf_src) ? *imf_src : scene_src->r.im_format;
+
+ if (imf_src && imf_src->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ /* Use settings specific to one node, image save operation, etc. */
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings,
+ &imf_src->linear_colorspace_settings);
+ }
+ else if (scene_src->r.im_format.color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ /* Use scene settings specific to render output. */
+ BKE_color_managed_display_settings_copy(&imf->display_settings,
+ &scene_src->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings,
+ &scene_src->r.im_format.view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings,
+ &scene_src->r.im_format.linear_colorspace_settings);
+ }
+ else {
+ /* Use general scene settings also used for display. */
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &scene_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &scene_src->view_settings);
+ STRNCPY(imf->linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR));
+ }
+}
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index f6ea814cbc0..f530183f967 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -11,6 +11,7 @@
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_vector.hh"
#include "DNA_image_types.h"
@@ -31,6 +32,8 @@
#include "RE_pipeline.h"
+using blender::Vector;
+
void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene)
{
memset(opts, 0, sizeof(*opts));
@@ -220,18 +223,19 @@ static bool image_save_single(ReportList *reports,
/* fancy multiview OpenEXR */
if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
/* save render result */
- ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer);
+ ok = BKE_image_render_write_exr(
+ reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
/* regular mono pipeline */
else if (is_mono) {
if (is_exr_rr) {
- ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer);
+ ok = BKE_image_render_write_exr(
+ reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
}
else {
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
imbuf_save_post(ibuf, colormanaged_ibuf);
}
@@ -262,7 +266,8 @@ static bool image_save_single(ReportList *reports,
if (is_exr_rr) {
BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
- ok_view = BKE_image_render_write_exr(reports, rr, filepath, imf, view, layer);
+ ok_view = BKE_image_render_write_exr(
+ reports, rr, filepath, imf, save_as_render, view, layer);
image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
}
else {
@@ -292,8 +297,7 @@ static bool image_save_single(ReportList *reports,
BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
imbuf_save_post(ibuf, colormanaged_ibuf);
image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
@@ -309,7 +313,8 @@ static bool image_save_single(ReportList *reports,
/* stereo (multiview) images */
else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
- ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer);
+ ok = BKE_image_render_write_exr(
+ reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
@@ -358,8 +363,7 @@ static bool image_save_single(ReportList *reports,
ibuf->planes = planes;
/* color manage the ImBuf leaving it ready for saving */
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
BKE_image_format_to_imbuf(colormanaged_ibuf, imf);
IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
@@ -453,10 +457,38 @@ bool BKE_image_save(
/* OpenEXR saving, single and multilayer. */
+static float *image_exr_from_scene_linear_to_output(float *rect,
+ const int width,
+ const int height,
+ const int channels,
+ const ImageFormatData *imf,
+ Vector<float *> &tmp_output_rects)
+{
+ if (imf == nullptr) {
+ return rect;
+ }
+
+ const char *to_colorspace = imf->linear_colorspace_settings.name;
+ if (to_colorspace[0] == '\0' || IMB_colormanagement_space_name_is_scene_linear(to_colorspace)) {
+ return rect;
+ }
+
+ float *output_rect = (float *)MEM_dupallocN(rect);
+ tmp_output_rects.append(output_rect);
+
+ const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
+ IMB_colormanagement_transform(
+ output_rect, width, height, channels, from_colorspace, to_colorspace, false);
+
+ return output_rect;
+}
+
bool BKE_image_render_write_exr(ReportList *reports,
const RenderResult *rr,
- const char *filename,
+ const char *filepath,
const ImageFormatData *imf,
+ const bool save_as_render,
const char *view,
int layer)
{
@@ -464,6 +496,7 @@ bool BKE_image_render_write_exr(ReportList *reports,
const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16);
const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR);
const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF));
+ Vector<float *> tmp_output_rects;
/* Write first layer if not multilayer and no layer was specified. */
if (!multi_layer && layer == -1) {
@@ -501,7 +534,10 @@ bool BKE_image_render_write_exr(ReportList *reports,
continue;
}
- float *output_rect = rview->rectf;
+ float *output_rect = (save_as_render) ?
+ image_exr_from_scene_linear_to_output(
+ rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
+ rview->rectf;
for (int a = 0; a < 4; a++) {
char passname[EXR_PASS_MAXNAME];
@@ -559,7 +595,11 @@ bool BKE_image_render_write_exr(ReportList *reports,
const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A"));
const bool pass_half_float = half_float && pass_RGBA;
- float *output_rect = rp->rect;
+ /* Colorspace conversion only happens on RGBA passes. */
+ float *output_rect = (save_as_render && pass_RGBA) ?
+ image_exr_from_scene_linear_to_output(
+ rp->rect, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
+ rp->rect;
for (int a = 0; a < rp->channels; a++) {
/* Save Combined as RGBA if single layer save. */
@@ -590,11 +630,11 @@ bool BKE_image_render_write_exr(ReportList *reports,
errno = 0;
- BLI_make_existing_file(filename);
+ BLI_make_existing_file(filepath);
int compress = (imf ? imf->exr_codec : 0);
bool success = IMB_exr_begin_write(
- exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data);
+ exrhandle, filepath, rr->rectx, rr->recty, compress, rr->stamp_data);
if (success) {
IMB_exr_write_channels(exrhandle);
}
@@ -604,6 +644,10 @@ bool BKE_image_render_write_exr(ReportList *reports,
reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
}
+ for (float *rect : tmp_output_rects) {
+ MEM_freeN(rect);
+ }
+
IMB_exr_close(exrhandle);
return success;
}
@@ -652,26 +696,27 @@ bool BKE_image_render_write(ReportList *reports,
const char *filename)
{
bool ok = true;
- const RenderData *rd = &scene->r;
if (!rr) {
return false;
}
+ ImageFormatData image_format;
+ BKE_image_format_init_for_write(&image_format, scene, nullptr);
+
const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
- const bool is_exr_rr = ELEM(rd->im_format.imtype,
- R_IMF_IMTYPE_OPENEXR,
- R_IMF_IMTYPE_MULTILAYER) &&
+ const bool is_exr_rr = ELEM(
+ image_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
RE_HasFloatPixels(rr);
const float dither = scene->r.dither_intensity;
- if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
- ok = BKE_image_render_write_exr(reports, rr, filename, &rd->im_format, nullptr, -1);
+ if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
+ ok = BKE_image_render_write_exr(reports, rr, filename, &image_format, true, nullptr, -1);
image_render_print_save_message(reports, filename, ok, errno);
}
/* mono, legacy code */
- else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ else if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
int view_id = 0;
for (const RenderView *rv = (const RenderView *)rr->views.first; rv;
rv = rv->next, view_id++) {
@@ -684,37 +729,35 @@ bool BKE_image_render_write(ReportList *reports,
}
if (is_exr_rr) {
- ok = BKE_image_render_write_exr(reports, rr, filepath, &rd->im_format, rv->name, -1);
+ ok = BKE_image_render_write_exr(reports, rr, filepath, &image_format, true, rv->name, -1);
image_render_print_save_message(reports, filepath, ok, errno);
/* optional preview images for exr */
- if (ok && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
- ImageFormatData imf = rd->im_format;
- imf.imtype = R_IMF_IMTYPE_JPEG90;
+ if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
+ image_format.imtype = R_IMF_IMTYPE_JPEG90;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
}
- BKE_image_path_ensure_ext_from_imformat(filepath, &imf);
+ BKE_image_path_ensure_ext_from_imformat(filepath, &image_format);
- ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &imf, dither, view_id);
+ ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
ibuf->planes = 24;
- IMB_colormanagement_imbuf_for_write(
- ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf);
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
- ok = image_render_write_stamp_test(reports, scene, rr, ibuf, filepath, &imf, stamp);
+ ok = image_render_write_stamp_test(
+ reports, scene, rr, ibuf, filepath, &image_format, stamp);
IMB_freeImBuf(ibuf);
}
}
else {
- ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
+ ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
- IMB_colormanagement_imbuf_for_write(
- ibuf, true, false, &scene->view_settings, &scene->display_settings, &rd->im_format);
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
ok = image_render_write_stamp_test(
- reports, scene, rr, ibuf, filepath, &rd->im_format, stamp);
+ reports, scene, rr, ibuf, filepath, &image_format, stamp);
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf);
@@ -722,12 +765,12 @@ bool BKE_image_render_write(ReportList *reports,
}
}
else { /* R_IMF_VIEWS_STEREO_3D */
- BLI_assert(rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D);
+ BLI_assert(image_format.views_format == R_IMF_VIEWS_STEREO_3D);
char filepath[FILE_MAX];
STRNCPY(filepath, filename);
- if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ if (image_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath);
}
else {
@@ -737,34 +780,29 @@ bool BKE_image_render_write(ReportList *reports,
for (i = 0; i < 2; i++) {
int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
- ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
- IMB_colormanagement_imbuf_for_write(ibuf_arr[i],
- true,
- false,
- &scene->view_settings,
- &scene->display_settings,
- &rd->im_format);
+ ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]);
}
- ibuf_arr[2] = IMB_stereo3d_ImBuf(&rd->im_format, ibuf_arr[0], ibuf_arr[1]);
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
ok = image_render_write_stamp_test(
- reports, scene, rr, ibuf_arr[2], filepath, &rd->im_format, stamp);
+ reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
/* optional preview images for exr */
- if (ok && is_exr_rr && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
- ImageFormatData imf = rd->im_format;
- imf.imtype = R_IMF_IMTYPE_JPEG90;
+ if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
+ image_format.imtype = R_IMF_IMTYPE_JPEG90;
if (BLI_path_extension_check(filepath, ".exr")) {
filepath[strlen(filepath) - 4] = 0;
}
- BKE_image_path_ensure_ext_from_imformat(filepath, &imf);
+ BKE_image_path_ensure_ext_from_imformat(filepath, &image_format);
ibuf_arr[2]->planes = 24;
- ok = image_render_write_stamp_test(reports, scene, rr, ibuf_arr[2], filepath, &imf, stamp);
+ ok = image_render_write_stamp_test(
+ reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
}
/* imbuf knows which rects are not part of ibuf */
@@ -774,5 +812,7 @@ bool BKE_image_render_write(ReportList *reports,
}
}
+ BKE_image_format_free(&image_format);
+
return ok;
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 11d6e6ef973..5247e9f358b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2171,16 +2171,14 @@ void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb)
BKE_keyblock_update_from_mesh(me, kb);
}
-void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
+void BKE_keyblock_convert_to_mesh(KeyBlock *kb, struct MVert *mvert, int totvert)
{
- MVert *mvert;
const float(*fp)[3];
int a, tot;
- mvert = me->mvert;
fp = kb->data;
- tot = min_ii(kb->totelem, me->totvert);
+ tot = min_ii(kb->totelem, totvert);
for (a = 0; a < tot; a++, fp++, mvert++) {
copy_v3_v3(mvert->co, *fp);
@@ -2193,68 +2191,77 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
float (*r_polynors)[3],
float (*r_loopnors)[3])
{
- /* We use a temp, shallow copy of mesh to work. */
- Mesh me;
- bool free_polynors = false;
-
if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) {
return;
}
- me = *mesh;
- me.mvert = MEM_dupallocN(mesh->mvert);
- CustomData_reset(&me.vdata);
- CustomData_reset(&me.edata);
- CustomData_reset(&me.pdata);
- CustomData_reset(&me.ldata);
- CustomData_reset(&me.fdata);
-
- BKE_keyblock_convert_to_mesh(kb, &me);
-
- if (r_polynors == NULL && r_loopnors != NULL) {
- r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
- free_polynors = true;
- }
-
- const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
- if (r_vertnors) {
- memcpy(r_vertnors, vert_normals, sizeof(float[3]) * me.totvert);
- }
-
- const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
- memcpy(r_polynors, face_normals, sizeof(float[3]) * me.totpoly);
-
- if (r_loopnors) {
+ MVert *mvert = MEM_dupallocN(mesh->mvert);
+ BKE_keyblock_convert_to_mesh(kb, mesh->mvert, mesh->totvert);
+
+ const bool loop_normals_needed = r_loopnors != NULL;
+ const bool vert_normals_needed = r_vertnors != NULL || loop_normals_needed;
+ const bool poly_normals_needed = r_polynors != NULL || vert_normals_needed ||
+ loop_normals_needed;
+
+ float(*vert_normals)[3] = r_vertnors;
+ float(*poly_normals)[3] = r_polynors;
+ bool free_vert_normals = false;
+ bool free_poly_normals = false;
+ if (vert_normals_needed && r_vertnors == NULL) {
+ vert_normals = MEM_malloc_arrayN(mesh->totvert, sizeof(float[3]), __func__);
+ free_vert_normals = true;
+ }
+ if (poly_normals_needed && r_polynors == NULL) {
+ poly_normals = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
+ free_poly_normals = true;
+ }
+
+ if (poly_normals_needed) {
+ BKE_mesh_calc_normals_poly(mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->totloop,
+ mesh->mpoly,
+ mesh->totpoly,
+ poly_normals);
+ }
+ if (vert_normals_needed) {
+ BKE_mesh_calc_normals_poly_and_vertex(mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->totloop,
+ mesh->mpoly,
+ mesh->totpoly,
+ poly_normals,
+ vert_normals);
+ }
+ if (loop_normals_needed) {
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
-
- BKE_mesh_normals_loop_split(me.mvert,
+ BKE_mesh_normals_loop_split(mesh->mvert,
vert_normals,
- me.totvert,
- me.medge,
- me.totedge,
- me.mloop,
+ mesh->totvert,
+ mesh->medge,
+ mesh->totedge,
+ mesh->mloop,
r_loopnors,
- me.totloop,
- me.mpoly,
- face_normals,
- me.totpoly,
- (me.flag & ME_AUTOSMOOTH) != 0,
- me.smoothresh,
+ mesh->totloop,
+ mesh->mpoly,
+ poly_normals,
+ mesh->totpoly,
+ (mesh->flag & ME_AUTOSMOOTH) != 0,
+ mesh->smoothresh,
NULL,
clnors,
NULL);
}
- CustomData_free(&me.vdata, me.totvert);
- CustomData_free(&me.edata, me.totedge);
- CustomData_free(&me.pdata, me.totpoly);
- CustomData_free(&me.ldata, me.totloop);
- CustomData_free(&me.fdata, me.totface);
- MEM_freeN(me.mvert);
-
- if (free_polynors) {
- MEM_freeN(r_polynors);
+ if (free_vert_normals) {
+ MEM_freeN(vert_normals);
+ }
+ if (free_poly_normals) {
+ MEM_freeN(poly_normals);
}
+ MEM_freeN(mvert);
}
/************************* raw coords ************************/
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index e6838264be8..782d5442c99 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -1166,6 +1166,7 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
{
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = false;
+ bmesh_from_mesh_params.calc_vert_normal = false;
bmesh_from_mesh_params.add_key_index = add_key_index;
bmesh_from_mesh_params.use_shapekey = true;
bmesh_from_mesh_params.active_shapekey = ob->shapenr;
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 1542f7119d1..40c6fbcf67e 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1308,7 +1308,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
if (build_shapekey_layers && me->key &&
(kb = (KeyBlock *)BLI_findlink(&me->key->block, ob_eval->shapenr - 1))) {
- BKE_keyblock_convert_to_mesh(kb, me);
+ BKE_keyblock_convert_to_mesh(kb, me->mvert, me->totvert);
}
Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index da23aea43f3..9202690b3c9 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -46,6 +46,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
.emask = CD_MASK_ORIGINDEX,
.pmask = CD_MASK_ORIGINDEX},
@@ -92,6 +93,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.cd_mask_extra =
{
.vmask = CD_MASK_SHAPEKEY,
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 1c2a903d8c3..7633a3155ba 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -306,14 +306,14 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn(
}
}
-static void mesh_calc_normals_poly_and_vertex(const MVert *mvert,
- const int mvert_len,
- const MLoop *mloop,
- const int UNUSED(mloop_len),
- const MPoly *mpoly,
- const int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3])
+void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
+ const int mvert_len,
+ const MLoop *mloop,
+ const int UNUSED(mloop_len),
+ const MPoly *mpoly,
+ const int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3])
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -372,14 +372,14 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
vert_normals = BKE_mesh_vertex_normals_for_write(&mesh_mutable);
poly_normals = BKE_mesh_poly_normals_for_write(&mesh_mutable);
- mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
- mesh_mutable.totvert,
- mesh_mutable.mloop,
- mesh_mutable.totloop,
- mesh_mutable.mpoly,
- mesh_mutable.totpoly,
- poly_normals,
- vert_normals);
+ BKE_mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals,
+ vert_normals);
BKE_mesh_vertex_normals_clear_dirty(&mesh_mutable);
BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index b34a241bca8..3c7992ec3d7 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -401,6 +401,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
+ bmesh_from_mesh_params.calc_vert_normal = true;
BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
BMVert *v;
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
index 80926bfc1e2..cad680ecedd 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.c
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -869,6 +869,7 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
return bm;
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 985c9edac1a..1e3b5d77fa7 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -4630,9 +4630,11 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
if (key->refkey) {
/* apply new basis key on original data */
switch (ob->type) {
- case OB_MESH:
- BKE_keyblock_convert_to_mesh(key->refkey, (Mesh *)ob->data);
+ case OB_MESH: {
+ Mesh *mesh = (Mesh *)ob->data;
+ BKE_keyblock_convert_to_mesh(key->refkey, mesh->mvert, mesh->totvert);
break;
+ }
case OB_CURVES_LEGACY:
case OB_SURF:
BKE_keyblock_convert_to_curve(
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 4bba84f2e29..c31e3045c97 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -202,7 +202,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
* \return the lowest squared distance to either of the planes.
* where `(return < 0.0)` is outside.
*
- * <pre>
+ * \code{.unparsed}
* v1
* +
* /
@@ -211,7 +211,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
* +----+
* v2 v3
* x - also outside
- * </pre>
+ * \endcode
*/
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
@@ -322,18 +322,22 @@ double closest_to_line_v2_db(double r_close[2],
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
/**
* Point closest to v1 on line v2-v3 in 2D.
+ *
+ * \return A value in [0, 1] that corresponds to the position of #r_close on the line segment.
*/
-void closest_to_line_segment_v2(float r_close[2],
- const float p[2],
- const float l1[2],
- const float l2[2]);
+float closest_to_line_segment_v2(float r_close[2],
+ const float p[2],
+ const float l1[2],
+ const float l2[2]);
/**
* Point closest to v1 on line v2-v3 in 3D.
+ *
+ * \return A value in [0, 1] that corresponds to the position of #r_close on the line segment.
*/
-void closest_to_line_segment_v3(float r_close[3],
- const float p[3],
- const float l1[3],
- const float l2[3]);
+float closest_to_line_segment_v3(float r_close[3],
+ const float p[3],
+ const float l1[3],
+ const float l2[3]);
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]);
/**
* Find the closest point on a plane.
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index bc3ed099fd5..e1ec22063e0 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -294,46 +294,48 @@ float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l
return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2));
}
-void closest_to_line_segment_v2(float r_close[2],
- const float p[2],
- const float l1[2],
- const float l2[2])
+float closest_to_line_segment_v2(float r_close[2],
+ const float p[2],
+ const float l1[2],
+ const float l2[2])
{
float lambda, cp[2];
lambda = closest_to_line_v2(cp, p, l1, l2);
/* flip checks for !finite case (when segment is a point) */
- if (!(lambda > 0.0f)) {
+ if (lambda <= 0.0f) {
copy_v2_v2(r_close, l1);
+ return 0.0f;
}
- else if (!(lambda < 1.0f)) {
+ if (lambda >= 1.0f) {
copy_v2_v2(r_close, l2);
+ return 1.0f;
}
- else {
- copy_v2_v2(r_close, cp);
- }
+ copy_v2_v2(r_close, cp);
+ return lambda;
}
-void closest_to_line_segment_v3(float r_close[3],
- const float p[3],
- const float l1[3],
- const float l2[3])
+float closest_to_line_segment_v3(float r_close[3],
+ const float p[3],
+ const float l1[3],
+ const float l2[3])
{
float lambda, cp[3];
lambda = closest_to_line_v3(cp, p, l1, l2);
/* flip checks for !finite case (when segment is a point) */
- if (!(lambda > 0.0f)) {
+ if (lambda <= 0.0f) {
copy_v3_v3(r_close, l1);
+ return 0.0f;
}
- else if (!(lambda < 1.0f)) {
+ if (lambda >= 1.0f) {
copy_v3_v3(r_close, l2);
+ return 1.0f;
}
- else {
- copy_v3_v3(r_close, cp);
- }
+ copy_v3_v3(r_close, cp);
+ return lambda;
}
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc
index 35a111f04db..8c310645d6d 100644
--- a/source/blender/blenlib/tests/BLI_math_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc
@@ -85,4 +85,4 @@ TEST(math_vector, Clamp)
EXPECT_EQ(result_2.z, -50);
}
-} // namespace blender::tests \ No newline at end of file
+} // namespace blender::tests
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 0d16cc9dffd..a5994b52bc2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -17,7 +17,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
struct BMeshCreateParams {
- uint use_toolflags : 1;
+ bool use_toolflags : true;
};
/**
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index fd14a3416e2..118e7751cbc 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -229,7 +229,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
* work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
* in edit mode. */
const float(*vert_normals)[3] = nullptr;
- if (!BKE_mesh_vertex_normals_are_dirty(me)) {
+ if (params->calc_vert_normal) {
vert_normals = BKE_mesh_vertex_normals_ensure(me);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 0bd70749cb1..cc1ad71549d 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -18,11 +18,12 @@ void BM_mesh_cd_flag_apply(BMesh *bm, char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
- uint calc_face_normal : 1;
+ bool calc_face_normal : true;
+ bool calc_vert_normal : true;
/* add a vertex CD_SHAPE_KEYINDEX layer */
- uint add_key_index : 1;
+ bool add_key_index : true;
/* set vertex coordinates from the shapekey */
- uint use_shapekey : 1;
+ bool use_shapekey : true;
/* define the active shape key (index + 1) */
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
@@ -42,7 +43,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFrom
struct BMeshToMeshParams {
/** Update object hook indices & vertex parents. */
- uint calc_object_remap : 1;
+ bool calc_object_remap : true;
/**
* This re-assigns shape-key indices. Only do if the BMesh will have continued use
* to update the mesh & shape key in the future.
@@ -52,12 +53,12 @@ struct BMeshToMeshParams {
* so a second flush or edit-mode exit doesn't run with indices
* that have become invalid from updating the shape-key, see T71865.
*/
- uint update_shapekey_indices : 1;
+ bool update_shapekey_indices : true;
/**
* Instead of copying the basis shape-key into the #MVert array,
* copy the #BMVert.co directly to #MVert.co (used for reading undo data).
*/
- uint active_shapekey_to_mvert : 1;
+ bool active_shapekey_to_mvert : true;
struct CustomData_MeshMasks cd_mask_extra;
};
/**
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 1bc5b70f874..8bc16324971 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -1869,7 +1869,7 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
for (int i = 0; i < len; i++) {
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
if ((f->len <= len) && (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0)) {
- /* Check if all vers in this face are flagged. */
+ /* Check if all verts in this face are flagged. */
BMLoop *l_iter, *l_first;
if (is_init == false) {
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index eafa6614d31..0fdd7647f8d 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -318,12 +318,6 @@ extern "C" {
* - output nodes can have different priorities in the WorkScheduler.
* This is implemented in the COM_execute function.
*
- * \param view_settings:
- * reference to view settings used for color management
- *
- * \param display_settings:
- * reference to display settings used for color management
- *
* OCIO_TODO: this options only used in rare cases, namely in output file node,
* so probably this settings could be passed in a nicer way.
* should be checked further, probably it'll be also needed for preview
@@ -335,8 +329,6 @@ void COM_execute(RenderData *render_data,
Scene *scene,
bNodeTree *node_tree,
int rendering,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name);
/**
diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc
index f17a24c6b9d..2c55af1779a 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.cc
+++ b/source/blender/compositor/intern/COM_CompositorContext.cc
@@ -12,8 +12,6 @@ CompositorContext::CompositorContext()
quality_ = eCompositorQuality::High;
hasActiveOpenCLDevices_ = false;
fast_calculation_ = false;
- view_settings_ = nullptr;
- display_settings_ = nullptr;
bnodetree_ = nullptr;
}
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index 430bab48352..480f70f4193 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -64,10 +64,6 @@ class CompositorContext {
*/
bool fast_calculation_;
- /* \brief color management settings */
- const ColorManagedViewSettings *view_settings_;
- const ColorManagedDisplaySettings *display_settings_;
-
/**
* \brief active rendering view name
*/
@@ -153,38 +149,6 @@ class CompositorContext {
}
/**
- * \brief set view settings of color management
- */
- void set_view_settings(const ColorManagedViewSettings *view_settings)
- {
- view_settings_ = view_settings;
- }
-
- /**
- * \brief get view settings of color management
- */
- const ColorManagedViewSettings *get_view_settings() const
- {
- return view_settings_;
- }
-
- /**
- * \brief set display settings of color management
- */
- void set_display_settings(const ColorManagedDisplaySettings *display_settings)
- {
- display_settings_ = display_settings;
- }
-
- /**
- * \brief get display settings of color management
- */
- const ColorManagedDisplaySettings *get_display_settings() const
- {
- return display_settings_;
- }
-
- /**
* \brief set the quality
*/
void set_quality(eCompositorQuality quality)
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index 036e2bc8a91..c850585148a 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -23,8 +23,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
bNodeTree *editingtree,
bool rendering,
bool fastcalculation,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name)
{
num_work_threads_ = WorkScheduler::get_num_cpu_threads();
@@ -45,8 +43,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
(editingtree->flag & NTREE_COM_OPENCL));
context_.set_render_data(rd);
- context_.set_view_settings(view_settings);
- context_.set_display_settings(display_settings);
BLI_mutex_init(&work_mutex_);
BLI_condition_init(&work_finished_cond_);
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index 9dd20d18144..2cd9e2d9001 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -160,8 +160,6 @@ class ExecutionSystem {
bNodeTree *editingtree,
bool rendering,
bool fastcalculation,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name);
/**
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 2f27699ce9c..788686f3036 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -221,8 +221,9 @@ PreviewOperation *NodeOperationBuilder::make_preview_operation() const
bNodeInstanceHash *previews = context_->get_preview_hash();
if (previews) {
- PreviewOperation *operation = new PreviewOperation(context_->get_view_settings(),
- context_->get_display_settings(),
+ Scene *scene = context_->get_scene();
+ PreviewOperation *operation = new PreviewOperation(&scene->view_settings,
+ &scene->display_settings,
current_node_->get_bnode()->preview_xsize,
current_node_->get_bnode()->preview_ysize);
operation->set_bnodetree(context_->get_bnodetree());
diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc
index 791cc327bfb..519ad93bcaf 100644
--- a/source/blender/compositor/intern/COM_compositor.cc
+++ b/source/blender/compositor/intern/COM_compositor.cc
@@ -49,8 +49,6 @@ void COM_execute(RenderData *render_data,
Scene *scene,
bNodeTree *node_tree,
int rendering,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name)
{
/* Initialize mutex, TODO: this mutex init is actually not thread safe and
@@ -80,14 +78,8 @@ void COM_execute(RenderData *render_data,
/* Execute. */
const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering;
if (twopass) {
- blender::compositor::ExecutionSystem fast_pass(render_data,
- scene,
- node_tree,
- rendering,
- true,
- view_settings,
- display_settings,
- view_name);
+ blender::compositor::ExecutionSystem fast_pass(
+ render_data, scene, node_tree, rendering, true, view_name);
fast_pass.execute();
if (node_tree->test_break(node_tree->tbh)) {
@@ -97,7 +89,7 @@ void COM_execute(RenderData *render_data,
}
blender::compositor::ExecutionSystem system(
- render_data, scene, node_tree, rendering, false, view_settings, display_settings, view_name);
+ render_data, scene, node_tree, rendering, false, view_name);
system.execute();
BLI_mutex_unlock(&g_compositor.mutex);
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index ab5898c526d..f69511d88e6 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cc
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
@@ -106,36 +106,33 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter,
if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) {
output_operation = new OutputOpenExrSingleLayerMultiViewOperation(
+ context.get_scene(),
context.get_render_data(),
context.get_bnodetree(),
input->get_data_type(),
format,
path,
- context.get_view_settings(),
- context.get_display_settings(),
context.get_view_name(),
sockdata->save_as_render);
}
else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- output_operation = new OutputSingleLayerOperation(context.get_render_data(),
+ output_operation = new OutputSingleLayerOperation(context.get_scene(),
+ context.get_render_data(),
context.get_bnodetree(),
input->get_data_type(),
format,
path,
- context.get_view_settings(),
- context.get_display_settings(),
context.get_view_name(),
sockdata->save_as_render);
}
else { /* R_IMF_VIEWS_STEREO_3D */
- output_operation = new OutputStereoOperation(context.get_render_data(),
+ output_operation = new OutputStereoOperation(context.get_scene(),
+ context.get_render_data(),
context.get_bnodetree(),
input->get_data_type(),
format,
path,
sockdata->layer,
- context.get_view_settings(),
- context.get_display_settings(),
context.get_view_name(),
sockdata->save_as_render);
}
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cc b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
index 0e7db05980a..d02bc6e773d 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cc
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
@@ -24,6 +24,7 @@ void SplitViewerNode::convert_to_operations(NodeConverter &converter,
NodeInput *image2Socket = this->get_input_socket(1);
Image *image = (Image *)this->get_bnode()->id;
ImageUser *image_user = (ImageUser *)this->get_bnode()->storage;
+ Scene *scene = context.get_scene();
SplitOperation *split_viewer_operation = new SplitOperation();
split_viewer_operation->set_split_percentage(this->get_bnode()->custom1);
@@ -36,8 +37,8 @@ void SplitViewerNode::convert_to_operations(NodeConverter &converter,
ViewerOperation *viewer_operation = new ViewerOperation();
viewer_operation->set_image(image);
viewer_operation->set_image_user(image_user);
- viewer_operation->set_view_settings(context.get_view_settings());
- viewer_operation->set_display_settings(context.get_display_settings());
+ viewer_operation->set_view_settings(&scene->view_settings);
+ viewer_operation->set_display_settings(&scene->display_settings);
viewer_operation->set_render_data(context.get_render_data());
viewer_operation->set_view_name(context.get_view_name());
diff --git a/source/blender/compositor/nodes/COM_TextureNode.cc b/source/blender/compositor/nodes/COM_TextureNode.cc
index 216df59cc47..be5f7b90e11 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.cc
+++ b/source/blender/compositor/nodes/COM_TextureNode.cc
@@ -17,8 +17,7 @@ void TextureNode::convert_to_operations(NodeConverter &converter,
bNode *editor_node = this->get_bnode();
Tex *texture = (Tex *)editor_node->id;
TextureOperation *operation = new TextureOperation();
- const ColorManagedDisplaySettings *display_settings = context.get_display_settings();
- bool scene_color_manage = !STREQ(display_settings->display_device, "None");
+ bool scene_color_manage = !STREQ(context.get_scene()->display_settings.display_device, "None");
operation->set_texture(texture);
operation->set_render_data(context.get_render_data());
operation->set_scene_color_manage(scene_color_manage);
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cc b/source/blender/compositor/nodes/COM_ViewerNode.cc
index 1b335abc4d7..ebef331c62f 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cc
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cc
@@ -37,8 +37,9 @@ void ViewerNode::convert_to_operations(NodeConverter &converter,
viewer_operation->set_render_data(context.get_render_data());
viewer_operation->set_view_name(context.get_view_name());
- viewer_operation->set_view_settings(context.get_view_settings());
- viewer_operation->set_display_settings(context.get_display_settings());
+ Scene *scene = context.get_scene();
+ viewer_operation->set_view_settings(&scene->view_settings);
+ viewer_operation->set_display_settings(&scene->display_settings);
viewer_operation->set_canvas_input_index(0);
if (!image_socket->is_linked()) {
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index 4da11cc9053..aeaf6b659e3 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
@@ -17,24 +17,16 @@ namespace blender::compositor {
/************************************ OpenEXR Singlelayer Multiview ******************************/
OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation(
+ const Scene *scene,
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
const bool save_as_render)
- : OutputSingleLayerOperation(rd,
- tree,
- datatype,
- format,
- path,
- view_settings,
- display_settings,
- view_name,
- save_as_render)
+ : OutputSingleLayerOperation(
+ scene, rd, tree, datatype, format, path, view_name, save_as_render)
{
}
@@ -68,7 +60,7 @@ void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filenam
/* prepare the file with all the channels */
- if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_->exr_codec, nullptr)) {
+ if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_.exr_codec, nullptr)) {
printf("Error Writing Singlelayer Multiview Openexr\n");
IMB_exr_close(exrhandle);
}
@@ -104,7 +96,7 @@ void OutputOpenExrSingleLayerMultiViewOperation::deinit_execution()
datatype_,
view_name_,
width,
- format_->depth == R_IMF_CHAN_DEPTH_16,
+ format_.depth == R_IMF_CHAN_DEPTH_16,
output_buffer_);
/* memory can only be freed after we write all views to the file */
@@ -247,25 +239,17 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinit_execution()
/******************************** Stereo3D ******************************/
-OutputStereoOperation::OutputStereoOperation(const RenderData *rd,
+OutputStereoOperation::OutputStereoOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
const char *name,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
const bool save_as_render)
- : OutputSingleLayerOperation(rd,
- tree,
- datatype,
- format,
- path,
- view_settings,
- display_settings,
- view_name,
- save_as_render)
+ : OutputSingleLayerOperation(
+ scene, rd, tree, datatype, format, path, view_name, save_as_render)
{
BLI_strncpy(name_, name, sizeof(name_));
channels_ = get_datatype_size(datatype);
@@ -317,7 +301,7 @@ void OutputStereoOperation::deinit_execution()
1,
channels_ * width * height,
buf,
- format_->depth == R_IMF_CHAN_DEPTH_16);
+ format_.depth == R_IMF_CHAN_DEPTH_16);
image_input_ = nullptr;
output_buffer_ = nullptr;
@@ -332,7 +316,7 @@ void OutputStereoOperation::deinit_execution()
/* get rectf from EXR */
for (i = 0; i < 2; i++) {
float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, name_, names[i]);
- ibuf[i] = IMB_allocImBuf(width, height, format_->planes, 0);
+ ibuf[i] = IMB_allocImBuf(width, height, format_.planes, 0);
ibuf[i]->channels = channels_;
ibuf[i]->rect_float = rectf;
@@ -340,24 +324,23 @@ void OutputStereoOperation::deinit_execution()
ibuf[i]->dither = rd_->dither_intensity;
/* do colormanagement in the individual views, so it doesn't need to do in the stereo */
- IMB_colormanagement_imbuf_for_write(
- ibuf[i], true, false, view_settings_, display_settings_, format_);
+ IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, &format_);
IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
}
/* create stereo buffer */
- ibuf[2] = IMB_stereo3d_ImBuf(format_, ibuf[0], ibuf[1]);
+ ibuf[2] = IMB_stereo3d_ImBuf(&format_, ibuf[0], ibuf[1]);
BKE_image_path_from_imformat(filename,
path_,
BKE_main_blendfile_path_from_global(),
rd_->cfra,
- format_,
+ &format_,
(rd_->scemode & R_EXTENSION) != 0,
true,
nullptr);
- BKE_imbuf_write(ibuf[2], filename, format_);
+ BKE_imbuf_write(ibuf[2], filename, &format_);
/* imbuf knows which rects are not part of ibuf */
for (i = 0; i < 3; i++) {
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
index 6d36db3b777..69f4011d340 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -18,13 +18,12 @@ namespace blender::compositor {
class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation {
private:
public:
- OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd,
+ OutputOpenExrSingleLayerMultiViewOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
bool save_as_render);
@@ -54,14 +53,13 @@ class OutputStereoOperation : public OutputSingleLayerOperation {
size_t channels_;
public:
- OutputStereoOperation(const RenderData *rd,
+ OutputStereoOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
struct ImageFormatData *format,
const char *path,
const char *name,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
bool save_as_render);
void *get_handle(const char *filename);
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 67c92a3bcb0..cde1496546e 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -200,16 +200,14 @@ static void write_buffer_rect(rcti *rect,
}
}
-OutputSingleLayerOperation::OutputSingleLayerOperation(
- const RenderData *rd,
- const bNodeTree *tree,
- DataType datatype,
- ImageFormatData *format,
- const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
- const char *view_name,
- const bool save_as_render)
+OutputSingleLayerOperation::OutputSingleLayerOperation(const Scene *scene,
+ const RenderData *rd,
+ const bNodeTree *tree,
+ DataType datatype,
+ ImageFormatData *format,
+ const char *path,
+ const char *view_name,
+ const bool save_as_render)
{
rd_ = rd;
tree_ = tree;
@@ -220,11 +218,9 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
datatype_ = datatype;
image_input_ = nullptr;
- format_ = format;
+ BKE_image_format_init_for_write(&format_, scene, format);
BLI_strncpy(path_, path, sizeof(path_));
- view_settings_ = view_settings;
- display_settings_ = display_settings;
view_name_ = view_name;
save_as_render_ = save_as_render;
}
@@ -245,7 +241,7 @@ void OutputSingleLayerOperation::deinit_execution()
if (this->get_width() * this->get_height() != 0) {
int size = get_datatype_size(datatype_);
- ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_->planes, 0);
+ ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_.planes, 0);
char filename[FILE_MAX];
const char *suffix;
@@ -254,8 +250,7 @@ void OutputSingleLayerOperation::deinit_execution()
ibuf->mall |= IB_rectfloat;
ibuf->dither = rd_->dither_intensity;
- IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render_, false, view_settings_, display_settings_, format_);
+ IMB_colormanagement_imbuf_for_write(ibuf, save_as_render_, false, &format_);
suffix = BKE_scene_multiview_view_suffix_get(rd_, view_name_);
@@ -263,12 +258,12 @@ void OutputSingleLayerOperation::deinit_execution()
path_,
BKE_main_blendfile_path_from_global(),
rd_->cfra,
- format_,
+ &format_,
(rd_->scemode & R_EXTENSION) != 0,
true,
suffix);
- if (0 == BKE_imbuf_write(ibuf, filename, format_)) {
+ if (0 == BKE_imbuf_write(ibuf, filename, &format_)) {
printf("Cannot save Node File Output to %s\n", filename);
}
else {
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 51240082a80..98b7e77cc21 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -20,27 +20,23 @@ class OutputSingleLayerOperation : public MultiThreadedOperation {
const RenderData *rd_;
const bNodeTree *tree_;
- ImageFormatData *format_;
+ ImageFormatData format_;
char path_[FILE_MAX];
float *output_buffer_;
DataType datatype_;
SocketReader *image_input_;
- const ColorManagedViewSettings *view_settings_;
- const ColorManagedDisplaySettings *display_settings_;
-
const char *view_name_;
bool save_as_render_;
public:
- OutputSingleLayerOperation(const RenderData *rd,
+ OutputSingleLayerOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
bool save_as_render);
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 78c01ce5a23..5dd26d19e02 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -214,6 +214,7 @@ set(SRC
engines/eevee_next/eevee_engine.h
engines/external/external_engine.h
engines/image/image_batches.hh
+ engines/image/image_buffer_cache.hh
engines/image/image_drawing_mode.hh
engines/image/image_engine.h
engines/image/image_instance_data.hh
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
index 584aacc9e19..ddc6a0b9661 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
@@ -26,10 +26,13 @@ struct ClosureEvalGlossy {
#ifdef STEP_RESOLVE /* SSR */
/* Prototype. */
+# ifndef GPU_METAL
+/* MSL does not require prototypes. */
void raytrace_resolve(ClosureInputGlossy cl_in,
inout ClosureEvalGlossy cl_eval,
inout ClosureEvalCommon cl_common,
inout ClosureOutputGlossy cl_out);
+# endif
#endif
ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index f66f45635f4..fefc8743691 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -32,8 +32,10 @@ struct Closure {
#endif
};
+#ifndef GPU_METAL
/* Prototype */
Closure nodetree_exec(void);
+#endif
/* clang-format off */
/* Avoid multi-line defines. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
index 9d9d7beb3cb..bdcc0a2ba93 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
@@ -150,7 +150,7 @@ vec4 step_blit(void)
float br = max_v3(m);
/* Under-threshold part: quadratic curve */
- float rq = clamp(br - curveThreshold.x, 0, curveThreshold.y);
+ float rq = clamp(br - curveThreshold.x, 0.0, curveThreshold.y);
rq = curveThreshold.z * rq * rq;
/* Combine and apply the brightness response curve. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl
index 57027c71156..688ae4915e1 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl
@@ -142,7 +142,7 @@ void dof_resolve_load_layer(sampler2D color_tex,
out float out_weight)
{
vec2 pixel_co = gl_FragCoord.xy / 2.0;
- vec2 uv = pixel_co / textureSize(color_tex, 0).xy;
+ vec2 uv = pixel_co / vec2(textureSize(color_tex, 0).xy);
out_color = textureLod(color_tex, uv, 0.0);
out_weight = textureLod(weight_tex, uv, 0.0).r;
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
index b05223e755d..51a351babd3 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
@@ -95,7 +95,7 @@ void main()
weights = dof_layer_weight(cocs) * dof_sample_weight(cocs);
/* Filter NaNs. */
- weights = mix(weights, vec4(0.0), equal(cocs, vec4(0.0)));
+ weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0)));
color1 = colors[0] * weights[0];
color2 = colors[1] * weights[1];
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl
index 235145b221b..178ef46862b 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl
@@ -54,12 +54,12 @@ void main()
bvec4 focus = lessThanEqual(cocs, vec4(0.5));
if (any(defocus) && any(focus)) {
/* For the same reason as in the flatten pass. This is a case we cannot optimize for. */
- cocs = mix(cocs, vec4(DOF_TILE_MIXED), focus);
- cocs = mix(cocs, vec4(DOF_TILE_MIXED), defocus);
+ cocs = select(cocs, vec4(DOF_TILE_MIXED), focus);
+ cocs = select(cocs, vec4(DOF_TILE_MIXED), defocus);
}
else {
- cocs = mix(cocs, vec4(DOF_TILE_FOCUS), focus);
- cocs = mix(cocs, vec4(DOF_TILE_DEFOCUS), defocus);
+ cocs = select(cocs, vec4(DOF_TILE_FOCUS), focus);
+ cocs = select(cocs, vec4(DOF_TILE_DEFOCUS), defocus);
}
outCoc.y = max_v4(cocs);
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
index ce455123987..aaf673eecd2 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -38,7 +38,7 @@ uniform vec2 texelSize;
/* On some AMD card / driver combination, it is needed otherwise,
* the shader does not write anything. */
-#if defined(GPU_INTEL) || defined(GPU_ATI)
+#if (defined(GPU_INTEL) || defined(GPU_ATI)) && defined(GPU_OPENGL)
out vec4 fragColor;
#endif
@@ -68,9 +68,14 @@ void main()
float val = minmax4(samp.x, samp.y, samp.z, samp.w);
#endif
-#if defined(GPU_INTEL) || defined(GPU_ATI)
+#if (defined(GPU_INTEL) || defined(GPU_ATI)) && defined(GPU_OPENGL)
/* Use color format instead of 24bit depth texture */
fragColor = vec4(val);
#endif
+
+#if !(defined(GPU_INTEL) && defined(GPU_OPENGL))
+ /* If using Intel workaround, do not write out depth as there will be no depth target and this is
+ * invalid. */
gl_FragDepth = val;
+#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
index f4ff28eaee4..c9010749060 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
@@ -60,11 +60,11 @@ void main()
vec3 P = transform_point(ViewMatrixInverse, vP);
vec3 vV = viewCameraVec(vP);
vec3 V = cameraVec(P);
- vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV);
+ vec3 vN = normal_decode(textureLod(normalBuffer, uvs, 0.0).rg, vV);
vec3 N = transform_direction(ViewMatrixInverse, vN);
/* Retrieve pixel data */
- vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba;
+ vec4 speccol_roughness = textureLod(specroughBuffer, uvs, 0.0).rgba;
/* Early out */
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl
index 300477570d0..fc8091161d7 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl
@@ -74,7 +74,7 @@ bool neighbor_affect_this_tile(ivec2 offset, vec2 velocity)
* offset. If the offset coordinate is zero then
* velocity is irrelevant.
*/
- vec2 point = sign(offset * velocity);
+ vec2 point = sign(vec2(offset) * velocity);
float dist = (point.x + point.y);
/**
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 84626eac4cf..e1035af37be 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -289,7 +289,7 @@ vec3 probe_evaluate_grid(GridData gd, vec3 P, vec3 N, vec3 localpos)
weight += prbIrradianceSmooth;
/* Trilinear weights */
- vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, offset);
+ vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, vec3(offset));
weight *= trilinear.x * trilinear.y * trilinear.z;
/* Avoid zero weight */
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
index cf44a04b707..5674e464f4c 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
@@ -16,11 +16,11 @@ void main()
{
#if 0
/* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
- vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+ vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0).xy);
FragColor = textureLod(source, vec3(uvs, layer), 0.0);
#else
- vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
+ vec2 texel_size = 1.0 / vec2(textureSize(source, 0).xy);
vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size;
vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index 25661a0d731..9f1afc4767c 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -31,7 +31,7 @@ layout(location = 3) out vec4 volumePhase;
void main()
{
- ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
+ ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice);
vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz);
viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index 12b7d8acbea..11f57c0a82e 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -52,7 +52,7 @@ void main()
ivec2 texco = ivec2(gl_FragCoord.xy);
#endif
for (int i = 0; i <= slice; i++) {
- ivec3 volume_cell = ivec3(gl_FragCoord.xy, i);
+ ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), i);
vec3 Lscat = texelFetch(volumeScattering, volume_cell, 0).rgb;
vec3 s_extinction = texelFetch(volumeExtinction, volume_cell, 0).rgb;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
index dc755aeab8b..df3f92966e6 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -22,7 +22,7 @@ layout(location = 1) out vec4 outTransmittance;
void main()
{
- ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
+ ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice);
/* Emission */
outScattering = texelFetch(volumeEmission, volume_cell, 0);
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 7bfbcfa9e21..be35660a4d7 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -269,8 +269,8 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
float vert_col_opacity = (override_vertcol) ?
(is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) :
- pd->is_render ? gpl->vertex_paint_opacity :
- pd->vertex_paint_opacity;
+ (pd->is_render ? gpl->vertex_paint_opacity :
+ pd->vertex_paint_opacity);
/* Negate thickness sign to tag that strokes are in screen space.
* Convert to world units (by default, 1 meter = 2000 pixels). */
float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR);
diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/background_frag.glsl
index 52052d414f8..19313c0415b 100644
--- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/background_frag.glsl
@@ -38,8 +38,8 @@ void main()
* This removes the alpha channel and put the background behind reference images
* while masking the reference images by the render alpha.
*/
- float alpha = texture(colorBuffer, uvcoordsvar.st).a;
- float depth = texture(depthBuffer, uvcoordsvar.st).r;
+ float alpha = texture(colorBuffer, uvcoordsvar.xy).a;
+ float depth = texture(depthBuffer, uvcoordsvar.xy).r;
vec3 bg_col;
vec3 col_high;
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index 0e4757f8ea8..19d54a57479 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -169,7 +169,7 @@ void diag_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end
void main()
{
- uint ref = textureLod(outlineId, uvcoordsvar.st, 0.0).r;
+ uint ref = textureLod(outlineId, uvcoordsvar.xy, 0.0).r;
uint ref_col = ref;
vec2 uvs = gl_FragCoord.xy * sizeViewportInv.xy;
diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
index f714646fe40..507beb8a418 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
@@ -53,7 +53,7 @@ vec4 flag_to_color(uint flag)
if (bool(flag & uint(16))) {
color.rgb += vec3(0.9, 0.3, 0.0); /* orange */
}
- if (color.rgb == vec3(0.0)) {
+ if (is_zero(color.rgb)) {
color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */
}
return color;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
index 59222b588a0..7704e7ed0b7 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
@@ -9,11 +9,11 @@ void main()
float cavity = 0.0, edges = 0.0, curvature = 0.0;
#ifdef USE_CAVITY
- cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges);
+ cavity_compute(uvcoordsvar.xy, depthBuffer, normalBuffer, cavity, edges);
#endif
#ifdef USE_CURVATURE
- curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature);
+ curvature_compute(uvcoordsvar.xy, objectIdBuffer, normalBuffer, curvature);
#endif
float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
index ae564435258..30daca6b7e3 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -1,7 +1,7 @@
void main()
{
- float depth = texture(depthBuffer, uvcoordsvar.st).r;
+ float depth = texture(depthBuffer, uvcoordsvar.xy).r;
/* Fix issues with Intel drivers (see T80023). */
fragColor = vec4(0.0);
/* Discard background pixels. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
index a2c45d2f8e3..35bea830bac 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
@@ -9,8 +9,8 @@ void main()
/* Revealage is actually stored in transparentAccum alpha channel.
* This is a workaround to older hardware not having separate blend equation per render target.
*/
- vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st);
- float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r;
+ vec4 trans_accum = texture(transparentAccum, uvcoordsvar.xy);
+ float trans_weight = texture(transparentRevealage, uvcoordsvar.xy).r;
float trans_reveal = trans_accum.a;
/* Listing 4 */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 076f6e80104..4ff281ccd29 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -94,7 +94,7 @@ vec4 flag_to_color(uint flag)
if (bool(flag & uint(16))) {
color.rgb += vec3(0.9, 0.3, 0.0); /* orange */
}
- if (color.rgb == vec3(0.0)) {
+ if (is_zero(color.rgb)) {
color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */
}
return color;
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index 37f884e398c..ed94c485b32 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -515,7 +515,7 @@ class Texture : NonCopyable {
/**
* Ensure the availability of mipmap views.
- * Mip view covers all layers of array textures.
+ * MIP view covers all layers of array textures.
*/
bool ensure_mip_views(bool cube_as_array = false)
{
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index eb73ab78a1a..832897b7040 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -432,7 +432,7 @@ struct DRWView {
struct DRWView *parent;
ViewInfos storage;
- /** Number of active clipplanes. */
+ /** Number of active clip planes. */
int clip_planes_len;
/** Does culling result needs to be updated. */
bool is_dirty;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index ae536f0b87c..27149a80f9b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -419,7 +419,7 @@ static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache
}
static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
void *_data,
uint subdiv_quad_index,
const BMFace *coarse_quad)
@@ -431,11 +431,8 @@ static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_ca
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
for (uint i = start_loop_idx; i < end_loop_idx; i++) {
const int vert_origindex = subdiv_loop_vert_index[i];
- const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
- vert_origindex != -1 &&
- mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
edituv_point_add(data,
- (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN)) || !real_vert,
+ (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) || vert_origindex == -1),
BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
i);
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
index 2dfd2cd43dc..f79fe345f5a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
@@ -137,7 +137,7 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cach
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
for (uint i = start_loop_idx; i < end_loop_idx; i++) {
const int vert_origindex = subdiv_loop_vert_index[i];
- const int edge_origindex = subdiv_loop_edge_index[i];
+ int edge_origindex = subdiv_loop_edge_index[i];
EditLoopData *edit_loop_data = &data->vbo_data[i];
memset(edit_loop_data, 0, sizeof(EditLoopData));
@@ -149,6 +149,22 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cach
mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data);
mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data);
}
+ else {
+ if (edge_origindex == -1) {
+ /* Find if the loop's vert is not part of an edit edge.
+ * For this, we check if the previous loop was on an edge. */
+ const uint loop_index_last = (i == start_loop_idx) ? end_loop_idx - 1 : i - 1;
+ edge_origindex = subdiv_loop_edge_index[loop_index_last];
+ }
+ if (edge_origindex != -1) {
+ /* Mapped points on an edge between two edit verts. */
+ BMEdge *eed = BM_edge_at_index(mr->bm, edge_origindex);
+ BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed);
+ mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data);
+ }
+ }
+
+ mesh_render_data_face_flag(mr, coarse_quad, data->cd_ofs, edit_loop_data);
}
}
diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
index 8d0ba713616..9e3c219a30b 100644
--- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
@@ -119,7 +119,7 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos)
*
* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation
* considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536)
- **/
+ */
vec4 gpencil_vertex(ivec4 ma,
ivec4 ma1,
ivec4 ma2,
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index ed8b8aeb849..7f94b7ea1c1 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -158,7 +158,7 @@ float hair_shaperadius(float shape, float root, float tip, float time)
return (radius * (root - tip)) + tip;
}
-# ifdef OS_MAC
+# if defined(OS_MAC) && defined(GPU_OPENGL)
in float dummy;
# endif
@@ -178,7 +178,7 @@ void hair_get_pos_tan_binor_time(bool is_persp,
wpos = data.point_position;
time = data.point_time;
-# ifdef OS_MAC
+# if defined(OS_MAC) && defined(GPU_OPENGL)
/* Generate a dummy read to avoid the driver bug with shaders having no
* vertex reads on macOS (T60171) */
wpos.y += dummy * 0.0;
diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
index 7b701d1d81b..6d4452c18c8 100644
--- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
@@ -86,7 +86,7 @@ float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
float line_unit_box_intersect_dist_safe(vec3 lineorigin, vec3 linedirection)
{
vec3 safe_linedirection = max(vec3(1e-8), abs(linedirection)) *
- mix(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0)));
+ select(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0)));
return line_unit_box_intersect_dist(lineorigin, safe_linedirection);
}
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index 1701056cbb7..4d0ffaeb40f 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -84,9 +84,9 @@ float avg(vec3 v) { return dot(vec3(1.0 / 3.0), v); }
float avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); }
float safe_rcp(float a) { return (a != 0.0) ? (1.0 / a) : 0.0; }
-vec2 safe_rcp(vec2 a) { return mix(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); }
-vec3 safe_rcp(vec3 a) { return mix(vec3(0.0), (1.0 / a), notEqual(a, vec3(0.0))); }
-vec4 safe_rcp(vec4 a) { return mix(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); }
+vec2 safe_rcp(vec2 a) { return select(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); }
+vec3 safe_rcp(vec3 a) { return select(vec3(0.0), (1.0 / a), notEqual(a, vec3(0.0))); }
+vec4 safe_rcp(vec4 a) { return select(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); }
float safe_sqrt(float a) { return sqrt(max(a, 0.0)); }
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 2ac157ad208..6c58752c8bb 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -174,7 +174,7 @@ flat in int resourceIDFrag;
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && (!defined(OS_MAC) || defined(GPU_METAL)) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)
/* clang-format on */
/* Temporary until we fully make the switch. */
@@ -251,7 +251,7 @@ uniform mat4 ModelMatrixInverse;
/* Due to some shader compiler bug, we somewhat need to access gl_VertexID
* to make vertex shaders work. even if it's actually dead code. */
-#ifdef GPU_INTEL
+#if defined(GPU_INTEL) && defined(GPU_OPENGL)
# define GPU_INTEL_VERTEX_SHADER_WORKAROUND gl_Position.x = float(gl_VertexID);
#else
# define GPU_INTEL_VERTEX_SHADER_WORKAROUND
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index df418b204f9..08379be36fa 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1131,7 +1131,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
{
AnimChanRearrangeFp rearrange_func;
ListBase anim_data_visible = {NULL, NULL};
- const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ac->obact);
+ const bool is_liboverride = (ac->obact != NULL) ? ID_IS_OVERRIDE_LIBRARY(ac->obact) : false;
/* hack: invert mode so that functions will work in right order */
mode *= -1;
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index dcf8835c911..6fcdd21bad8 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -715,54 +715,55 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
+ Scene *scene = CTX_data_scene(C);
KeyingSet *ks;
EnumPropertyItem *item = NULL, item_tmp = {0};
int totitem = 0;
int i = 0;
- if (C != NULL) {
- Scene *scene = CTX_data_scene(C);
- /* active Keying Set
- * - only include entry if it exists
- */
- if (scene->active_keyingset) {
- /* active Keying Set */
- item_tmp.identifier = "__ACTIVE__";
- item_tmp.name = "Active Keying Set";
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ if (C == NULL) {
+ return DummyRNA_DEFAULT_items;
+ }
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
- }
+ /* active Keying Set
+ * - only include entry if it exists
+ */
+ if (scene->active_keyingset) {
+ /* active Keying Set */
+ item_tmp.identifier = "__ACTIVE__";
+ item_tmp.name = "Active Keying Set";
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
- i++;
+ i++;
- /* user-defined Keying Sets
- * - these are listed in the order in which they were defined for the active scene
- */
- if (scene->keyingsets.first) {
- for (ks = scene->keyingsets.first; ks; ks = ks->next, i++) {
- if (ANIM_keyingset_context_ok_poll(C, ks)) {
- item_tmp.identifier = ks->idname;
- item_tmp.name = ks->name;
- item_tmp.description = ks->description;
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
+ /* user-defined Keying Sets
+ * - these are listed in the order in which they were defined for the active scene
+ */
+ if (scene->keyingsets.first) {
+ for (ks = scene->keyingsets.first; ks; ks = ks->next, i++) {
+ if (ANIM_keyingset_context_ok_poll(C, ks)) {
+ item_tmp.identifier = ks->idname;
+ item_tmp.name = ks->name;
+ item_tmp.description = ks->description;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
}
-
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
}
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
}
/* builtin Keying Sets */
i = -1;
for (ks = builtin_keyingsets.first; ks; ks = ks->next, i--) {
- /* Only show #KeyingSet if context is suitable or if there is no context which is needed
- * to support key-bindings to be assigned since key bindings are not context aware. */
- if ((C == NULL) || ANIM_keyingset_context_ok_poll(C, ks)) {
+ /* only show KeyingSet if context is suitable */
+ if (ANIM_keyingset_context_ok_poll(C, ks)) {
item_tmp.identifier = ks->idname;
item_tmp.name = ks->name;
item_tmp.description = ks->description;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 54bd1a2cebb..0f4f0ef48ff 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1976,6 +1976,9 @@ static void UI_OT_drop_name(wmOperatorType *ot)
static bool ui_list_focused_poll(bContext *C)
{
const ARegion *region = CTX_wm_region(C);
+ if (!region) {
+ return false;
+ }
const wmWindow *win = CTX_wm_window(C);
const uiList *list = UI_list_find_mouse_over(region, win->eventstate);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 077eedd6e58..38499a7f089 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -6223,16 +6223,13 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout,
ColorManagedViewSettings *view_settings = view_transform_ptr.data;
uiLayout *col = uiLayoutColumn(layout, false);
-
- uiLayout *row = uiLayoutRow(col, false);
- uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
+ uiItemR(col, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
+ uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE);
uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE);
- uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE);
-
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE);
if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index faf449a77aa..d3fc83eedd7 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -108,6 +108,7 @@ static int geometry_extract_apply(bContext *C,
new_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BMEditMesh *em = BKE_editmesh_create(bm);
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 9c7d712a739..ecc5f8f8ef5 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -673,6 +673,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em)
(&(struct BMeshFromMeshParams){
/* Handled with tessellation. */
.calc_face_normal = false,
+ .calc_vert_normal = false,
.active_shapekey = um->shapenr,
}));
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index b0c8646dd04..7fedc2c6265 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -2219,7 +2219,7 @@ static int multires_unsubdivide_exec(bContext *C, wmOperator *op)
int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
if (new_levels == 0) {
- BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level");
+ BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild a lower level");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index 1970851c326..24425b5a991 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -1135,7 +1135,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
if (ob->data == nullptr) {
- /* special support for dupligroups */
+ /* Special support for instanced collections. */
if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection &&
(ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) {
if (ID_IS_LINKED(ob->instance_collection)) {
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 247948c7e6d..7392f05aea4 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
)
set(SRC
+ curves_sculpt_3d_brush.cc
curves_sculpt_add.cc
curves_sculpt_comb.cc
curves_sculpt_delete.cc
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc
new file mode 100644
index 00000000000..94c0f5536b7
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+
+#include "ED_view3d.h"
+
+#include "UI_interface.h"
+
+#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_task.hh"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+struct BrushPositionCandidate {
+ /** 3D position of the brush. */
+ float3 position_cu;
+ /** Squared distance from the mouse position in screen space. */
+ float distance_sq_re = FLT_MAX;
+ /** Measure for how far away the candidate is from the camera. */
+ float depth_sq_cu = FLT_MAX;
+};
+
+/**
+ * Determine the 3D position of a brush based on curve segments under a screen position.
+ */
+static std::optional<float3> find_curves_brush_position(const CurvesGeometry &curves,
+ const float3 &ray_start_cu,
+ const float3 &ray_end_cu,
+ const float brush_radius_re,
+ ARegion &region,
+ RegionView3D &rv3d,
+ Object &object)
+{
+ /* This value might have to be adjusted based on user feedback. */
+ const float brush_inner_radius_re = std::min<float>(brush_radius_re, (float)UI_UNIT_X / 3.0f);
+ const float brush_inner_radius_sq_re = pow2f(brush_inner_radius_re);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(&rv3d, &object, projection.values);
+
+ float2 brush_pos_re;
+ ED_view3d_project_float_v2_m4(&region, ray_start_cu, brush_pos_re, projection.values);
+
+ const float max_depth_sq_cu = math::distance_squared(ray_start_cu, ray_end_cu);
+
+ /* Contains the logic that checks if `b` is a better candidate than `a`. */
+ auto is_better_candidate = [&](const BrushPositionCandidate &a,
+ const BrushPositionCandidate &b) {
+ if (b.distance_sq_re <= brush_inner_radius_sq_re) {
+ if (a.distance_sq_re > brush_inner_radius_sq_re) {
+ /* New candidate is in inner radius while old one is not. */
+ return true;
+ }
+ else if (b.depth_sq_cu < a.depth_sq_cu) {
+ /* Both candidates are in inner radius, but new one is closer to the camera. */
+ return true;
+ }
+ }
+ else if (b.distance_sq_re < a.distance_sq_re) {
+ /* Both candidates are outside of inner radius, but new on is closer to the brush center. */
+ return true;
+ }
+ return false;
+ };
+
+ auto update_if_better = [&](BrushPositionCandidate &a, const BrushPositionCandidate &b) {
+ if (is_better_candidate(a, b)) {
+ a = b;
+ }
+ };
+
+ const Span<float3> positions = curves.positions();
+
+ BrushPositionCandidate best_candidate = threading::parallel_reduce(
+ curves.curves_range(),
+ 128,
+ BrushPositionCandidate(),
+ [&](IndexRange curves_range, const BrushPositionCandidate &init) {
+ BrushPositionCandidate best_candidate = init;
+
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.range_for_curve(curve_i);
+ const int tot_segments = points.size() - 1;
+
+ for (const int segment_i : IndexRange(tot_segments)) {
+ const float3 &p1_cu = positions[points[segment_i]];
+ const float3 &p2_cu = positions[points[segment_i] + 1];
+
+ float2 p1_re, p2_re;
+ ED_view3d_project_float_v2_m4(&region, p1_cu, p1_re, projection.values);
+ ED_view3d_project_float_v2_m4(&region, p2_cu, p2_re, projection.values);
+
+ float2 closest_re;
+ const float lambda = closest_to_line_segment_v2(
+ closest_re, brush_pos_re, p1_re, p2_re);
+
+ const float3 closest_cu = math::interpolate(p1_cu, p2_cu, lambda);
+ const float depth_sq_cu = math::distance_squared(ray_start_cu, closest_cu);
+ if (depth_sq_cu > max_depth_sq_cu) {
+ continue;
+ }
+
+ const float distance_sq_re = math::distance_squared(brush_pos_re, closest_re);
+
+ BrushPositionCandidate candidate;
+ candidate.position_cu = closest_cu;
+ candidate.depth_sq_cu = depth_sq_cu;
+ candidate.distance_sq_re = distance_sq_re;
+
+ update_if_better(best_candidate, candidate);
+ }
+ }
+ return best_candidate;
+ },
+ [&](const BrushPositionCandidate &a, const BrushPositionCandidate &b) {
+ return is_better_candidate(a, b) ? b : a;
+ });
+
+ if (best_candidate.distance_sq_re == FLT_MAX) {
+ /* Nothing found. */
+ return std::nullopt;
+ }
+
+ return best_candidate.position_cu;
+}
+
+std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
+ Object &curves_object,
+ const float2 &brush_pos_re,
+ const float brush_radius_re)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
+ ARegion *region = CTX_wm_region(&C);
+ View3D *v3d = CTX_wm_view3d(&C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(&C);
+
+ Curves &curves_id = *static_cast<Curves *>(curves_object.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ Object *surface_object = curves_id.surface;
+
+ float3 center_ray_start_wo, center_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph, region, v3d, brush_pos_re, center_ray_start_wo, center_ray_end_wo, true);
+
+ /* Shorten ray when the surface object is hit. */
+ if (surface_object != nullptr) {
+ const float4x4 surface_to_world_mat = surface_object->obmat;
+ const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
+
+ Mesh &surface = *static_cast<Mesh *>(surface_object->data);
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ const float3 center_ray_start_su = world_to_surface_mat * center_ray_start_wo;
+ float3 center_ray_end_su = world_to_surface_mat * center_ray_end_wo;
+ const float3 center_ray_direction_su = math::normalize(center_ray_end_su -
+ center_ray_start_su);
+
+ BVHTreeRayHit center_ray_hit;
+ center_ray_hit.dist = FLT_MAX;
+ center_ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh.tree,
+ center_ray_start_su,
+ center_ray_direction_su,
+ 0.0f,
+ &center_ray_hit,
+ surface_bvh.raycast_callback,
+ &surface_bvh);
+ if (center_ray_hit.index >= 0) {
+ const float3 hit_position_su = center_ray_hit.co;
+ if (math::distance(center_ray_start_su, center_ray_end_su) >
+ math::distance(center_ray_start_su, hit_position_su)) {
+ center_ray_end_su = hit_position_su;
+ center_ray_end_wo = surface_to_world_mat * center_ray_end_su;
+ }
+ }
+ }
+
+ const float4x4 curves_to_world_mat = curves_object.obmat;
+ const float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
+
+ const float3 center_ray_start_cu = world_to_curves_mat * center_ray_start_wo;
+ const float3 center_ray_end_cu = world_to_curves_mat * center_ray_end_wo;
+
+ const std::optional<float3> brush_position_optional_cu = find_curves_brush_position(
+ curves,
+ center_ray_start_cu,
+ center_ray_end_cu,
+ brush_radius_re,
+ *region,
+ *rv3d,
+ curves_object);
+ if (!brush_position_optional_cu.has_value()) {
+ /* Nothing found. */
+ return std::nullopt;
+ }
+ const float3 brush_position_cu = *brush_position_optional_cu;
+
+ /* Determine the 3D brush radius. */
+ float3 radius_ray_start_wo, radius_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(depsgraph,
+ region,
+ v3d,
+ brush_pos_re + float2(brush_radius_re, 0.0f),
+ radius_ray_start_wo,
+ radius_ray_end_wo,
+ true);
+ const float3 radius_ray_start_cu = world_to_curves_mat * radius_ray_start_wo;
+ const float3 radius_ray_end_cu = world_to_curves_mat * radius_ray_end_wo;
+
+ CurvesBrush3D brush_3d;
+ brush_3d.position_cu = brush_position_cu;
+ brush_3d.radius_cu = dist_to_line_v3(brush_position_cu, radius_ray_start_cu, radius_ray_end_cu);
+ return brush_3d;
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index 6c13704a3a6..35b2b2ce956 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -35,129 +35,340 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "UI_interface.h"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
namespace blender::ed::sculpt_paint {
using blender::bke::CurvesGeometry;
+using threading::EnumerableThreadSpecific;
/**
* Moves individual points under the brush and does a length preservation step afterwards.
*/
class CombOperation : public CurvesSculptStrokeOperation {
private:
- float2 last_mouse_position_;
+ /** Last mouse position. */
+ float2 brush_pos_last_re_;
+
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ /** Length of each segment indexed by the index of the first point in the segment. */
+ Array<float> segment_lengths_cu_;
+
+ friend struct CombOperationExecutor;
public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct CombOperationExecutor {
+ CombOperation *self_ = nullptr;
+ bContext *C_ = nullptr;
+ Depsgraph *depsgraph_ = nullptr;
+ Scene *scene_ = nullptr;
+ Object *object_ = nullptr;
+ ARegion *region_ = nullptr;
+ View3D *v3d_ = nullptr;
+ RegionView3D *rv3d_ = nullptr;
+
+ CurvesSculpt *curves_sculpt_ = nullptr;
+ Brush *brush_ = nullptr;
+ float brush_radius_re_;
+ float brush_strength_;
+
+ eBrushFalloffShape falloff_shape_;
+
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ const Object *surface_ob_ = nullptr;
+ const Mesh *surface_ = nullptr;
+ Span<MLoopTri> surface_looptris_;
+
+ float2 brush_pos_prev_re_;
+ float2 brush_pos_re_;
+ float2 brush_pos_diff_re_;
+ float brush_pos_diff_length_re_;
+
+ float4x4 curves_to_world_mat_;
+ float4x4 world_to_curves_mat_;
+ float4x4 surface_to_world_mat_;
+ float4x4 world_to_surface_mat_;
+
+ BVHTreeFromMesh surface_bvh_;
+
+ void execute(CombOperation &self, bContext *C, const StrokeExtension &stroke_extension)
{
- BLI_SCOPED_DEFER([&]() { last_mouse_position_ = stroke_extension.mouse_position; });
+ self_ = &self;
+
+ BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; });
+
+ C_ = C;
+ depsgraph_ = CTX_data_depsgraph_pointer(C);
+ scene_ = CTX_data_scene(C);
+ object_ = CTX_data_active_object(C);
+ region_ = CTX_wm_region(C);
+ v3d_ = CTX_wm_view3d(C);
+ rv3d_ = CTX_wm_region_view3d(C);
+
+ curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+ brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
+
+ curves_to_world_mat_ = object_->obmat;
+ world_to_curves_mat_ = curves_to_world_mat_.inverted();
+
+ falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+
+ brush_pos_prev_re_ = self_->brush_pos_last_re_;
+ brush_pos_re_ = stroke_extension.mouse_position;
+ brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
+ brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_);
+
+ surface_ob_ = curves_id_->surface;
+ if (surface_ob_ != nullptr) {
+ surface_ = static_cast<const Mesh *>(surface_ob_->data);
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+ surface_to_world_mat_ = surface_ob_->obmat;
+ world_to_surface_mat_ = surface_to_world_mat_.inverted();
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ }
+
+ BLI_SCOPED_DEFER([&]() {
+ if (surface_ob_ != nullptr) {
+ free_bvhtree_from_mesh(&surface_bvh_);
+ }
+ });
if (stroke_extension.is_first) {
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->initialize_spherical_brush_reference_point();
+ }
+ this->initialize_segment_lengths();
+ /* Combing does nothing when there is no mouse movement, so return directly. */
return;
}
- Scene &scene = *CTX_data_scene(C);
- Object &object = *CTX_data_active_object(C);
- ARegion *region = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ EnumerableThreadSpecific<Vector<int>> changed_curves;
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
- const float brush_radius = BKE_brush_size_get(&scene, &brush);
- const float brush_strength = BKE_brush_alpha_get(&scene, &brush);
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->comb_projected(changed_curves);
+ }
+ else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->comb_spherical(changed_curves);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
- const float4x4 ob_mat = object.obmat;
- const float4x4 ob_imat = ob_mat.inverted();
+ this->restore_segment_lengths(changed_curves);
- float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(region_);
+ }
+
+ /**
+ * Do combing in screen space.
+ */
+ void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions();
- Curves &curves_id = *static_cast<Curves *>(object.data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- MutableSpan<float3> positions = curves.positions();
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
- const float2 mouse_prev = last_mouse_position_;
- const float2 mouse_cur = stroke_extension.mouse_position;
- const float2 mouse_diff = mouse_cur - mouse_prev;
- const float mouse_diff_len = math::length(mouse_diff);
+ const float brush_radius_sq_re = pow2f(brush_radius_re_);
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ Vector<int> &local_changed_curves = r_changed_curves.local();
for (const int curve_i : curves_range) {
- const IndexRange curve_points = curves.range_for_curve(curve_i);
- /* Compute lengths of the segments. Those are used to make sure that the lengths don't
- * change. */
- Vector<float, 16> segment_lengths(curve_points.size() - 1);
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- const float3 &p2 = positions[curve_points[segment_i] + 1];
- const float length = math::distance(p1, p2);
- segment_lengths[segment_i] = length;
- }
bool curve_changed = false;
- for (const int point_i : curve_points.drop_front(1)) {
- const float3 old_position = positions[point_i];
+ const IndexRange points = curves_->range_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 old_pos_cu = positions_cu[point_i];
/* Find the position of the point in screen space. */
- float2 old_position_screen;
- ED_view3d_project_float_v2_m4(
- region, old_position, old_position_screen, projection.values);
-
- /* Project the point onto the line drawn by the mouse. Note, it's projected on the
- * infinite line, not only on the line segment. */
- float2 old_position_screen_proj;
- /* t is 0 when the point is closest to the previous mouse position and 1 when it's
- * closest to the current mouse position. */
- const float t = closest_to_line_v2(
- old_position_screen_proj, old_position_screen, mouse_prev, mouse_cur);
-
- /* Compute the distance to the mouse line segment. */
- const float2 old_position_screen_proj_segment = mouse_prev +
- std::clamp(t, 0.0f, 1.0f) * mouse_diff;
- const float distance_screen = math::distance(old_position_screen,
- old_position_screen_proj_segment);
- if (distance_screen > brush_radius) {
+ float2 old_pos_re;
+ ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+
+ const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2(
+ old_pos_re, brush_pos_prev_re_, brush_pos_re_);
+ if (distance_to_brush_sq_re > brush_radius_sq_re) {
/* Ignore the point because it's too far away. */
continue;
}
- /* Compute a falloff that is based on how far along the point along the last stroke
- * segment is. */
- const float t_overshoot = brush_radius / mouse_diff_len;
- const float t_falloff = 1.0f - std::max(t, 0.0f) / (1.0f + t_overshoot);
+
+ const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
/* A falloff that is based on how far away the point is from the stroke. */
- const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius);
- /* Combine the different falloffs and brush strength. */
- const float weight = brush_strength * t_falloff * radius_falloff;
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_re, brush_radius_re_);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
/* Offset the old point position in screen space and transform it back into 3D space. */
- const float2 new_position_screen = old_position_screen + mouse_diff * weight;
- float3 new_position;
+ const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
+ float3 new_position_wo;
ED_view3d_win_to_3d(
- v3d, region, ob_mat * old_position, new_position_screen, new_position);
- new_position = ob_imat * new_position;
- positions[point_i] = new_position;
+ v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
+ const float3 new_position_cu = world_to_curves_mat_ * new_position_wo;
+ positions_cu[point_i] = new_position_cu;
curve_changed = true;
}
- if (!curve_changed) {
- continue;
+ if (curve_changed) {
+ local_changed_curves.append(curve_i);
}
- /* Ensure that the length of each segment stays the same. */
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- float3 &p2 = positions[curve_points[segment_i] + 1];
- const float3 direction = math::normalize(p2 - p1);
- const float desired_length = segment_lengths[segment_i];
- p2 = p1 + direction * desired_length;
+ }
+ });
+ }
+
+ /**
+ * Do combing in 3D space.
+ */
+ void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+
+ float3 brush_start_wo, brush_end_wo;
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ brush_pos_prev_re_,
+ brush_start_wo);
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_end_wo);
+ const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
+ const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+
+ const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
+
+ const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ Vector<int> &local_changed_curves = r_changed_curves.local();
+ for (const int curve_i : curves_range) {
+ bool curve_changed = false;
+ const IndexRange points = curves_->range_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 pos_old_cu = positions_cu[point_i];
+
+ /* Compute distance to the brush. */
+ const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3(
+ pos_old_cu, brush_start_cu, brush_end_cu);
+ if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu);
+
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_cu, brush_radius_cu);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ /* Update the point position. */
+ positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu;
+ curve_changed = true;
+ }
+ if (curve_changed) {
+ local_changed_curves.append(curve_i);
}
}
});
+ }
- curves.tag_positions_changed();
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region);
+ /**
+ * Sample depth under mouse by looking at curves and the surface.
+ */
+ void initialize_spherical_brush_reference_point()
+ {
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
+ *C_, *object_, brush_pos_re_, brush_radius_re_);
+ if (brush_3d.has_value()) {
+ self_->brush_3d_ = *brush_3d;
+ }
+ }
+
+ /**
+ * Remember the initial length of all curve segments. This allows restoring the length after
+ * combing.
+ */
+ void initialize_segment_lengths()
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_->points_size());
+ threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves_->range_for_curve(curve_i);
+ for (const int point_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[point_i];
+ const float3 &p2_cu = positions_cu[point_i + 1];
+ const float length_cu = math::distance(p1_cu, p2_cu);
+ self_->segment_lengths_cu_[point_i] = length_cu;
+ }
+ }
+ });
+ }
+
+ /**
+ * Restore previously stored length for each segment in the changed curves.
+ */
+ void restore_segment_lengths(EnumerableThreadSpecific<Vector<int>> &changed_curves)
+ {
+ const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
+ MutableSpan<float3> positions_cu = curves_->positions();
+
+ threading::parallel_for_each(changed_curves, [&](const Vector<int> &changed_curves) {
+ threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : changed_curves.as_span().slice(range)) {
+ const IndexRange points = curves_->range_for_curve(curve_i);
+ for (const int segment_i : IndexRange(points.size() - 1)) {
+ const float3 &p1_cu = positions_cu[points[segment_i]];
+ float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ const float3 direction = math::normalize(p2_cu - p1_cu);
+ const float expected_length_cu = expected_lengths_cu[points[segment_i]];
+ p2_cu = p1_cu + direction * expected_length_cu;
+ }
+ }
+ });
+ });
}
};
+void CombOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+{
+ CombOperationExecutor executor;
+ executor.execute(*this, C, stroke_extension);
+}
+
std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation()
{
return std::make_unique<CombOperation>();
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index d1de69f36b6..d021627921f 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -2,12 +2,22 @@
#pragma once
+#include <optional>
+
#include "curves_sculpt_intern.h"
#include "BLI_math_vector.hh"
+#include "BKE_curves.hh"
+
+struct ARegion;
+struct RegionView3D;
+struct Object;
+
namespace blender::ed::sculpt_paint {
+using bke::CurvesGeometry;
+
struct StrokeExtension {
bool is_first;
float2 mouse_position;
@@ -27,4 +37,17 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation();
+struct CurvesBrush3D {
+ float3 position_cu;
+ float radius_cu;
+};
+
+/**
+ * Find 3d brush position based on cursor position for curves sculpting.
+ */
+std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
+ Object &curves_object,
+ const float2 &brush_pos_re,
+ float brush_radius_re);
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index c05886d1be1..2b55eb379cc 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -962,6 +962,7 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
trim_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
BMO_op_callf(bm,
@@ -1214,12 +1215,14 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
trim_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BM_mesh_bm_from_me(bm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 0d65eef29f5..4f884420401 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -147,6 +147,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
}));
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index db3b8e40f09..7171c241534 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -379,6 +379,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BMIter iter;
@@ -574,6 +575,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
@@ -652,6 +654,7 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode)
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BMIter iter;
BMFace *f;
@@ -1184,6 +1187,7 @@ static void sculpt_face_set_delete_geometry(Object *ob,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BM_mesh_elem_table_init(bm, BM_FACE);
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index abde5f52bb0..208928afc1f 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -958,14 +958,11 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
{
ImageFormatData *imf = imfptr->data;
ID *id = imfptr->owner_id;
- PointerRNA display_settings_ptr;
- PropertyRNA *prop;
const int depth_ok = BKE_imtype_valid_depths(imf->imtype);
/* some settings depend on this being a scene that's rendered */
const bool is_render_out = (id && GS(id->name) == ID_SCE);
uiLayout *col;
- bool show_preview = false;
col = uiLayoutColumn(layout, false);
@@ -1005,7 +1002,6 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
}
if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
- show_preview = true;
uiItemR(col, imfptr, "use_preview", 0, NULL, ICON_NONE);
}
@@ -1037,18 +1033,22 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
uiItemR(col, imfptr, "tiff_codec", 0, NULL, ICON_NONE);
}
- /* color management */
- if (color_management && (!BKE_imtype_requires_linear_float(imf->imtype) ||
- (show_preview && imf->flag & R_IMF_FLAG_PREVIEW_JPG))) {
- prop = RNA_struct_find_property(imfptr, "display_settings");
- display_settings_ptr = RNA_property_pointer_get(imfptr, prop);
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Color Management"), ICON_NONE);
-
- uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE);
+ /* Override color management */
+ if (color_management) {
+ uiItemS(col);
+ uiItemR(col, imfptr, "color_management", 0, NULL, ICON_NONE);
- uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings");
+ if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ if (BKE_imtype_requires_linear_float(imf->imtype)) {
+ PointerRNA linear_settings_ptr = RNA_pointer_get(imfptr, "linear_colorspace_settings");
+ uiItemR(col, &linear_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE);
+ }
+ else {
+ PointerRNA display_settings_ptr = RNA_pointer_get(imfptr, "display_settings");
+ uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE);
+ uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings");
+ }
+ }
}
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 1a7fb67954e..1c4a1d7e8c9 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1737,7 +1737,7 @@ static int image_save_options_init(Main *bmain,
if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
/* imtype */
- BKE_image_format_copy(&opts->im_format, &scene->r.im_format);
+ BKE_image_format_init_for_write(&opts->im_format, scene, NULL);
is_depth_set = true;
if (!BKE_image_is_multiview(ima)) {
/* In case multiview is disabled,
@@ -1759,8 +1759,12 @@ static int image_save_options_init(Main *bmain,
/* use the multiview image settings as the default */
opts->im_format.stereo3d_format = *ima->stereo3d_format;
opts->im_format.views_format = ima->views_format;
+
+ BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene);
}
+ opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
+
if (ima->source == IMA_SRC_TILED) {
BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -1810,13 +1814,6 @@ static int image_save_options_init(Main *bmain,
STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
}
-
- /* color management */
- BKE_color_managed_display_settings_copy(&opts->im_format.display_settings,
- &scene->display_settings);
-
- BKE_color_managed_view_settings_free(&opts->im_format.view_settings);
- BKE_color_managed_view_settings_copy(&opts->im_format.view_settings, &scene->view_settings);
}
BKE_image_release_ibuf(ima, ibuf, lock);
@@ -2006,15 +2003,21 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
ImageSaveData *isd = op->customdata;
PointerRNA imf_ptr;
const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
+ const bool use_color_management = RNA_boolean_get(op->ptr, "save_as_render");
- /* image template */
- RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr);
- uiTemplateImageSettings(layout, &imf_ptr, false);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* main draw call */
uiDefAutoButsRNA(
layout, op->ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ uiItemS(layout);
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr);
+ uiTemplateImageSettings(layout, &imf_ptr, use_color_management);
+
/* multiview template */
if (is_multiview) {
uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 1c278de28d0..956bb581ee6 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -18,6 +18,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -274,28 +275,14 @@ static void compo_startjob(void *cjv,
/* 1 is do_previews */
if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
- ntreeCompositExecTree(cj->scene,
- ntree,
- &cj->scene->r,
- false,
- true,
- &scene->view_settings,
- &scene->display_settings,
- "");
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, "");
}
else {
LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) {
continue;
}
- ntreeCompositExecTree(cj->scene,
- ntree,
- &cj->scene->r,
- false,
- true,
- &scene->view_settings,
- &scene->display_settings,
- srv->name);
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, srv->name);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index a50dde68d28..8b03047b1dd 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -1785,6 +1785,11 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
const ListBase *lb,
const int x)
{
+ const float pad_x = 2.0f * UI_DPI_FAC;
+ const float pad_y = 0.5f * U.pixelsize;
+ const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x);
+ const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y);
+
LISTBASE_FOREACH (const TreeElement *, te, lb) {
const TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner)) {
@@ -1805,10 +1810,6 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
PropertyRNA *prop = &override_elem.override_rna_prop;
const PropertyType prop_type = RNA_property_type(prop);
- const float pad_x = 1 * UI_DPI_FAC;
- const float max_width = OL_RNA_COL_SIZEX - 2 * pad_x;
- const float height = UI_UNIT_Y - U.pixelsize;
-
uiBut *auto_but = uiDefAutoButR(block,
ptr,
prop,
@@ -1816,9 +1817,9 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
(prop_type == PROP_ENUM) ? nullptr : "",
ICON_NONE,
x + pad_x,
- te->ys,
- max_width,
- height);
+ te->ys + pad_y,
+ item_max_width,
+ item_height);
/* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons
* need to be handled. */
if (auto_but) {
@@ -1828,7 +1829,8 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block,
if (!auto_but) {
/* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension
* arrays? */
- uiDefAutoButsArrayR(block, ptr, prop, ICON_NONE, x, te->ys, max_width, height);
+ uiDefAutoButsArrayR(
+ block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height);
}
}
}
@@ -3915,7 +3917,7 @@ void draw_outliner(const bContext *C)
block, region, space_outliner, &space_outliner->tree, true);
UI_block_emboss_set(block, UI_EMBOSS);
- const int x = region->v2d.cur.xmax - OL_RNA_COL_SIZEX;
+ const int x = region->v2d.cur.xmax - right_column_width;
outliner_draw_separator(region, x);
outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x);
UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 73155a3b52f..6f55acff6a2 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1550,12 +1550,16 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-static Base *object_mouse_select_menu(bContext *C,
- ViewContext *vc,
- const GPUSelectResult *buffer,
- const int hits,
- const int mval[2],
- const struct SelectPick_Params *params)
+/**
+ * \return True when a menu was activated.
+ */
+static bool object_mouse_select_menu(bContext *C,
+ ViewContext *vc,
+ const GPUSelectResult *buffer,
+ const int hits,
+ const int mval[2],
+ const struct SelectPick_Params *params,
+ Base **r_basact)
{
int base_count = 0;
bool ok;
@@ -1596,13 +1600,16 @@ static Base *object_mouse_select_menu(bContext *C,
}
CTX_DATA_END;
+ *r_basact = NULL;
+
if (base_count == 0) {
- return NULL;
+ return false;
}
if (base_count == 1) {
Base *base = (Base *)linklist.list->link;
BLI_linklist_free(linklist.list, NULL);
- return base;
+ *r_basact = base;
+ return false;
}
/* UI, full in static array values that we later use in an enum function */
@@ -1631,7 +1638,7 @@ static Base *object_mouse_select_menu(bContext *C,
WM_operator_properties_free(&ptr);
BLI_linklist_free(linklist.list, NULL);
- return NULL;
+ return true;
}
static int bone_select_menu_exec(bContext *C, wmOperator *op)
@@ -1735,6 +1742,10 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/**
+ * \return True when a menu was activated.
+ */
static bool bone_mouse_select_menu(bContext *C,
const GPUSelectResult *buffer,
const int hits,
@@ -2189,6 +2200,49 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
return basact;
}
+static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const int mval[2])
+{
+ ARegion *region = vc->region;
+ ViewLayer *view_layer = vc->view_layer;
+ View3D *v3d = vc->v3d;
+
+ Base *oldbasact = BASACT(view_layer);
+
+ const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
+ float dist = ED_view3d_select_dist_px() * 1.3333f;
+ Base *basact = NULL;
+
+ /* Put the active object at a disadvantage to cycle through other objects. */
+ const float penalty_dist = 10.0f * UI_DPI_FAC;
+ Base *base = startbase;
+ while (base) {
+ if (BASE_SELECTABLE(v3d, base)) {
+ float screen_co[2];
+ if (ED_view3d_project_float_global(
+ region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
+ V3D_PROJ_RET_OK) {
+ float dist_test = len_manhattan_v2v2(mval_fl, screen_co);
+ if (base == oldbasact) {
+ dist_test += penalty_dist;
+ }
+ if (dist_test < dist) {
+ dist = dist_test;
+ basact = base;
+ }
+ }
+ }
+ base = base->next;
+
+ if (base == NULL) {
+ base = FIRSTBASE(view_layer);
+ }
+ if (base == startbase) {
+ break;
+ }
+ }
+ return basact;
+}
+
static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
const int mval[2],
int *r_material_slot)
@@ -2365,184 +2419,203 @@ static bool ed_object_select_pick_camera_track(bContext *C,
return changed || found;
}
+/**
+ * Cursor selection picking for object & pose-mode.
+ *
+ * \param mval: Region relative cursor coordinates.
+ * \param params: Selection parameters.
+ * \param center: Select by the cursors on-screen distances to the center/origin
+ * instead of the geometry any other contents of the item being selected.
+ * This could be used to select by bones by their origin too, currently it's only used for objects.
+ * \param enumerate: Show a menu for objects at the cursor location.
+ * Otherwise fall-through to non-menu selection.
+ * \param object_only: Only select objects (not bones / track markers).
+ */
static bool ed_object_select_pick(bContext *C,
const int mval[2],
const struct SelectPick_Params *params,
- bool obcenter,
- bool enumerate,
- bool object)
+ const bool center,
+ const bool enumerate,
+ const bool object_only)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* Setup view context for argument to callbacks. */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- const ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- /* Don't set when the context has no active object (hidden), see: T60807. */
- const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
- Base *base, *startbase = NULL, *basact = NULL;
- const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
- const bool is_obedit = (vc.obedit != NULL);
- float dist = ED_view3d_select_dist_px() * 1.3333f;
- const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
-
- /* Handle setting the new base active */
- bool use_activate_selected_base = false;
+ Scene *scene = vc.scene;
+ View3D *v3d = vc.v3d;
- /* When enabled, don't attempt any further selection. */
- bool handled = false;
- bool changed = false;
+ /* Menu activation may find a base to make active (if it only finds a single item to select). */
+ Base *basact_override = NULL;
- if (object) {
+ const bool is_obedit = (vc.obedit != NULL);
+ if (object_only) {
/* Signal for #view3d_opengl_select to skip edit-mode objects. */
vc.obedit = NULL;
}
- /* In pose-mode we don't want to change the object selection (unless exiting pose mode). */
- const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE);
-
- /* Always start list from `basact` when cycling the selection. */
- startbase = FIRSTBASE(view_layer);
- if (oldbasact && oldbasact->next) {
- startbase = oldbasact->next;
- }
-
- /* This block uses the control key to make the object selected
- * by its center point rather than its contents */
-
- /* In edit-mode do not activate. */
- if (obcenter) {
-
- /* NOTE: shift+alt goes to group-flush-selecting. */
- if (enumerate) {
- basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, params);
+ /* Set for GPU depth buffer picking, leave NULL when selecting by center. */
+ struct {
+ GPUSelectResult buffer[MAXPICKELEMS];
+ int hits;
+ bool do_nearest;
+ bool has_bones;
+ } *gpu = NULL;
+
+ /* First handle menu selection, early exit if a menu opens
+ * since this takes ownership of the selection action.
+ *
+ * Even when there is no menu `basact_override` may be set to avoid having to re-find
+ * the item under the cursor. */
+
+ if (center == false) {
+ gpu = MEM_mallocN(sizeof(*gpu), __func__);
+ gpu->do_nearest = false;
+ gpu->has_bones = false;
+
+ /* If objects have pose-mode set, the bones are in the same selection buffer. */
+ const eV3DSelectObjectFilter select_filter = ((object_only == false) ?
+ ED_view3d_select_filter_from_mode(scene,
+ vc.obact) :
+ VIEW3D_SELECT_FILTER_NOP);
+ gpu->hits = mixed_bones_object_selectbuffer_extended(&vc,
+ gpu->buffer,
+ ARRAY_SIZE(gpu->buffer),
+ mval,
+ select_filter,
+ true,
+ enumerate,
+ &gpu->do_nearest);
+ gpu->has_bones = (object_only && gpu->hits > 0) ?
+ false :
+ selectbuffer_has_bones(gpu->buffer, gpu->hits);
+ }
+
+ /* First handle menu selection, early exit when a menu was opened.
+ * Otherwise fall through to regular selection. */
+ if (enumerate) {
+ bool has_menu = false;
+ if (center) {
+ if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) {
+ has_menu = true;
+ }
}
else {
- /* Put the active object at a disadvantage to cycle through other objects. */
- const float penalty_dist = 10.0f * U.dpi_fac;
- base = startbase;
- while (base) {
- if (BASE_SELECTABLE(v3d, base)) {
- float screen_co[2];
- if (ED_view3d_project_float_global(
- region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
- V3D_PROJ_RET_OK) {
- float dist_test = len_manhattan_v2v2(mval_fl, screen_co);
- if (base == oldbasact) {
- dist_test += penalty_dist;
- }
- if (dist_test < dist) {
- dist = dist_test;
- basact = base;
- }
- }
+ if (gpu->hits != 0) {
+ if (gpu->has_bones && bone_mouse_select_menu(C, gpu->buffer, gpu->hits, false, params)) {
+ has_menu = true;
}
- base = base->next;
-
- if (base == NULL) {
- base = FIRSTBASE(view_layer);
- }
- if (base == startbase) {
- break;
+ else if (object_mouse_select_menu(
+ C, &vc, gpu->buffer, gpu->hits, mval, params, &basact_override)) {
+ has_menu = true;
}
}
}
- if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if (is_obedit == false) {
- if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
- if (object_mode == OB_MODE_OBJECT) {
- struct Main *bmain = CTX_data_main(C);
- ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
- }
- if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
- basact = NULL;
- }
- }
+
+ /* Let the menu handle any further actions. */
+ if (has_menu) {
+ if (gpu != NULL) {
+ MEM_freeN(gpu);
}
+ return false;
}
}
- else {
- GPUSelectResult buffer[MAXPICKELEMS];
- bool do_nearest;
- // TIMEIT_START(select_time);
+ /* No menu, continue with selection. */
- /* if objects have pose-mode set, the bones are in the same selection buffer */
- const eV3DSelectObjectFilter select_filter = ((object == false) ?
- ED_view3d_select_filter_from_mode(scene,
- vc.obact) :
- VIEW3D_SELECT_FILTER_NOP);
- const int hits = mixed_bones_object_selectbuffer_extended(
- &vc, buffer, ARRAY_SIZE(buffer), mval, select_filter, true, enumerate, &do_nearest);
+ ViewLayer *view_layer = vc.view_layer;
+ /* Don't set when the context has no active object (hidden), see: T60807. */
+ const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
+ /* Always start list from `basact` when cycling the selection. */
+ Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer);
+
+ /* The next object's base to make active. */
+ Base *basact = NULL;
+ const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
- // TIMEIT_END(select_time);
+ /* When enabled, don't attempt any further selection. */
+ bool handled = false;
- const bool has_bones = (object && hits > 0) ? false : selectbuffer_has_bones(buffer, hits);
+ /* Split `changed` into data-types so their associated updates can be properly performed.
+ * This is also needed as multiple changes may happen at once.
+ * Selecting a pose-bone or track can also select the object for e.g. */
+ bool changed_object = false;
+ bool changed_pose = false;
+ bool changed_track = false;
- if (hits > 0) {
- /* NOTE: bundles are handling in the same way as bones. */
+ /* Handle setting the new base active (even when `handled == true`). */
+ bool use_activate_selected_base = false;
- /* NOTE: shift+alt goes to group-flush-selecting. */
- if (enumerate) {
- if (has_bones && bone_mouse_select_menu(C, buffer, hits, false, params)) {
- handled = true;
- }
- else {
- basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, params);
- }
- }
- else {
- basact = mouse_select_eval_buffer(
- &vc, buffer, hits, startbase, has_bones, do_nearest, NULL);
- }
+ if (center) {
+ if (basact_override) {
+ basact = basact_override;
+ }
+ else {
+ basact = mouse_select_object_center(&vc, startbase, mval);
+ }
+ }
+ else {
+ if (basact_override) {
+ basact = basact_override;
+ }
+ else {
+ basact =
+ (gpu->hits > 0) ?
+ mouse_select_eval_buffer(
+ &vc, gpu->buffer, gpu->hits, startbase, gpu->has_bones, gpu->do_nearest, NULL) :
+ NULL;
}
- if ((handled == false) &&
- (((hits > 0) && has_bones) ||
- /* Special case, even when there are no hits, pose logic may de-select all bones. */
- ((hits == 0) && is_pose_mode))) {
+ /* Select pose-bones or camera-tracks. */
+ if (((gpu->hits > 0) && gpu->has_bones) ||
+ /* Special case, even when there are no hits, pose logic may de-select all bones. */
+ ((gpu->hits == 0) && (object_mode & OB_MODE_POSE))) {
- if (basact && (has_bones && (basact->object->type == OB_CAMERA))) {
+ if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) {
MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
if (clip != NULL) {
- if (ed_object_select_pick_camera_track(C, scene, basact, clip, buffer, hits, params)) {
+ if (ed_object_select_pick_camera_track(
+ C, scene, basact, clip, gpu->buffer, gpu->hits, params)) {
ED_object_base_select(basact, BA_SELECT);
-
/* Don't set `handled` here as the object activation may be necessary. */
- changed = true;
+ changed_object = true;
+
+ changed_track = true;
}
else {
/* Fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object. */
basact = mouse_select_eval_buffer(
- &vc, buffer, hits, startbase, false, do_nearest, NULL);
+ &vc, gpu->buffer, gpu->hits, startbase, false, gpu->do_nearest, NULL);
}
}
}
else if (ED_armature_pose_select_pick_with_buffer(view_layer,
v3d,
basact ? basact : (Base *)oldbasact,
- buffer,
- hits,
+ gpu->buffer,
+ gpu->hits,
params,
- do_nearest)) {
+ gpu->do_nearest)) {
+
+ changed_pose = true;
+
/* When there is no `baseact` this will have operated on `oldbasact`,
- * no object operations are needed. */
+ * allowing #SelectPick_Params.deselect_all work in pose-mode.
+ * In this case no object operations are needed. */
if (basact != NULL) {
- /* then bone is found */
- /* we make the armature selected:
- * not-selected active object in pose-mode won't work well for tools */
+ /* By convention the armature-object is selected when in pose-mode.
+ * While leaving it unselected will work, leaving pose-mode would leave the object
+ * active + unselected which isn't ideal when performing other actions on the object. */
ED_object_base_select(basact, BA_SELECT);
+ changed_object = true;
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
- DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- /* In weight-paint, we use selected bone to select vertex-group,
- * so don't switch to new active object. */
+ /* In weight-paint, we use selected bone to select vertex-group.
+ * In this case the active object mustn't change as it would leave weight-paint mode. */
if (oldbasact) {
if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) {
/* Prevent activating.
@@ -2553,7 +2626,7 @@ static bool ed_object_select_pick(bContext *C,
handled = true;
}
- else if (is_pose_mode && (basact->object->mode & OB_MODE_POSE)) {
+ else if ((object_mode & OB_MODE_POSE) && (basact->object->mode & OB_MODE_POSE)) {
/* Within pose-mode, keep the current selection when switching pose bones,
* this is noticeable when in pose mode with multiple objects at once.
* Where selecting the bone of a different object would de-select this one.
@@ -2578,36 +2651,36 @@ static bool ed_object_select_pick(bContext *C,
handled = true;
}
}
+ }
+ if (handled == false) {
if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if ((handled == false) && (is_obedit == false)) {
+ /* No special logic in edit-mode. */
+ if (is_obedit == false) {
if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
- struct Main *bmain = CTX_data_main(C);
+ struct Main *bmain = vc.bmain;
ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
}
if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
basact = NULL;
}
}
- }
- }
- }
- if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- /* Disallow switching modes,
- * special exception for edit-mode - vertex-parent operator. */
- if ((handled == false) && (is_obedit == false)) {
- if (oldbasact && basact) {
- if ((oldbasact->object->mode != basact->object->mode) &&
- (oldbasact->object->mode & basact->object->mode) == 0) {
- basact = NULL;
+ /* Disallow switching modes,
+ * special exception for edit-mode - vertex-parent operator. */
+ if (basact && oldbasact) {
+ if ((oldbasact->object->mode != basact->object->mode) &&
+ (oldbasact->object->mode & basact->object->mode) == 0) {
+ basact = NULL;
+ }
}
}
}
}
- /* Ensure code above doesn't change the active base. */
+ /* Ensure code above doesn't change the active base. This code is already fairly involved,
+ * it's best if changing the active object is localized to a single place. */
BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
bool found = (basact != NULL);
@@ -2620,20 +2693,22 @@ static bool ed_object_select_pick(bContext *C,
else if (found || params->deselect_all) {
/* Deselect everything. */
/* `basact` may be NULL. */
- changed |= object_deselect_all_except(view_layer, basact);
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ if (object_deselect_all_except(view_layer, basact)) {
+ changed_object = true;
+ }
}
}
}
- /* so, do we have something selected? */
if ((handled == false) && found) {
- changed = true;
if (vc.obedit) {
- /* Only do the select (use for setting vertex parents & hooks). */
+ /* Only do the select (use for setting vertex parents & hooks).
+ * In edit-mode do not activate. */
object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
+
+ changed_object = true;
}
/* Also prevent making it active on mouse selection. */
else if (BASE_SELECTABLE(v3d, basact)) {
@@ -2661,11 +2736,8 @@ static bool ed_object_select_pick(bContext *C,
break;
}
case SEL_OP_SET: {
- /* When enabled, this puts other objects out of multi pose-mode. */
- if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) {
- object_deselect_all_except(view_layer, basact);
- ED_object_base_select(basact, BA_SELECT);
- }
+ object_deselect_all_except(view_layer, basact);
+ ED_object_base_select(basact, BA_SELECT);
break;
}
case SEL_OP_AND: {
@@ -2673,52 +2745,37 @@ static bool ed_object_select_pick(bContext *C,
break;
}
}
- }
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ changed_object = true;
+ }
}
+ /* Perform the activation even when 'handled', since this is used to ensure
+ * the object from the pose-bone selected is also activated. */
if (use_activate_selected_base && (basact != NULL)) {
- changed = true;
+ changed_object = true;
ED_object_base_activate(C, basact); /* adds notifier */
if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) {
WM_toolsystem_update_from_context_view3d(C);
}
}
- if (changed) {
- if (use_activate_selected_base) {
- /* Set special modes for grease pencil
- * The grease pencil modes are not real modes, but a hack to make the interface
- * consistent, so need some tricks to keep UI synchronized */
- /* XXX(@aligorith): This stuff needs reviewing. */
- if (false && (((oldbasact) && oldbasact->object->type == OB_GPENCIL) ||
- (basact->object->type == OB_GPENCIL))) {
- /* set cursor */
- if (ELEM(basact->object->mode,
- OB_MODE_PAINT_GPENCIL,
- OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL,
- OB_MODE_VERTEX_GPENCIL)) {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
- else {
- /* TODO: maybe is better use restore. */
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
- }
- }
+ if (changed_object) {
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
- ED_outliner_select_sync_from_pose_bone_tag(C);
- }
- else {
- ED_outliner_select_sync_from_object_tag(C);
- }
+ ED_outliner_select_sync_from_object_tag(C);
}
- return changed;
+ if (changed_pose) {
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+ }
+
+ if (gpu != NULL) {
+ MEM_freeN(gpu);
+ }
+
+ return (changed_object || changed_pose || changed_track);
}
/**
@@ -2815,11 +2872,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
/* Only force object select for edit-mode to support vertex parenting,
* or paint-select to allow pose bone select with vert/face select. */
- bool object = (RNA_boolean_get(op->ptr, "object") &&
- (obedit || BKE_paint_select_elem_test(obact) ||
- /* so its possible to select bones in weight-paint mode (LMB select) */
- (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
- BKE_object_pose_armature_get(obact))));
+ bool object_only = (RNA_boolean_get(op->ptr, "object") &&
+ (obedit || BKE_paint_select_elem_test(obact) ||
+ /* so its possible to select bones in weight-paint mode (LMB select) */
+ (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
+ BKE_object_pose_armature_get(obact))));
/* This could be called "changed_or_found" since this is true when there is an element
* under the cursor to select, even if it happens that the selection & active state doesn't
@@ -2832,7 +2889,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
- if (object) {
+ if (object_only) {
obedit = NULL;
obact = NULL;
@@ -2842,7 +2899,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
center = false;
}
- if (obedit && object == false) {
+ if (obedit && object_only == false) {
if (obedit->type == OB_MESH) {
changed = EDBM_select_pick(C, mval, &params);
}
@@ -2884,7 +2941,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
changed = ed_wpaint_vertex_select_pick(C, mval, &params, obact);
}
else {
- changed = ed_object_select_pick(C, mval, &params, center, enumerate, object);
+ changed = ed_object_select_pick(C, mval, &params, center, enumerate, object_only);
}
/* Pass-through flag may be cleared, see #WM_operator_flag_only_pass_through_on_press. */
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 8b7133892ff..87053fe03d1 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -440,6 +440,44 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
bool is_object_active,
void *data);
+static bool snap_object_is_snappable(const SnapObjectContext *sctx,
+ const eSnapSelect snap_select,
+ const Base *base_act,
+ const Base *base,
+ const bool is_in_object_mode)
+{
+ if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
+ return false;
+ }
+
+ if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ return true;
+ }
+
+ if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
+ return false;
+ }
+
+ if (snap_select == SNAP_NOT_ACTIVE) {
+ return base_act == base;
+ }
+
+ if (snap_select == SNAP_NOT_SELECTED) {
+ if (is_in_object_mode) {
+ return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
+ }
+
+ /* What is selectable or not is part of the object and depends on the mode. */
+ return true;
+ }
+
+ if (snap_select == SNAP_SELECTABLE) {
+ return (base->flag & BASE_SELECTABLE) != 0;
+ }
+
+ return true;
+}
+
/**
* Walks through all objects in the scene to create the list of objects to snap.
*/
@@ -458,38 +496,13 @@ static void iter_snap_objects(SnapObjectContext *sctx,
return;
}
+ const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
- if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
- continue;
- }
-
- if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
- /* pass */
- }
- else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
+ if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) {
continue;
}
const bool is_object_active = (base == base_act);
- if (snap_select == SNAP_NOT_ACTIVE) {
- if (is_object_active) {
- continue;
- }
- }
- else if (snap_select == SNAP_NOT_SELECTED) {
- if (is_object_active && base->object->mode != OB_MODE_OBJECT) {
- /* Pass. Consider the selection of elements being edited. */
- }
- else if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
- continue;
- }
- }
- else if (snap_select == SNAP_SELECTABLE) {
- if (!(base->flag & BASE_SELECTABLE)) {
- continue;
- }
- }
-
Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base->object);
if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 938b798f4b6..ed4aa6985c4 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -2388,12 +2388,11 @@ void UV_OT_select_all(wmOperatorType *ot)
/** \name Mouse Select Operator
* \{ */
-static int uv_mouse_select_multi(bContext *C,
- Object **objects,
- uint objects_len,
- const float co[2],
- const bool extend,
- const bool deselect_all)
+static bool uv_mouse_select_multi(bContext *C,
+ Object **objects,
+ uint objects_len,
+ const float co[2],
+ const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const ARegion *region = CTX_wm_region(C);
@@ -2477,117 +2476,145 @@ static int uv_mouse_select_multi(bContext *C,
}
}
- if (!found_item) {
- if (deselect_all) {
- uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ bool found = found_item;
+ bool changed = false;
+
+ bool is_selected = false;
+ if (found) {
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (selectmode == UV_SELECT_FACE) {
+ is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ else { /* Vertex or island. */
+ is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ }
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && is_selected) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ changed = true;
}
- return OPERATOR_CANCELLED;
}
- Object *obedit = hit.ob;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (found) {
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* do selection */
- if (selectmode == UV_SELECT_ISLAND) {
- if (!extend) {
- uv_select_all_perform_multi_ex(scene, objects, objects_len, SEL_DESELECT, obedit);
- }
- /* Current behavior of 'extend'
- * is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(scene, objects, objects_len, &hit, false, false, extend, false);
- }
- else if (extend) {
- bool select = true;
- if (selectmode == UV_SELECT_VERTEX) {
- /* (de)select uv vertex */
- select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
- uvedit_uv_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* (de)select edge */
- select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
- uvedit_edge_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* (de)select face */
- select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
- uvedit_face_select_set_with_sticky(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = -1;
+ if (selectmode == UV_SELECT_ISLAND) {
+ const bool extend = params->sel_op == SEL_OP_ADD;
+ const bool deselect = params->sel_op == SEL_OP_SUB;
+ const bool toggle = params->sel_op == SEL_OP_XOR;
+ /* Current behavior of 'extend'
+ * is actually toggling, so pass extend flag as 'toggle' here */
+ uv_select_linked_multi(scene, objects, objects_len, &hit, extend, deselect, toggle, false);
+ /* TODO: check if this actually changed. */
+ changed = true;
}
+ else {
+ BLI_assert(ELEM(selectmode, UV_SELECT_VERTEX, UV_SELECT_EDGE, UV_SELECT_FACE));
+ bool select_value = false;
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ select_value = true;
+ break;
+ }
+ case SEL_OP_SUB: {
+ select_value = false;
+ break;
+ }
+ case SEL_OP_XOR: {
+ select_value = !is_selected;
+ break;
+ }
+ case SEL_OP_SET: {
+ /* Deselect has already been performed. */
+ select_value = true;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
+ }
- /* de-selecting an edge may deselect a face too - validate */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select == false) {
- BM_select_history_validate(em->bm);
+ if (selectmode == UV_SELECT_FACE) {
+ uvedit_face_select_set_with_sticky(
+ scene, em, hit.efa, select_value, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, hit.l, select_value, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_VERTEX) {
+ uvedit_uv_select_set_with_sticky(scene, em, hit.l, select_value, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else {
+ BLI_assert_unreachable();
}
- }
- /* (de)select sticky uv nodes */
- if (sticky != SI_STICKY_DISABLE) {
- flush = select ? 1 : -1;
- }
- }
- else {
- const bool select = true;
- /* deselect all */
- uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ /* De-selecting an edge may deselect a face too - validate. */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select_value == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
- if (selectmode == UV_SELECT_VERTEX) {
- /* select vertex */
- uvedit_uv_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* select edge */
- uvedit_edge_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* select face */
- uvedit_face_select_set_with_sticky(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = 1;
+ /* (de)select sticky UV nodes. */
+ if (sticky != SI_STICKY_DISABLE) {
+ flush = select_value ? 1 : -1;
+ }
+
+ changed = true;
}
- }
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (flush != 0) {
- EDBM_selectmode_flush(em);
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (flush != 0) {
+ EDBM_selectmode_flush(em);
+ }
+ }
+ else {
+ /* Setting the selection implies a single element, which doesn't need to be flushed. */
+ if (params->sel_op != SEL_OP_SET) {
+ ED_uvedit_selectmode_flush(scene, em);
+ }
}
- }
- /* #extend=false implies single vertex selection, which doesn't need to be flushed. */
- else if (extend) {
- ED_uvedit_selectmode_flush(scene, em);
}
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obiter = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ if (changed && found) {
+ /* Only update the `hit` object as de-selecting all will have refreshed the others. */
+ Object *obedit = hit.ob;
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ return changed || found;
}
-static int uv_mouse_select(bContext *C,
- const float co[2],
- const bool extend,
- const bool deselect_all)
+static bool uv_mouse_select(bContext *C, const float co[2], const struct SelectPick_Params *params)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all);
+ bool changed = uv_mouse_select_multi(C, objects, objects_len, co, params);
MEM_freeN(objects);
- return ret;
+ return changed;
}
static int uv_select_exec(bContext *C, wmOperator *op)
@@ -2595,10 +2622,20 @@ static int uv_select_exec(bContext *C, wmOperator *op)
float co[2];
RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const struct SelectPick_Params params = {
+ .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "deselect"),
+ RNA_boolean_get(op->ptr, "toggle")),
+ .deselect_all = RNA_boolean_get(op->ptr, "deselect_all"),
+ .select_passthrough = RNA_boolean_get(op->ptr, "select_passthrough"),
+ };
- return uv_mouse_select(C, co, extend, deselect_all);
+ const bool changed = uv_mouse_select(C, co, &params);
+
+ if (changed) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -2629,18 +2666,8 @@ void UV_OT_select(wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
- prop = RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ WM_operator_properties_mouse_select(ot);
prop = RNA_def_float_vector(
ot->srna,
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 3ed99052753..63300656fda 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -2969,6 +2969,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
ED_uvedit_select_all(bm);
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index 2a5a2d0d957..c2fad9fef3a 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -508,8 +508,6 @@ set(SRC
intern/view_map/ViewMapAdvancedIterators.h
intern/view_map/ViewMapBuilder.cpp
intern/view_map/ViewMapBuilder.h
- intern/view_map/ViewMapIO.cpp
- intern/view_map/ViewMapIO.h
intern/view_map/ViewMapIterators.h
intern/view_map/ViewMapTesselator.cpp
intern/view_map/ViewMapTesselator.h
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 024bc80f3fa..cc815b5317f 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -36,7 +36,6 @@ extern "C" {
#include "../view_map/SteerableViewMap.h"
#include "../view_map/ViewMap.h"
-#include "../view_map/ViewMapIO.h"
#include "../view_map/ViewMapTesselator.h"
#include "../winged_edge/Curvature.h"
@@ -1099,13 +1098,10 @@ void Controller::init_options()
Config::Path *cpath = Config::Path::getInstance();
// Directories
- ViewMapIO::Options::setModelsPath(cpath->getModelsPath());
TextureManager::Options::setPatternsPath(cpath->getPatternsPath());
TextureManager::Options::setBrushesPath(cpath->getModelsPath());
// ViewMap Format
- ViewMapIO::Options::rmFlags(ViewMapIO::Options::FLOAT_VECTORS);
- ViewMapIO::Options::rmFlags(ViewMapIO::Options::NO_OCCLUDERS);
setComputeSteerableViewMapFlag(false);
// Visibility
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index 63585df97a9..96bab8c2028 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -31,6 +31,13 @@
#include "BPy_ViewMap.h"
#include "BPy_ViewShape.h"
+#include "BKE_appdir.h"
+#include "DNA_scene_types.h"
+#include "FRS_freestyle.h"
+#include "RNA_access.h"
+#include "RNA_prototypes.h"
+#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,13 +46,6 @@ extern "C" {
//------------------------ MODULE FUNCTIONS ----------------------------------
-#include "BKE_appdir.h"
-#include "DNA_scene_types.h"
-#include "FRS_freestyle.h"
-#include "RNA_access.h"
-#include "RNA_prototypes.h"
-#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */
-
static char Freestyle_getCurrentScene___doc__[] =
".. function:: getCurrentScene()\n"
"\n"
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp
deleted file mode 100644
index 47d9e61ba2f..00000000000
--- a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp
+++ /dev/null
@@ -1,1294 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup freestyle
- * \brief Functions to manage I/O for the view map
- */
-
-#include <climits>
-
-#include "ViewMapIO.h"
-
-#ifdef IRIX
-# define WRITE(n) Internal::write<sizeof((n))>(out, (const char *)(&(n)))
-# define READ(n) Internal::read<sizeof((n))>(in, (char *)(&(n)))
-#else
-# define WRITE(n) out.write((const char *)(&(n)), sizeof((n)))
-# define READ(n) in.read((char *)(&(n)), sizeof((n)))
-#endif
-
-#define WRITE_IF_NON_NULL(ptr) \
- if (ptr) { \
- WRITE((ptr)->userdata); \
- } \
- else { \
- WRITE(ZERO); \
- } \
- (void)0
-
-#define READ_IF_NON_NULL(ptr, array) \
- READ(tmp); \
- if (tmp) { \
- (ptr) = (array)[tmp]; \
- } \
- else { \
- (ptr) = NULL; \
- } \
- (void)0
-
-namespace Freestyle::ViewMapIO {
-
-namespace Internal {
-
-static ViewMap *g_vm;
-
-//////////////////// 'load' Functions ////////////////////
-
-inline int load(istream &in, Vec3r &v)
-{
- if (Options::getFlags() & Options::FLOAT_VECTORS) {
- float tmp;
- READ(tmp);
- v[0] = tmp;
- READ(tmp);
- v[1] = tmp;
- READ(tmp);
- v[2] = tmp;
- }
- else {
- Vec3r::value_type tmp;
- READ(tmp);
- v[0] = tmp;
- READ(tmp);
- v[1] = tmp;
- READ(tmp);
- v[2] = tmp;
- }
- return 0;
-}
-
-inline int load(istream &in, Polygon3r &p)
-{
- unsigned tmp;
-
- // Id
- READ(tmp);
- p.setId(tmp);
-
- // vertices (List)
- vector<Vec3r> tmp_vec;
- Vec3r v;
- READ(tmp);
- for (unsigned int i = 0; i < tmp; i++) {
- load(in, v);
- tmp_vec.push_back(v);
- }
- p.setVertices(tmp_vec);
-
- // min & max
- // Already computed (in the SetVertices() method)
-
- return 0;
-}
-
-inline int load(istream &in, FrsMaterial &m)
-{
- float tmp_array[4];
- int i;
-
- // Diffuse
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setDiffuse(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Specular
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setSpecular(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Ambient
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setAmbient(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Emission
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setEmission(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Shininess
- READ(tmp_array[0]);
- m.setShininess(tmp_array[0]);
-
- return 0;
-}
-
-static int load(istream &in, ViewShape *vs)
-{
- if (!vs || !vs->sshape()) {
- return 1;
- }
-
- // SShape
-
- // -> Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- vs->sshape()->setId(Id(id1, id2));
-
- // -> Importance
- float importance;
- READ(importance);
- vs->sshape()->setImportance(importance);
-
- // -> BBox
- // Not necessary (only used during view map computatiom)
-
- unsigned i, size, tmp;
-
- // -> Material
- READ(size);
- vector<FrsMaterial> frs_materials;
- FrsMaterial m;
- for (i = 0; i < size; ++i) {
- load(in, m);
- frs_materials.push_back(m);
- }
- vs->sshape()->setFrsMaterials(frs_materials);
-
- // -> VerticesList (List)
- READ(size);
- for (i = 0; i < size; i++) {
- SVertex *sv;
- READ_IF_NON_NULL(sv, g_vm->SVertices());
- vs->sshape()->AddNewVertex(sv);
- }
-
- // -> Chains (List)
- READ(size);
- for (i = 0; i < size; i++) {
- FEdge *fe;
- READ_IF_NON_NULL(fe, g_vm->FEdges());
- vs->sshape()->AddChain(fe);
- }
-
- // -> EdgesList (List)
- READ(size);
- for (i = 0; i < size; i++) {
- FEdge *fe;
- READ_IF_NON_NULL(fe, g_vm->FEdges());
- vs->sshape()->AddEdge(fe);
- }
-
- // ViewEdges (List)
- READ(size);
- for (i = 0; i < size; i++) {
- ViewEdge *ve;
- READ_IF_NON_NULL(ve, g_vm->ViewEdges());
- vs->AddEdge(ve);
- }
-
- // ViewVertices (List)
- READ(size);
- for (i = 0; i < size; i++) {
- ViewVertex *vv;
- READ_IF_NON_NULL(vv, g_vm->ViewVertices());
- vs->AddVertex(vv);
- }
-
- return 0;
-}
-
-static int load(istream &in, FEdge *fe)
-{
- if (!fe) {
- return 1;
- }
-
- bool b;
-
- FEdgeSmooth *fesmooth = nullptr;
- FEdgeSharp *fesharp = nullptr;
- if (fe->isSmooth()) {
- fesmooth = dynamic_cast<FEdgeSmooth *>(fe);
- }
- else {
- fesharp = dynamic_cast<FEdgeSharp *>(fe);
- }
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- fe->setId(Id(id1, id2));
-
- // Nature
- Nature::EdgeNature nature;
- READ(nature);
- fe->setNature(nature);
-
-#if 0 // hasVisibilityPoint
- bool b;
- READ(b);
- fe->setHasVisibilityPoint(b);
-#endif
-
- Vec3r v;
- unsigned int matindex;
-
-#if 0
- // VisibilityPointA
- load(in, v);
- fe->setVisibilityPointA(v);
-
- // VisibilityPointB
- load(in, v);
- fe->setVisibilityPointB(v);
-#endif
-
- if (fe->isSmooth()) {
- // Normal
- load(in, v);
- fesmooth->setNormal(v);
-
- // Material
- READ(matindex);
- fesmooth->setFrsMaterialIndex(matindex);
- }
- else {
- // aNormal
- load(in, v);
- fesharp->setNormalA(v);
-
- // bNormal
- load(in, v);
- fesharp->setNormalB(v);
-
- // Materials
- READ(matindex);
- fesharp->setaFrsMaterialIndex(matindex);
- READ(matindex);
- fesharp->setbFrsMaterialIndex(matindex);
- }
-
- unsigned tmp;
-
- // VertexA
- SVertex *sva;
- READ_IF_NON_NULL(sva, g_vm->SVertices());
- fe->setVertexA(sva);
-
- // VertexB
- SVertex *svb;
- READ_IF_NON_NULL(svb, g_vm->SVertices());
- fe->setVertexB(svb);
-
- // NextEdge
- FEdge *nfe;
- READ_IF_NON_NULL(nfe, g_vm->FEdges());
- fe->setNextEdge(nfe);
-
- // PreviousEdge
- FEdge *pfe;
- READ_IF_NON_NULL(pfe, g_vm->FEdges());
- fe->setPreviousEdge(pfe);
-
- // ViewEdge
- ViewEdge *ve;
- READ_IF_NON_NULL(ve, g_vm->ViewEdges());
- fe->setViewEdge(ve);
-
- // Face
- // Not necessary (only used during view map computatiom)
-
- Polygon3r p;
-
- // aFace
- load(in, p);
- fe->setaFace(p);
-
- // occludeeEmpty
- READ(b);
- fe->setOccludeeEmpty(b);
-
- // occludeeIntersection
- load(in, v);
- fe->setOccludeeIntersection(v);
-
- return 0;
-}
-
-static int load(istream &in, SVertex *sv)
-{
- if (!sv) {
- return 1;
- }
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- sv->setId(Id(id1, id2));
-
- Vec3r v;
-
- // Point3D
- load(in, v);
- sv->setPoint3D(v);
-
- // Point2D
- load(in, v);
- sv->setPoint2D(v);
-
- unsigned tmp;
-
- // Shape
- ViewShape *vs;
- READ_IF_NON_NULL(vs, g_vm->ViewShapes());
- sv->setShape(vs->sshape());
-
- // pViewVertex
- ViewVertex *vv;
- READ_IF_NON_NULL(vv, g_vm->ViewVertices());
- sv->setViewVertex(vv);
-
- unsigned i, size;
-
- // Normals (List)
- READ(size);
- for (i = 0; i < size; i++) {
- load(in, v);
- sv->AddNormal(v);
- }
-
- // FEdges (List)
- READ(size);
- FEdge *fe;
- for (i = 0; i < size; i++) {
- READ_IF_NON_NULL(fe, g_vm->FEdges());
- sv->AddFEdge(fe);
- }
-
- return 0;
-}
-
-static int load(istream &in, ViewEdge *ve)
-{
- if (!ve) {
- return 1;
- }
-
- unsigned tmp;
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- ve->setId(Id(id1, id2));
-
- // Nature
- Nature::EdgeNature nature;
- READ(nature);
- ve->setNature(nature);
-
- // QI
- READ(tmp);
- ve->setQI(tmp);
-
- // Shape
- ViewShape *vs;
- READ_IF_NON_NULL(vs, g_vm->ViewShapes());
- ve->setShape(vs);
-
- // aShape
- ViewShape *avs;
- READ_IF_NON_NULL(avs, g_vm->ViewShapes());
- ve->setaShape(avs);
-
- // FEdgeA
- FEdge *fea;
- READ_IF_NON_NULL(fea, g_vm->FEdges());
- ve->setFEdgeA(fea);
-
- // FEdgeB
- FEdge *feb;
- READ_IF_NON_NULL(feb, g_vm->FEdges());
- ve->setFEdgeB(feb);
-
- // A
- ViewVertex *vva;
- READ_IF_NON_NULL(vva, g_vm->ViewVertices());
- ve->setA(vva);
-
- // B
- ViewVertex *vvb;
- READ_IF_NON_NULL(vvb, g_vm->ViewVertices());
- ve->setB(vvb);
-
- // Occluders (List)
- if (!(Options::getFlags() & Options::NO_OCCLUDERS)) {
- unsigned size;
- READ(size);
- ViewShape *vso;
- for (unsigned int i = 0; i < size; i++) {
- READ_IF_NON_NULL(vso, g_vm->ViewShapes());
- ve->AddOccluder(vso);
- }
- }
-
- return 0;
-}
-
-static int load(istream &in, ViewVertex *vv)
-{
- if (!vv) {
- return 1;
- }
-
- unsigned tmp;
- bool b;
-
- // Nature
- Nature::VertexNature nature;
- READ(nature);
- vv->setNature(nature);
-
- if (vv->getNature() & Nature::T_VERTEX) {
- TVertex *tv = dynamic_cast<TVertex *>(vv);
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- tv->setId(Id(id1, id2));
-
- // FrontSVertex
- SVertex *fsv;
- READ_IF_NON_NULL(fsv, g_vm->SVertices());
- tv->setFrontSVertex(fsv);
-
- // BackSVertex
- SVertex *bsv;
- READ_IF_NON_NULL(bsv, g_vm->SVertices());
- tv->setBackSVertex(bsv);
-
- // FrontEdgeA
- ViewEdge *fea;
- READ_IF_NON_NULL(fea, g_vm->ViewEdges());
- READ(b);
- tv->setFrontEdgeA(fea, b);
-
- // FrontEdgeB
- ViewEdge *feb;
- READ_IF_NON_NULL(feb, g_vm->ViewEdges());
- READ(b);
- tv->setFrontEdgeB(feb, b);
-
- // BackEdgeA
- ViewEdge *bea;
- READ_IF_NON_NULL(bea, g_vm->ViewEdges());
- READ(b);
- tv->setBackEdgeA(bea, b);
-
- // BackEdgeB
- ViewEdge *beb;
- READ_IF_NON_NULL(beb, g_vm->ViewEdges());
- READ(b);
- tv->setBackEdgeB(beb, b);
- }
- else if (vv->getNature() & Nature::NON_T_VERTEX) {
- NonTVertex *ntv = dynamic_cast<NonTVertex *>(vv);
-
- // SVertex
- SVertex *sv;
- READ_IF_NON_NULL(sv, g_vm->SVertices());
- ntv->setSVertex(sv);
-
- // ViewEdges (List)
- unsigned size;
- READ(size);
- ViewEdge *ve;
- for (unsigned int i = 0; i < size; i++) {
- READ_IF_NON_NULL(ve, g_vm->ViewEdges());
- READ(b);
- ntv->AddViewEdge(ve, b);
- }
- }
-
- return 0;
-}
-
-//////////////////// 'save' Functions ////////////////////
-
-inline int save(ostream &out, const Vec3r &v)
-{
- if (Options::getFlags() & Options::FLOAT_VECTORS) {
- float tmp;
-
- tmp = v[0];
- WRITE(tmp);
- tmp = v[1];
- WRITE(tmp);
- tmp = v[2];
- WRITE(tmp);
- }
- else {
- Vec3r::value_type tmp;
-
- tmp = v[0];
- WRITE(tmp);
- tmp = v[1];
- WRITE(tmp);
- tmp = v[2];
- WRITE(tmp);
- }
- return 0;
-}
-
-inline int save(ostream &out, const Polygon3r &p)
-{
- unsigned tmp;
-
- // Id
- tmp = p.getId();
- WRITE(tmp);
-
- // vertices (List)
- tmp = p.getVertices().size();
- WRITE(tmp);
- for (vector<Vec3r>::const_iterator i = p.getVertices().begin(); i != p.getVertices().end();
- i++) {
- save(out, *i);
- }
-
- // min & max
- // Do not need to be saved
-
- return 0;
-}
-
-inline int save(ostream &out, const FrsMaterial &m)
-{
- unsigned i;
-
- // Diffuse
- for (i = 0; i < 4; i++) {
- WRITE(m.diffuse()[i]);
- }
-
- // Specular
- for (i = 0; i < 4; i++) {
- WRITE(m.specular()[i]);
- }
-
- // Ambient
- for (i = 0; i < 4; i++) {
- WRITE(m.ambient()[i]);
- }
-
- // Emission
- for (i = 0; i < 4; i++) {
- WRITE(m.emission()[i]);
- }
-
- // Shininess
- float shininess = m.shininess();
- WRITE(shininess);
-
- return 0;
-}
-
-static int save(ostream &out, ViewShape *vs)
-{
- if (!vs || !vs->sshape()) {
- cerr << "Warning: null ViewShape" << endl;
- return 1;
- }
-
- unsigned tmp;
-
- // SShape
-
- // -> Id
- Id::id_type id = vs->sshape()->getId().getFirst();
- WRITE(id);
- id = vs->sshape()->getId().getSecond();
- WRITE(id);
-
- // -> Importance
- float importance = vs->sshape()->importance();
- WRITE(importance);
-
- // -> BBox
- // Not necessary (only used during view map computatiom)
-
- // -> Material
- unsigned int size = vs->sshape()->frs_materials().size();
- WRITE(size);
- for (unsigned int i = 0; i < size; ++i) {
- save(out, vs->sshape()->frs_material(i));
- }
-
- // -> VerticesList (List)
- tmp = vs->sshape()->getVertexList().size();
- WRITE(tmp);
- for (vector<SVertex *>::const_iterator i1 = vs->sshape()->getVertexList().begin();
- i1 != vs->sshape()->getVertexList().end();
- i1++) {
- WRITE_IF_NON_NULL(*i1);
- }
-
- // -> Chains (List)
- tmp = vs->sshape()->getChains().size();
- WRITE(tmp);
- for (vector<FEdge *>::const_iterator i2 = vs->sshape()->getChains().begin();
- i2 != vs->sshape()->getChains().end();
- i2++) {
- WRITE_IF_NON_NULL(*i2);
- }
-
- // -> EdgesList (List)
- tmp = vs->sshape()->getEdgeList().size();
- WRITE(tmp);
- for (vector<FEdge *>::const_iterator i3 = vs->sshape()->getEdgeList().begin();
- i3 != vs->sshape()->getEdgeList().end();
- i3++) {
- WRITE_IF_NON_NULL(*i3);
- }
-
- // ViewEdges (List)
- tmp = vs->edges().size();
- WRITE(tmp);
- for (vector<ViewEdge *>::const_iterator i4 = vs->edges().begin(); i4 != vs->edges().end();
- i4++) {
- WRITE_IF_NON_NULL(*i4);
- }
-
- // ViewVertices (List)
- tmp = vs->vertices().size();
- WRITE(tmp);
- for (vector<ViewVertex *>::const_iterator i5 = vs->vertices().begin();
- i5 != vs->vertices().end();
- i5++) {
- WRITE_IF_NON_NULL(*i5);
- }
-
- return 0;
-}
-
-static int save(ostream &out, FEdge *fe)
-{
- if (!fe) {
- cerr << "Warning: null FEdge" << endl;
- return 1;
- }
-
- FEdgeSmooth *fesmooth = dynamic_cast<FEdgeSmooth *>(fe);
- FEdgeSharp *fesharp = dynamic_cast<FEdgeSharp *>(fe);
-
- // Id
- Id::id_type id = fe->getId().getFirst();
- WRITE(id);
- id = fe->getId().getSecond();
- WRITE(id);
-
- // Nature
- Nature::EdgeNature nature = fe->getNature();
- WRITE(nature);
-
- bool b;
-
-#if 0
- // hasVisibilityPoint
- b = fe->hasVisibilityPoint();
- WRITE(b);
-
- // VisibilityPointA
- save(out, fe->visibilityPointA());
-
- // VisibilityPointB
- save(out, fe->visibilityPointB());
-#endif
-
- unsigned index;
- if (fe->isSmooth()) {
- // normal
- save(out, fesmooth->normal());
- // material
- index = fesmooth->frs_materialIndex();
- WRITE(index);
- }
- else {
- // aNormal
- save(out, fesharp->normalA());
- // bNormal
- save(out, fesharp->normalB());
- // aMaterial
- index = fesharp->aFrsMaterialIndex();
- WRITE(index);
- // bMaterial
- index = fesharp->bFrsMaterialIndex();
- WRITE(index);
- }
-
- // VertexA
- WRITE_IF_NON_NULL(fe->vertexA());
-
- // VertexB
- WRITE_IF_NON_NULL(fe->vertexB());
-
- // NextEdge
- WRITE_IF_NON_NULL(fe->nextEdge());
-
- // PreviousEdge
- WRITE_IF_NON_NULL(fe->previousEdge());
-
- // ViewEdge
- WRITE_IF_NON_NULL(fe->viewedge());
-
- // Face
- // Not necessary (only used during view map computatiom)
-
- // aFace
- save(out, (Polygon3r &)fe->aFace());
-
- // occludeeEmpty
- b = fe->getOccludeeEmpty();
- WRITE(b);
-
- // occludeeIntersection
- save(out, fe->getOccludeeIntersection());
-
- return 0;
-}
-
-static int save(ostream &out, SVertex *sv)
-{
- if (!sv) {
- cerr << "Warning: null SVertex" << endl;
- return 1;
- }
-
- unsigned tmp;
-
- // Id
- Id::id_type id = sv->getId().getFirst();
- WRITE(id);
- id = sv->getId().getSecond();
- WRITE(id);
-
- Vec3r v;
-
- // Point3D
- v = sv->point3D();
- save(out, sv->point3D());
-
- // Point2D
- v = sv->point2D();
- save(out, v);
-
- // Shape
- WRITE_IF_NON_NULL(sv->shape());
-
- // pViewVertex
- WRITE_IF_NON_NULL(sv->viewvertex());
-
- // Normals (List)
- // NOTE: the 'size()' method of a set doesn't seem to return the actual size of the given set, so
- // we have to hack it...
- set<Vec3r>::const_iterator i;
- for (i = sv->normals().begin(), tmp = 0; i != sv->normals().end(); i++, tmp++) {
- /* pass */
- }
- WRITE(tmp);
- for (i = sv->normals().begin(); i != sv->normals().end(); i++) {
- save(out, *i);
- }
-
- // FEdges (List)
- tmp = sv->fedges().size();
- WRITE(tmp);
- for (vector<FEdge *>::const_iterator j = sv->fedges_begin(); j != sv->fedges_end(); j++) {
- WRITE_IF_NON_NULL(*j);
- }
-
- return 0;
-}
-
-static int save(ostream &out, ViewEdge *ve)
-{
- if (!ve) {
- cerr << "Warning: null ViewEdge" << endl;
- return 1;
- }
-
- unsigned tmp;
-
- // Id
- Id::id_type id = ve->getId().getFirst();
- WRITE(id);
- id = ve->getId().getSecond();
- WRITE(id);
-
- // Nature
- Nature::EdgeNature nature = ve->getNature();
- WRITE(nature);
-
- // QI
- unsigned qi = ve->qi();
- WRITE(qi);
-
- // Shape
- WRITE_IF_NON_NULL(ve->shape());
-
- // aShape
- WRITE_IF_NON_NULL(ve->aShape());
-
- // FEdgeA
- WRITE_IF_NON_NULL(ve->fedgeA());
-
- // FEdgeB
- WRITE_IF_NON_NULL(ve->fedgeB());
-
- // A
- WRITE_IF_NON_NULL(ve->A());
-
- // B
- WRITE_IF_NON_NULL(ve->B());
-
- // Occluders (List)
- if (!(Options::getFlags() & Options::NO_OCCLUDERS)) {
- tmp = ve->occluders().size();
- WRITE(tmp);
- for (vector<ViewShape *>::const_iterator i = ve->occluders().begin();
- i != ve->occluders().end();
- i++) {
- WRITE_IF_NON_NULL((*i));
- }
- }
-
- return 0;
-}
-
-static int save(ostream &out, ViewVertex *vv)
-{
- if (!vv) {
- cerr << "Warning: null ViewVertex" << endl;
- return 1;
- }
-
- // Nature
- Nature::VertexNature nature = vv->getNature();
- WRITE(nature);
-
- if (vv->getNature() & Nature::T_VERTEX) {
- TVertex *tv = dynamic_cast<TVertex *>(vv);
-
- // Id
- Id::id_type id = tv->getId().getFirst();
- WRITE(id);
- id = tv->getId().getSecond();
- WRITE(id);
-
- // FrontSVertex
- WRITE_IF_NON_NULL(tv->frontSVertex());
-
- // BackSVertex
- WRITE_IF_NON_NULL(tv->backSVertex());
-
- // FrontEdgeA
- WRITE_IF_NON_NULL(tv->frontEdgeA().first);
- WRITE(tv->frontEdgeA().second);
-
- // FrontEdgeB
- WRITE_IF_NON_NULL(tv->frontEdgeB().first);
- WRITE(tv->frontEdgeB().second);
-
- // BackEdgeA
- WRITE_IF_NON_NULL(tv->backEdgeA().first);
- WRITE(tv->backEdgeA().second);
-
- // BackEdgeB
- WRITE_IF_NON_NULL(tv->backEdgeB().first);
- WRITE(tv->backEdgeB().second);
- }
- else if (vv->getNature() & Nature::NON_T_VERTEX) {
- NonTVertex *ntv = dynamic_cast<NonTVertex *>(vv);
-
- // SVertex
- WRITE_IF_NON_NULL(ntv->svertex());
-
- // ViewEdges (List)
- unsigned size = ntv->viewedges().size();
- WRITE(size);
- vector<ViewVertex::directedViewEdge>::const_iterator i = ntv->viewedges().begin();
- for (; i != ntv->viewedges().end(); i++) {
- WRITE_IF_NON_NULL(i->first);
- WRITE(i->second);
- }
- }
- else {
- cerr << "Warning: unexpected ViewVertex nature" << endl;
- return 1;
- }
-
- return 0;
-}
-
-} // End of namespace Internal
-
-//////////////////// "Public" 'load' and 'save' functions ////////////////////
-
-#define SET_PROGRESS(n) \
- if (pb) { \
- pb->setProgress((n)); \
- } \
- (void)0
-
-int load(istream &in, ViewMap *vm, ProgressBar *pb)
-{
- if (!vm) {
- return 1;
- }
-
- // soc unused - unsigned tmp;
- int err = 0;
- Internal::g_vm = vm;
-
- // Management of the progress bar (if present)
- if (pb) {
- pb->reset();
- pb->setLabelText("Loading View Map...");
- pb->setTotalSteps(6);
- pb->setProgress(0);
- }
-
- // Read and set the options
- unsigned char flags;
- READ(flags);
- Options::setFlags(flags);
-
- // Read the size of the five ViewMap's lists (with some extra information for the ViewVertices)
- // and instantiate them (with default costructors)
- unsigned vs_s, fe_s, fe_rle1, fe_rle2, sv_s, ve_s, vv_s, vv_rle1, vv_rle2;
- READ(vs_s);
- READ(fe_s);
-
- if (fe_s) {
- bool b;
- READ(b);
- /* NOLINTNEXTLINE: bugprone-infinite-loop */
- for (READ(fe_rle1), fe_rle2 = 0; fe_rle1 <= fe_s; fe_rle2 = fe_rle1, READ(fe_rle1)) {
- if (b) {
- for (unsigned int i = fe_rle2; i < fe_rle1; i++) {
- FEdgeSmooth *fes = new FEdgeSmooth;
- vm->AddFEdge(fes);
- }
- b = !b;
- }
- else if (!b) {
- for (unsigned int i = fe_rle2; i < fe_rle1; i++) {
- FEdgeSharp *fes = new FEdgeSharp;
- vm->AddFEdge(fes);
- }
- b = !b;
- }
- }
- }
-
- READ(sv_s);
- READ(ve_s);
- READ(vv_s);
-
- if (vv_s) {
- Nature::VertexNature nature;
- READ(nature);
- /* NOLINTNEXTLINE: bugprone-infinite-loop */
- for (READ(vv_rle1), vv_rle2 = 0; vv_rle1 <= vv_s; vv_rle2 = vv_rle1, READ(vv_rle1)) {
- if (nature & Nature::T_VERTEX) {
- for (unsigned int i = vv_rle2; i < vv_rle1; i++) {
- TVertex *tv = new TVertex();
- vm->AddViewVertex(tv);
- }
- nature = Nature::NON_T_VERTEX;
- }
- else if (nature & Nature::NON_T_VERTEX) {
- for (unsigned int i = vv_rle2; i < vv_rle1; i++) {
- NonTVertex *ntv = new NonTVertex();
- vm->AddViewVertex(ntv);
- }
- nature = Nature::T_VERTEX;
- }
- }
- }
-
- for (unsigned int i0 = 0; i0 < vs_s; i0++) {
- SShape *ss = new SShape();
- ViewShape *vs = new ViewShape();
- vs->setSShape(ss);
- ss->setViewShape(vs);
- vm->AddViewShape(vs);
- }
-#if 0
- for (unsigned int i1 = 0; i1 < fe_s; i1++) {
- FEdge *fe = new FEdge();
- vm->AddFEdge(fe);
- }
-#endif
- for (unsigned int i2 = 0; i2 < sv_s; i2++) {
- SVertex *sv = new SVertex();
- vm->AddSVertex(sv);
- }
- for (unsigned int i3 = 0; i3 < ve_s; i3++) {
- ViewEdge *ve = new ViewEdge();
- vm->AddViewEdge(ve);
- }
-
- // Read the values for all the objects created above
- SET_PROGRESS(1);
- for (vector<ViewShape *>::const_iterator i4 = vm->ViewShapes().begin();
- i4 != vm->ViewShapes().end();
- i4++) {
- err += Internal::load(in, *i4);
- }
- SET_PROGRESS(2);
- for (vector<FEdge *>::const_iterator i5 = vm->FEdges().begin(); i5 != vm->FEdges().end(); i5++) {
- err += Internal::load(in, *i5);
- }
- SET_PROGRESS(3);
- for (vector<SVertex *>::const_iterator i6 = vm->SVertices().begin(); i6 != vm->SVertices().end();
- i6++) {
- err += Internal::load(in, *i6);
- }
- SET_PROGRESS(4);
- for (vector<ViewEdge *>::const_iterator i7 = vm->ViewEdges().begin();
- i7 != vm->ViewEdges().end();
- i7++) {
- err += Internal::load(in, *i7);
- }
- SET_PROGRESS(5);
- for (vector<ViewVertex *>::const_iterator i8 = vm->ViewVertices().begin();
- i8 != vm->ViewVertices().end();
- i8++) {
- err += Internal::load(in, *i8);
- }
- SET_PROGRESS(6);
-
- // Read the shape id to index mapping
- unsigned map_s;
- READ(map_s);
- unsigned id, index;
- for (unsigned int i4 = 0; i4 < map_s; ++i4) {
- READ(id);
- READ(index);
- vm->shapeIdToIndexMap()[id] = index;
- }
-
- return err;
-}
-
-int save(ostream &out, ViewMap *vm, ProgressBar *pb)
-{
- if (!vm) {
- return 1;
- }
-
- int err = 0;
-
- // Management of the progress bar (if present)
- if (pb) {
- pb->reset();
- pb->setLabelText("Saving View Map...");
- pb->setTotalSteps(6);
- pb->setProgress(0);
- }
-
- // For every object, initialize its userdata member to its index in the ViewMap list
- for (unsigned int i0 = 0; i0 < vm->ViewShapes().size(); i0++) {
- vm->ViewShapes()[i0]->userdata = POINTER_FROM_UINT(i0);
- vm->ViewShapes()[i0]->sshape()->userdata = POINTER_FROM_UINT(i0);
- }
- for (unsigned int i1 = 0; i1 < vm->FEdges().size(); i1++) {
- vm->FEdges()[i1]->userdata = POINTER_FROM_UINT(i1);
- }
- for (unsigned int i2 = 0; i2 < vm->SVertices().size(); i2++) {
- vm->SVertices()[i2]->userdata = POINTER_FROM_UINT(i2);
- }
- for (unsigned int i3 = 0; i3 < vm->ViewEdges().size(); i3++) {
- vm->ViewEdges()[i3]->userdata = POINTER_FROM_UINT(i3);
- }
- for (unsigned int i4 = 0; i4 < vm->ViewVertices().size(); i4++) {
- vm->ViewVertices()[i4]->userdata = POINTER_FROM_UINT(i4);
- }
-
- // Write the current options
- unsigned char flags = Options::getFlags();
- WRITE(flags);
-
- // Write the size of the five lists (with some extra information for the ViewVertices)
- unsigned size;
- size = vm->ViewShapes().size();
- WRITE(size);
- size = vm->FEdges().size();
- WRITE(size);
- if (size) {
- bool b = vm->FEdges()[0]->isSmooth();
- WRITE(b);
- for (unsigned int i = 0; i < size; i++) {
- while (i < size && (vm->FEdges()[i]->isSmooth() == b)) {
- i++;
- }
- if (i < size) {
- WRITE(i);
- b = !b;
- }
- }
- WRITE(size);
- size++;
- WRITE(size);
- }
- size = vm->SVertices().size();
- WRITE(size);
- size = vm->ViewEdges().size();
- WRITE(size);
- size = vm->ViewVertices().size();
- WRITE(size);
- if (size) {
- Nature::VertexNature nature = vm->ViewVertices()[0]->getNature();
- WRITE(nature);
- nature &= ~Nature::VIEW_VERTEX;
- for (unsigned int i = 0; i < size; i++) {
- while (i < size && (vm->ViewVertices()[i]->getNature() & nature)) {
- i++;
- }
- if (i < size) {
- WRITE(i);
- nature = vm->ViewVertices()[i]->getNature() & ~Nature::VIEW_VERTEX;
- }
- }
- WRITE(size);
- size++;
- WRITE(size);
- }
-
- // Write all the elts of the ViewShapes List
- SET_PROGRESS(1);
- for (vector<ViewShape *>::const_iterator i5 = vm->ViewShapes().begin();
- i5 != vm->ViewShapes().end();
- i5++) {
- err += Internal::save(out, *i5);
- }
- SET_PROGRESS(2);
- for (vector<FEdge *>::const_iterator i6 = vm->FEdges().begin(); i6 != vm->FEdges().end(); i6++) {
- err += Internal::save(out, *i6);
- }
- SET_PROGRESS(3);
- for (vector<SVertex *>::const_iterator i7 = vm->SVertices().begin(); i7 != vm->SVertices().end();
- i7++) {
- err += Internal::save(out, *i7);
- }
- SET_PROGRESS(4);
- for (vector<ViewEdge *>::const_iterator i8 = vm->ViewEdges().begin();
- i8 != vm->ViewEdges().end();
- i8++) {
- err += Internal::save(out, *i8);
- }
- SET_PROGRESS(5);
- for (vector<ViewVertex *>::const_iterator i9 = vm->ViewVertices().begin();
- i9 != vm->ViewVertices().end();
- i9++) {
- err += Internal::save(out, *i9);
- }
-
- // Write the shape id to index mapping
- size = vm->shapeIdToIndexMap().size();
- WRITE(size);
- unsigned int id, index;
- for (ViewMap::id_to_index_map::iterator mit = vm->shapeIdToIndexMap().begin(),
- mitend = vm->shapeIdToIndexMap().end();
- mit != mitend;
- ++mit) {
- id = mit->first;
- index = mit->second;
- WRITE(id);
- WRITE(index);
- }
-
- // Reset 'userdata' members
- for (vector<ViewShape *>::const_iterator j0 = vm->ViewShapes().begin();
- j0 != vm->ViewShapes().end();
- j0++) {
- (*j0)->userdata = nullptr;
- (*j0)->sshape()->userdata = nullptr;
- }
- for (vector<FEdge *>::const_iterator j1 = vm->FEdges().begin(); j1 != vm->FEdges().end(); j1++) {
- (*j1)->userdata = nullptr;
- }
- for (vector<SVertex *>::const_iterator j2 = vm->SVertices().begin(); j2 != vm->SVertices().end();
- j2++) {
- (*j2)->userdata = nullptr;
- }
- for (vector<ViewEdge *>::const_iterator j3 = vm->ViewEdges().begin();
- j3 != vm->ViewEdges().end();
- j3++) {
- (*j3)->userdata = nullptr;
- }
- for (vector<ViewVertex *>::const_iterator j4 = vm->ViewVertices().begin();
- j4 != vm->ViewVertices().end();
- j4++) {
- (*j4)->userdata = nullptr;
- }
- SET_PROGRESS(6);
-
- return err;
-}
-
-//////////////////// Options ////////////////////
-
-namespace Options {
-
-namespace Internal {
-
-static unsigned char g_flags = 0;
-static string g_models_path;
-
-} // End of namespace Internal
-
-void setFlags(const unsigned char flags)
-{
- Internal::g_flags = flags;
-}
-
-void addFlags(const unsigned char flags)
-{
- Internal::g_flags |= flags;
-}
-
-void rmFlags(const unsigned char flags)
-{
- Internal::g_flags &= ~flags;
-}
-
-unsigned char getFlags()
-{
- return Internal::g_flags;
-}
-
-void setModelsPath(const string &path)
-{
- Internal::g_models_path = path;
-}
-
-string getModelsPath()
-{
- return Internal::g_models_path;
-}
-
-} // namespace Options
-
-} // namespace Freestyle::ViewMapIO
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h
deleted file mode 100644
index 4796b28a38a..00000000000
--- a/source/blender/freestyle/intern/view_map/ViewMapIO.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-/** \file
- * \ingroup freestyle
- * \brief Functions to manage I/O for the view map
- */
-
-#include <fstream>
-#include <string>
-
-#include "ViewMap.h"
-
-#include "../system/FreestyleConfig.h"
-#include "../system/ProgressBar.h"
-
-namespace Freestyle {
-
-namespace ViewMapIO {
-
-static const unsigned ZERO = UINT_MAX;
-
-int load(istream &in, ViewMap *vm, ProgressBar *pb = NULL);
-
-int save(ostream &out, ViewMap *vm, ProgressBar *pb = NULL);
-
-namespace Options {
-
-static const unsigned char FLOAT_VECTORS = 1;
-static const unsigned char NO_OCCLUDERS = 2;
-
-void setFlags(unsigned char flags);
-
-void addFlags(unsigned char flags);
-
-void rmFlags(unsigned char flags);
-
-unsigned char getFlags();
-
-void setModelsPath(const string &path);
-
-string getModelsPath();
-
-}; // namespace Options
-
-#ifdef IRIX
-
-namespace Internal {
-
-template<unsigned S> ostream &write(ostream &out, const char *str)
-{
- out.put(str[S - 1]);
- return write<S - 1>(out, str);
-}
-
-template<> ostream &write<1>(ostream &out, const char *str)
-{
- return out.put(str[0]);
-}
-
-template<> ostream &write<0>(ostream &out, const char *)
-{
- return out;
-}
-
-template<unsigned S> istream &read(istream &in, char *str)
-{
- in.get(str[S - 1]);
- return read<S - 1>(in, str);
-}
-
-template<> istream &read<1>(istream &in, char *str)
-{
- return in.get(str[0]);
-}
-
-template<> istream &read<0>(istream &in, char *)
-{
- return in;
-}
-
-} // End of namespace Internal
-
-#endif // IRIX
-
-} // End of namespace ViewMapIO
-
-} /* namespace Freestyle */
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 2f648d7ed4b..c96321b67aa 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1753,6 +1753,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
obi->original_me,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 45e614991ca..190454c8dfe 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -2,10 +2,10 @@
# Copyright 2006 Blender Foundation. All rights reserved.
# WITH_OPENGL limits the visibility of the opengl headers to just GPU and bg_gpu,
-# to more easily highlight codepadths in other libraries that need to be refactored,
+# to more easily highlight code-paths in other libraries that need to be refactored,
# bf_gpu is allowed to have opengl regardless of this option.
-if(NOT WITH_OPENGL)
+if(NOT WITH_OPENGL AND NOT WITH_METAL_BACKEND)
add_definitions(-DWITH_OPENGL)
endif()
@@ -13,6 +13,7 @@ set(INC
.
intern
opengl
+ metal
../blenkernel
../blenlib
../bmesh
@@ -78,27 +79,6 @@ set(SRC
intern/gpu_vertex_format.cc
intern/gpu_viewport.c
- opengl/gl_backend.cc
- opengl/gl_batch.cc
- opengl/gl_compute.cc
- opengl/gl_context.cc
- opengl/gl_debug.cc
- opengl/gl_debug_layer.cc
- opengl/gl_drawlist.cc
- opengl/gl_framebuffer.cc
- opengl/gl_immediate.cc
- opengl/gl_index_buffer.cc
- opengl/gl_query.cc
- opengl/gl_shader.cc
- opengl/gl_shader_interface.cc
- opengl/gl_shader_log.cc
- opengl/gl_state.cc
- opengl/gl_storage_buffer.cc
- opengl/gl_texture.cc
- opengl/gl_uniform_buffer.cc
- opengl/gl_vertex_array.cc
- opengl/gl_vertex_buffer.cc
-
GPU_batch.h
GPU_batch_presets.h
GPU_batch_utils.h
@@ -129,6 +109,7 @@ set(SRC
GPU_vertex_buffer.h
GPU_vertex_format.h
GPU_viewport.h
+ GPU_storage_buffer.h
intern/gpu_backend.hh
intern/gpu_batch_private.hh
@@ -153,10 +134,35 @@ set(SRC
intern/gpu_shader_interface.hh
intern/gpu_shader_private.hh
intern/gpu_state_private.hh
+ intern/gpu_storage_buffer_private.hh
intern/gpu_texture_private.hh
intern/gpu_uniform_buffer_private.hh
intern/gpu_vertex_buffer_private.hh
intern/gpu_vertex_format_private.h
+)
+
+set(OPENGL_SRC
+
+ opengl/gl_backend.cc
+ opengl/gl_batch.cc
+ opengl/gl_compute.cc
+ opengl/gl_context.cc
+ opengl/gl_debug.cc
+ opengl/gl_debug_layer.cc
+ opengl/gl_drawlist.cc
+ opengl/gl_framebuffer.cc
+ opengl/gl_immediate.cc
+ opengl/gl_index_buffer.cc
+ opengl/gl_query.cc
+ opengl/gl_shader.cc
+ opengl/gl_shader_interface.cc
+ opengl/gl_shader_log.cc
+ opengl/gl_state.cc
+ opengl/gl_storage_buffer.cc
+ opengl/gl_texture.cc
+ opengl/gl_uniform_buffer.cc
+ opengl/gl_vertex_array.cc
+ opengl/gl_vertex_buffer.cc
opengl/gl_backend.hh
opengl/gl_batch.hh
@@ -172,12 +178,29 @@ set(SRC
opengl/gl_shader.hh
opengl/gl_shader_interface.hh
opengl/gl_state.hh
+ opengl/gl_storage_buffer.hh
opengl/gl_texture.hh
opengl/gl_uniform_buffer.hh
opengl/gl_vertex_array.hh
opengl/gl_vertex_buffer.hh
)
+set(METAL_SRC
+ metal/mtl_backend.mm
+
+ metal/mtl_backend.hh
+ metal/mtl_capabilities.hh
+)
+
+# Select Backend source based on availability
+if(WITH_OPENGL)
+ list(APPEND SRC ${OPENGL_SRC})
+endif()
+
+if(WITH_METAL_BACKEND)
+ list(APPEND SRC ${METAL_SRC})
+endif()
+
set(LIB
${BLENDER_GL_LIBRARIES}
)
@@ -190,6 +213,7 @@ endif()
set(GLSL_SRC
GPU_shader_shared.h
+ shaders/opengl/glsl_shader_defines.glsl
shaders/gpu_shader_depth_only_frag.glsl
shaders/gpu_shader_uniform_color_frag.glsl
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 85433913456..f3b7f8c29bf 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -11,18 +11,15 @@
#include "GPU_batch.h"
#include "GPU_common.h"
+#include "GPU_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
-typedef enum eGPUBackendType {
- GPU_BACKEND_NONE = 0,
- GPU_BACKEND_OPENGL,
-} eGPUBackendType;
-
void GPU_backend_init(eGPUBackendType backend);
void GPU_backend_exit(void);
+bool GPU_backend_supported(eGPUBackendType type);
eGPUBackendType GPU_backend_get_type(void);
@@ -49,6 +46,14 @@ GPUContext *GPU_context_active_get(void);
void GPU_context_main_lock(void);
void GPU_context_main_unlock(void);
+/* GPU Begin/end work blocks */
+void GPU_render_begin(void);
+void GPU_render_end(void);
+
+/* For operations which need to run exactly once per frame -- even if there are no render updates.
+ */
+void GPU_render_step(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index d5a0fcfa921..d999216c7ff 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -12,6 +12,13 @@
/* GPU platform support */
+typedef enum eGPUBackendType {
+ GPU_BACKEND_NONE = 0,
+ GPU_BACKEND_OPENGL = 1 << 0,
+ GPU_BACKEND_METAL = 1 << 1,
+ GPU_BACKEND_ANY = 0xFFFFFFFFu
+} eGPUBackendType;
+
/* GPU Types */
typedef enum eGPUDeviceType {
GPU_DEVICE_NVIDIA = (1 << 0),
@@ -51,8 +58,13 @@ extern "C" {
#endif
/* GPU Types */
-
+/* TODO: Verify all use-cases of GPU_type_matches to determine which graphics API it should apply
+ * to, and replace with `GPU_type_matches_ex` where appropriate. */
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
+bool GPU_type_matches_ex(eGPUDeviceType device,
+ eGPUOSType os,
+ eGPUDriverType driver,
+ eGPUBackendType backend);
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_vendor(void);
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index ad906c74980..6e07e6c3229 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -49,6 +49,12 @@ class GPUBackend {
virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0;
virtual StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) = 0;
virtual VertBuf *vertbuf_alloc() = 0;
+
+ /* Render Frame Coordination --
+ * Used for performing per-frame actions globally */
+ virtual void render_begin() = 0;
+ virtual void render_end() = 0;
+ virtual void render_step() = 0;
};
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index d645d82a879..4a951eb8458 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -20,11 +20,13 @@ namespace blender::gpu {
*/
struct GPUCapabilities {
int max_texture_size = 0;
+ int max_texture_3d_size = 0;
int max_texture_layers = 0;
int max_textures = 0;
int max_textures_vert = 0;
int max_textures_geom = 0;
int max_textures_frag = 0;
+ int max_samplers = 0;
int max_work_group_count[3] = {0, 0, 0};
int max_work_group_size[3] = {0, 0, 0};
int max_uniforms_vert = 0;
@@ -41,6 +43,8 @@ struct GPUCapabilities {
bool compute_shader_support = false;
bool shader_storage_buffer_objects_support = false;
bool shader_image_load_store_support = false;
+ bool transform_feedback_support = false;
+
/* OpenGL related workarounds. */
bool mip_render_workaround = false;
bool depth_blitting_workaround = false;
@@ -48,6 +52,10 @@ struct GPUCapabilities {
bool broken_amd_driver = false;
bool use_hq_normals_workaround = false;
/* Vulkan related workarounds. */
+
+ /* Metal related workarounds. */
+ /* Minimum per-vertex stride in bytes (For a vertex buffer). */
+ int minimum_per_vertex_stride = 1;
};
extern GPUCapabilities GCaps;
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 60e95e09a99..c6eaf7defdc 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -13,7 +13,9 @@
*/
/* TODO: Create cmake option. */
-#define WITH_OPENGL_BACKEND 1
+#if WITH_OPENGL
+# define WITH_OPENGL_BACKEND 1
+#endif
#include "BLI_assert.h"
#include "BLI_utildefines.h"
@@ -32,6 +34,9 @@
# include "gl_backend.hh"
# include "gl_context.hh"
#endif
+#ifdef WITH_METAL_BACKEND
+# include "mtl_backend.hh"
+#endif
#include <mutex>
#include <vector>
@@ -141,21 +146,76 @@ void GPU_context_main_unlock()
/** \} */
/* -------------------------------------------------------------------- */
+/** \name GPU Begin/end work blocks
+ *
+ * Used to explicitly define a per-frame block within which GPU work will happen.
+ * Used for global autoreleasepool flushing in Metal
+ * \{ */
+
+void GPU_render_begin()
+{
+ GPUBackend *backend = GPUBackend::get();
+ BLI_assert(backend);
+ backend->render_begin();
+}
+void GPU_render_end()
+{
+ GPUBackend *backend = GPUBackend::get();
+ BLI_assert(backend);
+ backend->render_end();
+}
+void GPU_render_step()
+{
+ GPUBackend *backend = GPUBackend::get();
+ BLI_assert(backend);
+ backend->render_step();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Backend selection
* \{ */
static GPUBackend *g_backend;
+bool GPU_backend_supported(eGPUBackendType type)
+{
+ switch (type) {
+ case GPU_BACKEND_OPENGL:
+#ifdef WITH_OPENGL_BACKEND
+ return true;
+#else
+ return false;
+#endif
+ case GPU_BACKEND_METAL:
+#ifdef WITH_METAL_BACKEND
+ return MTLBackend::metal_is_supported();
+#else
+ return false;
+#endif
+ default:
+ BLI_assert(false && "No backend specified");
+ return false;
+ }
+}
+
void GPU_backend_init(eGPUBackendType backend_type)
{
BLI_assert(g_backend == nullptr);
+ BLI_assert(GPU_backend_supported(backend_type));
switch (backend_type) {
-#if WITH_OPENGL_BACKEND
+#ifdef WITH_OPENGL_BACKEND
case GPU_BACKEND_OPENGL:
g_backend = new GLBackend;
break;
#endif
+#ifdef WITH_METAL_BACKEND
+ case GPU_BACKEND_METAL:
+ g_backend = new MTLBackend;
+ break;
+#endif
default:
BLI_assert(0);
break;
@@ -172,9 +232,18 @@ void GPU_backend_exit()
eGPUBackendType GPU_backend_get_type()
{
+
+#ifdef WITH_OPENGL_BACKEND
if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) {
return GPU_BACKEND_OPENGL;
}
+#endif
+
+#ifdef WITH_METAL_BACKEND
+ if (g_backend && dynamic_cast<MTLBackend *>(g_backend) != nullptr) {
+ return GPU_BACKEND_METAL;
+ }
+#endif
return GPU_BACKEND_NONE;
}
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index 969a3033c6f..d108dd468a0 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -65,6 +65,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
eGPUOSType os_type,
eGPUDriverType driver_type,
eGPUSupportLevel gpu_support_level,
+ eGPUBackendType backend,
const char *vendor_str,
const char *renderer_str,
const char *version_str)
@@ -83,6 +84,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
this->version = BLI_strdup(version_str);
this->support_key = create_key(gpu_support_level, vendor_str, renderer_str, version_str);
this->gpu_name = create_gpu_name(vendor_str, renderer_str, version_str);
+ this->backend = backend;
}
void GPUPlatformGlobal::clear()
@@ -143,8 +145,17 @@ const char *GPU_platform_gpu_name()
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
+ return GPU_type_matches_ex(device, os, driver, GPU_BACKEND_ANY);
+}
+
+bool GPU_type_matches_ex(eGPUDeviceType device,
+ eGPUOSType os,
+ eGPUDriverType driver,
+ eGPUBackendType backend)
+{
BLI_assert(GPG.initialized);
- return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver);
+ return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver) &&
+ (GPG.backend & backend);
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh
index a6c400ad319..6e6c24a8662 100644
--- a/source/blender/gpu/intern/gpu_platform_private.hh
+++ b/source/blender/gpu/intern/gpu_platform_private.hh
@@ -23,12 +23,14 @@ class GPUPlatformGlobal {
char *version = nullptr;
char *support_key = nullptr;
char *gpu_name = nullptr;
+ eGPUBackendType backend = GPU_BACKEND_NONE;
public:
void init(eGPUDeviceType gpu_device,
eGPUOSType os_type,
eGPUDriverType driver_type,
eGPUSupportLevel gpu_support_level,
+ eGPUBackendType backend,
const char *vendor_str,
const char *renderer_str,
const char *version_str);
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index ac8e98a4a21..b434cfbbb0e 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -88,6 +88,16 @@ static void standard_defines(Vector<const char *> &sources)
else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
sources.append("#define OS_UNIX\n");
}
+ /* API Definition */
+ eGPUBackendType backend = GPU_backend_get_type();
+ switch (backend) {
+ case GPU_BACKEND_OPENGL:
+ sources.append("#define GPU_OPENGL\n");
+ break;
+ default:
+ BLI_assert(false && "Invalid GPU Backend Type");
+ break;
+ }
if (GPU_crappy_amd_driver()) {
sources.append("#define GPU_DEPRECATED_AMD_DRIVER\n");
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index b5a572bccbe..7bffafd7f9d 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -505,7 +505,9 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
bool display_colorspace,
bool do_overlay_merge)
{
- if (viewport->color_render_tx == NULL) {
+ const int view = 0;
+
+ if (viewport->color_render_tx[view] == NULL) {
return;
}
@@ -527,7 +529,7 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
};
gpu_viewport_draw_colormanaged(
- viewport, 0, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
+ viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
/* This one is from the offscreen. Don't free it with the viewport. */
viewport->depth_tx = NULL;
diff --git a/source/blender/gpu/metal/mtl_backend.hh b/source/blender/gpu/metal/mtl_backend.hh
new file mode 100644
index 00000000000..78f638d23f5
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_backend.hh
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_vector.hh"
+
+#include "gpu_backend.hh"
+#include "mtl_capabilities.hh"
+
+namespace blender {
+namespace gpu {
+
+class Batch;
+class DrawList;
+class FrameBuffer;
+class IndexBuf;
+class QueryPool;
+class Shader;
+class Texture;
+class UniformBuf;
+class VertBuf;
+class MTLContext;
+
+class MTLBackend : public GPUBackend {
+ friend class MTLContext;
+
+ public:
+ /* Capabilities. */
+ static MTLCapabilities capabilities;
+
+ inline ~MTLBackend()
+ {
+ MTLBackend::platform_exit();
+ }
+
+ static bool metal_is_supported();
+ inline static MTLBackend *get()
+ {
+ return static_cast<MTLBackend *>(GPUBackend::get());
+ }
+
+ void samplers_update() override;
+ inline void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
+ {
+ /* Placeholder */
+ }
+
+ /* MTL Allocators need to be implemented in separate .mm files, due to allocation of Objective-C
+ * objects. */
+ Context *context_alloc(void *ghost_window) override;
+ Batch *batch_alloc() override;
+ DrawList *drawlist_alloc(int list_length) override;
+ FrameBuffer *framebuffer_alloc(const char *name) override;
+ IndexBuf *indexbuf_alloc() override;
+ QueryPool *querypool_alloc() override;
+ Shader *shader_alloc(const char *name) override;
+ Texture *texture_alloc(const char *name) override;
+ UniformBuf *uniformbuf_alloc(int size, const char *name) override;
+ VertBuf *vertbuf_alloc() override;
+
+ /* Render Frame Coordination. */
+ void render_begin() override;
+ void render_end() override;
+ void render_step() override;
+ bool is_inside_render_boundary();
+
+ private:
+ static void platform_init(MTLContext *ctx);
+ static void platform_exit();
+
+ static void capabilities_init(MTLContext *ctx);
+};
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
new file mode 100644
index 00000000000..e1da371bd0b
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -0,0 +1,408 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BKE_global.h"
+
+#include "gpu_backend.hh"
+#include "mtl_backend.hh"
+
+#include "gpu_capabilities_private.hh"
+#include "gpu_platform_private.hh"
+
+#include <Cocoa/Cocoa.h>
+#include <Metal/Metal.h>
+#include <QuartzCore/QuartzCore.h>
+
+namespace blender {
+namespace gpu {
+
+/* Global per-thread AutoReleasePool. */
+thread_local NSAutoreleasePool *g_autoreleasepool = nil;
+thread_local int g_autoreleasepool_depth = 0;
+
+/* -------------------------------------------------------------------- */
+/** \name Metal Backend
+ * \{ */
+
+void MTLBackend::samplers_update(){
+ /* Placeholder -- Handled in MTLContext. */
+};
+
+Context *MTLBackend::context_alloc(void *ghost_window)
+{
+ /* TODO(Metal): Implement MTLContext. */
+ return nullptr;
+};
+
+Batch *MTLBackend::batch_alloc()
+{
+ /* TODO(Metal): Implement MTLBatch. */
+ return nullptr;
+};
+
+DrawList *MTLBackend::drawlist_alloc(int list_length)
+{
+ /* TODO(Metal): Implement MTLDrawList. */
+ return nullptr;
+};
+
+FrameBuffer *MTLBackend::framebuffer_alloc(const char *name)
+{
+ /* TODO(Metal): Implement MTLFrameBuffer. */
+ return nullptr;
+};
+
+IndexBuf *MTLBackend::indexbuf_alloc()
+{
+ /* TODO(Metal): Implement MTLIndexBuf. */
+ return nullptr;
+};
+
+QueryPool *MTLBackend::querypool_alloc()
+{
+ /* TODO(Metal): Implement MTLQueryPool. */
+ return nullptr;
+};
+
+Shader *MTLBackend::shader_alloc(const char *name)
+{
+ /* TODO(Metal): Implement MTLShader. */
+ return nullptr;
+};
+
+Texture *MTLBackend::texture_alloc(const char *name)
+{
+ /* TODO(Metal): Implement MTLTexture. */
+ return nullptr;
+}
+
+UniformBuf *MTLBackend::uniformbuf_alloc(int size, const char *name)
+{
+ /* TODO(Metal): Implement MTLUniformBuf. */
+ return nullptr;
+};
+
+VertBuf *MTLBackend::vertbuf_alloc()
+{
+ /* TODO(Metal): Implement MTLVertBuf. */
+ return nullptr;
+}
+
+void MTLBackend::render_begin()
+{
+ /* All Rendering must occur within a render boundary */
+ /* Track a call-count for nested calls, used to ensure we are inside an
+ * autoreleasepool from all rendering path. */
+ BLI_assert(g_autoreleasepool_depth >= 0);
+
+ if (g_autoreleasepool == nil) {
+ g_autoreleasepool = [[NSAutoreleasePool alloc] init];
+ }
+ g_autoreleasepool_depth++;
+ BLI_assert(g_autoreleasepool_depth > 0);
+}
+
+void MTLBackend::render_end()
+{
+ /* If call-count reaches zero, drain auto release pool.
+ * Ensures temporary objects are freed within a frame's lifetime. */
+ BLI_assert(g_autoreleasepool != nil);
+ g_autoreleasepool_depth--;
+ BLI_assert(g_autoreleasepool_depth >= 0);
+
+ if (g_autoreleasepool_depth == 0) {
+ [g_autoreleasepool drain];
+ g_autoreleasepool = nil;
+ }
+}
+
+void MTLBackend::render_step()
+{
+ /* Placeholder */
+}
+
+bool MTLBackend::is_inside_render_boundary()
+{
+ return (g_autoreleasepool != nil);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Platform
+ * \{ */
+
+/* For Metal, platform_init needs to be called after MTLContext initialization. */
+void MTLBackend::platform_init(MTLContext *ctx)
+{
+ if (GPG.initialized) {
+ return;
+ }
+
+ eGPUDeviceType device = GPU_DEVICE_UNKNOWN;
+ eGPUOSType os = GPU_OS_ANY;
+ eGPUDriverType driver = GPU_DRIVER_ANY;
+ eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED;
+
+ BLI_assert(ctx);
+ id<MTLDevice> mtl_device = nil; /*ctx->device; TODO(Metal): Implement MTLContext. */
+ BLI_assert(device);
+
+ NSString *gpu_name = [mtl_device name];
+ const char *vendor = [gpu_name UTF8String];
+ const char *renderer = "Metal API";
+ const char *version = "1.2";
+ printf("METAL API - DETECTED GPU: %s\n", vendor);
+
+ /* macOS is the only supported platform, but check to ensure we are not building with Metal
+ * enablement on another platform. */
+#ifdef _WIN32
+ os = GPU_OS_WIN;
+#elif defined(__APPLE__)
+ os = GPU_OS_MAC;
+#else
+ os = GPU_OS_UNIX;
+#endif
+
+ BLI_assert(os == GPU_OS_MAC && "Platform must be macOS");
+
+ /* Determine Vendor from name. */
+ if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
+ device = GPU_DEVICE_ATI;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "NVIDIA")) {
+ device = GPU_DEVICE_NVIDIA;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "Intel")) {
+ device = GPU_DEVICE_INTEL;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "Apple") || strstr(vendor, "APPLE")) {
+ /* Apple Silicon. */
+ device = GPU_DEVICE_APPLE;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(renderer, "Apple Software Renderer")) {
+ device = GPU_DEVICE_SOFTWARE;
+ driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) {
+ device = GPU_DEVICE_SOFTWARE;
+ driver = GPU_DRIVER_SOFTWARE;
+ }
+ else {
+ printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
+ printf("Detected configuration:\n");
+ printf("Vendor: %s\n", vendor);
+ printf("Renderer: %s\n", renderer);
+ }
+
+ GPG.init(device, os, driver, support_level, GPU_BACKEND_METAL, vendor, renderer, version);
+}
+
+void MTLBackend::platform_exit()
+{
+ BLI_assert(GPG.initialized);
+ GPG.clear();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Capabilities
+ * \{ */
+MTLCapabilities MTLBackend::capabilities = {};
+
+static const char *mtl_extensions_get_null(int i)
+{
+ return nullptr;
+}
+
+bool supports_barycentric_whitelist(id<MTLDevice> device)
+{
+ NSString *gpu_name = [device name];
+ BLI_assert([gpu_name length]);
+ const char *vendor = [gpu_name UTF8String];
+
+ /* Verify GPU support. */
+ bool supported_gpu = [device supportsFamily:MTLGPUFamilyMac2];
+ bool should_support_barycentrics = false;
+
+ /* Known good configs. */
+ if (strstr(vendor, "AMD") || strstr(vendor, "Apple") || strstr(vendor, "APPLE")) {
+ should_support_barycentrics = true;
+ }
+
+ /* Explicit support for Intel-based platforms. */
+ if ((strstr(vendor, "Intel") || strstr(vendor, "INTEL"))) {
+ should_support_barycentrics = true;
+ }
+ return supported_gpu && should_support_barycentrics;
+}
+
+bool MTLBackend::metal_is_supported()
+{
+ /* Device compatibility information using Metal Feature-set tables.
+ * See: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
+
+ NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
+
+ /* Metal Viewport requires macOS Version 10.15 onwards. */
+ bool supported_os_version = version.majorVersion >= 11 ||
+ (version.majorVersion == 10 ? version.minorVersion >= 15 : false);
+ if (!supported_os_version) {
+ printf(
+ "OS Version too low to run minimum required metal version. Required at least 10.15, got "
+ "%ld.%ld \n",
+ (long)version.majorVersion,
+ (long)version.minorVersion);
+ return false;
+ }
+
+ if (@available(macOS 10.15, *)) {
+ id<MTLDevice> device = MTLCreateSystemDefaultDevice();
+
+ /* Debug: Enable low power GPU with Environment Var: METAL_FORCE_INTEL. */
+ static const char *forceIntelStr = getenv("METAL_FORCE_INTEL");
+ bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false;
+
+ if (forceIntel) {
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> _device in allDevices) {
+ if (_device.lowPower) {
+ device = _device;
+ }
+ }
+ }
+
+ /* Metal Viewport requires argument buffer tier-2 support and Barycentric Coordinates.
+ * These are available on most hardware configurations supporting Metal 2.2. */
+ bool supports_argument_buffers_tier2 = ([device argumentBuffersSupport] ==
+ MTLArgumentBuffersTier2);
+ bool supports_barycentrics = [device supportsShaderBarycentricCoordinates] ||
+ supports_barycentric_whitelist(device);
+ bool supported_metal_version = [device supportsFamily:MTLGPUFamilyMac2];
+
+ bool result = supports_argument_buffers_tier2 && supports_barycentrics &&
+ supported_os_version && supported_metal_version;
+
+ if (!supports_argument_buffers_tier2) {
+ printf("[Metal] Device does not support argument buffers tier 2\n");
+ }
+ if (!supports_barycentrics) {
+ printf("[Metal] Device does not support barycentrics coordinates\n");
+ }
+ if (!supported_metal_version) {
+ printf("[Metal] Device does not support metal 2.2 or higher\n");
+ }
+
+ if (result) {
+ printf("Device with name %s supports metal minimum requirements\n",
+ [[device name] UTF8String]);
+ }
+
+ return result;
+ }
+ return false;
+}
+
+void MTLBackend::capabilities_init(MTLContext *ctx)
+{
+ BLI_assert(ctx);
+ id<MTLDevice> device = nil; /*ctx->device TODO(Metal): Implement MTLContext. */
+ BLI_assert(device);
+
+ /* Initialize Capabilities. */
+ MTLBackend::capabilities.supports_argument_buffers_tier2 = ([device argumentBuffersSupport] ==
+ MTLArgumentBuffersTier2);
+ MTLBackend::capabilities.supports_family_mac1 = [device supportsFamily:MTLGPUFamilyMac1];
+ MTLBackend::capabilities.supports_family_mac2 = [device supportsFamily:MTLGPUFamilyMac2];
+ MTLBackend::capabilities.supports_family_mac_catalyst1 = [device
+ supportsFamily:MTLGPUFamilyMacCatalyst1];
+ MTLBackend::capabilities.supports_family_mac_catalyst2 = [device
+ supportsFamily:MTLGPUFamilyMacCatalyst2];
+
+ /* Common Global Capabilities. */
+ GCaps.max_texture_size = ([device supportsFamily:MTLGPUFamilyApple3] ||
+ MTLBackend::capabilities.supports_family_mac1) ?
+ 16384 :
+ 8192;
+ GCaps.max_texture_3d_size = 2048;
+ GCaps.max_texture_layers = 2048;
+ GCaps.max_textures = (MTLBackend::capabilities.supports_family_mac1) ?
+ 128 :
+ (([device supportsFamily:MTLGPUFamilyApple4]) ? 96 : 31);
+ if (GCaps.max_textures <= 32) {
+ BLI_assert(false);
+ }
+ GCaps.max_samplers = (MTLBackend::capabilities.supports_argument_buffers_tier2) ? 1024 : 16;
+
+ GCaps.max_textures_vert = GCaps.max_textures;
+ GCaps.max_textures_geom = 0; /* N/A geometry shaders not supported. */
+ GCaps.max_textures_frag = GCaps.max_textures;
+
+ /* Conservative uniform data limit is 4KB per-stage -- This is the limit of setBytes.
+ * MTLBuffer path is also supported but not as efficient. */
+ GCaps.max_uniforms_vert = 1024;
+ GCaps.max_uniforms_frag = 1024;
+
+ GCaps.max_batch_indices = 1 << 31;
+ GCaps.max_batch_vertices = 1 << 31;
+ GCaps.max_vertex_attribs = 31;
+ GCaps.max_varying_floats = 60;
+
+ /* Feature support */
+ GCaps.mem_stats_support = false;
+ GCaps.shader_image_load_store_support = ([device supportsFamily:MTLGPUFamilyApple3] ||
+ MTLBackend::capabilities.supports_family_mac1 ||
+ MTLBackend::capabilities.supports_family_mac2);
+ GCaps.compute_shader_support = false; /* TODO(Metal): Add compute support. */
+ GCaps.shader_storage_buffer_objects_support =
+ false; /* TODO(Metal): implement Storage Buffer support.*/
+
+ /* Maximum buffer bindings: 31. Consider required slot for uniforms/UBOs/Vertex attributes.
+ * Can use argument buffers if a higher limit is required. */
+ GCaps.max_shader_storage_buffer_bindings = 24;
+
+ if (GCaps.compute_shader_support) {
+ GCaps.max_work_group_count[0] = 65535;
+ GCaps.max_work_group_count[1] = 65535;
+ GCaps.max_work_group_count[2] = 65535;
+
+ /* In Metal, total_thread_count is 512 or 1024, such that
+ * threadgroup `width*height*depth <= total_thread_count` */
+ unsigned int max_threads_per_threadgroup_per_dim =
+ ([device supportsFamily:MTLGPUFamilyApple4] ||
+ MTLBackend::capabilities.supports_family_mac1) ?
+ 1024 :
+ 512;
+ GCaps.max_work_group_size[0] = max_threads_per_threadgroup_per_dim;
+ GCaps.max_work_group_size[1] = max_threads_per_threadgroup_per_dim;
+ GCaps.max_work_group_size[2] = max_threads_per_threadgroup_per_dim;
+ }
+
+ GCaps.transform_feedback_support = true;
+
+ /* OPENGL Related workarounds -- none needed for Metal. */
+ GCaps.extensions_len = 0;
+ GCaps.extension_get = mtl_extensions_get_null;
+ GCaps.mip_render_workaround = false;
+ GCaps.depth_blitting_workaround = false;
+ GCaps.use_main_context_workaround = false;
+ GCaps.broken_amd_driver = false;
+
+ /* Metal related workarounds. */
+ /* Minimum per-vertex stride is 4 bytes in Metal.
+ * A bound vertex buffer must contribute at least 4 bytes per vertex. */
+ GCaps.minimum_per_vertex_stride = 4;
+}
+
+/** \} */
+
+} // gpu
+} // blender
diff --git a/source/blender/gpu/metal/mtl_capabilities.hh b/source/blender/gpu/metal/mtl_capabilities.hh
new file mode 100644
index 00000000000..5563008e87d
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_capabilities.hh
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+namespace blender {
+namespace gpu {
+
+/*** Derived from: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf ***/
+/** Upper Bound/Fixed Limits **/
+
+#define METAL_MAX_TEXTURE_SLOTS 128
+#define METAL_MAX_SAMPLER_SLOTS METAL_MAX_TEXTURE_SLOTS
+#define METAL_MAX_UNIFORM_BUFFER_BINDINGS 31
+#define METAL_MAX_VERTEX_INPUT_ATTRIBUTES 31
+#define METAL_MAX_UNIFORMS_PER_BLOCK 64
+
+/* Context-specific limits -- populated in 'MTLBackend::platform_init' */
+typedef struct MTLCapabilities {
+
+ /* Variable Limits & feature sets. */
+ int max_color_render_targets = 4; /* Minimum = 4 */
+ int buffer_alignment_for_textures = 256; /* Upper bound = 256 bytes */
+ int minimum_buffer_offset_alignment = 256; /* Upper bound = 256 bytes */
+
+ /* Capabilities */
+ bool supports_vertex_amplification = false;
+ bool supports_texture_swizzle = true;
+ bool supports_cubemaps = true;
+ bool supports_layered_rendering = true;
+ bool supports_memory_barriers = false;
+ bool supports_sampler_border_color = false;
+ bool supports_argument_buffers_tier2 = false;
+
+ /* GPU Family */
+ bool supports_family_mac1 = false;
+ bool supports_family_mac2 = false;
+ bool supports_family_mac_catalyst1 = false;
+ bool supports_family_mac_catalyst2 = false;
+
+} MTLCapabilities;
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 883f9403920..2c9cbdb99d8 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -140,7 +140,7 @@ void GLBackend::platform_init()
}
}
- GPG.init(device, os, driver, support_level, vendor, renderer, version);
+ GPG.init(device, os, driver, support_level, GPU_BACKEND_OPENGL, vendor, renderer, version);
}
void GLBackend::platform_exit()
@@ -418,6 +418,12 @@ static void detect_workarounds()
(strstr(renderer, "HD Graphics 4400") || strstr(renderer, "HD Graphics 4600"))) {
GCaps.shader_storage_buffer_objects_support = false;
}
+
+ /* Metal-related Workarounds. */
+
+ /* Minimum Per-Vertex stride is 1 byte for OpenGL. */
+ GCaps.minimum_per_vertex_stride = 1;
+
} // namespace blender::gpu
/** Internal capabilities. */
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index e72726d9c7b..29249111294 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -136,6 +136,11 @@ class GLBackend : public GPUBackend {
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
}
+ /* Render Frame Coordination */
+ void render_begin(void) override{};
+ void render_end(void) override{};
+ void render_step(void) override{};
+
private:
static void platform_init();
static void platform_exit();
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index c0182306047..5a55a2e8020 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -24,6 +24,8 @@ using namespace blender;
using namespace blender::gpu;
using namespace blender::gpu::shader;
+extern "C" char datatoc_glsl_shader_defines_glsl[];
+
/* -------------------------------------------------------------------- */
/** \name Creation / Destruction
* \{ */
@@ -760,7 +762,7 @@ bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info
static char *glsl_patch_default_get()
{
/** Used for shader patching. Init once. */
- static char patch[1024] = "\0";
+ static char patch[2048] = "\0";
if (patch[0] != '\0') {
return patch;
}
@@ -827,6 +829,9 @@ static char *glsl_patch_default_get()
STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]);
STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]);
+ /* GLSL Backend Lib. */
+ STR_CONCAT(patch, slen, datatoc_glsl_shader_defines_glsl);
+
BLI_assert(slen < sizeof(patch));
return patch;
}
diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc
index a461d834790..109bb65fcb7 100644
--- a/source/blender/gpu/opengl/gl_storage_buffer.cc
+++ b/source/blender/gpu/opengl/gl_storage_buffer.cc
@@ -27,7 +27,7 @@ GLStorageBuf::GLStorageBuf(size_t size, GPUUsageType usage, const char *name)
: StorageBuf(size, name)
{
usage_ = usage;
- /* Do not create ubo GL buffer here to allow allocation from any thread. */
+ /* Do not create UBO GL buffer here to allow allocation from any thread. */
BLI_assert(size <= GLContext::max_ssbo_size);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
index 9851e08fe2e..353bf1481da 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
@@ -23,15 +23,15 @@ void main()
/* Use pos to select the right swizzle (instead of gl_VertexID)
* in order to workaround an OSX driver bug. */
- if (pos == vec2(0.0, 0.0)) {
+ if (all(equal(pos, vec2(0.0, 0.0)))) {
rect.xy = rect.xz;
tex.xy = tex.xz;
}
- else if (pos == vec2(0.0, 1.0)) {
+ else if (all(equal(pos, vec2(0.0, 1.0)))) {
rect.xy = rect.xw;
tex.xy = tex.xw;
}
- else if (pos == vec2(1.0, 1.0)) {
+ else if (all(equal(pos, vec2(1.0, 1.0)))) {
rect.xy = rect.yw;
tex.xy = tex.yw;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
index d9a5aeeef46..903c602c5d6 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
@@ -15,6 +15,32 @@ void main()
{
vec2 uv;
vec2 co;
+
+#ifdef GPU_METAL
+/* Metal API does not support Triangle fan primitive topology.
+ * When this shader is called using Triangle-Strip, vertex ID's
+ * are in a different order. */
+# define GPU_PRIM_TRI_STRIP
+#endif
+
+#ifdef GPU_PRIM_TRI_STRIP
+ if (gl_VertexID == 0) {
+ co = rect_geom.xw;
+ uv = rect_icon.xw;
+ }
+ else if (gl_VertexID == 1) {
+ co = rect_geom.xy;
+ uv = rect_icon.xy;
+ }
+ else if (gl_VertexID == 2) {
+ co = rect_geom.zw;
+ uv = rect_icon.zw;
+ }
+ else {
+ co = rect_geom.zy;
+ uv = rect_icon.zy;
+ }
+#else
if (gl_VertexID == 0) {
co = rect_geom.xy;
uv = rect_icon.xy;
@@ -31,6 +57,7 @@ void main()
co = rect_geom.zy;
uv = rect_icon.zy;
}
+#endif
gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f);
texCoord_interp = uv;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
index 80b93baf20a..3a39cd8b847 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -53,7 +53,7 @@ flat out float lineWidth;
noperspective out float butCo;
flat out float discardFac;
-# ifdef OS_MAC
+# if defined(OS_MAC) && defined(GPU_OPENGL)
in float dummy;
# endif
#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
index 2314dbbc5d5..d77f073b7de 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
@@ -32,8 +32,8 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
void main()
{
- fragColor = texture(image_texture, texCoord_interp.st);
- vec4 overlay_col = texture(overlays_texture, texCoord_interp.st);
+ fragColor = texture(image_texture, texCoord_interp.xy);
+ vec4 overlay_col = texture(overlays_texture, texCoord_interp.xy);
if (overlay) {
fragColor = clamp(fragColor, 0.0, 1.0);
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
index 4ef3ff1a8d0..617c02ac079 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
@@ -43,7 +43,7 @@ bool test(int bit)
vec2 line_thresholds(float width)
{
- return vec2(max(0, width - line_falloff), width);
+ return vec2(max(0.0, width - line_falloff), width);
}
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index c339d3cbabb..f958a81b1eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -52,7 +52,7 @@ bool is_inside_box(ivec2 v)
float texture_1D_custom_bilinear_filter(vec2 uv)
{
- vec2 texel_2d = uv * glyph_dim + 0.5;
+ vec2 texel_2d = uv * vec2(glyph_dim) + vec2(0.5);
ivec2 texel_2d_near = ivec2(texel_2d) - 1;
int frag_offset = glyph_offset + texel_2d_near.y * glyph_dim.x + texel_2d_near.x;
@@ -100,7 +100,7 @@ void main()
fragColor.a = texture_1D_custom_bilinear_filter(texCoord_interp);
}
else {
- vec2 texel = 1.0 / glyph_dim;
+ vec2 texel = 1.0 / vec2(glyph_dim);
fragColor.a = 0.0;
if (interp_size == 1) {
diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
index 5b01fea5266..63d73733c2f 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -28,8 +28,9 @@ void main()
vec2 interp_offset = float(interp_size) / abs(pos.zw - pos.xy);
texCoord_interp = mix(-interp_offset, 1.0 + interp_offset, quad);
- vec2 final_pos = mix(
- pos.xy + ivec2(-interp_size, interp_size), pos.zw + ivec2(interp_size, -interp_size), quad);
+ vec2 final_pos = mix(vec2(ivec2(pos.xy) + ivec2(-interp_size, interp_size)),
+ vec2(ivec2(pos.zw) + ivec2(interp_size, -interp_size)),
+ quad);
gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 0.0, 1.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
index f3eae653f95..92762db5ff4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
@@ -1,7 +1,10 @@
-void node_light_falloff(
- float strength, float tsmooth, out float quadratic, out float linear, out float constant)
+void node_light_falloff(float strength,
+ float tsmooth,
+ out float quadratic,
+ out float linear,
+ out float falloff_constant)
{
quadratic = strength;
linear = strength;
- constant = strength;
+ falloff_constant = strength;
}
diff --git a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl
new file mode 100644
index 00000000000..a5fce2e71c3
--- /dev/null
+++ b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl
@@ -0,0 +1,17 @@
+/* Backend Functions. */
+#define select(A, B, mask) mix(A, B, mask)
+
+bool is_zero(vec2 A)
+{
+ return all(equal(A, vec2(0.0)));
+}
+
+bool is_zero(vec3 A)
+{
+ return all(equal(A, vec3(0.0)));
+}
+
+bool is_zero(vec4 A)
+{
+ return all(equal(A, vec4(0.0)));
+}
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 7434db732fd..7cf2c02e657 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -19,6 +19,7 @@ extern "C" {
struct ColorManagedColorspaceSettings;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct ColorManagedOutputSettings;
struct ColormanageProcessor;
struct EnumPropertyItem;
struct ImBuf;
@@ -52,6 +53,7 @@ bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
+bool IMB_colormanagement_space_name_is_scene_linear(const char *name);
/**
* Convert a float RGB triplet to the correct luminance weighted average.
@@ -238,23 +240,10 @@ void IMB_colormanagement_imbuf_make_display_space(
* in image format write callback and if float_colorspace is not NULL, no color
* space transformation should be applied on this buffer.
*/
-struct ImBuf *IMB_colormanagement_imbuf_for_write(
- struct ImBuf *ibuf,
- bool save_as_render,
- bool allocate_result,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings,
- const struct ImageFormatData *image_format_data);
-
-void IMB_colormanagement_buffer_make_display_space(
- float *buffer,
- unsigned char *display_buffer,
- int width,
- int height,
- int channels,
- float dither,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings);
+struct ImBuf *IMB_colormanagement_imbuf_for_write(struct ImBuf *ibuf,
+ bool save_as_render,
+ bool allocate_result,
+ const struct ImageFormatData *image_format);
/** \} */
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index 42941ace40b..c89b15480a2 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -33,6 +33,9 @@ typedef struct ColorSpace {
struct OCIO_ConstCPUProcessorRcPtr *to_scene_linear;
struct OCIO_ConstCPUProcessorRcPtr *from_scene_linear;
+ char (*aliases)[MAX_COLORSPACE_NAME];
+ int num_aliases;
+
bool is_invertible;
bool is_data;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index e60df0ca1c9..2e8c5cc4a40 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -504,7 +504,18 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
is_data = OCIO_colorSpaceIsData(ocio_colorspace);
- colormanage_colorspace_add(name, description, is_invertible, is_data);
+ ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data);
+
+ colorspace->num_aliases = OCIO_colorSpaceGetNumAliases(ocio_colorspace);
+ if (colorspace->num_aliases > 0) {
+ colorspace->aliases = MEM_callocN(sizeof(*colorspace->aliases) * colorspace->num_aliases,
+ "ColorSpace aliases");
+ for (int i = 0; i < colorspace->num_aliases; i++) {
+ BLI_strncpy(colorspace->aliases[i],
+ OCIO_colorSpaceGetAlias(ocio_colorspace, i),
+ MAX_COLORSPACE_NAME);
+ }
+ }
OCIO_colorSpaceRelease(ocio_colorspace);
}
@@ -587,6 +598,7 @@ static void colormanage_free_config(void)
}
/* free color space itself */
+ MEM_SAFE_FREE(colorspace->aliases);
MEM_freeN(colorspace);
colorspace = colorspace_next;
@@ -1394,6 +1406,12 @@ bool IMB_colormanagement_space_name_is_data(const char *name)
return (colorspace && colorspace->is_data);
}
+bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
+{
+ ColorSpace *colorspace = colormanage_colorspace_get_named(name);
+ return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
+}
+
const float *IMB_colormanagement_get_xyz_to_rgb()
{
return &imbuf_xyz_to_rgb[0][0];
@@ -2431,15 +2449,12 @@ void IMB_colormanagement_imbuf_make_display_space(
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
- const ImageFormatData *image_format_data)
+ const ImageFormatData *imf)
{
ImBuf *colormanaged_ibuf = ibuf;
- bool do_colormanagement;
- bool is_movie = BKE_imtype_is_movie(image_format_data->imtype);
- bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
- bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
+ const bool is_movie = BKE_imtype_is_movie(imf->imtype);
+ const bool requires_linear_float = BKE_imtype_requires_linear_float(imf->imtype);
+ const bool do_alpha_under = imf->planes != R_IMF_PLANES_RGBA;
if (ibuf->rect_float && ibuf->rect &&
(ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) {
@@ -2447,9 +2462,13 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
}
- do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
+ const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float);
+ const bool do_colormanagement_linear = save_as_render && requires_linear_float &&
+ imf->linear_colorspace_settings.name[0] &&
+ !IMB_colormanagement_space_name_is_scene_linear(
+ imf->linear_colorspace_settings.name);
- if (do_colormanagement || do_alpha_under) {
+ if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) {
if (allocate_result) {
colormanaged_ibuf = IMB_dupImBuf(ibuf);
}
@@ -2502,15 +2521,15 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
}
}
- if (do_colormanagement) {
+ if (do_colormanagement_display) {
+ /* Color management with display and view transform. */
bool make_byte = false;
/* for proper check whether byte buffer is required by a format or not
* should be pretty safe since this image buffer is supposed to be used for
* saving only and ftype would be overwritten a bit later by BKE_imbuf_write
*/
- colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format_data->imtype,
- &colormanaged_ibuf->foptions);
+ colormanaged_ibuf->ftype = BKE_imtype_to_ftype(imf->imtype, &colormanaged_ibuf->foptions);
/* if file format isn't able to handle float buffer itself,
* we need to allocate byte buffer and store color managed
@@ -2525,15 +2544,36 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
/* perform color space conversions */
colormanagement_imbuf_make_display_space(
- colormanaged_ibuf, view_settings, display_settings, make_byte);
+ colormanaged_ibuf, &imf->view_settings, &imf->display_settings, make_byte);
if (colormanaged_ibuf->rect_float) {
/* float buffer isn't linear anymore,
* image format write callback should check for this flag and assume
* no space conversion should happen if ibuf->float_colorspace != NULL
*/
- colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(view_settings,
- display_settings);
+ colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(
+ &imf->view_settings, &imf->display_settings);
+ }
+ }
+ else if (do_colormanagement_linear) {
+ /* Color management transform to another linear color space. */
+ if (!colormanaged_ibuf->rect_float) {
+ IMB_float_from_rect(colormanaged_ibuf);
+ imb_freerectImBuf(colormanaged_ibuf);
+ }
+
+ if (colormanaged_ibuf->rect_float) {
+ const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
+ global_role_scene_linear;
+ const char *to_colorspace = imf->linear_colorspace_settings.name;
+
+ IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace,
+ false);
}
}
@@ -2544,45 +2584,6 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
return colormanaged_ibuf;
}
-void IMB_colormanagement_buffer_make_display_space(
- float *buffer,
- unsigned char *display_buffer,
- int width,
- int height,
- int channels,
- float dither,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings)
-{
- ColormanageProcessor *cm_processor;
- size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
- float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
-
- /* TODO(sergey): Convert float directly to byte buffer. */
-
- memcpy(display_buffer_float, buffer, float_buffer_size);
-
- cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
-
- processor_transform_apply_threaded(
- NULL, display_buffer_float, width, height, channels, cm_processor, true, false);
-
- IMB_buffer_byte_from_float(display_buffer,
- display_buffer_float,
- channels,
- dither,
- IB_PROFILE_SRGB,
- IB_PROFILE_SRGB,
- true,
- width,
- height,
- width,
- width);
-
- MEM_freeN(display_buffer_float);
- IMB_colormanagement_processor_free(cm_processor);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -3064,6 +3065,12 @@ ColorSpace *colormanage_colorspace_get_named(const char *name)
if (STREQ(colorspace->name, name)) {
return colorspace;
}
+
+ for (int i = 0; i < colorspace->num_aliases; i++) {
+ if (STREQ(colorspace->aliases[i], name)) {
+ return colorspace;
+ }
+ }
}
return NULL;
diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h
index a9ade9b02fa..d0c10bd7f76 100644
--- a/source/blender/io/alembic/ABC_alembic.h
+++ b/source/blender/io/alembic/ABC_alembic.h
@@ -111,7 +111,7 @@ struct Mesh *ABC_read_mesh(struct CacheReader *reader,
bool ABC_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
- struct Mesh *existing_mesh,
+ const struct Mesh *existing_mesh,
float time,
const char **err_str);
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index 11693eeb4de..bbb196dc383 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -158,6 +158,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context)
BMeshCreateParams bmesh_create_params{};
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
+ bmesh_from_mesh_params.calc_vert_normal = true;
BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr);
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 1d00b55ca78..47f4dd2ea5d 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -658,7 +658,7 @@ bool AbcMeshReader::accepts_object_type(
return true;
}
-bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel)
+bool AbcMeshReader::topology_changed(const Mesh *existing_mesh, const ISampleSelector &sample_sel)
{
IPolyMeshSchema::Sample sample;
try {
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h
index 9f871d260a7..f97525297b7 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.h
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.h
@@ -30,7 +30,7 @@ class AbcMeshReader final : public AbcObjectReader {
const char *velocity_name,
float velocity_scale,
const char **err_str) override;
- bool topology_changed(Mesh *existing_mesh,
+ bool topology_changed(const Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel) override;
private:
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index 72aec8f4336..dac0890e7c5 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -140,7 +140,7 @@ struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
return existing_mesh;
}
-bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
+bool AbcObjectReader::topology_changed(const Mesh * /*existing_mesh*/,
const Alembic::Abc::ISampleSelector & /*sample_sel*/)
{
/* The default implementation of read_mesh() just returns the original mesh, so never changes the
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index d33eabfbee5..5898d1bd529 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -139,7 +139,7 @@ class AbcObjectReader {
const char *velocity_name,
float velocity_scale,
const char **err_str);
- virtual bool topology_changed(Mesh *existing_mesh,
+ virtual bool topology_changed(const Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel);
/** Reads the object matrix and sets up an object transform if animated. */
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index 769285c247f..c9c982aad6c 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -801,8 +801,11 @@ Mesh *ABC_read_mesh(CacheReader *reader,
existing_mesh, sample_sel, read_flag, velocity_name, velocity_scale, err_str);
}
-bool ABC_mesh_topology_changed(
- CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str)
+bool ABC_mesh_topology_changed(CacheReader *reader,
+ Object *ob,
+ const Mesh *existing_mesh,
+ const float time,
+ const char **err_str)
{
AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
if (abc_reader == nullptr) {
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 2c9f16c7624..3b21d423df5 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -120,7 +120,7 @@ void GeometryExporter::operator()(Object *ob)
/* skip the basis */
kb = kb->next;
for (; kb; kb = kb->next) {
- BKE_keyblock_convert_to_mesh(kb, me);
+ BKE_keyblock_convert_to_mesh(kb, me->mvert, me->totvert);
export_key_mesh(ob, me, kb);
}
}
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index 79ac5be35f8..8d7ada4a600 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -411,6 +411,7 @@ void bc_triangulate_mesh(Mesh *me)
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params);
BMeshFromMeshParams bm_from_me_params{};
bm_from_me_params.calc_face_normal = true;
+ bm_from_me_params.calc_vert_normal = true;
BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr);
diff --git a/source/blender/io/usd/intern/usd_reader_geom.h b/source/blender/io/usd/intern/usd_reader_geom.h
index 6dcad2ffac8..b73279250f2 100644
--- a/source/blender/io/usd/intern/usd_reader_geom.h
+++ b/source/blender/io/usd/intern/usd_reader_geom.h
@@ -24,7 +24,7 @@ class USDGeomReader : public USDXformReader {
int read_flag,
const char **err_str) = 0;
- virtual bool topology_changed(Mesh * /* existing_mesh */, double /* motionSampleTime */)
+ virtual bool topology_changed(const Mesh * /* existing_mesh */, double /* motionSampleTime */)
{
return true;
}
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 1f97c7b48b3..646d1ba1fde 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -232,7 +232,7 @@ bool USDMeshReader::valid() const
return static_cast<bool>(mesh_prim_);
}
-bool USDMeshReader::topology_changed(Mesh *existing_mesh, const double motionSampleTime)
+bool USDMeshReader::topology_changed(const Mesh *existing_mesh, const double motionSampleTime)
{
/* TODO(makowalski): Is it the best strategy to cache the mesh
* geometry in this function? This needs to be revisited. */
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index fdd814f56d4..5e33ce8b5e8 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -53,7 +53,7 @@ class USDMeshReader : public USDGeomReader {
int read_flag,
const char **err_str) override;
- bool topology_changed(Mesh *existing_mesh, double motionSampleTime) override;
+ bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override;
private:
void process_normals_vertex_varying(Mesh *mesh);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index a7508f01b0f..fb9074999f9 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -89,8 +89,13 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
if (export_mesh_eval_->totpoly <= 0) {
return {export_mesh_eval_, false};
}
- const struct BMeshCreateParams bm_create_params = {0u};
- const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0};
+ const BMeshCreateParams bm_create_params = {0u};
+ BMeshFromMeshParams bm_convert_params{};
+ bm_convert_params.calc_face_normal = true;
+ bm_convert_params.calc_vert_normal = true;
+ bm_convert_params.add_key_index = false;
+ bm_convert_params.use_shapekey = false;
+
/* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
* triangulated here. */
const int triangulate_min_verts = 4;
@@ -207,7 +212,10 @@ void OBJMesh::calc_poly_order()
blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) {
int mat_a = mpolys[a].mat_nr;
int mat_b = mpolys[b].mat_nr;
- return mat_a < mat_b;
+ if (mat_a != mat_b) {
+ return mat_a < mat_b;
+ }
+ return a < b;
});
}
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index be8f9f938a3..24c120ae860 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -429,6 +429,8 @@ typedef struct ImageFormatData {
Stereo3dFormat stereo3d_format;
/* color management */
+ char color_management;
+ char _pad1[7];
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
ColorManagedColorspaceSettings linear_colorspace_settings;
@@ -527,6 +529,10 @@ enum {
R_IMF_TIFF_CODEC_NONE = 3,
};
+/** #ImageFormatData.color_management */
+#define R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE 0
+#define R_IMF_COLOR_MANAGEMENT_OVERRIDE 1
+
typedef struct BakeData {
struct ImageFormatData im_format;
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index d4c38060e1b..3ebcae5f947 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -179,7 +179,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 2, 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 2, 9, 11, 13, 14, 15. */
typedef enum PropertyFlag {
/**
* Editable means the property is editable in the user
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 373aec975c2..840674c7bc6 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -605,6 +605,11 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
{
ID *id = ptr->owner_id;
+ if (!id) {
+ /* Happens for color space settings on operators. */
+ return;
+ }
+
if (GS(id->name) == ID_IM) {
Image *ima = (Image *)id;
diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c
index f31e72ce652..b7be5293578 100644
--- a/source/blender/makesrna/intern/rna_curve_api.c
+++ b/source/blender/makesrna/intern/rna_curve_api.c
@@ -43,22 +43,19 @@ static void rna_Nurb_valid_message(Nurb *nu, int direction, int *result_len, con
int pnts;
short order, flag;
- const char *dir;
if (direction == 0) {
pnts = nu->pntsu;
order = nu->orderu;
flag = nu->flagu;
- dir = "U";
}
else {
pnts = nu->pntsv;
order = nu->orderv;
flag = nu->flagv;
- dir = "V";
}
char buf[64];
- if (BKE_nurb_valid_message(pnts, order, flag, type, is_surf, dir, buf, sizeof(buf))) {
+ if (BKE_nurb_valid_message(pnts, order, flag, type, is_surf, direction, buf, sizeof(buf))) {
const int buf_len = strlen(buf);
*r_result = BLI_strdupn(buf, buf_len);
*result_len = buf_len;
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index ce0598d355d..dab3cd68d4c 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -2446,8 +2446,10 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cfl_condition");
RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "CFL", "Maximal velocity per cell (higher value results in greater timesteps)");
+ RNA_def_property_ui_text(prop,
+ "CFL",
+ "Maximal velocity per cell (greater CFL numbers will minimize the "
+ "number of simulation steps and the computation time.)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 92e3254765c..55d365f9827 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -25,7 +25,9 @@
#ifdef RNA_RUNTIME
# include "BKE_image.h"
+# include "BKE_image_format.h"
# include "BKE_main.h"
+# include "BKE_scene.h"
# include <errno.h>
# include "IMB_colormanagement.h"
@@ -68,19 +70,23 @@ static void rna_Image_save_render(
else {
ImBuf *write_ibuf;
- write_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format);
+ ImageFormatData image_format;
+ BKE_image_format_init_for_write(&image_format, scene, NULL);
- write_ibuf->planes = scene->r.im_format.planes;
+ write_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &image_format);
+
+ write_ibuf->planes = image_format.planes;
write_ibuf->dither = scene->r.dither_intensity;
- if (!BKE_imbuf_write(write_ibuf, path, &scene->r.im_format)) {
+ if (!BKE_imbuf_write(write_ibuf, path, &image_format)) {
BKE_reportf(reports, RPT_ERROR, "Could not write image: %s, '%s'", strerror(errno), path);
}
if (write_ibuf != ibuf) {
IMB_freeImBuf(write_ibuf);
}
+
+ BKE_image_format_free(&image_format);
}
BKE_image_release_ibuf(image, ibuf, lock);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 807fc27268d..eec1ce60089 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -393,7 +393,15 @@ char *rna_TextureSlot_path(struct PointerRNA *ptr);
char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
/* Set U.is_dirty and redraw. */
+
+/**
+ * Use single function so we can more easily break-point it.
+ */
void rna_userdef_is_dirty_update_impl(void);
+/**
+ * Use as a fallback update handler to ensure #U.runtime.is_dirty is set.
+ * So the preferences are saved when modified.
+ */
void rna_userdef_is_dirty_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
/* API functions */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 6d04d141f8e..9400e34d193 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -20,6 +20,7 @@
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "BLI_listbase.h"
@@ -29,6 +30,7 @@
#include "BKE_armature.h"
#include "BKE_editmesh.h"
+#include "BKE_idtype.h"
#include "BKE_paint.h"
#include "BKE_volume.h"
@@ -1440,6 +1442,35 @@ static const EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(bContext
}
# endif
+
+static bool rna_ImageFormatSettings_has_linear_colorspace_get(PointerRNA *ptr)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+ return BKE_imtype_requires_linear_float(imf->imtype);
+}
+
+static void rna_ImageFormatSettings_color_management_set(PointerRNA *ptr, int value)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+
+ if (imf->color_management != value) {
+ imf->color_management = value;
+
+ /* Copy from scene when enabling override. */
+ if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ ID *owner_id = ptr->owner_id;
+ if (owner_id && GS(owner_id->name) == ID_NT) {
+ /* For compositing nodes, find the corresponding scene. */
+ const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(owner_id);
+ owner_id = type_info->owner_get(G_MAIN, owner_id);
+ }
+ if (owner_id && GS(owner_id->name) == ID_SCE) {
+ BKE_image_format_color_management_copy_from_scene(imf, (Scene *)owner_id);
+ }
+ }
+ }
+}
+
static int rna_SceneRender_file_ext_length(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -5458,6 +5489,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
};
# endif
+ static const EnumPropertyItem color_management_items[] = {
+ {R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE, "FOLLOW_SCENE", 0, "Follow Scene", ""},
+ {R_IMF_COLOR_MANAGEMENT_OVERRIDE, "OVERRIDE", 0, "Override", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
StructRNA *srna;
PropertyRNA *prop;
@@ -5616,17 +5653,32 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3D");
/* color management */
+ prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, color_management_items);
+ RNA_def_property_ui_text(
+ prop, "Color Management", "Which color management settings to use for file saving");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_ImageFormatSettings_color_management_set", NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "view_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "view_settings");
RNA_def_property_struct_type(prop, "ColorManagedViewSettings");
RNA_def_property_ui_text(
prop, "View Settings", "Color management settings applied on image before saving");
prop = RNA_def_property(srna, "display_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "display_settings");
RNA_def_property_struct_type(prop, "ColorManagedDisplaySettings");
RNA_def_property_ui_text(
prop, "Display Settings", "Settings of device saved image would be displayed on");
+
+ prop = RNA_def_property(srna, "linear_colorspace_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
+ RNA_def_property_ui_text(prop, "Color Space Settings", "Output color space settings");
+
+ prop = RNA_def_property(srna, "has_linear_colorspace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_ImageFormatSettings_has_linear_colorspace_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Has Linear Color Space", "File format expects linear color space");
}
static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
@@ -6161,7 +6213,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 3);
- RNA_def_property_ui_text(prop, "Additional Subdiv", "Additional subdivision along the hair");
+ RNA_def_property_ui_text(prop, "Additional Subdivision", "Additional subdivision along the hair");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
/* Performance */
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 3c8f1ee28c9..56d1b48811a 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -21,6 +21,7 @@
#include "BLI_utildefines.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "RNA_define.h"
@@ -191,8 +192,23 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
static void rna_Texture_mapping_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
+ ID *id = ptr->owner_id;
TexMapping *texmap = ptr->data;
BKE_texture_mapping_init(texmap);
+
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ /* Try to find and tag the node that this #TexMapping belongs to. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ /* This assumes that the #TexMapping is stored at the beginning of the node storage. This is
+ * generally true, see #NodeTexBase. If the assumption happens to be false, there might be a
+ * missing update. */
+ if (node->storage == texmap) {
+ BKE_ntree_update_tag_node_property(ntree, node);
+ }
+ }
+ }
+
rna_Texture_update(bmain, scene, ptr);
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 30a4268e5a0..a0d53701e26 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -208,7 +208,6 @@ static void rna_userdef_version_get(PointerRNA *ptr, int *value)
/** Mark the preferences as being changed so they are saved on exit. */
# define USERDEF_TAG_DIRTY rna_userdef_is_dirty_update_impl()
-/** Use single function so we can more easily break-point it. */
void rna_userdef_is_dirty_update_impl(void)
{
/* We can't use 'ptr->data' because this update function
@@ -219,14 +218,11 @@ void rna_userdef_is_dirty_update_impl(void)
}
}
-/**
- * Use as a fallback update handler,
- * never use 'ptr' unless its type is checked.
- */
void rna_userdef_is_dirty_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *UNUSED(ptr))
{
+ /* WARNING: never use 'ptr' unless its type is checked. */
rna_userdef_is_dirty_update_impl();
}
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 88984a652d7..a5e5bf36dcd 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -61,7 +61,7 @@ set(SRC
intern/MOD_meshcache_pc2.c
intern/MOD_meshcache_util.c
intern/MOD_meshdeform.c
- intern/MOD_meshsequencecache.c
+ intern/MOD_meshsequencecache.cc
intern/MOD_mirror.c
intern/MOD_multires.c
intern/MOD_nodes.cc
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 4b2dfd7d493..b237f952287 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -412,7 +412,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
}
Object *end_cap_ob = amd->end_cap;
if (end_cap_ob && end_cap_ob != ctx->object) {
- if (start_cap_ob->type == OB_MESH && ctx->object->type == OB_MESH) {
+ if (end_cap_ob->type == OB_MESH && ctx->object->type == OB_MESH) {
vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
}
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index cbad4ccd662..b6cceade4e2 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -111,6 +111,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = 0,
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 52773e6d3ef..915428f99da 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -244,6 +244,7 @@ static BMesh *BMD_mesh_bm_create(
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
+ bmesh_from_mesh_params.calc_vert_normal = true;
BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params);
if (UNLIKELY(*r_is_flip)) {
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 8434446a074..67515478be5 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -91,6 +91,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
DecimateModifierData *dmd = (DecimateModifierData *)md;
Mesh *mesh = meshData, *result = NULL;
BMesh *bm;
+ bool calc_vert_normal;
bool calc_face_normal;
float *vweights = NULL;
@@ -107,18 +108,21 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return mesh;
}
calc_face_normal = true;
+ calc_vert_normal = true;
break;
case MOD_DECIM_MODE_UNSUBDIV:
if (dmd->iter == 0) {
return mesh;
}
calc_face_normal = false;
+ calc_vert_normal = false;
break;
case MOD_DECIM_MODE_DISSOLVE:
if (dmd->angle == 0.0f) {
return mesh;
}
calc_face_normal = true;
+ calc_vert_normal = false;
break;
default:
return mesh;
@@ -160,6 +164,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = calc_face_normal,
+ .calc_vert_normal = calc_vert_normal,
.cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
.emask = CD_MASK_ORIGINDEX,
.pmask = CD_MASK_ORIGINDEX},
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 3570bdda5a9..14431e5ff2e 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -57,6 +57,7 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd)
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = calc_face_normals,
+ .calc_vert_normal = false,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = 0,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
index 14af22645e3..c30ab622842 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
@@ -60,11 +60,11 @@
static void initData(ModifierData *md)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mcmd, modifier));
- mcmd->cache_file = NULL;
+ mcmd->cache_file = nullptr;
mcmd->object_path[0] = '\0';
mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
@@ -80,13 +80,13 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
BKE_modifier_copydata_generic(md, target, flag);
- tmcmd->reader = NULL;
+ tmcmd->reader = nullptr;
tmcmd->reader_object_path[0] = '\0';
}
static void freeData(ModifierData *md)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
if (mcmd->reader) {
mcmd->reader_object_path[0] = '\0';
@@ -98,10 +98,10 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
ModifierData *md,
bool UNUSED(useRenderParams))
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
/* leave it up to the modifier to check the file is valid on calculation */
- return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
+ return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0');
}
static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
@@ -145,17 +145,17 @@ static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
/* Only used to check whether we are operating on org data or not... */
- Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL;
+ Mesh *me = (ctx->object->type == OB_MESH) ? static_cast<Mesh *>(ctx->object->data) : nullptr;
Mesh *org_mesh = mesh;
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
CacheFile *cache_file = mcmd->cache_file;
const float frame = DEG_get_ctime(ctx->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
- const char *err_str = NULL;
+ const char *err_str = nullptr;
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
@@ -196,7 +196,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
}
- if (me != NULL) {
+ if (me != nullptr) {
MVert *mvert = mesh->mvert;
MEdge *medge = mesh->medge;
MPoly *mpoly = mesh->mpoly;
@@ -205,15 +205,16 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* flags) and duplicate those too. */
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
- mesh = (Mesh *)BKE_id_copy_ex(NULL,
- &mesh->id,
- NULL,
- LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
- LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW);
+ mesh = reinterpret_cast<Mesh *>(
+ BKE_id_copy_ex(nullptr,
+ &mesh->id,
+ nullptr,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW));
}
}
- Mesh *result = NULL;
+ Mesh *result = nullptr;
switch (cache_file->type) {
case CACHEFILE_TYPE_ALEMBIC: {
@@ -250,8 +251,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
}
- if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
- BKE_id_free(NULL, mesh);
+ if (!ELEM(result, nullptr, mesh) && (mesh != org_mesh)) {
+ BKE_id_free(nullptr, mesh);
mesh = org_mesh;
}
@@ -265,9 +266,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode)
{
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
/* Do not evaluate animations if using the render engine procedural. */
- return (mcmd->cache_file != NULL) &&
+ return (mcmd->cache_file != nullptr) &&
!BKE_cache_file_uses_render_procedural(mcmd->cache_file, scene, dag_eval_mode);
#else
UNUSED_VARS(scene, md, dag_eval_mode);
@@ -277,16 +278,16 @@ static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mod
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
- walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER);
+ walk(userData, ob, reinterpret_cast<ID **>(&mcmd->cache_file), IDWALK_CB_USER);
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
- if (mcmd->cache_file != NULL) {
+ if (mcmd->cache_file != nullptr) {
DEG_add_object_cache_relation(
ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
}
@@ -307,12 +308,13 @@ static void panel_draw(const bContext *C, Panel *panel)
uiTemplateCacheFile(layout, C, ptr, "cache_file");
if (has_cache_file) {
- uiItemPointerR(layout, ptr, "object_path", &cache_file_ptr, "object_paths", NULL, ICON_NONE);
+ uiItemPointerR(
+ layout, ptr, "object_path", &cache_file_ptr, "object_paths", nullptr, ICON_NONE);
}
if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
- uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_vertex_interpolation", 0, nullptr, ICON_NONE);
}
modifier_panel_end(layout, ptr);
@@ -332,7 +334,7 @@ static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
uiTemplateCacheFileVelocity(layout, &fileptr);
- uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "velocity_scale", 0, nullptr, ICON_NONE);
}
static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -387,27 +389,27 @@ static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = modifier_panel_register(
region_type, eModifierType_MeshSequenceCache, panel_draw);
- modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
+ modifier_subpanel_register(region_type, "time", "Time", nullptr, time_panel_draw, panel_type);
modifier_subpanel_register(region_type,
"render_procedural",
"Render Procedural",
- NULL,
+ nullptr,
render_procedural_panel_draw,
panel_type);
modifier_subpanel_register(
- region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
+ region_type, "velocity", "Velocity", nullptr, velocity_panel_draw, panel_type);
modifier_subpanel_register(region_type,
"override_layers",
"Override Layers",
- NULL,
+ nullptr,
override_layers_panel_draw,
panel_type);
}
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
{
- MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
- msmcd->reader = NULL;
+ MeshSeqCacheModifierData *msmcd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
+ msmcd->reader = nullptr;
msmcd->reader_object_path[0] = '\0';
}
@@ -417,29 +419,30 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
/* structSize */ sizeof(MeshSeqCacheModifierData),
/* srna */ &RNA_MeshSequenceCacheModifier,
/* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs,
+ /* flags */
+ static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs),
/* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
/* copyData */ copyData,
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
/* modifyMesh */ modifyMesh,
- /* modifyGeometrySet */ NULL,
+ /* modifyGeometrySet */ nullptr,
/* initData */ initData,
- /* requiredDataMask */ NULL,
+ /* requiredDataMask */ nullptr,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
- /* dependsOnNormals */ NULL,
+ /* dependsOnNormals */ nullptr,
/* foreachIDLink */ foreachIDLink,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
+ /* blendWrite */ nullptr,
/* blendRead */ blendRead,
};
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 79dcdf48402..e560a859735 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -61,6 +61,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
&((struct BMeshCreateParams){0}),
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = false,
.cd_mask_extra = cd_mask_extra,
}));
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 6d95a169319..dae7d19844e 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -69,6 +69,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = 0,
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index d5d97f7be2e..3d3450d9252 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -143,8 +143,6 @@ void ntreeCompositExecTree(struct Scene *scene,
struct RenderData *rd,
int rendering,
int do_previews,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings,
const char *view_name);
/**
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 7522ad1efe6..0b75dd9cef3 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -206,14 +206,12 @@ void ntreeCompositExecTree(Scene *scene,
RenderData *rd,
int rendering,
int do_preview,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name)
{
#ifdef WITH_COMPOSITOR
- COM_execute(rd, scene, ntree, rendering, view_settings, display_settings, view_name);
+ COM_execute(rd, scene, ntree, rendering, view_name);
#else
- UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings, view_name);
+ UNUSED_VARS(scene, ntree, rd, rendering, view_name);
#endif
UNUSED_VARS(do_preview);
diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
index 28de1f48b79..1fd6e62b4c5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
@@ -303,7 +303,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
node_composit_buts_file_output(layout, C, ptr);
- uiTemplateImageSettings(layout, &imfptr, false);
+ uiTemplateImageSettings(layout, &imfptr, true);
/* disable stereo output for multilayer, too much work for something that no one will use */
/* if someone asks for that we can implement it */
@@ -422,12 +422,16 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
ICON_NONE);
}
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, use_node_format == false);
- uiTemplateImageSettings(col, &imfptr, false);
+ if (!use_node_format) {
+ const bool use_color_management = RNA_boolean_get(&active_input_ptr, "save_as_render");
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ col = uiLayoutColumn(layout, false);
+ uiTemplateImageSettings(col, &imfptr, use_color_management);
+
+ if (is_multiview) {
+ col = uiLayoutColumn(layout, false);
+ uiTemplateImageFormatViews(col, &imfptr, nullptr);
+ }
}
}
}
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
index 3718ce6f359..a4fc1a6bfd1 100644
--- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -15,11 +15,20 @@ namespace blender::nodes::node_fn_rotate_euler_cc {
static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
{
+ auto enable_axis_angle = [](bNode &node) {
+ node.custom1 = FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE;
+ };
+
b.is_function_node();
b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value();
- b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER);
- b.add_input<decl::Vector>(N_("Axis")).default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
- b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
+ b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER).make_available([](bNode &node) {
+ node.custom1 = FN_NODE_ROTATE_EULER_TYPE_EULER;
+ });
+ b.add_input<decl::Vector>(N_("Axis"))
+ .default_value({0.0, 0.0, 1.0})
+ .subtype(PROP_XYZ)
+ .make_available(enable_axis_angle);
+ b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE).make_available(enable_axis_angle);
b.add_output<decl::Vector>(N_("Rotation"));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
index 6c7d7ed375b..38d81c54933 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -17,6 +17,13 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveArc)
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto enable_points = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS;
+ };
+ auto enable_radius = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS;
+ };
+
b.add_input<decl::Int>(N_("Resolution"))
.default_value(16)
.min(2)
@@ -26,34 +33,41 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Start"))
.default_value({-1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the first control point"));
+ .description(N_("Position of the first control point"))
+ .make_available(enable_points);
b.add_input<decl::Vector>(N_("Middle"))
.default_value({0.0f, 2.0f, 0.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the middle control point"));
+ .description(N_("Position of the middle control point"))
+ .make_available(enable_points);
b.add_input<decl::Vector>(N_("End"))
.default_value({1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the last control point"));
+ .description(N_("Position of the last control point"))
+ .make_available(enable_points);
b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description(N_("Distance of the points from the origin"));
+ .description(N_("Distance of the points from the origin"))
+ .make_available(enable_radius);
b.add_input<decl::Float>(N_("Start Angle"))
.default_value(0.0f)
.subtype(PROP_ANGLE)
- .description(N_("Starting angle of the arc"));
+ .description(N_("Starting angle of the arc"))
+ .make_available(enable_radius);
b.add_input<decl::Float>(N_("Sweep Angle"))
.default_value(1.75f * M_PI)
.min(-2 * M_PI)
.max(2 * M_PI)
.subtype(PROP_ANGLE)
- .description(N_("Length of the arc"));
+ .description(N_("Length of the arc"))
+ .make_available(enable_radius);
b.add_input<decl::Float>(N_("Offset Angle"))
.default_value(0.0f)
.subtype(PROP_ANGLE)
- .description(N_("Offset angle of the arc"));
+ .description(N_("Offset angle of the arc"))
+ .make_available(enable_points);
b.add_input<decl::Bool>(N_("Connect Center"))
.default_value(false)
.description(N_("Connect the arc at the center"));
@@ -64,17 +78,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
b.add_output<decl::Vector>(N_("Center"))
.description(N_("The center of the circle described by the three points"))
- .make_available(
- [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ .make_available(enable_points);
b.add_output<decl::Vector>(N_("Normal"))
.description(N_("The normal direction of the plane described by the three points, pointing "
"towards the positive Z axis"))
- .make_available(
- [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ .make_available(enable_points);
b.add_output<decl::Float>(N_("Radius"))
.description(N_("The radius of the circle described by the three points"))
- .make_available(
- [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ .make_available(enable_points);
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 2fb9f724130..aa4b3a785f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -13,6 +13,13 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle)
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto endable_points = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
+ };
+ auto enable_radius = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS;
+ };
+
b.add_input<decl::Int>(N_("Resolution"))
.default_value(32)
.min(3)
@@ -23,28 +30,30 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_TRANSLATION)
.description(
N_("One of the three points on the circle. The point order determines the circle's "
- "direction"));
+ "direction"))
+ .make_available(endable_points);
b.add_input<decl::Vector>(N_("Point 2"))
.default_value({0.0f, 1.0f, 0.0f})
.subtype(PROP_TRANSLATION)
.description(
N_("One of the three points on the circle. The point order determines the circle's "
- "direction"));
+ "direction"))
+ .make_available(endable_points);
b.add_input<decl::Vector>(N_("Point 3"))
.default_value({1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION)
.description(
N_("One of the three points on the circle. The point order determines the circle's "
- "direction"));
+ "direction"))
+ .make_available(endable_points);
b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description(N_("Distance of the points from the origin"));
+ .description(N_("Distance of the points from the origin"))
+ .make_available(enable_radius);
b.add_output<decl::Geometry>(N_("Curve"));
- b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) {
- node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
- });
+ b.add_output<decl::Vector>(N_("Center")).make_available(endable_points);
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 2e2f4254752..62dbcc91cc6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -13,21 +13,29 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine)
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto enable_direction = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION;
+ };
+
b.add_input<decl::Vector>(N_("Start"))
.subtype(PROP_TRANSLATION)
.description(N_("Position of the first control point"));
b.add_input<decl::Vector>(N_("End"))
.default_value({0.0f, 0.0f, 1.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the second control point"));
+ .description(N_("Position of the second control point"))
+ .make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
+ });
b.add_input<decl::Vector>(N_("Direction"))
.default_value({0.0f, 0.0f, 1.0f})
- .description(
- N_("Direction the line is going in. The length of this vector does not matter"));
+ .description(N_("Direction the line is going in. The length of this vector does not matter"))
+ .make_available(enable_direction);
b.add_input<decl::Float>(N_("Length"))
.default_value(1.0f)
.subtype(PROP_DISTANCE)
- .description(N_("Distance between the two points"));
+ .description(N_("Distance between the two points"))
+ .make_available(enable_direction);
b.add_output<decl::Geometry>(N_("Curve"));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index 8e28a4ba9b9..d9f29d1ef1c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -26,17 +26,35 @@ namespace blender::nodes::node_geo_distribute_points_on_faces_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto enable_random = [](bNode &node) {
+ node.custom1 = GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM;
+ };
+ auto enable_poisson = [](bNode &node) {
+ node.custom1 = GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON;
+ };
+
b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
- b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f);
- b.add_input<decl::Float>(N_("Density")).default_value(10.0f).min(0.0f).supports_field();
+ b.add_input<decl::Float>(N_("Distance Min"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .make_available(enable_poisson);
+ b.add_input<decl::Float>(N_("Density Max"))
+ .default_value(10.0f)
+ .min(0.0f)
+ .make_available(enable_poisson);
+ b.add_input<decl::Float>(N_("Density"))
+ .default_value(10.0f)
+ .min(0.0f)
+ .supports_field()
+ .make_available(enable_random);
b.add_input<decl::Float>(N_("Density Factor"))
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
- .supports_field();
+ .supports_field()
+ .make_available(enable_poisson);
b.add_input<decl::Int>(N_("Seed"));
b.add_output<decl::Geometry>(N_("Points"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
index f9d9ed75f30..7923ad6264d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -31,7 +31,8 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Axis"))
.default_value({1.0f, 0.0f, 0.0f})
.supports_field()
- .description(N_("Direction in which to scale the element"));
+ .description(N_("Direction in which to scale the element"))
+ .make_available([](bNode &node) { node.custom2 = GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS; });
b.add_output<decl::Geometry>(N_("Geometry"));
};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index 301410f5126..271dd824d27 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -106,10 +106,12 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
for (const int i : bezier.positions().index_range()) {
if (current_mask < selection.size() && selection[current_mask] == current_point) {
if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
- bezier.set_handle_position_left(i, positions_input[i] + offsets_input[i]);
+ bezier.set_handle_position_left(
+ i, positions_input[current_point] + offsets_input[current_point]);
}
else {
- bezier.set_handle_position_right(i, positions_input[i] + offsets_input[i]);
+ bezier.set_handle_position_right(
+ i, positions_input[current_point] + offsets_input[current_point]);
}
current_mask++;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index 543e57d38ad..0892e068ce2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -16,8 +16,11 @@ static void set_id_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<int> &id_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const AttributeDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
+ ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
+ GeometryComponentFieldContext field_context{component, domain};
+ const int domain_size = component.attribute_domain_size(domain);
if (domain_size == 0) {
return;
}
@@ -30,7 +33,7 @@ static void set_id_in_component(GeometryComponent &component,
* the field. However, as an optimization, use a faster code path when it already exists. */
if (component.attribute_exists("id")) {
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
- "id", ATTR_DOMAIN_POINT);
+ "id", domain);
evaluator.add_with_destination(id_field, id_attribute.varray());
evaluator.evaluate();
id_attribute.save();
@@ -41,7 +44,7 @@ static void set_id_in_component(GeometryComponent &component,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const VArray<int> &result_ids = evaluator.get_evaluated<int>(0);
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
- "id", ATTR_DOMAIN_POINT);
+ "id", domain);
result_ids.materialize(selection, id_attribute.as_span());
id_attribute.save();
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 5ded8413cf9..76cdbfb140f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -44,7 +44,13 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh,
CustomData_MeshMasks cd_mask_extra = {
CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX};
BMeshCreateParams create_params{0};
- BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra};
+ BMeshFromMeshParams from_mesh_params{};
+ from_mesh_params.calc_face_normal = true;
+ from_mesh_params.calc_vert_normal = true;
+ from_mesh_params.add_key_index = true;
+ from_mesh_params.use_shapekey = true;
+ from_mesh_params.active_shapekey = 1;
+ from_mesh_params.cd_mask_extra = cd_mask_extra;
BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
/* Tag faces to be triangulated from the selection mask. */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
index d4a0c092acd..a5ab6db0002 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
@@ -10,6 +10,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
namespace blender::nodes::node_shader_tex_sky_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -229,6 +231,24 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
+ }
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Vector"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeTexSky");
+ NodeTexSky *tex = (NodeTexSky *)node.storage;
+ tex->sun_disc = false;
+ params.update_and_connect_available_socket(node, "Vector");
+ });
+ }
+}
+
} // namespace blender::nodes::node_shader_tex_sky_cc
/* node type definition */
@@ -247,6 +267,7 @@ void register_node_type_sh_tex_sky()
node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky);
/* Remove vector input for Nishita sky model. */
node_type_update(&ntype, file_ns::node_shader_update_sky);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index 3f1a9d758ae..a041492fb13 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -17,9 +17,15 @@ static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
b.add_input<decl::Vector>(N_("Center"));
- b.add_input<decl::Vector>(N_("Axis")).min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Axis"))
+ .min(-1.0f)
+ .max(1.0f)
+ .default_value({0.0f, 0.0f, 1.0f})
+ .make_available([](bNode &node) { node.custom1 = NODE_VECTOR_ROTATE_TYPE_AXIS; });
b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
- b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).make_available([](bNode &node) {
+ node.custom1 = NODE_VECTOR_ROTATE_TYPE_EULER_XYZ;
+ });
b.add_output<decl::Vector>(N_("Vector"));
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index ccd483083ef..9ceff9b84b6 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1050,7 +1050,8 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
}
PyDoc_STRVAR(bpy_bmesh_from_object_doc,
- ".. method:: from_object(object, depsgraph, cage=False, face_normals=True)\n"
+ ".. method:: from_object(object, depsgraph, cage=False, face_normals=True, "
+ "vertex_normals=True)\n"
"\n"
" Initialize this bmesh from existing object data-block (only meshes are currently "
"supported).\n"
@@ -1060,10 +1061,12 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc,
" :arg cage: Get the mesh as a deformed cage.\n"
" :type cage: boolean\n"
" :arg face_normals: Calculate face normals.\n"
+ " :arg vertex_normals: Calculate vertex normals.\n"
" :type face_normals: boolean\n");
static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"object", "depsgraph", "cage", "face_normals", NULL};
+ static const char *kwlist[] = {
+ "object", "depsgraph", "cage", "face_normals", "vertex_normals", NULL};
PyObject *py_object;
PyObject *py_depsgraph;
Object *ob, *ob_eval;
@@ -1073,6 +1076,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
BMesh *bm;
bool use_cage = false;
bool use_fnorm = true;
+ bool use_vert_normal = true;
const CustomData_MeshMasks data_masks = CD_MASK_BMESH;
BPY_BM_CHECK_OBJ(self);
@@ -1086,7 +1090,9 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
PyC_ParseBool,
&use_cage,
PyC_ParseBool,
- &use_fnorm) ||
+ &use_fnorm,
+ PyC_ParseBool,
+ &use_vert_normal) ||
!(ob = PyC_RNA_AsPointer(py_object, "Object")) ||
!(depsgraph = PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))) {
return NULL;
@@ -1137,6 +1143,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
me_eval,
(&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm,
+ .calc_vert_normal = use_vert_normal,
}));
if (need_free) {
@@ -1148,7 +1155,8 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
PyDoc_STRVAR(
bpy_bmesh_from_mesh_doc,
- ".. method:: from_mesh(mesh, face_normals=True, use_shape_key=False, shape_key_index=0)\n"
+ ".. method:: from_mesh(mesh, face_normals=True, vertex_normals=True, use_shape_key=False, "
+ "shape_key_index=0)\n"
"\n"
" Initialize this bmesh from existing mesh datablock.\n"
"\n"
@@ -1168,11 +1176,13 @@ PyDoc_STRVAR(
"mesh won't be added.\n");
static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"mesh", "face_normals", "use_shape_key", "shape_key_index", NULL};
+ static const char *kwlist[] = {
+ "mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", NULL};
BMesh *bm;
PyObject *py_mesh;
Mesh *me;
bool use_fnorm = true;
+ bool use_vert_normal = true;
bool use_shape_key = false;
int shape_key_index = 0;
@@ -1186,6 +1196,8 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
PyC_ParseBool,
&use_fnorm,
PyC_ParseBool,
+ &use_vert_normal,
+ PyC_ParseBool,
&use_shape_key,
&shape_key_index) ||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh"))) {
@@ -1198,6 +1210,7 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm,
+ .calc_vert_normal = use_vert_normal,
.use_shapekey = use_shape_key,
.active_shapekey = shape_key_index + 1,
}));
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 6c58e2e3a30..6f278c1c771 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -36,6 +36,11 @@
#include "../generic/py_capi_rna.h"
#include "../generic/py_capi_utils.h"
+/* Disabled duplicating strings because the array can still be freed and
+ * the strings from it referenced, for now we can't support dynamically
+ * created strings from Python. */
+// #define USE_ENUM_COPY_STRINGS
+
/* -------------------------------------------------------------------- */
/** \name Shared Enums & Doc-Strings
* \{ */
@@ -1855,7 +1860,7 @@ static bool py_long_as_int(PyObject *py_long, int *r_int)
return false;
}
-#if 0
+#ifdef USE_ENUM_COPY_STRINGS
/* copies orig to buf, then sets orig to buf, returns copy length */
static size_t strswapbufcpy(char *buf, const char **orig)
{
@@ -1898,6 +1903,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
const Py_ssize_t seq_len = PySequence_Fast_GET_SIZE(seq_fast);
PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
int i;
+#ifdef USE_ENUM_COPY_STRINGS
+ Py_ssize_t totbuf = 0;
+#endif
short default_used = 0;
const char *default_str_cmp = NULL;
int default_int_cmp = 0;
@@ -1986,6 +1994,11 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
}
items[i] = tmp;
+
+#ifdef USE_ENUM_COPY_STRINGS
+ /* Calculate combine string length. */
+ totbuf += id_str_size + name_str_size + desc_str_size + 3; /* 3 is for '\0's */
+#endif
}
else if (item == Py_None) {
/* Only set since the rest is cleared. */
@@ -2030,13 +2043,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
}
}
- /* disabled duplicating strings because the array can still be freed and
- * the strings from it referenced, for now we can't support dynamically
- * created strings from python. */
-#if 0
- /* this would all work perfectly _but_ the python strings may be freed
- * immediately after use, so we need to duplicate them, ugh.
- * annoying because it works most of the time without this. */
+#ifdef USE_ENUM_COPY_STRINGS
+ /* This would all work perfectly _but_ the python strings may be freed immediately after use,
+ * so we need to duplicate them, ugh. annoying because it works most of the time without this. */
{
EnumPropertyItem *items_dup = MEM_mallocN((sizeof(EnumPropertyItem) * (seq_len + 1)) +
(sizeof(char) * totbuf),
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index cac320ad246..0a8668221ad 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -338,8 +338,8 @@ void RE_RenderFrame(struct Render *re,
struct Scene *scene,
struct ViewLayer *single_layer,
struct Object *camera_override,
- const int frame,
- const float subframe,
+ int frame,
+ float subframe,
bool write_still);
/**
* A version of #RE_RenderFrame that saves images to disk.
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
index d297ca19404..85bd06b9940 100644
--- a/source/blender/render/RE_texture_margin.h
+++ b/source/blender/render/RE_texture_margin.h
@@ -23,7 +23,7 @@ struct Mesh;
* \param mask: pixels with a mask value of 1 are not written to.
* \param margin: the size of the margin in pixels.
* \param me: the mesh to use the polygons of.
- * \param mloopuv: the uv data to use.
+ * \param uv_layer: The UV layer to use.
*/
void RE_generate_texturemargin_adjacentfaces(
struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer);
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 0ca2ca82cf7..a6c2e9eb194 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -1212,14 +1212,8 @@ static void do_render_compositor(Render *re)
RenderView *rv;
for (rv = re->result->views.first; rv; rv = rv->next) {
- ntreeCompositExecTree(re->pipeline_scene_eval,
- ntree,
- &re->r,
- true,
- G.background == 0,
- &re->scene->view_settings,
- &re->scene->display_settings,
- rv->name);
+ ntreeCompositExecTree(
+ re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name);
}
ntree->stats_draw = NULL;
@@ -1960,17 +1954,19 @@ bool RE_WriteRenderViewsMovie(ReportList *reports,
return false;
}
+ ImageFormatData image_format;
+ BKE_image_format_init_for_write(&image_format, scene, NULL);
+
const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
const float dither = scene->r.dither_intensity;
- if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
int view_id;
for (view_id = 0; view_id < totvideos; view_id++) {
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
- IMB_colormanagement_imbuf_for_write(
- ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format);
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
ok &= mh->append_movie(movie_ctx_arr[view_id],
rd,
@@ -1992,21 +1988,16 @@ bool RE_WriteRenderViewsMovie(ReportList *reports,
ImBuf *ibuf_arr[3] = {NULL};
int i;
- BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D));
+ BLI_assert((totvideos == 1) && (image_format.views_format == R_IMF_VIEWS_STEREO_3D));
for (i = 0; i < 2; i++) {
int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
- IMB_colormanagement_imbuf_for_write(ibuf_arr[i],
- true,
- false,
- &scene->view_settings,
- &scene->display_settings,
- &scene->r.im_format);
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
}
- ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
ok = mh->append_movie(movie_ctx_arr[0],
rd,
@@ -2024,6 +2015,8 @@ bool RE_WriteRenderViewsMovie(ReportList *reports,
}
}
+ BKE_image_format_free(&image_format);
+
return ok;
}
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index 2fe6e6d3caa..ea7fa961f0d 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -414,6 +414,11 @@ RenderResult *render_result_new(Render *re,
rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
+ /* Preview does not support deferred render result allocation. */
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ render_result_passes_allocated_ensure(rr);
+ }
+
return rr;
}
@@ -988,7 +993,7 @@ void render_result_exr_file_cache_write(Render *re)
render_result_exr_file_cache_path(re->scene, root, str);
printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str);
- BKE_image_render_write_exr(NULL, rr, str, NULL, NULL, -1);
+ BKE_image_render_write_exr(NULL, rr, str, NULL, true, NULL, -1);
}
bool render_result_exr_file_cache_read(Render *re)
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 8849b029d46..ddf75f3d664 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -298,7 +298,7 @@ static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
}
if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
CLOG_WARN(&LOG,
- "Strip overlaps with itself or another strip, that is to be shuffled."
+ "Strip overlaps with itself or another strip, that is to be shuffled. "
"This should never happen.");
continue;
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 46f7b67c2ba..3c8474b1b6c 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -1037,6 +1037,10 @@ void wm_draw_update(bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
GPU_context_main_lock();
+
+ GPU_render_begin();
+ GPU_render_step();
+
BKE_image_free_unused_gpu_textures();
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -1075,6 +1079,7 @@ void wm_draw_update(bContext *C)
/* Draw non-windows (surfaces) */
wm_surfaces_iter(C, wm_draw_surface);
+ GPU_render_end();
GPU_context_main_unlock();
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 6b7d3045da2..790b08437bd 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -4428,6 +4428,9 @@ void WM_event_add_mousemove(wmWindow *win)
/** \name Ghost Event Conversion
* \{ */
+/**
+ * \return The WM enum for key or #EVENT_NONE (which should be ignored).
+ */
static int convert_key(GHOST_TKey key)
{
if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) {
@@ -4451,7 +4454,7 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyLinefeed:
return EVT_LINEFEEDKEY;
case GHOST_kKeyClear:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyEnter:
return EVT_RETKEY;
@@ -4506,9 +4509,9 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyCapsLock:
return EVT_CAPSLOCKKEY;
case GHOST_kKeyNumLock:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyScrollLock:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyLeftArrow:
return EVT_LEFTARROWKEY;
@@ -4520,7 +4523,7 @@ static int convert_key(GHOST_TKey key)
return EVT_DOWNARROWKEY;
case GHOST_kKeyPrintScreen:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyPause:
return EVT_PAUSEKEY;
@@ -4562,9 +4565,28 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyMediaLast:
return EVT_MEDIALAST;
- default:
- return EVT_UNKNOWNKEY; /* #GHOST_kKeyUnknown (this could be asserted). */
+ case GHOST_kKeyUnknown:
+ return EVT_UNKNOWNKEY;
+
+#if defined(__GNUC__) || defined(__clang__)
+ /* Ensure all members of this enum are handled, otherwise generate a compiler warning.
+ * Note that these members have been handled, these ranges are to satisfy the compiler. */
+ case GHOST_kKeyF1 ... GHOST_kKeyF24:
+ case GHOST_kKeyA ... GHOST_kKeyZ:
+ case GHOST_kKeyNumpad0 ... GHOST_kKeyNumpad9:
+ case GHOST_kKey0 ... GHOST_kKey9: {
+ BLI_assert_unreachable();
+ break;
+ }
+#else
+ default: {
+ break;
+ }
+#endif
}
+
+ CLOG_WARN(WM_LOG_EVENTS, "unknown event type %d from ghost", (int)key);
+ return EVENT_NONE;
}
static void wm_eventemulation(wmEvent *event, bool test_only)
@@ -5087,6 +5109,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd = customdata;
event.type = convert_key(kd->key);
+ if (UNLIKELY(event.type == EVENT_NONE)) {
+ break;
+ }
+
event.ascii = kd->ascii;
/* Might be not NULL terminated. */
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));