WIP: Brush assets project #106303
|
@ -761,6 +761,7 @@ endif()
|
|||
# Unit testing
|
||||
option(WITH_GTESTS "Enable GTest unit testing" OFF)
|
||||
option(WITH_GPU_RENDER_TESTS "Enable GPU render related unit testing (EEVEE, Workbench and Grease Pencil)" OFF)
|
||||
option(WITH_GPU_RENDER_TESTS_SILENT "Run GPU render tests silently (finished tests will pass). Generated report will show failing tests" ON)
|
||||
option(WITH_GPU_DRAW_TESTS "Enable GPU drawing related unit testing (GPU backends and draw manager)" OFF)
|
||||
option(WITH_COMPOSITOR_REALTIME_TESTS "Enable regression testing for realtime compositor" OFF)
|
||||
if(UNIX AND NOT (APPLE OR HAIKU))
|
||||
|
|
|
@ -20,6 +20,7 @@ endif()
|
|||
set(WITH_CYCLES_NATIVE_ONLY ON CACHE BOOL "" FORCE)
|
||||
set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_GTESTS ON CACHE BOOL "" FORCE)
|
||||
set(WITH_GPU_RENDER_TESTS_SILENT OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_LIBMV_SCHUR_SPECIALIZATIONS OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_PYTHON_SAFETY ON CACHE BOOL "" FORCE)
|
||||
if(WIN32)
|
||||
|
|
|
@ -18,7 +18,7 @@ if NOT "%1" == "" (
|
|||
) else if "%1" == "with_tests" (
|
||||
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GTESTS=On
|
||||
) else if "%1" == "with_gpu_tests" (
|
||||
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GPU_DRAW_TESTS=On -DWITH_GPU_RENDER_TESTS=On
|
||||
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GPU_DRAW_TESTS=On -DWITH_GPU_RENDER_TESTS=On -DWITH_GPU_RENDER_TESTS_SILENT=Off
|
||||
) else if "%1" == "full" (
|
||||
set TARGET=Full
|
||||
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
|
||||
|
|
|
@ -593,9 +593,8 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
|
|||
/* If motion blur is enabled for the object we also check
|
||||
* whether it's enabled for the parent object as well.
|
||||
*
|
||||
* This way we can control motion blur from the dupligroup
|
||||
* duplicator much easier.
|
||||
*/
|
||||
* This way we can control motion blur from the dupli-group
|
||||
* duplicator much easier. */
|
||||
if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
|
||||
PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
|
||||
use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
|
||||
|
|
|
@ -538,7 +538,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
|||
/* TODO: check if the refraction configuration is valid. See `btdf_ggx()` in
|
||||
* `eevee_bxdf_lib.glsl`. */
|
||||
float3 H = is_transmission ? -(bsdf->ior * wo + wi) : (wi + wo);
|
||||
const float inv_len_H = 1.0f / len(H);
|
||||
const float inv_len_H = safe_divide(1.0f, len(H));
|
||||
H *= inv_len_H;
|
||||
|
||||
/* Compute Fresnel coefficients. */
|
||||
|
|
|
@ -238,10 +238,17 @@ integrate_direct_light_shadow_init_common(KernelGlobals kg,
|
|||
/* Path tracing: sample point on light and evaluate light shader, then
|
||||
* queue shadow ray to be traced. */
|
||||
template<uint node_feature_mask>
|
||||
ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const RNGState *rng_state)
|
||||
#if defined(__KERNEL_GPU__)
|
||||
ccl_device_forceinline
|
||||
#else
|
||||
/* MSVC has very long compilation time (x20) if we force inline this function */
|
||||
ccl_device
|
||||
#endif
|
||||
void
|
||||
integrate_surface_direct_light(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const RNGState *rng_state)
|
||||
{
|
||||
/* Test if there is a light or BSDF that needs direct light. */
|
||||
if (!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL))) {
|
||||
|
|
|
@ -47,11 +47,23 @@ ccl_device_forceinline bool osl_closure_skip(KernelGlobals kg,
|
|||
uint32_t path_flag,
|
||||
int scattering)
|
||||
{
|
||||
/* caustic options */
|
||||
/* Caustic options */
|
||||
if ((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
|
||||
if ((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
|
||||
(!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT)))
|
||||
{
|
||||
const bool has_reflect = (scattering & LABEL_REFLECT);
|
||||
const bool has_transmit = (scattering & LABEL_TRANSMIT);
|
||||
const bool reflect_caustics_disabled = !kernel_data.integrator.caustics_reflective;
|
||||
const bool refract_caustics_disabled = !kernel_data.integrator.caustics_refractive;
|
||||
|
||||
/* Reflective Caustics */
|
||||
if (reflect_caustics_disabled && has_reflect && !has_transmit) {
|
||||
return true;
|
||||
}
|
||||
/* Refractive Caustics*/
|
||||
if (refract_caustics_disabled && has_transmit && !has_reflect) {
|
||||
return true;
|
||||
}
|
||||
/* Glass Caustics */
|
||||
if (reflect_caustics_disabled && refract_caustics_disabled && has_reflect && has_transmit) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +334,12 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup(
|
|||
const bool has_reflection = !is_zero(closure->reflection_tint);
|
||||
const bool has_transmission = !is_zero(closure->transmission_tint);
|
||||
|
||||
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
|
||||
int label = LABEL_GLOSSY | LABEL_REFLECT;
|
||||
if (has_transmission) {
|
||||
label |= LABEL_TRANSMIT;
|
||||
}
|
||||
|
||||
if (osl_closure_skip(kg, sd, path_flag, label)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -271,64 +271,66 @@ ccl_device
|
|||
}
|
||||
|
||||
/* Metallic component */
|
||||
if (reflective_caustics && metallic > CLOSURE_WEIGHT_CUTOFF) {
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), metallic * weight);
|
||||
ccl_private FresnelF82Tint *fresnel =
|
||||
(bsdf != NULL) ?
|
||||
(ccl_private FresnelF82Tint *)closure_alloc_extra(sd, sizeof(FresnelF82Tint)) :
|
||||
NULL;
|
||||
if (metallic > CLOSURE_WEIGHT_CUTOFF) {
|
||||
if (reflective_caustics) {
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), metallic * weight);
|
||||
ccl_private FresnelF82Tint *fresnel =
|
||||
(bsdf != NULL) ?
|
||||
(ccl_private FresnelF82Tint *)closure_alloc_extra(sd, sizeof(FresnelF82Tint)) :
|
||||
NULL;
|
||||
|
||||
if (bsdf && fresnel) {
|
||||
bsdf->N = valid_reflection_N;
|
||||
bsdf->ior = 1.0f;
|
||||
bsdf->T = T;
|
||||
bsdf->alpha_x = alpha_x;
|
||||
bsdf->alpha_y = alpha_y;
|
||||
if (bsdf && fresnel) {
|
||||
bsdf->N = valid_reflection_N;
|
||||
bsdf->ior = 1.0f;
|
||||
bsdf->T = T;
|
||||
bsdf->alpha_x = alpha_x;
|
||||
bsdf->alpha_y = alpha_y;
|
||||
|
||||
fresnel->f0 = rgb_to_spectrum(clamped_base_color);
|
||||
const Spectrum f82 = min(specular_tint, one_spectrum());
|
||||
fresnel->f0 = rgb_to_spectrum(clamped_base_color);
|
||||
const Spectrum f82 = min(specular_tint, one_spectrum());
|
||||
|
||||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
bsdf_microfacet_setup_fresnel_f82_tint(kg, bsdf, sd, fresnel, f82, is_multiggx);
|
||||
|
||||
/* Attenuate other components */
|
||||
weight *= (1.0f - metallic);
|
||||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
|
||||
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
bsdf_microfacet_setup_fresnel_f82_tint(kg, bsdf, sd, fresnel, f82, is_multiggx);
|
||||
}
|
||||
}
|
||||
/* Attenuate other components */
|
||||
weight *= (1.0f - metallic);
|
||||
}
|
||||
|
||||
/* Transmission component */
|
||||
if (glass_caustics && transmission_weight > CLOSURE_WEIGHT_CUTOFF) {
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), transmission_weight * weight);
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelGeneralizedSchlick)) :
|
||||
NULL;
|
||||
if (transmission_weight > CLOSURE_WEIGHT_CUTOFF) {
|
||||
if (glass_caustics) {
|
||||
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
|
||||
sd, sizeof(MicrofacetBsdf), transmission_weight * weight);
|
||||
ccl_private FresnelGeneralizedSchlick *fresnel =
|
||||
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
|
||||
sd, sizeof(FresnelGeneralizedSchlick)) :
|
||||
NULL;
|
||||
|
||||
if (bsdf && fresnel) {
|
||||
bsdf->N = valid_reflection_N;
|
||||
bsdf->T = zero_float3();
|
||||
if (bsdf && fresnel) {
|
||||
bsdf->N = valid_reflection_N;
|
||||
bsdf->T = zero_float3();
|
||||
|
||||
bsdf->alpha_x = bsdf->alpha_y = sqr(roughness);
|
||||
bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / ior : ior;
|
||||
bsdf->alpha_x = bsdf->alpha_y = sqr(roughness);
|
||||
bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / ior : ior;
|
||||
|
||||
fresnel->f0 = make_float3(F0_from_ior(ior)) * specular_tint;
|
||||
fresnel->f90 = one_spectrum();
|
||||
fresnel->exponent = -ior;
|
||||
fresnel->reflection_tint = one_spectrum();
|
||||
fresnel->transmission_tint = sqrt(rgb_to_spectrum(clamped_base_color));
|
||||
fresnel->f0 = make_float3(F0_from_ior(ior)) * specular_tint;
|
||||
fresnel->f90 = one_spectrum();
|
||||
fresnel->exponent = -ior;
|
||||
fresnel->reflection_tint = one_spectrum();
|
||||
fresnel->transmission_tint = sqrt(rgb_to_spectrum(clamped_base_color));
|
||||
|
||||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
|
||||
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, is_multiggx);
|
||||
|
||||
/* Attenuate other components */
|
||||
weight *= (1.0f - transmission_weight);
|
||||
/* setup bsdf */
|
||||
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
|
||||
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, is_multiggx);
|
||||
}
|
||||
}
|
||||
/* Attenuate other components */
|
||||
weight *= (1.0f - transmission_weight);
|
||||
}
|
||||
|
||||
/* Apply IOR adjustment */
|
||||
|
|
|
@ -8,8 +8,14 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
/* IES Light */
|
||||
|
||||
ccl_device_inline float interpolate_ies_vertical(
|
||||
KernelGlobals kg, int ofs, int v, int v_num, float v_frac, int h)
|
||||
ccl_device_inline float interpolate_ies_vertical(KernelGlobals kg,
|
||||
int ofs,
|
||||
const bool wrap_vlow,
|
||||
const bool wrap_vhigh,
|
||||
int v,
|
||||
int v_num,
|
||||
float v_frac,
|
||||
int h)
|
||||
{
|
||||
/* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
|
||||
* of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
|
||||
|
@ -19,11 +25,22 @@ ccl_device_inline float interpolate_ies_vertical(
|
|||
* we can just take the corresponding value at the current horizontal coordinate. */
|
||||
|
||||
#define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v))
|
||||
/* If v is zero, assume symmetry and read at v=1 instead of v=-1. */
|
||||
float a = IES_LOOKUP((v == 0) ? 1 : v - 1);
|
||||
float a = 0.0f;
|
||||
if (v > 0) {
|
||||
a = IES_LOOKUP(v - 1);
|
||||
}
|
||||
else if (wrap_vlow) {
|
||||
a = IES_LOOKUP(1);
|
||||
}
|
||||
float b = IES_LOOKUP(v);
|
||||
float c = IES_LOOKUP(v + 1);
|
||||
float d = IES_LOOKUP(min(v + 2, v_num - 1));
|
||||
float d = 0.0f;
|
||||
if (v + 2 < v_num) {
|
||||
d = IES_LOOKUP(v + 2);
|
||||
}
|
||||
else if (wrap_vhigh) {
|
||||
d = IES_LOOKUP(v_num - 2);
|
||||
}
|
||||
#undef IES_LOOKUP
|
||||
|
||||
return cubic_interp(a, b, c, d, v_frac);
|
||||
|
@ -44,12 +61,21 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_an
|
|||
#define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v))
|
||||
|
||||
/* Check whether the angle is within the bounds of the IES texture. */
|
||||
if (v_angle < IES_LOOKUP_ANGLE_V(0) || v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
|
||||
const float v_low = IES_LOOKUP_ANGLE_V(0), v_high = IES_LOOKUP_ANGLE_V(v_num - 1);
|
||||
const float h_low = IES_LOOKUP_ANGLE_H(0), h_high = IES_LOOKUP_ANGLE_H(h_num - 1);
|
||||
if (v_angle < v_low || v_angle >= v_high) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (h_angle < h_low || h_angle >= h_high) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0));
|
||||
kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1));
|
||||
/* If the texture covers the full 360° range horizontally, wrap around the lookup
|
||||
* to get proper cubic interpolation. Otherwise, just set the out-of-range values to zero.
|
||||
* Similar logic for V, but there we check the lower and upper wrap separately. */
|
||||
const bool wrap_h = (h_low < 1e-7f && h_high > M_2PI_F - 1e-7f);
|
||||
const bool wrap_vlow = (v_low < 1e-7f);
|
||||
const bool wrap_vhigh = (v_high > M_PI_F - 1e-7f);
|
||||
|
||||
/* Lookup the angles to find the table position. */
|
||||
int h_i, v_i;
|
||||
|
@ -71,17 +97,24 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_an
|
|||
/* Skip forward to the actual intensity data. */
|
||||
ofs += h_num + v_num;
|
||||
|
||||
/* Perform cubic interpolation along the horizontal coordinate to get the intensity value.
|
||||
* If h_i is zero, just wrap around since the horizontal angles always go over the full circle.
|
||||
* However, the last entry (360°) equals the first one, so we need to wrap around to the one
|
||||
* before that. */
|
||||
float a = interpolate_ies_vertical(
|
||||
kg, ofs, v_i, v_num, v_frac, (h_i == 0) ? h_num - 2 : h_i - 1);
|
||||
float b = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i);
|
||||
float c = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i + 1);
|
||||
/* Same logic here, wrap around to the second element if necessary. */
|
||||
float d = interpolate_ies_vertical(
|
||||
kg, ofs, v_i, v_num, v_frac, (h_i + 2 == h_num) ? 1 : h_i + 2);
|
||||
float a = 0.0f;
|
||||
if (h_i > 0) {
|
||||
a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i - 1);
|
||||
}
|
||||
else if (wrap_h) {
|
||||
/* The last entry (360°) equals the first one, so we need to wrap around to the one before. */
|
||||
a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_num - 2);
|
||||
}
|
||||
float b = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i);
|
||||
float c = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1);
|
||||
float d = 0.0f;
|
||||
if (h_i + 2 < h_num) {
|
||||
d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 2);
|
||||
}
|
||||
else if (wrap_h) {
|
||||
/* Same logic here, wrap around to the second element if necessary. */
|
||||
d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, 1);
|
||||
}
|
||||
|
||||
/* Cubic interpolation can result in negative values, so get rid of them. */
|
||||
return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
|
||||
|
|
|
@ -154,11 +154,7 @@ bool IESFile::parse(const string &ies)
|
|||
int h_angles_num = parser.get_long(); /* Number of horizontal angles */
|
||||
type = (IESType)parser.get_long(); /* Photometric type */
|
||||
|
||||
/* TODO(lukas): Test whether the current type B processing can also deal with type A files.
|
||||
* In theory the only difference should be orientation which we ignore anyways, but with IES you
|
||||
* never know...
|
||||
*/
|
||||
if (type != TYPE_B && type != TYPE_C) {
|
||||
if (type != TYPE_A && type != TYPE_B && type != TYPE_C) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -205,8 +201,26 @@ bool IESFile::parse(const string &ies)
|
|||
return !parser.has_error();
|
||||
}
|
||||
|
||||
bool IESFile::process_type_b()
|
||||
static bool angle_close(float a, float b)
|
||||
{
|
||||
return fabsf(a - b) < 1e-4f;
|
||||
}
|
||||
|
||||
/* Processing functions to turn file contents into the format that Cycles expects.
|
||||
* Handles type conversion (the output format is based on Type C), symmetry/mirroring,
|
||||
* value shifting etc.
|
||||
* Note that this code is much more forgiving than the spec. For example, in type A and B,
|
||||
* the range of vertical angles officially must be either exactly 0°-90° or -90°-90°.
|
||||
* However, in practise, IES files are all over the place. Therefore, the handling is as
|
||||
* flexible as possible, and tries to turn any input into something useful. */
|
||||
|
||||
void IESFile::process_type_b()
|
||||
{
|
||||
/* According to the standard, Type B defines a different coordinate system where the polar axis
|
||||
* is horizontal, not vertical.
|
||||
* To avoid overcomplicating the conversion logic, we just transpose the angles and use the
|
||||
* regular Type A/C coordinate system. Users can just rotate the light to get the "proper"
|
||||
* orientation. */
|
||||
vector<vector<float>> newintensity;
|
||||
newintensity.resize(v_angles.size());
|
||||
for (int i = 0; i < v_angles.size(); i++) {
|
||||
|
@ -218,14 +232,8 @@ bool IESFile::process_type_b()
|
|||
intensity.swap(newintensity);
|
||||
h_angles.swap(v_angles);
|
||||
|
||||
float h_first = h_angles[0], h_last = h_angles[h_angles.size() - 1];
|
||||
if (h_last != 90.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (h_first == 0.0f) {
|
||||
/* The range in the file corresponds to 90°-180°, we need to mirror that to get the
|
||||
* full 180° range. */
|
||||
if (angle_close(h_angles[0], 0.0f)) {
|
||||
/* File angles cover 0°-90°. Mirror that to -90°-90°, and shift to 0°-180° to match Cycles. */
|
||||
vector<float> new_h_angles;
|
||||
vector<vector<float>> new_intensity;
|
||||
int hnum = h_angles.size();
|
||||
|
@ -242,26 +250,15 @@ bool IESFile::process_type_b()
|
|||
h_angles.swap(new_h_angles);
|
||||
intensity.swap(new_intensity);
|
||||
}
|
||||
else if (h_first == -90.0f) {
|
||||
/* We have full 180° coverage, so just shift to match the angle range convention. */
|
||||
else {
|
||||
/* File angles cover -90°-90°. Shift to 0°-180° to match Cycles. */
|
||||
for (int i = 0; i < h_angles.size(); i++) {
|
||||
h_angles[i] += 90.0f;
|
||||
}
|
||||
}
|
||||
/* To get correct results with the cubic interpolation in the kernel, the horizontal range
|
||||
* has to cover all 360°. Therefore, we copy the 0° entry to 360° to ensure full coverage
|
||||
* and seamless interpolation. */
|
||||
h_angles.push_back(360.0f);
|
||||
intensity.push_back(intensity[0]);
|
||||
|
||||
float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
|
||||
if (v_last != 90.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v_first == 0.0f) {
|
||||
/* The range in the file corresponds to 90°-180°, we need to mirror that to get the
|
||||
* full 180° range. */
|
||||
if (angle_close(v_angles[0], 0.0f)) {
|
||||
/* File angles cover 0°-90°. Mirror that to -90°-90°, and shift to 0°-180° to match Cycles. */
|
||||
vector<float> new_v_angles;
|
||||
int hnum = h_angles.size();
|
||||
int vnum = v_angles.size();
|
||||
|
@ -275,7 +272,7 @@ bool IESFile::process_type_b()
|
|||
for (int i = 0; i < hnum; i++) {
|
||||
vector<float> new_intensity;
|
||||
new_intensity.reserve(2 * vnum - 1);
|
||||
for (int j = vnum - 2; j >= 0; j--) {
|
||||
for (int j = vnum - 1; j > 0; j--) {
|
||||
new_intensity.push_back(intensity[i][j]);
|
||||
}
|
||||
new_intensity.insert(new_intensity.end(), intensity[i].begin(), intensity[i].end());
|
||||
|
@ -283,36 +280,64 @@ bool IESFile::process_type_b()
|
|||
}
|
||||
v_angles.swap(new_v_angles);
|
||||
}
|
||||
else if (v_first == -90.0f) {
|
||||
/* We have full 180° coverage, so just shift to match the angle range convention. */
|
||||
else {
|
||||
/* File angles cover -90°-90°. Shift to 0°-180° to match Cycles. */
|
||||
for (int i = 0; i < v_angles.size(); i++) {
|
||||
v_angles[i] += 90.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IESFile::process_type_c()
|
||||
void IESFile::process_type_a()
|
||||
{
|
||||
if (h_angles[0] == 90.0f) {
|
||||
/* Some files are stored from 90° to 270°, so we just rotate them to the regular 0°-180° range
|
||||
* here. */
|
||||
/* Convert vertical angles - just a simple offset. */
|
||||
for (int i = 0; i < v_angles.size(); i++) {
|
||||
v_angles[i] += 90.0f;
|
||||
}
|
||||
|
||||
vector<float> new_h_angles;
|
||||
new_h_angles.reserve(h_angles.size());
|
||||
vector<vector<float>> new_intensity;
|
||||
new_intensity.reserve(h_angles.size());
|
||||
|
||||
/* Type A goes from -90° to 90°, which is mapped to 270° to 90° respectively in Type C. */
|
||||
for (int i = h_angles.size() - 1; i >= 0; i--) {
|
||||
new_h_angles.push_back(180.0f - h_angles[i]);
|
||||
new_intensity.push_back(intensity[i]);
|
||||
}
|
||||
|
||||
/* If the file angles start at 0°, we need to mirror around that.
|
||||
* Since the negative input range (which we generate here) maps to 180° to 270°,
|
||||
* it comes after the original entries in the output. */
|
||||
if (angle_close(h_angles[0], 0.0f)) {
|
||||
new_h_angles.reserve(2 * h_angles.size() - 1);
|
||||
new_intensity.reserve(2 * h_angles.size() - 1);
|
||||
for (int i = 1; i < h_angles.size(); i++) {
|
||||
new_h_angles.push_back(180.0f + h_angles[i]);
|
||||
new_intensity.push_back(intensity[i]);
|
||||
}
|
||||
}
|
||||
|
||||
h_angles.swap(new_h_angles);
|
||||
intensity.swap(new_intensity);
|
||||
}
|
||||
|
||||
void IESFile::process_type_c()
|
||||
{
|
||||
if (angle_close(h_angles[0], 90.0f)) {
|
||||
/* Some files are stored from 90° to 270°, so rotate them to the regular 0°-180° range. */
|
||||
for (int i = 0; i < h_angles.size(); i++) {
|
||||
h_angles[i] -= 90.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (h_angles[0] != 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (h_angles.size() == 1) {
|
||||
h_angles[0] = 0.0f;
|
||||
h_angles.push_back(360.0f);
|
||||
intensity.push_back(intensity[0]);
|
||||
}
|
||||
|
||||
if (h_angles[h_angles.size() - 1] == 90.0f) {
|
||||
if (angle_close(h_angles[h_angles.size() - 1], 90.0f)) {
|
||||
/* Only one quadrant is defined, so we need to mirror twice (from one to two, then to four).
|
||||
* Since the two->four mirroring step might also be required if we get an input of two
|
||||
* quadrants, we only do the first mirror here and later do the second mirror in either case.
|
||||
|
@ -324,7 +349,7 @@ bool IESFile::process_type_c()
|
|||
}
|
||||
}
|
||||
|
||||
if (h_angles[h_angles.size() - 1] == 180.0f) {
|
||||
if (angle_close(h_angles[h_angles.size() - 1], 180.0f)) {
|
||||
/* Mirror half to the full range. */
|
||||
int hnum = h_angles.size();
|
||||
for (int i = hnum - 2; i >= 0; i--) {
|
||||
|
@ -335,31 +360,16 @@ bool IESFile::process_type_c()
|
|||
|
||||
/* Some files skip the 360° entry (contrary to standard) because it's supposed to be identical to
|
||||
* the 0° entry. If the file has a discernible order in its spacing, just fix this. */
|
||||
if (h_angles[h_angles.size() - 1] != 360.0f) {
|
||||
if (angle_close(h_angles[0], 0.0f) && !angle_close(h_angles[h_angles.size() - 1], 360.0f)) {
|
||||
int hnum = h_angles.size();
|
||||
float last_step = h_angles[hnum - 1] - h_angles[hnum - 2];
|
||||
float first_step = h_angles[1] - h_angles[0];
|
||||
float difference = 360.0f - h_angles[hnum - 1];
|
||||
if (last_step == difference || first_step == difference) {
|
||||
float gap_step = 360.0f - h_angles[hnum - 1];
|
||||
if (angle_close(last_step, gap_step) || angle_close(first_step, gap_step)) {
|
||||
h_angles.push_back(360.0f);
|
||||
intensity.push_back(intensity[0]);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
|
||||
if (v_first == 90.0f) {
|
||||
if (v_last != 180.0f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (v_first != 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IESFile::process()
|
||||
|
@ -368,22 +378,19 @@ bool IESFile::process()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (type == TYPE_B) {
|
||||
if (!process_type_b()) {
|
||||
return false;
|
||||
}
|
||||
if (type == TYPE_A) {
|
||||
process_type_a();
|
||||
}
|
||||
else if (type == TYPE_B) {
|
||||
process_type_b();
|
||||
}
|
||||
else if (type == TYPE_C) {
|
||||
process_type_c();
|
||||
}
|
||||
else {
|
||||
assert(type == TYPE_C);
|
||||
if (!process_type_c()) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(v_angles[0] == 0.0f || v_angles[0] == 90.0f);
|
||||
assert(h_angles[0] == 0.0f);
|
||||
assert(h_angles[h_angles.size() - 1] == 360.0f);
|
||||
|
||||
/* Convert from deg to rad. */
|
||||
for (int i = 0; i < v_angles.size(); i++) {
|
||||
v_angles[i] *= M_PI_F / 180.f;
|
||||
|
|
|
@ -24,8 +24,9 @@ class IESFile {
|
|||
protected:
|
||||
bool parse(const string &ies);
|
||||
bool process();
|
||||
bool process_type_b();
|
||||
bool process_type_c();
|
||||
void process_type_a();
|
||||
void process_type_b();
|
||||
void process_type_c();
|
||||
|
||||
/* The brightness distribution is stored in spherical coordinates.
|
||||
* The horizontal angles correspond to theta in the regular notation
|
||||
|
@ -36,7 +37,7 @@ class IESFile {
|
|||
* of one horizontal segment. */
|
||||
vector<vector<float>> intensity;
|
||||
|
||||
/* Types of angle representation in IES files. Currently, only B and C are supported. */
|
||||
/* Types of angle representation in IES files. */
|
||||
enum IESType { TYPE_A = 3, TYPE_B = 2, TYPE_C = 1 } type;
|
||||
};
|
||||
|
||||
|
|
|
@ -83,8 +83,8 @@ extern GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consu
|
|||
|
||||
/**
|
||||
* Returns the system time.
|
||||
* Returns the number of milliseconds since the start of the system process.
|
||||
* Based on ANSI clock() routine.
|
||||
* Returns the number of milliseconds since the start of the system.
|
||||
*
|
||||
* \param systemhandle: The handle to the system.
|
||||
* \return The number of milliseconds.
|
||||
*/
|
||||
|
|
|
@ -170,8 +170,10 @@ class GHOST_ISystem {
|
|||
|
||||
/**
|
||||
* Returns the system time.
|
||||
* Returns the number of milliseconds since the start of the system process.
|
||||
* Based on ANSI clock() routine.
|
||||
* Returns the number of milliseconds since the start of the system.
|
||||
* \note The exact method used is platform dependent however monotonic methods should be used
|
||||
* instead of wall-clock time.
|
||||
*
|
||||
* \return The number of milliseconds.
|
||||
*/
|
||||
virtual uint64_t getMilliSeconds() const = 0;
|
||||
|
|
|
@ -802,5 +802,5 @@ void GHOST_SystemSDL::putClipboard(const char *buffer, bool /*selection*/) const
|
|||
|
||||
uint64_t GHOST_SystemSDL::getMilliSeconds() const
|
||||
{
|
||||
return uint64_t(SDL_GetTicks()); /* NOTE: 32 -> 64bits. */
|
||||
return SDL_GetTicks64();
|
||||
}
|
||||
|
|
|
@ -106,7 +106,6 @@ using namespace std;
|
|||
GHOST_SystemX11::GHOST_SystemX11()
|
||||
: GHOST_System(),
|
||||
m_xkb_descr(nullptr),
|
||||
m_start_time(0),
|
||||
m_keyboard_vector{0},
|
||||
#ifdef WITH_X11_XINPUT
|
||||
m_last_key_time(0),
|
||||
|
@ -175,14 +174,6 @@ GHOST_SystemX11::GHOST_SystemX11()
|
|||
m_last_release_keycode = 0;
|
||||
m_last_release_time = 0;
|
||||
|
||||
{
|
||||
timespec ts = {0, 0};
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
GHOST_ASSERT(false, "Could not instantiate monotonic timer!");
|
||||
}
|
||||
m_start_time = (uint64_t(ts.tv_sec) * 1000) + uint64_t(ts.tv_nsec / 1000000);
|
||||
}
|
||||
|
||||
/* Use detectable auto-repeat, mac and windows also do this. */
|
||||
int use_xkb;
|
||||
int xkb_opcode, xkb_event, xkb_error;
|
||||
|
@ -278,8 +269,7 @@ uint64_t GHOST_SystemX11::getMilliSeconds() const
|
|||
}
|
||||
/* Taking care not to overflow the tv.tv_sec * 1000 */
|
||||
const uint64_t time = (uint64_t(ts.tv_sec) * 1000) + uint64_t(ts.tv_nsec / 1000000);
|
||||
GHOST_ASSERT(m_start_time <= time, "Monotonic time unexpectedly went backwards!");
|
||||
return time - m_start_time;
|
||||
return time;
|
||||
}
|
||||
|
||||
uint64_t GHOST_SystemX11::ms_from_input_time(Time timestamp) const
|
||||
|
@ -290,7 +280,7 @@ uint64_t GHOST_SystemX11::ms_from_input_time(Time timestamp) const
|
|||
* XORG/LIBINPUT which uses time-stamps based on the monotonic time,
|
||||
* Needed to resolve failure to detect double-clicking, see: #40009. */
|
||||
|
||||
/* Accumulate time rollover (as well as store the initial delta from `m_start_time`). */
|
||||
/* Accumulate time rollover (as well as store the initial delta from #getMilliSeconds). */
|
||||
static uint64_t timestamp_offset = 0;
|
||||
|
||||
/* The last event time (to detect rollover). */
|
||||
|
|
|
@ -348,9 +348,6 @@ class GHOST_SystemX11 : public GHOST_System {
|
|||
/** The vector of windows that need to be updated. */
|
||||
std::vector<GHOST_WindowX11 *> m_dirty_windows;
|
||||
|
||||
/** Start time at initialization (using `CLOCK_MONOTONIC`). */
|
||||
uint64_t m_start_time;
|
||||
|
||||
/** A vector of keyboard key masks. */
|
||||
char m_keyboard_vector[32];
|
||||
|
||||
|
|
|
@ -543,11 +543,11 @@ class NODE_MT_category_GEO_UTILITIES(Menu):
|
|||
layout.menu("NODE_MT_category_GEO_UTILITIES_MATH")
|
||||
layout.menu("NODE_MT_category_GEO_UTILITIES_ROTATION")
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeIndexSwitch")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMenuSwitch")
|
||||
node_add_menu.add_node_type(layout, "FunctionNodeRandomValue")
|
||||
node_add_menu.add_repeat_zone(layout, label="Repeat Zone")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSwitch")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeIndexSwitch")
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
|
||||
|
||||
|
|
|
@ -59,7 +59,13 @@ class DATA_PT_curves_surface(DataButtonsPanel, Panel):
|
|||
layout.prop(ob.data, "surface")
|
||||
has_surface = ob.data.surface is not None
|
||||
if has_surface:
|
||||
layout.prop_search(ob.data, "surface_uv_map", ob.data.surface.data, "uv_layers", text="UV Map", icon='GROUP_UVS')
|
||||
layout.prop_search(
|
||||
ob.data,
|
||||
"surface_uv_map",
|
||||
ob.data.surface.data,
|
||||
"uv_layers",
|
||||
text="UV Map",
|
||||
icon='GROUP_UVS')
|
||||
else:
|
||||
row = layout.row()
|
||||
row.prop(ob.data, "surface_uv_map", text="UV Map")
|
||||
|
|
|
@ -188,8 +188,9 @@ class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
|||
if ob_type == 'VOLUME':
|
||||
self.operator_modifier_add(layout, 'VOLUME_DISPLACE')
|
||||
if ob_type == 'GREASEPENCIL':
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_OFFSET')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_SMOOTH')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_OFFSET')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_NOISE')
|
||||
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
||||
|
||||
|
||||
|
|
|
@ -8510,7 +8510,7 @@ class VIEW3D_PT_sculpt_automasking(Panel):
|
|||
col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
|
||||
|
||||
if sculpt.use_automasking_boundary_edges or sculpt.use_automasking_boundary_face_sets:
|
||||
col.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps")
|
||||
col.prop(sculpt, "automasking_boundary_edges_propagation_steps")
|
||||
|
||||
col.separator()
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
* \brief Functions to work with AnimData.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ID;
|
||||
struct Main;
|
||||
|
||||
|
|
|
@ -7,16 +7,22 @@
|
|||
*/
|
||||
|
||||
#include "ANIM_animdata.hh"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_lib_id.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
||||
#include "ED_anim_api.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_path.hh"
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 15
|
||||
#define BLENDER_FILE_SUBVERSION 16
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -413,7 +413,7 @@ class Layer : public ::GreasePencilLayer {
|
|||
bool has_drawing_at(const int frame_number) const;
|
||||
|
||||
/**
|
||||
* \returns the key of the active frame at \a frame_number or std::nullopt if there is no frame.
|
||||
* \returns the key of the active frame at \a frame_number or #std::nullopt if there is no frame.
|
||||
*/
|
||||
std::optional<FramesMapKey> frame_key_at(int frame_number) const;
|
||||
|
||||
|
@ -438,12 +438,12 @@ class Layer : public ::GreasePencilLayer {
|
|||
void tag_frames_map_keys_changed();
|
||||
|
||||
/**
|
||||
* Prepare the DNA #GreasePencilLayer data before blendfile writing.
|
||||
* Prepare the DNA #GreasePencilLayer data before blend-file writing.
|
||||
*/
|
||||
void prepare_for_dna_write();
|
||||
|
||||
/**
|
||||
* Update from DNA #GreasePencilLayer data after blendfile reading.
|
||||
* Update from DNA #GreasePencilLayer data after blend-file reading.
|
||||
*/
|
||||
void update_from_dna_read();
|
||||
|
||||
|
@ -543,12 +543,12 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
|
|||
void print_nodes(StringRefNull header) const;
|
||||
|
||||
/**
|
||||
* Prepare the DNA #GreasePencilLayerTreeGroup data before blendfile writing.
|
||||
* Prepare the DNA #GreasePencilLayerTreeGroup data before blend-file writing.
|
||||
*/
|
||||
void prepare_for_dna_write();
|
||||
|
||||
/**
|
||||
* Update from DNA #GreasePencilLayerTreeGroup data after blendfile reading.
|
||||
* Update from DNA #GreasePencilLayerTreeGroup data after blend-file reading.
|
||||
*/
|
||||
void update_from_dna_read();
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, bool do_id_user);
|
|||
|
||||
/**
|
||||
* Free the bases of this #ViewLayer, and what they reference.
|
||||
* This includes baseact, object_bases, object_bases_hash, and layer_collections.
|
||||
* This includes `baseact`, `object_bases`, `object_bases_hash`, and `layer_collections`.
|
||||
*/
|
||||
void BKE_view_layer_free_object_content(ViewLayer *view_layer);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ blender::MutableSpan<NodeEnumItem> NodeEnumDefinition::items_for_write()
|
|||
return {this->items_array, this->items_num};
|
||||
}
|
||||
|
||||
NodeEnumItem *NodeEnumDefinition::add_item(blender::StringRef name)
|
||||
NodeEnumItem *NodeEnumDefinition::add_item(const blender::StringRef name)
|
||||
{
|
||||
const int insert_index = this->items_num;
|
||||
NodeEnumItem *old_items = this->items_array;
|
||||
|
@ -82,11 +82,11 @@ void NodeEnumDefinition::clear()
|
|||
this->active_index = int16_t(active_index);
|
||||
}
|
||||
|
||||
bool NodeEnumDefinition::move_item(uint16_t from_index, uint16_t to_index)
|
||||
bool NodeEnumDefinition::move_item(const int from_index, const int to_index)
|
||||
{
|
||||
if (to_index < this->items_num) {
|
||||
int items_num = this->items_num;
|
||||
int active_index = this->active_index;
|
||||
const int items_num = this->items_num;
|
||||
const int active_index = this->active_index;
|
||||
blender::dna::array::move_index(this->items_array, items_num, from_index, to_index);
|
||||
this->items_num = int16_t(items_num);
|
||||
this->active_index = int16_t(active_index);
|
||||
|
@ -115,7 +115,7 @@ void NodeEnumDefinition::active_item_set(NodeEnumItem *item)
|
|||
this->active_index = this->items().contains_ptr(item) ? item - this->items_array : -1;
|
||||
}
|
||||
|
||||
void NodeEnumDefinition::set_item_name(NodeEnumItem &item, blender::StringRef name)
|
||||
void NodeEnumDefinition::set_item_name(NodeEnumItem &item, const blender::StringRef name)
|
||||
{
|
||||
char unique_name[MAX_NAME + 4];
|
||||
STRNCPY(unique_name, name.data());
|
||||
|
|
|
@ -822,6 +822,8 @@ class NodeTreeMainUpdater {
|
|||
bNodeSocket &input = *node->input_sockets()[0];
|
||||
BLI_assert(input.is_available() && input.type == SOCK_MENU);
|
||||
this->set_enum_ptr(*input.default_value_typed<bNodeSocketValueMenu>(), enum_items);
|
||||
/* Remove initial user. */
|
||||
enum_items->remove_user_and_delete_if_last();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -841,12 +843,15 @@ class NodeTreeMainUpdater {
|
|||
|
||||
/* Propagate enum references from output links. */
|
||||
for (bNodeSocket *output : node->output_sockets()) {
|
||||
if (output->is_available() && output->type == SOCK_MENU) {
|
||||
for (const bNodeSocket *input : output->directly_linked_sockets()) {
|
||||
this->update_socket_enum_definition(
|
||||
*output->default_value_typed<bNodeSocketValueMenu>(),
|
||||
*input->default_value_typed<bNodeSocketValueMenu>());
|
||||
if (!output->is_available() || output->type != SOCK_MENU) {
|
||||
continue;
|
||||
}
|
||||
for (const bNodeSocket *input : output->directly_linked_sockets()) {
|
||||
if (!input->is_available() || input->type != SOCK_MENU) {
|
||||
continue;
|
||||
}
|
||||
this->update_socket_enum_definition(*output->default_value_typed<bNodeSocketValueMenu>(),
|
||||
*input->default_value_typed<bNodeSocketValueMenu>());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ typedef struct BlendFileData {
|
|||
|
||||
int fileflags;
|
||||
int globalf;
|
||||
/** Typically the actual filepath of the read blendfile, except when recovering
|
||||
/** Typically the actual filepath of the read blend-file, except when recovering
|
||||
* save-on-exit/autosave files. In the latter case, it will be the path of the file that
|
||||
* generated the auto-saved one being recovered.
|
||||
*
|
||||
|
|
|
@ -67,7 +67,7 @@ struct FileData {
|
|||
|
||||
/** Used for relative paths handling.
|
||||
*
|
||||
* Typically the actual filepath of the read blendfile, except when recovering
|
||||
* Typically the actual filepath of the read blend-file, except when recovering
|
||||
* save-on-exit/autosave files. In the latter case, it will be the path of the file that
|
||||
* generated the auto-saved one being recovered.
|
||||
*
|
||||
|
|
|
@ -1542,16 +1542,72 @@ static void version_principled_bsdf_specular_tint(bNodeTree *ntree)
|
|||
}
|
||||
|
||||
bNodeSocket *base_color_sock = nodeFindSocket(node, SOCK_IN, "Base Color");
|
||||
bNodeSocket *metallic_sock = nodeFindSocket(node, SOCK_IN, "Metallic");
|
||||
float specular_tint_old = *version_cycles_node_socket_float_value(specular_tint_sock);
|
||||
float *base_color = version_cycles_node_socket_rgba_value(base_color_sock);
|
||||
float metallic = *version_cycles_node_socket_float_value(metallic_sock);
|
||||
|
||||
/* Change socket type to Color. */
|
||||
nodeModifySocketTypeStatic(ntree, node, specular_tint_sock, SOCK_RGBA, 0);
|
||||
float *specular_tint = version_cycles_node_socket_rgba_value(specular_tint_sock);
|
||||
|
||||
/* The conversion logic here is that the new Specular Tint should be
|
||||
* mix(one, mix(base_color, one, metallic), old_specular_tint).
|
||||
* This needs to be handled both for the fixed values, as well as for any potential connected
|
||||
* inputs. */
|
||||
|
||||
static float one[] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
/* Add a mix node when working with dynamic inputs. */
|
||||
if (specular_tint_sock->link || (base_color_sock->link && specular_tint_old != 0)) {
|
||||
/* Mix the fixed values. */
|
||||
float metallic_mix[4];
|
||||
interp_v4_v4v4(metallic_mix, base_color, one, metallic);
|
||||
interp_v4_v4v4(specular_tint, one, metallic_mix, specular_tint_old);
|
||||
|
||||
if (specular_tint_sock->link == nullptr && specular_tint_old <= 0.0f) {
|
||||
/* Specular Tint was fixed at zero, we don't need any conversion node setup. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the Metallic input is dynamic, or fixed > 0 and base color is dynamic,
|
||||
* we need to insert a node to compute the metallic_mix.
|
||||
* Otherwise, use whatever is connected to the base color, or the static value
|
||||
* if it's unconnected. */
|
||||
bNodeSocket *metallic_mix_out = nullptr;
|
||||
bNode *metallic_mix_node = nullptr;
|
||||
if (metallic_sock->link || (base_color_sock->link && metallic > 0.0f)) {
|
||||
/* Metallic Mix needs to be dynamically mixed. */
|
||||
bNode *mix = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX);
|
||||
static_cast<NodeShaderMix *>(mix->storage)->data_type = SOCK_RGBA;
|
||||
mix->locx = node->locx - 270;
|
||||
mix->locy = node->locy - 120;
|
||||
|
||||
bNodeSocket *a_in = nodeFindSocket(mix, SOCK_IN, "A_Color");
|
||||
bNodeSocket *b_in = nodeFindSocket(mix, SOCK_IN, "B_Color");
|
||||
bNodeSocket *fac_in = nodeFindSocket(mix, SOCK_IN, "Factor_Float");
|
||||
metallic_mix_out = nodeFindSocket(mix, SOCK_OUT, "Result_Color");
|
||||
metallic_mix_node = mix;
|
||||
|
||||
copy_v4_v4(version_cycles_node_socket_rgba_value(a_in), base_color);
|
||||
if (base_color_sock->link) {
|
||||
nodeAddLink(
|
||||
ntree, base_color_sock->link->fromnode, base_color_sock->link->fromsock, mix, a_in);
|
||||
}
|
||||
copy_v4_v4(version_cycles_node_socket_rgba_value(b_in), one);
|
||||
*version_cycles_node_socket_float_value(fac_in) = metallic;
|
||||
if (metallic_sock->link) {
|
||||
nodeAddLink(
|
||||
ntree, metallic_sock->link->fromnode, metallic_sock->link->fromsock, mix, fac_in);
|
||||
}
|
||||
}
|
||||
else if (base_color_sock->link) {
|
||||
/* Metallic Mix is a no-op and equivalent to Base Color*/
|
||||
metallic_mix_out = base_color_sock->link->fromsock;
|
||||
metallic_mix_node = base_color_sock->link->fromnode;
|
||||
}
|
||||
|
||||
/* Similar to above, if the Specular Tint input is dynamic, or fixed > 0 and metallic mix
|
||||
* is dynamic, we need to insert a node to compute the new specular tint. */
|
||||
if (specular_tint_sock->link || (metallic_mix_out && specular_tint_old > 0.0f)) {
|
||||
bNode *mix = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX);
|
||||
static_cast<NodeShaderMix *>(mix->storage)->data_type = SOCK_RGBA;
|
||||
mix->locx = node->locx - 170;
|
||||
|
@ -1563,13 +1619,11 @@ static void version_principled_bsdf_specular_tint(bNodeTree *ntree)
|
|||
bNodeSocket *result_out = nodeFindSocket(mix, SOCK_OUT, "Result_Color");
|
||||
|
||||
copy_v4_v4(version_cycles_node_socket_rgba_value(a_in), one);
|
||||
copy_v4_v4(version_cycles_node_socket_rgba_value(b_in), base_color);
|
||||
*version_cycles_node_socket_float_value(fac_in) = specular_tint_old;
|
||||
|
||||
if (base_color_sock->link) {
|
||||
nodeAddLink(
|
||||
ntree, base_color_sock->link->fromnode, base_color_sock->link->fromsock, mix, b_in);
|
||||
copy_v4_v4(version_cycles_node_socket_rgba_value(b_in), metallic_mix);
|
||||
if (metallic_mix_out) {
|
||||
nodeAddLink(ntree, metallic_mix_node, metallic_mix_out, mix, b_in);
|
||||
}
|
||||
*version_cycles_node_socket_float_value(fac_in) = specular_tint_old;
|
||||
if (specular_tint_sock->link) {
|
||||
nodeAddLink(ntree,
|
||||
specular_tint_sock->link->fromnode,
|
||||
|
@ -1580,10 +1634,6 @@ static void version_principled_bsdf_specular_tint(bNodeTree *ntree)
|
|||
}
|
||||
nodeAddLink(ntree, mix, result_out, node, specular_tint_sock);
|
||||
}
|
||||
|
||||
float *specular_tint = version_cycles_node_socket_rgba_value(specular_tint_sock);
|
||||
/* Mix the fixed values. */
|
||||
interp_v4_v4v4(specular_tint, one, base_color, specular_tint_old);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2728,6 +2778,17 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 401, 16)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
Sculpt *sculpt = scene->toolsettings->sculpt;
|
||||
if (sculpt != nullptr) {
|
||||
Sculpt default_sculpt = *DNA_struct_default_get(Sculpt);
|
||||
sculpt->automasking_boundary_edges_propagation_steps =
|
||||
default_sculpt.automasking_boundary_edges_propagation_steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -383,6 +383,10 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
|
|||
if (idprop) {
|
||||
IDP_ClearProperty(idprop);
|
||||
}
|
||||
|
||||
if (ts->sculpt) {
|
||||
ts->sculpt->automasking_boundary_edges_propagation_steps = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
|
||||
|
|
|
@ -587,9 +587,6 @@ if(WITH_COMPOSITOR_CPU)
|
|||
operations/COM_MovieClipOperation.cc
|
||||
operations/COM_MovieClipOperation.h
|
||||
|
||||
operations/COM_AntiAliasOperation.cc
|
||||
operations/COM_AntiAliasOperation.h
|
||||
|
||||
operations/COM_MaskOperation.cc
|
||||
operations/COM_MaskOperation.h
|
||||
)
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_DilateErodeNode.h"
|
||||
#include "COM_AntiAliasOperation.h"
|
||||
#include "COM_DilateErodeOperation.h"
|
||||
#include "COM_GaussianAlphaXBlurOperation.h"
|
||||
#include "COM_GaussianAlphaYBlurOperation.h"
|
||||
#include "COM_SMAAOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
|
@ -38,11 +38,26 @@ void DilateErodeNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
||||
|
||||
if (editor_node->custom3 < 2.0f) {
|
||||
AntiAliasOperation *anti_alias = new AntiAliasOperation();
|
||||
converter.add_operation(anti_alias);
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
|
||||
converter.add_link(operation->get_output_socket(), anti_alias->get_input_socket(0));
|
||||
converter.map_output_socket(get_output_socket(0), anti_alias->get_output_socket(0));
|
||||
converter.add_link(operation->get_output_socket(), smaa_edge_detection->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood =
|
||||
new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(operation->get_output_socket(), smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
converter.map_output_socket(get_output_socket(0), smaa_neighborhood->get_output_socket());
|
||||
}
|
||||
else {
|
||||
converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include "COM_ZCombineNode.h"
|
||||
|
||||
#include "COM_AntiAliasOperation.h"
|
||||
#include "COM_MathBaseOperation.h"
|
||||
#include "COM_SMAAOperation.h"
|
||||
#include "COM_ZCombineOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
@ -54,11 +54,25 @@ void ZCombineNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.map_input_socket(get_input_socket(3), maskoperation->get_input_socket(1));
|
||||
|
||||
/* Step 2 anti alias mask bit of an expensive operation, but does the trick. */
|
||||
AntiAliasOperation *antialiasoperation = new AntiAliasOperation();
|
||||
converter.add_operation(antialiasoperation);
|
||||
SMAAEdgeDetectionOperation *smaa_edge_detection = new SMAAEdgeDetectionOperation();
|
||||
converter.add_operation(smaa_edge_detection);
|
||||
|
||||
converter.add_link(maskoperation->get_output_socket(),
|
||||
antialiasoperation->get_input_socket(0));
|
||||
smaa_edge_detection->get_input_socket(0));
|
||||
|
||||
SMAABlendingWeightCalculationOperation *smaa_blending_weights =
|
||||
new SMAABlendingWeightCalculationOperation();
|
||||
converter.add_operation(smaa_blending_weights);
|
||||
|
||||
converter.add_link(smaa_edge_detection->get_output_socket(),
|
||||
smaa_blending_weights->get_input_socket(0));
|
||||
|
||||
SMAANeighborhoodBlendingOperation *smaa_neighborhood = new SMAANeighborhoodBlendingOperation();
|
||||
converter.add_operation(smaa_neighborhood);
|
||||
|
||||
converter.add_link(maskoperation->get_output_socket(), smaa_neighborhood->get_input_socket(0));
|
||||
converter.add_link(smaa_blending_weights->get_output_socket(),
|
||||
smaa_neighborhood->get_input_socket(1));
|
||||
|
||||
/* use mask to blend between the input colors. */
|
||||
ZCombineMaskOperation *zcombineoperation = this->get_bnode()->custom1 ?
|
||||
|
@ -66,7 +80,7 @@ void ZCombineNode::convert_to_operations(NodeConverter &converter,
|
|||
new ZCombineMaskOperation();
|
||||
converter.add_operation(zcombineoperation);
|
||||
|
||||
converter.add_link(antialiasoperation->get_output_socket(),
|
||||
converter.add_link(smaa_neighborhood->get_output_socket(),
|
||||
zcombineoperation->get_input_socket(0));
|
||||
converter.map_input_socket(get_input_socket(0), zcombineoperation->get_input_socket(1));
|
||||
converter.map_input_socket(get_input_socket(2), zcombineoperation->get_input_socket(2));
|
||||
|
|
|
@ -1,258 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_AntiAliasOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/* An implementation of the Scale3X edge-extrapolation algorithm.
|
||||
*
|
||||
* Code from GIMP plugin, based on code from Adam D. Moss <adam@gimp.org>
|
||||
* licensed by the MIT license.
|
||||
*/
|
||||
static int extrapolate9(float *E0,
|
||||
float *E1,
|
||||
float *E2,
|
||||
float *E3,
|
||||
float *E4,
|
||||
float *E5,
|
||||
float *E6,
|
||||
float *E7,
|
||||
float *E8,
|
||||
const float *A,
|
||||
const float *B,
|
||||
const float *C,
|
||||
const float *D,
|
||||
const float *E,
|
||||
const float *F,
|
||||
const float *G,
|
||||
const float *H,
|
||||
const float *I)
|
||||
{
|
||||
#define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f)
|
||||
#define PCPY(DST, SRC) \
|
||||
do { \
|
||||
*DST = *SRC; \
|
||||
} while (0)
|
||||
if (!PEQ(B, H) && !PEQ(D, F)) {
|
||||
if (PEQ(D, B)) {
|
||||
PCPY(E0, D);
|
||||
}
|
||||
else {
|
||||
PCPY(E0, E);
|
||||
}
|
||||
if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A))) {
|
||||
PCPY(E1, B);
|
||||
}
|
||||
else {
|
||||
PCPY(E1, E);
|
||||
}
|
||||
if (PEQ(B, F)) {
|
||||
PCPY(E2, F);
|
||||
}
|
||||
else {
|
||||
PCPY(E2, E);
|
||||
}
|
||||
if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A))) {
|
||||
PCPY(E3, D);
|
||||
}
|
||||
else {
|
||||
PCPY(E3, E);
|
||||
}
|
||||
PCPY(E4, E);
|
||||
if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C))) {
|
||||
PCPY(E5, F);
|
||||
}
|
||||
else {
|
||||
PCPY(E5, E);
|
||||
}
|
||||
if (PEQ(D, H)) {
|
||||
PCPY(E6, D);
|
||||
}
|
||||
else {
|
||||
PCPY(E6, E);
|
||||
}
|
||||
if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G))) {
|
||||
PCPY(E7, H);
|
||||
}
|
||||
else {
|
||||
PCPY(E7, E);
|
||||
}
|
||||
if (PEQ(H, F)) {
|
||||
PCPY(E8, F);
|
||||
}
|
||||
else {
|
||||
PCPY(E8, E);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#undef PEQ
|
||||
#undef PCPY
|
||||
}
|
||||
|
||||
AntiAliasOperation::AntiAliasOperation()
|
||||
{
|
||||
this->add_input_socket(DataType::Value);
|
||||
this->add_output_socket(DataType::Value);
|
||||
value_reader_ = nullptr;
|
||||
flags_.complex = true;
|
||||
flags_.can_be_constant = true;
|
||||
}
|
||||
|
||||
void AntiAliasOperation::init_execution()
|
||||
{
|
||||
value_reader_ = this->get_input_socket_reader(0);
|
||||
}
|
||||
|
||||
void AntiAliasOperation::execute_pixel(float output[4], int x, int y, void *data)
|
||||
{
|
||||
MemoryBuffer *input_buffer = (MemoryBuffer *)data;
|
||||
const int buffer_width = input_buffer->get_width(), buffer_height = input_buffer->get_height();
|
||||
if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) {
|
||||
output[0] = 0.0f;
|
||||
}
|
||||
else {
|
||||
const float *buffer = input_buffer->get_buffer();
|
||||
const float *row_curr = &buffer[y * buffer_width];
|
||||
if (x == 0 || x == buffer_width - 1 || y == 0 || y == buffer_height - 1) {
|
||||
output[0] = row_curr[x];
|
||||
return;
|
||||
}
|
||||
const float *row_prev = &buffer[(y - 1) * buffer_width],
|
||||
*row_next = &buffer[(y + 1) * buffer_width];
|
||||
float ninepix[9];
|
||||
if (extrapolate9(&ninepix[0],
|
||||
&ninepix[1],
|
||||
&ninepix[2],
|
||||
&ninepix[3],
|
||||
&ninepix[4],
|
||||
&ninepix[5],
|
||||
&ninepix[6],
|
||||
&ninepix[7],
|
||||
&ninepix[8],
|
||||
&row_prev[x - 1],
|
||||
&row_prev[x],
|
||||
&row_prev[x + 1],
|
||||
&row_curr[x - 1],
|
||||
&row_curr[x],
|
||||
&row_curr[x + 1],
|
||||
&row_next[x - 1],
|
||||
&row_next[x],
|
||||
&row_next[x + 1]))
|
||||
{
|
||||
/* Some rounding magic to so make weighting correct with the
|
||||
* original coefficients.
|
||||
*/
|
||||
uchar result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] +
|
||||
6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] +
|
||||
3 * ninepix[8]) *
|
||||
255.0f +
|
||||
19.0f) /
|
||||
38.0f;
|
||||
output[0] = result / 255.0f;
|
||||
}
|
||||
else {
|
||||
output[0] = row_curr[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AntiAliasOperation::deinit_execution()
|
||||
{
|
||||
value_reader_ = nullptr;
|
||||
}
|
||||
|
||||
bool AntiAliasOperation::determine_depending_area_of_interest(rcti *input,
|
||||
ReadBufferOperation *read_operation,
|
||||
rcti *output)
|
||||
{
|
||||
rcti image_input;
|
||||
NodeOperation *operation = get_input_operation(0);
|
||||
image_input.xmax = input->xmax + 1;
|
||||
image_input.xmin = input->xmin - 1;
|
||||
image_input.ymax = input->ymax + 1;
|
||||
image_input.ymin = input->ymin - 1;
|
||||
return operation->determine_depending_area_of_interest(&image_input, read_operation, output);
|
||||
}
|
||||
|
||||
void *AntiAliasOperation::initialize_tile_data(rcti *rect)
|
||||
{
|
||||
return get_input_operation(0)->initialize_tile_data(rect);
|
||||
}
|
||||
|
||||
void AntiAliasOperation::get_area_of_interest(const int input_idx,
|
||||
const rcti &output_area,
|
||||
rcti &r_input_area)
|
||||
{
|
||||
BLI_assert(input_idx == 0);
|
||||
UNUSED_VARS_NDEBUG(input_idx);
|
||||
r_input_area.xmax = output_area.xmax + 1;
|
||||
r_input_area.xmin = output_area.xmin - 1;
|
||||
r_input_area.ymax = output_area.ymax + 1;
|
||||
r_input_area.ymin = output_area.ymin - 1;
|
||||
}
|
||||
|
||||
void AntiAliasOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
const MemoryBuffer *input = inputs[0];
|
||||
const rcti &input_area = input->get_rect();
|
||||
float ninepix[9];
|
||||
for (int y = area.ymin; y < area.ymax; y++) {
|
||||
float *out = output->get_elem(area.xmin, y);
|
||||
const float *row_curr = input->get_elem(area.xmin, y);
|
||||
const float *row_prev = row_curr - input->row_stride;
|
||||
const float *row_next = row_curr + input->row_stride;
|
||||
int x_offset = 0;
|
||||
for (int x = area.xmin; x < area.xmax;
|
||||
x++, out += output->elem_stride, x_offset += input->elem_stride)
|
||||
{
|
||||
if (x == input_area.xmin || x == input_area.xmax - 1 || y == input_area.xmin ||
|
||||
y == input_area.ymax - 1)
|
||||
{
|
||||
out[0] = row_curr[x_offset];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extrapolate9(&ninepix[0],
|
||||
&ninepix[1],
|
||||
&ninepix[2],
|
||||
&ninepix[3],
|
||||
&ninepix[4],
|
||||
&ninepix[5],
|
||||
&ninepix[6],
|
||||
&ninepix[7],
|
||||
&ninepix[8],
|
||||
&row_prev[x_offset - input->elem_stride],
|
||||
&row_prev[x_offset],
|
||||
&row_prev[x_offset + input->elem_stride],
|
||||
&row_curr[x_offset - input->elem_stride],
|
||||
&row_curr[x_offset],
|
||||
&row_curr[x_offset + input->elem_stride],
|
||||
&row_next[x_offset - input->elem_stride],
|
||||
&row_next[x_offset],
|
||||
&row_next[x_offset + input->elem_stride]))
|
||||
{
|
||||
/* Some rounding magic to make weighting correct with the
|
||||
* original coefficients. */
|
||||
uchar result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + 5 * ninepix[3] +
|
||||
6 * ninepix[4] + 5 * ninepix[5] + 3 * ninepix[6] + 5 * ninepix[7] +
|
||||
3 * ninepix[8]) *
|
||||
255.0f +
|
||||
19.0f) /
|
||||
38.0f;
|
||||
out[0] = result / 255.0f;
|
||||
}
|
||||
else {
|
||||
out[0] = row_curr[x_offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -1,54 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_MultiThreadedOperation.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/**
|
||||
* \brief AntiAlias operations
|
||||
* it only supports anti aliasing on BW buffers.
|
||||
* \ingroup operation
|
||||
*/
|
||||
class AntiAliasOperation : public MultiThreadedOperation {
|
||||
protected:
|
||||
/**
|
||||
* \brief Cached reference to the reader
|
||||
*/
|
||||
SocketReader *value_reader_;
|
||||
|
||||
public:
|
||||
AntiAliasOperation();
|
||||
|
||||
/**
|
||||
* The inner loop of this operation.
|
||||
*/
|
||||
void execute_pixel(float output[4], int x, int y, void *data) override;
|
||||
|
||||
/**
|
||||
* Initialize the execution
|
||||
*/
|
||||
void init_execution() override;
|
||||
|
||||
void *initialize_tile_data(rcti *rect) override;
|
||||
|
||||
/**
|
||||
* Deinitialize the execution
|
||||
*/
|
||||
void deinit_execution() override;
|
||||
bool determine_depending_area_of_interest(rcti *input,
|
||||
ReadBufferOperation *read_operation,
|
||||
rcti *output) override;
|
||||
|
||||
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
|
||||
|
||||
void update_memory_buffer_partial(MemoryBuffer *output,
|
||||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs) override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -84,7 +84,7 @@ void MaskOperation::deinit_execution()
|
|||
|
||||
void MaskOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
|
||||
{
|
||||
if (mask_width_ == 0 || mask_height_ == 0) {
|
||||
if (!mask_ || mask_width_ == 0 || mask_height_ == 0) {
|
||||
r_area = COM_AREA_NONE;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -927,28 +927,10 @@ void MixLightenOperation::execute_pixel_sampled(float output[4],
|
|||
if (this->use_value_alpha_multiply()) {
|
||||
value *= input_color2[3];
|
||||
}
|
||||
float tmp;
|
||||
tmp = value * input_color2[0];
|
||||
if (tmp > input_color1[0]) {
|
||||
output[0] = tmp;
|
||||
}
|
||||
else {
|
||||
output[0] = input_color1[0];
|
||||
}
|
||||
tmp = value * input_color2[1];
|
||||
if (tmp > input_color1[1]) {
|
||||
output[1] = tmp;
|
||||
}
|
||||
else {
|
||||
output[1] = input_color1[1];
|
||||
}
|
||||
tmp = value * input_color2[2];
|
||||
if (tmp > input_color1[2]) {
|
||||
output[2] = tmp;
|
||||
}
|
||||
else {
|
||||
output[2] = input_color1[2];
|
||||
}
|
||||
float valuem = 1.0f - value;
|
||||
output[0] = max_ff(input_color1[0], input_color2[0]) * value + input_color1[0] * valuem;
|
||||
output[1] = max_ff(input_color1[1], input_color2[1]) * value + input_color1[1] * valuem;
|
||||
output[2] = max_ff(input_color1[2], input_color2[2]) * value + input_color1[2] * valuem;
|
||||
output[3] = input_color1[3];
|
||||
|
||||
clamp_if_needed(output);
|
||||
|
@ -961,16 +943,10 @@ void MixLightenOperation::update_memory_buffer_row(PixelCursor &p)
|
|||
if (this->use_value_alpha_multiply()) {
|
||||
value *= p.color2[3];
|
||||
}
|
||||
|
||||
float tmp = value * p.color2[0];
|
||||
p.out[0] = std::max(tmp, p.color1[0]);
|
||||
|
||||
tmp = value * p.color2[1];
|
||||
p.out[1] = std::max(tmp, p.color1[1]);
|
||||
|
||||
tmp = value * p.color2[2];
|
||||
p.out[2] = std::max(tmp, p.color1[2]);
|
||||
|
||||
float value_m = 1.0f - value;
|
||||
p.out[0] = max_ff(p.color1[0], p.color2[0]) * value + p.color1[0] * value_m;
|
||||
p.out[1] = max_ff(p.color1[1], p.color2[1]) * value + p.color1[1] * value_m;
|
||||
p.out[2] = max_ff(p.color1[2], p.color2[2]) * value + p.color1[2] * value_m;
|
||||
p.out[3] = p.color1[3];
|
||||
|
||||
clamp_if_needed(p.out);
|
||||
|
|
|
@ -398,6 +398,7 @@ PassMain::Sub *ForwardPipeline::material_transparent_add(const Object *ob,
|
|||
void ForwardPipeline::render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb)
|
||||
{
|
||||
if (!has_transparent_ && !has_opaque_) {
|
||||
inst_.volume.draw_resolve(view);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -244,9 +244,9 @@ class ReflectionProbeModule {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the resolution of a single cubemap side when rendering probes.
|
||||
* Get the resolution of a single cube-map side when rendering probes.
|
||||
*
|
||||
* The cubemaps are rendered half size of the size of the octahedral texture.
|
||||
* The cube-maps are rendered half size of the size of the octahedral texture.
|
||||
*/
|
||||
int probe_render_extent() const;
|
||||
|
||||
|
|
|
@ -1090,6 +1090,7 @@ void ShadowModule::end_sync()
|
|||
sub.bind_resources(inst_.hiz_buffer.front);
|
||||
sub.bind_resources(inst_.sampling);
|
||||
sub.bind_resources(inst_.lights);
|
||||
sub.bind_resources(inst_.volume.properties);
|
||||
sub.bind_resources(inst_.volume.result);
|
||||
sub.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
sub.dispatch(math::divide_ceil(inst_.volume.grid_size(), int3(VOLUME_GROUP_SIZE)));
|
||||
|
|
|
@ -64,8 +64,7 @@ static void step_object_sync_render(void *instance,
|
|||
{
|
||||
Instance &inst = *reinterpret_cast<Instance *>(instance);
|
||||
|
||||
const bool is_velocity_type = ELEM(
|
||||
ob->type, OB_CURVES, OB_GPENCIL_LEGACY, OB_MESH, OB_POINTCLOUD);
|
||||
const bool is_velocity_type = ELEM(ob->type, OB_CURVES, OB_MESH, OB_POINTCLOUD);
|
||||
const int ob_visibility = DRW_object_visibility_in_active_context(ob);
|
||||
const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 &&
|
||||
(ob->type == OB_MESH);
|
||||
|
@ -244,6 +243,9 @@ void VelocityModule::geometry_steps_fill()
|
|||
{
|
||||
uint dst_ofs = 0;
|
||||
for (VelocityGeometryData &geom : geometry_map.values()) {
|
||||
if (!geom.pos_buf) {
|
||||
continue;
|
||||
}
|
||||
uint src_len = GPU_vertbuf_get_vertex_len(geom.pos_buf);
|
||||
geom.len = src_len;
|
||||
geom.ofs = dst_ofs;
|
||||
|
@ -260,6 +262,9 @@ void VelocityModule::geometry_steps_fill()
|
|||
copy_ps.bind_ssbo("out_buf", *geometry_steps[step_]);
|
||||
|
||||
for (VelocityGeometryData &geom : geometry_map.values()) {
|
||||
if (!geom.pos_buf) {
|
||||
continue;
|
||||
}
|
||||
const GPUVertFormat *format = GPU_vertbuf_get_format(geom.pos_buf);
|
||||
if (format->stride == 16) {
|
||||
GPU_storagebuf_copy_sub_from_vertbuf(*geometry_steps[step_],
|
||||
|
|
|
@ -36,9 +36,9 @@ class VelocityModule {
|
|||
/** VertBuf not yet ready to be copied to the #VelocityGeometryBuf. */
|
||||
GPUVertBuf *pos_buf = nullptr;
|
||||
/* Offset in the #VelocityGeometryBuf to the start of the data. In vertex. */
|
||||
int ofs;
|
||||
int ofs = 0;
|
||||
/* Length of the vertex buffer. In vertex. */
|
||||
int len;
|
||||
int len = 0;
|
||||
};
|
||||
/**
|
||||
* The map contains indirection indices to the obmat and geometry in each step buffer.
|
||||
|
|
|
@ -616,7 +616,6 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
|
|||
&texture_buffer,
|
||||
transform_mode,
|
||||
IMB_FILTER_NEAREST,
|
||||
1,
|
||||
uv_to_texel.ptr(),
|
||||
crop_rect_ptr);
|
||||
}
|
||||
|
|
|
@ -208,6 +208,15 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
|||
GreasePencilBatchCache *cache = static_cast<GreasePencilBatchCache *>(
|
||||
grease_pencil.runtime->batch_cache);
|
||||
|
||||
if (cache->edit_points_pos != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Should be discarded together. */
|
||||
BLI_assert(cache->edit_points_pos == nullptr && cache->edit_line_indices == nullptr &&
|
||||
cache->edit_points_indices == nullptr);
|
||||
BLI_assert(cache->edit_points == nullptr && cache->edit_lines == nullptr);
|
||||
|
||||
/* Get the visible drawings. */
|
||||
const Array<ed::greasepencil::DrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil);
|
||||
|
@ -225,8 +234,10 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
|||
&format_edit_points_selection, "selection", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
}
|
||||
|
||||
cache->edit_points_pos = GPU_vertbuf_create_with_format(&format_edit_points_pos);
|
||||
cache->edit_points_selection = GPU_vertbuf_create_with_format(&format_edit_points_selection);
|
||||
GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
|
||||
cache->edit_points_pos = GPU_vertbuf_create_with_format_ex(&format_edit_points_pos, vbo_flag);
|
||||
cache->edit_points_selection = GPU_vertbuf_create_with_format_ex(&format_edit_points_selection,
|
||||
vbo_flag);
|
||||
|
||||
int total_points_num = 0;
|
||||
for (const ed::greasepencil::DrawingInfo &info : drawings) {
|
||||
|
@ -371,6 +382,9 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
|||
cache->edit_lines = GPU_batch_create(
|
||||
GPU_PRIM_LINE_STRIP, cache->edit_points_pos, cache->edit_line_indices);
|
||||
GPU_batch_vertbuf_add(cache->edit_lines, cache->edit_points_selection, false);
|
||||
/* Allow creation of buffer texture. */
|
||||
GPU_vertbuf_use(cache->edit_points_pos);
|
||||
GPU_vertbuf_use(cache->edit_points_selection);
|
||||
|
||||
cache->is_dirty = false;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ typedef struct GlobalsUboStorage GlobalsUboStorage;
|
|||
#define UBO_FIRST_COLOR color_wire
|
||||
#define UBO_LAST_COLOR color_uv_shadow
|
||||
|
||||
/* Used as ubo but colors can be directly referenced as well */
|
||||
/* Used as UBO but colors can be directly referenced as well */
|
||||
/* \note Also keep all color as vec4 and between #UBO_FIRST_COLOR and #UBO_LAST_COLOR. */
|
||||
struct GlobalsUboStorage {
|
||||
/* UBOs data needs to be 16 byte aligned (size of vec4) */
|
||||
|
|
|
@ -5767,7 +5767,7 @@ void ANIM_channel_draw_widgets(const bContext *C,
|
|||
UI_UNIT_X,
|
||||
nullptr);
|
||||
|
||||
opptr_b = UI_but_operator_ptr_get(but);
|
||||
opptr_b = UI_but_operator_ptr_ensure(but);
|
||||
RNA_int_set(opptr_b, "track_index", channel_index);
|
||||
|
||||
UI_block_emboss_set(block, UI_EMBOSS_NONE);
|
||||
|
|
|
@ -929,6 +929,10 @@ static int add_or_move_to_collection_exec(bContext *C,
|
|||
|
||||
bArmature *arm = static_cast<bArmature *>(ob->data);
|
||||
BoneCollection *target_bcoll = add_or_move_to_collection_bcoll(op, arm);
|
||||
if (!target_bcoll) {
|
||||
/* add_or_move_to_collection_bcoll() already reported the reason. */
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
bool made_any_changes = false;
|
||||
bool had_bones_to_assign = false;
|
||||
|
@ -1107,7 +1111,9 @@ static void move_to_collection_menu_create(bContext *C, uiLayout *layout, void *
|
|||
child_count = arm->collection_root_count;
|
||||
}
|
||||
else {
|
||||
/* Add a menu item to assign to the parent first, before listing the children. */
|
||||
/* Add a menu item to assign to the parent first, before listing the children.
|
||||
* The parent is assumed to be editable, because otherwise the menu would
|
||||
* have been disabled already one recursion level higher. */
|
||||
const BoneCollection *parent = arm->collection_array[parent_bcoll_index];
|
||||
menu_add_item_for_move_assign_unassign(
|
||||
layout, arm, parent, parent_bcoll_index, is_move_operation);
|
||||
|
@ -1122,6 +1128,16 @@ static void move_to_collection_menu_create(bContext *C, uiLayout *layout, void *
|
|||
for (int index = child_index; index < child_index + child_count; index++) {
|
||||
const BoneCollection *bcoll = arm->collection_array[index];
|
||||
|
||||
/* Avoid assigning/moving to a linked bone collection. */
|
||||
if (!ANIM_armature_bonecoll_is_editable(arm, bcoll)) {
|
||||
uiLayout *sub = uiLayoutRow(layout, false);
|
||||
uiLayoutSetEnabled(sub, false);
|
||||
|
||||
/* TODO: figure out if we can add a 'disabled' message in the tooltip. */
|
||||
menu_add_item_for_move_assign_unassign(sub, arm, bcoll, index, is_move_operation);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blender::animrig::bonecoll_has_children(bcoll)) {
|
||||
uiItemMenuF(layout,
|
||||
bcoll->name,
|
||||
|
|
|
@ -1402,7 +1402,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
|
|||
const char *tip);
|
||||
|
||||
/** For passing inputs to ButO buttons. */
|
||||
PointerRNA *UI_but_operator_ptr_get(uiBut *but);
|
||||
PointerRNA *UI_but_operator_ptr_ensure(uiBut *but);
|
||||
|
||||
void UI_but_context_ptr_set(uiBlock *block, uiBut *but, const char *name, const PointerRNA *ptr);
|
||||
const PointerRNA *UI_but_context_ptr_get(const uiBut *but,
|
||||
|
@ -3043,10 +3043,15 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
|
|||
const char *UI_layout_introspect(uiLayout *layout);
|
||||
|
||||
/**
|
||||
* Helper to add a big icon and create a split layout for alert popups.
|
||||
* Helpers to add a big icon and create a split layout for alert popups.
|
||||
* Returns the layout to place further items into the alert box.
|
||||
*/
|
||||
uiLayout *uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon);
|
||||
uiLayout *uiItemsAlertBox(uiBlock *block,
|
||||
const uiStyle *style,
|
||||
const int dialog_width,
|
||||
const eAlertIcon icon,
|
||||
const int icon_size);
|
||||
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon);
|
||||
|
||||
/* UI Operators */
|
||||
struct uiDragColorHandle {
|
||||
|
|
|
@ -45,6 +45,7 @@ struct IconTextOverlay {
|
|||
#define PREVIEW_DEFAULT_HEIGHT 128
|
||||
|
||||
enum eAlertIcon {
|
||||
ALERT_ICON_NONE = -1,
|
||||
ALERT_ICON_WARNING = 0,
|
||||
ALERT_ICON_QUESTION = 1,
|
||||
ALERT_ICON_ERROR = 2,
|
||||
|
|
|
@ -1359,6 +1359,7 @@ static bool ui_but_event_property_operator_string(const bContext *C,
|
|||
char *buf,
|
||||
const size_t buf_maxncpy)
|
||||
{
|
||||
using namespace blender;
|
||||
/* Context toggle operator names to check. */
|
||||
|
||||
/* NOTE(@ideasman42): This function could use a refactor to generalize button type to operator
|
||||
|
@ -1448,18 +1449,17 @@ static bool ui_but_event_property_operator_string(const bContext *C,
|
|||
/* There may be multiple data-paths to the same properties,
|
||||
* support different variations so key bindings are properly detected no matter which are used.
|
||||
*/
|
||||
char *data_path_variations[2] = {nullptr};
|
||||
int data_path_variations_num = 0;
|
||||
Vector<std::string, 2> data_path_variations;
|
||||
|
||||
{
|
||||
char *data_path = WM_context_path_resolve_property_full(C, ptr, prop, prop_index);
|
||||
std::string data_path = WM_context_path_resolve_property_full(C, ptr, prop, prop_index);
|
||||
|
||||
/* Always iterate once, even if data-path isn't set. */
|
||||
data_path_variations[data_path_variations_num++] = data_path;
|
||||
data_path_variations.append(data_path);
|
||||
|
||||
if (data_path) {
|
||||
if (STRPREFIX(data_path, "scene.tool_settings.")) {
|
||||
data_path_variations[data_path_variations_num++] = BLI_strdup(data_path + 6);
|
||||
if (!data_path.empty()) {
|
||||
if (StringRef(data_path).startswith("scene.tool_settings.")) {
|
||||
data_path_variations.append(StringRef(data_path).drop_known_prefix("scene."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1467,18 +1467,18 @@ static bool ui_but_event_property_operator_string(const bContext *C,
|
|||
/* We have a data-path! */
|
||||
bool found = false;
|
||||
|
||||
for (int data_path_index = 0; data_path_index < data_path_variations_num && (found == false);
|
||||
for (int data_path_index = 0; data_path_index < data_path_variations.size() && (found == false);
|
||||
data_path_index++)
|
||||
{
|
||||
const char *data_path = data_path_variations[data_path_index];
|
||||
if (data_path || (prop_enum_value_ok && prop_enum_value_id)) {
|
||||
const StringRefNull data_path = data_path_variations[data_path_index];
|
||||
if (!data_path.is_empty() || (prop_enum_value_ok && prop_enum_value_id)) {
|
||||
/* Create a property to host the "data_path" property we're sending to the operators. */
|
||||
IDProperty *prop_path;
|
||||
|
||||
const IDPropertyTemplate group_val = {0};
|
||||
prop_path = IDP_New(IDP_GROUP, &group_val, __func__);
|
||||
if (data_path) {
|
||||
IDP_AddToGroup(prop_path, IDP_NewString(data_path, "data_path"));
|
||||
if (!data_path.is_empty()) {
|
||||
IDP_AddToGroup(prop_path, IDP_NewString(data_path.c_str(), "data_path"));
|
||||
}
|
||||
if (prop_enum_value_ok) {
|
||||
const EnumPropertyItem *item;
|
||||
|
@ -1522,12 +1522,6 @@ static bool ui_but_event_property_operator_string(const bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
for (int data_path_index = 0; data_path_index < data_path_variations_num; data_path_index++) {
|
||||
char *data_path = data_path_variations[data_path_index];
|
||||
if (data_path) {
|
||||
MEM_freeN(data_path);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
@ -5936,7 +5930,7 @@ int UI_but_return_value_get(uiBut *but)
|
|||
return but->retval;
|
||||
}
|
||||
|
||||
PointerRNA *UI_but_operator_ptr_get(uiBut *but)
|
||||
PointerRNA *UI_but_operator_ptr_ensure(uiBut *but)
|
||||
{
|
||||
if (but->optype && !but->opptr) {
|
||||
but->opptr = MEM_cnew<PointerRNA>(__func__);
|
||||
|
@ -6421,7 +6415,7 @@ static void operator_enum_search_update_fn(
|
|||
}
|
||||
else {
|
||||
/* Will create it if needed! */
|
||||
PointerRNA *ptr = UI_but_operator_ptr_get(static_cast<uiBut *>(but));
|
||||
PointerRNA *ptr = UI_but_operator_ptr_ensure(static_cast<uiBut *>(but));
|
||||
|
||||
bool do_free;
|
||||
const EnumPropertyItem *all_items;
|
||||
|
@ -6453,7 +6447,7 @@ static void operator_enum_search_exec_fn(bContext * /*C*/, void *but, void *arg2
|
|||
{
|
||||
wmOperatorType *ot = ((uiBut *)but)->optype;
|
||||
/* Will create it if needed! */
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(static_cast<uiBut *>(but));
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(static_cast<uiBut *>(but));
|
||||
|
||||
if (ot) {
|
||||
if (ot->prop) {
|
||||
|
@ -6498,7 +6492,7 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
|
|||
but->opcontext = WM_OP_EXEC_DEFAULT;
|
||||
|
||||
if (properties) {
|
||||
PointerRNA *ptr = UI_but_operator_ptr_get(but);
|
||||
PointerRNA *ptr = UI_but_operator_ptr_ensure(but);
|
||||
/* Copy id-properties. */
|
||||
ptr->data = IDP_CopyProperty(properties);
|
||||
}
|
||||
|
@ -6577,7 +6571,7 @@ std::optional<EnumPropertyItem> UI_but_rna_enum_item_get(bContext &C, uiBut &but
|
|||
wmOperatorType *ot = but.optype;
|
||||
|
||||
/* So the context is passed to `itemf` functions. */
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(&but);
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(&but);
|
||||
WM_operator_properties_sanitize(opptr, false);
|
||||
|
||||
/* If the default property of the operator is an enum and is set, fetch the tooltip of the
|
||||
|
@ -6662,7 +6656,7 @@ std::string UI_but_string_get_rna_label(uiBut &but)
|
|||
return RNA_property_ui_name(but.rnaprop);
|
||||
}
|
||||
if (but.optype) {
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(&but);
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(&but);
|
||||
return WM_operatortype_name(but.optype, opptr).c_str();
|
||||
}
|
||||
if (ELEM(but.type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) {
|
||||
|
@ -6717,7 +6711,7 @@ std::string UI_but_string_get_rna_tooltip(bContext &C, uiBut &but)
|
|||
}
|
||||
}
|
||||
else if (but.optype) {
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(&but);
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(&but);
|
||||
const bContextStore *previous_ctx = CTX_store_get(&C);
|
||||
CTX_store_set(&C, but.context);
|
||||
std::string tmp = WM_operatortype_description(&C, but.optype, opptr).c_str();
|
||||
|
|
|
@ -65,12 +65,7 @@ static FCurve *ui_but_get_fcurve(
|
|||
|
||||
void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
|
||||
{
|
||||
AnimData *adt;
|
||||
bAction *act;
|
||||
FCurve *fcu;
|
||||
bool driven;
|
||||
bool special;
|
||||
|
||||
/* Clear the flags that this function might set. */
|
||||
but->flag &= ~(UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN);
|
||||
but->drawflag &= ~UI_BUT_ANIMATED_CHANGED;
|
||||
|
||||
|
@ -78,41 +73,46 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
|
|||
* itself (which are used to animate properties of the animation data).
|
||||
* We count those as "animated" too for now
|
||||
*/
|
||||
fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
|
||||
AnimData *adt;
|
||||
bAction *act;
|
||||
bool driven;
|
||||
bool special;
|
||||
FCurve *fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
|
||||
|
||||
if (fcu) {
|
||||
if (!driven) {
|
||||
/* Empty curves are ignored by the animation evaluation system. */
|
||||
if (BKE_fcurve_is_empty(fcu)) {
|
||||
return;
|
||||
}
|
||||
if (!fcu) {
|
||||
return;
|
||||
}
|
||||
if (driven) {
|
||||
but->flag |= UI_BUT_DRIVEN;
|
||||
return;
|
||||
}
|
||||
|
||||
but->flag |= UI_BUT_ANIMATED;
|
||||
/* Empty curves are ignored by the animation evaluation system. */
|
||||
if (BKE_fcurve_is_empty(fcu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* #41525 - When the active action is a NLA strip being edited,
|
||||
* we need to correct the frame number to "look inside" the
|
||||
* remapped action
|
||||
*/
|
||||
float cfra = anim_eval_context->eval_time;
|
||||
if (adt) {
|
||||
cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
|
||||
}
|
||||
but->flag |= UI_BUT_ANIMATED;
|
||||
|
||||
if (fcurve_frame_has_keyframe(fcu, cfra)) {
|
||||
but->flag |= UI_BUT_ANIMATED_KEY;
|
||||
}
|
||||
/* #41525 - When the active action is a NLA strip being edited,
|
||||
* we need to correct the frame number to "look inside" the
|
||||
* remapped action
|
||||
*/
|
||||
float cfra = anim_eval_context->eval_time;
|
||||
if (adt) {
|
||||
cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
|
||||
}
|
||||
|
||||
/* XXX: this feature is totally broken and useless with NLA */
|
||||
if (adt == nullptr || adt->nla_tracks.first == nullptr) {
|
||||
const AnimationEvalContext remapped_context = BKE_animsys_eval_context_construct_at(
|
||||
anim_eval_context, cfra);
|
||||
if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, &remapped_context)) {
|
||||
but->drawflag |= UI_BUT_ANIMATED_CHANGED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
but->flag |= UI_BUT_DRIVEN;
|
||||
if (fcurve_frame_has_keyframe(fcu, cfra)) {
|
||||
but->flag |= UI_BUT_ANIMATED_KEY;
|
||||
}
|
||||
|
||||
/* XXX: this feature is totally broken and useless with NLA */
|
||||
if (adt == nullptr || adt->nla_tracks.first == nullptr) {
|
||||
const AnimationEvalContext remapped_context = BKE_animsys_eval_context_construct_at(
|
||||
anim_eval_context, cfra);
|
||||
if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, &remapped_context)) {
|
||||
but->drawflag |= UI_BUT_ANIMATED_CHANGED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,18 +61,16 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but)
|
|||
|
||||
/* If this returns null, we won't be able to bind shortcuts to these RNA properties.
|
||||
* Support can be added at #wm_context_member_from_ptr. */
|
||||
char *final_data_path = WM_context_path_resolve_property_full(
|
||||
std::string final_data_path = WM_context_path_resolve_property_full(
|
||||
C, &but->rnapoin, but->rnaprop, but->rnaindex);
|
||||
if (final_data_path == nullptr) {
|
||||
if (final_data_path.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Create ID property of data path, to pass to the operator. */
|
||||
const IDPropertyTemplate val = {0};
|
||||
IDProperty *prop = IDP_New(IDP_GROUP, &val, __func__);
|
||||
IDP_AddToGroup(prop, IDP_NewString(final_data_path, "data_path"));
|
||||
|
||||
MEM_freeN((void *)final_data_path);
|
||||
IDP_AddToGroup(prop, IDP_NewString(final_data_path.c_str(), "data_path"));
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
@ -321,9 +319,8 @@ static bool ui_but_is_user_menu_compatible(bContext *C, uiBut *but)
|
|||
}
|
||||
else if (but->rnaprop) {
|
||||
if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) {
|
||||
char *data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
if (data_path != nullptr) {
|
||||
MEM_freeN(data_path);
|
||||
std::string data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
if (!data_path.empty()) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
@ -346,14 +343,13 @@ static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *
|
|||
&um->items, but->optype, prop, "", but->opcontext);
|
||||
}
|
||||
if (but->rnaprop) {
|
||||
char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
std::string member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
/* Ignore the actual array index [pass -1] since the index is handled separately. */
|
||||
const char *prop_id = RNA_property_is_idprop(but->rnaprop) ?
|
||||
RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
|
||||
RNA_property_identifier(but->rnaprop);
|
||||
bUserMenuItem *umi = (bUserMenuItem *)ED_screen_user_menu_item_find_prop(
|
||||
&um->items, member_id_data_path, prop_id, but->rnaindex);
|
||||
MEM_freeN(member_id_data_path);
|
||||
&um->items, member_id_data_path.c_str(), prop_id, but->rnaindex);
|
||||
return umi;
|
||||
}
|
||||
|
||||
|
@ -423,14 +419,14 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
|
|||
}
|
||||
else if (but->rnaprop) {
|
||||
/* NOTE: 'member_id' may be a path. */
|
||||
char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
std::string member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
/* Ignore the actual array index [pass -1] since the index is handled separately. */
|
||||
const char *prop_id = RNA_property_is_idprop(but->rnaprop) ?
|
||||
RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
|
||||
RNA_property_identifier(but->rnaprop);
|
||||
/* NOTE: ignore 'drawstr', use property idname always. */
|
||||
ED_screen_user_menu_item_add_prop(&um->items, "", member_id_data_path, prop_id, but->rnaindex);
|
||||
MEM_freeN(member_id_data_path);
|
||||
ED_screen_user_menu_item_add_prop(
|
||||
&um->items, "", member_id_data_path.c_str(), prop_id, but->rnaindex);
|
||||
}
|
||||
else if ((mt = UI_but_menutype_get(but))) {
|
||||
ED_screen_user_menu_item_add_menu(&um->items, drawstr.c_str(), mt);
|
||||
|
|
|
@ -1001,13 +1001,12 @@ static void ui_apply_but_autokey(bContext *C, uiBut *but)
|
|||
}
|
||||
|
||||
/* make a little report about what we've done! */
|
||||
char *buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
|
||||
if (buf) {
|
||||
BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
|
||||
MEM_freeN(buf);
|
||||
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr);
|
||||
const std::string str = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
|
||||
if (str.empty()) {
|
||||
return;
|
||||
}
|
||||
BKE_report(CTX_wm_reports(C), RPT_PROPERTY, str.c_str());
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr);
|
||||
}
|
||||
|
||||
static void ui_apply_but_funcs_after(bContext *C)
|
||||
|
@ -2734,12 +2733,10 @@ static void ui_but_paste_CurveProfile(bContext *C, uiBut *but)
|
|||
|
||||
static void ui_but_copy_operator(bContext *C, uiBut *but, char *output, int output_maxncpy)
|
||||
{
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(but);
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(but);
|
||||
|
||||
char *str;
|
||||
str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
|
||||
BLI_strncpy(output, str, output_maxncpy);
|
||||
MEM_freeN(str);
|
||||
std::string str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
|
||||
BLI_strncpy(output, str.c_str(), output_maxncpy);
|
||||
}
|
||||
|
||||
static bool ui_but_copy_menu(uiBut *but, char *output, int output_maxncpy)
|
||||
|
|
|
@ -1286,7 +1286,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout,
|
|||
|
||||
/* assign properties */
|
||||
if (properties || r_opptr) {
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(but);
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(but);
|
||||
if (properties) {
|
||||
opptr->data = properties;
|
||||
}
|
||||
|
@ -6287,25 +6287,23 @@ static void ui_layout_introspect_button(DynStr *ds, uiButtonItem *bitem)
|
|||
BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : "");
|
||||
|
||||
if (but->optype) {
|
||||
char *opstr = WM_operator_pystring_ex(static_cast<bContext *>(but->block->evil_C),
|
||||
nullptr,
|
||||
false,
|
||||
true,
|
||||
but->optype,
|
||||
but->opptr);
|
||||
BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
|
||||
MEM_freeN(opstr);
|
||||
std::string opstr = WM_operator_pystring_ex(static_cast<bContext *>(but->block->evil_C),
|
||||
nullptr,
|
||||
false,
|
||||
true,
|
||||
but->optype,
|
||||
but->opptr);
|
||||
BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
PropertyRNA *prop = nullptr;
|
||||
wmOperatorType *ot = UI_but_operatortype_get_from_enum_menu(but, &prop);
|
||||
if (ot) {
|
||||
char *opstr = WM_operator_pystring_ex(
|
||||
std::string opstr = WM_operator_pystring_ex(
|
||||
static_cast<bContext *>(but->block->evil_C), nullptr, false, true, ot, nullptr);
|
||||
BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
|
||||
BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr.c_str());
|
||||
BLI_dynstr_appendf(ds, "'property':'''%s''', ", prop ? RNA_property_identifier(prop) : "");
|
||||
MEM_freeN(opstr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6396,12 +6394,12 @@ const char *UI_layout_introspect(uiLayout *layout)
|
|||
/** \name Alert Box with Big Icon
|
||||
* \{ */
|
||||
|
||||
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
|
||||
uiLayout *uiItemsAlertBox(uiBlock *block,
|
||||
const uiStyle *style,
|
||||
const int dialog_width,
|
||||
const eAlertIcon icon,
|
||||
const int icon_size)
|
||||
{
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
const short icon_size = 64 * UI_SCALE_FAC;
|
||||
const int text_points_max = std::max(style->widget.points, style->widgetlabel.points);
|
||||
const int dialog_width = icon_size + (text_points_max * size * UI_SCALE_FAC);
|
||||
/* By default, the space between icon and text/buttons will be equal to the 'columnspace',
|
||||
* this extra padding will add some space by increasing the left column width,
|
||||
* making the icon placement more symmetrical, between the block edge and the text. */
|
||||
|
@ -6428,4 +6426,13 @@ uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
|
|||
return layout;
|
||||
}
|
||||
|
||||
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
|
||||
{
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
const short icon_size = 64 * UI_SCALE_FAC;
|
||||
const int text_points_max = std::max(style->widget.points, style->widgetlabel.points);
|
||||
const int dialog_width = icon_size + (text_points_max * size * UI_SCALE_FAC);
|
||||
return uiItemsAlertBox(block, style, dialog_width, icon, icon_size);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -283,15 +283,12 @@ static int copy_python_command_button_exec(bContext *C, wmOperator * /*op*/)
|
|||
uiBut *but = UI_context_active_but_get(C);
|
||||
|
||||
if (but && (but->optype != nullptr)) {
|
||||
PointerRNA *opptr;
|
||||
char *str;
|
||||
opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
|
||||
/* allocated when needed, the button owns it */
|
||||
PointerRNA *opptr = UI_but_operator_ptr_ensure(but);
|
||||
|
||||
str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
|
||||
std::string str = WM_operator_pystring_ex(C, nullptr, false, true, but->optype, opptr);
|
||||
|
||||
WM_clipboard_text_set(str, false);
|
||||
|
||||
MEM_freeN(str);
|
||||
WM_clipboard_text_set(str.c_str(), false);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
|
|
@ -347,14 +347,14 @@ static void ui_tooltip_region_free_cb(ARegion *region)
|
|||
/** \name ToolTip Creation Utility Functions
|
||||
* \{ */
|
||||
|
||||
static char *ui_tooltip_text_python_from_op(bContext *C, wmOperatorType *ot, PointerRNA *opptr)
|
||||
static std::string ui_tooltip_text_python_from_op(bContext *C,
|
||||
wmOperatorType *ot,
|
||||
PointerRNA *opptr)
|
||||
{
|
||||
char *str = WM_operator_pystring_ex(C, nullptr, false, false, ot, opptr);
|
||||
std::string str = WM_operator_pystring_ex(C, nullptr, false, false, ot, opptr);
|
||||
|
||||
/* Avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary. */
|
||||
WM_operator_pystring_abbreviate(str, 32);
|
||||
|
||||
return str;
|
||||
return WM_operator_pystring_abbreviate(std::move(str), 32);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -397,10 +397,9 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
|
|||
|
||||
/* Python. */
|
||||
if (U.flag & USER_TOOLTIPS_PYTHON) {
|
||||
char *str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr);
|
||||
std::string str = ui_tooltip_text_python_from_op(C, ot, kmi->ptr);
|
||||
UI_tooltip_text_field_add(
|
||||
data, fmt::format(TIP_("Python: {}"), str), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_PYTHON);
|
||||
MEM_freeN(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -744,14 +743,13 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
|
|||
|
||||
/* Python */
|
||||
if ((is_label == false) && (U.flag & USER_TOOLTIPS_PYTHON)) {
|
||||
char *str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr);
|
||||
std::string str = ui_tooltip_text_python_from_op(C, but->optype, but->opptr);
|
||||
UI_tooltip_text_field_add(data,
|
||||
fmt::format(TIP_("Python: {}"), str),
|
||||
{},
|
||||
UI_TIP_STYLE_NORMAL,
|
||||
UI_TIP_LC_PYTHON,
|
||||
true);
|
||||
MEM_freeN(str);
|
||||
}
|
||||
|
||||
/* Keymap */
|
||||
|
@ -847,7 +845,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
|
|||
but_tip_label = UI_but_string_get_tooltip_label(*but);
|
||||
but_tip = UI_but_string_get_tooltip(*C, *but);
|
||||
enum_label = enum_item ? enum_item->name : "";
|
||||
enum_tip = enum_item ? enum_item->description : "";
|
||||
const char *description_c = enum_item ? enum_item->description : nullptr;
|
||||
enum_tip = description_c ? description_c : "";
|
||||
if (!is_menu) {
|
||||
op_keymap = UI_but_string_get_operator_keymap(*C, *but);
|
||||
prop_keymap = UI_but_string_get_property_keymap(*C, *but);
|
||||
|
@ -979,12 +978,12 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
|
|||
else if (optype) {
|
||||
PointerRNA *opptr = extra_icon ? UI_but_extra_operator_icon_opptr_get(extra_icon) :
|
||||
/* Allocated when needed, the button owns it. */
|
||||
UI_but_operator_ptr_get(but);
|
||||
UI_but_operator_ptr_ensure(but);
|
||||
|
||||
/* So the context is passed to field functions (some Python field functions use it). */
|
||||
WM_operator_properties_sanitize(opptr, false);
|
||||
|
||||
char *str = ui_tooltip_text_python_from_op(C, optype, opptr);
|
||||
std::string str = ui_tooltip_text_python_from_op(C, optype, opptr);
|
||||
|
||||
/* Operator info. */
|
||||
if (U.flag & USER_TOOLTIPS_PYTHON) {
|
||||
|
@ -995,8 +994,6 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
|
|||
UI_TIP_LC_PYTHON,
|
||||
true);
|
||||
}
|
||||
|
||||
MEM_freeN(str);
|
||||
}
|
||||
|
||||
/* Button is disabled, we may be able to tell user why. */
|
||||
|
|
|
@ -1534,7 +1534,7 @@ static void template_ID(const bContext *C,
|
|||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
TIP_("Packed File, click to unpack"));
|
||||
UI_but_operator_ptr_get(but);
|
||||
UI_but_operator_ptr_ensure(but);
|
||||
|
||||
RNA_string_set(but->opptr, "id_name", id->name + 2);
|
||||
RNA_int_set(but->opptr, "id_type", GS(id->name));
|
||||
|
@ -5911,7 +5911,7 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
|
|||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
nullptr);
|
||||
UI_but_operator_ptr_get(but);
|
||||
UI_but_operator_ptr_ensure(but);
|
||||
RNA_enum_set(but->opptr, "type", -1);
|
||||
|
||||
but = uiDefIconButO(block,
|
||||
|
@ -5924,7 +5924,7 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
|
|||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
nullptr);
|
||||
UI_but_operator_ptr_get(but);
|
||||
UI_but_operator_ptr_ensure(but);
|
||||
RNA_enum_set(but->opptr, "type", 1);
|
||||
|
||||
/* Menu. */
|
||||
|
|
|
@ -37,6 +37,7 @@ set(SRC
|
|||
io_ply_ops.cc
|
||||
io_stl_ops.cc
|
||||
io_usd.cc
|
||||
io_utils.cc
|
||||
|
||||
io_alembic.hh
|
||||
io_cache.hh
|
||||
|
@ -48,6 +49,7 @@ set(SRC
|
|||
io_ply_ops.hh
|
||||
io_stl_ops.hh
|
||||
io_usd.hh
|
||||
io_utils.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
# include "DNA_space_types.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.h"
|
||||
|
||||
|
@ -52,6 +53,7 @@
|
|||
# include "DEG_depsgraph.hh"
|
||||
|
||||
# include "io_alembic.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
# include "ABC_alembic.h"
|
||||
|
||||
|
@ -595,7 +597,7 @@ static int wm_alembic_import_invoke(bContext *C, wmOperator *op, const wmEvent *
|
|||
if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) {
|
||||
RNA_boolean_set(op->ptr, "as_background_job", true);
|
||||
}
|
||||
return WM_operator_filesel(C, op, event);
|
||||
return blender::ed::io::filesel_drop_import_invoke(C, op, event);
|
||||
}
|
||||
|
||||
static int wm_alembic_import_exec(bContext *C, wmOperator *op)
|
||||
|
@ -651,7 +653,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
|
|||
ot->name = "Import Alembic";
|
||||
ot->description = "Load an Alembic archive";
|
||||
ot->idname = "WM_OT_alembic_import";
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = wm_alembic_import_invoke;
|
||||
ot->exec = wm_alembic_import_exec;
|
||||
|
@ -716,4 +718,17 @@ void WM_OT_alembic_import(wmOperatorType *ot)
|
|||
"to run as a background job");
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void alembic_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_alembic");
|
||||
STRNCPY(fh->import_operator, "WM_OT_alembic_import");
|
||||
STRNCPY(fh->label, "Alembic");
|
||||
STRNCPY(fh->file_extensions_str, ".abc");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,3 +12,7 @@ struct wmOperatorType;
|
|||
|
||||
void WM_OT_alembic_export(wmOperatorType *ot);
|
||||
void WM_OT_alembic_import(wmOperatorType *ot);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void alembic_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
# include "BLT_translation.h"
|
||||
|
||||
# include "BLI_blenlib.h"
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_utildefines.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_object.hh"
|
||||
# include "BKE_report.h"
|
||||
|
@ -22,6 +24,7 @@
|
|||
|
||||
# include "ED_fileselect.hh"
|
||||
# include "ED_object.hh"
|
||||
# include "ED_outliner.hh"
|
||||
|
||||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
|
@ -35,6 +38,7 @@
|
|||
# include "collada.h"
|
||||
|
||||
# include "io_collada.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
|
@ -750,6 +754,11 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
|
|||
|
||||
if (collada_import(C, &import_settings)) {
|
||||
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -757,7 +766,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
|
||||
static void wm_collada_import_settings(uiLayout *layout, PointerRNA *imfptr)
|
||||
{
|
||||
uiLayout *box, *col;
|
||||
|
||||
|
@ -787,7 +796,7 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
|
|||
|
||||
static void wm_collada_import_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
uiCollada_importSettings(op->layout, op->ptr);
|
||||
wm_collada_import_settings(op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_collada_import(wmOperatorType *ot)
|
||||
|
@ -795,9 +804,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
|
|||
ot->name = "Import COLLADA";
|
||||
ot->description = "Load a Collada file";
|
||||
ot->idname = "WM_OT_collada_import";
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = WM_operator_filesel;
|
||||
ot->invoke = blender::ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_collada_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
|
||||
|
@ -862,4 +871,18 @@ void WM_OT_collada_import(wmOperatorType *ot)
|
|||
"Keep Bind Info",
|
||||
"Store Bindpose information in custom bone properties for later use during Collada export");
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void collada_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_collada");
|
||||
STRNCPY(fh->import_operator, "WM_OT_collada_import");
|
||||
STRNCPY(fh->label, "Collada");
|
||||
STRNCPY(fh->file_extensions_str, ".dae");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,3 +12,7 @@ struct wmOperatorType;
|
|||
|
||||
void WM_OT_collada_export(wmOperatorType *ot);
|
||||
void WM_OT_collada_import(wmOperatorType *ot);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void collada_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -24,3 +24,7 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot);
|
|||
|
||||
ARegion *get_invoke_region(bContext *C);
|
||||
View3D *get_invoke_view3d(bContext *C);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void gpencil_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifdef WITH_IO_GPENCIL
|
||||
|
||||
# include "BLI_path_util.h"
|
||||
# include "BLI_string.h"
|
||||
|
||||
# include "MEM_guardedalloc.h"
|
||||
|
||||
|
@ -16,6 +17,7 @@
|
|||
# include "DNA_space_types.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_gpencil_legacy.h"
|
||||
# include "BKE_report.h"
|
||||
|
||||
|
@ -36,6 +38,7 @@
|
|||
# include "ED_gpencil_legacy.hh"
|
||||
|
||||
# include "io_gpencil.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
# include "gpencil_io.h"
|
||||
|
||||
|
@ -55,13 +58,6 @@ static bool wm_gpencil_import_svg_common_check(bContext * /*C*/, wmOperator *op)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int wm_gpencil_import_svg_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
@ -136,7 +132,8 @@ static void ui_gpencil_import_svg_settings(uiLayout *layout, PointerRNA *imfptr)
|
|||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiLayout *col = uiLayoutColumn(layout, false);
|
||||
uiLayout *box = uiLayoutBox(layout);
|
||||
uiLayout *col = uiLayoutColumn(box, false);
|
||||
uiItemR(col, imfptr, "resolution", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, imfptr, "scale", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
@ -161,7 +158,7 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
|
|||
ot->description = "Import SVG into grease pencil";
|
||||
ot->idname = "WM_OT_gpencil_import_svg";
|
||||
|
||||
ot->invoke = wm_gpencil_import_svg_invoke;
|
||||
ot->invoke = blender::ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_gpencil_import_svg_exec;
|
||||
ot->poll = wm_gpencil_import_svg_poll;
|
||||
ot->ui = wm_gpencil_import_svg_draw;
|
||||
|
@ -197,4 +194,17 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
|
|||
100.0f);
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void gpencil_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_gpencil_svg");
|
||||
STRNCPY(fh->import_operator, "WM_OT_gpencil_import_svg");
|
||||
STRNCPY(fh->label, "SVG as Grease Pencil");
|
||||
STRNCPY(fh->file_extensions_str, ".svg");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif /* WITH_IO_GPENCIL */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# include "DNA_space_types.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.h"
|
||||
|
||||
|
@ -41,6 +42,7 @@
|
|||
# include "IO_wavefront_obj.hh"
|
||||
|
||||
# include "io_obj.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
|
||||
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
|
||||
|
@ -385,12 +387,6 @@ void WM_OT_obj_export(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int wm_obj_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
OBJImportParams import_params{};
|
||||
|
@ -485,9 +481,9 @@ void WM_OT_obj_import(wmOperatorType *ot)
|
|||
ot->name = "Import Wavefront OBJ";
|
||||
ot->description = "Load a Wavefront OBJ scene";
|
||||
ot->idname = "WM_OT_obj_import";
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = wm_obj_import_invoke;
|
||||
ot->invoke = blender::ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_obj_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_obj_import_draw;
|
||||
|
@ -559,4 +555,17 @@ void WM_OT_obj_import(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void obj_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_obj");
|
||||
STRNCPY(fh->import_operator, "WM_OT_obj_import");
|
||||
STRNCPY(fh->label, "Wavefront OBJ");
|
||||
STRNCPY(fh->file_extensions_str, ".obj");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif /* WITH_IO_WAVEFRONT_OBJ */
|
||||
|
|
|
@ -12,3 +12,7 @@ struct wmOperatorType;
|
|||
|
||||
void WM_OT_obj_export(wmOperatorType *ot);
|
||||
void WM_OT_obj_import(wmOperatorType *ot);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void obj_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -31,22 +31,27 @@
|
|||
|
||||
void ED_operatortypes_io()
|
||||
{
|
||||
using namespace blender;
|
||||
#ifdef WITH_COLLADA
|
||||
/* Collada operators: */
|
||||
WM_operatortype_append(WM_OT_collada_export);
|
||||
WM_operatortype_append(WM_OT_collada_import);
|
||||
ed::io::collada_file_handler_add();
|
||||
#endif
|
||||
#ifdef WITH_ALEMBIC
|
||||
WM_operatortype_append(WM_OT_alembic_import);
|
||||
WM_operatortype_append(WM_OT_alembic_export);
|
||||
ed::io::alembic_file_handler_add();
|
||||
#endif
|
||||
#ifdef WITH_USD
|
||||
WM_operatortype_append(WM_OT_usd_import);
|
||||
WM_operatortype_append(WM_OT_usd_export);
|
||||
ed::io::usd_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_GPENCIL
|
||||
WM_operatortype_append(WM_OT_gpencil_import_svg);
|
||||
ed::io::gpencil_file_handler_add();
|
||||
# ifdef WITH_PUGIXML
|
||||
WM_operatortype_append(WM_OT_gpencil_export_svg);
|
||||
# endif
|
||||
|
@ -64,16 +69,19 @@ void ED_operatortypes_io()
|
|||
#ifdef WITH_IO_WAVEFRONT_OBJ
|
||||
WM_operatortype_append(WM_OT_obj_export);
|
||||
WM_operatortype_append(WM_OT_obj_import);
|
||||
ed::io::obj_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_PLY
|
||||
WM_operatortype_append(WM_OT_ply_export);
|
||||
WM_operatortype_append(WM_OT_ply_import);
|
||||
ed::io::ply_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_STL
|
||||
WM_operatortype_append(WM_OT_stl_import);
|
||||
WM_operatortype_append(WM_OT_stl_export);
|
||||
ed::io::stl_file_handler_add();
|
||||
#endif
|
||||
WM_operatortype_append(WM_OT_drop_import_file);
|
||||
ED_dropbox_drop_import_file();
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
#ifdef WITH_IO_PLY
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.h"
|
||||
|
||||
# include "BLI_string.h"
|
||||
|
||||
# include "WM_api.hh"
|
||||
# include "WM_types.hh"
|
||||
|
||||
|
@ -37,6 +40,7 @@
|
|||
|
||||
# include "IO_ply.hh"
|
||||
# include "io_ply_ops.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
static const EnumPropertyItem ply_vertex_colors_mode[] = {
|
||||
{PLY_VERTEX_COLOR_NONE, "NONE", 0, "None", "Do not import/export color attributes"},
|
||||
|
@ -236,11 +240,6 @@ void WM_OT_ply_export(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static int wm_ply_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return WM_operator_filesel(C, op, event);
|
||||
}
|
||||
|
||||
static int wm_ply_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
PLYImportParams params{};
|
||||
|
@ -286,6 +285,26 @@ static int wm_ply_import_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ui_ply_import_settings(uiLayout *layout, PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
|
||||
uiLayout *box = uiLayoutBox(layout);
|
||||
uiLayout *col = uiLayoutColumn(box, false);
|
||||
uiItemR(col, ptr, "global_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_scene_unit", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "forward_axis", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "up_axis", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "merge_verts", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "import_colors", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
static void wm_ply_import_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
ui_ply_import_settings(op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_ply_import(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
@ -294,10 +313,11 @@ void WM_OT_ply_import(wmOperatorType *ot)
|
|||
ot->description = "Import an PLY file as an object";
|
||||
ot->idname = "WM_OT_ply_import";
|
||||
|
||||
ot->invoke = wm_ply_import_invoke;
|
||||
ot->invoke = blender::ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_ply_import_exec;
|
||||
ot->ui = wm_ply_import_draw;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER,
|
||||
|
@ -333,4 +353,17 @@ void WM_OT_ply_import(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void ply_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_ply");
|
||||
STRNCPY(fh->import_operator, "WM_OT_ply_import");
|
||||
STRNCPY(fh->label, "Stanford PLY");
|
||||
STRNCPY(fh->file_extensions_str, ".ply");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif /* WITH_IO_PLY */
|
||||
|
|
|
@ -12,3 +12,7 @@ struct wmOperatorType;
|
|||
|
||||
void WM_OT_ply_export(wmOperatorType *ot);
|
||||
void WM_OT_ply_import(wmOperatorType *ot);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void ply_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
#ifdef WITH_IO_STL
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_report.h"
|
||||
|
||||
# include "BLI_string.h"
|
||||
|
||||
# include "WM_api.hh"
|
||||
# include "WM_types.hh"
|
||||
|
||||
|
@ -29,6 +32,7 @@
|
|||
|
||||
# include "IO_stl.hh"
|
||||
# include "io_stl_ops.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
static int wm_stl_export_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
|
@ -175,11 +179,6 @@ void WM_OT_stl_export(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return WM_operator_filesel(C, op, event);
|
||||
}
|
||||
|
||||
static int wm_stl_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
STLImportParams params{};
|
||||
|
@ -237,6 +236,26 @@ static bool wm_stl_import_check(bContext * /*C*/, wmOperator *op)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void ui_stl_import_settings(uiLayout *layout, PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
|
||||
uiLayout *box = uiLayoutBox(layout);
|
||||
uiLayout *col = uiLayoutColumn(box, false);
|
||||
uiItemR(col, ptr, "global_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_scene_unit", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_facet_normal", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
|
||||
uiItemR(col, ptr, "up_axis", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_mesh_validate", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
static void wm_stl_import_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
ui_stl_import_settings(op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_stl_import(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
@ -245,11 +264,12 @@ void WM_OT_stl_import(wmOperatorType *ot)
|
|||
ot->description = "Import an STL file as an object";
|
||||
ot->idname = "WM_OT_stl_import";
|
||||
|
||||
ot->invoke = wm_stl_import_invoke;
|
||||
ot->invoke = blender::ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_stl_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->check = wm_stl_import_check;
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->ui = wm_stl_import_draw;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER,
|
||||
|
@ -284,4 +304,17 @@ void WM_OT_stl_import(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void stl_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_stl");
|
||||
STRNCPY(fh->import_operator, "WM_OT_stl_import");
|
||||
STRNCPY(fh->label, "STL");
|
||||
STRNCPY(fh->file_extensions_str, ".stl");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif /* WITH_IO_STL */
|
||||
|
|
|
@ -12,3 +12,7 @@ struct wmOperatorType;
|
|||
|
||||
void WM_OT_stl_export(wmOperatorType *ot);
|
||||
void WM_OT_stl_import(wmOperatorType *ot);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void stl_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# include <cstring>
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.h"
|
||||
|
||||
|
@ -42,6 +43,7 @@
|
|||
# include "DEG_depsgraph.hh"
|
||||
|
||||
# include "io_usd.hh"
|
||||
# include "io_utils.hh"
|
||||
# include "usd.h"
|
||||
|
||||
# include <cstdio>
|
||||
|
@ -457,7 +459,7 @@ static int wm_usd_import_invoke(bContext *C, wmOperator *op, const wmEvent *even
|
|||
options->as_background_job = true;
|
||||
op->customdata = options;
|
||||
|
||||
return WM_operator_filesel(C, op, event);
|
||||
return blender::ed::io::filesel_drop_import_invoke(C, op, event);
|
||||
}
|
||||
|
||||
static int wm_usd_import_exec(bContext *C, wmOperator *op)
|
||||
|
@ -603,7 +605,6 @@ static void wm_usd_import_draw(bContext * /*C*/, wmOperator *op)
|
|||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
|
||||
uiLayout *box = uiLayoutBox(layout);
|
||||
uiLayout *col = uiLayoutColumnWithHeading(box, true, IFACE_("Data Types"));
|
||||
uiItemR(col, ptr, "import_cameras", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
@ -672,7 +673,7 @@ void WM_OT_usd_import(wmOperatorType *ot)
|
|||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_usd_import_draw;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_USD,
|
||||
|
@ -827,4 +828,17 @@ void WM_OT_usd_import(wmOperatorType *ot)
|
|||
"Behavior when the name of an imported texture file conflicts with an existing file");
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void usd_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_usd");
|
||||
STRNCPY(fh->import_operator, "WM_OT_usd_import");
|
||||
STRNCPY(fh->label, "Universal Scene Description");
|
||||
STRNCPY(fh->file_extensions_str, ".usd;.usda;.usdc;.usdz");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif /* WITH_USD */
|
||||
|
|
|
@ -12,3 +12,6 @@ struct wmOperatorType;
|
|||
|
||||
void WM_OT_usd_export(wmOperatorType *ot);
|
||||
void WM_OT_usd_import(wmOperatorType *ot);
|
||||
namespace blender::ed::io {
|
||||
void usd_file_handler_add();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "ED_fileselect.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#include "io_utils.hh"
|
||||
|
||||
namespace blender::ed::io {
|
||||
|
||||
int filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent * /* event */)
|
||||
{
|
||||
|
||||
PropertyRNA *filepath_prop = RNA_struct_find_property(op->ptr, "filepath");
|
||||
PropertyRNA *directory_prop = RNA_struct_find_property(op->ptr, "directory");
|
||||
if ((filepath_prop && RNA_property_is_set(op->ptr, filepath_prop)) ||
|
||||
(directory_prop && RNA_property_is_set(op->ptr, directory_prop)))
|
||||
{
|
||||
return WM_operator_props_dialog_popup(C, op, 350);
|
||||
}
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
bool poll_file_object_drop(const bContext *C, blender::bke::FileHandlerType * /*fh*/)
|
||||
{
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
if (!region || region->regiontype != RGN_TYPE_WINDOW) {
|
||||
return false;
|
||||
}
|
||||
if (v3d) {
|
||||
return true;
|
||||
}
|
||||
if (space_outliner && space_outliner->outlinevis == SO_VIEW_LAYER) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace blender::ed::io
|
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
struct wmOperator;
|
||||
struct wmOperatorType;
|
||||
struct wmDrag;
|
||||
struct wmDropBox;
|
||||
|
||||
namespace blender::bke {
|
||||
struct FileHanlderType;
|
||||
} // namespace blender::bke
|
||||
|
||||
namespace blender::ed::io {
|
||||
/**
|
||||
* Shows a import dialog if the operator was invoked with filepath properties set,
|
||||
* otherwise invokes the file-select window.
|
||||
*/
|
||||
int filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent *event);
|
||||
|
||||
bool poll_file_object_drop(const bContext *C, blender::bke::FileHandlerType *fh);
|
||||
} // namespace blender::ed::io
|
|
@ -185,20 +185,34 @@ static bool is_constrained_by_radius(const Brush *br)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Fetch the propogation_steps value, preferring the brush level value over the global sculpt tool
|
||||
* value. */
|
||||
static int boundary_propagation_steps(const Sculpt *sd, const Brush *brush)
|
||||
{
|
||||
return brush && brush->automasking_flags &
|
||||
(BRUSH_AUTOMASKING_BOUNDARY_EDGES | BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) ?
|
||||
brush->automasking_boundary_edges_propagation_steps :
|
||||
sd->automasking_boundary_edges_propagation_steps;
|
||||
}
|
||||
|
||||
/* Determine if the given automasking settings require values to be precomputed and cached. */
|
||||
static bool needs_factors_cache(const Sculpt *sd, const Brush *brush)
|
||||
{
|
||||
|
||||
const int automasking_flags = calc_effective_bits(sd, brush);
|
||||
|
||||
if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY && brush && is_constrained_by_radius(brush)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (automasking_flags & (BRUSH_AUTOMASKING_BOUNDARY_EDGES |
|
||||
BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS | BRUSH_AUTOMASKING_VIEW_NORMAL))
|
||||
{
|
||||
if (automasking_flags & BRUSH_AUTOMASKING_VIEW_NORMAL) {
|
||||
return brush && brush->automasking_boundary_edges_propagation_steps != 1;
|
||||
}
|
||||
|
||||
if (automasking_flags &
|
||||
(BRUSH_AUTOMASKING_BOUNDARY_EDGES | BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS))
|
||||
{
|
||||
return boundary_propagation_steps(sd, brush) != 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -917,10 +931,6 @@ std::unique_ptr<Cache> cache_init(Sculpt *sd, Brush *brush, Object *ob)
|
|||
(*(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor)) = initial_value;
|
||||
}
|
||||
|
||||
const int boundary_propagation_steps = brush ?
|
||||
brush->automasking_boundary_edges_propagation_steps :
|
||||
1;
|
||||
|
||||
/* Additive modes. */
|
||||
if (mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) {
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
|
@ -934,13 +944,14 @@ std::unique_ptr<Cache> cache_init(Sculpt *sd, Brush *brush, Object *ob)
|
|||
init_face_sets_masking(sd, ob);
|
||||
}
|
||||
|
||||
const int steps = boundary_propagation_steps(sd, brush);
|
||||
if (mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
init_boundary_masking(ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps);
|
||||
init_boundary_masking(ob, AUTOMASK_INIT_BOUNDARY_EDGES, steps);
|
||||
}
|
||||
if (mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
init_boundary_masking(ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps);
|
||||
init_boundary_masking(ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, steps);
|
||||
}
|
||||
|
||||
/* Subtractive modes. */
|
||||
|
|
|
@ -1469,7 +1469,7 @@ static void file_draw_invalid_asset_library_hint(const bContext *C,
|
|||
UI_UNIT_X * 8,
|
||||
UI_UNIT_Y,
|
||||
nullptr);
|
||||
PointerRNA *but_opptr = UI_but_operator_ptr_get(but);
|
||||
PointerRNA *but_opptr = UI_but_operator_ptr_ensure(but);
|
||||
RNA_enum_set(but_opptr, "section", USER_SECTION_FILE_PATHS);
|
||||
|
||||
UI_block_end(C, block);
|
||||
|
|
|
@ -1415,7 +1415,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *panel)
|
|||
(x = UI_UNIT_X * 5),
|
||||
UI_UNIT_Y,
|
||||
"");
|
||||
but_ptr = UI_but_operator_ptr_get(but);
|
||||
but_ptr = UI_but_operator_ptr_ensure(but);
|
||||
RNA_int_set(but_ptr, "weight_group", i);
|
||||
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
|
||||
if (BKE_object_defgroup_active_index_get(ob) != i + 1) {
|
||||
|
|
|
@ -321,7 +321,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||
else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
t->options |= CTX_SEQUENCER_IMAGE;
|
||||
|
||||
/* Needed for autokeying transforms in preview during playback. */
|
||||
/* Needed for auto-keying transforms in preview during playback. */
|
||||
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
|
||||
t->animtimer = (animscreen) ? animscreen->animtimer : nullptr;
|
||||
}
|
||||
|
|
|
@ -88,9 +88,9 @@ class IndexedFaceSet : public Rep {
|
|||
* iTIndices
|
||||
* The Texture coordinates indices (per vertex). The integers contained in this array must
|
||||
* be multiple of 2. iTISize The size of iMIndices iCopy 0 : the arrays are not copied. The
|
||||
* pointers passed as arguments are used. IndexedFaceSet takes these arrays desallocation in
|
||||
* pointers passed as arguments are used. IndexedFaceSet takes these arrays deallocation in
|
||||
* charge. 1 : the arrays are copied. The caller is in charge of the arrays, passed as arguments
|
||||
* desallocation.
|
||||
* deallocation.
|
||||
*/
|
||||
IndexedFaceSet(float *iVertices,
|
||||
uint iVSize,
|
||||
|
|
|
@ -413,6 +413,15 @@ void ShaderCreateInfo::validate_vertex_attributes(const ShaderCreateInfo *other_
|
|||
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Disable optimization for this function with MSVC. It does not like the fact
|
||||
* shaders info are declared in the same function (same basic block or not does
|
||||
* not change anything).
|
||||
* Since it is just a function called to register shaders (once),
|
||||
* the fact it's optimized or not does not matter, it's not on any hot
|
||||
* code path. */
|
||||
# pragma optimize("", off)
|
||||
#endif
|
||||
void gpu_shader_create_info_init()
|
||||
{
|
||||
g_create_infos = new CreateInfoDictionnary();
|
||||
|
@ -553,6 +562,9 @@ void gpu_shader_create_info_init()
|
|||
/* TEST */
|
||||
// gpu_shader_create_info_compile(nullptr);
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
# pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
void gpu_shader_create_info_exit()
|
||||
{
|
||||
|
|
|
@ -266,6 +266,7 @@ enum eIMBInterpolationFilterMode {
|
|||
IMB_FILTER_BILINEAR,
|
||||
IMB_FILTER_CUBIC_BSPLINE,
|
||||
IMB_FILTER_CUBIC_MITCHELL,
|
||||
IMB_FILTER_BOX,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -651,8 +652,6 @@ enum eIMBTransformMode {
|
|||
* - Only one data type buffer will be used (rect_float has priority over rect)
|
||||
* \param mode: Cropping/Wrap repeat effect to apply during transformation.
|
||||
* \param filter: Interpolation to use during sampling.
|
||||
* \param num_subsamples: Number of subsamples to use. Increasing this would improve the quality,
|
||||
* but reduces the performance.
|
||||
* \param transform_matrix: Transformation matrix to use.
|
||||
* The given matrix should transform between dst pixel space to src pixel space.
|
||||
* One unit is one pixel.
|
||||
|
@ -667,7 +666,6 @@ void IMB_transform(const ImBuf *src,
|
|||
ImBuf *dst,
|
||||
eIMBTransformMode mode,
|
||||
eIMBInterpolationFilterMode filter,
|
||||
const int num_subsamples,
|
||||
const float transform_matrix[4][4],
|
||||
const rctf *src_crop);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "BLI_math_vector.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
@ -39,42 +38,21 @@ struct TransformContext {
|
|||
/* Source UV step delta, when moving along one destination pixel in Y axis. */
|
||||
float2 add_y;
|
||||
|
||||
/* Per-subsample source image delta UVs. */
|
||||
Vector<float2, 9> subsampling_deltas;
|
||||
|
||||
IndexRange dst_region_x_range;
|
||||
IndexRange dst_region_y_range;
|
||||
|
||||
/* Cropping region in source image pixel space. */
|
||||
rctf src_crop;
|
||||
|
||||
void init(const float4x4 &transform_matrix, const int num_subsamples, const bool has_source_crop)
|
||||
void init(const float4x4 &transform_matrix, const bool has_source_crop)
|
||||
{
|
||||
start_uv = transform_matrix.location().xy();
|
||||
add_x = transform_matrix.x_axis().xy();
|
||||
add_y = transform_matrix.y_axis().xy();
|
||||
init_subsampling(num_subsamples);
|
||||
init_destination_region(transform_matrix, has_source_crop);
|
||||
}
|
||||
|
||||
private:
|
||||
void init_subsampling(const int num_subsamples)
|
||||
{
|
||||
float2 subsample_add_x = add_x / num_subsamples;
|
||||
float2 subsample_add_y = add_y / num_subsamples;
|
||||
float2 offset_x = -add_x * 0.5f + subsample_add_x * 0.5f;
|
||||
float2 offset_y = -add_y * 0.5f + subsample_add_y * 0.5f;
|
||||
|
||||
for (int y : IndexRange(0, num_subsamples)) {
|
||||
for (int x : IndexRange(0, num_subsamples)) {
|
||||
float2 delta_uv = offset_x + offset_y;
|
||||
delta_uv += x * subsample_add_x;
|
||||
delta_uv += y * subsample_add_y;
|
||||
subsampling_deltas.append(delta_uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_destination_region(const float4x4 &transform_matrix, const bool has_source_crop)
|
||||
{
|
||||
if (!has_source_crop) {
|
||||
|
@ -265,27 +243,47 @@ template<eIMBInterpolationFilterMode Filter,
|
|||
bool WrapUV>
|
||||
static void process_scanlines(const TransformContext &ctx, IndexRange y_range)
|
||||
{
|
||||
/* Note: sample at pixel center for proper filtering. */
|
||||
float2 uv_start = ctx.start_uv + ctx.add_x * 0.5f + ctx.add_y * 0.5f;
|
||||
if constexpr (Filter == IMB_FILTER_BOX) {
|
||||
|
||||
if (ctx.subsampling_deltas.size() > 1) {
|
||||
/* Multiple samples per pixel: accumulate them pre-multiplied,
|
||||
* divide by sample count and write out (un-pre-multiplying if writing out
|
||||
* to byte image). */
|
||||
const float inv_count = 1.0f / ctx.subsampling_deltas.size();
|
||||
* to byte image).
|
||||
*
|
||||
* Do a box filter: for each destination pixel, accumulate XxY samples from source,
|
||||
* based on scaling factors (length of X/Y pixel steps). Use at least 2 samples
|
||||
* along each direction, so that in case of rotation the resulting edges get
|
||||
* some anti-aliasing, to match previous Subsampled3x3 filter behavior. The
|
||||
* "at least 2" can be removed once/if transform edge anti-aliasing is implemented
|
||||
* in general way for all filters. Use at most 100 samples along each direction,
|
||||
* just as some way of clamping possible upper cost. Scaling something down by more
|
||||
* than 100x should rarely if ever happen, worst case they will get some aliasing.
|
||||
*/
|
||||
float2 uv_start = ctx.start_uv;
|
||||
int sub_count_x = int(math::clamp(roundf(math::length(ctx.add_x)), 2.0f, 100.0f));
|
||||
int sub_count_y = int(math::clamp(roundf(math::length(ctx.add_y)), 2.0f, 100.0f));
|
||||
const float inv_count = 1.0f / (sub_count_x * sub_count_y);
|
||||
const float2 sub_step_x = ctx.add_x / sub_count_x;
|
||||
const float2 sub_step_y = ctx.add_y / sub_count_y;
|
||||
|
||||
for (int yi : y_range) {
|
||||
T *output = init_pixel_pointer<T>(ctx.dst, ctx.dst_region_x_range.first(), yi);
|
||||
float2 uv_row = uv_start + yi * ctx.add_y;
|
||||
for (int xi : ctx.dst_region_x_range) {
|
||||
float2 uv = uv_row + xi * ctx.add_x;
|
||||
const float2 uv = uv_row + xi * ctx.add_x;
|
||||
float sample[4] = {};
|
||||
|
||||
for (const float2 &delta_uv : ctx.subsampling_deltas) {
|
||||
const float2 sub_uv = uv + delta_uv;
|
||||
if (!CropSource || !should_discard(ctx, sub_uv)) {
|
||||
T sub_sample[4];
|
||||
sample_image<Filter, T, SrcChannels, WrapUV>(ctx.src, sub_uv.x, sub_uv.y, sub_sample);
|
||||
add_subsample(sub_sample, sample);
|
||||
for (int sub_y = 0; sub_y < sub_count_y; sub_y++) {
|
||||
for (int sub_x = 0; sub_x < sub_count_x; sub_x++) {
|
||||
float2 delta = (sub_x + 0.5f) * sub_step_x + (sub_y + 0.5f) * sub_step_y;
|
||||
float2 sub_uv = uv + delta;
|
||||
if (!CropSource || !should_discard(ctx, sub_uv)) {
|
||||
T sub_sample[4];
|
||||
sample_image<eIMBInterpolationFilterMode::IMB_FILTER_NEAREST,
|
||||
T,
|
||||
SrcChannels,
|
||||
WrapUV>(ctx.src, sub_uv.x, sub_uv.y, sub_sample);
|
||||
add_subsample(sub_sample, sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,7 +295,8 @@ static void process_scanlines(const TransformContext &ctx, IndexRange y_range)
|
|||
}
|
||||
}
|
||||
else {
|
||||
/* One sample per pixel. */
|
||||
/* One sample per pixel. Note: sample at pixel center for proper filtering. */
|
||||
float2 uv_start = ctx.start_uv + ctx.add_x * 0.5f + ctx.add_y * 0.5f;
|
||||
for (int yi : y_range) {
|
||||
T *output = init_pixel_pointer<T>(ctx.dst, ctx.dst_region_x_range.first(), yi);
|
||||
float2 uv_row = uv_start + yi * ctx.add_y;
|
||||
|
@ -369,7 +368,6 @@ void IMB_transform(const ImBuf *src,
|
|||
ImBuf *dst,
|
||||
const eIMBTransformMode mode,
|
||||
const eIMBInterpolationFilterMode filter,
|
||||
const int num_subsamples,
|
||||
const float transform_matrix[4][4],
|
||||
const rctf *src_crop)
|
||||
{
|
||||
|
@ -386,7 +384,7 @@ void IMB_transform(const ImBuf *src,
|
|||
if (crop) {
|
||||
ctx.src_crop = *src_crop;
|
||||
}
|
||||
ctx.init(blender::float4x4(transform_matrix), num_subsamples, crop);
|
||||
ctx.init(blender::float4x4(transform_matrix), crop);
|
||||
|
||||
threading::parallel_for(ctx.dst_region_y_range, 8, [&](IndexRange y_range) {
|
||||
if (filter == IMB_FILTER_NEAREST) {
|
||||
|
@ -401,5 +399,8 @@ void IMB_transform(const ImBuf *src,
|
|||
else if (filter == IMB_FILTER_CUBIC_MITCHELL) {
|
||||
transform_scanlines_filter<IMB_FILTER_CUBIC_MITCHELL>(ctx, y_range);
|
||||
}
|
||||
else if (filter == IMB_FILTER_BOX) {
|
||||
transform_scanlines_filter<IMB_FILTER_BOX>(ctx, y_range);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,29 +37,29 @@ static ImBuf *create_6x2_test_image()
|
|||
return img;
|
||||
}
|
||||
|
||||
static ImBuf *transform_2x_smaller(eIMBInterpolationFilterMode filter, int subsamples)
|
||||
static ImBuf *transform_2x_smaller(eIMBInterpolationFilterMode filter)
|
||||
{
|
||||
ImBuf *src = create_6x2_test_image();
|
||||
ImBuf *dst = IMB_allocImBuf(3, 1, 32, IB_rect);
|
||||
float4x4 matrix = math::from_scale<float4x4>(float4(2.0f));
|
||||
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, subsamples, matrix.ptr(), nullptr);
|
||||
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
|
||||
IMB_freeImBuf(src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static ImBuf *transform_fractional_larger(eIMBInterpolationFilterMode filter, int subsamples)
|
||||
static ImBuf *transform_fractional_larger(eIMBInterpolationFilterMode filter)
|
||||
{
|
||||
ImBuf *src = create_6x2_test_image();
|
||||
ImBuf *dst = IMB_allocImBuf(9, 7, 32, IB_rect);
|
||||
float4x4 matrix = math::from_scale<float4x4>(float4(6.0f / 9.0f, 2.0f / 7.0f, 1.0f, 1.0f));
|
||||
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, subsamples, matrix.ptr(), nullptr);
|
||||
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
|
||||
IMB_freeImBuf(src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
TEST(imbuf_transform, nearest_2x_smaller)
|
||||
{
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_NEAREST, 1);
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_NEAREST);
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0], ColorTheme4b(255, 255, 255, 255));
|
||||
EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 19));
|
||||
|
@ -67,19 +67,20 @@ TEST(imbuf_transform, nearest_2x_smaller)
|
|||
IMB_freeImBuf(res);
|
||||
}
|
||||
|
||||
TEST(imbuf_transform, nearest_subsample3_2x_smaller)
|
||||
TEST(imbuf_transform, box_2x_smaller)
|
||||
{
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_NEAREST, 3);
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_BOX);
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0], ColorTheme4b(227, 170, 113, 255));
|
||||
EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 17));
|
||||
EXPECT_EQ(got[2], ColorTheme4b(56, 22, 64, 253));
|
||||
/* At 2x reduction should be same as bilinear, save for some rounding errors. */
|
||||
EXPECT_EQ(got[0], ColorTheme4b(191, 128, 64, 255));
|
||||
EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 16));
|
||||
EXPECT_EQ(got[2], ColorTheme4b(54, 50, 48, 254));
|
||||
IMB_freeImBuf(res);
|
||||
}
|
||||
|
||||
TEST(imbuf_transform, bilinear_2x_smaller)
|
||||
{
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_BILINEAR, 1);
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_BILINEAR);
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0], ColorTheme4b(191, 128, 64, 255));
|
||||
EXPECT_EQ(got[1], ColorTheme4b(133, 55, 31, 16));
|
||||
|
@ -89,7 +90,7 @@ TEST(imbuf_transform, bilinear_2x_smaller)
|
|||
|
||||
TEST(imbuf_transform, cubic_bspline_2x_smaller)
|
||||
{
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_CUBIC_BSPLINE, 1);
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_CUBIC_BSPLINE);
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0], ColorTheme4b(189, 126, 62, 250));
|
||||
EXPECT_EQ(got[1], ColorTheme4b(134, 57, 33, 26));
|
||||
|
@ -99,7 +100,7 @@ TEST(imbuf_transform, cubic_bspline_2x_smaller)
|
|||
|
||||
TEST(imbuf_transform, cubic_mitchell_2x_smaller)
|
||||
{
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_CUBIC_MITCHELL, 1);
|
||||
ImBuf *res = transform_2x_smaller(IMB_FILTER_CUBIC_MITCHELL);
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0], ColorTheme4b(195, 130, 67, 255));
|
||||
EXPECT_EQ(got[1], ColorTheme4b(132, 51, 28, 0));
|
||||
|
@ -109,7 +110,7 @@ TEST(imbuf_transform, cubic_mitchell_2x_smaller)
|
|||
|
||||
TEST(imbuf_transform, cubic_mitchell_fractional_larger)
|
||||
{
|
||||
ImBuf *res = transform_fractional_larger(IMB_FILTER_CUBIC_MITCHELL, 1);
|
||||
ImBuf *res = transform_fractional_larger(IMB_FILTER_CUBIC_MITCHELL);
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0 + 0 * res->x], ColorTheme4b(0, 0, 0, 255));
|
||||
EXPECT_EQ(got[1 + 0 * res->x], ColorTheme4b(127, 0, 0, 255));
|
||||
|
@ -138,8 +139,7 @@ TEST(imbuf_transform, nearest_very_large_scale)
|
|||
ImBuf *res = IMB_allocImBuf(3841, 1, 32, IB_rect);
|
||||
float4x4 matrix = math::from_loc_rot_scale<float4x4>(
|
||||
float3(254, 0, 0), math::Quaternion::identity(), float3(3.0f / 3840.0f, 1, 1));
|
||||
IMB_transform(
|
||||
src, res, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, 1, matrix.ptr(), nullptr);
|
||||
IMB_transform(src, res, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, matrix.ptr(), nullptr);
|
||||
|
||||
/* Check result: leftmost red, middle green, two rightmost pixels blue and black.
|
||||
* If the transform code internally does not have enough precision while stepping
|
||||
|
|
|
@ -163,6 +163,8 @@ typedef struct BrushCurvesSculptSettings {
|
|||
struct CurveMapping *curve_parameter_falloff;
|
||||
} BrushCurvesSculptSettings;
|
||||
|
||||
/** Max number of propagation steps for automasking settings.*/
|
||||
#define AUTOMASKING_BOUNDARY_EDGES_MAX_PROPAGATION_STEPS 20
|
||||
typedef struct Brush {
|
||||
DNA_DEFINE_CXX_METHODS(Brush)
|
||||
|
||||
|
|
|
@ -835,7 +835,7 @@
|
|||
.factor = 1.0f, \
|
||||
.step = 1, \
|
||||
}
|
||||
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencilOffsetModifierData \
|
||||
{ \
|
||||
.flag = 0, \
|
||||
|
@ -847,4 +847,17 @@
|
|||
.stroke_start_offset = 0, \
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencilNoiseModifierData \
|
||||
{ \
|
||||
.flag = GP_NOISE_FULL_STROKE | GP_NOISE_USE_RANDOM, \
|
||||
.factor = 0.5f, \
|
||||
.factor_strength = 0.0f, \
|
||||
.factor_thickness = 0.0f, \
|
||||
.factor_uvs = 0.0f, \
|
||||
.noise_scale = 0.0f, \
|
||||
.noise_offset = 0.0f, \
|
||||
.step = 4, \
|
||||
.seed = 1, \
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
|
|
|
@ -99,6 +99,7 @@ typedef enum ModifierType {
|
|||
eModifierType_GreasePencilTint = 64,
|
||||
eModifierType_GreasePencilSmooth = 65,
|
||||
eModifierType_GreasePencilOffset = 66,
|
||||
eModifierType_GreasePencilNoise = 67,
|
||||
NUM_MODIFIER_TYPES,
|
||||
} ModifierType;
|
||||
|
||||
|
@ -2667,3 +2668,28 @@ typedef enum GreasePencilOffsetModifierMode {
|
|||
MOD_GREASE_PENCIL_OFFSET_MATERIAL = 2,
|
||||
MOD_GREASE_PENCIL_OFFSET_STROKE = 3,
|
||||
} GreasePencilOffsetModifierMode;
|
||||
|
||||
typedef struct GreasePencilNoiseModifierData {
|
||||
ModifierData modifier;
|
||||
GreasePencilModifierInfluenceData influence;
|
||||
|
||||
/** For convenience of versioning, these flags are kept in `eNoiseGpencil_Flag`. */
|
||||
int flag;
|
||||
|
||||
/** Factor of noise. */
|
||||
float factor;
|
||||
float factor_strength;
|
||||
float factor_thickness;
|
||||
float factor_uvs;
|
||||
/** Noise Frequency scaling */
|
||||
float noise_scale;
|
||||
float noise_offset;
|
||||
short noise_mode;
|
||||
char _pad[2];
|
||||
/** How many frames before recalculate randoms. */
|
||||
int step;
|
||||
/** Random seed */
|
||||
int seed;
|
||||
|
||||
void *_pad1;
|
||||
} GreasePencilNoiseModifierData;
|
||||
|
|
|
@ -1659,7 +1659,7 @@ typedef struct NodeEnumDefinition {
|
|||
NodeEnumItem *add_item(blender::StringRef name);
|
||||
bool remove_item(NodeEnumItem &item);
|
||||
void clear();
|
||||
bool move_item(uint16_t from_index, uint16_t to_index);
|
||||
bool move_item(int from_index, int to_index);
|
||||
|
||||
const NodeEnumItem *active_item() const;
|
||||
NodeEnumItem *active_item();
|
||||
|
|
|
@ -418,6 +418,7 @@
|
|||
.automasking_start_normal_falloff = 0.25f, \
|
||||
.automasking_view_normal_limit = 1.570796, /* 0.5 * pi. */ \
|
||||
.automasking_view_normal_falloff = 0.25f, \
|
||||
.automasking_boundary_edges_propagation_steps = 1, \
|
||||
.flags = SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE,\
|
||||
.paint = {\
|
||||
.symmetry_flags = PAINT_SYMMETRY_FEATHER,\
|
||||
|
|
|
@ -1114,9 +1114,9 @@ typedef struct Sculpt {
|
|||
float constant_detail;
|
||||
float detail_percent;
|
||||
|
||||
int automasking_boundary_edges_propagation_steps;
|
||||
int automasking_cavity_blur_steps;
|
||||
float automasking_cavity_factor;
|
||||
char _pad[4];
|
||||
|
||||
float automasking_start_normal_limit, automasking_start_normal_falloff;
|
||||
float automasking_view_normal_limit, automasking_view_normal_falloff;
|
||||
|
|
|
@ -838,7 +838,7 @@ typedef enum SequenceColorTag {
|
|||
enum {
|
||||
SEQ_TRANSFORM_FILTER_NEAREST = 0,
|
||||
SEQ_TRANSFORM_FILTER_BILINEAR = 1,
|
||||
SEQ_TRANSFORM_FILTER_NEAREST_3x3 = 2,
|
||||
SEQ_TRANSFORM_FILTER_BOX = 2,
|
||||
SEQ_TRANSFORM_FILTER_CUBIC_BSPLINE = 3,
|
||||
SEQ_TRANSFORM_FILTER_CUBIC_MITCHELL = 4,
|
||||
};
|
||||
|
|
|
@ -293,6 +293,7 @@ SDNA_DEFAULT_DECL_STRUCT(WeightVGProximityModifierData);
|
|||
SDNA_DEFAULT_DECL_STRUCT(WeldModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(WireframeModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilSubdivModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilNoiseModifierData);
|
||||
|
||||
/* Grease Pencil 3.0 modifiers. */
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilSmoothModifierData);
|
||||
|
@ -545,6 +546,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
|||
SDNA_DEFAULT_DECL(WeldModifierData),
|
||||
SDNA_DEFAULT_DECL(WireframeModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilSubdivModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilNoiseModifierData),
|
||||
|
||||
/* Grease Pencil 3.0 defaults. */
|
||||
SDNA_DEFAULT_DECL(GreasePencilSmoothModifierData),
|
||||
|
|
|
@ -3206,8 +3206,8 @@ static void rna_def_brush(BlenderRNA *brna)
|
|||
prop = RNA_def_property(
|
||||
srna, "automasking_boundary_edges_propagation_steps", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "automasking_boundary_edges_propagation_steps");
|
||||
RNA_def_property_range(prop, 1, 20);
|
||||
RNA_def_property_ui_range(prop, 1, 20, 1, 3);
|
||||
RNA_def_property_range(prop, 1, AUTOMASKING_BOUNDARY_EDGES_MAX_PROPAGATION_STEPS);
|
||||
RNA_def_property_ui_range(prop, 1, AUTOMASKING_BOUNDARY_EDGES_MAX_PROPAGATION_STEPS, 1, -1);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Propagation Steps",
|
||||
"Distance where boundary edge automasking is going to protect vertices "
|
||||
|
|
|
@ -306,6 +306,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
|||
ICON_MOD_OFFSET,
|
||||
"Offset",
|
||||
"Change stroke location, rotation, or scale"},
|
||||
{eModifierType_GreasePencilNoise,
|
||||
"GREASE_PENCIL_NOISE",
|
||||
ICON_MOD_NOISE,
|
||||
"Noise",
|
||||
"Generate noise wobble in grease pencil strokes"},
|
||||
|
||||
RNA_ENUM_ITEM_HEADING(N_("Physics"), nullptr),
|
||||
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
|
||||
|
@ -1829,12 +1834,14 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOpacity);
|
|||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilSubdiv);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilTint);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilSmooth);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilNoise);
|
||||
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilSubdiv);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilTint);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilSmooth);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilNoise);
|
||||
|
||||
static void rna_GreasePencilOpacityModifier_opacity_factor_range(
|
||||
PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax)
|
||||
|
@ -8129,6 +8136,97 @@ static void rna_def_modifier_grease_pencil_offset(BlenderRNA *brna)
|
|||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_grease_pencil_noise(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem modifier_noise_random_mode_items[] = {
|
||||
{GP_NOISE_RANDOM_STEP, "STEP", 0, "Steps", "Randomize every number of frames"},
|
||||
{GP_NOISE_RANDOM_KEYFRAME, "KEYFRAME", 0, "Keyframes", "Randomize on keyframes only"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilNoiseModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Grease Pencil Noise Modifier", "Noise effect modifier");
|
||||
RNA_def_struct_sdna(srna, "GreasePencilNoiseModifierData");
|
||||
RNA_def_struct_ui_icon(srna, ICON_MOD_NOISE);
|
||||
|
||||
rna_def_modifier_grease_pencil_layer_filter(srna);
|
||||
rna_def_modifier_grease_pencil_material_filter(
|
||||
srna, "rna_GreasePencilNoiseModifier_material_filter_set");
|
||||
rna_def_modifier_grease_pencil_vertex_group(
|
||||
srna, "rna_GreasePencilNoiseModifier_vertex_group_name_set");
|
||||
rna_def_modifier_grease_pencil_custom_curve(srna);
|
||||
|
||||
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 0);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_random_panel", 1);
|
||||
|
||||
RNA_define_lib_overridable(true);
|
||||
|
||||
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "factor");
|
||||
RNA_def_property_range(prop, 0.0, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
|
||||
RNA_def_property_ui_text(prop, "Offset Factor", "Amount of noise to apply");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "factor_strength", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "factor_strength");
|
||||
RNA_def_property_range(prop, 0.0, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
|
||||
RNA_def_property_ui_text(prop, "Strength Factor", "Amount of noise to apply to opacity");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "factor_thickness", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "factor_thickness");
|
||||
RNA_def_property_range(prop, 0.0, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
|
||||
RNA_def_property_ui_text(prop, "Thickness Factor", "Amount of noise to apply to thickness");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "factor_uvs", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "factor_uvs");
|
||||
RNA_def_property_range(prop, 0.0, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
|
||||
RNA_def_property_ui_text(prop, "UV Factor", "Amount of noise to apply to UV rotation");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_NOISE_USE_RANDOM);
|
||||
RNA_def_property_ui_text(prop, "Random", "Use random values over time");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_ui_text(prop, "Noise Seed", "Random seed");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "noise_scale");
|
||||
RNA_def_property_range(prop, 0.0, 1.0);
|
||||
RNA_def_property_ui_text(prop, "Noise Scale", "Scale the noise frequency");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "noise_offset", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "noise_offset");
|
||||
RNA_def_property_range(prop, 0.0, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
|
||||
RNA_def_property_ui_text(prop, "Noise Offset", "Offset the noise along the strokes");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "step");
|
||||
RNA_def_property_range(prop, 1, 100);
|
||||
RNA_def_property_ui_text(prop, "Step", "Number of frames between randomization steps");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "random_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "noise_mode");
|
||||
RNA_def_property_enum_items(prop, modifier_noise_random_mode_items);
|
||||
RNA_def_property_ui_text(prop, "Mode", "Where to perform randomization");
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
void RNA_def_modifier(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -8295,6 +8393,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
|||
rna_def_modifier_grease_pencil_tint(brna);
|
||||
rna_def_modifier_grease_pencil_smooth(brna);
|
||||
rna_def_modifier_grease_pencil_offset(brna);
|
||||
rna_def_modifier_grease_pencil_noise(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -425,7 +425,7 @@ const EnumPropertyItem *RNA_node_enum_definition_itemf(
|
|||
|
||||
for (const blender::bke::RuntimeNodeEnumItem &item : enum_items.items) {
|
||||
tmp.value = item.identifier;
|
||||
/* Item name is unique and used as the RNA identitifier as well.
|
||||
/* Item name is unique and used as the RNA identifier as well.
|
||||
* The integer value is persistent and unique and should be used
|
||||
* when storing the enum value. */
|
||||
tmp.identifier = item.name.c_str();
|
||||
|
|
|
@ -883,6 +883,17 @@ static void rna_def_sculpt(BlenderRNA *brna)
|
|||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
|
||||
} while ((++entry)->identifier);
|
||||
|
||||
prop = RNA_def_property(
|
||||
srna, "automasking_boundary_edges_propagation_steps", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "automasking_boundary_edges_propagation_steps");
|
||||
RNA_def_property_range(prop, 1, AUTOMASKING_BOUNDARY_EDGES_MAX_PROPAGATION_STEPS);
|
||||
RNA_def_property_ui_range(prop, 1, AUTOMASKING_BOUNDARY_EDGES_MAX_PROPAGATION_STEPS, 1, -1);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Propagation Steps",
|
||||
"Distance where boundary edge automasking is going to protect vertices "
|
||||
"from the fully masked edge");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "automasking_cavity_factor");
|
||||
RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask");
|
||||
|
|
|
@ -1726,11 +1726,11 @@ static const EnumPropertyItem transform_filter_items[] = {
|
|||
"Cubic B-Spline",
|
||||
"Cubic B-Spline filter (blurry but no ringing) on 4" BLI_STR_UTF8_MULTIPLICATION_SIGN
|
||||
"4 samples"},
|
||||
{SEQ_TRANSFORM_FILTER_NEAREST_3x3,
|
||||
"SUBSAMPLING_3x3",
|
||||
{SEQ_TRANSFORM_FILTER_BOX,
|
||||
"BOX",
|
||||
0,
|
||||
"Subsampling (3" BLI_STR_UTF8_MULTIPLICATION_SIGN "3)",
|
||||
"Use nearest with 3" BLI_STR_UTF8_MULTIPLICATION_SIGN "3 subsamples"},
|
||||
"Box",
|
||||
"Averages source image samples that fall under destination pixel"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
|
|
|
@ -209,10 +209,22 @@ static void rna_progress_end(wmWindowManager *wm)
|
|||
}
|
||||
|
||||
/* wrap these because of 'const wmEvent *' */
|
||||
static int rna_Operator_confirm(bContext *C, wmOperator *op, wmEvent *event)
|
||||
static int rna_Operator_confirm(bContext *C,
|
||||
wmOperator *op,
|
||||
wmEvent * /*event*/,
|
||||
const char *title,
|
||||
const char *message,
|
||||
const char *confirm_text,
|
||||
const int icon,
|
||||
const char *text_ctxt,
|
||||
const bool translate)
|
||||
{
|
||||
return WM_operator_confirm(C, op, event);
|
||||
title = RNA_translate_ui_text(title, text_ctxt, nullptr, nullptr, translate);
|
||||
message = RNA_translate_ui_text(message, text_ctxt, nullptr, nullptr, translate);
|
||||
confirm_text = RNA_translate_ui_text(confirm_text, text_ctxt, nullptr, nullptr, translate);
|
||||
return WM_operator_confirm_ex(C, op, title, message, confirm_text, icon);
|
||||
}
|
||||
|
||||
static int rna_Operator_props_popup(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
return WM_operator_props_popup(C, op, event);
|
||||
|
@ -788,6 +800,16 @@ void RNA_api_window(StructRNA *srna)
|
|||
RNA_def_function_return(func, parm);
|
||||
}
|
||||
|
||||
const EnumPropertyItem rna_operator_popup_icon_items[] = {
|
||||
{ALERT_ICON_NONE, "NONE", 0, "None", ""},
|
||||
{ALERT_ICON_WARNING, "WARNING", 0, "Warning", ""},
|
||||
{ALERT_ICON_QUESTION, "QUESTION", 0, "Question", ""},
|
||||
{ALERT_ICON_ERROR, "ERROR", 0, "Error", ""},
|
||||
{ALERT_ICON_INFO, "INFO", 0, "Info", ""},
|
||||
{ALERT_ICON_BLENDER, "BLENDER", 0, "Blender", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
void RNA_api_wm(StructRNA *srna)
|
||||
{
|
||||
FunctionRNA *func;
|
||||
|
@ -911,6 +933,24 @@ void RNA_api_wm(StructRNA *srna)
|
|||
"(only to let user confirm the execution, no operator properties shown)");
|
||||
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
|
||||
|
||||
parm = RNA_def_property(func, "title", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(parm, "Title", "Optional text to show as title of the popup");
|
||||
|
||||
parm = RNA_def_property(func, "message", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(parm, "Message", "Optional first line of content text");
|
||||
|
||||
parm = RNA_def_property(func, "confirm_text", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(
|
||||
parm,
|
||||
"Confirm Text",
|
||||
"Optional text to show instead to the default \"OK\" confirmation button text");
|
||||
|
||||
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(parm, rna_operator_popup_icon_items);
|
||||
RNA_def_property_ui_text(parm, "Icon", "Optional icon displayed in the dialog");
|
||||
|
||||
api_ui_item_common_translation(func);
|
||||
|
||||
/* wrap UI_popup_menu_begin */
|
||||
func = RNA_def_function(srna, "popmenu_begin__internal", "rna_PopMenuBegin");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
|
||||
|
|
|
@ -45,6 +45,7 @@ set(SRC
|
|||
intern/MOD_explode.cc
|
||||
intern/MOD_fluid.cc
|
||||
intern/MOD_grease_pencil_color.cc
|
||||
intern/MOD_grease_pencil_noise.cc
|
||||
intern/MOD_grease_pencil_offset.cc
|
||||
intern/MOD_grease_pencil_opacity.cc
|
||||
intern/MOD_grease_pencil_smooth.cc
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue