WIP: Experiment: Drop import operator helper and file drop type #111242
|
@ -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);
|
||||
}];
|
||||
|
||||
|
|
|
@ -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]])
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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 = (
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -2935,6 +2935,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
|
|||
}
|
||||
}
|
||||
|
||||
ntree->ensure_interface_cache();
|
||||
for (bNodeTreeInterfaceSocket *socket : ntree->interface_inputs()) {
|
||||
build_idproperties(socket->properties);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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_);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue