WIP: Experiment: Drop import operator helper and file drop type #111242

Closed
Guillermo Venegas wants to merge 23 commits from guishe/blender:drop-helper into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
242 changed files with 3441 additions and 1629 deletions
Showing only changes of commit c91f7cb42a - Show all commits

View File

@ -573,6 +573,12 @@ bool BVHMetal::build_BLAS_hair(Progress &progress,
return true;
}
# else /* MAC_OS_VERSION_14_0 */
(void)progress;
(void)device;
(void)queue;
(void)geom;
(void)(refit);
# endif /* MAC_OS_VERSION_14_0 */
return false;
}
@ -1145,8 +1151,7 @@ bool BVHMetal::build_TLAS(Progress &progress,
unique_blas_array.clear();
unique_blas_array.reserve(all_blas.count);
[all_blas enumerateObjectsUsingBlock:^(
id<MTLAccelerationStructure> blas, NSUInteger, BOOL *) {
[all_blas enumerateObjectsUsingBlock:^(id<MTLAccelerationStructure> blas, NSUInteger, BOOL *) {
unique_blas_array.push_back(blas);
}];

View File

@ -46,11 +46,12 @@ TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
{
TReturn result;
#ifdef __BVH_LOCAL__
# ifdef __BVH_LOCAL__
MetalKernelContext context(launch_params_metal);
if ((object != payload.local_object) || context.intersection_skip_self_local(payload.self, prim)) {
/* Only intersect with matching object and skip self-intersecton. */
if ((object != payload.local_object) || context.intersection_skip_self_local(payload.self, prim))
{
/* Only intersect with matching object and skip self-intersection. */
result.accept = false;
result.continue_search = true;
return result;
@ -138,7 +139,11 @@ __anyhit__cycles_metalrt_local_hit_tri_prim(
return metalrt_local_hit<PrimitiveIntersectionResult, METALRT_HIT_TRIANGLE>(
launch_params_metal, payload, payload.local_object, prim, barycentrics, ray_tmax);
}
[[intersection(triangle, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
[[intersection(triangle,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] PrimitiveIntersectionResult
__anyhit__cycles_metalrt_local_hit_tri(
constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload [[payload]],
@ -149,10 +154,19 @@ __anyhit__cycles_metalrt_local_hit_tri(
float ray_tmax [[distance]])
{
return metalrt_local_hit<PrimitiveIntersectionResult, METALRT_HIT_TRIANGLE>(
launch_params_metal, payload, instance_id, primitive_id + primitive_id_offset, barycentrics, ray_tmax);
launch_params_metal,
payload,
instance_id,
primitive_id + primitive_id_offset,
barycentrics,
ray_tmax);
}
[[intersection(bounding_box, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] BoundingBoxIntersectionResult
[[intersection(bounding_box,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] BoundingBoxIntersectionResult
__anyhit__cycles_metalrt_local_hit_box(const float ray_tmax [[max_distance]])
{
/* unused function */
@ -182,21 +196,20 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
const float2 barycentrics,
const float ray_tmax,
const float t = 0.0f,
ccl_private const Ray *ray = NULL
)
ccl_private const Ray *ray = NULL)
{
#ifdef __SHADOW_RECORD_ALL__
# ifdef __SHADOW_RECORD_ALL__
float u = barycentrics.x;
float v = barycentrics.y;
const int prim_type = kernel_data_fetch(objects, object).primitive_type;
int type;
# ifdef __HAIR__
# ifdef __HAIR__
if constexpr (intersection_type == METALRT_HIT_CURVE) {
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
type = segment.type;
prim = segment.prim;
/* Filter out curve end-caps. */
if (u == 0.0f || u == 1.0f) {
/* continue search */
@ -257,7 +270,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
return false;
}
# ifdef __HAIR__
# ifdef __HAIR__
/* Always use baked shadow transparency for curves. */
if constexpr (intersection_type == METALRT_HIT_CURVE) {
float throughput = payload.throughput;
@ -274,7 +287,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
return true;
}
}
# endif
# endif
payload.num_hits += 1;
payload.num_recorded_hits += 1;
@ -320,7 +333,11 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
return true;
}
[[intersection(triangle, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
[[intersection(triangle,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] PrimitiveIntersectionResult
__anyhit__cycles_metalrt_shadow_all_hit_tri(
constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
@ -339,7 +356,11 @@ __anyhit__cycles_metalrt_shadow_all_hit_tri(
return result;
}
[[intersection(bounding_box, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] BoundingBoxIntersectionResult
[[intersection(bounding_box,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] BoundingBoxIntersectionResult
__anyhit__cycles_metalrt_shadow_all_hit_box(const float ray_tmax [[max_distance]])
{
/* unused function */
@ -358,12 +379,11 @@ inline TReturnType metalrt_visibility_test(
uint prim,
const float u,
const float t = 0.0f,
ccl_private const Ray *ray = NULL
)
ccl_private const Ray *ray = NULL)
{
TReturnType result;
#ifdef __HAIR__
# ifdef __HAIR__
if constexpr (intersection_type == METALRT_HIT_CURVE) {
/* Filter out curve end-caps. */
if (u == 0.0f || u == 1.0f) {
@ -371,7 +391,7 @@ inline TReturnType metalrt_visibility_test(
result.continue_search = true;
return result;
}
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
int type = segment.type;
prim = segment.prim;
@ -425,7 +445,11 @@ inline TReturnType metalrt_visibility_test(
return result;
}
[[intersection(triangle, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
[[intersection(triangle,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] PrimitiveIntersectionResult
__anyhit__cycles_metalrt_visibility_test_tri(
constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
@ -440,7 +464,11 @@ __anyhit__cycles_metalrt_visibility_test_tri(
return result;
}
[[intersection(bounding_box, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] BoundingBoxIntersectionResult
[[intersection(bounding_box,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] BoundingBoxIntersectionResult
__anyhit__cycles_metalrt_visibility_test_box(const float ray_tmax [[max_distance]])
{
/* Unused function */
@ -453,57 +481,59 @@ __anyhit__cycles_metalrt_visibility_test_box(const float ray_tmax [[max_distance
/* Primitive intersection functions. */
#ifdef __HAIR__
[[intersection(curve, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
# ifdef __HAIR__
[[intersection(
curve, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
__intersection__curve(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload
[[payload]],
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
const uint object [[instance_id]],
const uint primitive_id [[primitive_id]],
const uint primitive_id_offset [[user_instance_id]],
float distance [[distance]],
float distance [[distance]],
const float3 ray_P [[origin]],
const float3 ray_D [[direction]],
float u [[curve_parameter]],
const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]]
# if defined(__METALRT_MOTION__)
,const float time [[time]]
# endif
)
# if defined(__METALRT_MOTION__)
,
const float time [[time]]
# endif
)
{
uint prim = primitive_id + primitive_id_offset;
Ray ray;
ray.P = ray_P;
ray.D = ray_D;
#if defined(__METALRT_MOTION__)
# if defined(__METALRT_MOTION__)
ray.time = time;
#endif
# endif
PrimitiveIntersectionResult result =
metalrt_visibility_test<PrimitiveIntersectionResult, METALRT_HIT_CURVE>(
launch_params_metal, payload, object, prim, u, distance, &ray);
metalrt_visibility_test<PrimitiveIntersectionResult, METALRT_HIT_CURVE>(
launch_params_metal, payload, object, prim, u, distance, &ray);
return result;
}
[[intersection(curve, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
__intersection__curve_shadow(
constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload [[payload]],
const uint object [[instance_id]],
const uint primitive_id [[primitive_id]],
const uint primitive_id_offset [[user_instance_id]],
const float3 ray_P [[origin]],
const float3 ray_D [[direction]],
float u [[curve_parameter]],
float t [[distance]],
# if defined(__METALRT_MOTION__)
const float time [[time]],
# endif
const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
[[intersection(
curve, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] PrimitiveIntersectionResult
__intersection__curve_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload
[[payload]],
const uint object [[instance_id]],
const uint primitive_id [[primitive_id]],
const uint primitive_id_offset [[user_instance_id]],
const float3 ray_P [[origin]],
const float3 ray_D [[direction]],
float u [[curve_parameter]],
float t [[distance]],
# if defined(__METALRT_MOTION__)
const float time [[time]],
# endif
const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
uint prim = primitive_id + primitive_id_offset;
@ -512,9 +542,9 @@ __intersection__curve_shadow(
Ray ray;
ray.P = ray_P;
ray.D = ray_D;
#if defined(__METALRT_MOTION__)
# if defined(__METALRT_MOTION__)
ray.time = time;
#endif
# endif
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_CURVE>(
launch_params_metal, payload, object, prim, float2(u, 0), ray_tmax, t, &ray);
@ -583,7 +613,11 @@ ccl_device_inline void metalrt_intersection_point_shadow(
}
}
[[intersection(bounding_box, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] BoundingBoxIntersectionResult
[[intersection(bounding_box,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] BoundingBoxIntersectionResult
__intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
const uint object [[instance_id]],
@ -591,9 +625,9 @@ __intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1
const uint primitive_id_offset [[user_instance_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
# if defined(__METALRT_MOTION__)
# if defined(__METALRT_MOTION__)
const float time [[time]],
# endif
# endif
const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
@ -624,7 +658,11 @@ __intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1
return result;
}
[[intersection(bounding_box, triangle_data, curve_data, METALRT_TAGS, extended_limits)]] BoundingBoxIntersectionResult
[[intersection(bounding_box,
triangle_data,
curve_data,
METALRT_TAGS,
extended_limits)]] BoundingBoxIntersectionResult
__intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload
[[payload]],
@ -633,9 +671,9 @@ __intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[b
const uint primitive_id_offset [[user_instance_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
# if defined(__METALRT_MOTION__)
# if defined(__METALRT_MOTION__)
const float time [[time]],
# endif
# endif
const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{

View File

@ -788,7 +788,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
const int diffuse_bounce = INTEGRATOR_STATE(state, path, diffuse_bounce);
const int bounce = INTEGRATOR_STATE(state, path, bounce);
/* Set diffuse bounce info . */
/* Set diffuse bounce info. */
INTEGRATOR_STATE_WRITE(state, path, diffuse_bounce) = diffuse_bounce + 1;
/* Evaluate light sample

View File

@ -31,6 +31,17 @@ struct ccl_align(8) LayerClosure
ccl_private const OSLClosure *top;
};
/* If we failed to allocate a layer-able closure, we need to zero out the albedo
* so that lower layers aren't falsely blocked.
* Therefore, to keep the code clean, set it to zero at the start and overwrite
* later if it succeeded. */
ccl_device_forceinline void osl_zero_albedo(float3 *layer_albedo)
{
if (layer_albedo != NULL) {
*layer_albedo = zero_float3();
}
}
ccl_device_forceinline bool osl_closure_skip(KernelGlobals kg,
ccl_private const ShaderData *sd,
uint32_t path_flag,
@ -182,6 +193,8 @@ ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg,
ccl_private const DielectricBSDFClosure *closure,
float3 *layer_albedo)
{
osl_zero_albedo(layer_albedo);
const bool has_reflection = !is_zero(closure->reflection_tint);
const bool has_transmission = !is_zero(closure->transmission_tint);
@ -240,8 +253,13 @@ ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg,
fresnel->transmission_tint = rgb_to_spectrum(closure->transmission_tint);
bsdf_microfacet_setup_fresnel_dielectric_tint(kg, bsdf, sd, fresnel, preserve_energy);
if (layer_albedo != NULL && has_reflection && !has_transmission) {
*layer_albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
if (layer_albedo != NULL) {
if (has_reflection && !has_transmission) {
*layer_albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
}
else {
*layer_albedo = one_float3();
}
}
}
@ -299,6 +317,8 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup(
ccl_private const GeneralizedSchlickBSDFClosure *closure,
float3 *layer_albedo)
{
osl_zero_albedo(layer_albedo);
const bool has_reflection = !is_zero(closure->reflection_tint);
const bool has_transmission = !is_zero(closure->transmission_tint);
@ -333,9 +353,6 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup(
else {
bsdf->ior = ior_from_F0(average(closure->f0));
}
if (sd->flag & SD_BACKFACING) {
bsdf->ior = 1.0f / bsdf->ior;
}
bool preserve_energy = false;
@ -373,8 +390,13 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup(
fresnel->exponent = closure->exponent;
bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, preserve_energy);
if (layer_albedo != NULL && has_reflection && !has_transmission) {
*layer_albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
if (layer_albedo != NULL) {
if (has_reflection && !has_transmission) {
*layer_albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
}
else {
*layer_albedo = one_float3();
}
}
}
@ -387,6 +409,8 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg,
ccl_private const MicrofacetClosure *closure,
float3 *layer_albedo)
{
osl_zero_albedo(layer_albedo);
const int label = (closure->refract) ? LABEL_TRANSMIT : LABEL_REFLECT;
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | label)) {
return;
@ -438,8 +462,13 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg,
}
}
if (layer_albedo != NULL && closure->refract == 0) {
*layer_albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
if (layer_albedo != NULL) {
if (closure->refract == 0) {
*layer_albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false);
}
else {
*layer_albedo = one_float3();
}
}
}
@ -485,6 +514,8 @@ ccl_device void osl_closure_microfacet_multi_ggx_aniso_setup(
ccl_private const MicrofacetMultiGGXClosure *closure,
float3 *layer_albedo)
{
osl_zero_albedo(layer_albedo);
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
return;
}
@ -545,6 +576,8 @@ ccl_device void osl_closure_sheen_setup(KernelGlobals kg,
ccl_private const SheenClosure *closure,
float3 *layer_albedo)
{
osl_zero_albedo(layer_albedo);
if (osl_closure_skip(kg, sd, path_flag, LABEL_DIFFUSE)) {
return;
}

View File

@ -13,6 +13,14 @@ shader node_subsurface_scattering(color Color = 0.8,
normal Normal = N,
output closure color BSSRDF = 0)
{
BSSRDF = Color *
bssrdf(method, Normal, Scale * Radius, Color, "ior", IOR, "anisotropy", Anisotropy);
BSSRDF = Color * bssrdf(method,
Normal,
Scale * Radius,
Color,
"ior",
IOR,
"anisotropy",
Anisotropy,
"roughness",
1.0);
}

View File

@ -943,7 +943,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
}
extensions_device.push_back("VK_KHR_dedicated_allocation");
extensions_device.push_back("VK_KHR_get_memory_requirements2");
/* Allow relaxed interface matching between shader stages.*/
/* Allow relaxed interface matching between shader stages. */
extensions_device.push_back("VK_KHR_maintenance4");
/* Enable MoltenVK required instance extensions. */
#ifdef VK_MVK_MOLTENVK_EXTENSION_NAME

View File

@ -5625,7 +5625,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
/* Ignore windowing requirements when running in background mode,
* as it doesn't make sense to fall back to X11 because of windowing functionality
* in background mode, also LIBDECOR is crashing in background mode `blender -b -f 1`
* for e.g. while it could be fixed, requiring the library at all makes no sense . */
* for e.g. while it could be fixed, requiring the library at all makes no sense. */
if (background) {
display_->libdecor_required = false;
}

View File

@ -1108,10 +1108,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
}
if (ELEM(status, XLookupChars, XLookupBoth)) {
if (uchar(utf8_buf[0]) >= 32) { /* not an ascii control character */
/* do nothing for now, this is valid utf8 */
}
else {
/* Check for ASCII control characters.
* Inline `iscntrl` because the users locale must not change behavior. */
if ((utf8_buf[0] < 32 && utf8_buf[0] > 0) || (utf8_buf[0] == 127)) {
utf8_buf[0] = '\0';
}
}

View File

@ -100,7 +100,7 @@ extern void *(*MEM_callocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_
* Allocate a block of memory of size (len * size), with tag name
* str, aborting in case of integer overflows to prevent vulnerabilities.
* The memory is cleared. The name must be static, because only a
* pointer to it is stored ! */
* pointer to it is stored! */
extern void *(*MEM_calloc_arrayN)(size_t len,
size_t size,
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
@ -108,7 +108,7 @@ extern void *(*MEM_calloc_arrayN)(size_t len,
/**
* Allocate a block of memory of size len, with tag name str. The
* name must be a static, because only a pointer to it is stored !
* name must be a static, because only a pointer to it is stored!
*/
extern void *(*MEM_mallocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2);
@ -116,7 +116,7 @@ extern void *(*MEM_mallocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_
/**
* Allocate a block of memory of size (len * size), with tag name str,
* aborting in case of integer overflow to prevent vulnerabilities. The
* name must be a static, because only a pointer to it is stored !
* name must be a static, because only a pointer to it is stored!
*/
extern void *(*MEM_malloc_arrayN)(size_t len,
size_t size,
@ -125,7 +125,7 @@ extern void *(*MEM_malloc_arrayN)(size_t len,
/**
* Allocate an aligned block of memory of size len, with tag name str. The
* name must be a static, because only a pointer to it is stored !
* name must be a static, because only a pointer to it is stored!
*/
extern void *(*MEM_mallocN_aligned)(size_t len,
size_t alignment,

View File

@ -214,7 +214,7 @@ const UserDef U_default = {
.file_space_data =
{
.display_type = FILE_VERTICALDISPLAY,
.thumbnail_size = 128,
.thumbnail_size = 96,
.sort_type = FILE_SORT_ALPHA,
.details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME,
.flag = FILE_HIDE_DOT,

View File

@ -56,7 +56,7 @@ const bTheme U_theme_default = {
.outline = RGBA(0x3d3d3dff),
.inner = RGBA(0x1d1d1dff),
.inner_sel = RGBA(0x181818ff),
.item = RGBA(0x4772b3ff),
.item = RGBA(0xffffff33),
.text = RGBA(0xe6e6e6ff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
@ -191,7 +191,7 @@ const bTheme U_theme_default = {
.outline = RGBA(0x2d2d2dff),
.inner = RGBA(0xffffff00),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0x4772b3ff),
.item = RGBA(0xffffff33),
.text = RGBA(0xccccccff),
.text_sel = RGBA(0xffffffff),
.roundness = 0.2f,
@ -758,8 +758,8 @@ const bTheme U_theme_default = {
.back = RGBA(0x3d3d3dff),
.sub_back = RGBA(0x0000001f),
},
.shade2 = RGBA(0x2d4366e6),
.hilite = RGBA(0xff0000ff),
.shade2 = RGBA(0x4d4d4de6),
.hilite = RGBA(0x65a2ffff),
.grid = RGBA(0x1d1d1dff),
.vertex_size = 3,
.outline_width = 1,
@ -767,7 +767,7 @@ const bTheme U_theme_default = {
.syntaxl = RGBA(0xe6d573ff),
.syntaxs = RGBA(0xff734dff),
.syntaxb = RGBA(0xe62e67ff),
.syntaxn = RGBA(0x48c5e6ff),
.syntaxn = RGBA(0x48d9e6ff),
.syntaxv = RGBA(0x689d06ff),
.syntaxc = RGBA(0x939393ff),
.syntaxd = RGBA(0x9c73e6ff),

View File

@ -369,10 +369,11 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
mod.__time__ = os.path.getmtime(mod.__file__)
mod.__addon_enabled__ = False
except BaseException as ex:
# if the addon doesn't exist, don't print full traceback
if type(ex) is ImportError and ex.name == module_name:
print("addon not loaded:", repr(module_name))
print("cause:", str(ex))
# If the add-on doesn't exist, don't print full trace-back because the back-trace is in this case
# is verbose without any useful details. A missing path is better communicated in a short message.
# Account for `ImportError` & `ModuleNotFoundError`.
if isinstance(ex, ImportError) and ex.name == module_name:
print("Add-on not loaded:", repr(module_name), "cause:", str(ex))
else:
handle_error(ex)

View File

@ -345,15 +345,15 @@ def load_scripts_extensions(*, reload_scripts=False):
bl_app_template_utils.reset(reload_scripts=reload_scripts)
del bl_app_template_utils
# deal with addons separately
_initialize = getattr(_addon_utils, "_initialize", None)
if _initialize is not None:
# Deal with add-ons separately.
_initialize_once = getattr(_addon_utils, "_initialize_once", None)
if _initialize_once is not None:
# first time, use fast-path
_initialize()
del _addon_utils._initialize
_initialize_once()
del _addon_utils._initialize_once
else:
_addon_utils.reset_all(reload_scripts=reload_scripts)
del _initialize
del _initialize_once
def script_path_user():

View File

@ -7,9 +7,29 @@ import bpy
language_id = "python"
# store our own __main__ module, not 100% needed
# but python expects this in some places
_BPY_MAIN_OWN = True
class _TempModuleOverride:
__slots__ = (
"module_name",
"module",
"module_override",
)
def __init__(self, module_name, module_override):
self.module_name = module_name
self.module = None
self.module_override = module_override
def __enter__(self):
self.module = sys.modules.get(self.module_name)
sys.modules[self.module_name] = self.module_override
def __exit__(self, type, value, traceback):
if self.module is None:
# Account for removal of `module_override` (albeit unlikely).
sys.modules.pop(self.module_name, None)
else:
sys.modules[self.module_name] = self.module
def add_scrollback(text, text_type):
@ -72,12 +92,9 @@ def get_console(console_id):
stdout = io.StringIO()
stderr = io.StringIO()
else:
if _BPY_MAIN_OWN:
import types
bpy_main_mod = types.ModuleType("__main__")
namespace = bpy_main_mod.__dict__
else:
namespace = {}
import types
bpy_main_mod = types.ModuleType("__main__")
namespace = bpy_main_mod.__dict__
namespace["__builtins__"] = sys.modules["builtins"]
namespace["bpy"] = bpy
@ -94,8 +111,7 @@ def get_console(console_id):
console.push("from mathutils import *")
console.push("from math import *")
if _BPY_MAIN_OWN:
console._bpy_main_mod = bpy_main_mod
console._bpy_main_mod = bpy_main_mod
import io
stdout = io.StringIO()
@ -121,25 +137,23 @@ def execute(context, is_interactive):
console, stdout, stderr = get_console(hash(context.region))
if _BPY_MAIN_OWN:
main_mod_back = sys.modules["__main__"]
sys.modules["__main__"] = console._bpy_main_mod
# redirect output
from contextlib import (
redirect_stdout,
redirect_stderr,
)
# not included with Python
# Not included with Python.
class redirect_stdin(redirect_stdout.__base__):
_stream = "stdin"
# don't allow the stdin to be used, can lock blender.
with redirect_stdout(stdout), \
redirect_stderr(stderr), \
redirect_stdin(None):
with (
redirect_stdout(stdout),
redirect_stderr(stderr),
# Don't allow the `stdin` to be used because it can lock Blender.
redirect_stdin(None),
_TempModuleOverride("__main__", console._bpy_main_mod),
):
# in case exception happens
line = "" # in case of encoding error
is_multiline = False
@ -156,9 +170,6 @@ def execute(context, is_interactive):
import traceback
stderr.write(traceback.format_exc())
if _BPY_MAIN_OWN:
sys.modules["__main__"] = main_mod_back
output = stdout.getvalue()
output_err = stderr.getvalue()
@ -220,46 +231,48 @@ def autocomplete(context):
if not console:
return {'CANCELLED'}
# don't allow the stdin to be used, can lock blender.
# note: unlikely stdin would be used for autocomplete. but its possible.
stdin_backup = sys.stdin
sys.stdin = None
scrollback = ""
scrollback_error = ""
if _BPY_MAIN_OWN:
main_mod_back = sys.modules["__main__"]
sys.modules["__main__"] = console._bpy_main_mod
# Don't allow the `stdin` to be used, can lock blender.
# note: unlikely `stdin` would be used for auto-complete - but it's possible.
try:
current_line = sc.history[-1]
line = current_line.body
from contextlib import redirect_stdout
# This function isn't aware of the text editor or being an operator
# just does the autocomplete then copy its results back
result = intellisense.expand(
line=line,
cursor=current_line.current_character,
namespace=console.locals,
private=bpy.app.debug_python)
# Not included with Python.
class redirect_stdin(redirect_stdout.__base__):
_stream = "stdin"
line_new = result[0]
current_line.body, current_line.current_character, scrollback = result
del result
with (
# Don't allow the `stdin` to be used because it can lock Blender.
redirect_stdin(None),
_TempModuleOverride("__main__", console._bpy_main_mod),
):
try:
current_line = sc.history[-1]
line = current_line.body
# update selection. setting body should really do this!
ofs = len(line_new) - len(line)
sc.select_start += ofs
sc.select_end += ofs
except:
# unlikely, but this can happen with unicode errors for example.
# or if the api attribute access itself causes an error.
import traceback
scrollback_error = traceback.format_exc()
# This function isn't aware of the text editor or being an operator
# just does the autocomplete then copy its results back
result = intellisense.expand(
line=line,
cursor=current_line.current_character,
namespace=console.locals,
private=bpy.app.debug_python)
if _BPY_MAIN_OWN:
sys.modules["__main__"] = main_mod_back
line_new = result[0]
current_line.body, current_line.current_character, scrollback = result
del result
# update selection. setting body should really do this!
ofs = len(line_new) - len(line)
sc.select_start += ofs
sc.select_end += ofs
except:
# unlikely, but this can happen with unicode errors for example.
# or if the API attribute access itself causes an error.
import traceback
scrollback_error = traceback.format_exc()
# Separate autocomplete output by command prompts
if scrollback != '':
@ -275,9 +288,6 @@ def autocomplete(context):
if scrollback_error:
add_scrollback(scrollback_error, 'ERROR')
# restore the stdin
sys.stdin = stdin_backup
context.area.tag_redraw()
return {'FINISHED'}

View File

@ -96,7 +96,7 @@
outline="#4d4d4dff"
inner="#282828ff"
inner_sel="#333333ff"
item="#8aace6ff"
item="#ffffff33"
text="#dddddd"
text_sel="#ffffff"
show_shaded="TRUE"
@ -306,7 +306,7 @@
outline="#e6e6e6ff"
inner="#1a1a1a00"
inner_sel="#668cccff"
item="#8aace6ff"
item="#ffffff33"
text="#1a1a1a"
text_sel="#ffffff"
show_shaded="FALSE"
@ -918,7 +918,7 @@
line_numbers="#d0d0d0"
line_numbers_background="#313133"
selected_text="#19191a"
cursor="#ff0000"
cursor="#71a8ff"
syntax_builtin="#ff1961"
syntax_symbols="#ff734d"
syntax_special="#95d600"
@ -926,7 +926,7 @@
syntax_reserved="#c4753b"
syntax_comment="#939393"
syntax_string="#f6e162"
syntax_numbers="#50dbff"
syntax_numbers="#50faff"
>
<space>
<ThemeSpaceGeneric

View File

@ -74,6 +74,8 @@ class Params:
"v3d_tilde_action",
# Alt-MMB axis switching 'RELATIVE' or 'ABSOLUTE' axis switching.
"v3d_alt_mmb_drag_action",
# Changes some transformers modal key-map items to avoid conflicts with navigation operations.
"use_alt_navigation",
# File selector actions on single click.
"use_file_single_click",
@ -106,8 +108,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",
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
"use_alt_navigation",
)
def __init__(
@ -131,10 +131,10 @@ class Params:
use_alt_tool_or_cursor=False,
use_alt_click_leader=False,
use_pie_click_drag=False,
use_alt_navigation=True,
use_file_single_click=False,
v3d_tilde_action='VIEW',
v3d_alt_mmb_drag_action='RELATIVE',
use_alt_navigation=True,
use_experimental_grease_pencil_version3=False,
):
from sys import platform
@ -209,6 +209,8 @@ class Params:
self.use_alt_click_leader = use_alt_click_leader
self.use_pie_click_drag = use_pie_click_drag
self.use_alt_navigation = use_alt_navigation
self.use_file_single_click = use_file_single_click
self.use_tweak_select_passthrough = not legacy
@ -235,7 +237,6 @@ class Params:
self.pie_value = 'CLICK_DRAG' if use_pie_click_drag else 'PRESS'
self.tool_tweak_event = {"type": self.tool_mouse, "value": 'CLICK_DRAG'}
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
self.use_alt_navigation = use_alt_navigation
# ------------------------------------------------------------------------------
@ -3760,7 +3761,7 @@ def km_grease_pencil_stroke_edit_mode(params):
# Close strokes
("gpencil.stroke_cyclical_set", {"type": 'F', "value": 'PRESS'},
{"properties": [("type", 'CLOSE'), ("geometry", True)]}),
# Copy + paset
# Copy + paste.
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("gpencil.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
# Snap
@ -6074,6 +6075,8 @@ def km_transform_modal_map(params):
{"items": items},
)
alt_without_navigaton = {} if params.use_alt_navigation else {"alt": True}
items.extend([
("CONFIRM", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
("CONFIRM", {"type": 'RET', "value": 'PRESS', "any": True}, None),
@ -6108,24 +6111,24 @@ def km_transform_modal_map(params):
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": not params.use_alt_navigation}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": not params.use_alt_navigation}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', **alt_without_navigaton}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', **alt_without_navigaton}, None),
("PROPORTIONAL_SIZE_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
("PROPORTIONAL_SIZE_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY', "alt": not params.use_alt_navigation}, None),
("PROPORTIONAL_SIZE", {"type": 'TRACKPADPAN', "value": 'ANY', **alt_without_navigaton}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "repeat": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "repeat": True}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'PAGE_UP', "value": 'PRESS', "shift": True, "repeat": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True, "repeat": True}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": not params.use_alt_navigation}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": not params.use_alt_navigation}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', **alt_without_navigaton}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', **alt_without_navigaton}, None),
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
("INSERTOFS_TOGGLE_DIR", {"type": 'T', "value": 'PRESS'}, None),
("NODE_ATTACH_ON", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
("NODE_ATTACH_OFF", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY', "alt": not params.use_alt_navigation}, None),
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True, "alt": not params.use_alt_navigation}, None),
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY', **alt_without_navigaton}, None),
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True, **alt_without_navigaton}, None),
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
("PRECISION", {"type": 'RIGHT_SHIFT', "value": 'ANY', "any": True}, None),
])

View File

@ -2359,7 +2359,7 @@ def km_grease_pencil_stroke_edit_mode(params):
("gpencil.stroke_join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
("gpencil.stroke_join", {"type": 'J', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("type", 'JOINCOPY')]}),
# Copy + paset
# Copy + paste.
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("gpencil.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
# Snap

View File

@ -908,6 +908,7 @@ class LoadImageAsEmpty:
)
filter_image: BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
filter_movie: BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
filter_folder: BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
view_align: BoolProperty(

View File

@ -17,10 +17,13 @@ class ASSETSHELF_PT_display(Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
shelf = context.asset_shelf
layout.prop(shelf, "preview_size", text="Size")
layout.prop(shelf, "show_names", text="Names")
layout.prop(shelf, "preview_size")
@classmethod
def poll(cls, context):

View File

@ -89,6 +89,16 @@ class DATA_UL_bone_collections(UIList):
layout.prop(bcoll, "name", text="", emboss=False,
icon='DOT' if has_active_bone else 'BLANK1')
if armature.override_library:
icon = 'LIBRARY_DATA_OVERRIDE' if bcoll.is_local_override else 'BLANK1'
layout.prop(
bcoll,
"is_local_override",
text="",
emboss=False,
icon=icon)
layout.prop(bcoll, "is_visible", text="", emboss=False,
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
@ -245,7 +255,17 @@ class DATA_PT_custom_props_bcoll(ArmatureButtonsPanel, PropertyPanel, Panel):
@classmethod
def poll(cls, context):
return context.armature and context.armature.collections.active
arm = context.armature
if not arm:
return False
is_lib_override = arm.id_data.override_library and arm.id_data.override_library.reference
if is_lib_override:
# This is due to a limitation in scripts/modules/rna_prop_ui.py; if that
# limitation is lifted, this poll function should be adjusted.
return False
return arm.collections.active
classes = (

View File

@ -13,6 +13,25 @@ class ModifierButtonsPanel:
bl_options = {'HIDE_HEADER'}
class ModifierAddMenu:
MODIFIER_TYPES_TO_LABELS = {enum_it.identifier: enum_it.name
for enum_it in bpy.types.Modifier.bl_rna.properties['type'].enum_items_static}
MODIFIER_TYPES_TO_ICONS = {enum_it.identifier: enum_it.icon
for enum_it in bpy.types.Modifier.bl_rna.properties['type'].enum_items_static}
MODIFIER_TYPES_I18N_CONTEXT = bpy.types.Modifier.bl_rna.properties['type'].translation_context
@classmethod
def operator_modifier_add(cls, layout, mod_type):
layout.operator(
"object.modifier_add",
text=cls.MODIFIER_TYPES_TO_LABELS[mod_type],
# Although these are operators, the label actually comes from an (enum) property,
# so the property's translation context must be used here.
text_ctxt=cls.MODIFIER_TYPES_I18N_CONTEXT,
icon=cls.MODIFIER_TYPES_TO_ICONS[mod_type],
).type = mod_type
class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
bl_label = "Modifiers"
@ -27,7 +46,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.template_modifiers()
class OBJECT_MT_modifier_add(Menu):
class OBJECT_MT_modifier_add(ModifierAddMenu, Menu):
bl_label = "Add Modifier"
bl_options = {'SEARCH_ON_KEY_PRESS'}
@ -36,7 +55,7 @@ class OBJECT_MT_modifier_add(Menu):
ob_type = context.object.type
geometry_nodes_supported = ob_type in {'MESH', 'CURVE', 'CURVES', 'FONT', 'SURFACE', 'VOLUME', 'POINTCLOUD'}
if geometry_nodes_supported:
layout.operator("object.modifier_add", icon='GEOMETRY_NODES', text="Geometry Nodes").type = 'NODES'
self.operator_modifier_add(layout, 'NODES')
layout.separator()
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.menu("OBJECT_MT_modifier_add_edit")
@ -51,159 +70,122 @@ class OBJECT_MT_modifier_add(Menu):
layout.menu_contents("OBJECT_MT_modifier_add_root_catalogs")
class OBJECT_MT_modifier_add_edit(Menu):
class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
bl_label = "Edit"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type == 'MESH':
layout.operator(
"object.modifier_add",
text="Data Transfer",
icon='MOD_DATA_TRANSFER',
).type = 'DATA_TRANSFER'
self.operator_modifier_add(layout, 'DATA_TRANSFER')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Mesh Cache", icon='MOD_MESHDEFORM').type = 'MESH_CACHE'
self.operator_modifier_add(layout, 'MESH_CACHE')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator(
"object.modifier_add",
text="Mesh Sequence Cache",
icon='MOD_MESHDEFORM',
).type = 'MESH_SEQUENCE_CACHE'
self.operator_modifier_add(layout, 'MESH_SEQUENCE_CACHE')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Normal Edit", icon='MOD_NORMALEDIT').type = 'NORMAL_EDIT'
layout.operator(
"object.modifier_add",
text="Weighted Normal",
icon='MOD_NORMALEDIT',
).type = 'WEIGHTED_NORMAL'
layout.operator("object.modifier_add", text="UV Project", icon='MOD_UVPROJECT').type = 'UV_PROJECT'
layout.operator("object.modifier_add", text="UV Warp", icon='MOD_UVPROJECT').type = 'UV_WARP'
layout.operator(
"object.modifier_add",
text="Vertex Weight Edit",
icon='MOD_VERTEX_WEIGHT',
).type = 'VERTEX_WEIGHT_EDIT'
layout.operator(
"object.modifier_add",
text="Vertex Weight Mix",
icon='MOD_VERTEX_WEIGHT',
).type = 'VERTEX_WEIGHT_MIX'
layout.operator(
"object.modifier_add",
text="Vertex Weight Proximity",
icon='MOD_VERTEX_WEIGHT',
).type = 'VERTEX_WEIGHT_PROXIMITY'
self.operator_modifier_add(layout, 'NORMAL_EDIT')
self.operator_modifier_add(layout, 'WEIGHTED_NORMAL')
self.operator_modifier_add(layout, 'UV_PROJECT')
self.operator_modifier_add(layout, 'UV_WARP')
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_EDIT')
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_MIX')
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_PROXIMITY')
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class OBJECT_MT_modifier_add_generate(Menu):
class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
bl_label = "Generate"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Array", icon='MOD_ARRAY').type = 'ARRAY'
layout.operator("object.modifier_add", text="Bevel", icon='MOD_BEVEL').type = 'BEVEL'
self.operator_modifier_add(layout, 'ARRAY')
self.operator_modifier_add(layout, 'BEVEL')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Boolean", icon='MOD_BOOLEAN').type = 'BOOLEAN'
self.operator_modifier_add(layout, 'BOOLEAN')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Build", icon='MOD_BUILD').type = 'BUILD'
layout.operator("object.modifier_add", text="Decimate", icon='MOD_DECIM').type = 'DECIMATE'
layout.operator("object.modifier_add", text="Edge Split", icon='MOD_EDGESPLIT').type = 'EDGE_SPLIT'
self.operator_modifier_add(layout, 'BUILD')
self.operator_modifier_add(layout, 'DECIMATE')
self.operator_modifier_add(layout, 'EDGE_SPLIT')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Mask", icon='MOD_MASK').type = 'MASK'
self.operator_modifier_add(layout, 'MASK')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Mirror", icon='MOD_MIRROR').type = 'MIRROR'
self.operator_modifier_add(layout, 'MIRROR')
if ob_type == 'VOLUME':
layout.operator("object.modifier_add", text="Mesh to Volume", icon='VOLUME_DATA').type = 'MESH_TO_VOLUME'
self.operator_modifier_add(layout, 'MESH_TO_VOLUME')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Multiresolution", icon='MOD_MULTIRES').type = 'MULTIRES'
self.operator_modifier_add(layout, 'MULTIRES')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Remesh", icon='MOD_REMESH').type = 'REMESH'
layout.operator("object.modifier_add", text="Screw", icon='MOD_SCREW').type = 'SCREW'
self.operator_modifier_add(layout, 'REMESH')
self.operator_modifier_add(layout, 'SCREW')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Skin", icon='MOD_SKIN').type = 'SKIN'
self.operator_modifier_add(layout, 'SKIN')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Solidify", icon='MOD_SOLIDIFY').type = 'SOLIDIFY'
layout.operator("object.modifier_add", text="Subdivision Surface", icon='MOD_SUBSURF').type = 'SUBSURF'
layout.operator("object.modifier_add", text="Triangulate", icon='MOD_TRIANGULATE').type = 'TRIANGULATE'
self.operator_modifier_add(layout, 'SOLIDIFY')
self.operator_modifier_add(layout, 'SUBSURF')
self.operator_modifier_add(layout, 'TRIANGULATE')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Volume to Mesh", icon='VOLUME_DATA').type = 'VOLUME_TO_MESH'
self.operator_modifier_add(layout, 'VOLUME_TO_MESH')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Weld", icon='AUTOMERGE_OFF').type = 'WELD'
self.operator_modifier_add(layout, 'WELD')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Wireframe", icon='MOD_WIREFRAME').type = 'WIREFRAME'
self.operator_modifier_add(layout, 'WIREFRAME')
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class OBJECT_MT_modifier_add_deform(Menu):
class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
bl_label = "Deform"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Armature", icon='MOD_ARMATURE').type = 'ARMATURE'
layout.operator("object.modifier_add", text="Cast", icon='MOD_CAST').type = 'CAST'
layout.operator("object.modifier_add", text="Curve", icon='MOD_CURVE').type = 'CURVE'
self.operator_modifier_add(layout, 'ARMATURE')
self.operator_modifier_add(layout, 'CAST')
self.operator_modifier_add(layout, 'CURVE')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Displace", icon='MOD_DISPLACE').type = 'DISPLACE'
self.operator_modifier_add(layout, 'DISPLACE')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Hook", icon='HOOK').type = 'HOOK'
self.operator_modifier_add(layout, 'HOOK')
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Laplacian Deform",
icon='MOD_MESHDEFORM').type = 'LAPLACIANDEFORM'
self.operator_modifier_add(layout, 'LAPLACIANDEFORM')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Lattice", icon='MOD_LATTICE').type = 'LATTICE'
layout.operator("object.modifier_add", text="Mesh Deform", icon='MOD_MESHDEFORM').type = 'MESH_DEFORM'
layout.operator("object.modifier_add", text="Shrinkwrap", icon='MOD_SHRINKWRAP').type = 'SHRINKWRAP'
layout.operator("object.modifier_add", text="Simple Deform", icon='MOD_SIMPLEDEFORM').type = 'SIMPLE_DEFORM'
self.operator_modifier_add(layout, 'LATTICE')
self.operator_modifier_add(layout, 'MESH_DEFORM')
self.operator_modifier_add(layout, 'SHRINKWRAP')
self.operator_modifier_add(layout, 'SIMPLE_DEFORM')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Smooth", icon='MOD_SMOOTH').type = 'SMOOTH'
self.operator_modifier_add(layout, 'SMOOTH')
if ob_type == 'MESH':
layout.operator(
"object.modifier_add",
text="Smooth Corrective",
icon='MOD_SMOOTH',
).type = 'CORRECTIVE_SMOOTH'
layout.operator("object.modifier_add", text="Smooth Laplacian", icon='MOD_SMOOTH').type = 'LAPLACIANSMOOTH'
layout.operator("object.modifier_add", text="Surface Deform", icon='MOD_MESHDEFORM').type = 'SURFACE_DEFORM'
self.operator_modifier_add(layout, 'CORRECTIVE_SMOOTH')
self.operator_modifier_add(layout, 'LAPLACIANSMOOTH')
self.operator_modifier_add(layout, 'SURFACE_DEFORM')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Warp", icon='MOD_WARP').type = 'WARP'
layout.operator("object.modifier_add", text="Wave", icon='MOD_WAVE').type = 'WAVE'
self.operator_modifier_add(layout, 'WARP')
self.operator_modifier_add(layout, 'WAVE')
if ob_type == 'VOLUME':
layout.operator("object.modifier_add", text="Volume Displace", icon='VOLUME_DATA').type = 'VOLUME_DISPLACE'
self.operator_modifier_add(layout, 'VOLUME_DISPLACE')
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class OBJECT_MT_modifier_add_physics(Menu):
class OBJECT_MT_modifier_add_physics(ModifierAddMenu, Menu):
bl_label = "Physics"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Cloth", icon='MOD_CLOTH').type = 'CLOTH'
layout.operator("object.modifier_add", text="Collision", icon='MOD_PHYSICS').type = 'COLLISION'
layout.operator("object.modifier_add", text="Dynamic Paint", icon='MOD_DYNAMICPAINT').type = 'DYNAMIC_PAINT'
layout.operator("object.modifier_add", text="Explode", icon='MOD_EXPLODE').type = 'EXPLODE'
layout.operator("object.modifier_add", text="Fluid", icon='MOD_FLUIDSIM').type = 'FLUID'
layout.operator("object.modifier_add", text="Ocean", icon='MOD_OCEAN').type = 'OCEAN'
layout.operator(
"object.modifier_add",
text="Particle Instance",
icon='MOD_PARTICLE_INSTANCE',
).type = 'PARTICLE_INSTANCE'
layout.operator(
"object.modifier_add",
text="Particle System",
icon='MOD_PARTICLES',
).type = 'PARTICLE_SYSTEM'
self.operator_modifier_add(layout, 'CLOTH')
self.operator_modifier_add(layout, 'COLLISION')
self.operator_modifier_add(layout, 'DYNAMIC_PAINT')
self.operator_modifier_add(layout, 'EXPLODE')
self.operator_modifier_add(layout, 'FLUID')
self.operator_modifier_add(layout, 'OCEAN')
self.operator_modifier_add(layout, 'PARTICLE_INSTANCE')
self.operator_modifier_add(layout, 'PARTICLE_SYSTEM')
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Soft Body", icon='MOD_SOFT').type = 'SOFT_BODY'
self.operator_modifier_add(layout, 'SOFT_BODY')
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)

View File

@ -2,8 +2,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
# panels get subclassed (not registered directly)
# menus are referenced `as is`
# Panels get sub-classed (not registered directly).
# Menus are referenced as-is.
from bpy.types import Menu, UIList
from bpy.app.translations import contexts as i18n_contexts

View File

@ -849,10 +849,10 @@ classes = (
FILEBROWSER_PT_display,
FILEBROWSER_PT_filter,
FILEBROWSER_UL_dir,
FILEBROWSER_PT_bookmarks_volumes,
FILEBROWSER_PT_bookmarks_system,
FILEBROWSER_MT_bookmarks_context_menu,
FILEBROWSER_PT_bookmarks_favorites,
FILEBROWSER_PT_bookmarks_system,
FILEBROWSER_PT_bookmarks_volumes,
FILEBROWSER_PT_bookmarks_recents,
FILEBROWSER_PT_advanced_filter,
FILEBROWSER_PT_directory_path,

View File

@ -368,7 +368,8 @@ class _draw_tool_settings_context_mode:
elif not tool.has_datablock:
return False
paint = context.tool_settings.gpencil_paint
tool_settings = context.tool_settings
paint = tool_settings.gpencil_paint
brush = paint.brush
if brush is None:
return False
@ -376,7 +377,6 @@ class _draw_tool_settings_context_mode:
gp_settings = brush.gpencil_settings
row = layout.row(align=True)
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_paint
row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
@ -401,7 +401,9 @@ class _draw_tool_settings_context_mode:
def SCULPT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
paint = context.tool_settings.gpencil_sculpt_paint
tool_settings = context.tool_settings
paint = tool_settings.gpencil_sculpt_paint
brush = paint.brush
from bl_ui.properties_paint_common import (
@ -415,7 +417,9 @@ class _draw_tool_settings_context_mode:
def WEIGHT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
paint = context.tool_settings.gpencil_weight_paint
tool_settings = context.tool_settings
paint = tool_settings.gpencil_weight_paint
brush = paint.brush
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
@ -432,11 +436,11 @@ class _draw_tool_settings_context_mode:
if (tool is None) or (not tool.has_datablock):
return False
paint = context.tool_settings.gpencil_vertex_paint
tool_settings = context.tool_settings
paint = tool_settings.gpencil_vertex_paint
brush = paint.brush
row = layout.row(align=True)
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_vertex_paint
row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
@ -458,7 +462,8 @@ class _draw_tool_settings_context_mode:
return False
# See: 'VIEW3D_PT_tools_brush', basically a duplicate
settings = context.tool_settings.particle_edit
tool_settings = context.tool_settings
settings = tool_settings.particle_edit
brush = settings.brush
tool = settings.tool
if tool == 'NONE':
@ -696,7 +701,7 @@ class VIEW3D_HT_header(Header):
row = layout.row(align=True)
obj = context.active_object
# mode_string = context.mode
mode_string = context.mode
object_mode = 'OBJECT' if obj is None else obj.mode
has_pose_mode = (
(object_mode == 'POSE') or
@ -959,6 +964,30 @@ class VIEW3D_HT_header(Header):
sub.active = overlay.show_overlays
sub.popover(panel="VIEW3D_PT_overlay", text="")
if mode_string == 'EDIT_MESH':
sub.popover(panel="VIEW3D_PT_overlay_edit_mesh", text="", icon='EDITMODE_HLT')
if mode_string == 'EDIT_CURVE':
sub.popover(panel="VIEW3D_PT_overlay_edit_curve", text="", icon='EDITMODE_HLT')
elif mode_string == 'SCULPT':
sub.popover(panel="VIEW3D_PT_overlay_sculpt", text="", icon='SCULPTMODE_HLT')
elif mode_string == 'SCULPT_CURVES':
sub.popover(panel="VIEW3D_PT_overlay_sculpt_curves", text="", icon='SCULPTMODE_HLT')
elif mode_string == 'PAINT_WEIGHT':
sub.popover(panel="VIEW3D_PT_overlay_weight_paint", text="", icon='WPAINT_HLT')
elif mode_string == 'PAINT_TEXTURE':
sub.popover(panel="VIEW3D_PT_overlay_texture_paint", text="", icon='TPAINT_HLT')
elif mode_string == 'PAINT_VERTEX':
sub.popover(panel="VIEW3D_PT_overlay_vertex_paint", text="", icon='VPAINT_HLT')
elif obj is not None and obj.type == 'GPENCIL':
sub.popover(panel="VIEW3D_PT_overlay_gpencil_options", text="", icon='OUTLINER_DATA_GREASEPENCIL')
# Separate from `elif` chain because it may coexist with weight-paint.
if (
has_pose_mode or
(object_mode in {'EDIT_ARMATURE', 'OBJECT'} and VIEW3D_PT_overlay_bones.is_using_wireframe(context))
):
sub.popover(panel="VIEW3D_PT_overlay_bones", text="", icon='POSE_HLT')
row = layout.row()
row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'})
@ -997,7 +1026,7 @@ class VIEW3D_MT_editor_menus(Menu):
edit_object = context.edit_object
gp_edit = obj and obj.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL',
'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}
tool_settings = context.scene.tool_settings
tool_settings = context.tool_settings
layout.menu("VIEW3D_MT_view")
@ -5494,7 +5523,9 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
def draw(self, context):
layout = self.layout
settings = context.tool_settings.gpencil_sculpt
tool_settings = context.tool_settings
settings = tool_settings.gpencil_sculpt
layout.operator("gpencil.stroke_subdivide", text="Subdivide").only_selected = False
layout.menu("VIEW3D_MT_gpencil_simplify")
@ -5771,18 +5802,20 @@ class VIEW3D_MT_pivot_pie(Menu):
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
tool_settings = context.tool_settings
obj = context.active_object
mode = context.mode
pie.prop_enum(context.scene.tool_settings, "transform_pivot_point", value='BOUNDING_BOX_CENTER')
pie.prop_enum(context.scene.tool_settings, "transform_pivot_point", value='CURSOR')
pie.prop_enum(context.scene.tool_settings, "transform_pivot_point", value='INDIVIDUAL_ORIGINS')
pie.prop_enum(context.scene.tool_settings, "transform_pivot_point", value='MEDIAN_POINT')
pie.prop_enum(context.scene.tool_settings, "transform_pivot_point", value='ACTIVE_ELEMENT')
pie.prop_enum(tool_settings, "transform_pivot_point", value='BOUNDING_BOX_CENTER')
pie.prop_enum(tool_settings, "transform_pivot_point", value='CURSOR')
pie.prop_enum(tool_settings, "transform_pivot_point", value='INDIVIDUAL_ORIGINS')
pie.prop_enum(tool_settings, "transform_pivot_point", value='MEDIAN_POINT')
pie.prop_enum(tool_settings, "transform_pivot_point", value='ACTIVE_ELEMENT')
if (obj is None) or (mode in {'OBJECT', 'POSE', 'WEIGHT_PAINT'}):
pie.prop(context.scene.tool_settings, "use_transform_pivot_point_align")
pie.prop(tool_settings, "use_transform_pivot_point_align")
if mode == 'EDIT_GPENCIL':
pie.prop(context.scene.tool_settings.gpencil_sculpt, "use_scale_thickness")
pie.prop(tool_settings.gpencil_sculpt, "use_scale_thickness")
class VIEW3D_MT_orientations_pie(Menu):
@ -5827,6 +5860,7 @@ class VIEW3D_MT_proportional_editing_falloff_pie(Menu):
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
tool_settings = context.scene.tool_settings
pie.prop(tool_settings, "proportional_edit_falloff", expand=True)
@ -6829,8 +6863,8 @@ class VIEW3D_PT_overlay_motion_tracking(Panel):
class VIEW3D_PT_overlay_edit_mesh(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Mesh Edit Mode"
bl_ui_units_x = 12
@classmethod
def poll(cls, context):
@ -6838,6 +6872,7 @@ class VIEW3D_PT_overlay_edit_mesh(Panel):
def draw(self, context):
layout = self.layout
layout.label(text="Mesh Edit Mode Overlays")
view = context.space_data
shading = view.shading
@ -7017,7 +7052,7 @@ class VIEW3D_PT_overlay_edit_mesh_normals(Panel):
class VIEW3D_PT_overlay_edit_mesh_freestyle(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh'
bl_label = "Freestyle"
@classmethod
@ -7042,7 +7077,6 @@ class VIEW3D_PT_overlay_edit_mesh_freestyle(Panel):
class VIEW3D_PT_overlay_edit_curve(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Curve Edit Mode"
@classmethod
@ -7055,6 +7089,8 @@ class VIEW3D_PT_overlay_edit_curve(Panel):
overlay = view.overlay
display_all = overlay.show_overlays
layout.label(text="Curve Edit Mode Overlays")
col = layout.column()
col.active = display_all
@ -7072,15 +7108,11 @@ class VIEW3D_PT_overlay_sculpt(Panel):
bl_space_type = 'VIEW_3D'
bl_context = ".sculpt_mode"
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Sculpt"
@classmethod
def poll(cls, context):
return (
context.mode == 'SCULPT' and
context.sculpt_object
)
return context.mode == 'SCULPT'
def draw(self, context):
layout = self.layout
@ -7088,6 +7120,8 @@ class VIEW3D_PT_overlay_sculpt(Panel):
view = context.space_data
overlay = view.overlay
layout.label(text="Sculpt Mode Overlays")
row = layout.row(align=True)
row.prop(overlay, "show_sculpt_mask", text="")
sub = row.row()
@ -7105,12 +7139,11 @@ class VIEW3D_PT_overlay_sculpt_curves(Panel):
bl_space_type = 'VIEW_3D'
bl_context = ".curves_sculpt"
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Sculpt"
@classmethod
def poll(cls, context):
return context.mode == 'SCULPT_CURVES' and (context.object)
return context.mode == 'SCULPT_CURVES'
def draw(self, context):
layout = self.layout
@ -7118,6 +7151,8 @@ class VIEW3D_PT_overlay_sculpt_curves(Panel):
view = context.space_data
overlay = view.overlay
layout.label(text="Curve Sculpt Overlays")
row = layout.row(align=True)
row.active = overlay.show_overlays
row.prop(overlay, "sculpt_mode_mask_opacity", text="Selection Opacity")
@ -7133,7 +7168,6 @@ class VIEW3D_PT_overlay_sculpt_curves(Panel):
class VIEW3D_PT_overlay_bones(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Bones"
@staticmethod
@ -7171,6 +7205,8 @@ class VIEW3D_PT_overlay_bones(Panel):
overlay = view.overlay
display_all = overlay.show_overlays
layout.label(text="Armature Overlays")
col = layout.column()
col.active = display_all
@ -7191,7 +7227,6 @@ class VIEW3D_PT_overlay_bones(Panel):
class VIEW3D_PT_overlay_texture_paint(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Texture Paint"
@classmethod
@ -7204,6 +7239,8 @@ class VIEW3D_PT_overlay_texture_paint(Panel):
overlay = view.overlay
display_all = overlay.show_overlays
layout.label(text="Texture Paint Overlays")
col = layout.column()
col.active = display_all
col.prop(overlay, "texture_paint_mode_opacity")
@ -7212,7 +7249,6 @@ class VIEW3D_PT_overlay_texture_paint(Panel):
class VIEW3D_PT_overlay_vertex_paint(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Vertex Paint"
@classmethod
@ -7225,6 +7261,8 @@ class VIEW3D_PT_overlay_vertex_paint(Panel):
overlay = view.overlay
display_all = overlay.show_overlays
layout.label(text="Vertex Paint Overlays")
col = layout.column()
col.active = display_all
@ -7235,8 +7273,8 @@ class VIEW3D_PT_overlay_vertex_paint(Panel):
class VIEW3D_PT_overlay_weight_paint(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = "Weight Paint"
bl_ui_units_x = 12
@classmethod
def poll(cls, context):
@ -7249,6 +7287,8 @@ class VIEW3D_PT_overlay_weight_paint(Panel):
display_all = overlay.show_overlays
tool_settings = context.tool_settings
layout.label(text="Weight Paint Overlays")
col = layout.column()
col.active = display_all
@ -7477,15 +7517,18 @@ class VIEW3D_PT_gpencil_guide(Panel):
class VIEW3D_PT_overlay_gpencil_options(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = ""
bl_ui_units_x = 13
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GPENCIL'
def draw_header(self, context):
def draw(self, context):
layout = self.layout
view = context.space_data
overlay = view.overlay
layout.label(text={
'PAINT_GPENCIL': iface_("Draw Grease Pencil"),
'EDIT_GPENCIL': iface_("Edit Grease Pencil"),
@ -7495,11 +7538,6 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
'OBJECT': iface_("Grease Pencil"),
}[context.mode], translate=False)
def draw(self, context):
layout = self.layout
view = context.space_data
overlay = view.overlay
layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin")
col = layout.column()

View File

@ -54,9 +54,6 @@ void ANIM_bonecoll_free(struct BoneCollection *bcoll);
/**
* Recalculate the armature & bone runtime data.
*
* NOTE: this should only be used when the runtime structs on the Armature and Bones are still
* empty. Any data allocated there will NOT be freed.
*
* TODO: move to BKE?
*/
void ANIM_armature_runtime_refresh(struct bArmature *armature);
@ -74,6 +71,17 @@ void ANIM_armature_runtime_free(struct bArmature *armature);
*/
struct BoneCollection *ANIM_armature_bonecoll_new(struct bArmature *armature, const char *name);
/**
* Add a bone collection to the Armature.
*
* NOTE: this should not typically be used. It is only used by the library overrides system to
* apply override operations.
*/
struct BoneCollection *ANIM_armature_bonecoll_insert_copy_after(
struct bArmature *armature,
struct BoneCollection *anchor,
const struct BoneCollection *bcoll_to_copy);
/**
* Remove a bone collection from the armature.
*/
@ -83,6 +91,9 @@ void ANIM_armature_bonecoll_remove(struct bArmature *armature, struct BoneCollec
* Set the given bone collection as the active one.
*
* Pass `nullptr` to clear the active bone collection.
*
* The bone collection MUST already be owned by this armature. If it is not,
* this function will simply clear the active bone collection.
*/
void ANIM_armature_bonecoll_active_set(struct bArmature *armature, struct BoneCollection *bcoll);
@ -94,6 +105,15 @@ void ANIM_armature_bonecoll_active_set(struct bArmature *armature, struct BoneCo
void ANIM_armature_bonecoll_active_index_set(struct bArmature *armature,
int bone_collection_index);
/**
* Determine whether the given bone collection is editable.
*
* Bone collections are editable when they are local, so either on a local Armature or added to a
* linked Armature via a library override in the local file.
*/
bool ANIM_armature_bonecoll_is_editable(const struct bArmature *armature,
const struct BoneCollection *bcoll);
/**
* Move the bone collection by \a step places up/down.
*

View File

@ -7,6 +7,7 @@
*/
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_math_color.h"
#include "BLI_string.h"
@ -72,19 +73,31 @@ void ANIM_bonecoll_free(BoneCollection *bcoll)
MEM_delete(bcoll);
}
/**
* Construct the mapping from the bones to this collection.
*
* This assumes that the bones do not have such a pointer yet, i.e. calling this
* twice for the same bone collection will cause duplicate pointers. */
static void add_reverse_pointers(BoneCollection *bcoll)
{
LISTBASE_FOREACH (BoneCollectionMember *, member, &bcoll->bones) {
BoneCollectionReference *ref = MEM_cnew<BoneCollectionReference>(__func__);
ref->bcoll = bcoll;
BLI_addtail(&member->bone->runtime.collections, ref);
}
}
void ANIM_armature_runtime_refresh(bArmature *armature)
{
ANIM_armature_runtime_free(armature);
ANIM_armature_bonecoll_active_set(armature, armature->active_collection);
BoneCollection *active = ANIM_armature_bonecoll_get_by_name(armature,
armature->active_collection_name);
ANIM_armature_bonecoll_active_set(armature, active);
/* Construct the bone-to-collections mapping. */
LISTBASE_FOREACH (BoneCollection *, bcoll, &armature->collections) {
LISTBASE_FOREACH (BoneCollectionMember *, member, &bcoll->bones) {
BoneCollectionReference *ref = MEM_cnew<BoneCollectionReference>(__func__);
ref->bcoll = bcoll;
BLI_addtail(&member->bone->runtime.collections, ref);
}
add_reverse_pointers(bcoll);
}
}
@ -108,15 +121,48 @@ static void bonecoll_ensure_name_unique(bArmature *armature, BoneCollection *bco
BoneCollection *ANIM_armature_bonecoll_new(bArmature *armature, const char *name)
{
BoneCollection *bcoll = ANIM_bonecoll_new(name);
if (!ID_IS_LINKED(&armature->id) && ID_IS_OVERRIDE_LIBRARY(&armature->id)) {
/* Mark this bone collection as local override, so that certain operations can be allowed. */
bcoll->flags |= BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
}
bonecoll_ensure_name_unique(armature, bcoll);
BLI_addtail(&armature->collections, bcoll);
return bcoll;
}
BoneCollection *ANIM_armature_bonecoll_insert_copy_after(bArmature *armature,
BoneCollection *anchor,
const BoneCollection *bcoll_to_copy)
{
BoneCollection *bcoll = static_cast<BoneCollection *>(MEM_dupallocN(bcoll_to_copy));
/* Remap the bone pointers to the given armature, as `bcoll_to_copy` will
* likely be owned by another copy of the armature. */
BLI_duplicatelist(&bcoll->bones, &bcoll->bones);
BLI_assert_msg(armature->bonehash, "Expected armature bone hash to be there");
LISTBASE_FOREACH (BoneCollectionMember *, member, &bcoll->bones) {
member->bone = BKE_armature_find_bone_name(armature, member->bone->name);
}
if (bcoll_to_copy->prop) {
bcoll->prop = IDP_CopyProperty_ex(bcoll_to_copy->prop,
0 /*do_id_user ? 0 : LIB_ID_CREATE_NO_USER_REFCOUNT*/);
}
BLI_insertlinkafter(&armature->collections, anchor, bcoll);
bonecoll_ensure_name_unique(armature, bcoll);
add_reverse_pointers(bcoll);
return bcoll;
}
static void armature_bonecoll_active_clear(bArmature *armature)
{
armature->runtime.active_collection_index = -1;
armature->active_collection = nullptr;
armature->runtime.active_collection = nullptr;
armature->active_collection_name[0] = '\0';
}
void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcoll)
@ -133,8 +179,9 @@ void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcol
return;
}
STRNCPY(armature->active_collection_name, bcoll->name);
armature->runtime.active_collection_index = index;
armature->active_collection = bcoll;
armature->runtime.active_collection = bcoll;
}
void ANIM_armature_bonecoll_active_index_set(bArmature *armature, const int bone_collection_index)
@ -152,8 +199,21 @@ void ANIM_armature_bonecoll_active_index_set(bArmature *armature, const int bone
return;
}
STRNCPY(armature->active_collection_name, bcoll->name);
armature->runtime.active_collection_index = bone_collection_index;
armature->active_collection = bcoll;
armature->runtime.active_collection = bcoll;
}
bool ANIM_armature_bonecoll_is_editable(const bArmature *armature, const BoneCollection *bcoll)
{
const bool is_override = ID_IS_OVERRIDE_LIBRARY(armature);
if (ID_IS_LINKED(armature) && !is_override) {
return false;
}
if (is_override && (bcoll->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL) == 0) {
return false;
}
return true;
}
bool ANIM_armature_bonecoll_move(bArmature *armature, BoneCollection *bcoll, const int step)
@ -166,7 +226,7 @@ bool ANIM_armature_bonecoll_move(bArmature *armature, BoneCollection *bcoll, con
return false;
}
if (bcoll == armature->active_collection) {
if (bcoll == armature->runtime.active_collection) {
armature->runtime.active_collection_index = BLI_findindex(&armature->collections, bcoll);
}
return true;
@ -178,7 +238,15 @@ void ANIM_armature_bonecoll_name_set(bArmature *armature, BoneCollection *bcoll,
STRNCPY(old_name, bcoll->name);
STRNCPY_UTF8(bcoll->name, name);
if (name[0] == '\0') {
/* Refuse to have nameless collections. The name of the active collection is stored in DNA, and
* an empty string means 'no active collection'. */
STRNCPY(bcoll->name, bonecoll_default_name);
}
else {
STRNCPY_UTF8(bcoll->name, name);
}
bonecoll_ensure_name_unique(armature, bcoll);
BKE_animdata_fix_paths_rename_all(&armature->id, "collections", old_name, bcoll->name);
@ -226,6 +294,13 @@ static void add_membership(BoneCollection *bcoll, Bone *bone)
member->bone = bone;
BLI_addtail(&bcoll->bones, member);
}
/* Store reverse membership on the bone. */
static void add_reference(Bone *bone, BoneCollection *bcoll)
{
BoneCollectionReference *ref = MEM_cnew<BoneCollectionReference>(__func__);
ref->bcoll = bcoll;
BLI_addtail(&bone->runtime.collections, ref);
}
bool ANIM_armature_bonecoll_assign(BoneCollection *bcoll, Bone *bone)
{
@ -237,11 +312,7 @@ bool ANIM_armature_bonecoll_assign(BoneCollection *bcoll, Bone *bone)
}
add_membership(bcoll, bone);
/* Store reverse membership on the bone. */
BoneCollectionReference *ref = MEM_cnew<BoneCollectionReference>(__func__);
ref->bcoll = bcoll;
BLI_addtail(&bone->runtime.collections, ref);
add_reference(bone, bcoll);
return true;
}
@ -300,6 +371,8 @@ bool ANIM_armature_bonecoll_unassign(BoneCollection *bcoll, Bone *bone)
void ANIM_armature_bonecoll_unassign_all(Bone *bone)
{
LISTBASE_FOREACH_MUTABLE (BoneCollectionReference *, ref, &bone->runtime.collections) {
/* TODO: include Armature as parameter, and check that the bone collection to unassign from is
* actually editable. */
ANIM_armature_bonecoll_unassign(ref->bcoll, bone);
}
}
@ -394,7 +467,7 @@ void ANIM_bone_set_layer_ebone(EditBone *ebone, const int layer)
void ANIM_armature_bonecoll_assign_active(const bArmature *armature, EditBone *ebone)
{
if (armature->active_collection == nullptr) {
if (armature->runtime.active_collection == nullptr) {
/* No active collection, do not assign to any. */
printf("ANIM_armature_bonecoll_assign_active(%s, %s): no active collection\n",
ebone->name,
@ -402,7 +475,7 @@ void ANIM_armature_bonecoll_assign_active(const bArmature *armature, EditBone *e
return;
}
ANIM_armature_bonecoll_assign_editbone(armature->active_collection, ebone);
ANIM_armature_bonecoll_assign_editbone(armature->runtime.active_collection, ebone);
}
void ANIM_armature_bonecoll_show_from_bone(bArmature *armature, const Bone *bone)

View File

@ -55,6 +55,13 @@ class ANIM_armature_bone_collections : public testing::Test {
BLI_addtail(&arm.bonebase, &bone2); /* bone2 is root bone. */
BLI_addtail(&bone2.childbase, &bone3); /* bone3 has bone2 as parent. */
}
void TearDown() override
{
LISTBASE_FOREACH_BACKWARD_MUTABLE (BoneCollection *, bcoll, &arm.collections) {
ANIM_armature_bonecoll_remove(&arm, bcoll);
}
}
};
TEST_F(ANIM_armature_bone_collections, armature_owned_collections)
@ -112,4 +119,93 @@ TEST_F(ANIM_armature_bone_collections, bones_assign_remove)
"removed";
}
TEST_F(ANIM_armature_bone_collections, active_set_clear_by_pointer)
{
BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
BoneCollection *bcoll3 = ANIM_bonecoll_new("Alien Bones");
ANIM_armature_bonecoll_active_set(&arm, bcoll1);
EXPECT_EQ(0, arm.runtime.active_collection_index);
EXPECT_EQ(bcoll1, arm.runtime.active_collection);
EXPECT_STREQ(bcoll1->name, arm.active_collection_name);
ANIM_armature_bonecoll_active_set(&arm, nullptr);
EXPECT_EQ(-1, arm.runtime.active_collection_index);
EXPECT_EQ(nullptr, arm.runtime.active_collection);
EXPECT_STREQ("", arm.active_collection_name);
ANIM_armature_bonecoll_active_set(&arm, bcoll2);
EXPECT_EQ(1, arm.runtime.active_collection_index);
EXPECT_EQ(bcoll2, arm.runtime.active_collection);
EXPECT_STREQ(bcoll2->name, arm.active_collection_name);
ANIM_armature_bonecoll_active_set(&arm, bcoll3);
EXPECT_EQ(-1, arm.runtime.active_collection_index);
EXPECT_EQ(nullptr, arm.runtime.active_collection);
EXPECT_STREQ("", arm.active_collection_name);
ANIM_bonecoll_free(bcoll3);
}
TEST_F(ANIM_armature_bone_collections, active_set_clear_by_index)
{
BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
ANIM_armature_bonecoll_active_index_set(&arm, 0);
EXPECT_EQ(0, arm.runtime.active_collection_index);
EXPECT_EQ(bcoll1, arm.runtime.active_collection);
EXPECT_STREQ(bcoll1->name, arm.active_collection_name);
ANIM_armature_bonecoll_active_index_set(&arm, -1);
EXPECT_EQ(-1, arm.runtime.active_collection_index);
EXPECT_EQ(nullptr, arm.runtime.active_collection);
EXPECT_STREQ("", arm.active_collection_name);
ANIM_armature_bonecoll_active_index_set(&arm, 1);
EXPECT_EQ(1, arm.runtime.active_collection_index);
EXPECT_EQ(bcoll2, arm.runtime.active_collection);
EXPECT_STREQ(bcoll2->name, arm.active_collection_name);
ANIM_armature_bonecoll_active_index_set(&arm, 47);
EXPECT_EQ(-1, arm.runtime.active_collection_index);
EXPECT_EQ(nullptr, arm.runtime.active_collection);
EXPECT_STREQ("", arm.active_collection_name);
}
TEST_F(ANIM_armature_bone_collections, bcoll_is_editable)
{
BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
EXPECT_EQ(0, bcoll1->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL);
EXPECT_EQ(0, bcoll2->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL);
EXPECT_TRUE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting local armature to be editable";
/* Fake that the armature is linked from another blend file. */
Library fake_lib;
arm.id.lib = &fake_lib;
EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting local armature to not be editable";
/* Fake that the armature is an override, but linked from another blend file. */
IDOverrideLibrary fake_override;
bArmature fake_reference;
fake_override.reference = &fake_reference.id;
arm.id.override_library = &fake_override;
EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting linked armature override to not be editable";
/* Fake that the armature is a local override. */
arm.id.lib = nullptr;
bcoll2->flags |= BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting linked bone collection on local armature override to not be editable";
EXPECT_TRUE(ANIM_armature_bonecoll_is_editable(&arm, bcoll2))
<< "Expecting local bone collection on local armature override to be editable";
}
} // namespace blender::animrig::tests

View File

@ -22,6 +22,8 @@
# include "BLI_winstuff.h"
#endif
#include "asset_library_service.hh"
#include "CLG_log.h"
static CLG_LogRef LOG = {"asset_system.asset_catalog_service"};
@ -236,6 +238,7 @@ void AssetCatalogService::prune_catalogs_by_path(const AssetCatalogPath &path)
}
this->rebuild_tree();
AssetLibraryService::get()->rebuild_all_library();
}
void AssetCatalogService::prune_catalogs_by_id(const CatalogID catalog_id)
@ -270,6 +273,7 @@ void AssetCatalogService::update_catalog_path(const CatalogID catalog_id,
}
this->rebuild_tree();
AssetLibraryService::get()->rebuild_all_library();
}
AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalog_path)
@ -296,6 +300,8 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo
BLI_assert_msg(catalog_tree_, "An Asset Catalog tree should always exist.");
catalog_tree_->insert_item(*catalog_ptr);
AssetLibraryService::get()->rebuild_all_library();
return catalog_ptr;
}
@ -644,6 +650,7 @@ void AssetCatalogService::undo()
redo_snapshots_.append(std::move(catalog_collection_));
catalog_collection_ = undo_snapshots_.pop_last();
rebuild_tree();
AssetLibraryService::get()->rebuild_all_library();
}
void AssetCatalogService::redo()
@ -654,6 +661,7 @@ void AssetCatalogService::redo()
undo_snapshots_.append(std::move(catalog_collection_));
catalog_collection_ = redo_snapshots_.pop_last();
rebuild_tree();
AssetLibraryService::get()->rebuild_all_library();
}
void AssetCatalogService::undo_push()

View File

@ -178,7 +178,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_current_file()
return lib;
}
static void rebuild_all_library(AssetLibrary &all_library, const bool reload_catalogs)
static void rebuild_all_library_ex(AssetLibrary &all_library, const bool reload_catalogs)
{
/* Start with empty catalog storage. */
all_library.catalog_service = std::make_unique<AssetCatalogService>(
@ -195,6 +195,13 @@ static void rebuild_all_library(AssetLibrary &all_library, const bool reload_cat
all_library.catalog_service->rebuild_tree();
}
void AssetLibraryService::rebuild_all_library()
{
if (all_library_) {
rebuild_all_library_ex(*all_library_, false);
}
}
AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
{
/* (Re-)load all other asset libraries. */
@ -218,10 +225,10 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
all_library_ = std::make_unique<AssetLibrary>(ASSET_LIBRARY_ALL);
/* Don't reload catalogs on this initial read, they've just been loaded above. */
rebuild_all_library(*all_library_, /*reload_catlogs=*/false);
rebuild_all_library_ex(*all_library_, /*reload_catlogs=*/false);
all_library_->on_refresh_ = [](AssetLibrary &all_library) {
rebuild_all_library(all_library, /*reload_catalogs=*/true);
rebuild_all_library_ex(all_library, /*reload_catalogs=*/true);
};
return all_library_.get();

View File

@ -80,6 +80,7 @@ class AssetLibraryService {
AssetLibrary *get_asset_library_current_file();
/** Get the "All" asset library, which loads all others and merges them into one. */
AssetLibrary *get_asset_library_all(const Main *bmain);
void rebuild_all_library();
/**
* Return the start position of the last blend-file extension in given path,

View File

@ -1053,7 +1053,10 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
}
if ((settings_font->flags & BLF_MONOSPACED) && (settings_font != glyph_font)) {
blf_glyph_transform_monospace(glyph, BLI_wcwidth(char32_t(charcode)) * fixed_width);
const int col = BLI_wcwidth(char32_t(charcode));
if (col > 0) {
blf_glyph_transform_monospace(glyph, col * fixed_width);
}
}
/* Fallback glyph transforms, but only if required and not yet done. */

View File

@ -224,7 +224,7 @@ void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
* \note This must be called in the same context as the poll function that created it.
*/
struct bContextPollMsgDyn_Params {
/** The result is allocated . */
/** The result is allocated. */
char *(*get_fn)(bContext *C, void *user_data);
/** Optionally free the user-data. */
void (*free_fn)(bContext *C, void *user_data);

View File

@ -34,11 +34,11 @@ struct ID;
typedef uint64_t eCustomDataMask;
/* These names are used as prefixes for UV layer names to find the associated boolean
* layers. They should never be longer than 2 chars, as MAX_CUSTOMDATA_LAYER_NAME
* layers. They should never be longer than 2 chars, as #MAX_CUSTOMDATA_LAYER_NAME
* has 4 extra bytes above what can be used for the base layer name, and these
* prefixes are placed between 2 '.'s at the start of the layer name.
* For example The uv vert selection layer of a layer named 'UVMap.001'
* will be called '.vs.UVMap.001' . */
* For example The uv vert selection layer of a layer named `UVMap.001`
* will be called `.vs.UVMap.001`. */
#define UV_VERTSEL_NAME "vs"
#define UV_EDGESEL_NAME "es"
#define UV_PINNED_NAME "pn"

View File

@ -434,7 +434,7 @@ typedef struct bNodeTreeType {
void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree);
void (*local_merge)(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
/* Tree update. Overrides `nodetype->updatetreefunc` ! */
/* Tree update. Overrides `nodetype->updatetreefunc`. */
void (*update)(struct bNodeTree *ntree);
bool (*validate_link)(eNodeSocketDatatype from, eNodeSocketDatatype to);

View File

@ -44,6 +44,9 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node);
void ntreeUpdateAllNew(Main *main);
/** Update asset meta-data cache of data-block properties. */
void node_update_asset_metadata(bNodeTree &node_tree);
void ntreeNodeFlagSet(const bNodeTree *ntree, int flag, bool enable);
/**

View File

@ -171,7 +171,6 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
bool has_undefined_nodes_or_sockets = false;
bNode *group_output_node = nullptr;
Vector<bNode *> root_frames;
bNodeTreeInterfaceCache interface_cache;
};
/**
@ -546,22 +545,27 @@ inline blender::Span<bNestedNodeRef> bNodeTree::nested_node_refs_span() const
return {this->nested_node_refs, this->nested_node_refs_num};
}
inline void bNodeTree::ensure_interface_cache() const
{
this->tree_interface.ensure_items_cache();
}
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_inputs() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->interface_cache.inputs;
BLI_assert(this->tree_interface.items_cache_is_available());
return this->tree_interface.runtime->inputs_;
}
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_outputs() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->interface_cache.outputs;
BLI_assert(this->tree_interface.items_cache_is_available());
return this->tree_interface.runtime->outputs_;
}
inline blender::Span<bNodeTreeInterfaceItem *> bNodeTree::interface_items() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->interface_cache.items;
BLI_assert(this->tree_interface.items_cache_is_available());
return this->tree_interface.runtime->items_;
}
/** \} */
@ -790,9 +794,14 @@ inline bool bNodeSocket::is_panel_collapsed() const
return (this->flag & SOCK_PANEL_COLLAPSED) != 0;
}
inline bool bNodeSocket::is_visible_or_panel_collapsed() const
{
return !this->is_hidden() && this->is_available();
}
inline bool bNodeSocket::is_visible() const
{
return !this->is_hidden() && this->is_available() && !this->is_panel_collapsed();
return this->is_visible_or_panel_collapsed() && !this->is_panel_collapsed();
}
inline bNode &bNodeSocket::owner_node()

View File

@ -12,18 +12,37 @@
#include <queue>
#include <type_traits>
#include "BLI_cache_mutex.hh"
#include "BLI_parameter_pack_utils.hh"
#include "BLI_vector.hh"
namespace blender::bke {
/* Runtime topology cache for linear access to items. */
struct bNodeTreeInterfaceCache {
Vector<bNodeTreeInterfaceItem *> items;
Vector<bNodeTreeInterfaceSocket *> inputs;
Vector<bNodeTreeInterfaceSocket *> outputs;
class NodeTreeMainUpdater;
void rebuild(bNodeTreeInterface &tree_interface);
class bNodeTreeInterfaceRuntime {
friend bNodeTreeInterface;
friend bNodeTree;
private:
/**
* Keeps track of what changed in the node tree until the next update.
* Should not be changed directly, instead use the functions in `BKE_node_tree_update.h`.
* #NodeTreeInterfaceChangedFlag.
*/
uint32_t changed_flag_ = 0;
/**
* Protects access to item cache variables below. This is necessary so that the cache can be
* updated on a const #bNodeTreeInterface.
*/
CacheMutex items_cache_mutex_;
/* Runtime topology cache for linear access to items. */
Vector<bNodeTreeInterfaceItem *> items_;
/* Socket-only lists for input/output access by index. */
Vector<bNodeTreeInterfaceSocket *> inputs_;
Vector<bNodeTreeInterfaceSocket *> outputs_;
};
namespace node_interface {

View File

@ -54,8 +54,6 @@ void BKE_ntree_update_tag_link_mute(struct bNodeTree *ntree, struct bNodeLink *l
void BKE_ntree_update_tag_active_output_changed(struct bNodeTree *ntree);
/** Used after file loading when run-time data on the tree has not been initialized yet. */
void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree);
/** Used when the interface sockets/values have changed. */
void BKE_ntree_update_tag_interface(struct bNodeTree *ntree);
/** Used when change parent node. */
void BKE_ntree_update_tag_parent_change(struct bNodeTree *ntree, struct bNode *node);
/** Used when an id data block changed that might be used by nodes that need to be updated. */

View File

@ -217,7 +217,7 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *t
* \note frame number should be in clip space, not scene space.
*/
typedef enum eTrackClearAction {
/* Clear path from `ref_frame+1` up to the . */
/* Clear path from `ref_frame+1` up to the. */
TRACK_CLEAR_UPTO,
/* Clear path from the beginning up to `ref_frame-1`. */
TRACK_CLEAR_REMAINED,

View File

@ -1768,9 +1768,9 @@ static float nla_blend_value(const int blendmode,
default: /* TODO: Do we really want to blend by default? it seems more uses might prefer add...
*/
/* Do linear interpolation. The influence of the accumulated data (elsewhere, that is called
* dstweight) is 1 - influence, since the strip's influence is srcweight.
*/
/* Do linear interpolation. The influence of the accumulated data
* (elsewhere, that is called `dstwegiht`) is 1 - influence,
* since the strip's influence is `srcweight`. */
return lower_value * (1.0f - influence) + (strip_value * influence);
}
}

View File

@ -350,10 +350,18 @@ static void armature_blend_read_data(BlendDataReader *reader, ID *id)
}
BLO_read_list(reader, &arm->collections);
/* Bone collections added via an override can be edited, but ones that already exist in another
* blend file (so on the linked Armature) should not be touched. */
const bool reset_bcoll_override_flag = ID_IS_LINKED(&arm->id);
LISTBASE_FOREACH (BoneCollection *, bcoll, &arm->collections) {
direct_link_bone_collection(reader, bcoll);
if (reset_bcoll_override_flag) {
/* The linked Armature may have overrides in the library file already, and
* those should *not* be editable here. */
bcoll->flags &= ~BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
}
}
BLO_read_data_address(reader, &arm->active_collection);
BLO_read_data_address(reader, &arm->act_bone);
arm->act_edbone = nullptr;

View File

@ -790,7 +790,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
return nullptr;
}
/* Add the position attribute later so it can be shared in some cases.*/
/* Add the position attribute later so it can be shared in some cases. */
Mesh *mesh = BKE_mesh_new_nomain(
0, offsets.edge.last(), offsets.face.last(), offsets.loop.last());
CustomData_free_layer_named(&mesh->vert_data, "position", 0);

View File

@ -1757,7 +1757,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(MRecast), "MRecast", 1, N_("Recast"), nullptr, nullptr, nullptr, nullptr},
/* 25: CD_MPOLY */ /* DEPRECATED */
{sizeof(MPoly), "MPoly", 1, N_("NGon Face"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 26: CD_MLOOP */ /* DEPRECATED*/
/* 26: CD_MLOOP */ /* DEPRECATED */
{sizeof(MLoop),
"MLoop",
1,

View File

@ -141,7 +141,7 @@ static void image_buf_fill_checker_slice(
rect = rect_orig;
rect_float = rect_float_orig;
/* 2nd pass, colored + */
/* 2nd pass, colored `+`. */
for (y = offset; y < height + offset; y++) {
float hoffs = 0.125f * floorf(y / checkerwidth);

View File

@ -2040,10 +2040,7 @@ static bool seq_convert_callback(Sequence *seq, void *userdata)
return true;
}
/* patch adrcode, so that we can map
* to different DNA variables later
* (semi-hack (tm) )
*/
/* Patch `adrcode`, so that we can map to different DNA variables later (semi-hack (tm)). */
switch (seq->type) {
case SEQ_TYPE_IMAGE:
case SEQ_TYPE_META:

View File

@ -2540,6 +2540,10 @@ void BKE_view_layer_verify_aov(RenderEngine *engine, Scene *scene, ViewLayer *vi
viewlayer_aov_make_name_unique(view_layer);
GHash *name_count = BLI_ghash_str_new(__func__);
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
/* Disable conflict flag, so that the AOV is included when iterating over all passes below. */
aov->flag &= ~AOV_CONFLICT;
}
RE_engine_update_render_passes(
engine, scene, view_layer, bke_view_layer_verify_aov_cb, name_count);
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {

View File

@ -176,8 +176,8 @@ static int id_free(Main *bmain, void *idv, int flag, const bool use_flag_from_id
void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
{
/* ViewLayer resync needs to be delayed during Scene freeing, since internal relationships
* between the Scene's master collection and its view_layers become invalid (due to remapping .
*/
* between the Scene's master collection and its view_layers become invalid
* (due to remapping). */
BKE_layer_collection_resync_forbid();
flag = id_free(bmain, idv, flag, use_flag_from_idtag);
@ -371,8 +371,8 @@ static size_t id_delete(Main *bmain,
BKE_main_unlock(bmain);
/* ViewLayer resync needs to be delayed during Scene freeing, since internal relationships
* between the Scene's master collection and its view_layers become invalid (due to remapping .
*/
* between the Scene's master collection and its view_layers become invalid
* (due to remapping). */
BKE_layer_collection_resync_forbid();
/* In usual reversed order, such that all usage of a given ID, even 'never nullptr' ones,

View File

@ -780,7 +780,7 @@ static bool lib_query_unused_ids_tag_recurse(Main *bmain,
bmain, tag, do_local_ids, do_linked_ids, id_from, r_num_tagged))
{
/* Dependency loop case, ignore the `id_from` tag value here (as it should not be considered
* as valid yet), and presume that this is a 'valid user' case for now. . */
* as valid yet), and presume that this is a 'valid user' case for now. */
is_part_of_dependency_loop = true;
continue;
}

View File

@ -158,12 +158,14 @@ void BKE_main_free(Main *mainvar)
bool BKE_main_is_empty(Main *bmain)
{
bool result = true;
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
return false;
result = false;
break;
}
FOREACH_MAIN_ID_END;
return true;
return result;
}
void BKE_main_lock(Main *bmain)

View File

@ -1094,14 +1094,17 @@ static void ntree_blend_read_after_liblink(BlendLibReader *reader, ID *id)
}
}
static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData *asset_data)
void node_update_asset_metadata(bNodeTree &node_tree)
{
bNodeTree &node_tree = *static_cast<bNodeTree *>(asset_ptr);
AssetMetaData *asset_data = node_tree.id.asset_data;
if (!asset_data) {
return;
}
BKE_asset_metadata_idprop_ensure(asset_data, idprop::create("type", node_tree.type).release());
auto inputs = idprop::create_group("inputs");
auto outputs = idprop::create_group("outputs");
node_tree.ensure_topology_cache();
node_tree.ensure_interface_cache();
for (const bNodeTreeInterfaceSocket *socket : node_tree.interface_inputs()) {
auto property = idprop::create(socket->name, socket->socket_type);
IDP_AddToGroup(inputs.get(), property.release());
@ -1119,6 +1122,11 @@ static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData *asset_data)
}
}
static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData * /*asset_data*/)
{
node_update_asset_metadata(*static_cast<bNodeTree *>(asset_ptr));
}
} // namespace blender::bke
static AssetTypeInfo AssetType_NT = {
@ -2748,7 +2756,8 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
bool nodeLinkIsHidden(const bNodeLink *link)
{
return !(link->fromsock->is_visible() && link->tosock->is_visible());
return !(link->fromsock->is_visible_or_panel_collapsed() &&
link->tosock->is_visible_or_panel_collapsed());
}
namespace blender::bke {

View File

@ -24,14 +24,6 @@ void preprocess_geometry_node_tree_for_evaluation(bNodeTree &tree_cow)
blender::nodes::ensure_geometry_nodes_lazy_function_graph(tree_cow);
}
static void update_interface(const bNodeTree &ntree)
{
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
/* const_cast needed because the cache stores mutable item pointers, but needs a mutable
* interface in order to get them. The interface itself is not modified here. */
tree_runtime.interface_cache.rebuild(const_cast<bNodeTreeInterface &>(ntree.tree_interface));
}
static void update_node_vector(const bNodeTree &ntree)
{
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
@ -538,7 +530,6 @@ static void ensure_topology_cache(const bNodeTree &ntree)
{
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
tree_runtime.topology_cache_mutex.ensure([&]() {
update_interface(ntree);
update_node_vector(ntree);
update_link_vector(ntree);
update_socket_vectors_and_owner_node(ntree);

View File

@ -203,6 +203,7 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
const bNodeTree &tree)
{
BLI_assert(!tree.has_available_link_cycle());
tree.ensure_interface_cache();
ResourceScope scope;
const Array<const aal::RelationsInNode *> relations_by_node = get_relations_by_node(tree, scope);

View File

@ -689,6 +689,7 @@ bool update_field_inferencing(const bNodeTree &tree)
{
BLI_assert(tree.type == NTREE_GEOMETRY);
tree.ensure_topology_cache();
tree.ensure_interface_cache();
const Span<const bNode *> nodes = tree.all_nodes();
ResourceScope scope;

View File

@ -20,6 +20,15 @@
#include "DNA_node_tree_interface_types.h"
#include "DNA_node_types.h"
/**
* These flags are used by the `changed_flag` field in #bNodeTreeInterfaceRuntime.
*/
enum NodeTreeInterfaceChangedFlag {
NODE_INTERFACE_CHANGED_NOTHING = 0,
NODE_INTERFACE_CHANGED_ITEMS = (1 << 1),
NODE_INTERFACE_CHANGED_ALL = -1,
};
namespace blender::bke::node_interface {
namespace socket_types {
@ -1021,6 +1030,9 @@ static bNodeTreeInterfacePanel *make_panel(const int uid,
void bNodeTreeInterface::init_data()
{
this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
this->tag_missing_runtime_data();
/* Root panel is allowed to contain child panels. */
root_panel.flag |= NODE_INTERFACE_PANEL_ALLOW_CHILD_PANELS;
}
@ -1029,10 +1041,15 @@ void bNodeTreeInterface::copy_data(const bNodeTreeInterface &src, int flag)
{
item_types::panel_init(this->root_panel, src.root_panel.items(), flag, nullptr);
this->active_index = src.active_index;
this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
this->tag_missing_runtime_data();
}
void bNodeTreeInterface::free_data()
{
MEM_delete(this->runtime);
/* Called when freeing the main database, don't do user refcount here. */
this->root_panel.clear(false);
}
@ -1047,6 +1064,9 @@ void bNodeTreeInterface::write(BlendWriter *writer)
void bNodeTreeInterface::read_data(BlendDataReader *reader)
{
item_types::item_read_data(reader, this->root_panel.item);
this->runtime = MEM_new<blender::bke::bNodeTreeInterfaceRuntime>(__func__);
this->tag_missing_runtime_data();
}
bNodeTreeInterfaceItem *bNodeTreeInterface::active_item()
@ -1109,6 +1129,8 @@ bNodeTreeInterfaceSocket *bNodeTreeInterface::add_socket(blender::StringRefNull
if (new_socket) {
parent->add_item(new_socket->item);
}
this->tag_items_changed();
return new_socket;
}
@ -1129,6 +1151,8 @@ bNodeTreeInterfaceSocket *bNodeTreeInterface::insert_socket(blender::StringRefNu
if (new_socket) {
parent->insert_item(new_socket->item, position);
}
this->tag_items_changed();
return new_socket;
}
@ -1151,6 +1175,8 @@ bNodeTreeInterfacePanel *bNodeTreeInterface::add_panel(blender::StringRefNull na
if (new_panel) {
parent->add_item(new_panel->item);
}
this->tag_items_changed();
return new_panel;
}
@ -1174,6 +1200,8 @@ bNodeTreeInterfacePanel *bNodeTreeInterface::insert_panel(blender::StringRefNull
if (new_panel) {
parent->insert_item(new_panel->item, position);
}
this->tag_items_changed();
return new_panel;
}
@ -1197,6 +1225,7 @@ bNodeTreeInterfaceItem *bNodeTreeInterface::add_item_copy(const bNodeTreeInterfa
item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
parent->add_item(*citem);
this->tag_items_changed();
return citem;
}
@ -1221,6 +1250,7 @@ bNodeTreeInterfaceItem *bNodeTreeInterface::insert_item_copy(const bNodeTreeInte
item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
parent->insert_item(*citem, position);
this->tag_items_changed();
return citem;
}
@ -1239,14 +1269,17 @@ bool bNodeTreeInterface::remove_item(bNodeTreeInterfaceItem &item, bool move_con
}
}
if (parent->remove_item(item, true)) {
this->tag_items_changed();
return true;
}
return false;
}
void bNodeTreeInterface::clear_items()
{
root_panel.clear(true);
this->tag_items_changed();
}
bool bNodeTreeInterface::move_item(bNodeTreeInterfaceItem &item, const int new_position)
@ -1255,7 +1288,12 @@ bool bNodeTreeInterface::move_item(bNodeTreeInterfaceItem &item, const int new_p
if (parent == nullptr) {
return false;
}
return parent->move_item(item, new_position);
if (parent->move_item(item, new_position)) {
this->tag_items_changed();
return true;
}
return false;
}
bool bNodeTreeInterface::move_item_to_parent(bNodeTreeInterfaceItem &item,
@ -1273,13 +1311,17 @@ bool bNodeTreeInterface::move_item_to_parent(bNodeTreeInterfaceItem &item,
return false;
}
if (parent == new_parent) {
return parent->move_item(item, new_position);
if (parent->move_item(item, new_position)) {
this->tag_items_changed();
return true;
}
}
else {
/* Note: only remove and reinsert when parents different, otherwise removing the item can
* change the desired target position! */
if (parent->remove_item(item, false)) {
new_parent->insert_item(item, new_position);
this->tag_items_changed();
return true;
}
}
@ -1291,27 +1333,59 @@ void bNodeTreeInterface::foreach_id(LibraryForeachIDData *cb)
item_types::item_foreach_id(cb, root_panel.item);
}
namespace blender::bke {
void bNodeTreeInterfaceCache::rebuild(bNodeTreeInterface &interface)
bool bNodeTreeInterface::items_cache_is_available() const
{
/* Rebuild draw-order list of interface items for linear access. */
items.clear();
inputs.clear();
outputs.clear();
return !this->runtime->items_cache_mutex_.is_dirty();
}
interface.foreach_item([&](bNodeTreeInterfaceItem &item) {
items.append(&item);
if (bNodeTreeInterfaceSocket *socket = get_item_as<bNodeTreeInterfaceSocket>(&item)) {
if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) {
inputs.append(socket);
void bNodeTreeInterface::ensure_items_cache() const
{
blender::bke::bNodeTreeInterfaceRuntime &runtime = *this->runtime;
runtime.items_cache_mutex_.ensure([&]() {
/* Rebuild draw-order list of interface items for linear access. */
runtime.items_.clear();
runtime.inputs_.clear();
runtime.outputs_.clear();
/* Items in the cache are mutable pointers, but node tree update considers ID data to be
* immutable when caching. DNA ListBase pointers can be mutable even if their container is
* const, but the items returned by #foreach_item inherit qualifiers from the container. */
bNodeTreeInterface &mutable_self = const_cast<bNodeTreeInterface &>(*this);
mutable_self.foreach_item([&](bNodeTreeInterfaceItem &item) {
runtime.items_.append(&item);
if (bNodeTreeInterfaceSocket *socket = get_item_as<bNodeTreeInterfaceSocket>(&item)) {
if (socket->flag & NODE_INTERFACE_SOCKET_INPUT) {
runtime.inputs_.append(socket);
}
if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
runtime.outputs_.append(socket);
}
}
if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
outputs.append(socket);
}
}
return true;
return true;
});
});
}
} // namespace blender::bke
void bNodeTreeInterface::tag_missing_runtime_data()
{
this->runtime->changed_flag_ |= NODE_INTERFACE_CHANGED_ALL;
this->runtime->items_cache_mutex_.tag_dirty();
}
bool bNodeTreeInterface::is_changed() const
{
return this->runtime->changed_flag_ != NODE_INTERFACE_CHANGED_NOTHING;
}
void bNodeTreeInterface::tag_items_changed()
{
this->runtime->changed_flag_ |= NODE_INTERFACE_CHANGED_ITEMS;
this->runtime->items_cache_mutex_.tag_dirty();
}
void bNodeTreeInterface::reset_changed_flags()
{
this->runtime->changed_flag_ = NODE_INTERFACE_CHANGED_NOTHING;
}

View File

@ -46,13 +46,12 @@ enum eNodeTreeChangedFlag {
NTREE_CHANGED_ANY = (1 << 1),
NTREE_CHANGED_NODE_PROPERTY = (1 << 2),
NTREE_CHANGED_NODE_OUTPUT = (1 << 3),
NTREE_CHANGED_INTERFACE = (1 << 4),
NTREE_CHANGED_LINK = (1 << 5),
NTREE_CHANGED_REMOVED_NODE = (1 << 6),
NTREE_CHANGED_REMOVED_SOCKET = (1 << 7),
NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8),
NTREE_CHANGED_INTERNAL_LINK = (1 << 9),
NTREE_CHANGED_PARENT = (1 << 10),
NTREE_CHANGED_LINK = (1 << 4),
NTREE_CHANGED_REMOVED_NODE = (1 << 5),
NTREE_CHANGED_REMOVED_SOCKET = (1 << 6),
NTREE_CHANGED_SOCKET_PROPERTY = (1 << 7),
NTREE_CHANGED_INTERNAL_LINK = (1 << 8),
NTREE_CHANGED_PARENT = (1 << 9),
NTREE_CHANGED_ALL = -1,
};
@ -163,6 +162,12 @@ static int get_internal_link_type_priority(const bNodeSocketType *from, const bN
return -1;
}
/* Check both the tree's own tags and the interface tags. */
static bool is_tree_changed(const bNodeTree &tree)
{
return tree.runtime->changed_flag != NTREE_CHANGED_NOTHING || tree.tree_interface.is_changed();
}
using TreeNodePair = std::pair<bNodeTree *, bNode *>;
using ObjectModifierPair = std::pair<Object *, ModifierData *>;
using NodeSocketPair = std::pair<bNode *, bNodeSocket *>;
@ -296,7 +301,7 @@ class NodeTreeMainUpdater {
{
Vector<bNodeTree *> changed_ntrees;
FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
if (ntree->runtime->changed_flag != NTREE_CHANGED_NOTHING) {
if (is_tree_changed(*ntree)) {
changed_ntrees.append(ntree);
}
}
@ -314,7 +319,7 @@ class NodeTreeMainUpdater {
if (root_ntrees.size() == 1) {
bNodeTree *ntree = root_ntrees[0];
if (ntree->runtime->changed_flag == NTREE_CHANGED_NOTHING) {
if (!is_tree_changed(*ntree)) {
return;
}
const TreeUpdateResult result = this->update_tree(*ntree);
@ -327,7 +332,7 @@ class NodeTreeMainUpdater {
if (!is_single_tree_update) {
Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees);
for (bNodeTree *ntree : ntrees_in_order) {
if (ntree->runtime->changed_flag == NTREE_CHANGED_NOTHING) {
if (!is_tree_changed(*ntree)) {
continue;
}
if (!update_result_by_tree_.contains(ntree)) {
@ -503,9 +508,7 @@ class NodeTreeMainUpdater {
ntreeTexCheckCyclics(&ntree);
}
if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE ||
ntree.runtime->changed_flag & NTREE_CHANGED_ANY)
{
if (ntree.tree_interface.is_changed()) {
result.interface_changed = true;
}
@ -579,7 +582,7 @@ class NodeTreeMainUpdater {
/* Currently we have no way to tell if a node needs to be updated when a link changed. */
return true;
}
if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
if (ntree.tree_interface.is_changed()) {
if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
return true;
}
@ -716,8 +719,7 @@ class NodeTreeMainUpdater {
{
/* Don't trigger preview removal when only those flags are set. */
const uint32_t allowed_flags = NTREE_CHANGED_LINK | NTREE_CHANGED_SOCKET_PROPERTY |
NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT |
NTREE_CHANGED_INTERFACE;
NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT;
if ((ntree.runtime->changed_flag & allowed_flags) == ntree.runtime->changed_flag) {
return;
}
@ -1243,6 +1245,8 @@ class NodeTreeMainUpdater {
socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
}
}
ntree.tree_interface.reset_changed_flags();
}
};
@ -1342,11 +1346,6 @@ void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
add_tree_tag(ntree, NTREE_CHANGED_ALL);
}
void BKE_ntree_update_tag_interface(bNodeTree *ntree)
{
add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
}
void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, bNode *node)
{
add_node_tag(ntree, node, NTREE_CHANGED_PARENT);

View File

@ -58,7 +58,7 @@
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define CHECK_TYPE_INLINE(val, type) \
(void)((void)(((type)0) != (0 ? (val) : ((type)0))), _Generic((val), type : 0, const type : 0))
/* NOTE: The NONCONST version is needed for scalar types on CLANG, to avoid warnings. . */
/* NOTE: The NONCONST version is needed for scalar types on CLANG, to avoid warnings. */
# define CHECK_TYPE_INLINE_NONCONST(val, type) \
(void)((void)(((type)0) != (0 ? (val) : ((type)0))), _Generic((val), type : 0))
#else

View File

@ -290,7 +290,7 @@ MINLINE uint divide_ceil_u(uint a, uint b);
MINLINE uint64_t divide_ceil_ul(uint64_t a, uint64_t b);
/**
* Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
* Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a.
*/
MINLINE uint ceil_to_multiple_u(uint a, uint b);
MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b);

View File

@ -88,7 +88,7 @@ template<typename T>
* \{ */
/**
* Transform \a v by rotation using the quaternion \a q .
* Transform \a v by rotation using the quaternion \a q.
*/
template<typename T>
[[nodiscard]] inline VecBase<T, 3> transform_point(const QuaternionBase<T> &q,

View File

@ -121,7 +121,7 @@ bool BLI_str_cursor_step_next_utf8(const char *str, size_t str_maxlen, int *pos)
const char *str_next = str_pos;
do {
str_next = BLI_str_find_next_char_utf8(str_next, str_end);
} while (str_next < str_end && str_next[0] != 0 && BLI_str_utf8_char_width(str_next) < 1);
} while (str_next < str_end && str_next[0] != 0 && BLI_str_utf8_char_width(str_next) == 0);
(*pos) += (str_next - str_pos);
if ((*pos) > (int)str_maxlen) {
(*pos) = (int)str_maxlen;

View File

@ -579,7 +579,7 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
BLI_addtail(in_out == SOCK_IN ? &ngroup->inputs_legacy : &ngroup->outputs_legacy, gsock);
BKE_ntree_update_tag_interface(ngroup);
ngroup->tree_interface.tag_items_changed();
return gsock;
}

View File

@ -1054,7 +1054,7 @@ static void version_geometry_nodes_extrude_smooth_propagation(bNodeTree &ntree)
}
/* Change the action strip (if a NLA strip is preset) to HOLD instead of HOLD FORWARD to maintain
* backwards compatibility.*/
* backwards compatibility. */
static void version_nla_action_strip_hold(Main *bmain)
{
ID *id;
@ -1070,9 +1070,8 @@ static void version_nla_action_strip_hold(Main *bmain)
if (BKE_nlatrack_has_strips(&adt->nla_tracks)) {
adt->act_extendmode = NLASTRIP_EXTEND_HOLD;
}
FOREACH_MAIN_ID_END;
}
FOREACH_MAIN_ID_END;
}
void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)

View File

@ -1960,7 +1960,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
}
/* Needed for interface cache. */
ntree->ensure_topology_cache();
ntree->ensure_interface_cache();
for (bNodeTreeInterfaceSocket *socket : ntree->interface_inputs()) {
build_idproperties(socket->properties);
}

View File

@ -2935,6 +2935,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
}
ntree->ensure_interface_cache();
for (bNodeTreeInterfaceSocket *socket : ntree->interface_inputs()) {
build_idproperties(socket->properties);
}

View File

@ -154,12 +154,12 @@ static void eevee_init_util_texture()
memcpy(texels_layer, blender::eevee::lut::ltc_mat_ggx, sizeof(float[4]) * 64 * 64);
texels_layer += 64 * 64;
/* Copy bsdf_split_sum_ggx into 2nd layer red and green channels.
/* Copy brdf_ggx into 2nd layer red and green channels.
* Copy ltc_mag_ggx into 2nd layer blue and alpha channel. */
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
texels_layer[y * 64 + x][0] = blender::eevee::lut::bsdf_split_sum_ggx[y][x][0];
texels_layer[y * 64 + x][1] = blender::eevee::lut::bsdf_split_sum_ggx[y][x][1];
texels_layer[y * 64 + x][0] = blender::eevee::lut::brdf_ggx[y][x][0];
texels_layer[y * 64 + x][1] = blender::eevee::lut::brdf_ggx[y][x][1];
texels_layer[y * 64 + x][2] = blender::eevee::lut::ltc_mag_ggx[y][x][0];
texels_layer[y * 64 + x][3] = blender::eevee::lut::ltc_mag_ggx[y][x][1];
}
@ -188,12 +188,12 @@ static void eevee_init_util_texture()
}
texels_layer += 64 * 64;
/* Copy Refraction GGX LUT in layer 5 - 21 */
/* Copy BSDF GGX LUT in layer 5 - 21 */
for (int j = 0; j < 16; j++) {
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
texels_layer[y * 64 + x][0] = blender::eevee::lut::btdf_split_sum_ggx[j][y][x][0];
texels_layer[y * 64 + x][1] = blender::eevee::lut::btdf_split_sum_ggx[j][y][x][1];
texels_layer[y * 64 + x][0] = blender::eevee::lut::bsdf_ggx[j][y][x][0];
texels_layer[y * 64 + x][1] = blender::eevee::lut::bsdf_ggx[j][y][x][1];
texels_layer[y * 64 + x][2] = 0.0; /* UNUSED */
texels_layer[y * 64 + x][3] = 0.0; /* UNUSED */
}

View File

@ -150,7 +150,7 @@ void closure_Glossy_indirect_end(ClosureInputGlossy cl_in,
#endif
/* Apply Ray-trace reflections after occlusion since they are direct, local reflections. */
#if defined(RESOLVE_PROBE)
/* NO OP - output base radiance*/
/* NO OP - output base radiance. */
#elif defined(RESOLVE_SSR)
/* Output only ray-trace radiance. */
cl_out.radiance = cl_eval.raytrace_radiance;

View File

@ -93,7 +93,7 @@ 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, float d);
vec2 bsdf_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);

View File

@ -25,7 +25,7 @@ uniform sampler2DArray utilTex;
#define NOISE_LAYER 2
#define LTC_DISK_LAYER 3 /* UNUSED */
/* Layers 4 to 20 are for BTDF Lut. */
/* Layers 4 to 20 are for BTDF LUT. */
#define lut_btdf_layer_first 4.0
#define lut_btdf_layer_count 16.0
@ -51,8 +51,23 @@ vec2 brdf_lut(float cos_theta, float roughness)
return textureLod(utilTex, vec3(lut_coords(cos_theta, roughness), BRDF_LUT_LAYER), 0.0).rg;
}
/* Return texture coordinates to sample Surface LUT. */
vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
vec4 sample_3D_texture(sampler2DArray tex, vec3 coords)
{
float layer_floored;
float interp = modf(coords.z, layer_floored);
coords.z = layer_floored;
vec4 tex_low = textureLod(tex, coords, 0.0);
coords.z += 1.0;
vec4 tex_high = textureLod(tex, coords, 0.0);
/* Manual trilinear interpolation. */
return mix(tex_low, tex_high, interp);
}
/* Return texture coordinates to sample BSDF LUT. */
vec3 lut_coords_bsdf(float cos_theta, float roughness, float ior)
{
/* ior is sin of critical angle. */
float critical_cos = sqrt(1.0 - ior * ior);
@ -69,15 +84,16 @@ vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
/* scale and bias coordinates, for correct filtered lookup */
coords.xy = coords.xy * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
coords.z = coords.z * lut_btdf_layer_count + lut_btdf_layer_first;
return coords;
}
/* Returns GGX BTDF in first component and fresnel in second. */
vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
/* Returns GGX transmittance in first component and reflectance in second. */
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
if (ior <= 1e-5) {
return vec2(0.0);
return vec2(0.0, 1.0);
}
if (ior >= 1.0) {
@ -95,19 +111,7 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
}
vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
float layer = coords.z * lut_btdf_layer_count;
float layer_floored = floor(layer);
coords.z = lut_btdf_layer_first + layer_floored;
vec2 btdf_brdf_low = textureLod(utilTex, coords, 0.0).rg;
coords.z += 1.0;
vec2 btdf_brdf_high = textureLod(utilTex, coords, 0.0).rg;
/* Manual trilinear interpolation. */
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
vec2 btdf_brdf = sample_3D_texture(utilTex, lut_coords_bsdf(cos_theta, roughness, ior)).rg;
if (do_multiscatter != 0.0) {
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming

View File

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

View File

@ -163,9 +163,9 @@ class IrradianceBake {
LightProbeGridCacheFrame *read_result_packed();
private:
/** Read surfel data back to CPU into \a cache_frame . */
/** Read surfel data back to CPU into \a cache_frame. */
void read_surfels(LightProbeGridCacheFrame *cache_frame);
/** Read virtual offset back to CPU into \a cache_frame . */
/** Read virtual offset back to CPU into \a cache_frame. */
void read_virtual_offset(LightProbeGridCacheFrame *cache_frame);
};

View File

@ -4144,7 +4144,7 @@ const float ltc_disk_integral[64][64][1] = {
{0.888889f}, {0.904762f}, {0.920635f}, {0.936508f}, {0.952381f}, {0.968254f}, {0.984127f},
{1.000000f}}};
const float bsdf_split_sum_ggx[64][64][2] = {
const float brdf_ggx[64][64][2] = {
{{1.000000f, 0.000000f}, {1.000000f, 0.000000f}, {1.000000f, 0.000000f},
{0.999996f, 0.000000f}, {0.999985f, 0.000000f}, {0.999962f, 0.000000f},
{0.999919f, 0.000000f}, {0.999847f, 0.000000f}, {0.999736f, 0.000000f},
@ -5554,7 +5554,7 @@ const float bsdf_split_sum_ggx[64][64][2] = {
{0.626607f, 0.023551f}, {0.615875f, 0.022188f}, {0.604963f, 0.020914f},
{0.593906f, 0.019723f}}};
const float btdf_split_sum_ggx[16][64][64][2] = {
const float bsdf_ggx[16][64][64][2] = {
{{{0.000000f, 1.000000f}, {0.000000f, 1.000000f}, {0.000000f, 1.000000f},
{0.000000f, 1.000000f}, {0.000000f, 1.000000f}, {0.000000f, 1.000000f},
{0.000000f, 1.000000f}, {0.000000f, 1.000000f}, {0.000000f, 1.000000f},

View File

@ -19,9 +19,9 @@ extern const float ltc_mag_ggx[64][64][2];
/* Precomputed Disk integral for different elevation angles and solid angle. */
extern const float ltc_disk_integral[64][64][1];
/* Precomputed integrated split fresnel term of the GGX BRDF. */
extern const float bsdf_split_sum_ggx[64][64][2];
/* Precomputed reflectance and transmission of glass material. */
extern const float btdf_split_sum_ggx[16][64][64][2];
extern const float brdf_ggx[64][64][2];
/* Precomputed reflectance and transmittance of glass material with IOR < 1. */
extern const float bsdf_ggx[16][64][64][2];
/* 4 different blue noise, one per channel. */
extern const float blue_noise[64][64][4];

View File

@ -683,7 +683,7 @@ void DeferredProbeLayer::begin_sync()
gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK);
}
/* Light eval resources.*/
/* Light evaluate resources. */
{
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
dummy_light_tx_.ensure_2d(GPU_RGBA16F, int2(1), usage);
@ -827,7 +827,7 @@ void CapturePipeline::sync()
surface_ps_.bind_ssbo(CAPTURE_BUF_SLOT, &inst_.irradiance_cache.bake.capture_info_buf_);
surface_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx);
/* TODO(fclem): Remove. Binded to get the camera data,
/* TODO(fclem): Remove. Bind to get the camera data,
* but there should be no view dependent behavior during capture. */
inst_.bind_uniform_data(&surface_ps_);
}

View File

@ -391,8 +391,8 @@ class UtilityTexture : public Texture {
Layer &layer = data[UTIL_LTC_MAG_LAYER];
for (auto x : IndexRange(lut_size)) {
for (auto y : IndexRange(lut_size)) {
layer.data[y][x][0] = lut::bsdf_split_sum_ggx[y][x][0];
layer.data[y][x][1] = lut::bsdf_split_sum_ggx[y][x][1];
layer.data[y][x][0] = lut::brdf_ggx[y][x][0];
layer.data[y][x][1] = lut::brdf_ggx[y][x][1];
layer.data[y][x][2] = lut::ltc_mag_ggx[y][x][0];
layer.data[y][x][3] = lut::ltc_mag_ggx[y][x][1];
}
@ -412,8 +412,8 @@ class UtilityTexture : public Texture {
Layer &layer = data[UTIL_BTDF_LAYER + layer_id];
for (auto x : IndexRange(lut_size)) {
for (auto y : IndexRange(lut_size)) {
layer.data[y][x][0] = lut::btdf_split_sum_ggx[layer_id][y][x][0];
layer.data[y][x][1] = lut::btdf_split_sum_ggx[layer_id][y][x][1];
layer.data[y][x][0] = lut::bsdf_ggx[layer_id][y][x][0];
layer.data[y][x][1] = lut::bsdf_ggx[layer_id][y][x][1];
}
}
}

View File

@ -88,7 +88,7 @@ enum eDebugMode : uint32_t {
enum PrecomputeType : uint32_t {
LUT_GGX_BRDF_SPLIT_SUM = 0u,
LUT_GGX_BTDF_SPLIT_SUM = 1u,
LUT_GGX_BSDF_SPLIT_SUM = 1u,
};
/** \} */
@ -1316,6 +1316,23 @@ float4 utility_tx_sample_lut(sampler2DArray util_tx, float2 uv, float layer)
return textureLod(util_tx, float3(uv, layer), 0.0);
}
/* Sample GGX BSDF LUT. */
float4 utility_tx_sample_bsdf_lut(sampler2DArray util_tx, float2 uv, float layer)
{
/* Scale and bias coordinates, for correct filtered lookup. */
uv = uv * UTIL_TEX_UV_SCALE + UTIL_TEX_UV_BIAS;
layer = layer * UTIL_BTDF_LAYER_COUNT + UTIL_BTDF_LAYER;
float layer_floored;
float interp = modf(layer, layer_floored);
float4 tex_low = textureLod(util_tx, float3(uv, layer_floored), 0.0);
float4 tex_high = textureLod(util_tx, float3(uv, layer_floored + 1.0), 0.0);
/* Manual trilinear interpolation. */
return mix(tex_low, tex_high, interp);
}
/* Sample LTC or BSDF LUTs with `cos_theta` and `roughness` as inputs. */
float4 utility_tx_sample_lut(sampler2DArray util_tx, float cos_theta, float roughness, float layer)
{

View File

@ -29,8 +29,6 @@ void SubsurfaceModule::end_sync()
data_.sample_len = 55;
}
precompute_samples_location();
subsurface_ps_.init();
subsurface_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL |
DRW_STATE_BLEND_ADD_FULL);
@ -51,6 +49,8 @@ void SubsurfaceModule::end_sync()
void SubsurfaceModule::render(View &view, Framebuffer &fb, Texture &diffuse_light_tx)
{
precompute_samples_location();
fb.bind();
diffuse_light_tx_ = *&diffuse_light_tx;
inst_.manager->submit(subsurface_ps_, view);
@ -74,6 +74,8 @@ void SubsurfaceModule::precompute_samples_location()
data_.samples[i].y = sinf(theta) * r;
data_.samples[i].z = 1.0f / burley_pdf(d, r);
}
inst_.push_uniform_data();
}
const Vector<float> &SubsurfaceModule::transmittance_profile()

View File

@ -121,8 +121,8 @@ bool VelocityModule::step_object_sync(Object *ob,
ObjectKey &object_key,
ResourceHandle resource_handle,
int /*IDRecalcFlag*/ recalc,
ModifierData *modifier_data /*= nullptr*/,
ParticleSystem *particle_sys /*= nullptr*/)
ModifierData *modifier_data /*=nullptr*/,
ParticleSystem *particle_sys /*=nullptr*/)
{
bool has_motion = object_has_velocity(ob) || (recalc & ID_RECALC_TRANSFORM);
/* NOTE: Fragile. This will only work with 1 frame of lag since we can't record every geometry

View File

@ -155,7 +155,7 @@ void VolumeModule::begin_sync()
void VolumeModule::sync_object(Object *ob,
ObjectHandle & /*ob_handle*/,
ResourceHandle res_handle,
MaterialPass *material_pass /*= nullptr*/)
MaterialPass *material_pass /*=nullptr*/)
{
float3 size = math::to_scale(float4x4(ob->object_to_world));
/* Check if any of the axes have 0 length. (see #69070) */

View File

@ -283,7 +283,7 @@ DofSample dof_amend_history(DofNeighborhoodMinMax bbox, DofSample history, DofSa
/* More responsive. */
history.color = clamp(history.color, bbox.min.color, bbox.max.color);
#endif
/* Clamp CoC to reduce convergence time. Otherwise the result is laggy. */
/* Clamp CoC to reduce convergence time. Otherwise the result lags. */
history.coc = clamp(history.coc, bbox.min.coc, bbox.max.coc);
return history;

View File

@ -55,7 +55,7 @@ vec4 ggx_brdf_split_sum(vec3 lut_coord)
}
/* Generate BSDF LUT for `IOR < 1`. Returns the transmittance and the reflectance. */
vec4 ggx_btdf_split_sum(vec3 lut_coord)
vec4 ggx_bsdf_split_sum(vec3 lut_coord)
{
float ior = sqrt(lut_coord.x);
/* ior is sin of critical angle. */
@ -99,7 +99,7 @@ vec4 ggx_btdf_split_sum(vec3 lut_coord)
}
/* Refraction. */
vec3 T = refract(-V, H, ior);
vec3 T = refract(-V, H, 1.0 / ior);
float NT = T.z;
/* In the case of TIR, `T == vec3(0)`. */
if (NT < 0.0) {
@ -125,8 +125,8 @@ void main()
case LUT_GGX_BRDF_SPLIT_SUM:
result = ggx_brdf_split_sum(lut_normalized_coordinate);
break;
case LUT_GGX_BTDF_SPLIT_SUM:
result = ggx_btdf_split_sum(lut_normalized_coordinate);
case LUT_GGX_BSDF_SPLIT_SUM:
result = ggx_bsdf_split_sum(lut_normalized_coordinate);
break;
}
imageStore(table_img, ivec3(gl_GlobalInvocationID), result);

View File

@ -297,10 +297,27 @@ vec2 brdf_lut(float cos_theta, float roughness)
#endif
}
vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
/* Return texture coordinates to sample BSDF LUT. */
vec3 lut_coords_bsdf(float cos_theta, float roughness, float ior)
{
/* IOR is the sine of the critical angle. */
float critical_cos = sqrt(1.0 - ior * ior);
vec3 coords;
coords.x = sqr(ior);
coords.y = cos_theta;
coords.y -= critical_cos;
coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
coords.y = coords.y * 0.5 + 0.5;
coords.z = roughness;
return saturate(coords);
}
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
if (ior <= 1e-5) {
return vec2(0.0);
return vec2(0.0, 1.0);
}
if (ior >= 1.0) {
@ -318,28 +335,9 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
}
/* IOR is sin of critical angle. */
float critical_cos = sqrt(1.0 - ior * ior);
vec3 coords;
coords.x = sqr(ior);
coords.y = cos_theta;
coords.y -= critical_cos;
coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
coords.y = coords.y * 0.5 + 0.5;
coords.z = roughness;
coords = saturate(coords);
float layer = coords.z * UTIL_BTDF_LAYER_COUNT;
float layer_floored = floor(layer);
#ifdef EEVEE_UTILITY_TX
coords.z = UTIL_BTDF_LAYER + layer_floored;
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_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
vec3 coords = lut_coords_bsdf(cos_theta, roughness, ior);
vec2 btdf_brdf = utility_tx_sample_bsdf_lut(utility_tx, coords.xy, coords.z).rg;
if (do_multiscatter != 0.0) {
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming

View File

@ -45,7 +45,7 @@ vec2 octahedral_uv_to_layer_texture_coords(vec2 octahedral_uv,
ReflectionProbeData probe_data,
vec2 texel_size)
{
/* Fix artifacts near edges. Proved one texel on each side.*/
/* Fix artifacts near edges. Proved one texel on each side. */
octahedral_uv = octahedral_uv * (1.0 - 2.0 * REFLECTION_PROBE_BORDER_SIZE * texel_size) +
REFLECTION_PROBE_BORDER_SIZE * texel_size + 0.5 * texel_size;

View File

@ -70,8 +70,8 @@ vec4 reflection_probe_eval(ClosureReflection reflection,
/* Clamped brightness. */
/* For artistic freedom this should be read from the scene/reflection probe.
* Note: EEVEE-legacy read the firefly_factor from gi_glossy_clamp.
* Note: Firefly removal should be moved to a different shader and also take SSR into
* account.*/
* Note: Firefly removal should be moved to a different shader and also take SSR into account.
*/
float luma = max(1e-8, max_v3(l_col));
const float firefly_factor = 1e16;
l_col.rgb *= 1.0 - max(0.0, luma - firefly_factor) / luma;

View File

@ -197,8 +197,8 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_data)
.uniform_buf(IRRADIANCE_GRID_BUF_SLOT,
"IrradianceGridData",
"grids_infos_buf[IRRADIANCE_GRID_MAX]")
/* NOTE: Use uint instead of IrradianceBrickPacked because Metal needs to know the exact
* type.*/
/* NOTE: Use uint instead of IrradianceBrickPacked because Metal needs to know the exact type.
*/
.storage_buf(IRRADIANCE_BRICK_BUF_SLOT, Qualifier::READ, "uint", "bricks_infos_buf[]")
.sampler(IRRADIANCE_ATLAS_TEX_SLOT, ImageType::FLOAT_3D, "irradiance_atlas_tx");

View File

@ -97,7 +97,7 @@ class ShaderModule {
using ShaderPtr = std::unique_ptr<GPUShader, ShaderDeleter>;
/** Shared shader module across all engine instances. */
static ShaderModule *g_shader_modules[2 /*Selection Instance*/][2 /*Clipping Enabled*/];
static ShaderModule *g_shader_modules[2 /* Selection Instance. */][2 /* Clipping Enabled. */];
const SelectionType selection_type_;
/** TODO: Support clipping. This global state should be set by the overlay::Instance and switch

View File

@ -169,26 +169,26 @@ void main()
output_vert(vec2(0.0), inner_color, world_pos[1], ndc_pos[1]);
break;
}
/* Bottom outline left point*/
/* Bottom outline left point. */
case 14:
case 15:
case 18: {
output_vert(-offset, outer_color, world_pos[0], ndc_pos[0]);
break;
}
/* Bottom outline right point*/
/* Bottom outline right point. */
case 17:
case 19:
case 22: {
output_vert(-offset, outer_color, world_pos[1], ndc_pos[1]);
break;
}
/* Bottom transparent border left*/
/* Bottom transparent border left. */
case 20:
case 21: {
output_vert(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0), world_pos[0], ndc_pos[0]);
}
/* Bottom transparent border right*/
/* Bottom transparent border right. */
case 23: {
output_vert(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0), world_pos[1], ndc_pos[1]);
}

View File

@ -15,7 +15,7 @@ GPU_SHADER_INTERFACE_INFO(workbench_shadow_iface, "vData")
.smooth(Type::VEC4, "frontPosition")
.smooth(Type::VEC4, "backPosition");
GPU_SHADER_INTERFACE_INFO(workbench_shadow_flat_iface, "vData_flat")
.flat(Type::VEC3, "light_direction_os"); /*Workbench Next*/
.flat(Type::VEC3, "light_direction_os"); /* Workbench Next. */
/* `workbench_shadow_vert.glsl` only used by geometry shader path.
* Vertex output iface not needed by non-geometry shader variants,

View File

@ -107,7 +107,7 @@ class Instance {
case V3D_SHADING_TEXTURE_COLOR:
ATTR_FALLTHROUGH;
case V3D_SHADING_MATERIAL_COLOR:
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot)) {
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot + 1)) {
return Material(*_mat);
}
ATTR_FALLTHROUGH;
@ -271,8 +271,7 @@ class Instance {
continue;
}
/* Material slots start from 1. */
int material_slot = i + 1;
int material_slot = i;
Material mat = get_material(ob_ref, object_state.color_type, material_slot);
has_transparent_material = has_transparent_material || mat.is_transparent();
@ -324,11 +323,16 @@ class Instance {
void sculpt_sync(ObjectRef &ob_ref, ResourceHandle handle, const ObjectState &object_state)
{
SculptBatchFeature features = SCULPT_BATCH_DEFAULT;
if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) {
features = SCULPT_BATCH_VERTEX_COLOR;
}
else if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
features = SCULPT_BATCH_UV;
}
if (object_state.use_per_material_batches) {
const int material_count = DRW_cache_object_material_count_get(ob_ref.object);
for (SculptBatch &batch : sculpt_batches_per_material_get(
ob_ref.object, {get_dummy_gpu_materials(material_count), material_count}))
{
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, true, features)) {
Material mat = get_material(ob_ref, object_state.color_type, batch.material_slot);
if (SCULPT_DEBUG_DRAW) {
mat.base_color = batch.debug_color();
@ -346,15 +350,7 @@ class Instance {
}
else {
Material mat = get_material(ob_ref, object_state.color_type);
SculptBatchFeature features = SCULPT_BATCH_DEFAULT;
if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) {
features = SCULPT_BATCH_VERTEX_COLOR;
}
else if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
features = SCULPT_BATCH_UV;
}
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, features)) {
for (SculptBatch &batch : sculpt_batches_get(ob_ref.object, false, features)) {
if (SCULPT_DEBUG_DRAW) {
mat.base_color = batch.debug_color();
}
@ -395,12 +391,12 @@ class Instance {
/* Skip frustum culling. */
ResourceHandle handle = manager.resource_handle(float4x4(ob_ref.object->object_to_world));
Material mat = get_material(ob_ref, object_state.color_type, psys->part->omat);
Material mat = get_material(ob_ref, object_state.color_type, psys->part->omat - 1);
::Image *image = nullptr;
ImageUser *iuser = nullptr;
GPUSamplerState sampler_state = GPUSamplerState::default_sampler();
if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
get_material_image(ob_ref.object, psys->part->omat, image, iuser, sampler_state);
get_material_image(ob_ref.object, psys->part->omat - 1, image, iuser, sampler_state);
}
resources.material_buf.append(mat);
int material_index = resources.material_buf.size() - 1;

View File

@ -68,7 +68,7 @@ void get_material_image(Object *ob,
{
const ::bNode *node = nullptr;
ED_object_get_active_image(ob, material_slot, &image, &iuser, &node, nullptr);
ED_object_get_active_image(ob, material_slot + 1, &image, &iuser, &node, nullptr);
if (node && image) {
switch (node->type) {
case SH_NODE_TEX_IMAGE: {

View File

@ -107,7 +107,6 @@ struct SceneState {
struct ObjectState {
eV3DShadingColorType color_type = V3D_SHADING_SINGLE_COLOR;
bool sculpt_pbvh = false;
bool texture_paint_mode = false;
::Image *image_paint_override = nullptr;
GPUSamplerState override_sampler_state = GPUSamplerState::default_sampler();
bool draw_shadow = false;

View File

@ -305,12 +305,12 @@ ShadowPass::~ShadowPass()
}
}
PassMain::Sub *&ShadowPass::get_pass_ptr(PassType type, bool manifold, bool cap /*= false*/)
PassMain::Sub *&ShadowPass::get_pass_ptr(PassType type, bool manifold, bool cap /*=false*/)
{
return passes_[type][manifold][cap];
}
GPUShader *ShadowPass::get_shader(bool depth_pass, bool manifold, bool cap /*= false*/)
GPUShader *ShadowPass::get_shader(bool depth_pass, bool manifold, bool cap /*=false*/)
{
GPUShader *&shader = shaders_[depth_pass][manifold][cap];

View File

@ -20,7 +20,7 @@
namespace blender::workbench {
void SceneState::init(Object *camera_ob /*= nullptr*/)
void SceneState::init(Object *camera_ob /*=nullptr*/)
{
bool reset_taa = reset_taa_next_sample;
reset_taa_next_sample = false;
@ -83,7 +83,7 @@ void SceneState::init(Object *camera_ob /*= nullptr*/)
}
xray_mode = shading.xray_alpha != 1.0f;
if (SHADING_XRAY_FLAG_ENABLED(shading)) {
if (xray_mode) {
/* Disable shading options that aren't supported in transparency mode. */
shading.flag &= ~(V3D_SHADING_SHADOW | V3D_SHADING_CAVITY | V3D_SHADING_DEPTH_OF_FIELD);
}
@ -197,32 +197,42 @@ static const CustomData *get_vert_custom_data(const Mesh *mesh)
ObjectState::ObjectState(const SceneState &scene_state, Object *ob)
{
sculpt_pbvh = false;
texture_paint_mode = false;
image_paint_override = nullptr;
override_sampler_state = GPUSamplerState::default_sampler();
draw_shadow = false;
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool is_active = (ob == draw_ctx->obact);
/* TODO(@pragma37): Is the double check needed?
* If it is, wouldn't be needed for sculpt_pbvh too? */
const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == nullptr);
color_type = (eV3DShadingColorType)scene_state.shading.color_type;
if (!(is_active && DRW_object_use_hide_faces(ob))) {
draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && scene_state.draw_shadows;
}
image_paint_override = nullptr;
override_sampler_state = GPUSamplerState::default_sampler();
sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->rv3d) &&
!DRW_state_is_image_render();
draw_shadow = scene_state.draw_shadows && (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 &&
!is_active && !sculpt_pbvh && !DRW_object_use_hide_faces(ob);
color_type = (eV3DShadingColorType)scene_state.shading.color_type;
bool has_color = false;
bool has_uv = false;
if (ob->type == OB_MESH) {
const Mesh *me = static_cast<Mesh *>(ob->data);
const CustomData *cd_vdata = get_vert_custom_data(me);
const CustomData *cd_ldata = get_loop_custom_data(me);
has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
has_uv = CustomData_has_layer(cd_ldata, CD_PROP_FLOAT2);
}
if (color_type == V3D_SHADING_TEXTURE_COLOR && (!has_uv || ob->dt < OB_TEXTURE)) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
else if (color_type == V3D_SHADING_VERTEX_COLOR && !has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
if (sculpt_pbvh) {
/* Shadows are unsupported in sculpt mode. We could revert to the slow
* method in this case but I'm not sure if it's a good idea given that
* sculpted meshes are heavy to begin with. */
draw_shadow = false;
if (color_type == V3D_SHADING_TEXTURE_COLOR && BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
/* Force use of material color for sculpt. */
color_type = V3D_SHADING_MATERIAL_COLOR;
@ -236,59 +246,25 @@ ObjectState::ObjectState(const SceneState &scene_state, Object *ob)
C, &scene_state.scene->toolsettings->paint_mode, ob, color_type);
}
}
else if (ob->type == OB_MESH) {
const Mesh *me = static_cast<Mesh *>(ob->data);
const CustomData *cd_vdata = get_vert_custom_data(me);
const CustomData *cd_ldata = get_loop_custom_data(me);
bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_COLOR) ||
CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR));
bool has_uv = CustomData_has_layer(cd_ldata, CD_PROP_FLOAT2);
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
if (ob->dt < OB_TEXTURE || !has_uv) {
color_type = V3D_SHADING_MATERIAL_COLOR;
else if (ob->type == OB_MESH && !DRW_state_is_scene_render()) {
/* Force texture or vertex mode if object is in paint mode. */
const bool is_vertpaint_mode = is_active && (scene_state.object_mode == CTX_MODE_PAINT_VERTEX);
const bool is_texpaint_mode = is_active && (scene_state.object_mode == CTX_MODE_PAINT_TEXTURE);
if (is_vertpaint_mode && has_color) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
else if (is_texpaint_mode && has_uv) {
color_type = V3D_SHADING_TEXTURE_COLOR;
const ImagePaintSettings *imapaint = &scene_state.scene->toolsettings->imapaint;
if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
image_paint_override = imapaint->canvas;
override_sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
override_sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
const bool use_linear_filter = imapaint->interp == IMAGEPAINT_INTERP_LINEAR;
override_sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR,
use_linear_filter);
}
}
else if (color_type == V3D_SHADING_VERTEX_COLOR && !has_color) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
if (!is_render) {
/* Force texture or vertex mode if object is in paint mode. */
const bool is_vertpaint_mode = is_active &&
(scene_state.object_mode == CTX_MODE_PAINT_VERTEX);
const bool is_texpaint_mode = is_active &&
(scene_state.object_mode == CTX_MODE_PAINT_TEXTURE);
if (is_vertpaint_mode && has_color) {
color_type = V3D_SHADING_VERTEX_COLOR;
}
else if (is_texpaint_mode && has_uv) {
color_type = V3D_SHADING_TEXTURE_COLOR;
texture_paint_mode = true;
const ImagePaintSettings *imapaint = &scene_state.scene->toolsettings->imapaint;
if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
image_paint_override = imapaint->canvas;
override_sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
override_sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
const bool use_linear_filter = imapaint->interp == IMAGEPAINT_INTERP_LINEAR;
override_sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR,
use_linear_filter);
}
}
}
}
else {
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
else if (color_type == V3D_SHADING_VERTEX_COLOR) {
color_type = V3D_SHADING_OBJECT_COLOR;
}
}
use_per_material_batches = image_paint_override == nullptr && ELEM(color_type,

View File

@ -247,8 +247,7 @@ static void grease_pencil_geom_batch_ensure(GreasePencil &grease_pencil, int cfr
total_points_num += curves.points_num();
/* One vertex is stored before and after as padding. Cyclic strokes have one extra
* vertex.*/
/* One vertex is stored before and after as padding. Cyclic strokes have one extra vertex. */
total_verts_num += curves.points_num() + num_cyclic + curves.curves_num() * 2;
total_triangles_num += (curves.points_num() + num_cyclic) * 2;
total_triangles_num += drawing->triangles().size();

View File

@ -152,7 +152,7 @@ static Vector<SculptBatch> sculpt_batches_get_ex(
return data.batches;
}
Vector<SculptBatch> sculpt_batches_get(Object *ob, SculptBatchFeature features)
Vector<SculptBatch> sculpt_batches_get(Object *ob, bool per_material, SculptBatchFeature features)
{
PBVHAttrReq attrs[16] = {};
int attrs_len = 0;
@ -193,7 +193,8 @@ Vector<SculptBatch> sculpt_batches_get(Object *ob, SculptBatchFeature features)
}
}
return sculpt_batches_get_ex(ob, features & SCULPT_BATCH_WIREFRAME, false, attrs, attrs_len);
return sculpt_batches_get_ex(
ob, features & SCULPT_BATCH_WIREFRAME, per_material, attrs, attrs_len);
}
Vector<SculptBatch> sculpt_batches_per_material_get(Object *ob,

View File

@ -32,9 +32,9 @@ enum SculptBatchFeature {
ENUM_OPERATORS(SculptBatchFeature, SCULPT_BATCH_UV);
/** Used by engines that don't use GPUMaterials, like the Workbench and Overlay engines. */
Vector<SculptBatch> sculpt_batches_get(Object *ob, SculptBatchFeature features);
Vector<SculptBatch> sculpt_batches_get(Object *ob, bool per_material, SculptBatchFeature features);
/** Used by EEVEE and Workbench Material/Texture modes. */
/** Used by EEVEE. */
Vector<SculptBatch> sculpt_batches_per_material_get(Object *ob,
MutableSpan<GPUMaterial *> materials);

View File

@ -294,7 +294,7 @@ float get_homogenous_z_offset(float vs_z, float hs_w, float vs_offset)
#define DRW_BASE_FROM_SET (1 << 3)
#define DRW_BASE_ACTIVE (1 << 4)
/* Wire Color Types, matching eV3DShadingColorType.*/
/* Wire Color Types, matching eV3DShadingColorType. */
#define V3D_SHADING_SINGLE_COLOR 2
#define V3D_SHADING_OBJECT_COLOR 4
#define V3D_SHADING_RANDOM_COLOR 1

View File

@ -1448,14 +1448,14 @@ static void test_eevee_lut_gen()
Manager manager;
/* Check if LUT generation matches the header version. */
auto bsdf_ggx_gen = Precompute(manager, LUT_GGX_BRDF_SPLIT_SUM, {64, 64, 1}).data<float2>();
auto btdf_ggx_gen = Precompute(manager, LUT_GGX_BTDF_SPLIT_SUM, {64, 64, 16}).data<float2>();
auto brdf_ggx_gen = Precompute(manager, LUT_GGX_BRDF_SPLIT_SUM, {64, 64, 1}).data<float2>();
auto bsdf_ggx_gen = Precompute(manager, LUT_GGX_BSDF_SPLIT_SUM, {64, 64, 16}).data<float2>();
Span<float2> bsdf_ggx_lut((const float2 *)&eevee::lut::bsdf_split_sum_ggx, 64 * 64);
Span<float2> btdf_ggx_lut((const float2 *)&eevee::lut::btdf_split_sum_ggx, 64 * 64 * 16);
Span<float2> brdf_ggx_lut((const float2 *)&eevee::lut::brdf_ggx, 64 * 64);
Span<float2> bsdf_ggx_lut((const float2 *)&eevee::lut::bsdf_ggx, 64 * 64 * 16);
EXPECT_NEAR_ARRAY_ND(brdf_ggx_lut.data(), brdf_ggx_gen.data(), brdf_ggx_gen.size(), 2, 1e-4f);
EXPECT_NEAR_ARRAY_ND(bsdf_ggx_lut.data(), bsdf_ggx_gen.data(), bsdf_ggx_gen.size(), 2, 1e-4f);
EXPECT_NEAR_ARRAY_ND(btdf_ggx_lut.data(), btdf_ggx_gen.data(), btdf_ggx_gen.size(), 2, 1e-4f);
GPU_render_end();
}

View File

@ -5374,6 +5374,22 @@ static void draw_setting_widget(bAnimContext *ac,
UI_but_disable(but, TIP_("Can't edit this property from a linked data-block"));
}
}
/* Post-button-creation modifications of the button. */
switch (setting) {
case ACHANNEL_SETTING_MOD_OFF:
/* Deactivate the button when there are no FCurve modifiers. */
if (ale->datatype == ALE_FCURVE) {
const FCurve *fcu = static_cast<const FCurve *>(ale->key_data);
if (BLI_listbase_is_empty(&fcu->modifiers)) {
UI_but_flag_enable(but, UI_BUT_INACTIVE);
}
}
break;
default:
break;
}
}
static void draw_grease_pencil_layer_widgets(bAnimListElem *ale,

View File

@ -4370,7 +4370,7 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
{
/* TODO: check on a poll callback for this, to get hotkeys into menus. */
WM_keymap_ensure(keyconf, "Animation Channels", 0, 0);
WM_keymap_ensure(keyconf, "Animation Channels", SPACE_EMPTY, RGN_TYPE_WINDOW);
}
/** \} */

View File

@ -138,7 +138,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
switch (saction->mode) {
case SACTCONT_ACTION: /* 'Action Editor' */
/* if not pinned, sync with active object */
if (/*saction->pin == 0*/ true) {
if (/* `saction->pin == 0` */ true) {
if (ac->obact && ac->obact->adt) {
saction->action = ac->obact->adt->action;
}
@ -158,7 +158,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->data = actedit_get_shapekeys(ac);
/* if not pinned, sync with active object */
if (/*saction->pin == 0*/ true) {
if (/* `saction->pin == 0` */ true) {
Key *key = (Key *)ac->data;
if (key && key->adt) {

View File

@ -1907,7 +1907,7 @@ void ED_operatortypes_marker()
void ED_keymap_marker(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Markers", 0, 0);
WM_keymap_ensure(keyconf, "Markers", SPACE_EMPTY, RGN_TYPE_WINDOW);
}
/** \} */

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