Mesh: Replace auto smooth with node group #108014

Merged
Hans Goudey merged 149 commits from HooglyBoogly/blender:refactor-mesh-corner-normals-lazy into main 2023-10-20 16:54:20 +02:00
265 changed files with 3755 additions and 2950 deletions
Showing only changes of commit 11668e1a66 - Show all commits

View File

@ -37,7 +37,18 @@ find_path(FFTW3_INCLUDE_DIR
include
)
find_library(FFTW3_LIBRARY
set(_FFTW3_LIBRARIES)
find_library(FFTW3_LIBRARY_F
NAMES
fftw3f
HINTS
${_fftw3_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
find_library(FFTW3_LIBRARY_D
NAMES
fftw3
HINTS
@ -46,17 +57,22 @@ find_library(FFTW3_LIBRARY
lib64 lib
)
list(APPEND _FFTW3_LIBRARIES "${FFTW3_LIBRARY_F}")
list(APPEND _FFTW3_LIBRARIES "${FFTW3_LIBRARY_D}")
# handle the QUIETLY and REQUIRED arguments and set FFTW3_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fftw3 DEFAULT_MSG
FFTW3_LIBRARY FFTW3_INCLUDE_DIR)
_FFTW3_LIBRARIES FFTW3_INCLUDE_DIR)
if(FFTW3_FOUND)
set(FFTW3_LIBRARIES ${FFTW3_LIBRARY})
set(FFTW3_LIBRARIES ${_FFTW3_LIBRARIES})
set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR})
endif()
unset(_FFTW3_LIBRARIES)
mark_as_advanced(
FFTW3_INCLUDE_DIR
FFTW3_LIBRARY

View File

@ -7,7 +7,12 @@ set(SHARED_LIBRARY FALSE) # "Build Shared Library"
set(WITH_C TRUE) # "Build C Module"
set(WITH_DOCS FALSE) # "Build C++ HTML Documentation with Doxygen"
set(WITH_FFMPEG ${WITH_CODEC_FFMPEG}) # "Build With FFMPEG"
set(WITH_FFTW FALSE) # "Build With FFTW"
if(DEFINED WITH_FFTW3) # "Build With FFTW"
set(FFTW_FOUND TRUE)
set(WITH_FFTW ${WITH_FFTW3})
set(FFTW_INCLUDE_DIR ${FFTW3_INCLUDE_DIRS})
set(FFTW_LIBRARY ${FFTW3_LIBRARIES})
endif()
set(WITH_LIBSNDFILE ${WITH_CODEC_SNDFILE}) # "Build With LibSndFile"
set(SEPARATE_C FALSE) # "Build C Binding as separate library"
set(PLUGIN_COREAUDIO FALSE) # "Build CoreAudio Plugin"

View File

@ -1638,7 +1638,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
elif device_type == 'ONEAPI':
import sys
if sys.platform.startswith("win"):
driver_version = "XX.X.101.4314"
driver_version = "XX.X.101.4644"
col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1')
col.label(text=iface_("and Windows driver version %s or newer") % driver_version,
icon='BLANK1', translate=False)

View File

@ -148,13 +148,14 @@ static inline void colorramp_to_array(BL::ColorRamp &ramp,
array<float> &ramp_alpha,
int size)
{
ramp_color.resize(size);
ramp_alpha.resize(size);
const int full_size = size + 1;
ramp_color.resize(full_size);
ramp_alpha.resize(full_size);
for (int i = 0; i < size; i++) {
for (int i = 0; i < full_size; i++) {
float color[4];
ramp.evaluate((float)i / (float)(size - 1), color);
ramp.evaluate(float(i) / float(size), color);
ramp_color[i] = make_float3(color[0], color[1], color[2]);
ramp_alpha[i] = color[3];
}
@ -184,9 +185,10 @@ static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &
{
cumap.update();
BL::CurveMap curve = cumap.curves[0];
data.resize(size);
for (int i = 0; i < size; i++) {
float t = (float)i / (float)(size - 1);
const int full_size = size + 1;
data.resize(full_size);
for (int i = 0; i < full_size; i++) {
float t = float(i) / float(size);
data[i] = cumap.evaluate(curve, t);
}
}
@ -205,10 +207,11 @@ static inline void curvemapping_float_to_array(BL::CurveMapping &cumap,
BL::CurveMap map = cumap.curves[0];
data.resize(size);
const int full_size = size + 1;
data.resize(full_size);
for (int i = 0; i < size; i++) {
float t = min + (float)i / (float)(size - 1) * range;
for (int i = 0; i < full_size; i++) {
float t = min + float(i) / float(size) * range;
data[i] = cumap.evaluate(map, t);
}
}
@ -242,20 +245,21 @@ static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
BL::CurveMap mapG = cumap.curves[1];
BL::CurveMap mapB = cumap.curves[2];
data.resize(size);
const int full_size = size + 1;
data.resize(full_size);
if (rgb_curve) {
BL::CurveMap mapI = cumap.curves[3];
for (int i = 0; i < size; i++) {
const float t = min_x + (float)i / (float)(size - 1) * range_x;
for (int i = 0; i < full_size; i++) {
const float t = min_x + float(i) / float(size) * range_x;
data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
}
}
else {
for (int i = 0; i < size; i++) {
float t = min_x + (float)i / (float)(size - 1) * range_x;
for (int i = 0; i < full_size; i++) {
float t = min_x + float(i) / float(size) * range_x;
data[i] = make_float3(
cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
}

View File

@ -853,10 +853,14 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
/* Compute-runtime (ie. NEO) version is what gets returned by sycl/L0 on Windows
* since Windows driver 101.3268. */
/* The same min compute-runtime version is currently used across Windows and Linux.
* For Windows driver 101.4314, compute-runtime version is 25977. */
static const int lowest_supported_driver_version_win = 1014314;
static const int lowest_supported_driver_version_win = 1014644;
# ifdef _WIN32
/* For Windows driver 101.4644, compute-runtime version is 26771.
* This information is returned by `ocloc query OCL_DRIVER_VERSION`.*/
static const int lowest_supported_driver_version_neo = 26771;
# else
static const int lowest_supported_driver_version_neo = 25812;
# endif
int OneapiDevice::parse_driver_build_version(const sycl::device &device)
{

View File

@ -857,8 +857,13 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
-fsycl-max-parallel-link-jobs=${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS}
-shared
-DWITH_ONEAPI
-ffast-math
-O2
-fno-fast-math
-ffp-contract=fast
-fassociative-math
-freciprocal-math
-fno-signed-zeros
-ffinite-math-only
-D__KERNEL_LOCAL_ATOMIC_SORT__
-o"${cycles_kernel_oneapi_lib}"
-I"${CMAKE_CURRENT_SOURCE_DIR}/.."

View File

@ -222,15 +222,9 @@ ccl_device_forceinline int __float_as_int(float x)
#define fmodf(x, y) sycl::fmod((x), (y))
#define lgammaf(x) sycl::lgamma((x))
/* `sycl::native::cos` precision is not sufficient and `-ffast-math` lets
* the current DPC++ compiler overload `sycl::cos` with it.
* We work around this issue by directly calling the SPIRV implementation which
* provides greater precision. */
#if defined(__SYCL_DEVICE_ONLY__) && defined(__SPIR__)
# define cosf(x) __spirv_ocl_cos(((float)(x)))
#else
# define cosf(x) sycl::cos(((float)(x)))
#endif
/* sycl::native::cos precision is not sufficient when using Nishita Sky node
* with a small sun size. */
#define cosf(x) sycl::cos(((float)(x)))
#define sinf(x) sycl::native::sin(((float)(x)))
#define powf(x, y) sycl::native::powr(((float)(x)), ((float)(y)))
#define tanf(x) sycl::native::tan(((float)(x)))

View File

@ -9,6 +9,8 @@
#define vector3 point
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
#define FRACTAL_VORONOI_X_FX(T) \
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
{ \
@ -20,7 +22,7 @@
Output.Distance = 0.0; \
Output.Color = color(0.0, 0.0, 0.0); \
Output.Position = vector4(0.0, 0.0, 0.0, 0.0); \
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
int zero_input = params.detail == 0.0 || params.roughness == 0.0; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
VoronoiOutput octave; \
@ -71,6 +73,8 @@
return Output; \
}
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
{ \
@ -79,7 +83,7 @@
float scale = 1.0; \
float distance = 8.0; \
\
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
int zero_input = params.detail == 0.0 || params.roughness == 0.0; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \

View File

@ -880,6 +880,8 @@ ccl_device float voronoi_n_sphere_radius(ccl_private const VoronoiParams &params
/* **** Fractal Voronoi **** */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
template<typename T>
ccl_device VoronoiOutput fractal_voronoi_x_fx(ccl_private const VoronoiParams &params,
const T coord)
@ -889,8 +891,7 @@ ccl_device VoronoiOutput fractal_voronoi_x_fx(ccl_private const VoronoiParams &p
float scale = 1.0f;
VoronoiOutput output;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f ||
params.lacunarity == 0.0f;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceilf(params.detail); ++i) {
VoronoiOutput octave = (params.feature == NODE_VORONOI_F2) ?
@ -936,6 +937,8 @@ ccl_device VoronoiOutput fractal_voronoi_x_fx(ccl_private const VoronoiParams &p
return output;
}
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
template<typename T>
ccl_device float fractal_voronoi_distance_to_edge(ccl_private const VoronoiParams &params,
const T coord)
@ -945,8 +948,7 @@ ccl_device float fractal_voronoi_distance_to_edge(ccl_private const VoronoiParam
float scale = 1.0f;
float distance = 8.0f;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f ||
params.lacunarity == 0.0f;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceilf(params.detail); ++i) {
const float octave_distance = voronoi_distance_to_edge(params, coord * scale);

View File

@ -7,6 +7,7 @@
*/
#include "GHOST_SystemWayland.hh"
#include "GHOST_Context.hh"
#include "GHOST_Event.hh"
#include "GHOST_EventButton.hh"
#include "GHOST_EventCursor.hh"

View File

@ -932,13 +932,15 @@ static void xdg_toplevel_handle_configure(void *data,
std::lock_guard lock_frame_guard{win->frame_pending_mutex};
#endif
if (win->frame.fractional_scale) {
win->frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame, width);
win->frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame, height);
}
else {
win->frame_pending.size[0] = width * win->frame.buffer_scale;
win->frame_pending.size[1] = height * win->frame.buffer_scale;
const int32_t size[2] = {width, height};
for (int i = 0; i < 2; i++) {
if (size[i] == 0) {
/* Values may be zero, in this case the client should choose. */
continue;
}
win->frame_pending.size[i] = win->frame.fractional_scale ?
gwl_window_fractional_to_viewport_round(win->frame, size[i]) :
(size[i] * win->frame.buffer_scale);
}
win->frame_pending.is_maximised = false;
@ -1059,9 +1061,9 @@ static const wp_fractional_scale_v1_listener wp_fractional_scale_listener = {
static CLG_LogRef LOG_WL_LIBDECOR_FRAME = {"ghost.wl.handle.libdecor_frame"};
# define LOG (&LOG_WL_LIBDECOR_FRAME)
static void frame_handle_configure(libdecor_frame *frame,
libdecor_configuration *configuration,
void *data)
static void libdecor_frame_handle_configure(libdecor_frame *frame,
libdecor_configuration *configuration,
void *data)
{
CLOG_INFO(LOG, 2, "configure");
@ -1133,7 +1135,7 @@ static void frame_handle_configure(libdecor_frame *frame,
}
}
static void frame_handle_close(libdecor_frame * /*frame*/, void *data)
static void libdecor_frame_handle_close(libdecor_frame * /*frame*/, void *data)
{
CLOG_INFO(LOG, 2, "close");
@ -1142,7 +1144,7 @@ static void frame_handle_close(libdecor_frame * /*frame*/, void *data)
win->ghost_window->close();
}
static void frame_handle_commit(libdecor_frame * /*frame*/, void *data)
static void libdecor_frame_handle_commit(libdecor_frame * /*frame*/, void *data)
{
CLOG_INFO(LOG, 2, "commit");
@ -1156,9 +1158,9 @@ static void frame_handle_commit(libdecor_frame * /*frame*/, void *data)
/* NOTE: cannot be `const` because of the LIBDECOR API. */
static libdecor_frame_interface libdecor_frame_iface = {
frame_handle_configure,
frame_handle_close,
frame_handle_commit,
libdecor_frame_handle_configure,
libdecor_frame_handle_close,
libdecor_frame_handle_commit,
};
# undef LOG

View File

@ -285,6 +285,13 @@ def load_scripts(*, reload_scripts=False, refresh_scripts=False):
del _global_loaded_modules[:]
# Update key-maps to account for operators no longer existing.
# Typically unloading operators would refresh the event system (such as disabling an add-on)
# however reloading scripts re-enable all add-ons immediately (which may inspect key-maps).
# For this reason it's important to update key-maps which will have been tagged to update.
# Without this, add-on register functions accessing key-map properties can crash, see: #111702.
_bpy.context.window_manager.keyconfigs.update()
from bpy_restrict_state import RestrictBlend
with RestrictBlend():

View File

@ -97,26 +97,6 @@ class Prefs(bpy.types.KeyConfigPreferences):
default=False,
update=update_fn,
)
# Experimental: only show with developer extras, see: #96544.
use_tweak_select_passthrough: BoolProperty(
name="Tweak Select: Mouse Select & Move",
description=(
"The tweak tool is activated immediately instead of placing the cursor. "
"This is an experimental preference and may be removed"
),
default=False,
update=update_fn,
)
# Experimental: only show with developer extras, see: #96544.
use_tweak_tool_lmb_interaction: BoolProperty(
name="Tweak Tool: Left Mouse Select & Move",
description=(
"The tweak tool is activated immediately instead of placing the cursor. "
"This is an experimental preference and may be removed"
),
default=False,
update=update_fn,
)
use_alt_click_leader: BoolProperty(
name="Alt Click Tool Prompt",
@ -313,12 +293,6 @@ class Prefs(bpy.types.KeyConfigPreferences):
row = sub.row()
row.prop(self, "use_select_all_toggle")
if show_developer_ui:
row = sub.row()
row.prop(self, "use_tweak_select_passthrough")
if show_developer_ui and (not is_select_left):
row = sub.row()
row.prop(self, "use_tweak_tool_lmb_interaction")
if show_developer_ui:
row = sub.row()
row.prop(self, "use_region_toggle_pie")
@ -385,11 +359,6 @@ def load():
# Otherwise LMB activates the fallback tool and RMB always tweak-selects.
(kc_prefs.rmb_action != 'FALLBACK_TOOL')
),
use_tweak_select_passthrough=(show_developer_ui and kc_prefs.use_tweak_select_passthrough),
use_tweak_tool_lmb_interaction=(
False if is_select_left else
(show_developer_ui and kc_prefs.use_tweak_tool_lmb_interaction)
),
use_alt_tool_or_cursor=(
(not use_mouse_emulate_3_button) and
(kc_prefs.use_alt_tool if is_select_left else kc_prefs.use_alt_cursor)
@ -397,8 +366,9 @@ def load():
use_alt_click_leader=kc_prefs.use_alt_click_leader,
use_pie_click_drag=kc_prefs.use_pie_click_drag,
use_file_single_click=kc_prefs.use_file_single_click,
experimental=prefs.experimental,
use_alt_navigation=kc_prefs.use_alt_navigation,
# Experimental features.
use_experimental_grease_pencil_version3=prefs.experimental.use_grease_pencil_version3,
),
)

View File

@ -41,7 +41,6 @@ class Params:
# - Click selects only the item at the cursor position.
# See: #97032.
"use_tweak_select_passthrough",
"use_tweak_tool_lmb_interaction",
"use_mouse_emulate_3_button",
# User preferences:
@ -78,6 +77,14 @@ class Params:
# File selector actions on single click.
"use_file_single_click",
# Experimental variables:
# Options for experimental features.
#
# NOTE: don't pass the experimental struct directly as this makes it less
# clear which experimental options impact shortcuts. Further, any experimental option
# that adjust shortcuts need to reload the key-configuration (see: `rna_userdef.cc`).
"use_experimental_grease_pencil_version3",
# Convenience variables:
# (derived from other settings).
#
@ -99,8 +106,6 @@ class Params:
# Since this means with RMB select enabled in edit-mode for e.g.
# `Ctrl-LMB` would be caught by box-select instead of add/extrude.
"tool_maybe_tweak_event",
# Access to bpy.context.preferences.experimental
"experimental",
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
"use_alt_navigation",
)
@ -120,8 +125,6 @@ class Params:
use_gizmo_drag=True,
use_fallback_tool=False,
use_fallback_tool_select_handled=True,
use_tweak_select_passthrough=False,
use_tweak_tool_lmb_interaction=False,
use_v3d_tab_menu=False,
use_v3d_shade_ex_pie=False,
use_v3d_mmb_pan=False,
@ -131,8 +134,8 @@ class Params:
use_file_single_click=False,
v3d_tilde_action='VIEW',
v3d_alt_mmb_drag_action='RELATIVE',
experimental=None,
use_alt_navigation=True,
use_experimental_grease_pencil_version3=False,
):
from sys import platform
self.apple = platform == 'darwin'
@ -152,8 +155,6 @@ class Params:
else:
self.tool_maybe_tweak_value = 'CLICK_DRAG'
self.use_tweak_tool_lmb_interaction = use_tweak_tool_lmb_interaction
self.context_menu_event = {"type": 'W', "value": 'PRESS'}
# Use the "cursor" functionality for RMB select.
@ -174,7 +175,6 @@ class Params:
self.action_mouse = 'RIGHTMOUSE'
self.tool_mouse = 'LEFTMOUSE'
self.tool_maybe_tweak_value = 'CLICK_DRAG'
self.use_tweak_tool_lmb_interaction = False
if self.legacy:
self.context_menu_event = {"type": 'W', "value": 'PRESS'}
@ -211,10 +211,13 @@ class Params:
self.use_file_single_click = use_file_single_click
self.use_tweak_select_passthrough = use_tweak_select_passthrough
self.use_tweak_select_passthrough = not legacy
self.use_fallback_tool = use_fallback_tool
# Experimental variables:
self.use_experimental_grease_pencil_version3 = use_experimental_grease_pencil_version3
# Convenience variables:
self.use_fallback_tool_select_handled = (
True if (select_mouse == 'LEFT') else
@ -234,8 +237,6 @@ class Params:
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
self.use_alt_navigation = use_alt_navigation
self.experimental = experimental
# ------------------------------------------------------------------------------
# Constants
@ -579,7 +580,7 @@ def _template_items_tool_select(
select_passthrough = params.use_tweak_select_passthrough
else:
if not cursor_prioritize:
select_passthrough = params.use_tweak_tool_lmb_interaction
select_passthrough = True
if select_passthrough:
return [
@ -3884,7 +3885,7 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
)
# Draw
if params.experimental and params.experimental.use_grease_pencil_version3:
if params.use_experimental_grease_pencil_version3:
items.extend([
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},

View File

@ -5,41 +5,80 @@
import bpy
from bpy.types import Menu
from bl_ui import node_add_menu
from bpy.app.translations import (
pgettext_iface as iface_,
)
class NODE_MT_category_COMP_INPUT(Menu):
bl_idname = "NODE_MT_category_COMP_INPUT"
bl_label = "Input"
def draw(self, _context):
def draw(self, context):
snode = context.space_data
is_group = (len(snode.path) > 1)
layout = self.layout
layout.menu("NODE_MT_category_COMP_INPUT_CONSTANT")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeBokehImage")
node_add_menu.add_node_type(layout, "CompositorNodeImage")
node_add_menu.add_node_type(layout, "CompositorNodeMask")
node_add_menu.add_node_type(layout, "CompositorNodeMovieClip")
node_add_menu.add_node_type(layout, "CompositorNodeRLayers")
node_add_menu.add_node_type(layout, "CompositorNodeRGB")
node_add_menu.add_node_type(layout, "CompositorNodeSceneTime")
node_add_menu.add_node_type(layout, "CompositorNodeTexture")
node_add_menu.add_node_type(layout, "CompositorNodeTime")
node_add_menu.add_node_type(layout, "CompositorNodeTrackPos")
if is_group:
layout.separator()
node_add_menu.add_node_type(layout, "NodeGroupInput")
layout.separator()
layout.menu("NODE_MT_category_COMP_INPUT_SCENE")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_INPUT_CONSTANT(Menu):
bl_idname = "NODE_MT_category_COMP_INPUT_CONSTANT"
bl_label = "Constant"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeRGB")
node_add_menu.add_node_type(layout, "CompositorNodeValue")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_INPUT_SCENE(Menu):
bl_idname = "NODE_MT_category_COMP_INPUT_SCENE"
bl_label = "Scene"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeRLayers")
node_add_menu.add_node_type(layout, "CompositorNodeSceneTime")
node_add_menu.add_node_type(layout, "CompositorNodeTime")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_OUTPUT(Menu):
bl_idname = "NODE_MT_category_COMP_OUTPUT"
bl_label = "Output"
def draw(self, _context):
layout = self.layout
def draw(self, context):
snode = context.space_data
is_group = (len(snode.path) > 1)
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeComposite")
node_add_menu.add_node_type(layout, "CompositorNodeOutputFile")
node_add_menu.add_node_type(layout, "CompositorNodeLevels")
node_add_menu.add_node_type(layout, "CompositorNodeSplitViewer")
node_add_menu.add_node_type(layout, "CompositorNodeViewer")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeOutputFile")
if is_group:
layout.separator()
node_add_menu.add_node_type(layout, "NodeGroupOutput")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
@ -50,7 +89,27 @@ class NODE_MT_category_COMP_COLOR(Menu):
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeAlphaOver")
layout.menu("NODE_MT_category_COMP_COLOR_ADJUST")
layout.separator()
layout.menu("NODE_MT_category_COMP_COLOR_MIX")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodePremulKey")
node_add_menu.add_node_type(layout, "CompositorNodeValToRGB")
node_add_menu.add_node_type(layout, "CompositorNodeConvertColorSpace")
node_add_menu.add_node_type(layout, "CompositorNodeSetAlpha")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeInvert")
node_add_menu.add_node_type(layout, "CompositorNodeRGBToBW")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_COLOR_ADJUST(Menu):
bl_idname = "NODE_MT_category_COMP_COLOR_ADJUST"
bl_label = "Adjust"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeBrightContrast")
node_add_menu.add_node_type(layout, "CompositorNodeColorBalance")
node_add_menu.add_node_type(layout, "CompositorNodeColorCorrection")
@ -58,35 +117,27 @@ class NODE_MT_category_COMP_COLOR(Menu):
node_add_menu.add_node_type(layout, "CompositorNodeGamma")
node_add_menu.add_node_type(layout, "CompositorNodeHueCorrect")
node_add_menu.add_node_type(layout, "CompositorNodeHueSat")
node_add_menu.add_node_type(layout, "CompositorNodeInvert")
node_add_menu.add_node_type(layout, "CompositorNodeMixRGB")
node_add_menu.add_node_type(layout, "CompositorNodePosterize")
node_add_menu.add_node_type(layout, "CompositorNodeCurveRGB")
node_add_menu.add_node_type(layout, "CompositorNodeTonemap")
node_add_menu.add_node_type(layout, "CompositorNodeZcombine")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_CONVERTER(Menu):
bl_idname = "NODE_MT_category_COMP_CONVERTER"
bl_label = "Converter"
class NODE_MT_category_COMP_COLOR_MIX(Menu):
bl_idname = "NODE_MT_category_COMP_COLOR_MIX"
bl_label = "Mix"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodePremulKey")
node_add_menu.add_node_type(layout, "CompositorNodeValToRGB")
node_add_menu.add_node_type(layout, "CompositorNodeAlphaOver")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeCombineColor")
node_add_menu.add_node_type(layout, "CompositorNodeCombineXYZ")
node_add_menu.add_node_type(layout, "CompositorNodeConvertColorSpace")
node_add_menu.add_node_type(layout, "CompositorNodeIDMask")
node_add_menu.add_node_type(layout, "CompositorNodeMath")
node_add_menu.add_node_type(layout, "CompositorNodeRGBToBW")
node_add_menu.add_node_type(layout, "CompositorNodeSeparateColor")
node_add_menu.add_node_type(layout, "CompositorNodeSeparateXYZ")
node_add_menu.add_node_type(layout, "CompositorNodeSetAlpha")
node_add_menu.add_node_type(layout, "CompositorNodeSwitchView")
layout.separator()
node_add_menu.add_node_type(
layout, "CompositorNodeMixRGB",
label=iface_("Mix Color"))
node_add_menu.add_node_type(layout, "CompositorNodeZcombine")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
@ -96,91 +147,41 @@ class NODE_MT_category_COMP_FILTER(Menu):
def draw(self, _context):
layout = self.layout
layout.menu("NODE_MT_category_COMP_FILTER_BLUR")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeAntiAliasing")
node_add_menu.add_node_type(layout, "CompositorNodeDenoise")
node_add_menu.add_node_type(layout, "CompositorNodeDespeckle")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeDilateErode")
node_add_menu.add_node_type(layout, "CompositorNodeInpaint")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeFilter")
node_add_menu.add_node_type(layout, "CompositorNodeGlare")
node_add_menu.add_node_type(layout, "CompositorNodeKuwahara")
node_add_menu.add_node_type(layout, "CompositorNodePixelate")
node_add_menu.add_node_type(layout, "CompositorNodePosterize")
node_add_menu.add_node_type(layout, "CompositorNodeSunBeams")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_FILTER_BLUR(Menu):
bl_idname = "NODE_MT_category_COMP_FILTER_BLUR"
bl_label = "Blur"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeBilateralblur")
node_add_menu.add_node_type(layout, "CompositorNodeBlur")
node_add_menu.add_node_type(layout, "CompositorNodeBokehBlur")
node_add_menu.add_node_type(layout, "CompositorNodeDefocus")
node_add_menu.add_node_type(layout, "CompositorNodeDenoise")
node_add_menu.add_node_type(layout, "CompositorNodeDespeckle")
node_add_menu.add_node_type(layout, "CompositorNodeDilateErode")
node_add_menu.add_node_type(layout, "CompositorNodeDBlur")
node_add_menu.add_node_type(layout, "CompositorNodeFilter")
node_add_menu.add_node_type(layout, "CompositorNodeGlare")
node_add_menu.add_node_type(layout, "CompositorNodeInpaint")
node_add_menu.add_node_type(layout, "CompositorNodeKuwahara")
node_add_menu.add_node_type(layout, "CompositorNodePixelate")
node_add_menu.add_node_type(layout, "CompositorNodeSunBeams")
node_add_menu.add_node_type(layout, "CompositorNodeVecBlur")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_VECTOR(Menu):
bl_idname = "NODE_MT_category_COMP_VECTOR"
bl_label = "Vector"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeMapRange")
node_add_menu.add_node_type(layout, "CompositorNodeMapValue")
node_add_menu.add_node_type(layout, "CompositorNodeNormal")
node_add_menu.add_node_type(layout, "CompositorNodeNormalize")
node_add_menu.add_node_type(layout, "CompositorNodeCurveVec")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_MATTE(Menu):
bl_idname = "NODE_MT_category_COMP_MATTE"
bl_label = "Matte"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeBoxMask")
node_add_menu.add_node_type(layout, "CompositorNodeChannelMatte")
node_add_menu.add_node_type(layout, "CompositorNodeChromaMatte")
node_add_menu.add_node_type(layout, "CompositorNodeColorMatte")
node_add_menu.add_node_type(layout, "CompositorNodeColorSpill")
node_add_menu.add_node_type(layout, "CompositorNodeCryptomatteV2")
node_add_menu.add_node_type(layout, "CompositorNodeCryptomatte")
node_add_menu.add_node_type(layout, "CompositorNodeDiffMatte")
node_add_menu.add_node_type(layout, "CompositorNodeDistanceMatte")
node_add_menu.add_node_type(layout, "CompositorNodeDoubleEdgeMask")
node_add_menu.add_node_type(layout, "CompositorNodeEllipseMask")
node_add_menu.add_node_type(layout, "CompositorNodeKeying")
node_add_menu.add_node_type(layout, "CompositorNodeKeyingScreen")
node_add_menu.add_node_type(layout, "CompositorNodeLumaMatte")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_DISTORT(Menu):
bl_idname = "NODE_MT_category_COMP_DISTORT"
bl_label = "Distort"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeCornerPin")
node_add_menu.add_node_type(layout, "CompositorNodeCrop")
node_add_menu.add_node_type(layout, "CompositorNodeDisplace")
node_add_menu.add_node_type(layout, "CompositorNodeFlip")
node_add_menu.add_node_type(layout, "CompositorNodeLensdist")
node_add_menu.add_node_type(layout, "CompositorNodeMapUV")
node_add_menu.add_node_type(layout, "CompositorNodeMovieDistortion")
node_add_menu.add_node_type(layout, "CompositorNodePlaneTrackDeform")
node_add_menu.add_node_type(layout, "CompositorNodeRotate")
node_add_menu.add_node_type(layout, "CompositorNodeScale")
node_add_menu.add_node_type(layout, "CompositorNodeStabilize")
node_add_menu.add_node_type(layout, "CompositorNodeTransform")
node_add_menu.add_node_type(layout, "CompositorNodeTranslate")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_GROUP(Menu):
bl_idname = "NODE_MT_category_COMP_GROUP"
bl_label = "Group"
@ -191,6 +192,116 @@ class NODE_MT_category_COMP_GROUP(Menu):
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_KEYING(Menu):
bl_idname = "NODE_MT_category_COMP_KEYING"
bl_label = "Keying"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeChannelMatte")
node_add_menu.add_node_type(layout, "CompositorNodeChromaMatte")
node_add_menu.add_node_type(layout, "CompositorNodeColorMatte")
node_add_menu.add_node_type(layout, "CompositorNodeColorSpill")
node_add_menu.add_node_type(layout, "CompositorNodeDiffMatte")
node_add_menu.add_node_type(layout, "CompositorNodeDistanceMatte")
node_add_menu.add_node_type(layout, "CompositorNodeKeying")
node_add_menu.add_node_type(layout, "CompositorNodeKeyingScreen")
node_add_menu.add_node_type(layout, "CompositorNodeLumaMatte")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_MASK(Menu):
bl_idname = "NODE_MT_category_COMP_MASK"
bl_label = "Mask"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeCryptomatteV2")
node_add_menu.add_node_type(layout, "CompositorNodeCryptomatte")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeBoxMask")
node_add_menu.add_node_type(layout, "CompositorNodeEllipseMask")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeDoubleEdgeMask")
node_add_menu.add_node_type(layout, "CompositorNodeIDMask")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_TRACKING(Menu):
bl_idname = "NODE_MT_category_COMP_TRACKING"
bl_label = "Tracking"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodePlaneTrackDeform")
node_add_menu.add_node_type(layout, "CompositorNodeStabilize")
node_add_menu.add_node_type(layout, "CompositorNodeTrackPos")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_TRANSFORM(Menu):
bl_idname = "NODE_MT_category_COMP_TRANSFORM"
bl_label = "Transform"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeRotate")
node_add_menu.add_node_type(layout, "CompositorNodeScale")
node_add_menu.add_node_type(layout, "CompositorNodeTransform")
node_add_menu.add_node_type(layout, "CompositorNodeTranslate")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeCornerPin")
node_add_menu.add_node_type(layout, "CompositorNodeCrop")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeDisplace")
node_add_menu.add_node_type(layout, "CompositorNodeFlip")
node_add_menu.add_node_type(layout, "CompositorNodeMapUV")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeLensdist")
node_add_menu.add_node_type(layout, "CompositorNodeMovieDistortion")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_UTIL(Menu):
bl_idname = "NODE_MT_category_COMP_UTIL"
bl_label = "Utilities"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeMapRange")
node_add_menu.add_node_type(layout, "CompositorNodeMapValue")
node_add_menu.add_node_type(layout, "CompositorNodeMath")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeLevels")
node_add_menu.add_node_type(layout, "CompositorNodeNormalize")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeSwitch")
node_add_menu.add_node_type(
layout, "CompositorNodeSwitchView",
label=iface_("Switch Stereo View"))
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_VECTOR(Menu):
bl_idname = "NODE_MT_category_COMP_VECTOR"
bl_label = "Vector"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "CompositorNodeCombineXYZ")
node_add_menu.add_node_type(layout, "CompositorNodeSeparateXYZ")
layout.separator()
node_add_menu.add_node_type(layout, "CompositorNodeNormal")
node_add_menu.add_node_type(layout, "CompositorNodeCurveVec")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_COMP_LAYOUT(Menu):
bl_idname = "NODE_MT_category_COMP_LAYOUT"
bl_label = "Layout"
@ -213,10 +324,15 @@ class NODE_MT_compositing_node_add_all(Menu):
layout.menu("NODE_MT_category_COMP_OUTPUT")
layout.separator()
layout.menu("NODE_MT_category_COMP_COLOR")
layout.menu("NODE_MT_category_COMP_CONVERTER")
layout.menu("NODE_MT_category_COMP_DISTORT")
layout.menu("NODE_MT_category_COMP_FILTER")
layout.menu("NODE_MT_category_COMP_MATTE")
layout.separator()
layout.menu("NODE_MT_category_COMP_KEYING")
layout.menu("NODE_MT_category_COMP_MASK")
layout.separator()
layout.menu("NODE_MT_category_COMP_TRACKING")
layout.separator()
layout.menu("NODE_MT_category_COMP_TRANSFORM")
layout.menu("NODE_MT_category_COMP_UTIL")
layout.menu("NODE_MT_category_COMP_VECTOR")
layout.separator()
layout.menu("NODE_MT_category_COMP_GROUP")
@ -228,13 +344,20 @@ class NODE_MT_compositing_node_add_all(Menu):
classes = (
NODE_MT_compositing_node_add_all,
NODE_MT_category_COMP_INPUT,
NODE_MT_category_COMP_INPUT_CONSTANT,
NODE_MT_category_COMP_INPUT_SCENE,
NODE_MT_category_COMP_OUTPUT,
NODE_MT_category_COMP_COLOR,
NODE_MT_category_COMP_CONVERTER,
NODE_MT_category_COMP_COLOR_ADJUST,
NODE_MT_category_COMP_COLOR_MIX,
NODE_MT_category_COMP_FILTER,
NODE_MT_category_COMP_FILTER_BLUR,
NODE_MT_category_COMP_KEYING,
NODE_MT_category_COMP_MASK,
NODE_MT_category_COMP_TRACKING,
NODE_MT_category_COMP_TRANSFORM,
NODE_MT_category_COMP_UTIL,
NODE_MT_category_COMP_VECTOR,
NODE_MT_category_COMP_MATTE,
NODE_MT_category_COMP_DISTORT,
NODE_MT_category_COMP_GROUP,
NODE_MT_category_COMP_LAYOUT,
)

View File

@ -224,12 +224,6 @@ class BONE_PT_relations(BoneButtonsPanel, Panel):
bone = context.edit_bone
col = layout.column()
col.use_property_split = False
col.prop(bone, "layers", text="")
col.use_property_split = True
col = layout.column()
col.separator()
if context.bone:
col.prop(bone, "parent")

View File

@ -302,6 +302,7 @@ class GRAPH_MT_key_blending(Menu):
layout.operator("graph.blend_offset", text="Blend Offset")
layout.operator("graph.blend_to_ease", text="Blend to Ease")
layout.operator("graph.match_slope", text="Match Slope")
layout.operator("graph.shear", text="Shear Keys")
class GRAPH_MT_key_smoothing(Menu):

View File

@ -962,7 +962,11 @@ class SEQUENCER_MT_strip(Menu):
if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator_menu_enum("sequencer.strip_video_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
else:
layout.separator()
layout.operator_menu_enum("sequencer.strip_sound_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if strip_type in {
@ -1103,17 +1107,19 @@ class SEQUENCER_MT_context_menu(Menu):
if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator_menu_enum("sequencer.strip_video_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if selected_sequences_count >= 2:
layout.separator()
col = layout.column()
col.menu("SEQUENCER_MT_add_transitions", text="Add Transition")
elif selected_sequences_count >= 2:
else:
layout.separator()
layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")
layout.operator_menu_enum("sequencer.strip_sound_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if selected_sequences_count >= 2:
layout.separator()
layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")
if selected_sequences_count >= 1:
col = layout.column()
@ -2503,8 +2509,13 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
strip = context.active_sequence_strip
ed = context.scene.sequence_editor
if strip.type == 'SOUND':
sound = strip.sound
else:
sound = None
layout.prop(strip, "use_linear_modifiers")
if sound is None:
layout.prop(strip, "use_linear_modifiers")
layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
layout.operator("sequencer.strip_modifier_copy")
@ -2531,45 +2542,78 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name
if mod.show_expanded:
row = box.row()
row.prop(mod, "input_mask_type", expand=True)
if mod.input_mask_type == 'STRIP':
sequences_object = ed
if ed.meta_stack:
sequences_object = ed.meta_stack[-1]
box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
else:
box.prop(mod, "input_mask_id")
if sound is None:
row = box.row()
row.prop(mod, "mask_time", expand=True)
row.prop(mod, "input_mask_type", expand=True)
if mod.type == 'COLOR_BALANCE':
box.prop(mod, "color_multiply")
draw_color_balance(box, mod.color_balance)
elif mod.type == 'CURVES':
box.template_curve_mapping(mod, "curve_mapping", type='COLOR', show_tone=True)
elif mod.type == 'HUE_CORRECT':
box.template_curve_mapping(mod, "curve_mapping", type='HUE')
elif mod.type == 'BRIGHT_CONTRAST':
col = box.column()
col.prop(mod, "bright")
col.prop(mod, "contrast")
elif mod.type == 'WHITE_BALANCE':
col = box.column()
col.prop(mod, "white_value")
elif mod.type == 'TONEMAP':
col = box.column()
col.prop(mod, "tonemap_type")
if mod.tonemap_type == 'RD_PHOTORECEPTOR':
col.prop(mod, "intensity")
if mod.input_mask_type == 'STRIP':
sequences_object = ed
if ed.meta_stack:
sequences_object = ed.meta_stack[-1]
box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
else:
box.prop(mod, "input_mask_id")
row = box.row()
row.prop(mod, "mask_time", expand=True)
if mod.type == 'COLOR_BALANCE':
box.prop(mod, "color_multiply")
draw_color_balance(box, mod.color_balance)
elif mod.type == 'CURVES':
box.template_curve_mapping(mod, "curve_mapping", type='COLOR', show_tone=True)
elif mod.type == 'HUE_CORRECT':
box.template_curve_mapping(mod, "curve_mapping", type='HUE')
elif mod.type == 'BRIGHT_CONTRAST':
col = box.column()
col.prop(mod, "bright")
col.prop(mod, "contrast")
col.prop(mod, "adaptation")
col.prop(mod, "correction")
elif mod.tonemap_type == 'RH_SIMPLE':
col.prop(mod, "key")
col.prop(mod, "offset")
col.prop(mod, "gamma")
elif mod.type == 'WHITE_BALANCE':
col = box.column()
col.prop(mod, "white_value")
elif mod.type == 'TONEMAP':
col = box.column()
col.prop(mod, "tonemap_type")
if mod.tonemap_type == 'RD_PHOTORECEPTOR':
col.prop(mod, "intensity")
col.prop(mod, "contrast")
col.prop(mod, "adaptation")
col.prop(mod, "correction")
elif mod.tonemap_type == 'RH_SIMPLE':
col.prop(mod, "key")
col.prop(mod, "offset")
col.prop(mod, "gamma")
else:
if mod.type == 'SOUND_EQUALIZER':
eq_row = box.row()
# eq_graphs = eq_row.operator_menu_enum("sequencer.strip_modifier_equalizer_redefine", "graphs")
# eq_graphs.name = mod.name
flow = box.grid_flow(
row_major=True,
columns=0,
even_columns=True,
even_rows=False,
align=False,
)
for sound_eq in mod.graphics:
col = flow.column()
box = col.box()
split = box.split(factor=0.4)
split.label(text="%.2f" % sound_eq.curve_mapping.clip_min_x)
split.label(text="Hz")
split.alignment = "RIGHT"
split.label(text="%.2f" % sound_eq.curve_mapping.clip_max_x)
box.template_curve_mapping(
sound_eq,
"curve_mapping",
type='NONE',
levels=False,
brush=True,
use_negative_slope=True,
show_tone=False,
)
second_row = col.row()
second_row.label(text="dB")
second_row.alignment = 'CENTER'
class SEQUENCER_PT_annotation(AnnotationDataPanel, SequencerButtonsPanel_Output, Panel):

View File

@ -123,21 +123,13 @@ class TIME_MT_view(Menu):
scene = context.scene
st = context.space_data
layout.prop(st, "show_region_hud")
layout.menu("INFO_MT_area")
layout.separator()
layout.prop(st, "show_seconds")
layout.prop(st, "show_locked_time")
layout.separator()
layout.prop(st, "show_markers")
layout.separator()
layout.prop(scene, "show_keys_from_selected_only")
layout.prop(st.dopesheet, "show_only_errors")
# NOTE: "action" now, since timeline is in the dopesheet editor, instead of as own editor
layout.operator("action.view_frame")
layout.operator("action.view_all")
layout.separator()
@ -145,13 +137,21 @@ class TIME_MT_view(Menu):
layout.separator()
# NOTE: "action" now, since timeline is in the dopesheet editor, instead of as own editor
layout.operator("action.view_all")
layout.operator("action.view_frame")
layout.prop(st.dopesheet, "show_only_errors")
layout.prop(scene, "show_keys_from_selected_only")
layout.separator()
layout.menu("INFO_MT_area")
layout.prop(st, "show_markers")
layout.separator()
layout.prop(st, "show_locked_time")
layout.prop(st, "show_seconds")
layout.separator()
layout.prop(st, "show_region_hud")
class TIME_MT_cache(Menu):
@ -182,27 +182,14 @@ def marker_menu_generic(layout, context):
# layout.operator_context = 'EXEC_REGION_WIN'
layout.column()
layout.operator("marker.add", text="Add Marker")
layout.operator("marker.duplicate", text="Duplicate Marker")
if len(bpy.data.scenes) > 10:
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY')
else:
layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene")
layout.operator("marker.delete", text="Delete Marker")
tool_settings = context.tool_settings
layout.prop(tool_settings, "lock_markers")
layout.separator()
props = layout.operator("wm.call_panel", text="Rename Marker")
props.name = "TOPBAR_PT_name_marker"
props.keep_open = False
layout.operator("marker.move", text="Move Marker")
layout.separator()
layout.menu('NLA_MT_marker_select')
layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
layout.separator()
@ -210,12 +197,28 @@ def marker_menu_generic(layout, context):
layout.separator()
layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
layout.menu('NLA_MT_marker_select')
layout.separator()
tool_settings = context.tool_settings
layout.prop(tool_settings, "lock_markers")
layout.operator("marker.move", text="Move Marker")
props = layout.operator("wm.call_panel", text="Rename Marker")
props.name = "TOPBAR_PT_name_marker"
props.keep_open = False
layout.separator()
layout.operator("marker.delete", text="Delete Marker")
if len(bpy.data.scenes) > 10:
layout.operator_context = 'INVOKE_DEFAULT'
layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY')
else:
layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene")
layout.operator("marker.duplicate", text="Duplicate Marker")
layout.operator("marker.add", text="Add Marker")
###################################

View File

@ -923,23 +923,23 @@ class USERPREF_PT_theme_interface_state(ThemePanel, CenterAlignMixIn, Panel):
col = flow.column(align=True)
col.prop(ui_state, "inner_anim")
col.prop(ui_state, "inner_anim_sel")
col.prop(ui_state, "inner_anim_sel", text="Selected")
col = flow.column(align=True)
col.prop(ui_state, "inner_driven")
col.prop(ui_state, "inner_driven_sel")
col.prop(ui_state, "inner_driven_sel", text="Selected")
col = flow.column(align=True)
col.prop(ui_state, "inner_key")
col.prop(ui_state, "inner_key_sel")
col.prop(ui_state, "inner_key_sel", text="Selected")
col = flow.column(align=True)
col.prop(ui_state, "inner_overridden")
col.prop(ui_state, "inner_overridden_sel")
col.prop(ui_state, "inner_overridden_sel", text="Selected")
col = flow.column(align=True)
col.prop(ui_state, "inner_changed")
col.prop(ui_state, "inner_changed_sel")
col.prop(ui_state, "inner_changed_sel", text="Selected")
col = flow.column(align=True)
col.prop(ui_state, "blend")
@ -956,14 +956,19 @@ class USERPREF_PT_theme_interface_styles(ThemePanel, CenterAlignMixIn, Panel):
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow.prop(ui, "menu_shadow_fac")
flow.prop(ui, "menu_shadow_width")
flow.prop(ui, "icon_alpha")
flow.prop(ui, "icon_saturation")
flow.prop(ui, "editor_outline")
flow.prop(ui, "widget_text_cursor")
flow.prop(ui, "widget_emboss")
flow.prop(ui, "panel_roundness")
col = flow.column(align=True)
col.prop(ui, "menu_shadow_fac")
col.prop(ui, "menu_shadow_width", text="Shadow Width")
col = flow.column(align=True)
col.prop(ui, "icon_alpha")
col.prop(ui, "icon_saturation", text="Saturation")
col = flow.column()
col.prop(ui, "widget_text_cursor")
col.prop(ui, "editor_outline")
col.prop(ui, "widget_emboss")
col.prop(ui, "panel_roundness")
class USERPREF_PT_theme_interface_transparent_checker(ThemePanel, CenterAlignMixIn, Panel):
@ -978,9 +983,12 @@ class USERPREF_PT_theme_interface_transparent_checker(ThemePanel, CenterAlignMix
flow = layout.grid_flow(
row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow.prop(ui, "transparent_checker_primary")
flow.prop(ui, "transparent_checker_secondary")
flow.prop(ui, "transparent_checker_size")
col = flow.column(align=True)
col.prop(ui, "transparent_checker_primary")
col.prop(ui, "transparent_checker_secondary")
col = flow.column()
col.prop(ui, "transparent_checker_size")
class USERPREF_PT_theme_interface_gizmos(ThemePanel, CenterAlignMixIn, Panel):
@ -1001,12 +1009,12 @@ class USERPREF_PT_theme_interface_gizmos(ThemePanel, CenterAlignMixIn, Panel):
col = flow.column()
col.prop(ui, "gizmo_primary")
col.prop(ui, "gizmo_secondary")
col.prop(ui, "gizmo_view_align")
col.prop(ui, "gizmo_secondary", text="Secondary")
col.prop(ui, "gizmo_view_align", text="View Align")
col = flow.column()
col.prop(ui, "gizmo_a")
col.prop(ui, "gizmo_b")
col.prop(ui, "gizmo_b", text="B")
class USERPREF_PT_theme_interface_icons(ThemePanel, CenterAlignMixIn, Panel):
@ -1037,7 +1045,7 @@ class USERPREF_PT_theme_text_style(ThemePanel, CenterAlignMixIn, Panel):
@staticmethod
def _ui_font_style(layout, font_style):
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
col = flow.column()
col.prop(font_style, "points")
@ -1046,10 +1054,10 @@ class USERPREF_PT_theme_text_style(ThemePanel, CenterAlignMixIn, Panel):
col.prop(font_style, "shadow_offset_x", text="Shadow Offset X")
col.prop(font_style, "shadow_offset_y", text="Y")
col = flow.column()
col = flow.column(align=True)
col.prop(font_style, "shadow")
col.prop(font_style, "shadow_alpha")
col.prop(font_style, "shadow_value")
col.prop(font_style, "shadow_alpha", text="Alpha")
col.prop(font_style, "shadow_value", text="Brightness")
def draw_header(self, _context):
layout = self.layout
@ -1090,10 +1098,10 @@ class USERPREF_PT_theme_bone_color_sets(ThemePanel, CenterAlignMixIn, Panel):
for i, ui in enumerate(theme.bone_color_sets, 1):
layout.label(text=iface_("Color Set %d") % i, translate=False)
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
flow.prop(ui, "normal")
flow.prop(ui, "select")
flow.prop(ui, "select", text="Selected")
flow.prop(ui, "active")
flow.prop(ui, "show_colored_constraints")
@ -1112,7 +1120,7 @@ class USERPREF_PT_theme_collection_colors(ThemePanel, CenterAlignMixIn, Panel):
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow = layout.grid_flow(row_major=False, columns=2, even_columns=True, even_rows=False, align=False)
for i, ui in enumerate(theme.collection_color, 1):
flow.prop(ui, "color", text=iface_("Color %d") % i, translate=False)
@ -1131,7 +1139,7 @@ class USERPREF_PT_theme_strip_colors(ThemePanel, CenterAlignMixIn, Panel):
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
flow = layout.grid_flow(row_major=False, columns=2, even_columns=True, even_rows=False, align=False)
for i, ui in enumerate(theme.strip_color, 1):
flow.prop(ui, "color", text=iface_("Color %d") % i, translate=False)
@ -1217,28 +1225,28 @@ class ThemeGenericClassGenerator:
@staticmethod
def generate_panel_classes_for_wcols():
wcols = [
("Box", "wcol_box"),
("List Item", "wcol_list_item"),
("Menu", "wcol_menu"),
("Menu Background", "wcol_menu_back"),
("Menu Item", "wcol_menu_item"),
("Number Field", "wcol_num"),
("Option", "wcol_option"),
("Pie Menu", "wcol_pie_menu"),
("Progress Bar", "wcol_progress"),
("Pulldown", "wcol_pulldown"),
("Radio Buttons", "wcol_radio"),
("Regular", "wcol_regular"),
("Scroll Bar", "wcol_scroll"),
("Tab", "wcol_tab"),
("Text", "wcol_text"),
("Toggle", "wcol_toggle"),
("Tool", "wcol_tool"),
("Toolbar Item", "wcol_toolbar_item"),
("Radio Buttons", "wcol_radio"),
("Text", "wcol_text"),
("Option", "wcol_option"),
("Toggle", "wcol_toggle"),
("Number Field", "wcol_num"),
("Value Slider", "wcol_numslider"),
("Box", "wcol_box"),
("Menu", "wcol_menu"),
("Pie Menu", "wcol_pie_menu"),
("Pulldown", "wcol_pulldown"),
("Menu Back", "wcol_menu_back"),
("Tooltip", "wcol_tooltip"),
("Menu Item", "wcol_menu_item"),
("Scroll Bar", "wcol_scroll"),
("Progress Bar", "wcol_progress"),
("List Item", "wcol_list_item"),
("Value Slider", "wcol_numslider"),
# Not used yet, so hide this from the UI.
# ("Data-View Item", "wcol_view_item"),
("Tab", "wcol_tab"),
]
for (name, wcol) in wcols:
@ -2588,11 +2596,11 @@ classes = (
USERPREF_MT_interface_theme_presets,
USERPREF_PT_theme,
USERPREF_PT_theme_interface_gizmos,
USERPREF_PT_theme_interface_icons,
USERPREF_PT_theme_interface_state,
USERPREF_PT_theme_interface_styles,
USERPREF_PT_theme_interface_gizmos,
USERPREF_PT_theme_interface_transparent_checker,
USERPREF_PT_theme_interface_icons,
USERPREF_PT_theme_text_style,
USERPREF_PT_theme_bone_color_sets,
USERPREF_PT_theme_collection_colors,

View File

@ -9,6 +9,7 @@
#include "BLI_linklist.h"
#include "BLI_math_color.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@ -46,10 +47,9 @@ BoneCollection *ANIM_bonecoll_new(const char *name)
/* Note: the collection name may change after the collection is added to an
* armature, to ensure it is unique within the armature. */
std::string alloc_name = std::string(__func__) + "('" + name + "')";
BoneCollection *bcoll = MEM_cnew<BoneCollection>(alloc_name.c_str());
BoneCollection *bcoll = MEM_cnew<BoneCollection>(__func__);
BLI_strncpy(bcoll->name, name, sizeof(bcoll->name));
STRNCPY_UTF8(bcoll->name, name);
bcoll->flags = default_flags;
bcoll->prop = nullptr;
@ -92,7 +92,7 @@ static void bonecoll_ensure_name_unique(bArmature *armature, BoneCollection *bco
{
BLI_uniquename(&armature->collections,
bcoll,
bcoll->name,
"Bones",
'.',
offsetof(BoneCollection, name),
sizeof(bcoll->name));
@ -151,7 +151,7 @@ void ANIM_armature_bonecoll_active_index_set(bArmature *armature, const int bone
bool ANIM_armature_bonecoll_move(bArmature *armature, BoneCollection *bcoll, const int step)
{
if (bcoll == NULL) {
if (bcoll == nullptr) {
return false;
}
@ -169,9 +169,9 @@ void ANIM_armature_bonecoll_name_set(bArmature *armature, BoneCollection *bcoll,
{
char old_name[sizeof(bcoll->name)];
BLI_strncpy(old_name, bcoll->name, sizeof(bcoll->name));
STRNCPY(old_name, bcoll->name);
BLI_strncpy(bcoll->name, name, sizeof(bcoll->name));
STRNCPY_UTF8(bcoll->name, name);
bonecoll_ensure_name_unique(armature, bcoll);
BKE_animdata_fix_paths_rename_all(&armature->id, "collections", old_name, bcoll->name);
@ -309,7 +309,7 @@ bool ANIM_armature_bonecoll_unassign_editbone(BoneCollection *bcoll, EditBone *e
return was_found;
}
void ANIM_armature_bonecoll_reconstruct(struct bArmature *armature)
void ANIM_armature_bonecoll_reconstruct(bArmature *armature)
{
/* Remove all the old collection memberships. */
LISTBASE_FOREACH (BoneCollection *, bcoll, &armature->collections) {
@ -343,12 +343,11 @@ static bool any_bone_collection_visible(const ListBase /*BoneCollectionRef*/ *co
/* TODO: these two functions were originally implemented for armature layers, hence the armature
* parameters. These should be removed at some point. */
bool ANIM_bonecoll_is_visible(const struct bArmature * /*armature*/, const struct Bone *bone)
bool ANIM_bonecoll_is_visible(const bArmature * /*armature*/, const Bone *bone)
{
return any_bone_collection_visible(&bone->runtime.collections);
}
bool ANIM_bonecoll_is_visible_editbone(const struct bArmature * /*armature*/,
const struct EditBone *ebone)
bool ANIM_bonecoll_is_visible_editbone(const bArmature * /*armature*/, const EditBone *ebone)
{
return any_bone_collection_visible(&ebone->bone_collections);
}

View File

@ -19,6 +19,22 @@ class BakeItem {
virtual ~BakeItem() = default;
};
struct BakeState {
/**
* The ids are usually correspond to socket ids, so that the mapping stays intact even if socket
* order changes.
*/
Map<int, std::unique_ptr<BakeItem>> items_by_id;
};
/** Same as above, but does not own the bake items. */
struct BakeStateRef {
Map<int, const BakeItem *> items_by_id;
BakeStateRef() = default;
BakeStateRef(const BakeState &bake_state);
};
class GeometryBakeItem : public BakeItem {
public:
GeometrySet geometry;

View File

@ -0,0 +1,43 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <optional>
#include <string>
#include "BLI_string_ref.hh"
#include "BLI_sub_frame.hh"
#include "BLI_vector.hh"
namespace blender::bke::bake_paths {
struct MetaFile {
SubFrame frame;
std::string path;
};
struct BakePath {
/** Path to the directory containing the meta data per frame. */
std::string meta_dir;
/**
* Path to the directory that contains the binary data. Could be shared between multiple bakes
* to reduce memory consumption.
*/
std::string bdata_dir;
/**
* Folder that is allowed to be deleted when the bake is deleted and it doesn't contain anything
* else. Typically, this contains the meta and bdata directories.
*/
std::optional<std::string> bake_dir;
static BakePath from_single_root(StringRefNull root_dir);
};
std::string frame_to_file_name(const SubFrame &frame);
std::optional<SubFrame> file_name_to_frame(const StringRefNull file_name);
Vector<MetaFile> find_sorted_meta_files(const StringRefNull meta_dir);
} // namespace blender::bke::bake_paths

View File

@ -136,18 +136,13 @@ class DiskBDataWriter : public BDataWriter {
BDataSlice write(const void *data, int64_t size) override;
};
/**
* Writes the bake item into `r_io_item`.
*/
void serialize_bake_item(const BakeItem &item,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
io::serialize::DictionaryValue &r_io_item);
/**
* Creates a bake item from `io_item`.
*/
std::unique_ptr<BakeItem> deserialize_bake_item(const io::serialize::DictionaryValue &io_item,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing);
void serialize_bake(const BakeState &bake_state,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
std::ostream &r_stream);
std::optional<BakeState> deserialize_bake(std::istream &stream,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing);
} // namespace blender::bke

View File

@ -24,8 +24,13 @@ struct ImBuf;
struct Scopes;
struct rctf;
void BKE_curvemapping_set_defaults(
struct CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy);
void BKE_curvemapping_set_defaults(struct CurveMapping *cumap,
int tot,
float minx,
float miny,
float maxx,
float maxy,
short default_handle_type);
struct CurveMapping *BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
void BKE_curvemapping_free_data(struct CurveMapping *cumap);
void BKE_curvemapping_free(struct CurveMapping *cumap);

View File

@ -98,9 +98,6 @@ struct bContextStoreEntry {
};
struct bContextStore {
bContextStore *next = nullptr;
bContextStore *prev = nullptr;
blender::Vector<bContextStoreEntry> entries;
bool used = false;
};
@ -152,17 +149,16 @@ bContext *CTX_copy(const bContext *C);
/* Stored Context */
bContextStore *CTX_store_add(ListBase *contexts,
bContextStore *CTX_store_add(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
blender::StringRefNull name,
const PointerRNA *ptr);
bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context);
bContextStore *CTX_store_get(bContext *C);
void CTX_store_set(bContext *C, bContextStore *store);
bContextStore *CTX_store_add_all(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
const bContextStore *context);
const bContextStore *CTX_store_get(const bContext *C);
void CTX_store_set(bContext *C, const bContextStore *store);
const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
blender::StringRefNull name,
const StructRNA *type = nullptr);
bContextStore *CTX_store_copy(const bContextStore *store);
void CTX_store_free(bContextStore *store);
#endif

View File

@ -216,7 +216,8 @@ void BKE_previewimg_ensure(struct PreviewImage *prv, int size);
const char *BKE_previewimg_deferred_filepath_get(const struct PreviewImage *prv);
#ifdef __cplusplus
std::optional<int> BKE_previewimg_deferred_thumb_source_get(const struct PreviewImage *prv);
extern "C++" std::optional<int> BKE_previewimg_deferred_thumb_source_get(
const struct PreviewImage *prv);
#endif
/**

View File

@ -235,6 +235,11 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain);
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
* which case \a scene's master collection children hierarchy is used instead).
* \param id_root: The root liboverride ID to resync from.
* \param do_hierarchy_enforce: If `true`, enforce the liboverride hierarchy of dependencies to
* match the one from the reference linked data (i.e. if some manually
* override were applied to some ID pointers, they will be reset to
* the default reference value).
*
* \return true if override was successfully resynced.
*/
bool BKE_lib_override_library_resync(Main *bmain,

View File

@ -321,16 +321,10 @@ void BKE_mesh_recalc_looptri(const int *corner_verts,
/* *** mesh_normals.cc *** */
/**
* Return true if the mesh vertex normals either are not stored or are dirty.
* This can be used to help decide whether to transfer them when copying a mesh.
*/
/** Return true if the mesh vertex normals either are not stored or are dirty. */
bool BKE_mesh_vert_normals_are_dirty(const struct Mesh *mesh);
/**
* Return true if the mesh face normals either are not stored or are dirty.
* This can be used to help decide whether to transfer them when copying a mesh.
*/
/** Return true if the mesh face normals either are not stored or are dirty. */
bool BKE_mesh_face_normals_are_dirty(const struct Mesh *mesh);
/**

View File

@ -146,7 +146,6 @@ short2 lnor_space_custom_normal_to_data(const CornerNormalSpace &lnor_space,
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry
* (splitting edges).
*
* \param loop_to_face_map: Optional pre-created map from corners to their face.
* \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on
* each side of the edge.
* \param r_lnors_spacearr: Optional return data filled with information about the custom
@ -202,6 +201,7 @@ void edges_sharp_from_angle_set(OffsetIndices<int> faces,
Span<int> corner_verts,
Span<int> corner_edges,
Span<float3> face_normals,
Span<int> loop_to_face,
const bool *sharp_faces,
const float split_angle,
MutableSpan<bool> sharp_edges);

View File

@ -280,12 +280,17 @@ GroupedSpan<int> build_vert_to_edge_map(Span<int2> edges,
Array<int> &r_offsets,
Array<int> &r_indices);
void build_vert_to_face_indices(OffsetIndices<int> faces,
Span<int> corner_verts,
OffsetIndices<int> offsets,
MutableSpan<int> face_indices);
GroupedSpan<int> build_vert_to_face_map(OffsetIndices<int> faces,
Span<int> corner_verts,
int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices);
Array<int> build_vert_to_corner_indices(Span<int> corner_verts, OffsetIndices<int> offsets);
GroupedSpan<int> build_vert_to_loop_map(Span<int> corner_verts,
int verts_num,
Array<int> &r_offsets,

View File

@ -141,6 +141,17 @@ struct MeshRuntime {
SharedCache<Vector<float3>> face_normals_cache;
SharedCache<Vector<float3>> corner_normals_cache;
/**
* Cache of offsets for vert to face/corner maps. The same offsets array is used to group
* indices for both the vertex to face and vertex to corner maps.
*/
SharedCache<Array<int>> vert_to_face_offset_cache;
/** Cache of indices for vert to face map. */
SharedCache<Array<int>> vert_to_face_map_cache;
/** Cache of indices for vert to corner map. */
SharedCache<Array<int>> vert_to_corner_map_cache;
/** Cache of face indices for each face corner. */
SharedCache<Array<int>> corner_to_face_map_cache;
/** Cache of data about edges not used by faces. See #Mesh::loose_edges(). */
SharedCache<LooseEdgeCache> loose_edges_cache;
/** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */

View File

@ -288,9 +288,7 @@ class bNodeRuntime : NonCopyable, NonMovable {
/** Update flags. */
int update = 0;
/** Initial locx for insert offset animation. */
float anim_init_locx;
/** Offset that will be added to locx for insert offset animation. */
/** Offset that will be added to #bNote::locx for insert offset animation. */
float anim_ofsx;
/** List of cached internal links (input to output), for muted nodes and operators. */

View File

@ -267,12 +267,7 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain
/** Used for both vertex color and weight paint. */
struct SculptVertexPaintGeomMap {
blender::Array<int> vert_to_loop_offsets;
blender::Array<int> vert_to_loop_indices;
blender::GroupedSpan<int> vert_to_loop;
blender::Array<int> vert_to_face_offsets;
blender::Array<int> vert_to_face_indices;
blender::GroupedSpan<int> vert_to_face;
};
@ -591,9 +586,7 @@ struct SculptSession {
float *vmask;
/* Mesh connectivity maps. */
/* Vertices to adjacent faces. */
blender::Array<int> vert_to_face_offsets;
blender::Array<int> vert_to_face_indices;
/* Vertices to adjacent polys. */
blender::GroupedSpan<int> pmap;
/* Edges to adjacent faces. */

View File

@ -210,7 +210,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
CCGKey *key,
void **gridfaces,
blender::Span<int> grid_to_face_map,
DMFlagMat *flagmats,
unsigned int **grid_hidden,
Mesh *me,
@ -445,7 +445,7 @@ void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3]);
void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *pbvh,
CCGElem **grids,
void **gridfaces,
blender::Span<int> grid_to_face_map,
DMFlagMat *flagmats,
unsigned int **grid_hidden,
CCGKey *key);

View File

@ -414,6 +414,12 @@ typedef struct MenuType {
void (*draw)(const struct bContext *C, struct Menu *menu);
void (*listener)(const wmRegionListenerParams *params);
/**
* True if the menu depends on data retrieved via #CTX_data_pointer_get. If it is context
* dependent, menu search has to scan it in different contexts.
*/
bool context_dependent;
/* RNA integration */
ExtensionRNA rna_ext;
} MenuType;

View File

@ -4,6 +4,7 @@
#pragma once
#include "BKE_bake_items_paths.hh"
#include "BKE_bake_items_serialize.hh"
#include "BKE_geometry_set.hh"
@ -11,65 +12,12 @@
#include "BLI_sub_frame.hh"
struct bNodeTree;
struct ModifierData;
struct NodesModifierData;
struct Main;
namespace blender::bke::sim {
class ModifierSimulationCache;
/**
* Storage of values for a single simulation input and output node pair.
* Used as a cache to allow random access in time, and as an intermediate form before data is
* baked.
*/
class SimulationZoneState {
public:
Map<int, std::unique_ptr<BakeItem>> item_by_identifier;
};
/** Identifies a simulation zone (input and output node pair) used by a modifier. */
struct SimulationZoneID {
/** ID of the #bNestedNodeRef that references the output node of the zone. */
int32_t nested_node_id;
uint64_t hash() const
{
return this->nested_node_id;
}
friend bool operator==(const SimulationZoneID &a, const SimulationZoneID &b)
{
return a.nested_node_id == b.nested_node_id;
}
};
/**
* Stores a single frame of simulation states for all simulation zones in a modifier's node
* hierarchy.
*/
class ModifierSimulationState {
private:
mutable bool bake_loaded_;
public:
ModifierSimulationCache *owner_;
mutable std::mutex mutex_;
Map<SimulationZoneID, std::unique_ptr<SimulationZoneState>> zone_states_;
/** File path to folder containing baked meta-data. */
std::optional<std::string> meta_path_;
/** File path to folder containing baked data. */
std::optional<std::string> bdata_dir_;
SimulationZoneState *get_zone_state(const SimulationZoneID &zone_id);
const SimulationZoneState *get_zone_state(const SimulationZoneID &zone_id) const;
SimulationZoneState &get_zone_state_for_write(const SimulationZoneID &zone_id);
void ensure_bake_loaded(const bNodeTree &ntree) const;
};
struct ModifierSimulationStateAtFrame {
SubFrame frame;
ModifierSimulationState state;
};
enum class CacheState {
/** The cache is up-to-date with the inputs. */
Valid,
@ -82,56 +30,34 @@ enum class CacheState {
Baked,
};
struct StatesAroundFrame {
const ModifierSimulationStateAtFrame *prev = nullptr;
const ModifierSimulationStateAtFrame *current = nullptr;
const ModifierSimulationStateAtFrame *next = nullptr;
struct SimulationZoneFrameCache {
SubFrame frame;
BakeState state;
/** Used when the baked data is loaded lazily. */
std::optional<std::string> meta_path;
};
struct ModifierSimulationCacheRealtime {
std::unique_ptr<ModifierSimulationState> prev_state;
std::unique_ptr<ModifierSimulationState> current_state;
SubFrame prev_frame;
SubFrame current_frame;
struct SimulationZonePrevState {
BakeState state;
SubFrame frame;
};
struct SimulationZoneCache {
Vector<std::unique_ptr<SimulationZoneFrameCache>> frame_caches;
std::optional<SimulationZonePrevState> prev_state;
std::optional<std::string> bdata_dir;
std::unique_ptr<BDataSharing> bdata_sharing;
bool failed_finding_bake = false;
CacheState cache_state = CacheState::Valid;
void reset();
};
class ModifierSimulationCache {
private:
mutable std::mutex states_at_frames_mutex_;
/**
* All simulation states, sorted by frame.
*/
Vector<std::unique_ptr<ModifierSimulationStateAtFrame>> states_at_frames_;
/**
* Used for baking to deduplicate arrays when writing and writing from storage. Sharing info
* must be kept alive for multiple frames to detect if each data array's version has changed.
*/
std::unique_ptr<BDataSharing> bdata_sharing_;
friend ModifierSimulationState;
bool failed_finding_bake_ = false;
public:
CacheState cache_state = CacheState::Valid;
/** A non-persistent cache used only to pass simulation state data from one frame to the next. */
ModifierSimulationCacheRealtime realtime_cache;
void try_discover_bake(StringRefNull absolute_bake_dir);
bool has_state_at_frame(const SubFrame &frame) const;
bool has_states() const;
const ModifierSimulationState *get_state_at_exact_frame(const SubFrame &frame) const;
ModifierSimulationState &get_state_at_frame_for_write(const SubFrame &frame);
StatesAroundFrame get_states_around_frame(const SubFrame &frame) const;
void invalidate()
{
this->cache_state = CacheState::Invalid;
}
void reset();
mutable std::mutex mutex;
Map<int, std::unique_ptr<SimulationZoneCache>> cache_by_zone_id;
};
/**
@ -140,4 +66,19 @@ class ModifierSimulationCache {
*/
void scene_simulation_states_reset(Scene &scene);
std::optional<bake_paths::BakePath> get_simulation_zone_bake_path(const Main &bmain,
const Object &object,
const NodesModifierData &nmd,
int zone_id);
std::optional<std::string> get_modifier_simulation_bake_path(const Main &bmain,
const Object &object,
const NodesModifierData &nmd);
/**
* Get the directory that contains all baked simulation data for the given modifier.
*/
std::string get_default_modifier_bake_directory(const Main &bmain,
const Object &object,
const ModifierData &md);
} // namespace blender::bke::sim

View File

@ -1,50 +0,0 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BKE_bake_items_serialize.hh"
#include "BKE_simulation_state.hh"
#include "BLI_serialize.hh"
struct Main;
struct ModifierData;
struct Object;
namespace blender {
class fstream;
}
namespace blender::bke::sim {
using DictionaryValue = io::serialize::DictionaryValue;
using DictionaryValuePtr = std::shared_ptr<DictionaryValue>;
/**
* Get the directory that contains all baked simulation data for the given modifier.
*/
std::string get_default_modifier_bake_directory(const Main &bmain,
const Object &object,
const ModifierData &md);
/**
* Encode the simulation state in a #DictionaryValue which also contains references to external
* binary data that has been written using #bdata_writer.
*/
void serialize_modifier_simulation_state(const ModifierSimulationState &state,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
DictionaryValue &r_io_root);
/**
* Fill the simulation state by parsing the provided #DictionaryValue which also contains
* references to external binary data that is read using #bdata_reader.
*/
void deserialize_modifier_simulation_state(const bNodeTree &ntree,
const DictionaryValue &io_root,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing,
ModifierSimulationState &r_state);
} // namespace blender::bke::sim

View File

@ -127,6 +127,7 @@ void BKE_sound_update_scene_listener(struct Scene *scene);
void *BKE_sound_scene_add_scene_sound(
struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
void *BKE_sound_add_scene_sound(
@ -145,8 +146,14 @@ void BKE_sound_move_scene_sound(const struct Scene *scene,
double audio_offset);
void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
/* Join the Sequence with the structure in Audaspace, the second parameter is a bSound */
void BKE_sound_update_scene_sound(void *handle, struct bSound *sound);
/* Join the Sequence with the structure in Audaspace, the second parameter is the AUD_Sound created
* in Audaspace previously
*/
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle);
void BKE_sound_set_cfra(int cfra);
void BKE_sound_set_scene_volume(struct Scene *scene, float volume);

View File

@ -160,7 +160,7 @@ struct SubdivCCG {
int num_faces = -1;
SubdivCCGFace *faces = nullptr;
/* Indexed by grid index, points to corresponding face from `faces`. */
SubdivCCGFace **grid_faces = nullptr;
blender::Array<int> grid_to_face_map;
/* Edges which are adjacent to faces.
* Used for faster grid stitching, in the cost of extra memory.

View File

@ -73,6 +73,7 @@ set(SRC
intern/attribute_math.cc
intern/autoexec.cc
intern/bake_items.cc
intern/bake_items_paths.cc
intern/bake_items_serialize.cc
intern/bake_items_socket.cc
intern/blender.cc
@ -270,7 +271,6 @@ set(SRC
intern/shader_fx.cc
intern/shrinkwrap.cc
intern/simulation_state.cc
intern/simulation_state_serialize.cc
intern/softbody.c
intern/sound.cc
intern/speaker.cc
@ -333,6 +333,7 @@ set(SRC
BKE_attribute_math.hh
BKE_autoexec.h
BKE_bake_items.hh
BKE_bake_items_paths.hh
BKE_bake_items_serialize.hh
BKE_bake_items_socket.hh
BKE_blender.h
@ -480,7 +481,6 @@ set(SRC
BKE_shader_fx.h
BKE_shrinkwrap.h
BKE_simulation_state.hh
BKE_simulation_state_serialize.hh
BKE_softbody.h
BKE_sound.h
BKE_speaker.h

View File

@ -87,6 +87,7 @@ static void armature_init_data(ID *id)
/* Give the Armature its default bone collection. */
BoneCollection *default_bonecoll = ANIM_bonecoll_new("");
BLI_addhead(&armature->collections, default_bonecoll);
ANIM_armature_bonecoll_active_set(armature, default_bonecoll);
}
/**

View File

@ -14,6 +14,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_uuid.h"
@ -86,7 +87,7 @@ AssetMetaData::~AssetMetaData()
static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name)
{
AssetTag *tag = (AssetTag *)MEM_callocN(sizeof(*tag), __func__);
STRNCPY(tag->name, name);
STRNCPY_UTF8(tag->name, name);
BLI_addtail(&asset_data->tags, tag);
asset_data->tot_tags++;

View File

@ -73,4 +73,12 @@ PrimitiveBakeItem::~PrimitiveBakeItem()
StringBakeItem::StringBakeItem(std::string value) : value_(std::move(value)) {}
BakeStateRef::BakeStateRef(const BakeState &bake_state)
{
this->items_by_id.reserve(bake_state.items_by_id.size());
for (auto item : bake_state.items_by_id.items()) {
this->items_by_id.add_new(item.key, item.value.get());
}
}
} // namespace blender::bke

View File

@ -0,0 +1,76 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_bake_items_paths.hh"
#include "BLI_fileops.hh"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
namespace blender::bke::bake_paths {
std::string frame_to_file_name(const SubFrame &frame)
{
char file_name_c[FILE_MAX];
SNPRINTF(file_name_c, "%011.5f", double(frame));
BLI_string_replace_char(file_name_c, '.', '_');
return file_name_c;
}
std::optional<SubFrame> file_name_to_frame(const StringRefNull file_name)
{
char modified_file_name[FILE_MAX];
STRNCPY(modified_file_name, file_name.c_str());
BLI_string_replace_char(modified_file_name, '_', '.');
const SubFrame frame = std::stof(modified_file_name);
return frame;
}
Vector<MetaFile> find_sorted_meta_files(const StringRefNull meta_dir)
{
if (!BLI_is_dir(meta_dir.c_str())) {
return {};
}
direntry *dir_entries = nullptr;
const int dir_entries_num = BLI_filelist_dir_contents(meta_dir.c_str(), &dir_entries);
BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
Vector<MetaFile> meta_files;
for (const int i : IndexRange(dir_entries_num)) {
const direntry &dir_entry = dir_entries[i];
const StringRefNull dir_entry_path = dir_entry.path;
if (!dir_entry_path.endswith(".json")) {
continue;
}
const std::optional<SubFrame> frame = file_name_to_frame(dir_entry.relname);
if (!frame) {
continue;
}
meta_files.append({*frame, dir_entry_path});
}
std::sort(meta_files.begin(), meta_files.end(), [](const MetaFile &a, const MetaFile &b) {
return a.frame < b.frame;
});
return meta_files;
}
BakePath BakePath::from_single_root(StringRefNull root_dir)
{
char meta_dir[FILE_MAX];
BLI_path_join(meta_dir, sizeof(meta_dir), root_dir.c_str(), "meta");
char bdata_dir[FILE_MAX];
BLI_path_join(bdata_dir, sizeof(bdata_dir), root_dir.c_str(), "bdata");
BakePath bake_path;
bake_path.meta_dir = meta_dir;
bake_path.bdata_dir = bdata_dir;
bake_path.bake_dir = root_dir;
return bake_path;
}
} // namespace blender::bke::bake_paths

View File

@ -960,10 +960,10 @@ template<typename T>
return false;
}
void serialize_bake_item(const BakeItem &item,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
DictionaryValue &r_io_item)
static void serialize_bake_item(const BakeItem &item,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
DictionaryValue &r_io_item)
{
if (const auto *geometry_state_item = dynamic_cast<const GeometryBakeItem *>(&item)) {
r_io_item.append_str("type", "GEOMETRY");
@ -996,9 +996,9 @@ void serialize_bake_item(const BakeItem &item,
}
}
std::unique_ptr<BakeItem> deserialize_bake_item(const DictionaryValue &io_item,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing)
static std::unique_ptr<BakeItem> deserialize_bake_item(const DictionaryValue &io_item,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing)
{
const std::optional<StringRefNull> state_item_type = io_item.lookup_str("type");
@ -1064,4 +1064,70 @@ std::unique_ptr<BakeItem> deserialize_bake_item(const DictionaryValue &io_item,
return {};
}
static constexpr int bake_file_version = 3;
void serialize_bake(const BakeState &bake_state,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
std::ostream &r_stream)
{
io::serialize::DictionaryValue io_root;
io_root.append_int("version", bake_file_version);
io::serialize::DictionaryValue &io_items = *io_root.append_dict("items");
for (auto item : bake_state.items_by_id.items()) {
io::serialize::DictionaryValue &io_item = *io_items.append_dict(std::to_string(item.key));
bke::serialize_bake_item(*item.value, bdata_writer, bdata_sharing, io_item);
}
io::serialize::JsonFormatter formatter;
formatter.serialize(r_stream, io_root);
}
std::optional<BakeState> deserialize_bake(std::istream &stream,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing)
{
JsonFormatter formatter;
std::unique_ptr<io::serialize::Value> io_root_value = formatter.deserialize(stream);
if (!io_root_value) {
return std::nullopt;
}
const io::serialize::DictionaryValue *io_root = io_root_value->as_dictionary_value();
if (!io_root) {
return std::nullopt;
}
const std::optional<int> version = io_root->lookup_int("version");
if (!version.has_value() || *version != bake_file_version) {
return std::nullopt;
}
const io::serialize::DictionaryValue *io_items = io_root->lookup_dict("items");
if (!io_items) {
return std::nullopt;
}
BakeState bake_state;
for (const auto &io_item_value : io_items->elements()) {
const io::serialize::DictionaryValue *io_item = io_item_value.second->as_dictionary_value();
if (!io_item) {
return std::nullopt;
}
int id;
try {
id = std::stoi(io_item_value.first);
}
catch (...) {
return std::nullopt;
}
if (bake_state.items_by_id.contains(id)) {
return std::nullopt;
}
std::unique_ptr<BakeItem> bake_item = deserialize_bake_item(
*io_item, bdata_reader, bdata_sharing);
if (!bake_item) {
return std::nullopt;
}
bake_state.items_by_id.add_new(id, std::move(bake_item));
}
return bake_state;
}
} // namespace blender::bke

View File

@ -776,7 +776,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
@ -813,7 +813,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
@ -850,7 +850,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
@ -886,12 +886,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_CHISEL_SENSIVITY);
custom_curve = brush->gpencil_settings->curve_strength;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_CHISEL_STRENGTH);

View File

@ -34,8 +34,13 @@
/* ***************** operations on full struct ************* */
void BKE_curvemapping_set_defaults(
CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
void BKE_curvemapping_set_defaults(CurveMapping *cumap,
int tot,
float minx,
float miny,
float maxx,
float maxy,
short default_handle_type)
{
int a;
float clipminx, clipminy, clipmaxx, clipmaxy;
@ -57,14 +62,23 @@ void BKE_curvemapping_set_defaults(
cumap->bwmul[0] = cumap->bwmul[1] = cumap->bwmul[2] = 1.0f;
for (a = 0; a < tot; a++) {
if (default_handle_type == HD_VECT) {
cumap->cm[a].default_handle_type = CUMA_HANDLE_VECTOR;
}
else if (default_handle_type == HD_AUTO_ANIM) {
cumap->cm[a].default_handle_type = CUMA_HANDLE_AUTO_ANIM;
}
cumap->cm[a].totpoint = 2;
cumap->cm[a].curve = static_cast<CurveMapPoint *>(
MEM_callocN(2 * sizeof(CurveMapPoint), "curve points"));
cumap->cm[a].curve[0].x = minx;
cumap->cm[a].curve[0].y = miny;
cumap->cm[a].curve[0].flag |= default_handle_type;
cumap->cm[a].curve[1].x = maxx;
cumap->cm[a].curve[1].y = maxy;
cumap->cm[a].curve[1].flag |= default_handle_type;
}
cumap->changed_timestamp = 0;
@ -76,7 +90,7 @@ CurveMapping *BKE_curvemapping_add(int tot, float minx, float miny, float maxx,
cumap = static_cast<CurveMapping *>(MEM_callocN(sizeof(CurveMapping), "new curvemap"));
BKE_curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy);
BKE_curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy, HD_AUTO);
return cumap;
}
@ -238,6 +252,7 @@ CurveMapPoint *BKE_curvemap_insert(CurveMap *cuma, float x, float y)
cmp[a].x = x;
cmp[a].y = y;
cmp[a].flag = CUMA_SELECT;
cmp[a].flag |= cuma->default_handle_type;
foundloc = true;
newcmp = &cmp[a];
}
@ -266,6 +281,7 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
switch (preset) {
case CURVE_PRESET_LINE:
case CURVE_PRESET_CONSTANT_MEDIAN:
cuma->totpoint = 2;
break;
case CURVE_PRESET_SHARP:
@ -297,6 +313,10 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
cuma->curve = static_cast<CurveMapPoint *>(
MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points"));
for (int i = 0; i < cuma->totpoint; i++) {
cuma->curve[i].flag = cuma->default_handle_type;
}
switch (preset) {
case CURVE_PRESET_LINE:
cuma->curve[0].x = clipr->xmin;
@ -304,10 +324,18 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = clipr->ymin;
if (slope == CURVEMAP_SLOPE_POS_NEG) {
cuma->curve[0].flag &= ~CUMA_HANDLE_AUTO_ANIM;
cuma->curve[1].flag &= ~CUMA_HANDLE_AUTO_ANIM;
cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
}
break;
case CURVE_PRESET_CONSTANT_MEDIAN:
cuma->curve[0].x = clipr->xmin;
cuma->curve[0].y = (clipr->ymin + clipr->ymax) / 2.0f;
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = (clipr->ymin + clipr->ymax) / 2.0f;
break;
case CURVE_PRESET_SHARP:
cuma->curve[0].x = 0;
cuma->curve[0].y = 1;

View File

@ -68,7 +68,7 @@ struct bContext {
ARegion *region;
ARegion *menu;
wmGizmoGroup *gizmo_group;
bContextStore *store;
const bContextStore *store;
/* Operator poll. */
/**
@ -128,60 +128,51 @@ void CTX_free(bContext *C)
/* store */
bContextStore *CTX_store_add(ListBase *contexts,
bContextStore *CTX_store_add(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
const blender::StringRefNull name,
const PointerRNA *ptr)
{
/* ensure we have a context to put the entry in, if it was already used
* we have to copy the context to ensure */
bContextStore *ctx = static_cast<bContextStore *>(contexts->last);
if (!ctx || ctx->used) {
if (ctx) {
ctx = MEM_new<bContextStore>(__func__, *ctx);
}
else {
ctx = MEM_new<bContextStore>(__func__);
}
BLI_addtail(contexts, ctx);
if (contexts.is_empty()) {
contexts.append(std::make_unique<bContextStore>());
}
else if (contexts.last()->used) {
auto new_ctx = std::make_unique<bContextStore>(bContextStore{contexts.last()->entries, false});
contexts.append(std::move(new_ctx));
}
bContextStore *ctx = contexts.last().get();
ctx->entries.append(bContextStoreEntry{name, *ptr});
return ctx;
}
bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context)
bContextStore *CTX_store_add_all(blender::Vector<std::unique_ptr<bContextStore>> &contexts,
const bContextStore *context)
{
/* ensure we have a context to put the entries in, if it was already used
/* ensure we have a context to put the entry in, if it was already used
* we have to copy the context to ensure */
bContextStore *ctx = static_cast<bContextStore *>(contexts->last);
if (!ctx || ctx->used) {
if (ctx) {
ctx = MEM_new<bContextStore>(__func__, *ctx);
}
else {
ctx = MEM_new<bContextStore>(__func__);
}
BLI_addtail(contexts, ctx);
if (contexts.is_empty()) {
contexts.append(std::make_unique<bContextStore>());
}
else if (contexts.last()->used) {
auto new_ctx = std::make_unique<bContextStore>(bContextStore{contexts.last()->entries, false});
contexts.append(std::move(new_ctx));
}
bContextStore *ctx = contexts.last().get();
for (const bContextStoreEntry &src_entry : context->entries) {
ctx->entries.append(src_entry);
}
return ctx;
}
bContextStore *CTX_store_get(bContext *C)
const bContextStore *CTX_store_get(const bContext *C)
{
return C->wm.store;
}
void CTX_store_set(bContext *C, bContextStore *store)
void CTX_store_set(bContext *C, const bContextStore *store)
{
C->wm.store = store;
}
@ -200,16 +191,6 @@ const PointerRNA *CTX_store_ptr_lookup(const bContextStore *store,
return nullptr;
}
bContextStore *CTX_store_copy(const bContextStore *store)
{
return MEM_new<bContextStore>(__func__, *store);
}
void CTX_store_free(bContextStore *store)
{
MEM_delete(store);
}
/* is python initialized? */
bool CTX_py_init_get(bContext *C)

View File

@ -291,7 +291,7 @@ void BKE_previewimg_freefunc(void *link)
if (!prv) {
return;
}
BKE_previewimg_freefunc(&prv);
BKE_previewimg_free(&prv);
}
void BKE_previewimg_free(PreviewImage **prv)
@ -310,9 +310,7 @@ void BKE_previewimg_free(PreviewImage **prv)
PreviewImageDeferred &this_deferred = PreviewImageDeferred::from_base(**prv);
std::destroy_at(&this_deferred.filepath);
}
else {
MEM_delete(*prv);
}
MEM_delete(*prv);
*prv = nullptr;
}
}

View File

@ -2278,7 +2278,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
faces,
corner_verts,
corner_edges,
{},
mesh->corner_to_face_map(),
{reinterpret_cast<blender::float3 *>(vert_normals), mesh->totvert},
{reinterpret_cast<blender::float3 *>(face_normals), faces.size()},
sharp_edges,

View File

@ -139,6 +139,10 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache;
mesh_dst->runtime->looptri_faces_cache = mesh_src->runtime->looptri_faces_cache;
mesh_dst->runtime->vert_to_face_offset_cache = mesh_src->runtime->vert_to_face_offset_cache;
mesh_dst->runtime->vert_to_face_map_cache = mesh_src->runtime->vert_to_face_map_cache;
mesh_dst->runtime->vert_to_corner_map_cache = mesh_src->runtime->vert_to_corner_map_cache;
mesh_dst->runtime->corner_to_face_map_cache = mesh_src->runtime->corner_to_face_map_cache;
/* Only do tessface if we have no faces. */
const bool do_tessface = ((mesh_src->totface_legacy != 0) && (mesh_src->faces_num == 0));
@ -1053,9 +1057,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
CustomData_add_layer(&me_dst->fdata_legacy, CD_MFACE, CD_SET_DEFAULT, me_dst->totface_legacy);
}
/* Expect that normals aren't copied at all, since the destination mesh is new. */
BLI_assert(BKE_mesh_vert_normals_are_dirty(me_dst));
return me_dst;
}

View File

@ -204,8 +204,7 @@ class MeshFairingContext : public FairingContext {
faces = mesh->faces();
corner_verts_ = mesh->corner_verts();
corner_edges_ = mesh->corner_edges();
vlmap_ = blender::bke::mesh::build_vert_to_loop_map(
corner_verts_, positions.size(), vert_to_face_offsets_, vert_to_face_indices_);
vlmap_ = mesh->vert_to_corner_map();
/* Deformation coords. */
co_.reserve(mesh->totvert);
@ -220,7 +219,7 @@ class MeshFairingContext : public FairingContext {
}
}
loop_to_face_map_ = blender::bke::mesh::build_loop_to_face_map(faces);
loop_to_face_map_ = mesh->corner_to_face_map();
}
void adjacents_coords_from_loop(const int loop,
@ -247,9 +246,7 @@ class MeshFairingContext : public FairingContext {
Span<int> corner_edges_;
blender::OffsetIndices<int> faces;
Span<blender::int2> edges_;
Array<int> loop_to_face_map_;
Array<int> vert_to_face_offsets_;
Array<int> vert_to_face_indices_;
Span<int> loop_to_face_map_;
};
class BMeshFairingContext : public FairingContext {

View File

@ -379,6 +379,20 @@ GroupedSpan<int> build_vert_to_edge_map(const Span<int2> edges,
return {OffsetIndices<int>(r_offsets), r_indices};
}
void build_vert_to_face_indices(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const OffsetIndices<int> offsets,
MutableSpan<int> r_indices)
{
Array<int> counts(offsets.size(), 0);
for (const int64_t face_i : faces.index_range()) {
for (const int vert : corner_verts.slice(faces[face_i])) {
r_indices[offsets[vert].start() + counts[vert]] = int(face_i);
counts[vert]++;
}
}
}
GroupedSpan<int> build_vert_to_face_map(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const int verts_num,
@ -387,17 +401,16 @@ GroupedSpan<int> build_vert_to_face_map(const OffsetIndices<int> faces,
{
r_offsets = create_reverse_offsets(corner_verts, verts_num);
r_indices.reinitialize(r_offsets.last());
Array<int> counts(verts_num, 0);
for (const int64_t face_i : faces.index_range()) {
for (const int vert : corner_verts.slice(faces[face_i])) {
r_indices[r_offsets[vert] + counts[vert]] = int(face_i);
counts[vert]++;
}
}
build_vert_to_face_indices(faces, corner_verts, OffsetIndices<int>(r_offsets), r_indices);
return {OffsetIndices<int>(r_offsets), r_indices};
}
Array<int> build_vert_to_corner_indices(const Span<int> corner_verts,
const OffsetIndices<int> offsets)
{
return reverse_indices_in_groups(corner_verts, offsets);
}
GroupedSpan<int> build_vert_to_loop_map(const Span<int> corner_verts,
const int verts_num,
Array<int> &r_offsets,

View File

@ -114,10 +114,7 @@ void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *me)
return;
}
Array<int> vert_to_loop_offsets;
Array<int> vert_to_loop_indices;
const GroupedSpan<int> vert_to_loop = bke::mesh::build_vert_to_loop_map(
me->corner_verts(), me->totvert, vert_to_loop_offsets, vert_to_loop_indices);
const GroupedSpan<int> vert_to_loop = me->vert_to_corner_map();
Vector<float2 *> mloopuv_layers;
mloopuv_layers.reserve(mloopuv_layers_num);

View File

@ -415,7 +415,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
result_faces,
result_corner_verts,
result_corner_edges,
{},
result->corner_to_face_map(),
result->vert_normals(),
result->face_normals(),
sharp_edges,

View File

@ -902,6 +902,7 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<int> corner_edges,
const Span<float3> face_normals,
const Span<int> loop_to_face,
const bool *sharp_faces,
const float split_angle,
MutableSpan<bool> sharp_edges)
@ -914,9 +915,6 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> faces,
/* Mapping edge -> loops. See #bke::mesh::normals_calc_loop for details. */
Array<int2> edge_to_loops(sharp_edges.size(), int2(0));
/* Simple mapping from a loop to its face index. */
const Array<int> loop_to_face = build_loop_to_face_map(faces);
mesh_edges_sharp_tag(faces,
corner_verts,
corner_edges,
@ -1341,17 +1339,6 @@ void normals_calc_loop(const Span<float3> vert_positions,
* Note also that loose edges always have both values set to 0! */
Array<int2> edge_to_loops(edges.size(), int2(0));
/* Simple mapping from a loop to its face index. */
Span<int> loop_to_face;
Array<int> local_loop_to_face_map;
if (loop_to_face_map.is_empty()) {
local_loop_to_face_map = build_loop_to_face_map(faces);
loop_to_face = local_loop_to_face_map;
}
else {
loop_to_face = loop_to_face_map;
}
CornerNormalSpaceArray _lnors_spacearr;
#ifdef DEBUG_TIME
@ -1374,7 +1361,7 @@ void normals_calc_loop(const Span<float3> vert_positions,
common_data.corner_verts = corner_verts;
common_data.corner_edges = corner_edges;
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_face = loop_to_face;
common_data.loop_to_face = loop_to_face_map;
common_data.face_normals = face_normals;
common_data.vert_normals = vert_normals;

View File

@ -1267,12 +1267,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
blender::Array<blender::float3> face_cents_src;
Array<int> vert_to_loop_src_offsets;
Array<int> vert_to_loop_src_indices;
GroupedSpan<int> vert_to_loop_map_src;
Array<int> vert_to_face_src_offsets;
Array<int> vert_to_face_src_indices;
GroupedSpan<int> vert_to_face_map_src;
Array<int> edge_to_face_src_offsets;
@ -1283,7 +1278,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
int *face_to_looptri_map_src_buff = nullptr;
/* Unlike above, those are one-to-one mappings, simpler! */
blender::Array<int> loop_to_face_map_src;
blender::Span<int> loop_to_face_map_src;
const blender::Span<blender::float3> positions_src = me_src->vert_positions();
const int num_verts_src = me_src->totvert;
@ -1335,15 +1330,9 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (use_from_vert) {
vert_to_loop_map_src = bke::mesh::build_vert_to_loop_map(
corner_verts_src, num_verts_src, vert_to_loop_src_offsets, vert_to_loop_src_indices);
vert_to_loop_map_src = me_src->vert_to_corner_map();
if (mode & MREMAP_USE_POLY) {
vert_to_face_map_src = bke::mesh::build_vert_to_face_map(faces_src,
corner_verts_src,
num_verts_src,
vert_to_face_src_offsets,
vert_to_face_src_indices);
vert_to_face_map_src = me_src->vert_to_face_map();
}
}
@ -1355,7 +1344,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
edge_to_face_src_indices);
if (use_from_vert) {
loop_to_face_map_src = blender::bke::mesh::build_loop_to_face_map(faces_src);
loop_to_face_map_src = me_src->corner_to_face_map();
face_cents_src.reinitialize(faces_src.size());
for (const int64_t i : faces_src.index_range()) {
face_cents_src[i] = blender::bke::mesh::face_center_calc(

View File

@ -386,27 +386,13 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
return;
}
Array<int> source_vert_to_loop_offsets;
Array<int> source_vert_to_loop_indices;
GroupedSpan<int> source_lmap;
Array<int> target_vert_to_loop_offsets;
Array<int> target_vert_to_loop_indices;
GroupedSpan<int> target_lmap;
BVHTreeFromMesh bvhtree = {nullptr};
threading::parallel_invoke(
[&]() { BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2); },
[&]() {
source_lmap = mesh::build_vert_to_loop_map(source->corner_verts(),
source->totvert,
source_vert_to_loop_offsets,
source_vert_to_loop_indices);
},
[&]() {
target_lmap = mesh::build_vert_to_loop_map(target->corner_verts(),
target->totvert,
target_vert_to_loop_offsets,
target_vert_to_loop_indices);
});
[&]() { source_lmap = source->vert_to_corner_map(); },
[&]() { target_lmap = target->vert_to_corner_map(); });
const Span<float3> target_positions = target->vert_positions();
Array<int> nearest_src_verts(target_positions.size());

View File

@ -14,6 +14,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_array_utils.hh"
#include "BLI_math_geom.h"
#include "BLI_task.hh"
#include "BLI_timeit.hh"
@ -22,6 +23,7 @@
#include "BKE_editmesh_cache.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_mapping.hh"
#include "BKE_mesh_runtime.hh"
#include "BKE_shrinkwrap.h"
#include "BKE_subdiv_ccg.hh"
@ -125,6 +127,58 @@ static void try_tag_verts_no_face_none(const Mesh &mesh)
} // namespace blender::bke
blender::Span<int> Mesh::corner_to_face_map() const
{
using namespace blender;
this->runtime->corner_to_face_map_cache.ensure([&](Array<int> &r_data) {
const OffsetIndices faces = this->faces();
r_data = bke::mesh::build_loop_to_face_map(faces);
});
return this->runtime->corner_to_face_map_cache.data();
}
blender::OffsetIndices<int> Mesh::vert_to_face_map_offsets() const
{
using namespace blender;
this->runtime->vert_to_face_offset_cache.ensure([&](Array<int> &r_data) {
r_data = Array<int>(this->totvert + 1, 0);
offset_indices::build_reverse_offsets(this->corner_verts(), r_data);
});
return OffsetIndices<int>(this->runtime->vert_to_face_offset_cache.data());
}
blender::GroupedSpan<int> Mesh::vert_to_face_map() const
{
using namespace blender;
const OffsetIndices offsets = this->vert_to_face_map_offsets();
this->runtime->vert_to_face_map_cache.ensure([&](Array<int> &r_data) {
r_data.reinitialize(this->totloop);
if (this->runtime->vert_to_corner_map_cache.is_cached() &&
this->runtime->corner_to_face_map_cache.is_cached())
{
/* The vertex to face cache can be built from the vertex to face corner
* and face corner to face maps if they are both already cached. */
array_utils::gather(this->runtime->vert_to_corner_map_cache.data().as_span(),
this->runtime->corner_to_face_map_cache.data().as_span(),
r_data.as_mutable_span());
}
else {
bke::mesh::build_vert_to_face_indices(this->faces(), this->corner_verts(), offsets, r_data);
}
});
return {offsets, this->runtime->vert_to_face_map_cache.data()};
}
blender::GroupedSpan<int> Mesh::vert_to_corner_map() const
{
using namespace blender;
const OffsetIndices offsets = this->vert_to_face_map_offsets();
this->runtime->vert_to_corner_map_cache.ensure([&](Array<int> &r_data) {
r_data = bke::mesh::build_vert_to_corner_indices(this->corner_verts(), offsets);
});
return {offsets, this->runtime->vert_to_corner_map_cache.data()};
}
const blender::bke::LooseVertCache &Mesh::loose_verts() const
{
using namespace blender::bke;
@ -250,6 +304,10 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
free_bvh_cache(*mesh->runtime);
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->bounds_cache.tag_dirty();
mesh->runtime->vert_to_face_offset_cache.tag_dirty();
mesh->runtime->vert_to_face_map_cache.tag_dirty();
mesh->runtime->vert_to_corner_map_cache.tag_dirty();
mesh->runtime->corner_to_face_map_cache.tag_dirty();
mesh->runtime->vert_normals_cache.tag_dirty();
mesh->runtime->face_normals_cache.tag_dirty();
mesh->runtime->loose_edges_cache.tag_dirty();
@ -271,6 +329,9 @@ void BKE_mesh_tag_edges_split(Mesh *mesh)
free_bvh_cache(*mesh->runtime);
mesh->runtime->vert_normals_cache.tag_dirty();
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->vert_to_face_offset_cache.tag_dirty();
mesh->runtime->vert_to_face_map_cache.tag_dirty();
mesh->runtime->vert_to_corner_map_cache.tag_dirty();
if (mesh->runtime->loose_edges_cache.is_cached() &&
mesh->runtime->loose_edges_cache.data().count != 0)
{
@ -299,6 +360,7 @@ void BKE_mesh_tag_face_winding_changed(Mesh *mesh)
mesh->runtime->vert_normals_cache.tag_dirty();
mesh->runtime->face_normals_cache.tag_dirty();
mesh->runtime->corner_normals_cache.tag_dirty();
mesh->runtime->vert_to_corner_map_cache.tag_dirty();
}
void BKE_mesh_tag_positions_changed(Mesh *mesh)

View File

@ -469,10 +469,6 @@ void multires_force_sculpt_rebuild(Object *object)
BKE_pbvh_free(ss->pbvh);
object->sculpt->pbvh = nullptr;
}
ss->vert_to_face_indices = {};
ss->vert_to_face_offsets = {};
ss->pmap = {};
}
void multires_force_external_reload(Object *object)

View File

@ -72,14 +72,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
blender::MutableSpan<blender::float3> base_positions = base_mesh->vert_positions_for_write();
/* Update the context in case the vertices were duplicated. */
reshape_context->base_positions = base_positions;
blender::Array<int> vert_to_face_offsets;
blender::Array<int> vert_to_face_indices;
const blender::GroupedSpan<int> pmap = blender::bke::mesh::build_vert_to_face_map(
reshape_context->base_faces,
reshape_context->base_corner_verts,
base_mesh->totvert,
vert_to_face_offsets,
vert_to_face_indices);
const blender::GroupedSpan<int> pmap = base_mesh->vert_to_face_map();
float(*origco)[3] = static_cast<float(*)[3]>(
MEM_calloc_arrayN(base_mesh->totvert, sizeof(float[3]), __func__));

View File

@ -925,7 +925,6 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
MultiresUnsubdivideContext *context)
{
Mesh *original_mesh = context->original_mesh;
const blender::OffsetIndices original_faces = original_mesh->faces();
Mesh *base_mesh = context->base_mesh;
@ -953,7 +952,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract(
BM_elem_flag_set(v, BM_ELEM_TAG, true);
}
context->loop_to_face_map = blender::bke::mesh::build_loop_to_face_map(original_faces);
context->loop_to_face_map = original_mesh->corner_to_face_map();
}
/**

View File

@ -52,7 +52,7 @@ struct MultiresUnsubdivideContext {
/* Private data. */
BMesh *bm_original_mesh;
blender::Array<int> loop_to_face_map;
blender::Span<int> loop_to_face_map;
const int *base_to_orig_vmap;
};

View File

@ -490,8 +490,8 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
BLI_strncpy(sock->identifier, identifier.data(), sizeof(sock->identifier));
BLI_strncpy(sock->name, name.data(), sizeof(sock->name));
STRNCPY(sock->identifier, identifier.data());
STRNCPY(sock->name, name.data());
sock->storage = nullptr;
sock->flag |= SOCK_COLLAPSED;
@ -519,7 +519,7 @@ static void construct_interface_as_legacy_sockets(bNodeTree *ntree)
}
if (socket.description) {
BLI_strncpy(iosock->description, socket.description, sizeof(iosock->description));
STRNCPY(iosock->description, socket.description);
}
node_socket_copy_default_value_data(
eNodeSocketDatatype(iosock->typeinfo->type), iosock->default_value, socket.socket_data);
@ -812,6 +812,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
blender::bke::forward_compat::write_legacy_sockets(writer, ntree);
}
BLO_write_struct(writer, GeometryNodeAssetTraits, ntree->geometry_node_asset_traits);
BLO_write_struct_array(
writer, bNestedNodeRef, ntree->nested_node_refs_num, ntree->nested_node_refs);

View File

@ -758,7 +758,7 @@ int bNodeTreeInterfacePanel::find_valid_insert_position_for_item(
break;
}
if (items[test_pos]->item_type == NODE_INTERFACE_PANEL) {
/* Found valid position, insering moves the first panel. */
/* Found valid position, inserting moves the first panel. */
pos = test_pos;
break;
}
@ -1205,7 +1205,7 @@ bNodeTreeInterfaceItem *bNodeTreeInterface::insert_item_copy(const bNodeTreeInte
bool bNodeTreeInterface::remove_item(bNodeTreeInterfaceItem &item, bool move_content_to_parent)
{
bNodeTreeInterfacePanel *parent = this->find_item_parent(item);
bNodeTreeInterfacePanel *parent = this->find_item_parent(item, true);
if (parent == nullptr) {
return false;
}

View File

@ -1391,13 +1391,7 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss)
void BKE_sculptsession_free_vwpaint_data(SculptSession *ss)
{
SculptVertexPaintGeomMap *gmap = nullptr;
if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
gmap = &ss->mode.vpaint.gmap;
}
else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
gmap = &ss->mode.wpaint.gmap;
if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight);
if (ss->mode.wpaint.dvert_prev) {
BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert);
@ -1405,15 +1399,6 @@ void BKE_sculptsession_free_vwpaint_data(SculptSession *ss)
ss->mode.wpaint.dvert_prev = nullptr;
}
}
else {
return;
}
gmap->vert_to_loop_offsets = {};
gmap->vert_to_loop_indices = {};
gmap->vert_to_loop = {};
gmap->vert_to_face_offsets = {};
gmap->vert_to_face_indices = {};
gmap->vert_to_face = {};
}
/**
@ -1459,8 +1444,6 @@ static void sculptsession_free_pbvh(Object *object)
ss->pbvh = nullptr;
}
ss->vert_to_face_offsets = {};
ss->vert_to_face_indices = {};
ss->pmap = {};
ss->edge_to_face_offsets = {};
ss->edge_to_face_indices = {};
@ -1776,12 +1759,8 @@ static void sculpt_update_object(
sculpt_attribute_update_refs(ob);
sculpt_update_persistent_base(ob);
if (ob->type == OB_MESH && ss->pmap.is_empty()) {
ss->pmap = blender::bke::mesh::build_vert_to_face_map(me->faces(),
me->corner_verts(),
me->totvert,
ss->vert_to_face_offsets,
ss->vert_to_face_indices);
if (ob->type == OB_MESH) {
ss->pmap = me->vert_to_face_map();
}
if (ss->pbvh) {
@ -2236,7 +2215,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
subdiv_ccg->grids,
subdiv_ccg->num_grids,
&key,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_to_face_map,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
base_mesh,
@ -2325,7 +2304,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
BKE_pbvh_grids_update(pbvh,
subdiv_ccg->grids,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_to_face_map,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
&key);

View File

@ -914,7 +914,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
CCGKey *key,
void **gridfaces,
blender::Span<int> grid_to_face_map,
DMFlagMat *flagmats,
BLI_bitmap **grid_hidden,
Mesh *me,
@ -924,7 +924,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
pbvh->header.type = PBVH_GRIDS;
pbvh->grids = grids;
pbvh->gridfaces = gridfaces;
pbvh->grid_to_face_map = grid_to_face_map;
pbvh->grid_flag_mats = flagmats;
pbvh->totgrid = totgrid;
pbvh->gridkey = *key;
@ -1715,10 +1715,11 @@ void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int
pbvh_iter_begin(&iter, pbvh, {});
SubdivCCGFace *all_faces = pbvh->subdiv_ccg->faces;
while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) {
if (node->flag & PBVH_UpdateNormals) {
for (const int grid : node->prim_indices) {
void *face = pbvh->gridfaces[grid];
void *face = &all_faces[pbvh->grid_to_face_map[grid]];
BLI_gset_add(face_set, face);
}
@ -2944,14 +2945,14 @@ void BKE_pbvh_draw_debug_cb(PBVH *pbvh,
void BKE_pbvh_grids_update(PBVH *pbvh,
CCGElem **grids,
void **gridfaces,
blender::Span<int> grid_to_face_map,
DMFlagMat *flagmats,
BLI_bitmap **grid_hidden,
CCGKey *key)
{
pbvh->gridkey = *key;
pbvh->grids = grids;
pbvh->gridfaces = gridfaces;
pbvh->grid_to_face_map = grid_to_face_map;
if (flagmats != pbvh->grid_flag_mats || pbvh->grid_hidden != grid_hidden) {
pbvh->grid_flag_mats = flagmats;

View File

@ -175,7 +175,7 @@ struct PBVH {
/* Grid Data */
CCGKey gridkey;
CCGElem **grids;
void **gridfaces;
blender::Span<int> grid_to_face_map;
const DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;

View File

@ -158,7 +158,7 @@ static void scene_init_data(ID *id)
STRNCPY(scene->r.bake.filepath, U.renderdir);
mblur_shutter_curve = &scene->r.mblur_shutter_curve;
BKE_curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(mblur_shutter_curve);
BKE_curvemap_reset(mblur_shutter_curve->cm,
&mblur_shutter_curve->clipr,

View File

@ -1270,7 +1270,7 @@ bool BKE_screen_area_map_blend_read_data(BlendDataReader *reader, ScrAreaMap *ar
static void regions_remove_invalid(SpaceType *space_type, ListBase *regionbase)
{
LISTBASE_FOREACH_MUTABLE (ARegion *, region, regionbase) {
if (BKE_regiontype_from_id(space_type, region->regiontype) != NULL) {
if (BKE_regiontype_from_id(space_type, region->regiontype) != nullptr) {
continue;
}

View File

@ -2,10 +2,12 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include <sstream>
#include "BKE_collection.h"
#include "BKE_curves.hh"
#include "BKE_main.h"
#include "BKE_simulation_state.hh"
#include "BKE_simulation_state_serialize.hh"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
@ -21,213 +23,13 @@
namespace blender::bke::sim {
void ModifierSimulationCache::try_discover_bake(const StringRefNull absolute_bake_dir)
void SimulationZoneCache::reset()
{
if (failed_finding_bake_) {
return;
}
char meta_dir[FILE_MAX];
BLI_path_join(meta_dir, sizeof(meta_dir), absolute_bake_dir.c_str(), "meta");
char bdata_dir[FILE_MAX];
BLI_path_join(bdata_dir, sizeof(bdata_dir), absolute_bake_dir.c_str(), "bdata");
if (!BLI_is_dir(meta_dir) || !BLI_is_dir(bdata_dir)) {
failed_finding_bake_ = true;
return;
}
direntry *dir_entries = nullptr;
const int dir_entries_num = BLI_filelist_dir_contents(meta_dir, &dir_entries);
BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
if (dir_entries_num == 0) {
failed_finding_bake_ = true;
return;
}
this->reset();
{
std::lock_guard lock(states_at_frames_mutex_);
for (const int i : IndexRange(dir_entries_num)) {
const direntry &dir_entry = dir_entries[i];
const StringRefNull dir_entry_path = dir_entry.path;
if (!dir_entry_path.endswith(".json")) {
continue;
}
char modified_file_name[FILE_MAX];
STRNCPY(modified_file_name, dir_entry.relname);
BLI_string_replace_char(modified_file_name, '_', '.');
const SubFrame frame = std::stof(modified_file_name);
auto new_state_at_frame = std::make_unique<ModifierSimulationStateAtFrame>();
new_state_at_frame->frame = frame;
new_state_at_frame->state.bdata_dir_ = bdata_dir;
new_state_at_frame->state.meta_path_ = dir_entry.path;
new_state_at_frame->state.owner_ = this;
states_at_frames_.append(std::move(new_state_at_frame));
}
bdata_sharing_ = std::make_unique<BDataSharing>();
this->cache_state = CacheState::Baked;
}
}
static int64_t find_state_at_frame(
const Span<std::unique_ptr<ModifierSimulationStateAtFrame>> states, const SubFrame &frame)
{
const int64_t i = binary_search::find_predicate_begin(
states, [&](const auto &item) { return item->frame >= frame; });
if (i == states.size()) {
return -1;
}
return i;
}
static int64_t find_state_at_frame_exact(
const Span<std::unique_ptr<ModifierSimulationStateAtFrame>> states, const SubFrame &frame)
{
const int64_t i = find_state_at_frame(states, frame);
if (i == -1) {
return -1;
}
if (states[i]->frame != frame) {
return -1;
}
return i;
}
bool ModifierSimulationCache::has_state_at_frame(const SubFrame &frame) const
{
std::lock_guard lock(states_at_frames_mutex_);
return find_state_at_frame_exact(states_at_frames_, frame) != -1;
}
bool ModifierSimulationCache::has_states() const
{
std::lock_guard lock(states_at_frames_mutex_);
return !states_at_frames_.is_empty();
}
const ModifierSimulationState *ModifierSimulationCache::get_state_at_exact_frame(
const SubFrame &frame) const
{
std::lock_guard lock(states_at_frames_mutex_);
const int64_t i = find_state_at_frame_exact(states_at_frames_, frame);
if (i == -1) {
return nullptr;
}
return &states_at_frames_[i]->state;
}
ModifierSimulationState &ModifierSimulationCache::get_state_at_frame_for_write(
const SubFrame &frame)
{
std::lock_guard lock(states_at_frames_mutex_);
const int64_t i = find_state_at_frame_exact(states_at_frames_, frame);
if (i != -1) {
return states_at_frames_[i]->state;
}
if (!states_at_frames_.is_empty()) {
BLI_assert(frame > states_at_frames_.last()->frame);
}
states_at_frames_.append(std::make_unique<ModifierSimulationStateAtFrame>());
states_at_frames_.last()->frame = frame;
states_at_frames_.last()->state.owner_ = this;
return states_at_frames_.last()->state;
}
StatesAroundFrame ModifierSimulationCache::get_states_around_frame(const SubFrame &frame) const
{
std::lock_guard lock(states_at_frames_mutex_);
const int64_t i = find_state_at_frame(states_at_frames_, frame);
StatesAroundFrame states_around_frame{};
if (i == -1) {
if (!states_at_frames_.is_empty() && states_at_frames_.last()->frame < frame) {
states_around_frame.prev = states_at_frames_.last().get();
}
return states_around_frame;
}
if (states_at_frames_[i]->frame == frame) {
states_around_frame.current = states_at_frames_[i].get();
}
if (i > 0) {
states_around_frame.prev = states_at_frames_[i - 1].get();
}
if (i < states_at_frames_.size() - 2) {
states_around_frame.next = states_at_frames_[i + 1].get();
}
return states_around_frame;
}
SimulationZoneState *ModifierSimulationState::get_zone_state(const SimulationZoneID &zone_id)
{
std::lock_guard lock{mutex_};
if (auto *ptr = zone_states_.lookup_ptr(zone_id)) {
return ptr->get();
}
return nullptr;
}
const SimulationZoneState *ModifierSimulationState::get_zone_state(
const SimulationZoneID &zone_id) const
{
std::lock_guard lock{mutex_};
if (auto *ptr = zone_states_.lookup_ptr(zone_id)) {
return ptr->get();
}
return nullptr;
}
SimulationZoneState &ModifierSimulationState::get_zone_state_for_write(
const SimulationZoneID &zone_id)
{
std::lock_guard lock{mutex_};
return *zone_states_.lookup_or_add_cb(zone_id,
[]() { return std::make_unique<SimulationZoneState>(); });
}
void ModifierSimulationState::ensure_bake_loaded(const bNodeTree &ntree) const
{
std::scoped_lock lock{mutex_};
if (bake_loaded_) {
return;
}
if (!meta_path_ || !bdata_dir_) {
return;
}
const std::shared_ptr<io::serialize::Value> io_root_value = io::serialize::read_json_file(
*meta_path_);
if (!io_root_value) {
return;
}
const DictionaryValue *io_root = io_root_value->as_dictionary_value();
if (!io_root) {
return;
}
const DiskBDataReader bdata_reader{*bdata_dir_};
deserialize_modifier_simulation_state(ntree,
*io_root,
bdata_reader,
*owner_->bdata_sharing_,
const_cast<ModifierSimulationState &>(*this));
bake_loaded_ = true;
}
void ModifierSimulationCache::reset()
{
std::lock_guard lock(states_at_frames_mutex_);
states_at_frames_.clear();
bdata_sharing_.reset();
this->realtime_cache.current_state.reset();
this->realtime_cache.prev_state.reset();
this->frame_caches.clear();
this->prev_state.reset();
this->bdata_dir.reset();
this->bdata_sharing.reset();
this->failed_finding_bake = false;
this->cache_state = CacheState::Valid;
}
@ -239,10 +41,106 @@ void scene_simulation_states_reset(Scene &scene)
continue;
}
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
nmd->runtime->simulation_cache->reset();
if (!nmd->runtime->simulation_cache) {
continue;
}
for (auto item : nmd->runtime->simulation_cache->cache_by_zone_id.items()) {
item.value->reset();
}
}
}
FOREACH_SCENE_OBJECT_END;
}
std::optional<std::string> get_modifier_simulation_bake_path(const Main &bmain,
const Object &object,
const NodesModifierData &nmd)
{
const StringRefNull bmain_path = BKE_main_blendfile_path(&bmain);
if (bmain_path.is_empty()) {
return std::nullopt;
}
if (StringRef(nmd.simulation_bake_directory).is_empty()) {
return std::nullopt;
}
const char *base_path = ID_BLEND_PATH(&bmain, &object.id);
char absolute_bake_dir[FILE_MAX];
STRNCPY(absolute_bake_dir, nmd.simulation_bake_directory);
BLI_path_abs(absolute_bake_dir, base_path);
return absolute_bake_dir;
}
std::optional<bake_paths::BakePath> get_simulation_zone_bake_path(const Main &bmain,
const Object &object,
const NodesModifierData &nmd,
int zone_id)
{
const std::optional<std::string> modifier_bake_path = get_modifier_simulation_bake_path(
bmain, object, nmd);
if (!modifier_bake_path) {
return std::nullopt;
}
char zone_bake_dir[FILE_MAX];
BLI_path_join(zone_bake_dir,
sizeof(zone_bake_dir),
modifier_bake_path->c_str(),
std::to_string(zone_id).c_str());
return bake_paths::BakePath::from_single_root(zone_bake_dir);
}
/**
* Turn the name into something that can be used as file name. It does not necessarily have to be
* human readable, but it can help if it is at least partially readable.
*/
static std::string escape_name(const StringRef name)
{
std::stringstream ss;
for (const char c : name) {
/* Only some letters allowed. Digits are not because they could lead to name collisions. */
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
ss << c;
}
else {
ss << int(c);
}
}
return ss.str();
}
static std::string get_blend_file_name(const Main &bmain)
{
const StringRefNull blend_file_path = BKE_main_blendfile_path(&bmain);
char blend_name[FILE_MAX];
BLI_path_split_file_part(blend_file_path.c_str(), blend_name, sizeof(blend_name));
const int64_t type_start_index = StringRef(blend_name).rfind(".");
if (type_start_index == StringRef::not_found) {
return "";
}
blend_name[type_start_index] = '\0';
return "blendcache_" + StringRef(blend_name);
}
static std::string get_modifier_sim_name(const Object &object, const ModifierData &md)
{
const std::string object_name_escaped = escape_name(object.id.name + 2);
const std::string modifier_name_escaped = escape_name(md.name);
return "sim_" + object_name_escaped + "_" + modifier_name_escaped;
}
std::string get_default_modifier_bake_directory(const Main &bmain,
const Object &object,
const ModifierData &md)
{
char dir[FILE_MAX];
/* Make path that's relative to the .blend file. */
BLI_path_join(dir,
sizeof(dir),
"//",
get_blend_file_name(bmain).c_str(),
get_modifier_sim_name(object, md).c_str());
return dir;
}
} // namespace blender::bke::sim

View File

@ -1,193 +0,0 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_curves.hh"
#include "BKE_instances.hh"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.hh"
#include "BKE_node_runtime.hh"
#include "BKE_pointcloud.h"
#include "BKE_simulation_state_serialize.hh"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BLI_endian_defines.h"
#include "BLI_endian_switch.h"
#include "BLI_fileops.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_path_util.h"
#include "RNA_access.hh"
#include "RNA_enum_types.hh"
#include <sstream>
namespace blender::bke::sim {
/**
* Turn the name into something that can be used as file name. It does not necessarily have to be
* human readable, but it can help if it is at least partially readable.
*/
static std::string escape_name(const StringRef name)
{
std::stringstream ss;
for (const char c : name) {
/* Only some letters allowed. Digits are not because they could lead to name collisions. */
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
ss << c;
}
else {
ss << int(c);
}
}
return ss.str();
}
static std::string get_blend_file_name(const Main &bmain)
{
const StringRefNull blend_file_path = BKE_main_blendfile_path(&bmain);
char blend_name[FILE_MAX];
BLI_path_split_file_part(blend_file_path.c_str(), blend_name, sizeof(blend_name));
const int64_t type_start_index = StringRef(blend_name).rfind(".");
if (type_start_index == StringRef::not_found) {
return "";
}
blend_name[type_start_index] = '\0';
return "blendcache_" + StringRef(blend_name);
}
static std::string get_modifier_sim_name(const Object &object, const ModifierData &md)
{
const std::string object_name_escaped = escape_name(object.id.name + 2);
const std::string modifier_name_escaped = escape_name(md.name);
return "sim_" + object_name_escaped + "_" + modifier_name_escaped;
}
std::string get_default_modifier_bake_directory(const Main &bmain,
const Object &object,
const ModifierData &md)
{
char dir[FILE_MAX];
/* Make path that's relative to the .blend file. */
BLI_path_join(dir,
sizeof(dir),
"//",
get_blend_file_name(bmain).c_str(),
get_modifier_sim_name(object, md).c_str());
return dir;
}
/**
* Version written to the baked data.
*/
static constexpr int serialize_format_version = 2;
void serialize_modifier_simulation_state(const ModifierSimulationState &state,
BDataWriter &bdata_writer,
BDataSharing &bdata_sharing,
DictionaryValue &r_io_root)
{
r_io_root.append_int("version", serialize_format_version);
auto io_zones = r_io_root.append_array("zones");
for (const auto item : state.zone_states_.items()) {
const SimulationZoneID &zone_id = item.key;
const SimulationZoneState &zone_state = *item.value;
auto io_zone = io_zones->append_dict();
io_zone->append_int("state_id", zone_id.nested_node_id);
auto io_state_items = io_zone->append_array("state_items");
for (const MapItem<int, std::unique_ptr<BakeItem>> &state_item_with_id :
zone_state.item_by_identifier.items())
{
auto io_state_item = io_state_items->append_dict();
io_state_item->append_int("id", state_item_with_id.key);
serialize_bake_item(*state_item_with_id.value, bdata_writer, bdata_sharing, *io_state_item);
}
}
}
void deserialize_modifier_simulation_state(const bNodeTree &ntree,
const DictionaryValue &io_root,
const BDataReader &bdata_reader,
const BDataSharing &bdata_sharing,
ModifierSimulationState &r_state)
{
io::serialize::JsonFormatter formatter;
const std::optional<int> version = io_root.lookup_int("version");
if (!version) {
return;
}
if (*version > serialize_format_version) {
return;
}
const io::serialize::ArrayValue *io_zones = io_root.lookup_array("zones");
if (!io_zones) {
return;
}
for (const auto &io_zone_value : io_zones->elements()) {
const DictionaryValue *io_zone = io_zone_value->as_dictionary_value();
if (!io_zone) {
continue;
}
bke::sim::SimulationZoneID zone_id;
if (const std::optional<int> state_id = io_zone->lookup_int("state_id")) {
zone_id.nested_node_id = *state_id;
}
else if (const io::serialize::ArrayValue *io_zone_id = io_zone->lookup_array("zone_id")) {
/* In the initial release of simulation nodes, the entire node id path was written to the
* baked data. For backward compatibility the node ids are read here and then the nested node
* id is looked up. */
Vector<int> node_ids;
for (const auto &io_zone_id_element : io_zone_id->elements()) {
const io::serialize::IntValue *io_node_id = io_zone_id_element->as_int_value();
if (!io_node_id) {
continue;
}
node_ids.append(io_node_id->value());
}
const bNestedNodeRef *nested_node_ref = ntree.nested_node_ref_from_node_id_path(node_ids);
if (!nested_node_ref) {
continue;
}
zone_id.nested_node_id = nested_node_ref->id;
}
const io::serialize::ArrayValue *io_state_items = io_zone->lookup_array("state_items");
if (!io_state_items) {
continue;
}
auto zone_state = std::make_unique<bke::sim::SimulationZoneState>();
for (const auto &io_state_item_value : io_state_items->elements()) {
const DictionaryValue *io_state_item = io_state_item_value->as_dictionary_value();
if (!io_state_item) {
continue;
}
const std::optional<int> state_item_id = io_state_item->lookup_int("id");
if (!state_item_id) {
continue;
}
std::unique_ptr<BakeItem> new_state_item = deserialize_bake_item(
*io_state_item, bdata_reader, bdata_sharing);
BLI_assert(new_state_item);
zone_state->item_by_identifier.add(*state_item_id, std::move(new_state_item));
}
r_state.zone_states_.add_overwrite(zone_id, std::move(zone_state));
}
}
} // namespace blender::bke::sim

View File

@ -789,6 +789,19 @@ void BKE_sound_update_scene_sound(void *handle, bSound *sound)
AUD_SequenceEntry_setSound(handle, sound->playback_handle);
}
#endif /* WITH_AUDASPACE */
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle)
{
#ifdef WITH_AUDASPACE
AUD_SequenceEntry_setSound(handle, sound_handle);
#else
UNUSED_VARS(handle, sound_handle);
#endif
}
#ifdef WITH_AUDASPACE
void BKE_sound_set_cfra(int cfra)
{
sound_cfra = cfra;

View File

@ -155,8 +155,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
if (num_faces) {
subdiv_ccg->faces = static_cast<SubdivCCGFace *>(
MEM_calloc_arrayN(num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces"));
subdiv_ccg->grid_faces = static_cast<SubdivCCGFace **>(
MEM_calloc_arrayN(num_grids, sizeof(SubdivCCGFace *), "Subdiv CCG grid faces"));
subdiv_ccg->grid_to_face_map.reinitialize(num_grids);
}
}
@ -235,7 +234,7 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_
const float grid_size_1_inv = 1.0f / (grid_size - 1);
const int element_size = element_size_bytes_get(subdiv_ccg);
SubdivCCGFace *faces = subdiv_ccg->faces;
SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
blender::MutableSpan<int> grid_to_face_map = subdiv_ccg->grid_to_face_map;
const SubdivCCGFace *face = &faces[face_index];
for (int corner = 0; corner < face->num_grids; corner++) {
const int grid_index = face->start_grid_index + corner;
@ -252,7 +251,7 @@ static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_
}
}
/* Assign grid's face. */
grid_faces[grid_index] = &faces[face_index];
grid_to_face_map[grid_index] = face_index;
/* Assign material flags. */
subdiv_ccg->grid_flag_mats[grid_index] = data->material_flags_evaluator->eval_material_flags(
data->material_flags_evaluator, face_index);
@ -266,7 +265,7 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_
const float grid_size_1_inv = 1.0f / (grid_size - 1);
const int element_size = element_size_bytes_get(subdiv_ccg);
SubdivCCGFace *faces = subdiv_ccg->faces;
SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
blender::MutableSpan<int> grid_to_face_map = subdiv_ccg->grid_to_face_map;
const SubdivCCGFace *face = &faces[face_index];
for (int corner = 0; corner < face->num_grids; corner++) {
const int grid_index = face->start_grid_index + corner;
@ -282,7 +281,7 @@ static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_
}
}
/* Assign grid's face. */
grid_faces[grid_index] = &faces[face_index];
grid_to_face_map[grid_index] = face_index;
/* Assign material flags. */
subdiv_ccg->grid_flag_mats[grid_index] = data->material_flags_evaluator->eval_material_flags(
data->material_flags_evaluator, face_index);
@ -596,7 +595,6 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
BKE_subdiv_free(subdiv_ccg->subdiv);
}
MEM_SAFE_FREE(subdiv_ccg->faces);
MEM_SAFE_FREE(subdiv_ccg->grid_faces);
/* Free map of adjacent edges. */
for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) {
SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i];
@ -1452,7 +1450,7 @@ static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG *subdiv_cc
BLI_INLINE
int next_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
{
SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
const SubdivCCGFace *face = &subdiv_ccg->faces[subdiv_ccg->grid_to_face_map[coord->grid_index]];
const int face_grid_index = coord->grid_index;
int next_face_grid_index = face_grid_index + 1 - face->start_grid_index;
if (next_face_grid_index == face->num_grids) {
@ -1462,7 +1460,7 @@ int next_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord
}
BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord)
{
SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
const SubdivCCGFace *face = &subdiv_ccg->faces[subdiv_ccg->grid_to_face_map[coord->grid_index]];
const int face_grid_index = coord->grid_index;
int prev_face_grid_index = face_grid_index - 1 - face->start_grid_index;
if (prev_face_grid_index < 0) {
@ -1478,7 +1476,7 @@ static void neighbor_coords_corner_center_get(const SubdivCCG *subdiv_ccg,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
const SubdivCCGFace *face = &subdiv_ccg->faces[subdiv_ccg->grid_to_face_map[coord->grid_index]];
const int num_adjacent_grids = face->num_grids;
subdiv_ccg_neighbors_init(
@ -1506,7 +1504,7 @@ static int adjacent_vertex_index_from_coord(const SubdivCCG *subdiv_ccg,
Subdiv *subdiv = subdiv_ccg->subdiv;
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
const SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
const SubdivCCGFace *face = &subdiv_ccg->faces[subdiv_ccg->grid_to_face_map[coord->grid_index]];
const int face_index = face - subdiv_ccg->faces;
const int face_grid_index = coord->grid_index - face->start_grid_index;
const int num_face_grids = face->num_grids;
@ -1583,7 +1581,7 @@ static int adjacent_edge_index_from_coord(const SubdivCCG *subdiv_ccg, const Sub
{
Subdiv *subdiv = subdiv_ccg->subdiv;
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
const SubdivCCGFace *face = &subdiv_ccg->faces[subdiv_ccg->grid_to_face_map[coord->grid_index]];
const int face_grid_index = coord->grid_index - face->start_grid_index;
const int face_index = face - subdiv_ccg->faces;
@ -1876,9 +1874,7 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index)
{
const SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index];
const int face_index = face - subdiv_ccg->faces;
return face_index;
return subdiv_ccg->grid_to_face_map[grid_index];
}
const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG *subdiv_ccg)

View File

@ -1196,6 +1196,11 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
Mesh *result = subdiv_context.subdiv_mesh;
/* NOTE: Using normals from the limit surface gives different results than Blender's vertex
* normal calculation. Since vertex normals are supposed to be a consistent cache, don't bother
* calculating them here. The work may have been pointless anyway if the mesh is deformed or
* changed afterwards. */
/* Move the optimal display edge array to the final bit vector. */
if (!subdiv_context.subdiv_display_edges.is_empty()) {
const Span<bool> span = subdiv_context.subdiv_display_edges;
@ -1224,12 +1229,6 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
// BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Using normals from the limit surface gives different results than Blender's vertex normal
* calculation. Since vertex normals are supposed to be a consistent cache, don't bother
* calculating them here. The work may have been pointless anyway if the mesh is deformed or
* changed afterwards. */
BLI_assert(BKE_mesh_vert_normals_are_dirty(result) || BKE_mesh_face_normals_are_dirty(result));
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
}

View File

@ -85,11 +85,6 @@ struct SubFrame {
{
return a.frame_ >= b.frame_ || (a.frame_ == b.frame_ && a.subframe_ >= b.subframe_);
}
friend std::ostream &operator<<(std::ostream &stream, const SubFrame &a)
{
return stream << float(a);
}
};
} // namespace blender

View File

@ -2309,6 +2309,8 @@ float voronoi_n_sphere_radius(const VoronoiParams &params, const float4 coord)
/* **** Fractal Voronoi **** */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
template<typename T>
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &params,
const T coord,
@ -2319,8 +2321,7 @@ VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &params,
float scale = 1.0f;
VoronoiOutput output;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f ||
params.lacunarity == 0.0f;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceilf(params.detail); ++i) {
VoronoiOutput octave = (params.feature == NOISE_SHD_VORONOI_F2) ?
@ -2367,6 +2368,8 @@ VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &params,
return output;
}
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
template<typename T>
float fractal_voronoi_distance_to_edge(const VoronoiParams &params, const T coord)
{
@ -2375,8 +2378,7 @@ float fractal_voronoi_distance_to_edge(const VoronoiParams &params, const T coor
float scale = 1.0f;
float distance = 8.0f;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f ||
params.lacunarity == 0.0f;
const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceilf(params.detail); ++i) {
const float octave_distance = voronoi_distance_to_edge(params, coord * scale);

View File

@ -999,7 +999,7 @@ void blo_do_versions_270(FileData *fd, Library * /*lib*/, Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "CurveMapping", "mblur_shutter_curve")) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
CurveMapping *curve_mapping = &scene->r.mblur_shutter_curve;
BKE_curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(curve_mapping);
BKE_curvemap_reset(
curve_mapping->cm, &curve_mapping->clipr, CURVE_PRESET_MAX, CURVEMAP_SLOPE_POS_NEG);

View File

@ -71,7 +71,7 @@
#include "BKE_modifier.h"
#include "BKE_node.hh"
#include "BKE_screen.h"
#include "BKE_simulation_state_serialize.hh"
#include "BKE_simulation_state.hh"
#include "BKE_workspace.h"
#include "RNA_access.hh"

View File

@ -144,17 +144,16 @@ static void version_bonelayers_to_bonecollections(Main *bmain)
if (arm_idprops) {
/* See if we can use the layer name from the Bone Manager add-on. This is a popular add-on
* for managing bone layers and giving them names. */
BLI_snprintf(custom_prop_name, sizeof(custom_prop_name), "layer_name_%u", layer);
SNPRINTF(custom_prop_name, "layer_name_%u", layer);
IDProperty *prop = IDP_GetPropertyFromGroup(arm_idprops, custom_prop_name);
if (prop != nullptr && prop->type == IDP_STRING && IDP_String(prop)[0] != '\0') {
BLI_snprintf(
bcoll_name, sizeof(bcoll_name), "Layer %u - %s", layer + 1, IDP_String(prop));
SNPRINTF(bcoll_name, "Layer %u - %s", layer + 1, IDP_String(prop));
}
}
if (bcoll_name[0] == '\0') {
/* Either there was no name defined in the custom property, or
* it was the empty string. */
BLI_snprintf(bcoll_name, sizeof(bcoll_name), "Layer %u", layer + 1);
SNPRINTF(bcoll_name, "Layer %u", layer + 1);
}
/* Create a new bone collection for this layer. */
@ -984,7 +983,7 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
else {
/* Legacy node tree sockets are created for forward compatibilty,
/* Legacy node tree sockets are created for forward compatibility,
* but have to be freed after loading and versioning. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
/* Clear legacy sockets after conversion.

View File

@ -871,6 +871,9 @@ void blo_do_versions_userdef(UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
/* Clear deprecated USER_MENUFIXEDORDER user flag for reuse. */
userdef->uiflag &= ~USER_UIFLAG_UNUSED_4;
}
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {

View File

@ -24,7 +24,7 @@ float ior_from_f0(float f0)
}
/* Simplified form of F_eta(eta, 1.0). */
float f0_from_ior(float eta)
float F0_from_ior(float eta)
{
float A = (eta - 1.0) / (eta + 1.0);
return A * A;
@ -69,7 +69,7 @@ float F_eta(float eta, float cos_theta)
/* Fresnel color blend base on fresnel factor */
vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
{
float f0 = f0_from_ior(eta);
float f0 = F0_from_ior(eta);
float fac = saturate((fresnel - f0) / (1.0 - f0));
return mix(f0_color, vec3(1.0), fac);
}

View File

@ -95,11 +95,12 @@ float ambient_occlusion_eval(vec3 normal,
vec3 safe_normalize(vec3 N);
float fast_sqrt(float a);
vec3 cameraVec(vec3 P);
vec2 btdf_lut(float a, float b, float c);
vec2 btdf_lut(float a, float b, float c, float d);
vec2 brdf_lut(float a, float b);
vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c);
vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c);
float F_eta(float a, float b);
float F0_from_ior(float a);
#endif
#ifdef VOLUMETRICS

View File

@ -74,7 +74,7 @@ vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
}
/* Returns GGX BTDF in first component and fresnel in second. */
vec2 btdf_lut(float cos_theta, float roughness, float ior)
vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
if (ior <= 1e-5) {
return vec2(0.0);
@ -82,17 +82,17 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
if (ior >= 1.0) {
vec2 split_sum = brdf_lut(cos_theta, roughness);
float f0 = f0_from_ior(ior);
/* Baked IOR for GGX BRDF. */
const float specular = 1.0;
const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
/* Avoid harsh transition coming from ior == 1. */
float f90 = fast_sqrt(saturate(f0 / (f0_from_ior(eta_brdf) * 0.25)));
float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r;
/* Setting the BTDF to one is not really important since it is only used for multi-scatter
* and it's already quite close to ground truth. */
float btdf = 1.0;
return vec2(btdf, fresnel);
float f0 = F0_from_ior(ior);
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
* transition at `IOR == 1`. */
float f90 = fast_sqrt(saturate(f0 / 0.02));
float brdf = F_brdf_multi_scatter(vec3(f0), vec3(f90), split_sum).r;
/* Energy conservation. */
float btdf = 1.0 - brdf;
/* Assuming the energy loss caused by single-scattering is distributed proportionally in the
* reflection and refraction lobes. */
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
}
vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
@ -101,15 +101,21 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
float layer_floored = floor(layer);
coords.z = lut_btdf_layer_first + layer_floored;
vec2 btdf_low = textureLod(utilTex, coords, 0.0).rg;
vec2 btdf_brdf_low = textureLod(utilTex, coords, 0.0).rg;
coords.z += 1.0;
vec2 btdf_high = textureLod(utilTex, coords, 0.0).rg;
vec2 btdf_brdf_high = textureLod(utilTex, coords, 0.0).rg;
/* Manual trilinear interpolation. */
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
return btdf;
if (do_multiscatter != 0.0) {
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming
* the energy loss of single-scattering is distributed proportionally in the two lobes. */
btdf_brdf /= (btdf_brdf.x + btdf_brdf.y);
}
return btdf_brdf;
}
/** \} */

View File

@ -63,7 +63,7 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness
/* Empirical fit for refraction. */
/* TODO: find a better fit or precompute inside the LUT. */
cone_tan *= 0.5 * fast_sqrt(f0_from_ior((ior < 1.0) ? 1.0 / ior : ior));
cone_tan *= 0.5 * fast_sqrt(F0_from_ior((ior < 1.0) ? 1.0 / ior : ior));
float cone_footprint = hit_dist * cone_tan;

View File

@ -38,7 +38,7 @@ void main()
}
/* Stubs */
vec2 btdf_lut(float a, float b, float c)
vec2 btdf_lut(float a, float b, float c, float d)
{
return vec2(0.0);
}

View File

@ -316,7 +316,7 @@ vec2 brdf_lut(float cos_theta, float roughness)
#endif
}
vec2 btdf_lut(float cos_theta, float roughness, float ior)
vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
if (ior <= 1e-5) {
return vec2(0.0);
@ -325,16 +325,16 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
if (ior >= 1.0) {
vec2 split_sum = brdf_lut(cos_theta, roughness);
float f0 = F0_from_ior(ior);
/* Baked IOR for GGX BRDF. */
const float specular = 1.0;
const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
/* Avoid harsh transition coming from ior == 1. */
float f90 = fast_sqrt(saturate(f0 / (F0_from_ior(eta_brdf) * 0.25)));
float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r;
/* Setting the BTDF to one is not really important since it is only used for multi-scatter
* and it's already quite close to ground truth. */
float btdf = 1.0;
return vec2(btdf, fresnel);
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
* transition at `IOR == 1`. */
float f90 = fast_sqrt(saturate(f0 / 0.02));
float brdf = F_brdf_multi_scatter(vec3(f0), vec3(f90), split_sum).r;
/* Energy conservation. */
float btdf = 1.0 - brdf;
/* Assuming the energy loss caused by single-scattering is distributed proportionally in the
* reflection and refraction lobes. */
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
}
/* IOR is sin of critical angle. */
@ -355,11 +355,18 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
#ifdef EEVEE_UTILITY_TX
coords.z = UTIL_BTDF_LAYER + layer_floored;
vec2 btdf_low = utility_tx_sample_lut(utility_tx, coords.xy, coords.z).rg;
vec2 btdf_high = utility_tx_sample_lut(utility_tx, coords.xy, coords.z + 1.0).rg;
vec2 btdf_brdf_low = utility_tx_sample_lut(utility_tx, coords.xy, coords.z).rg;
vec2 btdf_brdf_high = utility_tx_sample_lut(utility_tx, coords.xy, coords.z + 1.0).rg;
/* Manual trilinear interpolation. */
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
return btdf;
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
if (do_multiscatter != 0.0) {
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming
* the energy loss of single-scattering is distributed proportionally in the two lobes. */
btdf_brdf /= (btdf_brdf.x + btdf_brdf.y);
}
return btdf_brdf;
#else
return vec2(0.0);
#endif

View File

@ -292,9 +292,15 @@ void AntiAliasingPass::draw(Manager &manager,
draw_overlay_depth(sample0_depth_tx_);
GPU_texture_copy(sample0_depth_in_front_tx_, resources.depth_in_front_tx);
}
/* Copy back the saved depth buffer for correct overlays. */
GPU_texture_copy(depth_tx, sample0_depth_tx_);
GPU_texture_copy(depth_in_front_tx, sample0_depth_in_front_tx_);
if (!DRW_state_is_scene_render()) {
/* Copy back the saved depth buffer for correct overlays. */
GPU_texture_copy(depth_tx, sample0_depth_tx_);
GPU_texture_copy(depth_in_front_tx, sample0_depth_in_front_tx_);
}
else if (last_sample) {
GPU_texture_copy(depth_tx, sample0_depth_tx_);
/* There's no depth_in_front_tx in scene image renders. */
}
if (!DRW_state_is_image_render() || last_sample) {
smaa_weight_tx_.acquire(

View File

@ -826,6 +826,42 @@ bool match_slope_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float
/* ---------------- */
void shear_fcurve_segment(FCurve *fcu,
FCurveSegment *segment,
const float factor,
tShearDirection direction)
{
const BezTriple *left_key = fcurve_segment_start_get(fcu, segment->start_index);
const BezTriple *right_key = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
const float key_x_range = right_key->vec[1][0] - left_key->vec[1][0];
const float key_y_range = right_key->vec[1][1] - left_key->vec[1][1];
/* Happens if there is only 1 key on the FCurve. Needs to be skipped because it
* would be a divide by 0. */
if (IS_EQF(key_x_range, 0.0f)) {
return;
}
for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
/* For easy calculation of the curve, the values are normalized. */
float normalized_x;
if (direction == SHEAR_FROM_LEFT) {
normalized_x = (fcu->bezt[i].vec[1][0] - left_key->vec[1][0]) / key_x_range;
}
else {
normalized_x = (right_key->vec[1][0] - fcu->bezt[i].vec[1][0]) / key_x_range;
}
const float y_delta = key_y_range * normalized_x;
const float key_y_value = fcu->bezt[i].vec[1][1] + y_delta * factor;
BKE_fcurve_keyframe_move_value_with_handles(&fcu->bezt[i], key_y_value);
}
}
/* ---------------- */
void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
{
const BezTriple *left_bezt = fcurve_segment_start_get(fcu, segment->start_index);

View File

@ -87,7 +87,8 @@ static int bone_collection_add_exec(bContext *C, wmOperator * /* op */)
}
bArmature *armature = static_cast<bArmature *>(ob->data);
ANIM_armature_bonecoll_new(armature, nullptr);
BoneCollection *bcoll = ANIM_armature_bonecoll_new(armature, nullptr);
ANIM_armature_bonecoll_active_set(armature, bcoll);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
return OPERATOR_FINISHED;
@ -166,7 +167,7 @@ void ARMATURE_OT_collection_move(wmOperatorType *ot)
static const EnumPropertyItem bcoll_slot_move[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
{0, NULL, 0, NULL, NULL},
{0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@ -371,7 +372,7 @@ void ARMATURE_OT_collection_assign(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna,
"name",
NULL,
nullptr,
MAX_NAME,
"Bone Collection",
"Name of the bone collection to assign this bone to; empty to assign to the "
@ -432,7 +433,7 @@ void ARMATURE_OT_collection_unassign(wmOperatorType *ot)
RNA_def_string(ot->srna,
"name",
NULL,
nullptr,
MAX_NAME,
"Bone Collection",
"Name of the bone collection to unassign this bone from; empty to unassign from "
@ -465,13 +466,7 @@ static void bone_collection_select(bContext *C,
if (!editbone_is_member(ebone, bcoll)) {
continue;
}
if (select) {
ebone->flag |= BONE_SELECTED;
}
else {
ebone->flag &= ~BONE_SELECTED;
}
ED_armature_ebone_select_set(ebone, select);
}
}
else {
@ -494,7 +489,12 @@ static void bone_collection_select(bContext *C,
}
DEG_id_tag_update(&armature->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
if (is_editmode) {
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
}
else {
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
}
if (is_editmode) {
ED_outliner_select_sync_from_edit_bone_tag(C);
@ -537,7 +537,7 @@ void ARMATURE_OT_collection_select(wmOperatorType *ot)
PropertyRNA *prop = RNA_def_string(
ot->srna,
"name",
NULL,
nullptr,
MAX_NAME,
"Bone Collection",
"Name of the bone collection to select bones from; empty use the active bone collection");
@ -577,7 +577,7 @@ void ARMATURE_OT_collection_deselect(wmOperatorType *ot)
PropertyRNA *prop = RNA_def_string(
ot->srna,
"name",
NULL,
nullptr,
MAX_NAME,
"Bone Collection",
"Name of the bone collection to deselect bones from; empty use the active bone collection");

View File

@ -749,6 +749,7 @@ MenuType node_group_operator_assets_menu()
type.poll = asset_menu_poll;
type.draw = node_add_catalog_assets_draw;
type.listener = asset::asset_reading_region_listen_fn;
type.context_dependent = true;
return type;
}

View File

@ -458,6 +458,14 @@ void smooth_fcurve_segment(FCurve *fcu,
int kernel_size,
double *kernel);
void ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, float factor);
enum tShearDirection {
SHEAR_FROM_LEFT = 1,
SHEAR_FROM_RIGHT,
};
void shear_fcurve_segment(struct FCurve *fcu,
struct FCurveSegment *segment,
float factor,
tShearDirection direction);
/**
* Shift the FCurve segment up/down so that it aligns with the key before/after
* the segment.

View File

@ -36,12 +36,22 @@ void ED_operatortypes_uvedit();
void ED_operatormacros_uvedit();
void ED_keymap_uvedit(wmKeyConfig *keyconf);
bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float min[2], float max[2]);
/**
* Be careful when using this, it bypasses all synchronization options.
*/
void ED_uvedit_select_all(BMesh *bm);
void ED_uvedit_foreach_uv(const Scene *scene,
BMesh *bm,
const bool skip_invisible,
const bool selected,
blender::FunctionRef<void(float[2])> user_fn);
void ED_uvedit_foreach_uv_multi(const Scene *scene,
Object **objects_edit,
uint objects_len,
const bool skip_invisible,
const bool skip_nonselected,
blender::FunctionRef<void(float[2])> user_fn);
bool ED_uvedit_minmax_multi(
const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]);
bool ED_uvedit_center_multi(
@ -53,8 +63,6 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
float r_center[2],
char mode,
bool *r_has_select);
bool ED_uvedit_center_from_pivot(
SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode);
bool ED_object_get_active_image(Object *ob,
int mat_nr,

View File

@ -145,23 +145,19 @@ enum {
/** #uiBlock.flag (controls) */
enum {
UI_BLOCK_LOOP = 1 << 0,
/** Indicate that items in a popup are drawn with inverted order. Used for arrow key navigation
* so that it knows to invert the navigation direction to match the drawing order. */
UI_BLOCK_IS_FLIP = 1 << 1,
UI_BLOCK_NO_FLIP = 1 << 2,
UI_BLOCK_NUMSELECT = 1 << 3,
UI_BLOCK_NUMSELECT = 1 << 1,
/** Don't apply window clipping. */
UI_BLOCK_NO_WIN_CLIP = 1 << 4,
UI_BLOCK_CLIPBOTTOM = 1 << 5,
UI_BLOCK_CLIPTOP = 1 << 6,
UI_BLOCK_MOVEMOUSE_QUIT = 1 << 7,
UI_BLOCK_KEEP_OPEN = 1 << 8,
UI_BLOCK_POPUP = 1 << 9,
UI_BLOCK_OUT_1 = 1 << 10,
UI_BLOCK_SEARCH_MENU = 1 << 11,
UI_BLOCK_POPUP_MEMORY = 1 << 12,
UI_BLOCK_NO_WIN_CLIP = 1 << 2,
UI_BLOCK_CLIPBOTTOM = 1 << 3,
UI_BLOCK_CLIPTOP = 1 << 4,
UI_BLOCK_MOVEMOUSE_QUIT = 1 << 5,
UI_BLOCK_KEEP_OPEN = 1 << 6,
UI_BLOCK_POPUP = 1 << 7,
UI_BLOCK_OUT_1 = 1 << 8,
UI_BLOCK_SEARCH_MENU = 1 << 9,
UI_BLOCK_POPUP_MEMORY = 1 << 10,
/** Stop handling mouse events. */
UI_BLOCK_CLIP_EVENTS = 1 << 13,
UI_BLOCK_CLIP_EVENTS = 1 << 11,
/* #uiBlock::flags bits 14-17 are identical to #uiBut::drawflag bits. */
@ -874,7 +870,6 @@ void UI_block_direction_set(uiBlock *block, char direction);
/**
* This call escapes if there's alignment flags.
*/
void UI_block_order_flip(uiBlock *block);
void UI_block_flag_enable(uiBlock *block, int flag);
void UI_block_flag_disable(uiBlock *block, int flag);
void UI_block_translate(uiBlock *block, int x, int y);
@ -1365,7 +1360,7 @@ void UI_but_context_ptr_set(uiBlock *block, uiBut *but, const char *name, const
const PointerRNA *UI_but_context_ptr_get(const uiBut *but,
const char *name,
const StructRNA *type CPP_ARG_DEFAULT(nullptr));
bContextStore *UI_but_context_get(const uiBut *but);
const bContextStore *UI_but_context_get(const uiBut *but);
void UI_but_unit_type_set(uiBut *but, int unit_type);
int UI_but_unit_type_get(const uiBut *but);
@ -2111,7 +2106,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout);
void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr);
bContextStore *uiLayoutGetContextStore(uiLayout *layout);
void uiLayoutContextCopy(uiLayout *layout, bContextStore *context);
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context);
/**
* Set tooltip function for all buttons in the layout.

View File

@ -3523,10 +3523,6 @@ void UI_block_free(const bContext *C, uiBlock *block)
MEM_freeN(block->func_argN);
}
LISTBASE_FOREACH_MUTABLE (bContextStore *, store, &block->contexts) {
CTX_store_free(store);
}
BLI_freelistN(&block->saferct);
BLI_freelistN(&block->color_pickers.list);
BLI_freelistN(&block->dynamic_listeners);
@ -4315,7 +4311,6 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
if (!item->identifier[0]) {
/* inconsistent, but menus with categories do not look good flipped */
if (item->name) {
block->flag |= UI_BLOCK_NO_FLIP;
categories++;
entries_nosepr_count++;
}
@ -4347,8 +4342,8 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
const char *title = RNA_property_ui_name(but->rnaprop);
if (title[0] && (categories == 0) && (block->flag & UI_BLOCK_NO_FLIP)) {
/* Title at the top for menus with categories. */
if (title[0] && !but->str[0] && (categories == 0)) {
/* Show title when no categories and calling button has no text. */
uiDefBut(block,
UI_BTYPE_LABEL,
0,
@ -4472,32 +4467,11 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
}
}
if (title[0] && (categories == 0) && !(block->flag & UI_BLOCK_NO_FLIP)) {
/* Title at the bottom for menus without categories. */
uiItemS(layout);
uiDefBut(block,
UI_BTYPE_LABEL,
0,
title,
0,
0,
UI_UNIT_X * 5,
UI_UNIT_Y,
nullptr,
0.0,
0.0,
0,
0,
"");
}
UI_block_layout_set_current(block, layout);
if (free) {
MEM_freeN((void *)item_array);
}
BLI_assert((block->flag & UI_BLOCK_IS_FLIP) == 0);
block->flag |= UI_BLOCK_IS_FLIP;
}
static void ui_def_but_rna__panel_type(bContext *C, uiLayout *layout, void *but_p)
@ -4739,7 +4713,7 @@ static uiBut *ui_def_but_rna(uiBlock *block,
* access it. */
const PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
if (pptr.data && RNA_struct_is_ID(pptr.type)) {
but->context = CTX_store_add(&block->contexts, "id", &pptr);
but->context = CTX_store_add(block->contexts, "id", &pptr);
}
}
@ -5852,39 +5826,6 @@ void UI_block_direction_set(uiBlock *block, char direction)
block->direction = direction;
}
void UI_block_order_flip(uiBlock *block)
{
float centy, miny = 10000, maxy = -10000;
if (U.uiflag & USER_MENUFIXEDORDER) {
return;
}
if (block->flag & UI_BLOCK_NO_FLIP) {
return;
}
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->drawflag & UI_BUT_ALIGN) {
return;
}
if (but->rect.ymin < miny) {
miny = but->rect.ymin;
}
if (but->rect.ymax > maxy) {
maxy = but->rect.ymax;
}
}
/* mirror trick */
centy = (miny + maxy) / 2.0f;
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
but->rect.ymin = centy - (but->rect.ymin - centy);
but->rect.ymax = centy - (but->rect.ymax - centy);
std::swap(but->rect.ymin, but->rect.ymax);
}
block->flag ^= UI_BLOCK_IS_FLIP;
}
void UI_block_flag_enable(uiBlock *block, int flag)
{
block->flag |= flag;
@ -5967,8 +5908,9 @@ PointerRNA *UI_but_operator_ptr_get(uiBut *but)
void UI_but_context_ptr_set(uiBlock *block, uiBut *but, const char *name, const PointerRNA *ptr)
{
but->context = CTX_store_add(&block->contexts, name, ptr);
but->context->used = true;
bContextStore *ctx = CTX_store_add(block->contexts, name, ptr);
ctx->used = true;
but->context = ctx;
}
const PointerRNA *UI_but_context_ptr_get(const uiBut *but, const char *name, const StructRNA *type)
@ -5976,7 +5918,7 @@ const PointerRNA *UI_but_context_ptr_get(const uiBut *but, const char *name, con
return CTX_store_ptr_lookup(but->context, name, type);
}
bContextStore *UI_but_context_get(const uiBut *but)
const bContextStore *UI_but_context_get(const uiBut *but)
{
return but->context;
}
@ -6666,7 +6608,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
tmp = BLI_strdup(WM_operatortype_name(but->optype, opptr).c_str());
}
else {
bContextStore *previous_ctx = CTX_store_get(C);
const bContextStore *previous_ctx = CTX_store_get(C);
CTX_store_set(C, but->context);
tmp = BLI_strdup(WM_operatortype_description(C, but->optype, opptr).c_str());
CTX_store_set(C, previous_ctx);

View File

@ -489,7 +489,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
uiPopupMenu *pup;
uiLayout *layout;
bContextStore *previous_ctx = CTX_store_get(C);
const bContextStore *previous_ctx = CTX_store_get(C);
{
uiStringInfo label = {BUT_GET_LABEL, nullptr};
@ -946,7 +946,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
if (view_item_but) {
BLI_assert(view_item_but->type == UI_BTYPE_VIEW_ITEM);
bContextStore *prev_ctx = CTX_store_get(C);
const bContextStore *prev_ctx = CTX_store_get(C);
/* Sub-layout for context override. */
uiLayout *sub = uiLayoutColumn(layout, false);
set_layout_context_from_button(C, sub, view_item_but);

View File

@ -503,7 +503,7 @@ struct uiAfterFunc {
uiBlockInteraction_CallbackData custom_interaction_callbacks;
uiBlockInteraction_Handle *custom_interaction_handle;
bContextStore *context;
std::optional<bContextStore> context;
char undostr[BKE_UNDO_STR_MAX];
char drawstr[UI_MAX_DRAW_STR];
@ -789,7 +789,7 @@ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot,
}
if (context_but && context_but->context) {
after->context = CTX_store_copy(context_but->context);
after->context = *context_but->context;
}
if (context_but) {
@ -905,7 +905,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
}
if (but->context) {
after->context = CTX_store_copy(but->context);
after->context = *but->context;
}
ui_but_drawstr_without_sep_char(but, after->drawstr, sizeof(after->drawstr));
@ -1020,7 +1020,7 @@ static void ui_apply_but_funcs_after(bContext *C)
MEM_delete(afterf);
if (after.context) {
CTX_store_set(C, after.context);
CTX_store_set(C, &after.context.value());
}
if (after.popup_op) {
@ -1053,7 +1053,6 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.context) {
CTX_store_set(C, nullptr);
CTX_store_free(after.context);
}
if (after.func) {
@ -10483,19 +10482,18 @@ static int ui_handle_menu_event(bContext *C,
if (val == KM_PRESS) {
/* Determine scroll operation. */
uiMenuScrollType scrolltype;
const bool ui_block_flipped = (block->flag & UI_BLOCK_IS_FLIP) != 0;
if (ELEM(type, EVT_PAGEUPKEY, EVT_HOMEKEY)) {
scrolltype = ui_block_flipped ? MENU_SCROLL_TOP : MENU_SCROLL_BOTTOM;
scrolltype = MENU_SCROLL_TOP;
}
else if (ELEM(type, EVT_PAGEDOWNKEY, EVT_ENDKEY)) {
scrolltype = ui_block_flipped ? MENU_SCROLL_BOTTOM : MENU_SCROLL_TOP;
scrolltype = MENU_SCROLL_BOTTOM;
}
else if (ELEM(type, EVT_UPARROWKEY, WHEELUPMOUSE)) {
scrolltype = ui_block_flipped ? MENU_SCROLL_UP : MENU_SCROLL_DOWN;
scrolltype = MENU_SCROLL_UP;
}
else {
scrolltype = ui_block_flipped ? MENU_SCROLL_DOWN : MENU_SCROLL_UP;
scrolltype = MENU_SCROLL_DOWN;
}
if (ui_menu_pass_event_to_parent_if_nonactive(
@ -11053,10 +11051,10 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
if (menu->scrolltimer == nullptr) {
menu->scrolltimer = WM_event_timer_add(
CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL);
menu->scrolltimer->duration = 0.0;
menu->scrolltimer->time_duration = 0.0;
}
const double duration = menu->scrolltimer->duration;
const double duration = menu->scrolltimer->time_duration;
float event_xy[2] = {float(event->xy[0]), float(event->xy[1])};

View File

@ -202,7 +202,7 @@ struct uiBut {
uiButHandleNFunc funcN = nullptr;
void *func_argN = nullptr;
bContextStore *context = nullptr;
const bContextStore *context = nullptr;
uiButCompleteFunc autocomplete_func = nullptr;
void *autofunc_arg = nullptr;
@ -487,7 +487,7 @@ struct uiBlock {
ListBase layouts;
uiLayout *curlayout;
ListBase contexts;
blender::Vector<std::unique_ptr<bContextStore>> contexts;
/** A block can store "views" on data-sets. Currently tree-views (#AbstractTreeView) only.
* Others are imaginable, e.g. table-views, grid-views, etc. These are stored here to support

View File

@ -1290,7 +1290,6 @@ static void ui_item_menu_hold(bContext *C, ARegion *butregion, uiBut *but)
UI_popup_menu_but_set(pup, butregion, but);
block->flag |= UI_BLOCK_POPUP_HOLD;
block->flag |= UI_BLOCK_IS_FLIP;
char direction = UI_DIR_DOWN;
if (!but->drawstr[0]) {
@ -1554,9 +1553,6 @@ void uiItemsFullEnumO_items(uiLayout *layout,
if (item->name) {
if (item != item_array && !radial && split != nullptr) {
target = uiLayoutColumn(split, layout->align);
/* inconsistent, but menus with labels do not look good flipped */
block->flag |= UI_BLOCK_NO_FLIP;
}
uiBut *but;
@ -1647,7 +1643,7 @@ void uiItemsFullEnumO(uiLayout *layout,
}
else {
bContext *C = static_cast<bContext *>(block->evil_C);
bContextStore *previous_ctx = CTX_store_get(C);
const bContextStore *previous_ctx = CTX_store_get(C);
CTX_store_set(C, layout->context);
RNA_property_enum_items_gettexted(C, &ptr, prop, &item_array, &totitem, &free);
CTX_store_set(C, previous_ctx);
@ -1659,9 +1655,6 @@ void uiItemsFullEnumO(uiLayout *layout,
if (free) {
MEM_freeN((void *)item_array);
}
/* intentionally don't touch UI_BLOCK_IS_FLIP here,
* we don't know the context this is called in */
}
else if (prop && RNA_property_type(prop) != PROP_ENUM) {
RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
@ -2723,8 +2716,6 @@ void uiItemsEnumR(uiLayout *layout, PointerRNA *ptr, const char *propname)
if (item[i].name) {
if (i != 0) {
column = uiLayoutColumn(split, false);
/* inconsistent, but menus with labels do not look good flipped */
block->flag |= UI_BLOCK_NO_FLIP;
}
uiItemL(column, item[i].name, ICON_NONE);
@ -2742,9 +2733,6 @@ void uiItemsEnumR(uiLayout *layout, PointerRNA *ptr, const char *propname)
if (free) {
MEM_freeN((void *)item);
}
/* intentionally don't touch UI_BLOCK_IS_FLIP here,
* we don't know the context this is called in */
}
/* Pointer RNA button with search */
@ -2955,20 +2943,13 @@ void uiItemPointerR(uiLayout *layout,
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
{
MenuType *mt = (MenuType *)arg_mt;
UI_menutype_draw(C, mt, layout);
/* Menus are created flipped (from event handling point of view). */
layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
}
void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
{
PanelType *pt = (PanelType *)arg_pt;
UI_paneltype_draw(C, pt, layout);
/* Panels are created flipped (from event handling POV). */
layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
}
static uiBut *ui_item_menu(uiLayout *layout,
@ -3096,7 +3077,7 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
return;
}
bContextStore *previous_ctx = CTX_store_get(C);
const bContextStore *previous_ctx = CTX_store_get(C);
UI_menutype_draw(C, mt, layout);
/* Restore context that was cleared by `UI_menutype_draw`. */
@ -3576,8 +3557,6 @@ static void menu_item_enum_opname_menu(bContext * /*C*/, uiLayout *layout, void
uiLayoutSetOperatorContext(layout, lvl->opcontext);
uiItemsFullEnumO(layout, lvl->opname, lvl->propname, op_props, lvl->opcontext, UI_ITEM_NONE);
layout->root->block->flag |= UI_BLOCK_IS_FLIP;
/* override default, needed since this was assumed pre 2.70 */
UI_block_direction_set(layout->root->block, UI_DIR_DOWN);
}
@ -3668,7 +3647,6 @@ static void menu_item_enum_rna_menu(bContext * /*C*/, uiLayout *layout, void *ar
uiLayoutSetOperatorContext(layout, lvl->opcontext);
uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
layout->root->block->flag |= UI_BLOCK_IS_FLIP;
}
void uiItemMenuEnumR_prop(
@ -5703,7 +5681,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
if (layout->context) {
but->context = layout->context;
but->context->used = true;
layout->context->used = true;
}
if (layout->emboss != UI_EMBOSS_UNDEFINED) {
@ -5832,7 +5810,7 @@ bool UI_block_layout_needs_resolving(const uiBlock *block)
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
{
uiBlock *block = layout->root->block;
layout->context = CTX_store_add(&block->contexts, name, ptr);
layout->context = CTX_store_add(block->contexts, name, ptr);
}
bContextStore *uiLayoutGetContextStore(uiLayout *layout)
@ -5840,10 +5818,10 @@ bContextStore *uiLayoutGetContextStore(uiLayout *layout)
return layout->context;
}
void uiLayoutContextCopy(uiLayout *layout, bContextStore *context)
void uiLayoutContextCopy(uiLayout *layout, const bContextStore *context)
{
uiBlock *block = layout->root->block;
layout->context = CTX_store_add_all(&block->contexts, context);
layout->context = CTX_store_add_all(block->contexts, context);
}
void uiLayoutSetTooltipFunc(uiLayout *layout,

Some files were not shown because too many files have changed in this diff Show More