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:
-rw-r--r--release/datafiles/userdef/userdef_default.c2
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py2
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py24
-rw-r--r--release/scripts/startup/bl_ui/space_statusbar.py19
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py17
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/intern/image.c2
-rw-r--r--source/blender/blenlib/BLI_math_geom.h7
-rw-r--r--source/blender/blenlib/intern/math_geom.c31
-rw-r--r--source/blender/blenlib/intern/timecode.c4
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c4
-rw-r--r--source/blender/blenloader/intern/writefile.c4
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c1
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c21
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h3
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c5
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl4
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/include/ED_info.h6
-rw-r--r--source/blender/editors/interface/interface_icons.c4
-rw-r--r--source/blender/editors/mask/mask_ops.c6
-rw-r--r--source/blender/editors/screen/screen_ops.c31
-rw-r--r--source/blender/editors/space_clip/clip_ops.c2
-rw-r--r--source/blender/editors/space_info/info_stats.c242
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c6
-rw-r--r--source/blender/editors/undo/ed_undo.c8
-rw-r--r--source/blender/functions/FN_multi_function_network.hh2
-rw-r--r--source/blender/functions/intern/multi_function_network.cc8
-rw-r--r--source/blender/gpu/GPU_matrix.h12
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c2
-rw-r--r--source/blender/gpu/intern/gpu_matrix.c14
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl1
-rw-r--r--source/blender/imbuf/IMB_imbuf.h12
-rw-r--r--source/blender/imbuf/intern/IMB_indexer.h6
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp10
-rw-r--r--source/blender/io/usd/intern/usd_hierarchy_iterator.cc2
-rw-r--r--source/blender/makesdna/DNA_layer_types.h1
-rw-r--r--source/blender/makesdna/DNA_screen_types.h2
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h20
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c22
-rw-r--r--source/blender/makesrna/intern/rna_screen.c19
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c36
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc2
-rw-r--r--source/blender/python/intern/bpy_interface.c6
-rw-r--r--source/blender/python/intern/bpy_rna.c4
-rw-r--r--source/blender/python/intern/bpy_traceback.c4
-rw-r--r--source/blender/simulation/CMakeLists.txt5
-rw-r--r--source/blender/simulation/intern/particle_allocator.cc77
-rw-r--r--source/blender/simulation/intern/particle_allocator.hh95
-rw-r--r--source/blender/simulation/intern/particle_function.cc15
-rw-r--r--source/blender/simulation/intern/particle_function.hh (renamed from source/blender/simulation/SIM_particle_function.hh)7
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.cc183
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.hh20
-rw-r--r--source/blender/simulation/intern/simulation_solver.cc202
-rw-r--r--source/blender/simulation/intern/simulation_solver.hh119
-rw-r--r--source/blender/simulation/intern/simulation_update.cc37
-rw-r--r--source/blender/simulation/intern/time_interval.hh57
64 files changed, 1162 insertions, 315 deletions
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index 31d0eb8e923..fbdb226ab6d 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -229,6 +229,8 @@ const UserDef U_default = {
.collection_instance_empty_size = 1.0f,
+ .statusbar_flag = STATUSBAR_SHOW_VERSION,
+
.runtime =
{
.is_dirty = 0,
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 87802c90068..7a0350510b7 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -3176,7 +3176,7 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("gpencil.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
# Snap
- op_menu("GPENCIL_MT_snap", {"type": 'S', "value": 'PRESS', "shift": True}),
+ op_menu_pie("GPENCIL_MT_snap_pie", {"type": 'S', "value": 'PRESS', "shift": True}),
# Show/hide
("gpencil.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
("gpencil.hide", {"type": 'H', "value": 'PRESS'},
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index f275d892abe..eedf07935c8 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -2316,7 +2316,7 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("gpencil.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
# Snap
- op_menu("GPENCIL_MT_snap", {"type": 'X', "value": 'PRESS', "shift": True}),
+ op_menu_pie("GPENCIL_MT_snap_pie", {"type": 'X', "value": 'PRESS', "shift": True}),
# Show/hide
("gpencil.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
("gpencil.hide", {"type": 'H', "value": 'PRESS', "ctrl": True},
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 07c9fc363b5..55b6f76632f 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -279,6 +279,29 @@ class GPENCIL_MT_snap(Menu):
layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
+class GPENCIL_MT_snap_pie(Menu):
+ bl_label = "Snap"
+
+ def draw(self, _context):
+ layout = self.layout
+ pie = layout.menu_pie()
+
+ pie.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid", icon='CURSOR')
+ pie.operator("gpencil.snap_to_grid", text="Selection to Grid", icon='RESTRICT_SELECT_OFF')
+ pie.operator("gpencil.snap_cursor_to_selected", text="Cursor to Selected", icon='CURSOR')
+ pie.operator(
+ "gpencil.snap_to_cursor",
+ text="Selection to Cursor",
+ icon='RESTRICT_SELECT_OFF'
+ ).use_offset = False
+ pie.operator(
+ "gpencil.snap_to_cursor",
+ text="Selection to Cursor (Keep Offset)",
+ icon='RESTRICT_SELECT_OFF'
+ ).use_offset = True
+ pie.operator("view3d.snap_cursor_to_center", text="Cursor to World Origin", icon='CURSOR')
+
+
class GPENCIL_MT_move_to_layer(Menu):
bl_label = "Move to Layer"
@@ -901,6 +924,7 @@ class GreasePencilFlipTintColors(Operator):
classes = (
GPENCIL_MT_snap,
+ GPENCIL_MT_snap_pie,
GPENCIL_MT_cleanup,
GPENCIL_MT_move_to_layer,
GPENCIL_MT_layer_active,
diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py
index 4984372eed3..cbf72a7bc59 100644
--- a/release/scripts/startup/bl_ui/space_statusbar.py
+++ b/release/scripts/startup/bl_ui/space_statusbar.py
@@ -31,17 +31,20 @@ class STATUSBAR_HT_header(Header):
layout.separator_spacer()
- # messages
- layout.template_reports_banner()
- layout.template_running_jobs()
-
+ # Nothing in the center.
layout.separator_spacer()
- # stats
- scene = context.scene
- view_layer = context.view_layer
+ row = layout.row()
+ row.alignment = 'RIGHT'
+
+ # Stats & Info
+ row.label(text=context.screen.statusbar_info(), translate=False)
+
+ # Messages
+ row.template_reports_banner()
- layout.label(text=scene.statistics(view_layer), translate=False)
+ # Progress Bar
+ row.template_running_jobs()
classes = (
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 66c98b81e0e..03f85578b6e 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -283,6 +283,22 @@ class USERPREF_PT_interface_temporary_windows(InterfacePanel, CenterAlignMixIn,
col.prop(view, "filebrowser_display_type", text="File Browser")
+class USERPREF_PT_interface_statusbar(InterfacePanel, CenterAlignMixIn, Panel):
+ bl_label = "Status Bar"
+ bl_parent_id = "USERPREF_PT_interface_editors"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_centered(self, context, layout):
+ prefs = context.preferences
+ view = prefs.view
+
+ col = layout.column(heading="Show")
+ col.prop(view, "show_statusbar_stats", text="Scene Statistics")
+ col.prop(view, "show_statusbar_memory", text="System Memory")
+ col.prop(view, "show_statusbar_vram", text="Video Memory")
+ col.prop(view, "show_statusbar_version", text="Blender Version")
+
+
class USERPREF_PT_interface_menus(InterfacePanel, Panel):
bl_label = "Menus"
bl_options = {'DEFAULT_CLOSED'}
@@ -2189,6 +2205,7 @@ classes = (
USERPREF_PT_interface_display,
USERPREF_PT_interface_editors,
USERPREF_PT_interface_temporary_windows,
+ USERPREF_PT_interface_statusbar,
USERPREF_PT_interface_translation,
USERPREF_PT_interface_text,
USERPREF_PT_interface_menus,
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 749e92bdcf7..077b53559aa 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -7034,7 +7034,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.separator()
col.menu("VIEW3D_MT_mirror", text="Mirror Points")
- col.menu("VIEW3D_MT_snap", text="Snap Points")
+ col.menu("GPENCIL_MT_snap", text="Snap Points")
col.separator()
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 57f22a8d709..556c1c961dc 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -40,7 +40,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 6
+#define BLENDER_FILE_SUBVERSION 7
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index a246265c3f2..9365ee040c2 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -64,7 +64,7 @@
#include "BLI_mempool.h"
#include "BLI_system.h"
#include "BLI_threads.h"
-#include "BLI_timecode.h" /* for stamp timecode format */
+#include "BLI_timecode.h" /* For stamp time-code format. */
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index f51486c5e7b..64b0dcccda1 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -671,6 +671,13 @@ void projmat_dimensions(const float projmat[4][4],
float *r_top,
float *r_near,
float *r_far);
+void projmat_dimensions_db(const float projmat[4][4],
+ double *r_left,
+ double *r_right,
+ double *r_bottom,
+ double *r_top,
+ double *r_near,
+ double *r_far);
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index d3dc4729617..2891279bb63 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -4880,6 +4880,37 @@ void projmat_dimensions(const float projmat[4][4],
}
}
+void projmat_dimensions_db(const float projmat_fl[4][4],
+ double *r_left,
+ double *r_right,
+ double *r_bottom,
+ double *r_top,
+ double *r_near,
+ double *r_far)
+{
+ double projmat[4][4];
+ copy_m4d_m4(projmat, projmat_fl);
+
+ bool is_persp = projmat[3][3] == 0.0f;
+
+ if (is_persp) {
+ *r_left = (projmat[2][0] - 1.0) / projmat[0][0];
+ *r_right = (projmat[2][0] + 1.0) / projmat[0][0];
+ *r_bottom = (projmat[2][1] - 1.0) / projmat[1][1];
+ *r_top = (projmat[2][1] + 1.0) / projmat[1][1];
+ *r_near = projmat[3][2] / (projmat[2][2] - 1.0);
+ *r_far = projmat[3][2] / (projmat[2][2] + 1.0);
+ }
+ else {
+ *r_left = (-projmat[3][0] - 1.0) / projmat[0][0];
+ *r_right = (-projmat[3][0] + 1.0) / projmat[0][0];
+ *r_bottom = (-projmat[3][1] - 1.0) / projmat[1][1];
+ *r_top = (-projmat[3][1] + 1.0) / projmat[1][1];
+ *r_near = (projmat[3][2] + 1.0) / projmat[2][2];
+ *r_far = (projmat[3][2] - 1.0) / projmat[2][2];
+ }
+}
+
/**
* Creates a projection matrix for a small region of the viewport.
*
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 510b9651961..9586da941a4 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -36,7 +36,7 @@
#include "BLI_strict_flags.h"
/**
- * Generate timecode/frame number string and store in \a str
+ * Generate time-code/frame number string and store in \a str
*
* \param str: destination string
* \param maxncpy: maximum number of characters to copy ``sizeof(str)``
@@ -44,7 +44,7 @@
* used to specify how detailed we need to be
* \param time_seconds: time total time in seconds
* \param fps: frames per second, typically from the #FPS macro
- * \param timecode_style: enum from eTimecodeStyles
+ * \param timecode_style: enum from #eTimecodeStyles
* \return length of \a str
*/
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index ce472a97337..8c00c20c822 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -579,7 +579,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 109) {
- /* new variable: gridlines */
+ /* New variable: `gridlines`. */
bScreen *screen = bmain->screens.first;
while (screen) {
ScrArea *area = screen->areabase.first;
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 1b0e41ec54a..50e3b375166 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -753,6 +753,10 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
userdef->transopts &= ~USER_DOTRANSLATE_DEPRECATED;
}
+ if (!USER_VERSION_ATLEAST(290, 7)) {
+ userdef->statusbar_flag = STATUSBAR_SHOW_VERSION;
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 3a8f6075621..988bc2b97ac 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -3857,6 +3857,10 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const
layers,
CD_MASK_ALL);
+ if (layers != NULL && layers != layers_buff) {
+ MEM_freeN(layers);
+ }
+
write_pointcaches(writer, &particle_state->ptcaches);
break;
}
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index daf83e11e17..0144fac76ab 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -178,6 +178,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS)
{
format = formats->instance_bone;
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index f096c9657c7..d4169014385 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -199,6 +199,9 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+
+ /* Buffer access for drawing isolated points, matching `extra_lines`. */
+ cb->extra_points = BUF_POINT(grp, formats->point_extra);
}
{
format = formats->pos;
@@ -230,6 +233,11 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
}
}
+void OVERLAY_extra_point(OVERLAY_ExtraCallBuffers *cb, const float point[3], const float color[4])
+{
+ DRW_buffer_add_entry(cb->extra_points, point, color);
+}
+
void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
const float start[3],
const float end[3],
@@ -1276,6 +1284,19 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
OVERLAY_extra_line_dashed(cb, parent_pos, ob->obmat[3], relation_color);
}
+ /* Drawing the hook lines. */
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+ float center[3];
+ mul_v3_m4v3(center, ob->obmat, hmd->cent);
+ if (hmd->object) {
+ OVERLAY_extra_line_dashed(cb, hmd->object->obmat[3], center, relation_color);
+ }
+ OVERLAY_extra_point(cb, center, relation_color);
+ }
+ }
+
if (ob->rigidbody_constraint) {
Object *rbc_ob1 = ob->rigidbody_constraint->ob1;
Object *rbc_ob2 = ob->rigidbody_constraint->ob2;
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 465a14a57d7..21d92112d53 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -150,6 +150,7 @@ typedef struct OVERLAY_ExtraCallBuffers {
DRWCallBuffer *extra_dashed_lines;
DRWCallBuffer *extra_lines;
+ DRWCallBuffer *extra_points;
DRWCallBuffer *field_curve;
DRWCallBuffer *field_force;
@@ -391,6 +392,7 @@ typedef struct OVERLAY_InstanceFormats {
struct GPUVertFormat *pos;
struct GPUVertFormat *pos_color;
struct GPUVertFormat *wire_extra;
+ struct GPUVertFormat *point_extra;
} OVERLAY_InstanceFormats;
/* Pack data into the last row of the 4x4 matrix. It will be decoded by the vertex shader. */
@@ -484,6 +486,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob);
OVERLAY_ExtraCallBuffers *OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_extra_point(OVERLAY_ExtraCallBuffers *cb, const float point[3], const float color[4]);
void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
const float start[3],
const float end[3],
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index 87f4642809b..e3cb052890b 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -1476,6 +1476,11 @@ OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void)
{"pos", DRW_ATTR_FLOAT, 3},
{"colorid", DRW_ATTR_INT, 1},
});
+ DRW_shgroup_instance_format(g_formats.point_extra,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ {"colorid", DRW_ATTR_INT, 1},
+ });
DRW_shgroup_instance_format(g_formats.instance_bone,
{
{"inst_obmat", DRW_ATTR_FLOAT, 16},
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
index 265d19f336f..c529f23265b 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -48,7 +48,7 @@ float workbench_float_pair_encode(float v1, float v2)
{
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
- /* Same as above because some compiler are dumb af. and think we use mediump int. */
+ /* Same as above because some compiler are very dumb and think we use medium int. */
const int v1_mask = 0x1F;
const int v2_mask = 0x7;
int iv1 = int(v1 * float(v1_mask));
@@ -60,7 +60,7 @@ void workbench_float_pair_decode(float data, out float v1, out float v2)
{
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
- /* Same as above because some compiler are dumb af. and think we use mediump int. */
+ /* Same as above because some compiler are very dumb and think we use medium int. */
const int v1_mask = 0x1F;
const int v2_mask = 0x7;
int idata = int(data);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 3e428eaffc2..91a8ea0fa3a 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -4085,7 +4085,7 @@ static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
void CURVE_OT_normals_make_consistent(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Recalc Normals";
+ ot->name = "Recalculate Handles";
ot->description = "Recalculate the direction of selected handles";
ot->idname = "CURVE_OT_normals_make_consistent";
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index 1146c49bef2..e97fd424742 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -31,9 +31,11 @@ struct Main;
/* info_stats.c */
void ED_info_stats_clear(struct ViewLayer *view_layer);
-const char *ED_info_footer_string(struct ViewLayer *view_layer);
+const char *ED_info_statusbar_string(struct Main *bmain,
+ struct bScreen *screen,
+ struct bContext *C);
void ED_info_draw_stats(
- Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height);
+ struct Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index bac86adbabb..586f5e07997 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -881,7 +881,7 @@ void UI_icons_reload_internal_textures(void)
}
if (need_icons_with_border && icongltex.tex[1] == NULL) {
- icongltex.tex[0] = GPU_texture_create_nD(b32buf_border->x,
+ icongltex.tex[1] = GPU_texture_create_nD(b32buf_border->x,
b32buf_border->y,
0,
2,
@@ -891,7 +891,7 @@ void UI_icons_reload_internal_textures(void)
0,
false,
NULL);
- GPU_texture_add_mipmap(icongltex.tex[0], GPU_DATA_UNSIGNED_BYTE, 1, b16buf_border->rect);
+ GPU_texture_add_mipmap(icongltex.tex[1], GPU_DATA_UNSIGNED_BYTE, 1, b16buf_border->rect);
}
}
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index d953a8f9d42..51f3a94efde 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -1589,12 +1589,12 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
return OPERATOR_CANCELLED;
}
-/* named to match mesh recalc normals */
+/* Named to match mesh recalculate normals. */
void MASK_OT_normals_make_consistent(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Recalc Normals";
- ot->description = "Re-calculate the direction of selected handles";
+ ot->name = "Recalculate Handles";
+ ot->description = "Recalculate the direction of selected handles";
ot->idname = "MASK_OT_normals_make_consistent";
/* api callbacks */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index b034fb186d2..fde1498bc5e 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -89,6 +89,8 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "GPU_extensions.h"
+
#include "screen_intern.h" /* own module include */
#define KM_MODAL_CANCEL 1
@@ -4127,12 +4129,6 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
/** \name Region Context Menu Operator (Header/Footer/Navbar)
* \{ */
-static bool screen_region_context_menu_poll(bContext *C)
-{
- ScrArea *area = CTX_wm_area(C);
- return (area && area->spacetype != SPACE_STATUSBAR);
-}
-
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
ScrArea *area = CTX_wm_area(C);
@@ -4221,15 +4217,35 @@ void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout,
uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
}
+static void ed_screens_statusbar_menu_create(uiLayout *layout, void *UNUSED(arg))
+{
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, &RNA_PreferencesView, &U, &ptr);
+ uiItemR(layout, &ptr, "show_statusbar_stats", 0, IFACE_("Scene Statistics"), ICON_NONE);
+ uiItemR(layout, &ptr, "show_statusbar_memory", 0, IFACE_("System Memory"), ICON_NONE);
+ if (GPU_mem_stats_supported()) {
+ uiItemR(layout, &ptr, "show_statusbar_vram", 0, IFACE_("Video Memory"), ICON_NONE);
+ }
+ uiItemR(layout, &ptr, "show_statusbar_version", 0, IFACE_("Blender Version"), ICON_NONE);
+}
+
static int screen_context_menu_invoke(bContext *C,
wmOperator *UNUSED(op),
const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
+ const ScrArea *area = CTX_wm_area(C);
const ARegion *region = CTX_wm_region(C);
- if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
+ if (area && area->spacetype == SPACE_STATUSBAR) {
+ pup = UI_popup_menu_begin(C, IFACE_("Status Bar"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ ed_screens_statusbar_menu_create(layout, NULL);
+ UI_popup_menu_end(C, pup);
+ }
+ else if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
ED_screens_header_tools_menu_create(C, layout, NULL);
@@ -4259,7 +4275,6 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
ot->idname = "SCREEN_OT_region_context_menu";
/* api callbacks */
- ot->poll = screen_region_context_menu_poll;
ot->invoke = screen_context_menu_invoke;
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 9da75ab7e3c..8532d8420f9 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1515,7 +1515,7 @@ static void proxy_endjob(void *pjv)
}
if (pj->clip->source == MCLIP_SRC_MOVIE) {
- /* Timecode might have changed, so do a full reload to deal with this. */
+ /* Time-code might have changed, so do a full reload to deal with this. */
DEG_id_tag_update(&pj->clip->id, ID_RECALC_SOURCE);
}
else {
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index e1937dffb37..4e91da01cc9 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
#include "BKE_blender_version.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
@@ -405,46 +406,6 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
*(view_layer->stats) = stats;
}
-static const char *footer_string(ViewLayer *view_layer)
-{
-#define MAX_INFO_MEM_LEN 64
- char memstr[MAX_INFO_MEM_LEN];
- char gpumemstr[MAX_INFO_MEM_LEN] = "";
- char formatted_mem[15];
- size_t ofs = 0;
-
- uintptr_t mem_in_use = MEM_get_memory_in_use();
-
- /* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
- ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem);
-
- if (GPU_mem_stats_supported()) {
- int gpu_free_mem, gpu_tot_memory;
-
- GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
-
- BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
- ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
-
- if (gpu_tot_memory) {
- BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
- BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
- }
- }
-
- BLI_snprintf(view_layer->footer_str,
- sizeof(view_layer->footer_str),
- "%s%s | %s",
- memstr,
- gpumemstr,
- BKE_blender_version_string());
-
- return view_layer->footer_str;
-
-#undef MAX_INFO_MEM_LEN
-}
-
void ED_info_stats_clear(ViewLayer *view_layer)
{
if (view_layer->stats) {
@@ -453,45 +414,26 @@ void ED_info_stats_clear(ViewLayer *view_layer)
}
}
-const char *ED_info_footer_string(ViewLayer *view_layer)
-{
- return footer_string(view_layer);
-}
-
-static void stats_row(int col1,
- const char *key,
- int col2,
- const char *value1,
- const char *value2,
- int *y,
- int height)
-{
- *y -= height;
- BLF_draw_default(col1, *y, 0.0f, key, 128);
- char values[128];
- BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2);
- BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
-}
-
-void ED_info_draw_stats(
- Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
+static bool format_stats(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ SceneStatsFmt *stats_fmt)
{
/* Create stats if they don't already exist. */
if (!view_layer->stats) {
/* Do not not access dependency graph if interface is marked as locked. */
wmWindowManager *wm = bmain->wm.first;
if (wm->is_interface_locked) {
- return;
+ return false;
}
Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
stats_update(depsgraph, view_layer);
}
SceneStats *stats = view_layer->stats;
- SceneStatsFmt stats_fmt;
/* Generate formatted numbers. */
-#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
+#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt->_id, stats->_id)
SCENE_STATS_FMT_INT(totvert);
SCENE_STATS_FMT_INT(totvertsel);
@@ -519,6 +461,176 @@ void ED_info_draw_stats(
SCENE_STATS_FMT_INT(totgppoint);
#undef SCENE_STATS_FMT_INT
+ return true;
+}
+
+static void get_stats_string(
+ char *info, int len, size_t *ofs, ViewLayer *view_layer, SceneStatsFmt *stats_fmt)
+{
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
+ LayerCollection *layer_collection = view_layer->active_collection;
+
+ if (object_mode == OB_MODE_OBJECT) {
+ *ofs += BLI_snprintf(info + *ofs,
+ len - *ofs,
+ "%s | ",
+ BKE_collection_ui_name_get(layer_collection->collection));
+ }
+
+ if (ob) {
+ *ofs += BLI_snprintf(info + *ofs, len - *ofs, "%s | ", ob->id.name + 2);
+ }
+
+ if (obedit) {
+ if (BKE_keyblock_from_object(obedit)) {
+ *ofs += BLI_strncpy_rlen(info + *ofs, TIP_("(Key) "), len - *ofs);
+ }
+
+ if (obedit->type == OB_MESH) {
+ *ofs += BLI_snprintf(info + *ofs,
+ len - *ofs,
+ TIP_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
+ stats_fmt->totvertsel,
+ stats_fmt->totvert,
+ stats_fmt->totedgesel,
+ stats_fmt->totedge,
+ stats_fmt->totfacesel,
+ stats_fmt->totface,
+ stats_fmt->tottri);
+ }
+ else if (obedit->type == OB_ARMATURE) {
+ *ofs += BLI_snprintf(info + *ofs,
+ len - *ofs,
+ TIP_("Verts:%s/%s | Bones:%s/%s"),
+ stats_fmt->totvertsel,
+ stats_fmt->totvert,
+ stats_fmt->totbonesel,
+ stats_fmt->totbone);
+ }
+ else {
+ *ofs += BLI_snprintf(
+ info + *ofs, len - *ofs, TIP_("Verts:%s/%s"), stats_fmt->totvertsel, stats_fmt->totvert);
+ }
+ }
+ else if (ob && (object_mode & OB_MODE_POSE)) {
+ *ofs += BLI_snprintf(
+ info + *ofs, len - *ofs, TIP_("Bones:%s/%s"), stats_fmt->totbonesel, stats_fmt->totbone);
+ }
+ else if ((ob) && (ob->type == OB_GPENCIL)) {
+ *ofs += BLI_snprintf(info + *ofs,
+ len - *ofs,
+ TIP_("Layers:%s | Frames:%s | Strokes:%s | Points:%s"),
+ stats_fmt->totgplayer,
+ stats_fmt->totgpframe,
+ stats_fmt->totgpstroke,
+ stats_fmt->totgppoint);
+ }
+ else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
+ *ofs += BLI_snprintf(info + *ofs,
+ len - *ofs,
+ TIP_("Verts:%s | Tris:%s"),
+ stats_fmt->totvert,
+ stats_fmt->tottri);
+ }
+ else {
+ *ofs += BLI_snprintf(info + *ofs,
+ len - *ofs,
+ TIP_("Verts:%s | Faces:%s | Tris:%s"),
+ stats_fmt->totvert,
+ stats_fmt->totface,
+ stats_fmt->tottri);
+ }
+
+ *ofs += BLI_snprintf(
+ info + *ofs, len - *ofs, TIP_(" | Objects:%s/%s"), stats_fmt->totobjsel, stats_fmt->totobj);
+}
+
+const char *ED_info_statusbar_string(Main *bmain, bScreen *screen, bContext *C)
+{
+ char formatted_mem[15];
+ size_t ofs = 0;
+ char *info = screen->statusbar_info;
+ int len = sizeof(screen->statusbar_info);
+
+ info[0] = '\0';
+
+ /* Scene statistics. */
+ if (U.statusbar_flag & STATUSBAR_SHOW_STATS) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ SceneStatsFmt stats_fmt;
+ if (format_stats(bmain, scene, view_layer, &stats_fmt)) {
+ get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt);
+ }
+ }
+
+ /* Memory status. */
+ if (U.statusbar_flag & STATUSBAR_SHOW_MEMORY) {
+ if (info[0]) {
+ ofs += BLI_snprintf(info + ofs, len - ofs, " | ");
+ }
+ uintptr_t mem_in_use = MEM_get_memory_in_use();
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
+ ofs += BLI_snprintf(info + ofs, len, TIP_("Memory: %s"), formatted_mem);
+ }
+
+ /* GPU VRAM status. */
+ if ((U.statusbar_flag & STATUSBAR_SHOW_VRAM) && (GPU_mem_stats_supported())) {
+ int gpu_free_mem_kb, gpu_tot_mem_kb;
+ GPU_mem_stats_get(&gpu_tot_mem_kb, &gpu_free_mem_kb);
+ float gpu_total_gb = gpu_tot_mem_kb / 1048576.0f;
+ float gpu_free_gb = gpu_free_mem_kb / 1048576.0f;
+ if (info[0]) {
+ ofs += BLI_snprintf(info + ofs, len - ofs, " | ");
+ }
+ if (gpu_free_mem_kb && gpu_tot_mem_kb) {
+ ofs += BLI_snprintf(info + ofs,
+ len - ofs,
+ TIP_("VRAM: %.1f/%.1f GiB"),
+ gpu_total_gb - gpu_free_gb,
+ gpu_total_gb);
+ }
+ else {
+ /* Can only show amount of GPU VRAM available. */
+ ofs += BLI_snprintf(info + ofs, len - ofs, TIP_("VRAM: %.1f GiB Free"), gpu_free_gb);
+ }
+ }
+
+ /* Blender version. */
+ if (U.statusbar_flag & STATUSBAR_SHOW_VERSION) {
+ if (info[0]) {
+ ofs += BLI_snprintf(info + ofs, len - ofs, " | ");
+ }
+ ofs += BLI_snprintf(info + ofs, len - ofs, TIP_("%s"), BKE_blender_version_string());
+ }
+
+ return info;
+}
+
+static void stats_row(int col1,
+ const char *key,
+ int col2,
+ const char *value1,
+ const char *value2,
+ int *y,
+ int height)
+{
+ *y -= height;
+ BLF_draw_default(col1, *y, 0.0f, key, 128);
+ char values[128];
+ BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2);
+ BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
+}
+
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
+{
+ SceneStatsFmt stats_fmt;
+ if (!format_stats(bmain, scene, view_layer, &stats_fmt)) {
+ return;
+ }
Object *ob = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index b4098f17212..cc5f7deb418 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1699,6 +1699,11 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
/* set flags */
G.f |= G_FLAG_RENDER_VIEWPORT;
+ /* There are too many functions inside the draw manager that check the shading type,
+ * so use a temporary override instead. */
+ const eDrawType drawtype_orig = v3d->shading.type;
+ v3d->shading.type = drawtype;
+
{
/* free images which can have changed on frame-change
* warning! can be slow so only free animated images - campbell */
@@ -1739,6 +1744,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
UI_Theme_Restore(&theme_state);
+ v3d->shading.type = drawtype_orig;
G.f &= ~G_FLAG_RENDER_VIEWPORT;
}
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 43341eadb97..50e0bb1f1c2 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -98,6 +98,14 @@ void ED_undo_push(bContext *C, const char *str)
if (steps <= 0) {
return;
}
+ if (G.background) {
+ /* Python developers may have explicitly created the undo stack in background mode,
+ * otherwise allow it to be NULL, see: T60934.
+ * Otherwise it must never be NULL, even when undo is disabled. */
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+ }
/* Only apply limit if this is the last undo step. */
if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
diff --git a/source/blender/functions/FN_multi_function_network.hh b/source/blender/functions/FN_multi_function_network.hh
index e47c8260057..91eb5bb65dc 100644
--- a/source/blender/functions/FN_multi_function_network.hh
+++ b/source/blender/functions/FN_multi_function_network.hh
@@ -233,6 +233,8 @@ class MFNetwork : NonCopyable, NonMovable {
VectorSet<const MFOutputSocket *> &r_dummy_sockets,
VectorSet<const MFInputSocket *> &r_unlinked_inputs) const;
+ bool have_dummy_or_unlinked_dependencies(Span<const MFInputSocket *> sockets) const;
+
std::string to_dot(Span<const MFNode *> marked_nodes = {}) const;
};
diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc
index 11c9c065f51..1d3d3a8b5f2 100644
--- a/source/blender/functions/intern/multi_function_network.cc
+++ b/source/blender/functions/intern/multi_function_network.cc
@@ -269,6 +269,14 @@ void MFNetwork::find_dependencies(Span<const MFInputSocket *> sockets,
}
}
+bool MFNetwork::have_dummy_or_unlinked_dependencies(Span<const MFInputSocket *> sockets) const
+{
+ VectorSet<const MFOutputSocket *> dummy_sockets;
+ VectorSet<const MFInputSocket *> unlinked_inputs;
+ this->find_dependencies(sockets, dummy_sockets, unlinked_inputs);
+ return dummy_sockets.size() + unlinked_inputs.size() > 0;
+}
+
std::string MFNetwork::to_dot(Span<const MFNode *> marked_nodes) const
{
dot::DirectedGraph digraph;
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index 56d640ea0e4..eabfb5d2dc3 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -102,11 +102,15 @@ struct GPUMatrixUnproject_Precalc {
float model_inverted[4][4];
float view[4];
bool is_persp;
- /** Result of 'projmat_dimensions'. */
+ /**
+ * Result of #projmat_dimensions_db.
+ * Using double precision here is important as far clipping ranges
+ * can cause divide-by-zero when using float, see: T66937.
+ */
struct {
- float xmin, xmax;
- float ymin, ymax;
- float zmin, zmax;
+ double xmin, xmax;
+ double ymin, ymax;
+ double zmin, zmax;
} dims;
};
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 1c533c80ab7..77ad16eeb72 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -409,7 +409,7 @@ void gpu_extensions_exit(void)
bool GPU_mem_stats_supported(void)
{
#ifndef GPU_STANDALONE
- return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM);
+ return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo);
#else
return false;
#endif
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c
index d0f7eab32a3..669bf56b726 100644
--- a/source/blender/gpu/intern/gpu_matrix.c
+++ b/source/blender/gpu/intern/gpu_matrix.c
@@ -536,13 +536,13 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc,
const int view[4])
{
precalc->is_persp = proj[3][3] == 0.0f;
- projmat_dimensions(proj,
- &precalc->dims.xmin,
- &precalc->dims.xmax,
- &precalc->dims.ymin,
- &precalc->dims.ymax,
- &precalc->dims.zmin,
- &precalc->dims.zmax);
+ projmat_dimensions_db(proj,
+ &precalc->dims.xmin,
+ &precalc->dims.xmax,
+ &precalc->dims.ymin,
+ &precalc->dims.ymax,
+ &precalc->dims.zmin,
+ &precalc->dims.zmax);
if (isinf(precalc->dims.zmax)) {
/* We cannot retrieve the actual value of the clip_end.
* Use `FLT_MAX` to avoid nans. */
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 3067be1c485..bf59b720cff 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -116,7 +116,7 @@ typedef struct GPUInput {
struct GPUInput *next, *prev;
GPUNode *node;
- eGPUType type; /* datatype */
+ eGPUType type; /* data-type. */
GPUNodeLink *link;
int id; /* unique id as created by code generator */
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index cc12e3f78a5..d85884e0a25 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -136,4 +136,5 @@ void main()
}
fragColor.a *= color_flat.a;
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
}
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index fc7e03c3073..478297e61b2 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -291,7 +291,7 @@ void IMB_rectblend_threaded(struct ImBuf *dbuf,
*/
typedef enum IMB_Timecode_Type {
- /** Don't use timecode files at all. */
+ /** Don't use time-code files at all. */
IMB_TC_NONE = 0,
/** use images in the order as they are recorded
* (currently, this is the only one implemented
@@ -318,7 +318,7 @@ typedef enum IMB_Proxy_Size {
IMB_PROXY_MAX_SLOT = 4,
} IMB_Proxy_Size;
-/* defaults to BL_proxy within the directory of the animation */
+/* Defaults to BL_proxy within the directory of the animation. */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
void IMB_anim_get_fname(struct anim *anim, char *file, int size);
@@ -328,7 +328,7 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim);
struct IndexBuildContext;
-/* prepare context for proxies/imecodes builder */
+/* Prepare context for proxies/time-codes builder. */
struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
@@ -336,13 +336,13 @@ struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
const bool overwrite,
struct GSet *file_list);
-/* will rebuild all used indices and proxies at once */
+/* Will rebuild all used indices and proxies at once. */
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
short *stop,
short *do_update,
float *progress);
-/* finish rebuilding proxises/timecodes and free temporary contexts used */
+/* Finish rebuilding proxies/time-codes and free temporary contexts used. */
void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop);
/**
@@ -391,7 +391,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
/**
*
* \attention Defined in anim_movie.c
- * fetches a define previewframe, usually half way into the movie
+ * fetches a define preview-frame, usually half way into the movie.
*/
struct ImBuf *IMB_anim_previewframe(struct anim *anim);
diff --git a/source/blender/imbuf/intern/IMB_indexer.h b/source/blender/imbuf/intern/IMB_indexer.h
index 61bb50aff38..446aaa0655e 100644
--- a/source/blender/imbuf/intern/IMB_indexer.h
+++ b/source/blender/imbuf/intern/IMB_indexer.h
@@ -31,9 +31,9 @@
/*
* separate animation index files to solve the following problems:
*
- * a) different timecodes within one file (like DTS/PTS, Timecode-Track,
- * "implicit" timecodes within DV-files and HDV-files etc.)
- * b) seeking difficulties within ffmpeg for files with timestamp holes
+ * a) different time-codes within one file (like DTS/PTS, Time-code-Track,
+ * "implicit" time-codes within DV-files and HDV-files etc.)
+ * b) seeking difficulties within FFMPEG for files with timestamp holes
* c) broken files that miss several frames / have varying framerates
* d) use proxies accordingly
*
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 2a5532a0902..887225f0dc6 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1209,7 +1209,7 @@ void IMB_exr_read_channels(void *handle)
ExrHandle *data = (ExrHandle *)handle;
int numparts = data->ifile->parts();
- /* check if exr was saved with previous versions of blender which flipped images */
+ /* Check if EXR was saved with previous versions of blender which flipped images. */
const StringAttribute *ta = data->ifile->header(0).findTypedAttribute<StringAttribute>(
"BlenderMultiChannel");
@@ -1803,12 +1803,12 @@ static void imb_exr_type_by_channels(ChannelList &channels,
}
if (!layerNames.empty()) {
- /* if layerNames is not empty, it means at least one layer is non-empty,
+ /* If `layerNames` is not empty, it means at least one layer is non-empty,
* but it also could be layers without names in the file and such case
- * shall be considered a multilayer exr
+ * shall be considered a multi-layer EXR.
*
- * that's what we do here: test whether there're empty layer names together
- * with non-empty ones in the file
+ * That's what we do here: test whether there are empty layer names together
+ * with non-empty ones in the file.
*/
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++) {
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
index f42349d99e8..d0db1284c77 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
@@ -73,7 +73,7 @@ std::string USDHierarchyIterator::make_valid_name(const std::string &name) const
void USDHierarchyIterator::set_export_frame(float frame_nr)
{
- // The USD stage is already set up to have FPS timecodes per frame.
+ /* The USD stage is already set up to have FPS time-codes per frame. */
export_time_ = pxr::UsdTimeCode(frame_nr);
}
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 6348dc5f03d..cb604fd6681 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -115,7 +115,6 @@ typedef struct ViewLayer {
ListBase object_bases;
/** Default allocated now. */
struct SceneStats *stats;
- char footer_str[128];
struct Base *basact;
/** A view layer has one top level layer collection, because a scene has only one top level
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 72421ecb79d..bf5c097322f 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -69,6 +69,8 @@ typedef struct bScreen {
/** User-setting for which editors get redrawn during anim playback. */
short redraws_flag;
+ char statusbar_info[256];
+
/** Temp screen in a temp window, don't save (like user prefs). */
char temp;
/** Temp screen for image render display or fileselect. */
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index a2b81b731d3..c4ff51a107e 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -32,6 +32,8 @@ typedef struct Simulation {
int flag;
float current_frame;
+ float current_simulation_time;
+ char _pad[4];
/** List containing SimulationState objects. */
struct ListBase states;
@@ -53,7 +55,7 @@ typedef struct ParticleSimulationState {
/** Contains the state of the particles at time Simulation->current_frame. */
int tot_particles;
- int _pad;
+ int next_particle_id;
struct CustomData attributes;
/** Caches the state of the particles over time. The cache only exists on the original data
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 8ea4d3b6476..e6f6ce1e208 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -661,9 +661,9 @@ typedef struct UserDef {
char anim_player[1024];
int anim_player_preset;
- /** Minimum spacing between gridlines in View2D grids. */
+ /** Minimum spacing between grid-lines in View2D grids. */
short v2d_min_gridsize;
- /** #eTimecodeStyles, style of timecode display. */
+ /** #eTimecodeStyles, style of time-code display. */
short timecode_style;
short versions;
@@ -694,7 +694,7 @@ typedef struct UserDef {
float ui_scale;
/** Setting for UI line width. */
int ui_line_width;
- /** Runtime, full DPI divided by pixelsize. */
+ /** Runtime, full DPI divided by `pixelsize`. */
int dpi;
/** Runtime, multiplier to scale UI elements based on DPI. */
float dpi_fac;
@@ -704,7 +704,7 @@ typedef struct UserDef {
/** Deprecated, for forward compatibility. */
int virtual_pixel;
- /** Console scrollback limit. */
+ /** Console scroll-back limit. */
int scrollback;
/** Node insert offset (aka auto-offset) margin, but might be useful for later stuff as well. */
char node_margin;
@@ -880,7 +880,9 @@ typedef struct UserDef {
char _pad5[2];
float collection_instance_empty_size;
- char _pad10[4];
+ char _pad10[3];
+
+ char statusbar_flag; /* eUserpref_StatusBar_Flag */
struct WalkNavigation walk_navigation;
@@ -1079,6 +1081,14 @@ typedef enum eUserpref_APP_Flag {
USER_APP_LOCK_UI_LAYOUT = (1 << 0),
} eUserpref_APP_Flag;
+/** #UserDef.statusbar_flag */
+typedef enum eUserpref_StatusBar_Flag {
+ STATUSBAR_SHOW_MEMORY = (1 << 0),
+ STATUSBAR_SHOW_VRAM = (1 << 1),
+ STATUSBAR_SHOW_STATS = (1 << 2),
+ STATUSBAR_SHOW_VERSION = (1 << 3),
+} eUserpref_StatusBar_Flag;
+
/**
* Auto-Keying mode.
* #UserDef.autokey_mode
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index f3c73e75434..b94221ae936 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -218,7 +218,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "100%", "Build proxy resolution 100% of the original undistorted footage dimension");
- /* build timecodes */
+ /* Build time-codes. */
prop = RNA_def_property(srna, "build_record_run", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_tc_flag", IMB_TC_RECORD_RUN);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 9b98be61cbf..a6247474c69 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -924,13 +924,6 @@ static void rna_Scene_volume_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_VOLUME | ID_RECALC_SEQUENCER_STRIPS);
}
-static const char *rna_Scene_statistics_string_get(Scene *UNUSED(scene),
- Main *UNUSED(bmain),
- ViewLayer *view_layer)
-{
- return ED_info_footer_string(view_layer);
-}
-
static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
scene->r.framelen = (float)scene->r.framapto / (float)scene->r.images;
@@ -3456,7 +3449,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_edge_path_live_unwrap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1);
- RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam re-calculates UV unwrap");
+ RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam recalculates UV unwrap");
prop = RNA_def_property(srna, "normal_vector", PROP_FLOAT, PROP_XYZ);
RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply");
@@ -4814,7 +4807,7 @@ void rna_def_freestyle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"View Map Cache",
- "Keep the computed view map and avoid re-calculating it if mesh geometry is unchanged");
+ "Keep the computed view map and avoid recalculating it if mesh geometry is unchanged");
RNA_def_property_update(
prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_use_view_map_cache_update");
@@ -7275,9 +7268,6 @@ void RNA_def_scene(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- FunctionRNA *func;
- PropertyRNA *parm;
-
static const EnumPropertyItem audio_distance_model_items[] = {
{0, "NONE", 0, "None", "No distance attenuation"},
{1, "INVERSE", 0, "Inverse", "Inverse distance model"},
@@ -7669,14 +7659,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE, NULL);
RNA_def_property_update(prop, NC_SCENE, "rna_Scene_volume_update");
- /* Statistics */
- func = RNA_def_function(srna, "statistics", "rna_Scene_statistics_string_get");
- RNA_def_function_flag(func, FUNC_USE_MAIN);
- parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "Active layer");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
- parm = RNA_def_string(func, "statistics", NULL, 0, "Statistics", "");
- RNA_def_function_return(func, parm);
-
/* Grease Pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index ea6421c8d11..2b65bf4922c 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -30,6 +30,8 @@
#include "DNA_screen_types.h"
#include "DNA_workspace_types.h"
+#include "ED_info.h"
+
const EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_WINDOW, "WINDOW", 0, "Window", ""},
{RGN_TYPE_HEADER, "HEADER", 0, "Header", ""},
@@ -286,6 +288,11 @@ static void rna_View2D_view_to_region(
}
}
+static const char *rna_Screen_statusbar_info_get(struct bScreen *screen, Main *bmain, bContext *C)
+{
+ return ED_info_statusbar_string(bmain, screen, C);
+}
+
#else
/* Area.spaces */
@@ -536,6 +543,9 @@ static void rna_def_screen(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
srna = RNA_def_struct(brna, "Screen", "ID");
RNA_def_struct_sdna(srna, "Screen"); /* it is actually bScreen but for 2.5 the dna is patched! */
RNA_def_struct_ui_text(
@@ -570,11 +580,18 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Screen_fullscreen_get", NULL);
RNA_def_property_ui_text(prop, "Maximize", "An area is maximized, filling this screen");
+ /* Status Bar. */
+
prop = RNA_def_property(srna, "show_statusbar", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCREEN_COLLAPSE_STATUSBAR);
- RNA_def_property_ui_text(prop, "Show Status Bar", "Show status bar");
+ RNA_def_property_ui_text(prop, "Show Status Bar", "Show Status Bar");
RNA_def_property_update(prop, 0, "rna_Screen_bar_update");
+ func = RNA_def_function(srna, "statusbar_info", "rna_Screen_statusbar_info_get");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_CONTEXT);
+ parm = RNA_def_string(func, "statusbar_info", NULL, 0, "Status Bar Info", "");
+ RNA_def_function_return(func, parm);
+
/* Define Anim Playback Areas */
prop = RNA_def_property(srna, "use_play_top_left_3d_editor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_REGION);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index de225e3c685..6589ae4b8da 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2145,7 +2145,7 @@ static void rna_def_proxy(StructRNA *srna)
prop = RNA_def_property(srna, "use_proxy", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXY);
RNA_def_property_ui_text(
- prop, "Use Proxy / Timecode", "Use a preview proxy and/or timecode index for this strip");
+ prop, "Use Proxy / Timecode", "Use a preview proxy and/or time-code index for this strip");
RNA_def_property_boolean_funcs(prop, NULL, "rna_Sequence_use_proxy_set");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 956fb65054b..4884b536258 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -188,6 +188,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "DEG_depsgraph.h"
# include "GPU_draw.h"
+# include "GPU_extensions.h"
# include "GPU_select.h"
# include "BLF_api.h"
@@ -439,13 +440,12 @@ static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value)
UserDef *userdef = (UserDef *)ptr->data;
int required_size = userdef->v2d_min_gridsize;
- /* set the timecode style */
+ /* Set the time-code style. */
userdef->timecode_style = value;
- /* adjust the v2d gridsize if needed so that timecodes don't overlap
+ /* Adjust the v2d grid-size if needed so that time-codes don't overlap
* NOTE: most of these have been hand-picked to avoid overlaps while still keeping
- * things from getting too blown out
- */
+ * things from getting too blown out. */
switch (value) {
case USER_TIMECODE_MINIMAL:
case USER_TIMECODE_SECONDS_ONLY:
@@ -1066,6 +1066,11 @@ static void rna_UserDef_studiolight_light_ambient_get(PointerRNA *ptr, float *va
copy_v3_v3(values, sl->light_ambient);
}
+int rna_show_statusbar_vram_editable(struct PointerRNA *UNUSED(ptr), const char **UNUSED(r_info))
+{
+ return GPU_mem_stats_supported() ? PROP_EDITABLE : 0;
+}
+
#else
# define USERDEF_TAG_DIRTY_PROPERTY_UPDATE_ENABLE \
@@ -4771,6 +4776,29 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Translate New Names",
"Translate the names of new data-blocks (objects, materials...)");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ /* Statusbar. */
+
+ prop = RNA_def_property(srna, "show_statusbar_memory", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "statusbar_flag", STATUSBAR_SHOW_MEMORY);
+ RNA_def_property_ui_text(prop, "Show Memory", "Show Blender memory usage");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "show_statusbar_vram", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "statusbar_flag", STATUSBAR_SHOW_VRAM);
+ RNA_def_property_ui_text(prop, "Show VRAM", "Show GPU video memory usage");
+ RNA_def_property_editable_func(prop, "rna_show_statusbar_vram_editable");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "show_statusbar_version", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "statusbar_flag", STATUSBAR_SHOW_VERSION);
+ RNA_def_property_ui_text(prop, "Show Version", "Show Blender version string");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "show_statusbar_stats", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "statusbar_flag", STATUSBAR_SHOW_STATS);
+ RNA_def_property_ui_text(prop, "Show Statistics", "Show scene statistics");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_INFO, "rna_userdef_update");
}
static void rna_def_userdef_edit(BlenderRNA *brna)
diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc
index 38dc1546763..819ed320255 100644
--- a/source/blender/modifiers/intern/MOD_simulation.cc
+++ b/source/blender/modifiers/intern/MOD_simulation.cc
@@ -129,7 +129,7 @@ static PointCloud *modifyPointCloud(ModifierData *md,
memcpy(pointcloud->co, positions, sizeof(float3) * state->tot_particles);
for (int i = 0; i < state->tot_particles; i++) {
- pointcloud->radius[i] = 0.1f;
+ pointcloud->radius[i] = 0.03f;
}
return pointcloud;
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index be5a92309f2..ed5e505176c 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -268,11 +268,11 @@ void BPY_python_start(int argc, const char **argv)
/* allow to use our own included python */
PyC_SetHomePath(py_path_bundle);
- /* without this the sys.stdout may be set to 'ascii'
+ /* Without this the `sys.stdout` may be set to 'ascii'
* (it is on my system at least), where printing unicode values will raise
- * an error, this is highly annoying, another stumbling block for devs,
+ * an error, this is highly annoying, another stumbling block for developers,
* so use a more relaxed error handler and enforce utf-8 since the rest of
- * blender is utf-8 too - campbell */
+ * Blender is utf-8 too - campbell */
Py_SetStandardStreamEncoding("utf-8", "surrogateescape");
/* Suppress error messages when calculating the module search path.
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index ebbbc8f3140..893832b61b6 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -7660,8 +7660,8 @@ void BPY_update_rna_module(void)
}
#if 0
-/* This is a way we can access docstrings for RNA types
- * without having the datatypes in blender */
+/* This is a way we can access doc-strings for RNA types
+ * without having the data-types in Blender. */
PyObject *BPY_rna_doc(void)
{
PointerRNA ptr;
diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c
index dd7e6b03e8b..e2c894e90f8 100644
--- a/source/blender/python/intern/bpy_traceback.c
+++ b/source/blender/python/intern/bpy_traceback.c
@@ -140,8 +140,8 @@ void python_script_error_jump(const char *filepath, int *lineno, int *offset)
PyErr_Fetch(&exception, &value, (PyObject **)&tb);
if (exception && PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError)) {
- /* no traceback available when SyntaxError.
- * python has no api's to this. reference parse_syntax_error() from pythonrun.c */
+ /* no trace-back available when `SyntaxError`.
+ * python has no API's to this. reference #parse_syntax_error() from pythonrun.c */
PyErr_NormalizeException(&exception, &value, (PyObject **)&tb);
if (value) { /* should always be true */
diff --git a/source/blender/simulation/CMakeLists.txt b/source/blender/simulation/CMakeLists.txt
index a19e96e1a91..243b056db74 100644
--- a/source/blender/simulation/CMakeLists.txt
+++ b/source/blender/simulation/CMakeLists.txt
@@ -41,6 +41,7 @@ set(SRC
intern/hair_volume.cpp
intern/implicit_blender.c
intern/implicit_eigen.cpp
+ intern/particle_allocator.cc
intern/particle_function.cc
intern/simulation_collect_influences.cc
intern/simulation_solver.cc
@@ -49,11 +50,13 @@ set(SRC
intern/ConstrainedConjugateGradient.h
intern/eigen_utils.h
intern/implicit.h
+ intern/particle_allocator.hh
+ intern/particle_function.hh
intern/simulation_collect_influences.hh
intern/simulation_solver.hh
+ intern/time_interval.hh
SIM_mass_spring.h
- SIM_particle_function.hh
SIM_simulation_update.hh
)
diff --git a/source/blender/simulation/intern/particle_allocator.cc b/source/blender/simulation/intern/particle_allocator.cc
new file mode 100644
index 00000000000..b65c0197c76
--- /dev/null
+++ b/source/blender/simulation/intern/particle_allocator.cc
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "particle_allocator.hh"
+
+namespace blender::sim {
+
+AttributesAllocator::~AttributesAllocator()
+{
+ for (std::unique_ptr<AttributesBlock> &block : allocated_blocks_) {
+ for (uint i : attributes_info_.index_range()) {
+ const fn::CPPType &type = attributes_info_.type_of(i);
+ type.destruct_n(block->buffers[i], block->size);
+ MEM_freeN(block->buffers[i]);
+ }
+ }
+}
+
+fn::MutableAttributesRef AttributesAllocator::allocate_uninitialized(uint size)
+{
+ std::unique_ptr<AttributesBlock> block = std::make_unique<AttributesBlock>();
+ block->buffers = Array<void *>(attributes_info_.size(), nullptr);
+ block->size = size;
+
+ for (uint i : attributes_info_.index_range()) {
+ const fn::CPPType &type = attributes_info_.type_of(i);
+ void *buffer = MEM_mallocN_aligned(size * type.size(), type.alignment(), AT);
+ block->buffers[i] = buffer;
+ }
+
+ fn::MutableAttributesRef attributes{attributes_info_, block->buffers, size};
+
+ {
+ std::lock_guard lock{mutex_};
+ allocated_blocks_.append(std::move(block));
+ allocated_attributes_.append(attributes);
+ total_allocated_ += size;
+ }
+
+ return attributes;
+}
+
+fn::MutableAttributesRef ParticleAllocator::allocate(uint size)
+{
+ const fn::AttributesInfo &info = attributes_allocator_.attributes_info();
+ fn::MutableAttributesRef attributes = attributes_allocator_.allocate_uninitialized(size);
+ for (uint i : info.index_range()) {
+ const fn::CPPType &type = info.type_of(i);
+ StringRef name = info.name_of(i);
+ if (name == "ID") {
+ uint start_id = next_id_.fetch_add(size);
+ MutableSpan<int> ids = attributes.get<int>("ID");
+ for (uint pindex : IndexRange(size)) {
+ ids[pindex] = start_id + pindex;
+ }
+ }
+ else {
+ type.fill_uninitialized(info.default_of(i), attributes.get(i).buffer(), size);
+ }
+ }
+ return attributes;
+}
+
+} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_allocator.hh b/source/blender/simulation/intern/particle_allocator.hh
new file mode 100644
index 00000000000..f854413c9aa
--- /dev/null
+++ b/source/blender/simulation/intern/particle_allocator.hh
@@ -0,0 +1,95 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __SIM_PARTICLE_ALLOCATOR_HH__
+#define __SIM_PARTICLE_ALLOCATOR_HH__
+
+#include "BLI_array.hh"
+#include "BLI_vector.hh"
+
+#include "FN_attributes_ref.hh"
+
+#include <atomic>
+#include <mutex>
+
+namespace blender::sim {
+
+class AttributesAllocator : NonCopyable, NonMovable {
+ private:
+ struct AttributesBlock {
+ Array<void *> buffers;
+ uint size;
+ };
+
+ const fn::AttributesInfo &attributes_info_;
+ Vector<std::unique_ptr<AttributesBlock>> allocated_blocks_;
+ Vector<fn::MutableAttributesRef> allocated_attributes_;
+ uint total_allocated_ = 0;
+ std::mutex mutex_;
+
+ public:
+ AttributesAllocator(const fn::AttributesInfo &attributes_info)
+ : attributes_info_(attributes_info)
+ {
+ }
+
+ ~AttributesAllocator();
+
+ Span<fn::MutableAttributesRef> get_allocations() const
+ {
+ return allocated_attributes_;
+ }
+
+ uint total_allocated() const
+ {
+ return total_allocated_;
+ }
+
+ const fn::AttributesInfo &attributes_info() const
+ {
+ return attributes_info_;
+ }
+
+ fn::MutableAttributesRef allocate_uninitialized(uint size);
+};
+
+class ParticleAllocator : NonCopyable, NonMovable {
+ private:
+ AttributesAllocator attributes_allocator_;
+ std::atomic<uint> next_id_;
+
+ public:
+ ParticleAllocator(const fn::AttributesInfo &attributes_info, uint next_id)
+ : attributes_allocator_(attributes_info), next_id_(next_id)
+ {
+ }
+
+ Span<fn::MutableAttributesRef> get_allocations() const
+ {
+ return attributes_allocator_.get_allocations();
+ }
+
+ uint total_allocated() const
+ {
+ return attributes_allocator_.total_allocated();
+ }
+
+ fn::MutableAttributesRef allocate(uint size);
+};
+
+} // namespace blender::sim
+
+#endif /* __SIM_PARTICLE_ALLOCATOR_HH__ */
diff --git a/source/blender/simulation/intern/particle_function.cc b/source/blender/simulation/intern/particle_function.cc
index 7a0c9ccdb13..3788fd17e36 100644
--- a/source/blender/simulation/intern/particle_function.cc
+++ b/source/blender/simulation/intern/particle_function.cc
@@ -14,7 +14,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "SIM_particle_function.hh"
+#include "particle_function.hh"
namespace blender::sim {
@@ -49,12 +49,11 @@ ParticleFunction::ParticleFunction(const fn::MultiFunction *global_fn,
}
}
-ParticleFunctionEvaluator::ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
- IndexMask mask,
- fn::AttributesRef particle_attributes)
+ParticleFunctionEvaluator::ParticleFunctionEvaluator(
+ const ParticleFunction &particle_fn, const ParticleChunkContext &particle_chunk_context)
: particle_fn_(particle_fn),
- mask_(mask),
- particle_attributes_(particle_attributes),
+ particle_chunk_context_(particle_chunk_context),
+ mask_(particle_chunk_context_.index_mask()),
outputs_(particle_fn_.output_types_.size(), nullptr)
{
}
@@ -112,7 +111,7 @@ void ParticleFunctionEvaluator::compute_globals()
/* Add input parameters. */
for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) {
- input->add_input(particle_attributes_, params, resources_);
+ input->add_input(particle_chunk_context_.attributes(), params, resources_);
}
/* Add output parameters. */
@@ -139,7 +138,7 @@ void ParticleFunctionEvaluator::compute_per_particle()
/* Add input parameters. */
for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) {
- input->add_input(particle_attributes_, params, resources_);
+ input->add_input(particle_chunk_context_.attributes(), params, resources_);
}
/* Add output parameters. */
diff --git a/source/blender/simulation/SIM_particle_function.hh b/source/blender/simulation/intern/particle_function.hh
index eae61b1ae11..abed9063bae 100644
--- a/source/blender/simulation/SIM_particle_function.hh
+++ b/source/blender/simulation/intern/particle_function.hh
@@ -22,6 +22,8 @@
#include "BLI_resource_collector.hh"
+#include "simulation_solver.hh"
+
namespace blender::sim {
class ParticleFunctionInput {
@@ -58,17 +60,16 @@ class ParticleFunctionEvaluator {
private:
ResourceCollector resources_;
const ParticleFunction &particle_fn_;
+ const ParticleChunkContext &particle_chunk_context_;
IndexMask mask_;
fn::MFContextBuilder global_context_;
fn::MFContextBuilder per_particle_context_;
- fn::AttributesRef particle_attributes_;
Vector<void *> outputs_;
bool is_computed_ = false;
public:
ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
- IndexMask mask,
- fn::AttributesRef particle_attributes);
+ const ParticleChunkContext &particle_chunk_context);
~ParticleFunctionEvaluator();
void compute();
diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc
index 3feb0ccce5b..98b055802c9 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.cc
+++ b/source/blender/simulation/intern/simulation_collect_influences.cc
@@ -15,7 +15,7 @@
*/
#include "simulation_collect_influences.hh"
-#include "SIM_particle_function.hh"
+#include "particle_function.hh"
#include "FN_attributes_ref.hh"
#include "FN_multi_function_network_evaluation.hh"
@@ -23,49 +23,88 @@
#include "NOD_node_tree_multi_function.hh"
+#include "BLI_rand.hh"
+
namespace blender::sim {
+struct DummyDataSources {
+ Map<const fn::MFOutputSocket *, std::string> particle_attributes;
+};
+
extern "C" {
void WM_clipboard_text_set(const char *buf, bool selection);
}
-static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes(
- fn::MFNetwork &network,
- nodes::MFNetworkTreeMap &network_map,
- const nodes::DerivedNodeTree &tree)
+static std::string dnode_to_path(const nodes::DNode &dnode)
{
- Span<const nodes::DNode *> attribute_dnodes = tree.nodes_by_type(
- "SimulationNodeParticleAttribute");
- uint amount = attribute_dnodes.size();
+ std::string path;
+ for (const nodes::DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
+ path = parent->node_ref().name() + "/" + path;
+ }
+ path = path + dnode.name();
+ return path;
+}
+
+static Span<const nodes::DNode *> get_particle_simulation_nodes(const nodes::DerivedNodeTree &tree)
+{
+ return tree.nodes_by_type("SimulationNodeParticleSimulation");
+}
+
+static std::optional<Array<std::string>> compute_global_string_inputs(
+ nodes::MFNetworkTreeMap &network_map, Span<const fn::MFInputSocket *> sockets)
+{
+ uint amount = sockets.size();
if (amount == 0) {
- return {};
+ return Array<std::string>();
}
- Vector<fn::MFInputSocket *> name_sockets;
- for (const nodes::DNode *dnode : attribute_dnodes) {
- fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0));
- name_sockets.append(&name_socket);
+ if (network_map.network().have_dummy_or_unlinked_dependencies(sockets)) {
+ return {};
}
- fn::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()};
+ fn::MFNetworkEvaluator network_fn{{}, sockets};
fn::MFParamsBuilder params{network_fn, 1};
- Array<std::string> attribute_names{amount, NoInitialization()};
+ Array<std::string> strings(amount, NoInitialization());
for (uint i : IndexRange(amount)) {
params.add_uninitialized_single_output(
- fn::GMutableSpan(fn::CPPType::get<std::string>(), attribute_names.data() + i, 1));
+ fn::GMutableSpan(fn::CPPType::get<std::string>(), strings.data() + i, 1));
}
fn::MFContextBuilder context;
- /* Todo: Check that the names don't depend on dummy nodes. */
network_fn.call({0}, params, context);
+ return strings;
+}
+
+static void find_and_deduplicate_particle_attribute_nodes(nodes::MFNetworkTreeMap &network_map,
+ DummyDataSources &r_data_sources)
+{
+ fn::MFNetwork &network = network_map.network();
+ const nodes::DerivedNodeTree &tree = network_map.tree();
+
+ Span<const nodes::DNode *> attribute_dnodes = tree.nodes_by_type(
+ "SimulationNodeParticleAttribute");
+
+ Vector<fn::MFInputSocket *> name_sockets;
+ for (const nodes::DNode *dnode : attribute_dnodes) {
+ fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0));
+ name_sockets.append(&name_socket);
+ }
+
+ std::optional<Array<std::string>> attribute_names = compute_global_string_inputs(network_map,
+ name_sockets);
+ if (!attribute_names.has_value()) {
+ return;
+ }
+
Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>>
attribute_nodes_by_name_and_type;
- for (uint i : IndexRange(amount)) {
+ for (uint i : attribute_names->index_range()) {
attribute_nodes_by_name_and_type
- .lookup_or_add_default({attribute_names[i], name_sockets[i]->node().output(0).data_type()})
+ .lookup_or_add_default(
+ {(*attribute_names)[i], name_sockets[i]->node().output(0).data_type()})
.append(&name_sockets[i]->node());
}
@@ -82,10 +121,8 @@ static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes(
}
network.remove(nodes);
- attribute_inputs.add_new(&new_attribute_socket, attribute_name);
+ r_data_sources.particle_attributes.add_new(&new_attribute_socket, attribute_name);
}
-
- return attribute_inputs;
}
class ParticleAttributeInput : public ParticleFunctionInput {
@@ -116,7 +153,7 @@ class ParticleAttributeInput : public ParticleFunctionInput {
static const ParticleFunction *create_particle_function_for_inputs(
Span<const fn::MFInputSocket *> sockets_to_compute,
ResourceCollector &resources,
- const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs)
+ DummyDataSources &data_sources)
{
BLI_assert(sockets_to_compute.size() >= 1);
const fn::MFNetwork &network = sockets_to_compute[0]->node().network();
@@ -128,7 +165,7 @@ static const ParticleFunction *create_particle_function_for_inputs(
Vector<const ParticleFunctionInput *> per_particle_inputs;
for (const fn::MFOutputSocket *socket : dummy_deps) {
- const std::string *attribute_name = attribute_inputs.lookup_ptr(socket);
+ const std::string *attribute_name = data_sources.particle_attributes.lookup_ptr(socket);
if (attribute_name == nullptr) {
return nullptr;
}
@@ -161,12 +198,15 @@ class ParticleFunctionForce : public ParticleForce {
{
}
- void add_force(fn::AttributesRef attributes, MutableSpan<float3> r_combined_force) const override
+ void add_force(ParticleForceContext &context) const override
{
- IndexMask mask = IndexRange(attributes.size());
- ParticleFunctionEvaluator evaluator{particle_fn_, mask, attributes};
+ IndexMask mask = context.particle_chunk().index_mask();
+ MutableSpan<float3> r_combined_force = context.force_dst();
+
+ ParticleFunctionEvaluator evaluator{particle_fn_, context.particle_chunk()};
evaluator.compute();
fn::VSpan<float3> forces = evaluator.get<float3>(0, "Force");
+
for (uint i : mask) {
r_combined_force[i] += forces[i];
}
@@ -177,7 +217,7 @@ static Vector<const ParticleForce *> create_forces_for_particle_simulation(
const nodes::DNode &simulation_node,
nodes::MFNetworkTreeMap &network_map,
ResourceCollector &resources,
- const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs)
+ DummyDataSources &data_sources)
{
Vector<const ParticleForce *> forces;
for (const nodes::DOutputSocket *origin_socket :
@@ -191,7 +231,7 @@ static Vector<const ParticleForce *> create_forces_for_particle_simulation(
origin_node.input(0, "Force"));
const ParticleFunction *particle_fn = create_particle_function_for_inputs(
- {&force_socket}, resources, attribute_inputs);
+ {&force_socket}, resources, data_sources);
if (particle_fn == nullptr) {
continue;
@@ -205,32 +245,99 @@ static Vector<const ParticleForce *> create_forces_for_particle_simulation(
static void collect_forces(nodes::MFNetworkTreeMap &network_map,
ResourceCollector &resources,
- const Map<const fn::MFOutputSocket *, std::string> &attribute_inputs,
+ DummyDataSources &data_sources,
SimulationInfluences &r_influences)
{
- for (const nodes::DNode *dnode :
- network_map.tree().nodes_by_type("SimulationNodeParticleSimulation")) {
+ for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) {
std::string name = dnode_to_path(*dnode);
Vector<const ParticleForce *> forces = create_forces_for_particle_simulation(
- *dnode, network_map, resources, attribute_inputs);
+ *dnode, network_map, resources, data_sources);
r_influences.particle_forces.add_new(std::move(name), std::move(forces));
}
}
-void collect_simulation_influences(const nodes::DerivedNodeTree &tree,
+class MyBasicEmitter : public ParticleEmitter {
+ private:
+ std::string name_;
+
+ public:
+ MyBasicEmitter(std::string name) : name_(std::move(name))
+ {
+ }
+
+ void emit(ParticleEmitterContext &context) const override
+ {
+ ParticleAllocator *allocator = context.try_get_particle_allocator(name_);
+ if (allocator == nullptr) {
+ return;
+ }
+
+ fn::MutableAttributesRef attributes = allocator->allocate(10);
+ RandomNumberGenerator rng{(uint)context.simulation_time_interval().start() ^
+ DefaultHash<std::string>{}(name_)};
+
+ MutableSpan<float3> positions = attributes.get<float3>("Position");
+ MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
+
+ for (uint i : IndexRange(attributes.size())) {
+ positions[i] = rng.get_unit_float3();
+ velocities[i] = rng.get_unit_float3();
+ }
+ }
+};
+
+static void collect_emitters(nodes::MFNetworkTreeMap &network_map,
+ ResourceCollector &resources,
+ SimulationInfluences &r_influences)
+{
+ for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) {
+ std::string name = dnode_to_path(*dnode);
+ ParticleEmitter &emitter = resources.construct<MyBasicEmitter>(AT, name);
+ r_influences.particle_emitters.append(&emitter);
+ }
+}
+
+static void prepare_particle_attribute_builders(nodes::MFNetworkTreeMap &network_map,
+ ResourceCollector &resources,
+ SimulationInfluences &r_influences)
+{
+ for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) {
+ std::string name = dnode_to_path(*dnode);
+ fn::AttributesInfoBuilder &builder = resources.construct<fn::AttributesInfoBuilder>(AT);
+ builder.add<float3>("Position", {0, 0, 0});
+ builder.add<float3>("Velocity", {0, 0, 0});
+ builder.add<int>("ID", 0);
+ r_influences.particle_attributes_builder.add_new(std::move(name), &builder);
+ }
+}
+
+void collect_simulation_influences(Simulation &simulation,
ResourceCollector &resources,
- SimulationInfluences &r_influences)
+ SimulationInfluences &r_influences,
+ SimulationStatesInfo &r_states_info)
{
+ nodes::NodeTreeRefMap tree_refs;
+ const nodes::DerivedNodeTree tree{simulation.nodetree, tree_refs};
+
fn::MFNetwork &network = resources.construct<fn::MFNetwork>(AT);
nodes::MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources);
- Map<const fn::MFOutputSocket *, std::string> attribute_inputs = deduplicate_attribute_nodes(
- network, network_map, tree);
+
+ prepare_particle_attribute_builders(network_map, resources, r_influences);
+
+ DummyDataSources data_sources;
+ find_and_deduplicate_particle_attribute_nodes(network_map, data_sources);
+
fn::mf_network_optimization::constant_folding(network, resources);
fn::mf_network_optimization::common_subnetwork_elimination(network);
fn::mf_network_optimization::dead_node_removal(network);
// WM_clipboard_text_set(network.to_dot().c_str(), false);
- collect_forces(network_map, resources, attribute_inputs, r_influences);
+ collect_forces(network_map, resources, data_sources, r_influences);
+ collect_emitters(network_map, resources, r_influences);
+
+ for (const nodes::DNode *dnode : get_particle_simulation_nodes(tree)) {
+ r_states_info.particle_simulation_names.add(dnode_to_path(*dnode));
+ }
}
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_collect_influences.hh b/source/blender/simulation/intern/simulation_collect_influences.hh
index a02a6320419..cca396ffa66 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.hh
+++ b/source/blender/simulation/intern/simulation_collect_influences.hh
@@ -25,20 +25,14 @@
namespace blender::sim {
-void collect_simulation_influences(const nodes::DerivedNodeTree &tree,
+struct SimulationStatesInfo {
+ VectorSet<std::string> particle_simulation_names;
+};
+
+void collect_simulation_influences(Simulation &simulation,
ResourceCollector &resources,
- SimulationInfluences &r_influences);
-
-/* TODO: Move this to a better place. */
-inline std::string dnode_to_path(const nodes::DNode &dnode)
-{
- std::string path;
- for (const nodes::DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
- path = parent->node_ref().name() + "/" + path;
- }
- path = path + dnode.name();
- return path;
-}
+ SimulationInfluences &r_influences,
+ SimulationStatesInfo &r_states_info);
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc
index c51e8e1a37f..310261f6c95 100644
--- a/source/blender/simulation/intern/simulation_solver.cc
+++ b/source/blender/simulation/intern/simulation_solver.cc
@@ -26,57 +26,103 @@ ParticleForce::~ParticleForce()
{
}
+ParticleEmitter::~ParticleEmitter()
+{
+}
+
+static CustomDataType cpp_to_custom_data_type(const fn::CPPType &type)
+{
+ if (type.is<float3>()) {
+ return CD_PROP_FLOAT3;
+ }
+ if (type.is<float>()) {
+ return CD_PROP_FLOAT;
+ }
+ if (type.is<int32_t>()) {
+ return CD_PROP_INT32;
+ }
+ BLI_assert(false);
+ return CD_PROP_FLOAT;
+}
+
+static const fn::CPPType &custom_to_cpp_data_type(CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_FLOAT3:
+ return fn::CPPType::get<float3>();
+ case CD_PROP_FLOAT:
+ return fn::CPPType::get<float>();
+ case CD_PROP_INT32:
+ return fn::CPPType::get<int32_t>();
+ default:
+ BLI_assert(false);
+ return fn::CPPType::get<float>();
+ }
+}
+
class CustomDataAttributesRef {
private:
- Vector<void *> buffers_;
+ Array<void *> buffers_;
uint size_;
- std::unique_ptr<fn::AttributesInfo> info_;
+ const fn::AttributesInfo &info_;
public:
- CustomDataAttributesRef(CustomData &custom_data, uint size)
+ CustomDataAttributesRef(CustomData &custom_data, uint size, const fn::AttributesInfo &info)
+ : buffers_(info.size(), nullptr), size_(size), info_(info)
{
- fn::AttributesInfoBuilder builder;
- for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
- buffers_.append(layer.data);
- switch (layer.type) {
- case CD_PROP_INT32: {
- builder.add<int32_t>(layer.name, 0);
- break;
- }
- case CD_PROP_FLOAT3: {
- builder.add<float3>(layer.name, {0, 0, 0});
- break;
- }
- }
+ for (uint attribute_index : info.index_range()) {
+ StringRefNull name = info.name_of(attribute_index);
+ const fn::CPPType &cpp_type = info.type_of(attribute_index);
+ CustomDataType custom_type = cpp_to_custom_data_type(cpp_type);
+ void *data = CustomData_get_layer_named(&custom_data, custom_type, name.c_str());
+ buffers_[attribute_index] = data;
}
- info_ = std::make_unique<fn::AttributesInfo>(builder);
- size_ = size;
}
operator fn::MutableAttributesRef()
{
- return fn::MutableAttributesRef(*info_, buffers_, size_);
+ return fn::MutableAttributesRef(info_, buffers_, size_);
}
operator fn::AttributesRef() const
{
- return fn::AttributesRef(*info_, buffers_, size_);
+ return fn::AttributesRef(info_, buffers_, size_);
}
};
-static void ensure_attributes_exist(ParticleSimulationState *state)
+static void ensure_attributes_exist(ParticleSimulationState *state, const fn::AttributesInfo &info)
{
- if (CustomData_get_layer_named(&state->attributes, CD_PROP_FLOAT3, "Position") == nullptr) {
- CustomData_add_layer_named(
- &state->attributes, CD_PROP_FLOAT3, CD_CALLOC, nullptr, state->tot_particles, "Position");
- }
- if (CustomData_get_layer_named(&state->attributes, CD_PROP_FLOAT3, "Velocity") == nullptr) {
- CustomData_add_layer_named(
- &state->attributes, CD_PROP_FLOAT3, CD_CALLOC, nullptr, state->tot_particles, "Velocity");
- }
- if (CustomData_get_layer_named(&state->attributes, CD_PROP_INT32, "ID") == nullptr) {
- CustomData_add_layer_named(
- &state->attributes, CD_PROP_INT32, CD_CALLOC, nullptr, state->tot_particles, "ID");
+ bool found_layer_to_remove;
+ do {
+ found_layer_to_remove = false;
+ for (int layer_index = 0; layer_index < state->attributes.totlayer; layer_index++) {
+ CustomDataLayer *layer = &state->attributes.layers[layer_index];
+ BLI_assert(layer->name != nullptr);
+ const fn::CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer->type);
+ StringRefNull name = layer->name;
+ if (!info.has_attribute(name, cpp_type)) {
+ found_layer_to_remove = true;
+ CustomData_free_layer(&state->attributes, layer->type, state->tot_particles, layer_index);
+ break;
+ }
+ }
+ } while (found_layer_to_remove);
+
+ for (uint attribute_index : info.index_range()) {
+ StringRefNull attribute_name = info.name_of(attribute_index);
+ const fn::CPPType &cpp_type = info.type_of(attribute_index);
+ CustomDataType custom_type = cpp_to_custom_data_type(cpp_type);
+ if (CustomData_get_layer_named(&state->attributes, custom_type, attribute_name.c_str()) ==
+ nullptr) {
+ void *data = CustomData_add_layer_named(&state->attributes,
+ custom_type,
+ CD_CALLOC,
+ nullptr,
+ state->tot_particles,
+ attribute_name.c_str());
+ cpp_type.fill_uninitialized(
+ info.default_of(attribute_index), data, (uint)state->tot_particles);
+ }
}
}
@@ -84,48 +130,52 @@ void initialize_simulation_states(Simulation &simulation,
Depsgraph &UNUSED(depsgraph),
const SimulationInfluences &UNUSED(influences))
{
- RandomNumberGenerator rng;
-
- LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation.states) {
- state->tot_particles = 1000;
- CustomData_realloc(&state->attributes, state->tot_particles);
- ensure_attributes_exist(state);
-
- CustomDataAttributesRef custom_data_attributes{state->attributes, (uint)state->tot_particles};
-
- fn::MutableAttributesRef attributes = custom_data_attributes;
- MutableSpan<float3> positions = attributes.get<float3>("Position");
- MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
- MutableSpan<int32_t> ids = attributes.get<int32_t>("ID");
-
- for (uint i : positions.index_range()) {
- positions[i] = {i / 100.0f, 0, 0};
- velocities[i] = {0, rng.get_float() - 0.5f, rng.get_float() - 0.5f};
- ids[i] = i;
- }
- }
+ simulation.current_simulation_time = 0.0f;
}
void solve_simulation_time_step(Simulation &simulation,
- Depsgraph &UNUSED(depsgraph),
+ Depsgraph &depsgraph,
const SimulationInfluences &influences,
float time_step)
{
+ SimulationSolveContext solve_context{simulation, depsgraph, influences};
+ TimeInterval simulation_time_interval{simulation.current_simulation_time, time_step};
+
+ Map<std::string, std::unique_ptr<fn::AttributesInfo>> attribute_infos;
+ Map<std::string, std::unique_ptr<ParticleAllocator>> particle_allocators;
LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation.states) {
- ensure_attributes_exist(state);
+ const fn::AttributesInfoBuilder &builder = *influences.particle_attributes_builder.lookup_as(
+ state->head.name);
+ auto info = std::make_unique<fn::AttributesInfo>(builder);
- CustomDataAttributesRef custom_data_attributes{state->attributes, (uint)state->tot_particles};
+ ensure_attributes_exist(state, *info);
+ particle_allocators.add_new(
+ state->head.name, std::make_unique<ParticleAllocator>(*info, state->next_particle_id));
+ attribute_infos.add_new(state->head.name, std::move(info));
+ }
+
+ LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation.states) {
+ const fn::AttributesInfo &attributes_info = *attribute_infos.lookup_as(state->head.name);
+ CustomDataAttributesRef custom_data_attributes{
+ state->attributes, (uint)state->tot_particles, attributes_info};
fn::MutableAttributesRef attributes = custom_data_attributes;
+
MutableSpan<float3> positions = attributes.get<float3>("Position");
MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
Array<float3> force_vectors{(uint)state->tot_particles, {0, 0, 0}};
const Vector<const ParticleForce *> *forces = influences.particle_forces.lookup_ptr(
state->head.name);
+
if (forces != nullptr) {
+ ParticleChunkContext particle_chunk_context{IndexMask((uint)state->tot_particles),
+ attributes};
+ ParticleForceContext particle_force_context{
+ solve_context, particle_chunk_context, force_vectors};
+
for (const ParticleForce *force : *forces) {
- force->add_force(attributes, force_vectors);
+ force->add_force(particle_force_context);
}
}
@@ -134,6 +184,46 @@ void solve_simulation_time_step(Simulation &simulation,
positions[i] += velocities[i] * time_step;
}
}
+
+ for (const ParticleEmitter *emitter : influences.particle_emitters) {
+ ParticleEmitterContext emitter_context{
+ solve_context, particle_allocators, simulation_time_interval};
+ emitter->emit(emitter_context);
+ }
+
+ LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation.states) {
+ const fn::AttributesInfo &attributes_info = *attribute_infos.lookup_as(state->head.name);
+ ParticleAllocator &allocator = *particle_allocators.lookup_as(state->head.name);
+
+ const uint emitted_particle_amount = allocator.total_allocated();
+ const uint old_particle_amount = state->tot_particles;
+ const uint new_particle_amount = old_particle_amount + emitted_particle_amount;
+
+ CustomData_realloc(&state->attributes, new_particle_amount);
+
+ CustomDataAttributesRef custom_data_attributes{
+ state->attributes, new_particle_amount, attributes_info};
+ fn::MutableAttributesRef attributes = custom_data_attributes;
+
+ uint offset = old_particle_amount;
+ for (fn::MutableAttributesRef emitted_attributes : allocator.get_allocations()) {
+ fn::MutableAttributesRef dst_attributes = attributes.slice(
+ IndexRange(offset, emitted_attributes.size()));
+ for (uint attribute_index : attributes.info().index_range()) {
+ fn::GMutableSpan emitted_data = emitted_attributes.get(attribute_index);
+ fn::GMutableSpan dst = dst_attributes.get(attribute_index);
+ const fn::CPPType &type = dst.type();
+ type.copy_to_uninitialized_n(
+ emitted_data.buffer(), dst.buffer(), emitted_attributes.size());
+ }
+ offset += emitted_attributes.size();
+ }
+
+ state->tot_particles = new_particle_amount;
+ state->next_particle_id += emitted_particle_amount;
+ }
+
+ simulation.current_simulation_time = simulation_time_interval.end();
}
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver.hh b/source/blender/simulation/intern/simulation_solver.hh
index 818bcf067a3..7b37ed0583d 100644
--- a/source/blender/simulation/intern/simulation_solver.hh
+++ b/source/blender/simulation/intern/simulation_solver.hh
@@ -24,19 +24,134 @@
#include "FN_attributes_ref.hh"
+#include "particle_allocator.hh"
+#include "time_interval.hh"
+
struct Depsgraph;
namespace blender::sim {
+class ParticleEmitterContext;
+class ParticleForceContext;
+
+class ParticleEmitter {
+ public:
+ virtual ~ParticleEmitter();
+ virtual void emit(ParticleEmitterContext &context) const = 0;
+};
+
class ParticleForce {
public:
virtual ~ParticleForce();
- virtual void add_force(fn::AttributesRef attributes,
- MutableSpan<float3> r_combined_force) const = 0;
+ virtual void add_force(ParticleForceContext &context) const = 0;
};
struct SimulationInfluences {
Map<std::string, Vector<const ParticleForce *>> particle_forces;
+ Map<std::string, fn::AttributesInfoBuilder *> particle_attributes_builder;
+ Vector<const ParticleEmitter *> particle_emitters;
+};
+
+class SimulationSolveContext {
+ private:
+ Simulation &simulation_;
+ Depsgraph &depsgraph_;
+ const SimulationInfluences &influences_;
+
+ public:
+ SimulationSolveContext(Simulation &simulation,
+ Depsgraph &depsgraph,
+ const SimulationInfluences &influences)
+ : simulation_(simulation), depsgraph_(depsgraph), influences_(influences)
+ {
+ }
+};
+
+class ParticleChunkContext {
+ private:
+ IndexMask index_mask_;
+ fn::MutableAttributesRef attributes_;
+
+ public:
+ ParticleChunkContext(IndexMask index_mask, fn::MutableAttributesRef attributes)
+ : index_mask_(index_mask), attributes_(attributes)
+ {
+ }
+
+ IndexMask index_mask() const
+ {
+ return index_mask_;
+ }
+
+ fn::MutableAttributesRef attributes()
+ {
+ return attributes_;
+ }
+
+ fn::AttributesRef attributes() const
+ {
+ return attributes_;
+ }
+};
+
+class ParticleEmitterContext {
+ private:
+ SimulationSolveContext &solve_context_;
+ Map<std::string, std::unique_ptr<ParticleAllocator>> &particle_allocators_;
+ TimeInterval simulation_time_interval_;
+
+ public:
+ ParticleEmitterContext(SimulationSolveContext &solve_context,
+ Map<std::string, std::unique_ptr<ParticleAllocator>> &particle_allocators,
+ TimeInterval simulation_time_interval)
+ : solve_context_(solve_context),
+ particle_allocators_(particle_allocators),
+ simulation_time_interval_(simulation_time_interval)
+ {
+ }
+
+ ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name)
+ {
+ auto *ptr = particle_allocators_.lookup_ptr_as(particle_simulation_name);
+ if (ptr != nullptr) {
+ return ptr->get();
+ }
+ else {
+ return nullptr;
+ }
+ }
+
+ TimeInterval simulation_time_interval() const
+ {
+ return simulation_time_interval_;
+ }
+};
+
+class ParticleForceContext {
+ private:
+ SimulationSolveContext &solve_context_;
+ const ParticleChunkContext &particle_chunk_context_;
+ MutableSpan<float3> force_dst_;
+
+ public:
+ ParticleForceContext(SimulationSolveContext &solve_context,
+ const ParticleChunkContext &particle_chunk_context,
+ MutableSpan<float3> force_dst)
+ : solve_context_(solve_context),
+ particle_chunk_context_(particle_chunk_context),
+ force_dst_(force_dst)
+ {
+ }
+
+ const ParticleChunkContext &particle_chunk() const
+ {
+ return particle_chunk_context_;
+ }
+
+ MutableSpan<float3> force_dst()
+ {
+ return force_dst_;
+ }
};
void initialize_simulation_states(Simulation &simulation,
diff --git a/source/blender/simulation/intern/simulation_update.cc b/source/blender/simulation/intern/simulation_update.cc
index a3fddbbe18f..5328304863b 100644
--- a/source/blender/simulation/intern/simulation_update.cc
+++ b/source/blender/simulation/intern/simulation_update.cc
@@ -14,7 +14,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "SIM_particle_function.hh"
#include "SIM_simulation_update.hh"
#include "BKE_customdata.h"
@@ -32,6 +31,7 @@
#include "BLI_rand.h"
#include "BLI_vector.hh"
+#include "particle_function.hh"
#include "simulation_collect_influences.hh"
#include "simulation_solver.hh"
@@ -107,28 +107,18 @@ static void add_missing_particle_states(Simulation *simulation, Span<std::string
}
static void reinitialize_empty_simulation_states(Simulation *simulation,
- const nodes::DerivedNodeTree &tree)
+ const SimulationStatesInfo &states_info)
{
- VectorSet<std::string> state_names;
- for (const nodes::DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) {
- state_names.add(dnode_to_path(*dnode));
- }
-
- remove_unused_states(simulation, state_names);
+ remove_unused_states(simulation, states_info.particle_simulation_names);
reset_states(simulation);
- add_missing_particle_states(simulation, state_names);
+ add_missing_particle_states(simulation, states_info.particle_simulation_names);
}
static void update_simulation_state_list(Simulation *simulation,
- const nodes::DerivedNodeTree &tree)
+ const SimulationStatesInfo &states_info)
{
- VectorSet<std::string> state_names;
- for (const nodes::DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) {
- state_names.add(dnode_to_path(*dnode));
- }
-
- remove_unused_states(simulation, state_names);
- add_missing_particle_states(simulation, state_names);
+ remove_unused_states(simulation, states_info.particle_simulation_names);
+ add_missing_particle_states(simulation, states_info.particle_simulation_names);
}
void update_simulation_in_depsgraph(Depsgraph *depsgraph,
@@ -147,16 +137,15 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
Simulation *simulation_orig = (Simulation *)DEG_get_original_id(&simulation_cow->id);
- nodes::NodeTreeRefMap tree_refs;
- /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */
- const nodes::DerivedNodeTree tree{simulation_orig->nodetree, tree_refs};
-
ResourceCollector resources;
SimulationInfluences influences;
- collect_simulation_influences(tree, resources, influences);
+ SimulationStatesInfo states_info;
+
+ /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */
+ collect_simulation_influences(*simulation_orig, resources, influences, states_info);
if (current_frame == 1) {
- reinitialize_empty_simulation_states(simulation_orig, tree);
+ reinitialize_empty_simulation_states(simulation_orig, states_info);
initialize_simulation_states(*simulation_orig, *depsgraph, influences);
simulation_orig->current_frame = 1;
@@ -164,7 +153,7 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
copy_states_to_cow(simulation_orig, simulation_cow);
}
else if (current_frame == simulation_orig->current_frame + 1) {
- update_simulation_state_list(simulation_orig, tree);
+ update_simulation_state_list(simulation_orig, states_info);
float time_step = 1.0f / 24.0f;
solve_simulation_time_step(*simulation_orig, *depsgraph, influences, time_step);
diff --git a/source/blender/simulation/intern/time_interval.hh b/source/blender/simulation/intern/time_interval.hh
new file mode 100644
index 00000000000..49600dd10de
--- /dev/null
+++ b/source/blender/simulation/intern/time_interval.hh
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __SIM_TIME_INTERVAL_HH__
+#define __SIM_TIME_INTERVAL_HH__
+
+#include "BLI_utildefines.h"
+
+namespace blender::sim {
+
+/**
+ * The start time is inclusive and the end time is exclusive. The duration is zero, the interval
+ * describes a single point in time.
+ */
+class TimeInterval {
+ private:
+ float start_;
+ float duration_;
+
+ public:
+ TimeInterval(float start, float duration) : start_(start), duration_(duration)
+ {
+ BLI_assert(duration_ >= 0.0f);
+ }
+
+ float start() const
+ {
+ return start_;
+ }
+
+ float end() const
+ {
+ return start_ + duration_;
+ }
+
+ float duration() const
+ {
+ return duration_;
+ }
+};
+
+} // namespace blender::sim
+
+#endif /* __SIM_TIME_INTERVAL_HH__ */