Geometry Nodes: make evaluation and logging system aware of zones #109029
|
@ -106,7 +106,8 @@ ExternalProject_Add(external_openimageio
|
|||
CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR}
|
||||
PREFIX ${BUILD_DIR}/openimageio
|
||||
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff &&
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff &&
|
||||
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_deadlock.diff
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS}
|
||||
INSTALL_DIR ${LIBDIR}/openimageio
|
||||
)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
diff -Naur orig/src/idiff/idiff.cpp external_openimageio/src/idiff/idiff.cpp
|
||||
--- orig/src/idiff/idiff.cpp 2023-06-07 07:47:42 -0600
|
||||
+++ external_openimageio/src/idiff/idiff.cpp 2023-06-07 09:46:47 -0600
|
||||
@@ -399,5 +399,6 @@
|
||||
|
||||
imagecache->invalidate_all(true);
|
||||
ImageCache::destroy(imagecache);
|
||||
+ default_thread_pool()->resize(0);
|
||||
return ret;
|
||||
}
|
||||
diff -Naur orig/src/libutil/thread.cpp external_openimageio/src/libutil/thread.cpp
|
||||
--- orig/src/libutil/thread.cpp 2023-06-07 07:47:42 -0600
|
||||
+++ external_openimageio/src/libutil/thread.cpp 2023-06-07 09:45:39 -0600
|
||||
@@ -151,9 +151,10 @@
|
||||
this->set_thread(i);
|
||||
}
|
||||
} else { // the number of threads is decreased
|
||||
+ std::vector<std::unique_ptr<std::thread>> terminating_threads;
|
||||
for (int i = oldNThreads - 1; i >= nThreads; --i) {
|
||||
*this->flags[i] = true; // this thread will finish
|
||||
- this->terminating_threads.push_back(
|
||||
+ terminating_threads.push_back(
|
||||
std::move(this->threads[i]));
|
||||
this->threads.erase(this->threads.begin() + i);
|
||||
}
|
||||
@@ -162,6 +163,11 @@
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_all();
|
||||
}
|
||||
+ // wait for the terminated threads to finish
|
||||
+ for (auto& thread : terminating_threads) {
|
||||
+ if (thread->joinable())
|
||||
+ thread->join();
|
||||
+ }
|
||||
this->threads.resize(
|
||||
nThreads); // safe to delete because the threads are detached
|
||||
this->flags.resize(
|
||||
@@ -238,16 +244,10 @@
|
||||
if (thread->joinable())
|
||||
thread->join();
|
||||
}
|
||||
- // wait for the terminated threads to finish
|
||||
- for (auto& thread : this->terminating_threads) {
|
||||
- if (thread->joinable())
|
||||
- thread->join();
|
||||
- }
|
||||
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
|
||||
// therefore delete them here
|
||||
this->clear_queue();
|
||||
this->threads.clear();
|
||||
- this->terminating_threads.clear();
|
||||
this->flags.clear();
|
||||
}
|
||||
|
||||
@@ -349,7 +349,6 @@
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<std::thread>> threads;
|
||||
- std::vector<std::unique_ptr<std::thread>> terminating_threads;
|
||||
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
|
||||
mutable pvt::ThreadsafeQueue<std::function<void(int id)>*> q;
|
||||
std::atomic<bool> isDone;
|
|
@ -873,6 +873,7 @@ static ShaderNode *add_node(Scene *scene,
|
|||
voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
|
||||
voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
|
||||
voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
|
||||
voronoi->set_normalize(b_voronoi_node.normalize());
|
||||
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
|
||||
get_tex_mapping(voronoi, b_texture_mapping);
|
||||
node = voronoi;
|
||||
|
|
|
@ -307,7 +307,12 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
|
|||
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
|
||||
*eta = CLOSURE_IS_REFRACTIVE(bsdf->type) ? 1.0f / bsdf->ior : bsdf->ior;
|
||||
if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) {
|
||||
*eta = 1.0f / bsdf->ior;
|
||||
}
|
||||
else {
|
||||
*eta = bsdf->ior;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
|
||||
|
@ -594,7 +599,9 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
|
|||
}
|
||||
|
||||
ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
||||
ccl_private const ShaderClosure *sc)
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const bool reflection,
|
||||
const bool transmission)
|
||||
{
|
||||
Spectrum albedo = sc->weight;
|
||||
/* Some closures include additional components such as Fresnel terms that cause their albedo to
|
||||
|
@ -608,12 +615,16 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
|||
* extra overhead though. */
|
||||
#if defined(__SVM__) || defined(__OSL__)
|
||||
if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
|
||||
albedo *= bsdf_microfacet_estimate_fresnel(sd, (ccl_private const MicrofacetBsdf *)sc);
|
||||
albedo *= bsdf_microfacet_estimate_fresnel(
|
||||
sd, (ccl_private const MicrofacetBsdf *)sc, reflection, transmission);
|
||||
}
|
||||
else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
|
||||
kernel_assert(reflection);
|
||||
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
|
||||
}
|
||||
else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
|
||||
/* TODO(lukas): Principled Hair could also be split into a glossy and a transmission component,
|
||||
* similar to Glass BSDFs. */
|
||||
albedo *= bsdf_principled_hair_albedo(sd, sc);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -338,17 +338,20 @@ ccl_device_inline void microfacet_ggx_preserve_energy(KernelGlobals kg,
|
|||
* For better results, we'd be blending between this and Fss based on roughness, but that
|
||||
* would involve storing or recomputing Fss, which is probably not worth it. */
|
||||
ccl_device Spectrum bsdf_microfacet_estimate_fresnel(ccl_private const ShaderData *sd,
|
||||
ccl_private const MicrofacetBsdf *bsdf)
|
||||
ccl_private const MicrofacetBsdf *bsdf,
|
||||
const bool reflection,
|
||||
const bool transmission)
|
||||
{
|
||||
const bool is_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool is_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
|
||||
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool m_reflection = !(m_refraction || m_glass);
|
||||
|
||||
Spectrum albedo = zero_spectrum();
|
||||
if (!is_refractive || is_glass) {
|
||||
if (reflection && (m_reflection || m_glass)) {
|
||||
/* BSDF has a reflective lobe. */
|
||||
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, false);
|
||||
}
|
||||
if (is_refractive) {
|
||||
if (transmission && (m_refraction || m_glass)) {
|
||||
/* BSDF has a refractive lobe (unless there's TIR). */
|
||||
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, true);
|
||||
}
|
||||
|
@ -455,8 +458,12 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
|||
}
|
||||
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const bool m_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
/* Refraction: Only consider BTDF
|
||||
* Glass: Consider both BRDF and BTDF, mix based on Fresnel
|
||||
* Reflection: Only consider BRDF */
|
||||
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
|
||||
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool m_reflection = !(m_refraction || m_glass);
|
||||
|
||||
const float3 N = bsdf->N;
|
||||
const float cos_NI = dot(N, wi);
|
||||
|
@ -466,7 +473,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
|||
const float alpha_x = bsdf->alpha_x;
|
||||
const float alpha_y = bsdf->alpha_y;
|
||||
|
||||
const bool is_refraction = (cos_NO < 0.0f);
|
||||
const bool is_transmission = (cos_NO < 0.0f);
|
||||
|
||||
/* Check whether the pair of directions is valid for evaluation:
|
||||
* - Incoming direction has to be in the upper hemisphere (Cycles convention)
|
||||
|
@ -475,15 +482,15 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
|||
* - Purely reflective closures can't have refraction.
|
||||
* - Purely refractive closures can't have reflection.
|
||||
*/
|
||||
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_refraction) ||
|
||||
(is_refraction && !m_refractive) || (!is_refraction && m_refractive && !m_glass))
|
||||
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_transmission) ||
|
||||
(is_transmission && m_reflection) || (!is_transmission && m_refraction))
|
||||
{
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
/* Compute half vector. */
|
||||
float3 H = is_refraction ? -(bsdf->ior * wo + wi) : (wi + wo);
|
||||
float3 H = is_transmission ? -(bsdf->ior * wo + wi) : (wi + wo);
|
||||
const float inv_len_H = 1.0f / len(H);
|
||||
H *= inv_len_H;
|
||||
|
||||
|
@ -491,7 +498,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
|||
float D, lambdaI, lambdaO;
|
||||
|
||||
/* TODO: add support for anisotropic transmission. */
|
||||
if (alpha_x == alpha_y || is_refraction) { /* Isotropic. */
|
||||
if (alpha_x == alpha_y || is_transmission) { /* Isotropic. */
|
||||
float alpha2 = alpha_x * alpha_y;
|
||||
|
||||
if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
|
||||
|
@ -523,19 +530,19 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
|
|||
}
|
||||
|
||||
float common = D / cos_NI *
|
||||
(is_refraction ? sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
|
||||
0.25f);
|
||||
(is_transmission ? sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
|
||||
0.25f);
|
||||
|
||||
float lobe_pdf = 1.0f;
|
||||
if (m_glass) {
|
||||
float fresnel = fresnel_dielectric_cos(dot(H, wi), bsdf->ior);
|
||||
float reflect_pdf = (fresnel == 1.0f) ? 1.0f : clamp(fresnel, 0.125f, 0.875f);
|
||||
lobe_pdf = is_refraction ? (1.0f - reflect_pdf) : reflect_pdf;
|
||||
lobe_pdf = is_transmission ? (1.0f - reflect_pdf) : reflect_pdf;
|
||||
}
|
||||
|
||||
*pdf = common * lobe_pdf / (1.0f + lambdaI);
|
||||
|
||||
const Spectrum F = microfacet_fresnel(bsdf, wi, H, is_refraction);
|
||||
const Spectrum F = microfacet_fresnel(bsdf, wi, H, is_transmission);
|
||||
return F * common / (1.0f + lambdaO + lambdaI);
|
||||
}
|
||||
|
||||
|
@ -554,7 +561,9 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
|||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
|
||||
const float m_eta = bsdf->ior;
|
||||
const bool m_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
|
||||
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool m_reflection = !(m_refraction || m_glass);
|
||||
const float alpha_x = bsdf->alpha_x;
|
||||
const float alpha_y = bsdf->alpha_y;
|
||||
bool m_singular = (m_type == MicrofacetType::SHARP) || (alpha_x * alpha_y <= 5e-7f);
|
||||
|
@ -564,7 +573,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
|||
if (cos_NI <= 0) {
|
||||
*eval = zero_spectrum();
|
||||
*pdf = 0.0f;
|
||||
return (m_refractive ? LABEL_TRANSMIT : LABEL_REFLECT) |
|
||||
return (m_reflection ? LABEL_REFLECT : LABEL_TRANSMIT) |
|
||||
(m_singular ? LABEL_SINGULAR : LABEL_GLOSSY);
|
||||
}
|
||||
|
||||
|
@ -603,13 +612,13 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
|||
bool valid;
|
||||
bool do_refract;
|
||||
float lobe_pdf;
|
||||
if (m_refractive) {
|
||||
if (m_refraction || m_glass) {
|
||||
bool inside;
|
||||
float fresnel = fresnel_dielectric(m_eta, H, wi, wo, &inside);
|
||||
valid = !inside;
|
||||
|
||||
/* For glass closures, we decide between reflection and refraction here. */
|
||||
if (CLOSURE_IS_GLASS(bsdf->type)) {
|
||||
if (m_glass) {
|
||||
if (fresnel == 1.0f) {
|
||||
/* TIR, reflection is the only option. */
|
||||
do_refract = false;
|
||||
|
@ -725,7 +734,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_conductor(KernelGlobals kg,
|
|||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
if (preserve_energy) {
|
||||
/* In order to estimate Fss of the conductor, we fit the F82-tint model to it based on the
|
||||
|
@ -748,7 +757,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
|
|||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
if (preserve_energy) {
|
||||
/* Assume that the transmissive tint makes up most of the overall color. */
|
||||
|
@ -765,7 +774,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
|
|||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
if (preserve_energy) {
|
||||
Spectrum Fss = one_spectrum();
|
||||
|
@ -852,7 +861,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
|
|||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
|
||||
bsdf->energy_scale = 1.0f;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals
|
|||
}
|
||||
}
|
||||
|
||||
Spectrum closure_albedo = bsdf_albedo(sd, sc);
|
||||
Spectrum closure_albedo = bsdf_albedo(sd, sc, true, true);
|
||||
if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) {
|
||||
diffuse_albedo += closure_albedo;
|
||||
sum_nonspecular_weight += sc->sample_weight;
|
||||
|
|
|
@ -20,36 +20,61 @@ CCL_NAMESPACE_BEGIN
|
|||
* them separately. */
|
||||
|
||||
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval,
|
||||
const ClosureType closure_type,
|
||||
const ShaderClosure *sc,
|
||||
const float3 wo,
|
||||
Spectrum value)
|
||||
{
|
||||
eval->diffuse = zero_spectrum();
|
||||
eval->glossy = zero_spectrum();
|
||||
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
eval->diffuse = value;
|
||||
}
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) {
|
||||
eval->glossy = value;
|
||||
}
|
||||
else if (CLOSURE_IS_GLASS(sc->type)) {
|
||||
/* Glass can count as glossy or transmission, depending on which side we end up on. */
|
||||
if (dot(sc->N, wo) > 0.0f) {
|
||||
eval->glossy = value;
|
||||
}
|
||||
}
|
||||
|
||||
eval->sum = value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval, Spectrum value)
|
||||
{
|
||||
eval->diffuse = zero_spectrum();
|
||||
eval->glossy = zero_spectrum();
|
||||
eval->sum = value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
|
||||
const ClosureType closure_type,
|
||||
const ShaderClosure *sc,
|
||||
const float3 wo,
|
||||
Spectrum value)
|
||||
{
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
eval->diffuse += value;
|
||||
}
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) {
|
||||
eval->glossy += value;
|
||||
}
|
||||
else if (CLOSURE_IS_GLASS(sc->type)) {
|
||||
if (dot(sc->N, wo) > 0.0f) {
|
||||
eval->glossy += value;
|
||||
}
|
||||
}
|
||||
|
||||
eval->sum += value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval, Spectrum value)
|
||||
{
|
||||
eval->sum += value;
|
||||
}
|
||||
|
||||
ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
|
||||
{
|
||||
return is_zero(eval->sum);
|
||||
|
|
|
@ -979,7 +979,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
|
|||
bool found_refractive_microfacet_bsdf = false;
|
||||
for (int ci = 0; ci < sd_mnee->num_closure; ci++) {
|
||||
ccl_private ShaderClosure *bsdf = &sd_mnee->closure[ci];
|
||||
if (CLOSURE_IS_REFRACTIVE(bsdf->type)) {
|
||||
if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) {
|
||||
/* Note that Glass closures are treated as refractive further below. */
|
||||
|
||||
found_refractive_microfacet_bsdf = true;
|
||||
|
|
|
@ -140,11 +140,12 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
|
|||
{
|
||||
/* Filter out closures. */
|
||||
if (kernel_data.integrator.filter_closures) {
|
||||
if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_EMISSION) {
|
||||
const int filter_closures = kernel_data.integrator.filter_closures;
|
||||
if (filter_closures & FILTER_CLOSURE_EMISSION) {
|
||||
sd->closure_emission_background = zero_spectrum();
|
||||
}
|
||||
|
||||
if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
|
||||
if (filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
|
||||
sd->flag &= ~SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
||||
|
@ -152,19 +153,20 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
|
|||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIFFUSE)) ||
|
||||
(CLOSURE_IS_BSDF_GLOSSY(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_GLOSSY)) ||
|
||||
(CLOSURE_IS_BSDF_TRANSMISSION(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSMISSION)))
|
||||
const bool filter_diffuse = (filter_closures & FILTER_CLOSURE_DIFFUSE);
|
||||
const bool filter_glossy = (filter_closures & FILTER_CLOSURE_GLOSSY);
|
||||
const bool filter_transmission = (filter_closures & FILTER_CLOSURE_TRANSMISSION);
|
||||
const bool filter_glass = filter_glossy && filter_transmission;
|
||||
if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) && filter_diffuse) ||
|
||||
(CLOSURE_IS_BSDF_GLOSSY(sc->type) && filter_glossy) ||
|
||||
(CLOSURE_IS_BSDF_TRANSMISSION(sc->type) && filter_transmission) ||
|
||||
(CLOSURE_IS_GLASS(sc->type) && filter_glass))
|
||||
{
|
||||
sc->type = CLOSURE_NONE_ID;
|
||||
sc->sample_weight = 0.0f;
|
||||
}
|
||||
else if ((CLOSURE_IS_BSDF_TRANSPARENT(sc->type) &&
|
||||
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSPARENT)))
|
||||
{
|
||||
(filter_closures & FILTER_CLOSURE_TRANSPARENT))) {
|
||||
sc->type = CLOSURE_HOLDOUT_ID;
|
||||
sc->sample_weight = 0.0f;
|
||||
sd->flag |= SD_HOLDOUT;
|
||||
|
@ -268,6 +270,13 @@ ccl_device_forceinline bool _surface_shader_exclude(ClosureType type, uint light
|
|||
return true;
|
||||
}
|
||||
}
|
||||
/* Glass closures are both glossy and transmissive, so only exclude them if both are filtered. */
|
||||
const uint exclude_glass = SHADER_EXCLUDE_TRANSMIT | SHADER_EXCLUDE_GLOSSY;
|
||||
if ((light_shader_flags & exclude_glass) == exclude_glass) {
|
||||
if (CLOSURE_IS_GLASS(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -295,7 +304,7 @@ ccl_device_inline float _surface_shader_bsdf_eval_mis(KernelGlobals kg,
|
|||
Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf);
|
||||
|
||||
if (bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_accum(result_eval, sc, wo, eval * sc->weight);
|
||||
sum_pdf += bsdf_pdf * sc->sample_weight;
|
||||
}
|
||||
}
|
||||
|
@ -318,7 +327,7 @@ ccl_device_inline float surface_shader_bsdf_eval_pdfs(const KernelGlobals kg,
|
|||
* factors drop out when using balance heuristic weighting. */
|
||||
float sum_pdf = 0.0f;
|
||||
float sum_sample_weight = 0.0f;
|
||||
bsdf_eval_init(result_eval, CLOSURE_NONE_ID, zero_spectrum());
|
||||
bsdf_eval_init(result_eval, zero_spectrum());
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
|
@ -328,7 +337,7 @@ ccl_device_inline float surface_shader_bsdf_eval_pdfs(const KernelGlobals kg,
|
|||
Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf);
|
||||
kernel_assert(bsdf_pdf >= 0.0f);
|
||||
if (bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_accum(result_eval, sc, wo, eval * sc->weight);
|
||||
sum_pdf += bsdf_pdf * sc->sample_weight;
|
||||
kernel_assert(bsdf_pdf * sc->sample_weight >= 0.0f);
|
||||
pdfs[i] = bsdf_pdf * sc->sample_weight;
|
||||
|
@ -369,7 +378,7 @@ ccl_device_inline
|
|||
ccl_private BsdfEval *bsdf_eval,
|
||||
const uint light_shader_flags)
|
||||
{
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, zero_spectrum());
|
||||
bsdf_eval_init(bsdf_eval, zero_spectrum());
|
||||
|
||||
float pdf = _surface_shader_bsdf_eval_mis(
|
||||
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
|
||||
|
@ -499,7 +508,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
|
|||
/* Initialize to zero. */
|
||||
int label = LABEL_NONE;
|
||||
Spectrum eval = zero_spectrum();
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
bsdf_eval_init(bsdf_eval, eval);
|
||||
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
float guide_pdf = 0.0f;
|
||||
|
@ -570,7 +579,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
|
|||
# endif
|
||||
|
||||
if (*unguided_bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
||||
|
@ -622,7 +631,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
|
|||
/* Initialize to zero. */
|
||||
int label = LABEL_NONE;
|
||||
Spectrum eval = zero_spectrum();
|
||||
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
bsdf_eval_init(bsdf_eval, eval);
|
||||
|
||||
*unguided_bsdf_pdf = 0.0f;
|
||||
float guide_pdf = 0.0f;
|
||||
|
@ -652,7 +661,8 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
|
|||
&ris_samples[0].sampled_roughness,
|
||||
&ris_samples[0].eta);
|
||||
|
||||
bsdf_eval_init(&ris_samples[0].bsdf_eval, sc->type, ris_samples[0].eval * sc->weight);
|
||||
bsdf_eval_init(
|
||||
&ris_samples[0].bsdf_eval, sc, ris_samples[0].wo, ris_samples[0].eval * sc->weight);
|
||||
if (ris_samples[0].bsdf_pdf > 0.0f) {
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
|
@ -679,7 +689,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
|
|||
// generate the second RIS candidate using a sample from the guiding distribution
|
||||
// ------------------------------------------------------------------------------
|
||||
float unguided_bsdf_pdfs[MAX_CLOSURE];
|
||||
bsdf_eval_init(&ris_samples[1].bsdf_eval, CLOSURE_NONE_ID, eval);
|
||||
bsdf_eval_init(&ris_samples[1].bsdf_eval, eval);
|
||||
ris_samples[1].guide_pdf = guiding_bsdf_sample(
|
||||
kg, state, float3_to_float2(ris_samples[1].rand), &ris_samples[1].wo);
|
||||
ris_samples[1].guide_pdf *= (1.0f - bssrdf_sampling_prob);
|
||||
|
@ -812,7 +822,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
|
|||
# endif
|
||||
|
||||
if (*unguided_bsdf_pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
|
||||
|
||||
|
@ -914,7 +924,7 @@ ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg,
|
|||
label = bsdf_sample(kg, sd, sc, path_flag, rand_bsdf, &eval, wo, pdf, sampled_roughness, eta);
|
||||
|
||||
if (*pdf != 0.0f) {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
|
||||
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
|
||||
|
||||
if (sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
|
@ -922,7 +932,7 @@ ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg,
|
|||
}
|
||||
}
|
||||
else {
|
||||
bsdf_eval_init(bsdf_eval, sc->type, zero_spectrum());
|
||||
bsdf_eval_init(bsdf_eval, zero_spectrum());
|
||||
}
|
||||
|
||||
return label;
|
||||
|
@ -994,7 +1004,7 @@ ccl_device Spectrum surface_shader_diffuse(KernelGlobals kg, ccl_private const S
|
|||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type))
|
||||
eval += bsdf_albedo(sd, sc);
|
||||
eval += bsdf_albedo(sd, sc, true, true);
|
||||
}
|
||||
|
||||
return eval;
|
||||
|
@ -1007,8 +1017,8 @@ ccl_device Spectrum surface_shader_glossy(KernelGlobals kg, ccl_private const Sh
|
|||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_GLOSSY(sc->type))
|
||||
eval += bsdf_albedo(sd, sc);
|
||||
if (CLOSURE_IS_BSDF_GLOSSY(sc->type) || CLOSURE_IS_GLASS(sc->type))
|
||||
eval += bsdf_albedo(sd, sc, true, false);
|
||||
}
|
||||
|
||||
return eval;
|
||||
|
@ -1021,8 +1031,8 @@ ccl_device Spectrum surface_shader_transmission(KernelGlobals kg, ccl_private co
|
|||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
|
||||
eval += bsdf_albedo(sd, sc);
|
||||
if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type) || CLOSURE_IS_GLASS(sc->type))
|
||||
eval += bsdf_albedo(sd, sc, false, true);
|
||||
}
|
||||
|
||||
return eval;
|
||||
|
|
|
@ -217,7 +217,7 @@ ccl_device_inline float _volume_shader_phase_eval_mis(ccl_private const ShaderDa
|
|||
Spectrum eval = volume_phase_eval(sd, svc, wo, &phase_pdf);
|
||||
|
||||
if (phase_pdf != 0.0f) {
|
||||
bsdf_eval_accum(result_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_accum(result_eval, eval);
|
||||
sum_pdf += phase_pdf * svc->sample_weight;
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
|
|||
Spectrum eval = volume_phase_eval(sd, svc, wo, &phase_pdf);
|
||||
|
||||
if (phase_pdf != 0.0f) {
|
||||
bsdf_eval_accum(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_accum(phase_eval, eval);
|
||||
}
|
||||
|
||||
return phase_pdf;
|
||||
|
@ -250,7 +250,7 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
|
|||
const float3 wo,
|
||||
ccl_private BsdfEval *phase_eval)
|
||||
{
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
|
||||
bsdf_eval_init(phase_eval, zero_spectrum());
|
||||
|
||||
float pdf = _volume_shader_phase_eval_mis(sd, phases, wo, -1, phase_eval, 0.0f, 0.0f);
|
||||
|
||||
|
@ -300,7 +300,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
|
|||
float guide_pdf = 0.0f;
|
||||
*sampled_roughness = 1.0f - fabsf(svc->g);
|
||||
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
|
||||
bsdf_eval_init(phase_eval, zero_spectrum());
|
||||
|
||||
if (sample_guiding) {
|
||||
/* Sample guiding distribution. */
|
||||
|
@ -320,7 +320,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
|
|||
label = volume_phase_sample(sd, svc, rand_phase, &eval, wo, unguided_phase_pdf);
|
||||
|
||||
if (*unguided_phase_pdf != 0.0f) {
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_init(phase_eval, eval);
|
||||
|
||||
*phase_pdf = *unguided_phase_pdf;
|
||||
if (use_volume_guiding) {
|
||||
|
@ -332,7 +332,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
|
|||
kernel_assert(reduce_min(bsdf_eval_sum(phase_eval)) >= 0.0f);
|
||||
}
|
||||
else {
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
|
||||
bsdf_eval_init(phase_eval, zero_spectrum());
|
||||
}
|
||||
|
||||
kernel_assert(reduce_min(bsdf_eval_sum(phase_eval)) >= 0.0f);
|
||||
|
@ -359,7 +359,7 @@ ccl_device int volume_shader_phase_sample(KernelGlobals kg,
|
|||
int label = volume_phase_sample(sd, svc, rand_phase, &eval, wo, pdf);
|
||||
|
||||
if (*pdf != 0.0f) {
|
||||
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
|
||||
bsdf_eval_init(phase_eval, eval);
|
||||
}
|
||||
|
||||
return label;
|
||||
|
|
|
@ -113,11 +113,13 @@ file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h)
|
|||
set(SRC_OSL_HEADERS
|
||||
node_color.h
|
||||
node_color_blend.h
|
||||
node_fractal_voronoi.h
|
||||
node_fresnel.h
|
||||
node_hash.h
|
||||
node_math.h
|
||||
node_noise.h
|
||||
node_ramp_util.h
|
||||
node_voronoi.h
|
||||
stdcycles.h
|
||||
${SRC_OSL_HEADER_DIST}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "node_voronoi.h"
|
||||
#include "stdcycles.h"
|
||||
#include "vector2.h"
|
||||
#include "vector4.h"
|
||||
|
||||
#define vector3 point
|
||||
|
||||
#define FRACTAL_VORONOI_X_FX(T) \
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.0; \
|
||||
float scale = 1.0; \
|
||||
\
|
||||
VoronoiOutput Output; \
|
||||
Output.Distance = 0.0; \
|
||||
Output.Color = color(0.0, 0.0, 0.0); \
|
||||
Output.Position = vector4(0.0, 0.0, 0.0, 0.0); \
|
||||
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
VoronoiOutput octave; \
|
||||
if (params.feature == "f1") { \
|
||||
octave = voronoi_f1(params, coord * scale); \
|
||||
} \
|
||||
else if (params.feature == "smooth_f1") { \
|
||||
octave = voronoi_smooth_f1(params, coord * scale); \
|
||||
} \
|
||||
else { \
|
||||
octave = voronoi_f2(params, coord * scale); \
|
||||
} \
|
||||
\
|
||||
if (zero_input) { \
|
||||
max_amplitude = 1.0; \
|
||||
Output = octave; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude += amplitude; \
|
||||
Output.Distance += octave.Distance * amplitude; \
|
||||
Output.Color += octave.Color * amplitude; \
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
|
||||
Output.Distance = mix( \
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
|
||||
Output.Position = mix(Output.Position, \
|
||||
mix(Output.Position, octave.Position / scale, amplitude), \
|
||||
remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
Output.Distance /= max_amplitude * params.max_distance; \
|
||||
Output.Color /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
Output.Position = safe_divide(Output.Position, params.scale); \
|
||||
\
|
||||
return Output; \
|
||||
}
|
||||
|
||||
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
|
||||
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.5 + 0.5 * params.randomness; \
|
||||
float scale = 1.0; \
|
||||
float distance = 8.0; \
|
||||
\
|
||||
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
|
||||
\
|
||||
if (zero_input) { \
|
||||
distance = octave_distance; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude = mix(max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
float lerp_amplitude = mix( \
|
||||
max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
|
||||
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
distance = mix(distance, min(distance, lerp_distance), remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
distance /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
return distance; \
|
||||
}
|
||||
|
||||
/* **** 1D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(float)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
|
||||
|
||||
/* **** 2D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector2)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector2)
|
||||
|
||||
/* **** 3D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector3)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector3)
|
||||
|
||||
/* **** 4D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector4)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector4)
|
|
@ -0,0 +1,920 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "node_hash.h"
|
||||
#include "stdcycles.h"
|
||||
#include "vector2.h"
|
||||
#include "vector4.h"
|
||||
|
||||
#define vector3 point
|
||||
|
||||
struct VoronoiParams {
|
||||
float scale;
|
||||
float detail;
|
||||
float roughness;
|
||||
float lacunarity;
|
||||
float smoothness;
|
||||
float exponent;
|
||||
float randomness;
|
||||
float max_distance;
|
||||
int normalize;
|
||||
string feature;
|
||||
string metric;
|
||||
};
|
||||
|
||||
struct VoronoiOutput {
|
||||
float Distance;
|
||||
color Color;
|
||||
vector4 Position;
|
||||
};
|
||||
|
||||
/* **** Distance Functions **** */
|
||||
|
||||
float distance(float a, float b)
|
||||
{
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
float distance(vector2 a, vector2 b)
|
||||
{
|
||||
return length(a - b);
|
||||
}
|
||||
|
||||
float distance(vector4 a, vector4 b)
|
||||
{
|
||||
return length(a - b);
|
||||
}
|
||||
|
||||
float voronoi_distance(float a, float b)
|
||||
{
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
float voronoi_distance(vector2 a, vector2 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a.x - b.x) + abs(a.y - b.y);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a.x - b.x), abs(a.y - b.y));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vector3 a, vector3 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a[0] - b[0]), params.exponent) + pow(abs(a[1] - b[1]), params.exponent) +
|
||||
pow(abs(a[2] - b[2]), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vector4 a, vector4 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
|
||||
pow(abs(a.z - b.z), params.exponent) + pow(abs(a.w - b.w), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* **** Safe Division **** */
|
||||
|
||||
vector2 safe_divide(vector2 a, float b)
|
||||
{
|
||||
return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
|
||||
}
|
||||
|
||||
vector4 safe_divide(vector4 a, float b)
|
||||
{
|
||||
return vector4((b != 0.0) ? a.x / b : 0.0,
|
||||
(b != 0.0) ? a.y / b : 0.0,
|
||||
(b != 0.0) ? a.z / b : 0.0,
|
||||
(b != 0.0) ? a.w / b : 0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Original code is copyright (c) 2013 Inigo Quilez.
|
||||
*
|
||||
* Smooth Voronoi:
|
||||
* - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
|
||||
*
|
||||
* Distance To Edge based on:
|
||||
*
|
||||
* - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
|
||||
* - https://www.shadertoy.com/view/ldl3W8
|
||||
*
|
||||
* With optimization to change -2..2 scan window to -1..1 for better performance,
|
||||
* as explained in https://www.shadertoy.com/view/llG3zy.
|
||||
*/
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(float coord)
|
||||
{
|
||||
return vector4(0.0, 0.0, 0.0, coord);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
float targetOffset = 0.0;
|
||||
float targetPosition = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_float_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
float smoothPosition = 0.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_float_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
float offsetF1 = 0.0;
|
||||
float positionF1 = 0.0;
|
||||
float offsetF2 = 0.0;
|
||||
float positionF2 = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_float_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
|
||||
float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * params.randomness;
|
||||
float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * params.randomness;
|
||||
float distanceToMidLeft = abs((midPointPosition + leftPointPosition) / 2.0 - localPosition);
|
||||
float distanceToMidRight = abs((midPointPosition + rightPointPosition) / 2.0 - localPosition);
|
||||
|
||||
return min(distanceToMidLeft, distanceToMidRight);
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float closestPoint = 0.0;
|
||||
float closestPointOffset = 0.0;
|
||||
float minDistance = 8.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(pointPosition - localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
float closestPointToClosestPoint = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
float cellOffset = i + closestPointOffset;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(closestPoint - pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
return abs(closestPointToClosestPoint - closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector2 coord)
|
||||
{
|
||||
return vector4(coord.x, coord.y, 0.0, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector2 targetOffset = vector2(0.0, 0.0);
|
||||
vector2 targetPosition = vector2(0.0, 0.0);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector2_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector2 smoothPosition = vector2(0.0, 0.0);
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector2_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector2 offsetF1 = vector2(0.0, 0.0);
|
||||
vector2 positionF1 = vector2(0.0, 0.0);
|
||||
vector2 offsetF2 = vector2(0.0, 0.0);
|
||||
vector2 positionF2 = vector2(0.0, 0.0);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector2_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
vector2 vectorToClosest = vector2(0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 vectorToPoint = cellOffset +
|
||||
hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 vectorToPoint = cellOffset +
|
||||
hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
vector2 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
|
||||
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
|
||||
normalize(perpendicularToEdge));
|
||||
minDistance = min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
vector2 closestPoint = vector2(0.0, 0.0);
|
||||
vector2 closestPointOffset = vector2(0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector2 closestPointToClosestPoint = vector2(0.0, 0.0);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0) {
|
||||
continue;
|
||||
}
|
||||
vector2 cellOffset = vector2(i, j) + closestPointOffset;
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector3 coord)
|
||||
{
|
||||
return vector4(coord.x, coord.y, coord.z, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector3 targetOffset = vector3(0.0, 0.0, 0.0);
|
||||
vector3 targetPosition = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector3_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector3 smoothPosition = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector3_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector3 offsetF1 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 positionF1 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 offsetF2 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 positionF2 = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector3_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
vector3 vectorToClosest = vector3(0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 vectorToPoint = cellOffset +
|
||||
hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 vectorToPoint = cellOffset +
|
||||
hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
|
||||
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
|
||||
normalize((vector)perpendicularToEdge));
|
||||
minDistance = min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
vector3 closestPoint = vector3(0.0, 0.0, 0.0);
|
||||
vector3 closestPointOffset = vector3(0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector3 closestPointToClosestPoint = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0 && k == 0) {
|
||||
continue;
|
||||
}
|
||||
vector3 cellOffset = vector3(i, j, k) + closestPointOffset;
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector4 coord)
|
||||
{
|
||||
return coord;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector4 targetOffset = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 targetPosition = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector4_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -2; u <= 2; u++) {
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector4_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 offsetF2 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 positionF2 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector4_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
vector4 vectorToClosest = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 vectorToPoint = cellOffset +
|
||||
hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 vectorToPoint = cellOffset +
|
||||
hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
vector4 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
|
||||
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
|
||||
normalize(perpendicularToEdge));
|
||||
minDistance = min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
vector4 closestPoint = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 closestPointOffset = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector4 closestPointToClosestPoint = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0 && k == 0 && u == 0) {
|
||||
continue;
|
||||
}
|
||||
vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset;
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -434,12 +434,14 @@ typedef enum ClosureType {
|
|||
CLOSURE_BSDF_REFRACTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
|
||||
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
/* Glass */
|
||||
CLOSURE_BSDF_SHARP_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
/* Special cases */
|
||||
CLOSURE_BSDF_TRANSPARENT_ID,
|
||||
|
@ -473,15 +475,15 @@ typedef enum ClosureType {
|
|||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
|
||||
#define CLOSURE_IS_BSDF_SINGULAR(type) \
|
||||
(type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \
|
||||
type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
type == CLOSURE_BSDF_TRANSPARENT_ID || type == CLOSURE_BSDF_SHARP_GLASS_ID)
|
||||
#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
|
||||
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
|
||||
type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_BSDF_MICROFACET(type) \
|
||||
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
|
||||
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
|
||||
((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) || \
|
||||
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
|
||||
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
|
||||
#define CLOSURE_IS_BSSRDF(type) \
|
||||
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
|
||||
|
@ -491,8 +493,8 @@ typedef enum ClosureType {
|
|||
#define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID)
|
||||
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
|
||||
#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
|
||||
#define CLOSURE_IS_REFRACTIVE(type) \
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_REFRACTION(type) \
|
||||
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)
|
||||
#define CLOSURE_IS_GLASS(type) \
|
||||
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1207,9 +1207,14 @@ NODE_DEFINE(VoronoiTextureNode)
|
|||
feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
|
||||
SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
|
||||
|
||||
SOCKET_BOOLEAN(normalize, "Normalize", false);
|
||||
|
||||
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
||||
SOCKET_IN_FLOAT(w, "W", 0.0f);
|
||||
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
|
||||
SOCKET_IN_FLOAT(detail, "Detail", 0.0f);
|
||||
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
|
||||
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
|
||||
SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
|
||||
SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
|
||||
SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
|
||||
|
@ -1230,6 +1235,9 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|||
ShaderInput *vector_in = input("Vector");
|
||||
ShaderInput *w_in = input("W");
|
||||
ShaderInput *scale_in = input("Scale");
|
||||
ShaderInput *detail_in = input("Detail");
|
||||
ShaderInput *roughness_in = input("Roughness");
|
||||
ShaderInput *lacunarity_in = input("Lacunarity");
|
||||
ShaderInput *smoothness_in = input("Smoothness");
|
||||
ShaderInput *exponent_in = input("Exponent");
|
||||
ShaderInput *randomness_in = input("Randomness");
|
||||
|
@ -1243,6 +1251,9 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|||
int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
|
||||
int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
|
||||
int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
|
||||
int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
|
||||
int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
|
||||
int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
|
||||
int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
|
||||
int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
|
||||
int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
|
||||
|
@ -1255,19 +1266,21 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|||
compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
|
||||
compiler.add_node(
|
||||
compiler.encode_uchar4(
|
||||
vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
|
||||
compiler.encode_uchar4(exponent_stack_offset,
|
||||
randomness_stack_offset,
|
||||
distance_stack_offset,
|
||||
color_stack_offset),
|
||||
compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
|
||||
__float_as_int(w));
|
||||
vector_stack_offset, w_in_stack_offset, scale_stack_offset, detail_stack_offset),
|
||||
compiler.encode_uchar4(roughness_stack_offset,
|
||||
lacunarity_stack_offset,
|
||||
smoothness_stack_offset,
|
||||
exponent_stack_offset),
|
||||
compiler.encode_uchar4(
|
||||
randomness_stack_offset, normalize, distance_stack_offset, color_stack_offset),
|
||||
compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset));
|
||||
|
||||
compiler.add_node(__float_as_int(scale),
|
||||
compiler.add_node(
|
||||
__float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
|
||||
compiler.add_node(__float_as_int(lacunarity),
|
||||
__float_as_int(smoothness),
|
||||
__float_as_int(exponent),
|
||||
__float_as_int(randomness));
|
||||
|
||||
tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
|
||||
}
|
||||
|
||||
|
@ -1278,6 +1291,7 @@ void VoronoiTextureNode::compile(OSLCompiler &compiler)
|
|||
compiler.parameter(this, "dimensions");
|
||||
compiler.parameter(this, "feature");
|
||||
compiler.parameter(this, "metric");
|
||||
compiler.parameter(this, "normalize");
|
||||
compiler.add(this, "node_voronoi_texture");
|
||||
}
|
||||
|
||||
|
|
|
@ -254,8 +254,12 @@ class VoronoiTextureNode : public TextureNode {
|
|||
NODE_SOCKET_API(int, dimensions)
|
||||
NODE_SOCKET_API(NodeVoronoiDistanceMetric, metric)
|
||||
NODE_SOCKET_API(NodeVoronoiFeature, feature)
|
||||
NODE_SOCKET_API(bool, normalize)
|
||||
NODE_SOCKET_API(float, w)
|
||||
NODE_SOCKET_API(float, scale)
|
||||
NODE_SOCKET_API(float, detail)
|
||||
NODE_SOCKET_API(float, roughness)
|
||||
NODE_SOCKET_API(float, lacunarity)
|
||||
NODE_SOCKET_API(float, exponent)
|
||||
NODE_SOCKET_API(float, smoothness)
|
||||
NODE_SOCKET_API(float, randomness)
|
||||
|
|
|
@ -224,6 +224,12 @@ ccl_device_inline float2 floor(const float2 a)
|
|||
|
||||
#endif /* !__KERNEL_METAL__ */
|
||||
|
||||
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
|
||||
ccl_device_inline float2 power(float2 v, float e)
|
||||
{
|
||||
return make_float2(powf(v.x, e), powf(v.y, e));
|
||||
}
|
||||
|
||||
ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
|
||||
{
|
||||
return (b != 0.0f) ? a / b : zero_float2();
|
||||
|
|
|
@ -469,7 +469,8 @@ ccl_device_inline bool isequal(const float3 a, const float3 b)
|
|||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline float3 pow(float3 v, float e)
|
||||
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
|
||||
ccl_device_inline float3 power(float3 v, float e)
|
||||
{
|
||||
return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
|
||||
}
|
||||
|
|
|
@ -593,7 +593,8 @@ ccl_device_inline float4 ensure_finite(float4 v)
|
|||
return v;
|
||||
}
|
||||
|
||||
ccl_device_inline float4 pow(float4 v, float e)
|
||||
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
|
||||
ccl_device_inline float4 power(float4 v, float e)
|
||||
{
|
||||
return make_float4(powf(v.x, e), powf(v.y, e), powf(v.z, e), powf(v.w, e));
|
||||
}
|
||||
|
|
|
@ -931,6 +931,8 @@ def km_user_interface(_params):
|
|||
("ui.reset_default_button", {"type": 'BACK_SPACE', "value": 'PRESS'}, {"properties": [("all", True)]}),
|
||||
# UI lists (polls check if there's a UI list under the cursor).
|
||||
("ui.list_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
|
||||
# UI views (polls check if there's a UI view under the cursor).
|
||||
("ui.view_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -4508,6 +4510,11 @@ def km_grease_pencil_edit(params):
|
|||
|
||||
items.extend([
|
||||
*_template_items_select_actions(params, "grease_pencil.select_all"),
|
||||
# Select linked
|
||||
("grease_pencil.select_linked", {"type": 'L', "value": 'PRESS'}, None),
|
||||
("grease_pencil.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||
("grease_pencil.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||
("grease_pencil.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -44,10 +44,9 @@ def geometry_modifier_poll(context):
|
|||
|
||||
|
||||
def get_context_modifier(context):
|
||||
# Context only has a 'modifier' attribute in the modifier extra operators dropdown.
|
||||
if hasattr(context, 'modifier'):
|
||||
modifier = context.modifier
|
||||
else:
|
||||
# Context only has a "modifier" attribute in the modifier extra operators drop-down.
|
||||
modifier = getattr(context, "modifier", ...)
|
||||
if modifier is ...:
|
||||
ob = context.object
|
||||
if ob is None:
|
||||
return False
|
||||
|
|
|
@ -2030,6 +2030,13 @@ class VIEW3D_MT_select_edit_gpencil(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("grease_pencil.select_linked", text="Linked")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("grease_pencil.select_more")
|
||||
layout.operator("grease_pencil.select_less")
|
||||
|
||||
|
||||
class VIEW3D_MT_select_paint_mask(Menu):
|
||||
bl_label = "Select"
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
#include "BLI_cpp_type.hh"
|
||||
#include "BLI_generic_span.hh"
|
||||
#include "BLI_generic_virtual_array.hh"
|
||||
#include "BLI_math_axis_angle.hh"
|
||||
#include "BLI_math_color.hh"
|
||||
#include "BLI_math_quaternion.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
|
@ -31,7 +33,8 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
|
|||
bool,
|
||||
int8_t,
|
||||
ColorGeometry4f,
|
||||
ColorGeometry4b>([&](auto type_tag) {
|
||||
ColorGeometry4b,
|
||||
math::Quaternion>([&](auto type_tag) {
|
||||
using T = typename decltype(type_tag)::type;
|
||||
if constexpr (std::is_same_v<T, void>) {
|
||||
/* It's expected that the given cpp type is one of the supported ones. */
|
||||
|
@ -400,7 +403,10 @@ class BooleanPropagationMixer {
|
|||
* This mixer accumulates values in a type that is different from the one that is mixed.
|
||||
* Some types cannot encode the floating point weights in their values (e.g. int and bool).
|
||||
*/
|
||||
template<typename T, typename AccumulationT, T (*ConvertToT)(const AccumulationT &value)>
|
||||
template<typename T,
|
||||
typename AccumulationT,
|
||||
AccumulationT (*ValueToAccumulate)(const T &value),
|
||||
T (*AccumulateToValue)(const AccumulationT &value)>
|
||||
class SimpleMixerWithAccumulationType {
|
||||
private:
|
||||
struct Item {
|
||||
|
@ -432,7 +438,7 @@ class SimpleMixerWithAccumulationType {
|
|||
|
||||
void set(const int64_t index, const T &value, const float weight = 1.0f)
|
||||
{
|
||||
const AccumulationT converted_value = static_cast<AccumulationT>(value);
|
||||
const AccumulationT converted_value = ValueToAccumulate(value);
|
||||
Item &item = accumulation_buffer_[index];
|
||||
item.value = converted_value * weight;
|
||||
item.weight = weight;
|
||||
|
@ -440,7 +446,7 @@ class SimpleMixerWithAccumulationType {
|
|||
|
||||
void mix_in(const int64_t index, const T &value, const float weight = 1.0f)
|
||||
{
|
||||
const AccumulationT converted_value = static_cast<AccumulationT>(value);
|
||||
const AccumulationT converted_value = ValueToAccumulate(value);
|
||||
Item &item = accumulation_buffer_[index];
|
||||
item.value += converted_value * weight;
|
||||
item.weight += weight;
|
||||
|
@ -457,7 +463,7 @@ class SimpleMixerWithAccumulationType {
|
|||
const Item &item = accumulation_buffer_[i];
|
||||
if (item.weight > 0.0f) {
|
||||
const float weight_inv = 1.0f / item.weight;
|
||||
const T converted_value = ConvertToT(item.value * weight_inv);
|
||||
const T converted_value = AccumulateToValue(item.value * weight_inv);
|
||||
buffer_[i] = converted_value;
|
||||
}
|
||||
else {
|
||||
|
@ -532,40 +538,68 @@ template<> struct DefaultMixerStruct<ColorGeometry4b> {
|
|||
using type = ColorGeometry4bMixer;
|
||||
};
|
||||
template<> struct DefaultMixerStruct<int> {
|
||||
static double int_to_double(const int &value)
|
||||
{
|
||||
return double(value);
|
||||
}
|
||||
static int double_to_int(const double &value)
|
||||
{
|
||||
return int(std::round(value));
|
||||
}
|
||||
/* Store interpolated ints in a double temporarily, so that weights are handled correctly. It
|
||||
* uses double instead of float so that it is accurate for all 32 bit integers. */
|
||||
using type = SimpleMixerWithAccumulationType<int, double, double_to_int>;
|
||||
using type = SimpleMixerWithAccumulationType<int, double, int_to_double, double_to_int>;
|
||||
};
|
||||
template<> struct DefaultMixerStruct<int2> {
|
||||
static double2 int_to_double(const int2 &value)
|
||||
{
|
||||
return double2(value);
|
||||
}
|
||||
static int2 double_to_int(const double2 &value)
|
||||
{
|
||||
return int2(math::round(value));
|
||||
}
|
||||
/* Store interpolated ints in a double temporarily, so that weights are handled correctly. It
|
||||
* uses double instead of float so that it is accurate for all 32 bit integers. */
|
||||
using type = SimpleMixerWithAccumulationType<int2, double2, double_to_int>;
|
||||
using type = SimpleMixerWithAccumulationType<int2, double2, int_to_double, double_to_int>;
|
||||
};
|
||||
template<> struct DefaultMixerStruct<bool> {
|
||||
static float bool_to_float(const bool &value)
|
||||
{
|
||||
return value ? 1.0f : 0.0f;
|
||||
}
|
||||
static bool float_to_bool(const float &value)
|
||||
{
|
||||
return value >= 0.5f;
|
||||
}
|
||||
/* Store interpolated booleans in a float temporary.
|
||||
* Otherwise information provided by weights is easily rounded away. */
|
||||
using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>;
|
||||
using type = SimpleMixerWithAccumulationType<bool, float, bool_to_float, float_to_bool>;
|
||||
};
|
||||
|
||||
template<> struct DefaultMixerStruct<int8_t> {
|
||||
static float int8_t_to_float(const int8_t &value)
|
||||
{
|
||||
return float(value);
|
||||
}
|
||||
static int8_t float_to_int8_t(const float &value)
|
||||
{
|
||||
return int8_t(std::round(value));
|
||||
}
|
||||
/* Store interpolated 8 bit integers in a float temporarily to increase accuracy. */
|
||||
using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>;
|
||||
using type = SimpleMixerWithAccumulationType<int8_t, float, int8_t_to_float, float_to_int8_t>;
|
||||
};
|
||||
template<> struct DefaultMixerStruct<math::Quaternion> {
|
||||
static float3 quat_to_expmap(const math::Quaternion &value)
|
||||
{
|
||||
return value.expmap();
|
||||
}
|
||||
static math::Quaternion expmap_to_quat(const float3 &value)
|
||||
{
|
||||
return math::Quaternion::expmap(value);
|
||||
}
|
||||
using type =
|
||||
SimpleMixerWithAccumulationType<math::Quaternion, float3, quat_to_expmap, expmap_to_quat>;
|
||||
};
|
||||
|
||||
template<typename T> struct DefaultPropagationMixerStruct {
|
||||
|
|
|
@ -30,7 +30,7 @@ bool BKE_curves_attribute_required(const struct Curves *curves, const char *name
|
|||
|
||||
/* Depsgraph */
|
||||
|
||||
struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src);
|
||||
struct Curves *BKE_curves_copy_for_eval(const struct Curves *curves_src);
|
||||
|
||||
void BKE_curves_data_update(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
|
|
|
@ -80,7 +80,7 @@ bool BKE_pointcloud_attribute_required(const struct PointCloud *pointcloud, cons
|
|||
|
||||
/* Dependency Graph */
|
||||
|
||||
struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src);
|
||||
struct PointCloud *BKE_pointcloud_copy_for_eval(const struct PointCloud *pointcloud_src);
|
||||
|
||||
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
|
|
|
@ -48,7 +48,7 @@ struct wmWindow;
|
|||
struct wmWindowManager;
|
||||
|
||||
/* spacetype has everything stored to get an editor working, it gets initialized via
|
||||
* #ED_spacetypes_init() in `editors/space_api/spacetypes.c` */
|
||||
* #ED_spacetypes_init() in `editors/space_api/spacetypes.cc` */
|
||||
/* an editor in Blender is a combined ScrArea + SpaceType + SpaceData */
|
||||
|
||||
#define BKE_ST_MAXNAME 64
|
||||
|
|
|
@ -132,7 +132,7 @@ void BKE_volume_grid_transform_matrix_set(const struct Volume *volume,
|
|||
* file path. Grids are shared with the source data-block, not copied. */
|
||||
|
||||
struct Volume *BKE_volume_new_for_eval(const struct Volume *volume_src);
|
||||
struct Volume *BKE_volume_copy_for_eval(struct Volume *volume_src);
|
||||
struct Volume *BKE_volume_copy_for_eval(const struct Volume *volume_src);
|
||||
|
||||
struct VolumeGrid *BKE_volume_grid_add(struct Volume *volume,
|
||||
const char *name,
|
||||
|
|
|
@ -107,11 +107,13 @@ static int attribute_data_type_complexity(const eCustomDataType data_type)
|
|||
return 6;
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
return 7;
|
||||
case CD_PROP_COLOR:
|
||||
case CD_PROP_QUATERNION:
|
||||
return 8;
|
||||
case CD_PROP_COLOR:
|
||||
return 9;
|
||||
#if 0 /* These attribute types are not supported yet. */
|
||||
case CD_PROP_STRING:
|
||||
return 9;
|
||||
return 10;
|
||||
#endif
|
||||
default:
|
||||
/* Only accept "generic" custom data types used by the attribute system. */
|
||||
|
|
|
@ -3,11 +3,39 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_math_quaternion.hh"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
|
||||
namespace blender::bke::attribute_math {
|
||||
|
||||
template<>
|
||||
math::Quaternion mix2(const float factor, const math::Quaternion &a, const math::Quaternion &b)
|
||||
{
|
||||
return math::interpolate(a, b, factor);
|
||||
}
|
||||
|
||||
template<>
|
||||
math::Quaternion mix3(const float3 &weights,
|
||||
const math::Quaternion &v0,
|
||||
const math::Quaternion &v1,
|
||||
const math::Quaternion &v2)
|
||||
{
|
||||
const float3 expmap_mixed = mix3(weights, v0.expmap(), v1.expmap(), v2.expmap());
|
||||
return math::Quaternion::expmap(expmap_mixed);
|
||||
}
|
||||
|
||||
template<>
|
||||
math::Quaternion mix4(const float4 &weights,
|
||||
const math::Quaternion &v0,
|
||||
const math::Quaternion &v1,
|
||||
const math::Quaternion &v2,
|
||||
const math::Quaternion &v3)
|
||||
{
|
||||
const float3 expmap_mixed = mix4(weights, v0.expmap(), v1.expmap(), v2.expmap(), v3.expmap());
|
||||
return math::Quaternion::expmap(expmap_mixed);
|
||||
}
|
||||
|
||||
ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer,
|
||||
ColorGeometry4f default_color)
|
||||
: ColorGeometry4fMixer(buffer, buffer.index_range(), default_color)
|
||||
|
|
|
@ -222,7 +222,7 @@ bool BKE_curves_attribute_required(const Curves * /*curves*/, const char *name)
|
|||
return STREQ(name, ATTR_POSITION);
|
||||
}
|
||||
|
||||
Curves *BKE_curves_copy_for_eval(Curves *curves_src)
|
||||
Curves *BKE_curves_copy_for_eval(const Curves *curves_src)
|
||||
{
|
||||
return reinterpret_cast<Curves *>(
|
||||
BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, LIB_ID_COPY_LOCALIZE));
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "BLI_index_range.hh"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_mempool.h"
|
||||
#include "BLI_path_util.h"
|
||||
|
@ -1542,6 +1543,20 @@ static void layerInterp_propbool(const void **sources,
|
|||
*(bool *)dest = result;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Callbacks for (#math::Quaternion, #CD_PROP_QUATERNION)
|
||||
* \{ */
|
||||
|
||||
static void layerDefault_propquaternion(void *data, const int count)
|
||||
{
|
||||
using namespace blender;
|
||||
MutableSpan(static_cast<math::Quaternion *>(data), count).fill(math::Quaternion::identity());
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
/* 0: CD_MVERT */ /* DEPRECATED */
|
||||
{sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
|
@ -1933,6 +1948,16 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
|||
nullptr},
|
||||
/* 51: CD_HAIRLENGTH */
|
||||
{sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 52: CD_PROP_QUATERNION */
|
||||
{sizeof(float[4]),
|
||||
"vec4f",
|
||||
1,
|
||||
N_("Quaternion"),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
layerDefault_propquaternion},
|
||||
};
|
||||
|
||||
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
|
||||
|
@ -1990,6 +2015,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
|
|||
"CDPropFloat2",
|
||||
"CDPropBoolean",
|
||||
"CDHairLength",
|
||||
"CDPropQuaternion",
|
||||
};
|
||||
|
||||
const CustomData_MeshMasks CD_MASK_BAREMESH = {
|
||||
|
@ -5354,6 +5380,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
|
|||
return &CPPType::get<int8_t>();
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
return &CPPType::get<ColorGeometry4b>();
|
||||
case CD_PROP_QUATERNION:
|
||||
return &CPPType::get<math::Quaternion>();
|
||||
case CD_PROP_STRING:
|
||||
return &CPPType::get<MStringProperty>();
|
||||
default:
|
||||
|
@ -5390,6 +5418,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
|
|||
if (type.is<ColorGeometry4b>()) {
|
||||
return CD_PROP_BYTE_COLOR;
|
||||
}
|
||||
if (type.is<math::Quaternion>()) {
|
||||
return CD_PROP_QUATERNION;
|
||||
}
|
||||
if (type.is<MStringProperty>()) {
|
||||
return CD_PROP_STRING;
|
||||
}
|
||||
|
|
|
@ -661,6 +661,26 @@ static int customdata_compare(
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CD_PROP_QUATERNION: {
|
||||
const float(*l1_data)[4] = (float(*)[4])l1->data;
|
||||
const float(*l2_data)[4] = (float(*)[4])l2->data;
|
||||
|
||||
for (int i = 0; i < total_length; i++) {
|
||||
if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) {
|
||||
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
|
||||
}
|
||||
if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) {
|
||||
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
|
||||
}
|
||||
if (compare_threshold_relative(l1_data[i][2], l2_data[i][2], thresh)) {
|
||||
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
|
||||
}
|
||||
if (compare_threshold_relative(l1_data[i][3], l2_data[i][3], thresh)) {
|
||||
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CD_PROP_INT32: {
|
||||
const int *l1_data = (int *)l1->data;
|
||||
const int *l2_data = (int *)l2->data;
|
||||
|
|
|
@ -320,7 +320,7 @@ bool BKE_pointcloud_attribute_required(const PointCloud * /*pointcloud*/, const
|
|||
|
||||
/* Dependency Graph */
|
||||
|
||||
PointCloud *BKE_pointcloud_copy_for_eval(PointCloud *pointcloud_src)
|
||||
PointCloud *BKE_pointcloud_copy_for_eval(const PointCloud *pointcloud_src)
|
||||
{
|
||||
return reinterpret_cast<PointCloud *>(
|
||||
BKE_id_copy_ex(nullptr, &pointcloud_src->id, nullptr, LIB_ID_COPY_LOCALIZE));
|
||||
|
|
|
@ -2684,7 +2684,8 @@ void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
|
|||
BKE_sound_set_scene_volume(scene, scene->audio.volume);
|
||||
}
|
||||
if (recalc & ID_RECALC_AUDIO_MUTE) {
|
||||
const bool is_mute = (scene->audio.flag & AUDIO_MUTE);
|
||||
const bool is_mute = (DEG_get_mode(depsgraph) == DAG_EVAL_VIEWPORT) &&
|
||||
(scene->audio.flag & AUDIO_MUTE);
|
||||
BKE_sound_mute_scene(scene, is_mute);
|
||||
}
|
||||
if (recalc & ID_RECALC_AUDIO_LISTENER) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "BLI_endian_switch.h"
|
||||
#include "BLI_fileops.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_path_util.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
@ -778,6 +779,10 @@ static std::shared_ptr<io::serialize::Value> serialize_primitive_value(
|
|||
const ColorGeometry4f value = *static_cast<const ColorGeometry4f *>(value_ptr);
|
||||
return serialize_float_array({&value.r, 4});
|
||||
}
|
||||
case CD_PROP_QUATERNION: {
|
||||
const math::Quaternion value = *static_cast<const math::Quaternion *>(value_ptr);
|
||||
return serialize_float_array({&value.x, 4});
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -966,6 +971,9 @@ template<typename T>
|
|||
case CD_PROP_COLOR: {
|
||||
return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
|
||||
}
|
||||
case CD_PROP_QUATERNION: {
|
||||
return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1530,7 +1530,7 @@ Volume *BKE_volume_new_for_eval(const Volume *volume_src)
|
|||
return volume_dst;
|
||||
}
|
||||
|
||||
Volume *BKE_volume_copy_for_eval(Volume *volume_src)
|
||||
Volume *BKE_volume_copy_for_eval(const Volume *volume_src)
|
||||
{
|
||||
return reinterpret_cast<Volume *>(
|
||||
BKE_id_copy_ex(nullptr, &volume_src->id, nullptr, LIB_ID_COPY_LOCALIZE));
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_math_color.hh"
|
||||
#include "BLI_math_quaternion.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
namespace blender::length_parameterize {
|
||||
|
|
|
@ -306,87 +306,85 @@ float musgrave_hetero_terrain(
|
|||
/** \name Voronoi Noise
|
||||
* \{ */
|
||||
|
||||
void voronoi_f1(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_smooth_f1(
|
||||
float w, float smoothness, float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_f2(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_distance_to_edge(float w, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(float w, float randomness, float *r_radius);
|
||||
struct VoronoiParams {
|
||||
float scale;
|
||||
float detail;
|
||||
float roughness;
|
||||
float lacunarity;
|
||||
float smoothness;
|
||||
float exponent;
|
||||
float randomness;
|
||||
float max_distance;
|
||||
bool normalize;
|
||||
int feature;
|
||||
int metric;
|
||||
};
|
||||
|
||||
void voronoi_f1(const float2 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_smooth_f1(const float2 coord,
|
||||
float smoothness,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_f2(const float2 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_distance_to_edge(const float2 coord, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float2 coord, float randomness, float *r_radius);
|
||||
struct VoronoiOutput {
|
||||
float distance = 0.0f;
|
||||
float3 color{0.0f, 0.0f, 0.0f};
|
||||
float4 position{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
};
|
||||
|
||||
void voronoi_f1(const float3 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_smooth_f1(const float3 coord,
|
||||
float smoothness,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_f2(const float3 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_distance_to_edge(const float3 coord, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float3 coord, float randomness, float *r_radius);
|
||||
/* ***** Distances ***** */
|
||||
|
||||
void voronoi_f1(const float4 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_smooth_f1(const float4 coord,
|
||||
float smoothness,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_f2(const float4 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_distance_to_edge(const float4 coord, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float4 coord, float randomness, float *r_radius);
|
||||
float voronoi_distance(const float a, const float b);
|
||||
float voronoi_distance(const float2 a, const float2 b, const VoronoiParams ¶ms);
|
||||
float voronoi_distance(const float3 a, const float3 b, const VoronoiParams ¶ms);
|
||||
float voronoi_distance(const float4 a, const float4 b, const VoronoiParams ¶ms);
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float coord);
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float2 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float2 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float2 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float2 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float2 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float2 coord);
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float3 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float3 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float3 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float3 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float3 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float3 coord);
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float4 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float4 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float4 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float4 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float4 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float4 coord);
|
||||
|
||||
/* Fractal Voronoi Noise */
|
||||
|
||||
template<typename T>
|
||||
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams ¶ms,
|
||||
const T coord,
|
||||
const bool calc_color);
|
||||
template<typename T>
|
||||
float fractal_voronoi_distance_to_edge(const VoronoiParams ¶ms, const T coord);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ template<typename T> class OffsetIndices {
|
|||
OffsetIndices() = default;
|
||||
OffsetIndices(const Span<T> offsets) : offsets_(offsets)
|
||||
{
|
||||
BLI_assert(std::is_sorted(offsets_.begin(), offsets_.end()));
|
||||
BLI_assert(offsets_.size() < 2 || std::is_sorted(offsets_.begin(), offsets_.end()));
|
||||
}
|
||||
|
||||
/** Return the total number of elements in the referenced arrays. */
|
||||
|
|
|
@ -265,6 +265,10 @@ int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
|
|||
* Removes the last slash and everything after it to the end of path, if there is one.
|
||||
*/
|
||||
void BLI_path_slash_rstrip(char *path) ATTR_NONNULL(1);
|
||||
/**
|
||||
* \return the next non-slash character or the null byte (when `path` only contains slashes).
|
||||
*/
|
||||
const char *BLI_path_slash_skip(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Changes to the path separators to the native ones for this OS.
|
||||
*/
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "BLI_cpp_type_make.hh"
|
||||
#include "BLI_cpp_types_make.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
namespace blender {
|
||||
|
@ -65,6 +66,8 @@ BLI_CPP_TYPE_MAKE(uint64_t, CPPTypeFlags::BasicType)
|
|||
BLI_CPP_TYPE_MAKE(blender::ColorGeometry4f, CPPTypeFlags::BasicType)
|
||||
BLI_CPP_TYPE_MAKE(blender::ColorGeometry4b, CPPTypeFlags::BasicType)
|
||||
|
||||
BLI_CPP_TYPE_MAKE(blender::math::Quaternion, CPPTypeFlags::BasicType)
|
||||
|
||||
BLI_CPP_TYPE_MAKE(std::string, CPPTypeFlags::BasicType)
|
||||
|
||||
BLI_VECTOR_CPP_TYPE_MAKE(std::string)
|
||||
|
@ -94,6 +97,8 @@ void register_cpp_types()
|
|||
BLI_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
|
||||
BLI_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
|
||||
|
||||
BLI_CPP_TYPE_REGISTER(math::Quaternion);
|
||||
|
||||
BLI_CPP_TYPE_REGISTER(std::string);
|
||||
|
||||
BLI_VECTOR_CPP_TYPE_REGISTER(std::string);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1118,9 +1118,7 @@ bool BLI_path_abs(char path[FILE_MAX], const char *basepath)
|
|||
BLI_assert(strlen(tmp) == root_dir_len);
|
||||
|
||||
/* Step over the slashes at the beginning of the path. */
|
||||
while (BLI_path_slash_is_native_compat(*p)) {
|
||||
p++;
|
||||
}
|
||||
p = (char *)BLI_path_slash_skip(p);
|
||||
BLI_strncpy(tmp + root_dir_len, p, sizeof(tmp) - root_dir_len);
|
||||
}
|
||||
else {
|
||||
|
@ -1958,6 +1956,15 @@ void BLI_path_slash_rstrip(char *path)
|
|||
}
|
||||
}
|
||||
|
||||
const char *BLI_path_slash_skip(const char *path)
|
||||
{
|
||||
/* This accounts for a null byte too. */
|
||||
while (BLI_path_slash_is_native_compat(*path)) {
|
||||
path++;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void BLI_path_slash_native(char *path)
|
||||
{
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -42,7 +42,7 @@ set(SRC
|
|||
intern/undofile.cc
|
||||
intern/versioning_250.c
|
||||
intern/versioning_260.c
|
||||
intern/versioning_270.c
|
||||
intern/versioning_270.cc
|
||||
intern/versioning_280.cc
|
||||
intern/versioning_290.cc
|
||||
intern/versioning_300.cc
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -329,7 +329,9 @@ static void do_version_scene_collection_convert(
|
|||
BLI_ghash_insert(collection_map, collection, sc);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) {
|
||||
for (SceneCollection *nsc = static_cast<SceneCollection *>(sc->scene_collections.first);
|
||||
nsc != nullptr;)
|
||||
{
|
||||
SceneCollection *nsc_next = nsc->next;
|
||||
Collection *ncollection = BKE_collection_add(bmain, collection, nsc->name);
|
||||
ncollection->id.lib = id->lib;
|
||||
|
|
|
@ -32,16 +32,16 @@ class DenoiseFilter {
|
|||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
oidn::DeviceRef device_;
|
||||
oidn::FilterRef filter_;
|
||||
#endif
|
||||
bool initialized_ = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
~DenoiseFilter()
|
||||
{
|
||||
BLI_assert(!initialized_);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
void init_and_lock_denoiser(MemoryBuffer *output)
|
||||
{
|
||||
/* Since it's memory intensive, it's better to run only one instance of OIDN at a time.
|
||||
|
|
|
@ -298,3 +298,6 @@ if(WITH_OPENCOLORIO)
|
|||
endif()
|
||||
|
||||
blender_add_lib(bf_realtime_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
# Needed so we can use dna_type_offsets.h
|
||||
add_dependencies(bf_realtime_compositor bf_dna)
|
||||
|
|
|
@ -246,7 +246,7 @@ void output_renderpass_color(int id, vec4 color)
|
|||
imageStore(rp_color_img, ivec3(texel, id), color);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
void output_renderpass_value(int id, float value)
|
||||
{
|
||||
|
@ -256,7 +256,7 @@ void output_renderpass_value(int id, float value)
|
|||
imageStore(rp_value_img, ivec3(texel, id), vec4(value));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
void clear_aovs()
|
||||
{
|
||||
|
|
|
@ -83,7 +83,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
|
|||
int *r_layer_index,
|
||||
eCustomDataType *r_type)
|
||||
{
|
||||
const eCustomDataType possible_attribute_types[9] = {
|
||||
const eCustomDataType possible_attribute_types[10] = {
|
||||
CD_PROP_BOOL,
|
||||
CD_PROP_INT8,
|
||||
CD_PROP_INT32_2D,
|
||||
|
@ -92,6 +92,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
|
|||
CD_PROP_FLOAT2,
|
||||
CD_PROP_FLOAT3,
|
||||
CD_PROP_COLOR,
|
||||
CD_PROP_QUATERNION,
|
||||
CD_PROP_BYTE_COLOR,
|
||||
};
|
||||
|
||||
|
|
|
@ -392,6 +392,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
|
|||
}
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
case CD_PROP_COLOR:
|
||||
case CD_PROP_QUATERNION:
|
||||
case CD_PROP_FLOAT3:
|
||||
case CD_PROP_BOOL:
|
||||
case CD_PROP_INT8:
|
||||
|
|
|
@ -107,6 +107,7 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type)
|
|||
return 3;
|
||||
case CD_PROP_COLOR:
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
case CD_PROP_QUATERNION:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -315,6 +316,7 @@ static void extract_attr(const MeshRenderData *mr,
|
|||
case CD_PROP_FLOAT3:
|
||||
extract_attr_generic<float3>(mr, vbo, request);
|
||||
break;
|
||||
case CD_PROP_QUATERNION:
|
||||
case CD_PROP_COLOR:
|
||||
extract_attr_generic<float4>(mr, vbo, request);
|
||||
break;
|
||||
|
|
|
@ -76,6 +76,102 @@ static void GREASE_PENCIL_OT_select_all(wmOperatorType *ot)
|
|||
WM_operator_properties_select_all(ot);
|
||||
}
|
||||
|
||||
static int select_more_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
grease_pencil.foreach_editable_drawing(
|
||||
scene->r.cfra, [](int /*drawing_index*/, GreasePencilDrawing &drawing) {
|
||||
// TODO: Support different selection domains.
|
||||
blender::ed::curves::select_adjacent(drawing.geometry.wrap(), false);
|
||||
});
|
||||
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
||||
* attribute for now. */
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_select_more(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Select More";
|
||||
ot->idname = "GREASE_PENCIL_OT_select_more";
|
||||
ot->description = "Grow the selection by one point";
|
||||
|
||||
ot->exec = select_more_exec;
|
||||
ot->poll = editable_grease_pencil_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int select_less_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
grease_pencil.foreach_editable_drawing(
|
||||
scene->r.cfra, [](int /*drawing_index*/, GreasePencilDrawing &drawing) {
|
||||
// TODO: Support different selection domains.
|
||||
blender::ed::curves::select_adjacent(drawing.geometry.wrap(), true);
|
||||
});
|
||||
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
||||
* attribute for now. */
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_select_less(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Select Less";
|
||||
ot->idname = "GREASE_PENCIL_OT_select_less";
|
||||
ot->description = "Shrink the selection by one point";
|
||||
|
||||
ot->exec = select_less_exec;
|
||||
ot->poll = editable_grease_pencil_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int select_linked_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
grease_pencil.foreach_editable_drawing(
|
||||
scene->r.cfra, [](int /*drawing_index*/, GreasePencilDrawing &drawing) {
|
||||
// TODO: Support different selection domains.
|
||||
blender::ed::curves::select_linked(drawing.geometry.wrap());
|
||||
});
|
||||
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
||||
* attribute for now. */
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_select_linked(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Select Linked";
|
||||
ot->idname = "GREASE_PENCIL_OT_select_linked";
|
||||
ot->description = "Select all points in curves with any point selection";
|
||||
|
||||
ot->exec = select_linked_exec;
|
||||
ot->poll = editable_grease_pencil_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static void keymap_grease_pencil_editing(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Edit Mode", 0, 0);
|
||||
|
@ -88,6 +184,9 @@ void ED_operatortypes_grease_pencil(void)
|
|||
{
|
||||
using namespace blender::ed::greasepencil;
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_select_all);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_select_more);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_select_less);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_select_linked);
|
||||
}
|
||||
|
||||
void ED_keymap_grease_pencil(wmKeyConfig *keyconf)
|
||||
|
|
|
@ -10,16 +10,16 @@
|
|||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum eSceneCopyMethod;
|
||||
|
||||
struct Scene *ED_scene_add(struct Main *bmain,
|
||||
struct bContext *C,
|
||||
struct wmWindow *win,
|
||||
enum eSceneCopyMethod method) ATTR_NONNULL();
|
||||
eSceneCopyMethod method) ATTR_NONNULL();
|
||||
/**
|
||||
* Add a new scene in the sequence editor.
|
||||
*
|
||||
|
@ -27,8 +27,8 @@ struct Scene *ED_scene_add(struct Main *bmain,
|
|||
*/
|
||||
struct Scene *ED_scene_sequencer_add(struct Main *bmain,
|
||||
struct bContext *C,
|
||||
enum eSceneCopyMethod method,
|
||||
const bool assign_strip);
|
||||
eSceneCopyMethod method,
|
||||
bool assign_strip);
|
||||
/**
|
||||
* \note Only call outside of area/region loops.
|
||||
* \return true if successful.
|
||||
|
|
|
@ -493,9 +493,9 @@ bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
|
|||
bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
|
||||
|
||||
/* screen keymaps */
|
||||
/* called in spacetypes.c */
|
||||
/* called in spacetypes.cc */
|
||||
void ED_operatortypes_screen(void);
|
||||
/* called in spacetypes.c */
|
||||
/* called in spacetypes.cc */
|
||||
void ED_keymap_screen(struct wmKeyConfig *keyconf);
|
||||
/**
|
||||
* Workspace key-maps.
|
||||
|
|
|
@ -84,6 +84,13 @@ class AbstractView {
|
|||
/** Listen to a notifier, returning true if a redraw is needed. */
|
||||
virtual bool listen(const wmNotifier &) const;
|
||||
|
||||
/**
|
||||
* Enable filtering. Typically used to enable a filter text button. Triggered on Ctrl+F by
|
||||
* default.
|
||||
* \return True when filtering was enabled successfully.
|
||||
*/
|
||||
virtual bool begin_filtering(const bContext &C) const;
|
||||
|
||||
/**
|
||||
* Makes \a item valid for display in this view. Behavior is undefined for items not registered
|
||||
* with this.
|
||||
|
@ -136,6 +143,9 @@ class AbstractViewItem {
|
|||
bool is_active_ = false;
|
||||
bool is_renaming_ = false;
|
||||
|
||||
/** Cache filtered state here to avoid having to re-query. */
|
||||
mutable std::optional<bool> is_filtered_visible_;
|
||||
|
||||
public:
|
||||
virtual ~AbstractViewItem() = default;
|
||||
|
||||
|
@ -174,6 +184,10 @@ class AbstractViewItem {
|
|||
*/
|
||||
virtual std::unique_ptr<AbstractViewItemDropTarget> create_drop_target();
|
||||
|
||||
/** Return the result of #is_filtered_visible(), but ensure the result is cached so it's only
|
||||
* queried once per redraw. */
|
||||
bool is_filtered_visible_cached() const;
|
||||
|
||||
/** Get the view this item is registered for using #AbstractView::register_item(). */
|
||||
AbstractView &get_view() const;
|
||||
|
||||
|
@ -217,6 +231,12 @@ class AbstractViewItem {
|
|||
*/
|
||||
virtual void update_from_old(const AbstractViewItem &old);
|
||||
|
||||
/**
|
||||
* \note Do not call this directly to avoid constantly rechecking the filter state. Instead use
|
||||
* #is_filtered_visible_cached() for querying.
|
||||
*/
|
||||
virtual bool is_filtered_visible() const;
|
||||
|
||||
/**
|
||||
* Add a text button for renaming the item to \a block. This must be used for the built-in
|
||||
* renaming to work. This button is meant to appear temporarily. It is removed when renaming is
|
||||
|
|
|
@ -98,6 +98,8 @@ class AbstractGridView : public AbstractView {
|
|||
|
||||
protected:
|
||||
Vector<std::unique_ptr<AbstractGridViewItem>> items_;
|
||||
/** Store this to avoid recomputing. */
|
||||
mutable std::optional<int> item_count_filtered_;
|
||||
/** <identifier, item> map to lookup items by identifier, used for efficient lookups in
|
||||
* #update_from_old(). */
|
||||
Map<StringRef, AbstractGridViewItem *> item_map_;
|
||||
|
@ -109,6 +111,7 @@ class AbstractGridView : public AbstractView {
|
|||
|
||||
using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>;
|
||||
void foreach_item(ItemIterFn iter_fn) const;
|
||||
void foreach_filtered_item(ItemIterFn iter_fn) const;
|
||||
|
||||
/**
|
||||
* Convenience wrapper constructing the item by forwarding given arguments to the constructor of
|
||||
|
@ -126,6 +129,7 @@ class AbstractGridView : public AbstractView {
|
|||
template<class ItemT, typename... Args> inline ItemT &add_item(Args &&...args);
|
||||
const GridViewStyle &get_style() const;
|
||||
int get_item_count() const;
|
||||
int get_item_count_filtered() const;
|
||||
|
||||
protected:
|
||||
virtual void build_items() = 0;
|
||||
|
|
|
@ -3269,6 +3269,13 @@ void UI_interface_tag_script_reload(void);
|
|||
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
|
||||
#define USE_UI_POPOVER_ONCE
|
||||
|
||||
/**
|
||||
* Call the #ui::AbstractView::begin_filtering() function of the view to enable filtering.
|
||||
* Typically used to enable a filter text button. Triggered on Ctrl+F by default.
|
||||
* \return True when filtering was enabled successfully.
|
||||
*/
|
||||
bool UI_view_begin_filtering(const struct bContext *C, const uiViewHandle *view_handle);
|
||||
|
||||
bool UI_view_item_is_interactive(const uiViewItemHandle *item_handle);
|
||||
bool UI_view_item_is_active(const uiViewItemHandle *item_handle);
|
||||
bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle);
|
||||
|
|
|
@ -66,6 +66,7 @@ class TreeViewItemContainer {
|
|||
enum class IterOptions {
|
||||
None = 0,
|
||||
SkipCollapsed = 1 << 0,
|
||||
SkipFiltered = 1 << 1,
|
||||
|
||||
/* Keep ENUM_OPERATORS() below updated! */
|
||||
};
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
#include "RNA_path.h"
|
||||
#include "RNA_prototypes.h"
|
||||
#include "RNA_types.h"
|
||||
|
@ -2341,6 +2342,48 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UI View Start Filter Operator
|
||||
* \{ */
|
||||
|
||||
static bool ui_view_focused_poll(bContext *C)
|
||||
{
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
if (!region) {
|
||||
return false;
|
||||
}
|
||||
const wmWindow *win = CTX_wm_window(C);
|
||||
const uiViewHandle *view = UI_region_view_find_at(region, win->eventstate->xy, 0);
|
||||
|
||||
return view != nullptr;
|
||||
}
|
||||
|
||||
static int ui_view_start_filter_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
|
||||
{
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
const uiViewHandle *hovered_view = UI_region_view_find_at(region, event->xy, 0);
|
||||
|
||||
if (!UI_view_begin_filtering(C, hovered_view)) {
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void UI_OT_view_start_filter(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "View Filter";
|
||||
ot->idname = "UI_OT_view_start_filter";
|
||||
ot->description = "Start entering filter text for the data-set in focus";
|
||||
|
||||
ot->invoke = ui_view_start_filter_invoke;
|
||||
ot->poll = ui_view_focused_poll;
|
||||
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UI View Drop Operator
|
||||
* \{ */
|
||||
|
@ -2528,6 +2571,7 @@ void ED_operatortypes_ui(void)
|
|||
|
||||
WM_operatortype_append(UI_OT_list_start_filter);
|
||||
|
||||
WM_operatortype_append(UI_OT_view_start_filter);
|
||||
WM_operatortype_append(UI_OT_view_drop);
|
||||
WM_operatortype_append(UI_OT_view_item_rename);
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include "UI_abstract_view.hh"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
namespace blender::ui {
|
||||
|
||||
void AbstractView::register_item(AbstractViewItem &item)
|
||||
|
@ -76,6 +78,11 @@ bool AbstractView::listen(const wmNotifier & /*notifier*/) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AbstractView::begin_filtering(const bContext & /*C*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -119,16 +126,26 @@ std::optional<rcti> AbstractView::get_bounds() const
|
|||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name General API functions
|
||||
* \{ */
|
||||
|
||||
namespace blender::ui {
|
||||
|
||||
std::unique_ptr<DropTargetInterface> view_drop_target(uiViewHandle *view_handle)
|
||||
{
|
||||
AbstractView &view = reinterpret_cast<AbstractView &>(*view_handle);
|
||||
return view.create_drop_target();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
bool UI_view_begin_filtering(const bContext *C, const uiViewHandle *view_handle)
|
||||
{
|
||||
const ui::AbstractView &view = reinterpret_cast<const ui::AbstractView &>(*view_handle);
|
||||
return view.begin_filtering(*C);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -166,6 +166,27 @@ void AbstractViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*
|
|||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Filtering
|
||||
* \{ */
|
||||
|
||||
bool AbstractViewItem::is_filtered_visible() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractViewItem::is_filtered_visible_cached() const
|
||||
{
|
||||
if (is_filtered_visible_.has_value()) {
|
||||
return *is_filtered_visible_;
|
||||
}
|
||||
|
||||
is_filtered_visible_ = is_filtered_visible();
|
||||
return *is_filtered_visible_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Drag 'n Drop
|
||||
* \{ */
|
||||
|
|
|
@ -44,6 +44,15 @@ void AbstractGridView::foreach_item(ItemIterFn iter_fn) const
|
|||
}
|
||||
}
|
||||
|
||||
void AbstractGridView::foreach_filtered_item(ItemIterFn iter_fn) const
|
||||
{
|
||||
for (const auto &item_ptr : items_) {
|
||||
if (item_ptr->is_filtered_visible_cached()) {
|
||||
iter_fn(*item_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbstractGridViewItem *AbstractGridView::find_matching_item(
|
||||
const AbstractGridViewItem &item_to_match, const AbstractGridView &view_to_search_in) const
|
||||
{
|
||||
|
@ -86,6 +95,20 @@ int AbstractGridView::get_item_count() const
|
|||
return items_.size();
|
||||
}
|
||||
|
||||
int AbstractGridView::get_item_count_filtered() const
|
||||
{
|
||||
if (item_count_filtered_) {
|
||||
return *item_count_filtered_;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
foreach_filtered_item([&i](const auto &) { i++; });
|
||||
|
||||
BLI_assert(i <= get_item_count());
|
||||
item_count_filtered_ = i;
|
||||
return i;
|
||||
}
|
||||
|
||||
GridViewStyle::GridViewStyle(int width, int height) : tile_width(width), tile_height(height) {}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -265,7 +288,7 @@ void BuildOnlyVisibleButtonsHelper::fill_layout_before_visible(uiBlock &block) c
|
|||
|
||||
void BuildOnlyVisibleButtonsHelper::fill_layout_after_visible(uiBlock &block) const
|
||||
{
|
||||
const int last_item_idx = grid_view_.get_item_count() - 1;
|
||||
const int last_item_idx = grid_view_.get_item_count_filtered() - 1;
|
||||
const int last_visible_idx = visible_items_range_.last();
|
||||
|
||||
if (last_item_idx > last_visible_idx) {
|
||||
|
@ -350,7 +373,7 @@ void GridViewLayoutBuilder::build_from_view(const AbstractGridView &grid_view,
|
|||
|
||||
int item_idx = 0;
|
||||
uiLayout *row = nullptr;
|
||||
grid_view.foreach_item([&](AbstractGridViewItem &item) {
|
||||
grid_view.foreach_filtered_item([&](AbstractGridViewItem &item) {
|
||||
/* Skip if item isn't visible. */
|
||||
if (!build_visible_helper.is_item_visible(item_idx)) {
|
||||
item_idx++;
|
||||
|
|
|
@ -52,7 +52,15 @@ AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
|
|||
void TreeViewItemContainer::foreach_item_recursive(ItemIterFn iter_fn, IterOptions options) const
|
||||
{
|
||||
for (const auto &child : children_) {
|
||||
iter_fn(*child);
|
||||
bool skip = false;
|
||||
if (bool(options & IterOptions::SkipFiltered) && !child->is_filtered_visible_cached()) {
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
iter_fn(*child);
|
||||
}
|
||||
|
||||
if (bool(options & IterOptions::SkipCollapsed) && child->is_collapsed()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -428,7 +436,8 @@ void TreeViewLayoutBuilder::build_from_tree(const AbstractTreeView &tree_view)
|
|||
uiLayoutColumn(box, false);
|
||||
|
||||
tree_view.foreach_item([this](AbstractTreeViewItem &item) { build_row(item); },
|
||||
AbstractTreeView::IterOptions::SkipCollapsed);
|
||||
AbstractTreeView::IterOptions::SkipCollapsed |
|
||||
AbstractTreeView::IterOptions::SkipFiltered);
|
||||
|
||||
UI_block_layout_set_current(&block(), &parent_layout);
|
||||
}
|
||||
|
@ -502,7 +511,7 @@ void TreeViewBuilder::ensure_min_rows_items(AbstractTreeView &tree_view)
|
|||
int tot_visible_items = 0;
|
||||
tree_view.foreach_item(
|
||||
[&tot_visible_items](AbstractTreeViewItem & /*item*/) { tot_visible_items++; },
|
||||
AbstractTreeView::IterOptions::SkipCollapsed);
|
||||
AbstractTreeView::IterOptions::SkipCollapsed | AbstractTreeView::IterOptions::SkipFiltered);
|
||||
|
||||
if (tot_visible_items >= tree_view.min_rows_) {
|
||||
return;
|
||||
|
|
|
@ -45,7 +45,7 @@ set(SRC
|
|||
io_collada.hh
|
||||
io_gpencil.hh
|
||||
io_obj.hh
|
||||
io_ops.h
|
||||
io_ops.hh
|
||||
io_ply_ops.hh
|
||||
io_stl_ops.hh
|
||||
io_usd.hh
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "io_ops.h" /* own include */
|
||||
#include "io_ops.hh" /* own include */
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
|||
#include "io_ply_ops.hh"
|
||||
#include "io_stl_ops.hh"
|
||||
|
||||
void ED_operatortypes_io(void)
|
||||
void ED_operatortypes_io()
|
||||
{
|
||||
#ifdef WITH_COLLADA
|
||||
/* Collada operators: */
|
||||
|
|
|
@ -8,12 +8,4 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void ED_operatortypes_io(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
void ED_operatortypes_io();
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_generic_pointer.hh"
|
||||
#include "BLI_math_quaternion.hh"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_context.h"
|
||||
|
@ -106,6 +107,8 @@ static StringRefNull rna_property_name_for_type(const eCustomDataType type)
|
|||
return "value_int";
|
||||
case CD_PROP_INT32_2D:
|
||||
return "value_int_vector_2d";
|
||||
case CD_PROP_QUATERNION:
|
||||
return "value_quat";
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return "";
|
||||
|
@ -198,6 +201,12 @@ static int mesh_set_attribute_exec(bContext *C, wmOperator *op)
|
|||
case CD_PROP_COLOR:
|
||||
RNA_float_get_array(op->ptr, prop_name.c_str(), static_cast<float *>(buffer));
|
||||
break;
|
||||
case CD_PROP_QUATERNION: {
|
||||
float4 value;
|
||||
RNA_float_get_array(op->ptr, prop_name.c_str(), value);
|
||||
*static_cast<math::Quaternion *>(buffer) = math::normalize(math::Quaternion(value));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
ColorGeometry4f value;
|
||||
RNA_float_get_array(op->ptr, prop_name.c_str(), value);
|
||||
|
@ -330,6 +339,11 @@ static int mesh_set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent
|
|||
case CD_PROP_INT32_2D:
|
||||
RNA_property_int_set_array(op->ptr, prop, *active_value.get<int2>());
|
||||
break;
|
||||
case CD_PROP_QUATERNION: {
|
||||
const math::Quaternion value = math::normalize(*active_value.get<math::Quaternion>());
|
||||
RNA_property_float_set_array(op->ptr, prop, float4(value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
@ -408,6 +422,16 @@ void MESH_OT_attribute_set(wmOperatorType *ot)
|
|||
RNA_def_float_color(
|
||||
ot->srna, "value_color", 4, color_default, -FLT_MAX, FLT_MAX, "Value", "", 0.0f, 1.0f);
|
||||
RNA_def_boolean(ot->srna, "value_bool", false, "Value", "");
|
||||
RNA_def_float_array(ot->srna,
|
||||
"value_quat",
|
||||
4,
|
||||
rna_default_quaternion,
|
||||
-FLT_MAX,
|
||||
FLT_MAX,
|
||||
"Value",
|
||||
"",
|
||||
FLT_MAX,
|
||||
FLT_MAX);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -123,8 +123,10 @@ void PaintOperation::on_stroke_done(const bContext &C)
|
|||
/* Set position, radius and opacity attribute. */
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
SpanAttributeWriter<float> radii = attributes.lookup_for_write_span<float>("radius");
|
||||
SpanAttributeWriter<float> opacities = attributes.lookup_for_write_span<float>("opacity");
|
||||
SpanAttributeWriter<float> radii = attributes.lookup_or_add_for_write_span<float>(
|
||||
"radius", ATTR_DOMAIN_POINT);
|
||||
SpanAttributeWriter<float> opacities = attributes.lookup_or_add_for_write_span<float>(
|
||||
"opacity", ATTR_DOMAIN_POINT);
|
||||
for (const int i : IndexRange(stroke_points.size())) {
|
||||
const bke::greasepencil::StrokePoint &point = stroke_points[i];
|
||||
const int point_i = new_points_range[i];
|
||||
|
@ -135,7 +137,9 @@ void PaintOperation::on_stroke_done(const bContext &C)
|
|||
|
||||
/* Set material index attribute. */
|
||||
int material_index = 0;
|
||||
SpanAttributeWriter<int> materials = attributes.lookup_for_write_span<int>("material_index");
|
||||
SpanAttributeWriter<int> materials = attributes.lookup_or_add_for_write_span<int>(
|
||||
"material_index", ATTR_DOMAIN_CURVE);
|
||||
|
||||
materials.span.slice(new_curves_range).fill(material_index);
|
||||
|
||||
/* Set curve_type attribute. */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
set(INC
|
||||
../include
|
||||
../io
|
||||
../../asset_system
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
../../gpu
|
||||
|
@ -19,7 +20,7 @@ set(INC_SYS
|
|||
)
|
||||
|
||||
set(SRC
|
||||
spacetypes.c
|
||||
spacetypes.cc
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* \ingroup spapi
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
|
@ -58,9 +58,9 @@
|
|||
#include "ED_util.h"
|
||||
#include "ED_uvedit.h"
|
||||
|
||||
#include "io_ops.h"
|
||||
#include "io_ops.hh"
|
||||
|
||||
void ED_spacetypes_init(void)
|
||||
void ED_spacetypes_init()
|
||||
{
|
||||
/* UI unit is a variable, may be used in some space type initialization. */
|
||||
U.widget_unit = 20;
|
||||
|
@ -149,7 +149,7 @@ void ED_spacetypes_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
void ED_spacemacros_init(void)
|
||||
void ED_spacemacros_init()
|
||||
{
|
||||
/* Macros must go last since they reference other operators.
|
||||
* They need to be registered after python operators too. */
|
||||
|
@ -221,22 +221,21 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
|
|||
|
||||
/* ********************** Custom Draw Call API ***************** */
|
||||
|
||||
typedef struct RegionDrawCB {
|
||||
struct RegionDrawCB {
|
||||
struct RegionDrawCB *next, *prev;
|
||||
|
||||
void (*draw)(const bContext *, ARegion *, void *);
|
||||
void *customdata;
|
||||
|
||||
int type;
|
||||
|
||||
} RegionDrawCB;
|
||||
};
|
||||
|
||||
void *ED_region_draw_cb_activate(ARegionType *art,
|
||||
void (*draw)(const bContext *, ARegion *, void *),
|
||||
void *customdata,
|
||||
int type)
|
||||
{
|
||||
RegionDrawCB *rdc = MEM_callocN(sizeof(RegionDrawCB), "RegionDrawCB");
|
||||
RegionDrawCB *rdc = MEM_cnew<RegionDrawCB>(__func__);
|
||||
|
||||
BLI_addtail(&art->drawcalls, rdc);
|
||||
rdc->draw = draw;
|
||||
|
@ -277,7 +276,7 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
|
|||
|
||||
void ED_region_surface_draw_cb_draw(ARegionType *art, int type)
|
||||
{
|
||||
ed_region_draw_cb_draw(NULL, NULL, art, type);
|
||||
ed_region_draw_cb_draw(nullptr, nullptr, art, type);
|
||||
}
|
||||
|
||||
void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*free)(void *))
|
||||
|
@ -295,19 +294,19 @@ void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*fr
|
|||
|
||||
/* ********************* space template *********************** */
|
||||
/* forward declare */
|
||||
void ED_spacetype_xxx(void);
|
||||
void ED_spacetype_xxx();
|
||||
|
||||
/* allocate and init some vars */
|
||||
static SpaceLink *xxx_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
|
||||
static SpaceLink *xxx_create(const ScrArea * /*area*/, const Scene * /*scene*/)
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Doesn't free the space-link itself. */
|
||||
static void xxx_free(SpaceLink *UNUSED(sl)) {}
|
||||
static void xxx_free(SpaceLink * /*sl*/) {}
|
||||
|
||||
/* spacetype; init callback for usage, should be re-doable. */
|
||||
static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
|
||||
static void xxx_init(wmWindowManager * /*wm*/, ScrArea * /*area*/)
|
||||
{
|
||||
|
||||
/* link area to SpaceXXX struct */
|
||||
|
@ -317,24 +316,23 @@ static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
|
|||
/* add types to regions */
|
||||
}
|
||||
|
||||
static SpaceLink *xxx_duplicate(SpaceLink *UNUSED(sl))
|
||||
static SpaceLink *xxx_duplicate(SpaceLink * /*sl*/)
|
||||
{
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void xxx_operatortypes(void)
|
||||
static void xxx_operatortypes()
|
||||
{
|
||||
/* register operator types for this space */
|
||||
}
|
||||
|
||||
static void xxx_keymap(wmKeyConfig *UNUSED(keyconf))
|
||||
static void xxx_keymap(wmKeyConfig * /*keyconf*/)
|
||||
{
|
||||
/* add default items to keymap */
|
||||
}
|
||||
|
||||
/* only called once, from screen/spacetypes.c */
|
||||
void ED_spacetype_xxx(void)
|
||||
/* only called once, from screen/spacetypes.cc */
|
||||
void ED_spacetype_xxx()
|
||||
{
|
||||
static SpaceType st;
|
||||
|
|
@ -405,8 +405,8 @@ std::string AssetCatalogDropTarget::drop_tooltip_asset_catalog(const wmDrag &dra
|
|||
const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library());
|
||||
|
||||
return fmt::format(TIP_("Move catalog {} into {}"),
|
||||
(std::string_view)src_catalog->path.name(),
|
||||
(std::string_view)catalog_item_.get_name());
|
||||
std::string_view(src_catalog->path.name()),
|
||||
std::string_view(catalog_item_.get_name()));
|
||||
}
|
||||
|
||||
std::string AssetCatalogDropTarget::drop_tooltip_asset_list(const wmDrag &drag) const
|
||||
|
@ -620,7 +620,7 @@ std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(const wmDrag &
|
|||
drag, *get_view<AssetCatalogTreeView>().asset_library_);
|
||||
|
||||
return fmt::format(TIP_("Move catalog {} to the top level of the tree"),
|
||||
(std::string_view)drag_catalog->path.name());
|
||||
std::string_view(drag_catalog->path.name()));
|
||||
}
|
||||
|
||||
bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(bContext * /*C*/, const wmDrag &drag) const
|
||||
|
|
|
@ -247,6 +247,13 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
bNode *new_node = bke::node_copy_with_mapping(
|
||||
&tree, node, LIB_ID_COPY_DEFAULT, true, socket_map);
|
||||
/* Reset socket shape in case a node is copied to a different tree type. */
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->inputs) {
|
||||
socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->outputs) {
|
||||
socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
|
||||
}
|
||||
node_map.add_new(&node, new_node);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -59,9 +59,11 @@ set(SRC
|
|||
tree/tree_element_id.cc
|
||||
tree/tree_element_id_curve.cc
|
||||
tree/tree_element_id_library.cc
|
||||
tree/tree_element_id_linestyle.cc
|
||||
tree/tree_element_id_mesh.cc
|
||||
tree/tree_element_id_metaball.cc
|
||||
tree/tree_element_id_scene.cc
|
||||
tree/tree_element_id_texture.cc
|
||||
tree/tree_element_label.cc
|
||||
tree/tree_element_nla.cc
|
||||
tree/tree_element_overrides.cc
|
||||
|
@ -82,9 +84,11 @@ set(SRC
|
|||
tree/tree_element_id.hh
|
||||
tree/tree_element_id_curve.hh
|
||||
tree/tree_element_id_library.hh
|
||||
tree/tree_element_id_linestyle.hh
|
||||
tree/tree_element_id_mesh.hh
|
||||
tree/tree_element_id_metaball.hh
|
||||
tree/tree_element_id_scene.hh
|
||||
tree/tree_element_id_texture.hh
|
||||
tree/tree_element_label.hh
|
||||
tree/tree_element_nla.hh
|
||||
tree/tree_element_overrides.hh
|
||||
|
|
|
@ -554,6 +554,8 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
|
|||
case ID_ME:
|
||||
case ID_CU_LEGACY:
|
||||
case ID_MB:
|
||||
case ID_TE:
|
||||
case ID_LS:
|
||||
BLI_assert_msg(0, "ID type expected to be expanded through new tree-element design");
|
||||
break;
|
||||
case ID_OB: {
|
||||
|
@ -567,14 +569,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ID_TE: {
|
||||
Tex *tex = (Tex *)id;
|
||||
if (outliner_animdata_test(tex->adt)) {
|
||||
outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
|
||||
}
|
||||
outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0);
|
||||
break;
|
||||
}
|
||||
case ID_CA: {
|
||||
Camera *ca = (Camera *)id;
|
||||
if (outliner_animdata_test(ca->adt)) {
|
||||
|
@ -679,20 +673,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ID_LS: {
|
||||
FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
|
||||
|
||||
if (outliner_animdata_test(linestyle->adt)) {
|
||||
outliner_add_element(space_outliner, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
|
||||
}
|
||||
|
||||
for (int a = 0; a < MAX_MTEX; a++) {
|
||||
if (linestyle->mtex[a]) {
|
||||
outliner_add_element(space_outliner, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ID_GD_LEGACY: {
|
||||
bGPdata *gpd = (bGPdata *)id;
|
||||
|
||||
|
|
|
@ -22,9 +22,11 @@
|
|||
#include "common.hh"
|
||||
#include "tree_element_id_curve.hh"
|
||||
#include "tree_element_id_library.hh"
|
||||
#include "tree_element_id_linestyle.hh"
|
||||
#include "tree_element_id_mesh.hh"
|
||||
#include "tree_element_id_metaball.hh"
|
||||
#include "tree_element_id_scene.hh"
|
||||
#include "tree_element_id_texture.hh"
|
||||
|
||||
#include "tree_element_id.hh"
|
||||
|
||||
|
@ -48,9 +50,12 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
|
|||
return std::make_unique<TreeElementIDCurve>(legacy_te, (Curve &)id);
|
||||
case ID_MB:
|
||||
return std::make_unique<TreeElementIDMetaBall>(legacy_te, (MetaBall &)id);
|
||||
case ID_TE:
|
||||
return std::make_unique<TreeElementIDTexture>(legacy_te, (Tex &)id);
|
||||
case ID_LS:
|
||||
return std::make_unique<TreeElementIDLineStyle>(legacy_te, (FreestyleLineStyle &)id);
|
||||
case ID_OB:
|
||||
case ID_MA:
|
||||
case ID_TE:
|
||||
case ID_LT:
|
||||
case ID_LA:
|
||||
case ID_CA:
|
||||
|
@ -64,7 +69,6 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
|
|||
case ID_PA:
|
||||
case ID_MC:
|
||||
case ID_MSK:
|
||||
case ID_LS:
|
||||
case ID_LP:
|
||||
case ID_GD_LEGACY:
|
||||
case ID_WS:
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup spoutliner
|
||||
*/
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_linestyle_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_outliner_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
|
||||
#include "../outliner_intern.hh"
|
||||
|
||||
#include "tree_element_id_linestyle.hh"
|
||||
|
||||
namespace blender::ed::outliner {
|
||||
|
||||
TreeElementIDLineStyle::TreeElementIDLineStyle(TreeElement &legacy_te,
|
||||
FreestyleLineStyle &linestyle)
|
||||
: TreeElementID(legacy_te, linestyle.id), linestyle_(linestyle)
|
||||
{
|
||||
}
|
||||
|
||||
void TreeElementIDLineStyle::expand(SpaceOutliner &space_outliner) const
|
||||
{
|
||||
expand_animation_data(space_outliner, linestyle_.adt);
|
||||
|
||||
expandTextures(space_outliner);
|
||||
}
|
||||
|
||||
bool TreeElementIDLineStyle::isExpandValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void TreeElementIDLineStyle::expandTextures(SpaceOutliner &space_outliner) const
|
||||
{
|
||||
for (int a = 0; a < MAX_MTEX; a++) {
|
||||
if (linestyle_.mtex[a]) {
|
||||
outliner_add_element(&space_outliner,
|
||||
&legacy_te_.subtree,
|
||||
(linestyle_.mtex[a])->tex,
|
||||
&legacy_te_,
|
||||
TSE_SOME_ID,
|
||||
a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::ed::outliner
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup spoutliner
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tree_element_id.hh"
|
||||
|
||||
struct FreestyleLineStyle;
|
||||
|
||||
namespace blender::ed::outliner {
|
||||
|
||||
class TreeElementIDLineStyle final : public TreeElementID {
|
||||
FreestyleLineStyle &linestyle_;
|
||||
|
||||
public:
|
||||
TreeElementIDLineStyle(TreeElement &legacy_te, FreestyleLineStyle &linestyle);
|
||||
|
||||
void expand(SpaceOutliner &) const override;
|
||||
bool isExpandValid() const override;
|
||||
|
||||
private:
|
||||
void expandTextures(SpaceOutliner &) const;
|
||||
};
|
||||
|
||||
} // namespace blender::ed::outliner
|
|
@ -0,0 +1,42 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup spoutliner
|
||||
*/
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_outliner_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
|
||||
#include "../outliner_intern.hh"
|
||||
|
||||
#include "tree_element_id_texture.hh"
|
||||
|
||||
namespace blender::ed::outliner {
|
||||
|
||||
TreeElementIDTexture::TreeElementIDTexture(TreeElement &legacy_te, Tex &texture)
|
||||
: TreeElementID(legacy_te, texture.id), texture_(texture)
|
||||
{
|
||||
}
|
||||
|
||||
bool TreeElementIDTexture::isExpandValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void TreeElementIDTexture::expand(SpaceOutliner &space_outliner) const
|
||||
{
|
||||
expand_animation_data(space_outliner, texture_.adt);
|
||||
|
||||
expandImage(space_outliner);
|
||||
}
|
||||
|
||||
void TreeElementIDTexture::expandImage(SpaceOutliner &space_outliner) const
|
||||
{
|
||||
outliner_add_element(
|
||||
&space_outliner, &legacy_te_.subtree, texture_.ima, &legacy_te_, TSE_SOME_ID, 0);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::outliner
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup spoutliner
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tree_element_id.hh"
|
||||
|
||||
namespace blender::ed::outliner {
|
||||
|
||||
class TreeElementIDTexture final : public TreeElementID {
|
||||
Tex &texture_;
|
||||
|
||||
public:
|
||||
TreeElementIDTexture(TreeElement &legacy_te, Tex &texture);
|
||||
|
||||
void expand(SpaceOutliner &) const override;
|
||||
bool isExpandValid() const override;
|
||||
|
||||
private:
|
||||
void expandImage(SpaceOutliner &) const;
|
||||
};
|
||||
|
||||
} // namespace blender::ed::outliner
|
|
@ -37,6 +37,7 @@ typedef struct GizmoGroup_retime {
|
|||
wmGizmo *add_handle_gizmo;
|
||||
wmGizmo *move_handle_gizmo;
|
||||
wmGizmo *remove_handle_gizmo;
|
||||
wmGizmo *speed_set_gizmo;
|
||||
} GizmoGroup_retime;
|
||||
|
||||
static bool gizmogroup_retime_poll(const bContext *C, wmGizmoGroupType *gzgt)
|
||||
|
@ -81,6 +82,8 @@ static void gizmogroup_retime_setup(const bContext * /* C */, wmGizmoGroup *gzgr
|
|||
ggd->remove_handle_gizmo = WM_gizmo_new_ptr(gzt_remove_handle, gzgroup, nullptr);
|
||||
const wmGizmoType *gzt_move_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_move", true);
|
||||
ggd->move_handle_gizmo = WM_gizmo_new_ptr(gzt_move_handle, gzgroup, nullptr);
|
||||
const wmGizmoType *gzt_speed_set = WM_gizmotype_find("GIZMO_GT_retime_speed_set", true);
|
||||
ggd->speed_set_gizmo = WM_gizmo_new_ptr(gzt_speed_set, gzgroup, nullptr);
|
||||
gzgroup->customdata = ggd;
|
||||
|
||||
/* Assign operators. */
|
||||
|
@ -90,6 +93,8 @@ static void gizmogroup_retime_setup(const bContext * /* C */, wmGizmoGroup *gzgr
|
|||
WM_gizmo_operator_set(ggd->add_handle_gizmo, 0, ot, nullptr);
|
||||
ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_remove", true);
|
||||
WM_gizmo_operator_set(ggd->remove_handle_gizmo, 0, ot, nullptr);
|
||||
ot = WM_operatortype_find("SEQUENCER_OT_retiming_segment_speed_set", true);
|
||||
WM_gizmo_operator_set(ggd->speed_set_gizmo, 0, ot, nullptr);
|
||||
}
|
||||
|
||||
void SEQUENCER_GGT_gizmo_retime(wmGizmoGroupType *gzgt)
|
||||
|
|
|
@ -403,61 +403,6 @@ static void retime_handle_draw(const bContext *C,
|
|||
immEnd();
|
||||
}
|
||||
|
||||
static void retime_speed_text_draw(const bContext *C,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingHandle *handle)
|
||||
{
|
||||
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
|
||||
if (handle == last_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const int start_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
||||
const int end_frame = SEQ_time_right_handle_frame_get(scene, seq);
|
||||
|
||||
int next_handle_index = SEQ_retiming_handle_index_get(seq, handle) + 1;
|
||||
const SeqRetimingHandle *next_handle = &SEQ_retiming_handles_get(seq)[next_handle_index];
|
||||
if (handle_x_get(scene, seq, next_handle) < start_frame ||
|
||||
handle_x_get(scene, seq, handle) > end_frame)
|
||||
{
|
||||
return; /* Label out of strip bounds. */
|
||||
}
|
||||
|
||||
char label_str[40];
|
||||
size_t label_len;
|
||||
|
||||
if (SEQ_retiming_handle_is_transition_type(handle)) {
|
||||
const float prev_speed = SEQ_retiming_handle_speed_get(seq, handle - 1);
|
||||
const float next_speed = SEQ_retiming_handle_speed_get(seq, next_handle + 1);
|
||||
label_len = SNPRINTF_RLEN(label_str,
|
||||
"%d%% - %d%%",
|
||||
round_fl_to_int(prev_speed * 100.0f),
|
||||
round_fl_to_int(next_speed * 100.0f));
|
||||
}
|
||||
else {
|
||||
const float speed = SEQ_retiming_handle_speed_get(seq, next_handle);
|
||||
label_len = SNPRINTF_RLEN(label_str, "%d%%", round_fl_to_int(speed * 100.0f));
|
||||
}
|
||||
|
||||
const float width = pixels_to_view_width(C, BLF_width(BLF_default(), label_str, label_len));
|
||||
|
||||
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq),
|
||||
handle_x_get(scene, seq, handle));
|
||||
const float xmax = min_ff(SEQ_time_right_handle_frame_get(scene, seq),
|
||||
handle_x_get(scene, seq, next_handle));
|
||||
|
||||
const float text_x = (xmin + xmax - width) / 2;
|
||||
const float text_y = strip_y_rescale(seq, 0) + pixels_to_view_height(C, 5);
|
||||
|
||||
if (width > xmax - xmin) {
|
||||
return; /* Not enough space to draw label. */
|
||||
}
|
||||
|
||||
const uchar col[4] = {255, 255, 255, 255};
|
||||
UI_view2d_text_cache_add(UI_view2d_fromcontext(C), text_x, text_y, label_str, label_len, col);
|
||||
}
|
||||
|
||||
static void gizmo_retime_handle_draw(const bContext *C, wmGizmo *gz)
|
||||
{
|
||||
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
|
||||
|
@ -488,8 +433,6 @@ static void gizmo_retime_handle_draw(const bContext *C, wmGizmo *gz)
|
|||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
|
||||
for (const SeqRetimingHandle &handle : handles) {
|
||||
retime_speed_text_draw(C, seq, &handle);
|
||||
|
||||
if (&handle == handles.begin()) {
|
||||
continue; /* Ignore first handle. */
|
||||
}
|
||||
|
@ -646,3 +589,183 @@ void GIZMO_GT_retime_remove(wmGizmoType *gzt)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Speed Set Gizmo
|
||||
* \{ */
|
||||
|
||||
static size_t label_str_get(const Sequence *seq,
|
||||
const SeqRetimingHandle *handle,
|
||||
size_t str_len,
|
||||
char *r_label_str)
|
||||
{
|
||||
const SeqRetimingHandle *next_handle = handle + 1;
|
||||
if (SEQ_retiming_handle_is_transition_type(handle)) {
|
||||
const float prev_speed = SEQ_retiming_handle_speed_get(seq, handle - 1);
|
||||
const float next_speed = SEQ_retiming_handle_speed_get(seq, next_handle + 1);
|
||||
return BLI_snprintf_rlen(r_label_str,
|
||||
str_len,
|
||||
"%d%% - %d%%",
|
||||
round_fl_to_int(prev_speed * 100.0f),
|
||||
round_fl_to_int(next_speed * 100.0f));
|
||||
}
|
||||
const float speed = SEQ_retiming_handle_speed_get(seq, next_handle);
|
||||
return BLI_snprintf_rlen(r_label_str, str_len, "%d%%", round_fl_to_int(speed * 100.0f));
|
||||
}
|
||||
|
||||
static bool label_rect_get(const bContext *C,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingHandle *handle,
|
||||
char *label_str,
|
||||
size_t label_len,
|
||||
rctf *rect)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const SeqRetimingHandle *next_handle = handle + 1;
|
||||
const float width = pixels_to_view_width(C, BLF_width(BLF_default(), label_str, label_len));
|
||||
const float height = pixels_to_view_height(C, BLF_height(BLF_default(), label_str, label_len));
|
||||
|
||||
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq),
|
||||
handle_x_get(scene, seq, handle));
|
||||
const float xmax = min_ff(SEQ_time_right_handle_frame_get(scene, seq),
|
||||
handle_x_get(scene, seq, next_handle));
|
||||
|
||||
rect->xmin = (xmin + xmax - width) / 2;
|
||||
rect->xmax = rect->xmin + width;
|
||||
rect->ymin = strip_y_rescale(seq, 0) + pixels_to_view_height(C, 5);
|
||||
rect->ymax = rect->ymin + height;
|
||||
|
||||
return width < xmax - xmin;
|
||||
}
|
||||
|
||||
static void label_rect_apply_mouseover_offset(const View2D *v2d, rctf *rect)
|
||||
{
|
||||
float scale_x, scale_y;
|
||||
UI_view2d_scale_get_inverse(v2d, &scale_x, &scale_y);
|
||||
rect->xmin -= RETIME_HANDLE_MOUSEOVER_THRESHOLD * scale_x;
|
||||
rect->xmax += RETIME_HANDLE_MOUSEOVER_THRESHOLD * scale_x;
|
||||
rect->ymax += RETIME_HANDLE_MOUSEOVER_THRESHOLD * scale_y;
|
||||
}
|
||||
|
||||
static void retime_speed_text_draw(const bContext *C,
|
||||
const Sequence *seq,
|
||||
const SeqRetimingHandle *handle)
|
||||
{
|
||||
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
|
||||
if (handle == last_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const int start_frame = SEQ_time_left_handle_frame_get(scene, seq);
|
||||
const int end_frame = SEQ_time_right_handle_frame_get(scene, seq);
|
||||
|
||||
const SeqRetimingHandle *next_handle = handle + 1;
|
||||
if (handle_x_get(scene, seq, next_handle) < start_frame ||
|
||||
handle_x_get(scene, seq, handle) > end_frame)
|
||||
{
|
||||
return; /* Label out of strip bounds. */
|
||||
}
|
||||
|
||||
char label_str[40];
|
||||
rctf label_rect;
|
||||
size_t label_len = label_str_get(seq, handle, sizeof(label_str), label_str);
|
||||
|
||||
if (!label_rect_get(C, seq, handle, label_str, label_len, &label_rect)) {
|
||||
return; /* Not enough space to draw label. */
|
||||
}
|
||||
|
||||
const uchar col[4] = {255, 255, 255, 255};
|
||||
UI_view2d_text_cache_add(
|
||||
UI_view2d_fromcontext(C), label_rect.xmin, label_rect.ymin, label_str, label_len, col);
|
||||
}
|
||||
|
||||
static void gizmo_retime_speed_set_draw(const bContext *C, wmGizmo * /* gz */)
|
||||
{
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
|
||||
wmOrtho2_region_pixelspace(CTX_wm_region(C));
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
|
||||
Sequence *seq = active_seq_from_context(C);
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
|
||||
for (const SeqRetimingHandle &handle : handles) {
|
||||
retime_speed_text_draw(C, seq, &handle);
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
UI_view2d_text_cache_draw(CTX_wm_region(C));
|
||||
UI_view2d_view_ortho(v2d); /* 'UI_view2d_text_cache_draw()' messes up current view. */
|
||||
}
|
||||
|
||||
static int gizmo_retime_speed_set_test_select(bContext *C, wmGizmo *gz, const int mval[2])
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
|
||||
Sequence *seq = active_seq_from_context(C);
|
||||
SEQ_retiming_data_ensure(seq);
|
||||
|
||||
for (const SeqRetimingHandle &handle : SEQ_retiming_handles_get(seq)) {
|
||||
if (SEQ_retiming_handle_is_transition_type(&handle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char label_str[40];
|
||||
rctf label_rect;
|
||||
size_t label_len = label_str_get(seq, &handle, sizeof(label_str), label_str);
|
||||
|
||||
if (!label_rect_get(C, seq, &handle, label_str, label_len, &label_rect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
label_rect_apply_mouseover_offset(v2d, &label_rect);
|
||||
|
||||
float mouse_view[2];
|
||||
UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouse_view[0], &mouse_view[1]);
|
||||
|
||||
if (!BLI_rctf_isect_pt(&label_rect, mouse_view[0], mouse_view[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Store next handle in RNA property, since label rect uses first handle as reference. */
|
||||
const int handle_index = SEQ_retiming_handle_index_get(seq, &handle) + 1;
|
||||
RNA_int_set(&op_elem->ptr, "handle_index", handle_index);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gizmo_retime_speed_set_cursor_get(wmGizmo *gz)
|
||||
{
|
||||
if (RNA_boolean_get(gz->ptr, "show_drag")) {
|
||||
return WM_CURSOR_TEXT_EDIT;
|
||||
}
|
||||
return WM_CURSOR_DEFAULT;
|
||||
}
|
||||
|
||||
void GIZMO_GT_speed_set_remove(wmGizmoType *gzt)
|
||||
{
|
||||
/* Identifiers. */
|
||||
gzt->idname = "GIZMO_GT_retime_speed_set";
|
||||
|
||||
/* Api callbacks. */
|
||||
gzt->draw = gizmo_retime_speed_set_draw;
|
||||
gzt->test_select = gizmo_retime_speed_set_test_select;
|
||||
gzt->cursor_get = gizmo_retime_speed_set_cursor_get;
|
||||
gzt->struct_size = sizeof(wmGizmo);
|
||||
|
||||
/* Currently only used for cursor display. */
|
||||
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -312,6 +312,7 @@ void SEQUENCER_OT_retiming_reset(struct wmOperatorType *ot);
|
|||
void SEQUENCER_OT_retiming_handle_move(struct wmOperatorType *ot);
|
||||
void SEQUENCER_OT_retiming_handle_add(struct wmOperatorType *ot);
|
||||
void SEQUENCER_OT_retiming_handle_remove(struct wmOperatorType *ot);
|
||||
void SEQUENCER_OT_retiming_segment_speed_set(struct wmOperatorType *ot);
|
||||
|
||||
/* sequencer_gizmo_retime.c */
|
||||
void SEQUENCER_GGT_gizmo_retime(struct wmGizmoGroupType *gzgt);
|
||||
|
@ -320,6 +321,7 @@ void SEQUENCER_GGT_gizmo_retime(struct wmGizmoGroupType *gzgt);
|
|||
void GIZMO_GT_retime_handle_add(struct wmGizmoType *gzt);
|
||||
void GIZMO_GT_retime_handle(struct wmGizmoType *gzt);
|
||||
void GIZMO_GT_retime_remove(struct wmGizmoType *gzt);
|
||||
void GIZMO_GT_speed_set_remove(struct wmGizmoType *gzt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ void sequencer_operatortypes(void)
|
|||
WM_operatortype_append(SEQUENCER_OT_retiming_handle_move);
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_handle_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_handle_remove);
|
||||
WM_operatortype_append(SEQUENCER_OT_retiming_segment_speed_set);
|
||||
|
||||
/* sequencer_select.c */
|
||||
WM_operatortype_append(SEQUENCER_OT_select_all);
|
||||
|
|
|
@ -461,3 +461,95 @@ void SEQUENCER_OT_retiming_handle_remove(wmOperatorType *ot)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Retiming Set Segment Speed
|
||||
* \{ */
|
||||
|
||||
static int sequencer_retiming_segment_speed_set_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
Sequence *seq = ed->act_seq;
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
SeqRetimingHandle *handle = &handles[RNA_int_get(op->ptr, "handle_index")];
|
||||
|
||||
SEQ_retiming_handle_speed_set(scene, seq, handle, RNA_float_get(op->ptr, "speed"));
|
||||
SEQ_relations_invalidate_cache_raw(scene, seq);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int sequencer_retiming_segment_speed_set_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
const Sequence *seq = ed->act_seq;
|
||||
|
||||
if (seq == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
MutableSpan handles = SEQ_retiming_handles_get(seq);
|
||||
SeqRetimingHandle *handle = nullptr;
|
||||
|
||||
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
|
||||
const int handle_index = RNA_int_get(op->ptr, "handle_index");
|
||||
BLI_assert(handle_index < handles.size());
|
||||
handle = &handles[handle_index];
|
||||
}
|
||||
else {
|
||||
handle = closest_retiming_handle_get(C, seq, event->mval[0]);
|
||||
}
|
||||
|
||||
if (handle == nullptr) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No handle available");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
RNA_float_set(op->ptr, "speed", SEQ_retiming_handle_speed_get(seq, handle) * 100.0f);
|
||||
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, handle));
|
||||
return WM_operator_props_popup(C, op, event);
|
||||
}
|
||||
|
||||
void SEQUENCER_OT_retiming_segment_speed_set(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Set Speed";
|
||||
ot->description = "Set speed of retimed segment";
|
||||
ot->idname = "SEQUENCER_OT_retiming_segment_speed_set";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = sequencer_retiming_segment_speed_set_invoke;
|
||||
ot->exec = sequencer_retiming_segment_speed_set_exec;
|
||||
ot->poll = retiming_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
PropertyRNA *prop = RNA_def_int(ot->srna,
|
||||
"handle_index",
|
||||
0,
|
||||
0,
|
||||
INT_MAX,
|
||||
"Handle Index",
|
||||
"Index of handle to be removed",
|
||||
0,
|
||||
INT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
prop = RNA_def_float(ot->srna,
|
||||
"speed",
|
||||
100.0f,
|
||||
0.001f,
|
||||
FLT_MAX,
|
||||
"Speed",
|
||||
"New speed of retimed segment",
|
||||
0.1f,
|
||||
FLT_MAX);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -430,6 +430,7 @@ static void sequencer_gizmos(void)
|
|||
WM_gizmotype_append(GIZMO_GT_retime_handle_add);
|
||||
WM_gizmotype_append(GIZMO_GT_retime_handle);
|
||||
WM_gizmotype_append(GIZMO_GT_retime_remove);
|
||||
WM_gizmotype_append(GIZMO_GT_speed_set_remove);
|
||||
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d);
|
||||
WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_translate);
|
||||
|
|
|
@ -346,6 +346,7 @@ static float get_default_column_width(const ColumnValues &values)
|
|||
return 3.0f * float_width;
|
||||
case SPREADSHEET_VALUE_TYPE_COLOR:
|
||||
case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
|
||||
case SPREADSHEET_VALUE_TYPE_QUATERNION:
|
||||
return 4.0f * float_width;
|
||||
case SPREADSHEET_VALUE_TYPE_INSTANCES:
|
||||
return 8.0f;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "BLI_color.hh"
|
||||
#include "BLI_cpp_type.hh"
|
||||
#include "BLI_hash.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
@ -56,6 +57,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
|
|||
if (type.is<ColorGeometry4b>()) {
|
||||
return SPREADSHEET_VALUE_TYPE_BYTE_COLOR;
|
||||
}
|
||||
if (type.is<math::Quaternion>()) {
|
||||
return SPREADSHEET_VALUE_TYPE_QUATERNION;
|
||||
}
|
||||
|
||||
return SPREADSHEET_VALUE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
|
@ -204,6 +205,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
|
|||
const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
|
||||
this->draw_byte_color(params, value);
|
||||
}
|
||||
else if (data.type().is<math::Quaternion>()) {
|
||||
const float4 value = float4(data.get<math::Quaternion>(real_index));
|
||||
this->draw_float_vector(params, Span(&value.x, 4));
|
||||
}
|
||||
else if (data.type().is<bke::InstanceReference>()) {
|
||||
const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index);
|
||||
switch (value.type()) {
|
||||
|
|
|
@ -107,6 +107,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
|
|||
}
|
||||
case SPREADSHEET_VALUE_TYPE_STRING:
|
||||
return row_filter.value_string;
|
||||
case SPREADSHEET_VALUE_TYPE_QUATERNION:
|
||||
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
|
||||
return "";
|
||||
}
|
||||
|
@ -250,7 +251,8 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
|
|||
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
|
||||
break;
|
||||
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
|
||||
uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR);
|
||||
case SPREADSHEET_VALUE_TYPE_QUATERNION:
|
||||
uiItemL(layout, IFACE_("Unsupported column type"), ICON_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -590,6 +590,9 @@ static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3])
|
|||
if (active_pchan && active_pchan->parent) {
|
||||
/* For child, show parent local regardless if "local location" is set for parent bone. */
|
||||
transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat));
|
||||
float ob_orientations_mat[3][3];
|
||||
transform_orientations_create_from_axis(ob_orientations_mat, UNPACK3(ob->object_to_world));
|
||||
mul_m3_m3_pre(r_mat, ob_orientations_mat);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "BLI_cpp_type_make.hh"
|
||||
#include "BLI_cpp_types_make.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "FN_field_cpp_type_make.hh"
|
||||
|
@ -16,6 +17,7 @@ FN_FIELD_CPP_TYPE_MAKE(blender::float2);
|
|||
FN_FIELD_CPP_TYPE_MAKE(blender::float3);
|
||||
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4f);
|
||||
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4b);
|
||||
FN_FIELD_CPP_TYPE_MAKE(blender::math::Quaternion);
|
||||
FN_FIELD_CPP_TYPE_MAKE(bool);
|
||||
FN_FIELD_CPP_TYPE_MAKE(int8_t);
|
||||
FN_FIELD_CPP_TYPE_MAKE(int32_t);
|
||||
|
@ -31,6 +33,7 @@ void FN_register_cpp_types()
|
|||
FN_FIELD_CPP_TYPE_REGISTER(blender::float3);
|
||||
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
|
||||
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
|
||||
FN_FIELD_CPP_TYPE_REGISTER(blender::math::Quaternion);
|
||||
FN_FIELD_CPP_TYPE_REGISTER(bool);
|
||||
FN_FIELD_CPP_TYPE_REGISTER(int8_t);
|
||||
FN_FIELD_CPP_TYPE_REGISTER(int32_t);
|
||||
|
|
|
@ -1457,6 +1457,8 @@ static void customdata_weld(
|
|||
int src_i, dest_i;
|
||||
int j;
|
||||
|
||||
int vs_flag = 0;
|
||||
|
||||
/* interpolates a layer at a time */
|
||||
dest_i = 0;
|
||||
for (src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
|
@ -1477,7 +1479,21 @@ static void customdata_weld(
|
|||
/* if we found a matching layer, add the data */
|
||||
if (dest->layers[dest_i].type == type) {
|
||||
void *src_data = source->layers[src_i].data;
|
||||
if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
if (type == CD_MVERT_SKIN) {
|
||||
/* The `typeInfo->interp` of #CD_MVERT_SKIN does not include the flags, so #MVERT_SKIN_ROOT
|
||||
* and #MVERT_SKIN_LOOSE are lost after the interpolation.
|
||||
*
|
||||
* This behavior is not incorrect. Ideally, islands should be checked to avoid repeated
|
||||
* roots.
|
||||
*
|
||||
* However, for now, to prevent the loss of flags, they are simply re-added if any of the
|
||||
* merged vertices have them. */
|
||||
for (j = 0; j < count; j++) {
|
||||
MVertSkin *vs = &((MVertSkin *)src_data)[src_indices[j]];
|
||||
vs_flag |= vs->flag;
|
||||
}
|
||||
}
|
||||
else if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
/* Already calculated.
|
||||
* TODO: Optimize by exposing `typeInfo->interp`. */
|
||||
}
|
||||
|
@ -1507,7 +1523,11 @@ static void customdata_weld(
|
|||
for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
|
||||
CustomDataLayer *layer_dst = &dest->layers[dest_i];
|
||||
const eCustomDataType type = eCustomDataType(layer_dst->type);
|
||||
if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
if (type == CD_MVERT_SKIN) {
|
||||
MVertSkin *vs = &((MVertSkin *)layer_dst->data)[dest_index];
|
||||
vs->flag = vs_flag;
|
||||
}
|
||||
else if (CustomData_layer_has_interp(dest, dest_i)) {
|
||||
/* Already calculated. */
|
||||
}
|
||||
else if (CustomData_layer_has_math(dest, dest_i)) {
|
||||
|
|
|
@ -482,6 +482,7 @@ set(GLSL_SRC
|
|||
shaders/material/gpu_shader_material_eevee_specular.glsl
|
||||
shaders/material/gpu_shader_material_emission.glsl
|
||||
shaders/material/gpu_shader_material_fractal_noise.glsl
|
||||
shaders/material/gpu_shader_material_fractal_voronoi.glsl
|
||||
shaders/material/gpu_shader_material_fresnel.glsl
|
||||
shaders/material/gpu_shader_material_gamma.glsl
|
||||
shaders/material/gpu_shader_material_geometry.glsl
|
||||
|
@ -546,6 +547,7 @@ set(GLSL_SRC
|
|||
shaders/material/gpu_shader_material_volume_absorption.glsl
|
||||
shaders/material/gpu_shader_material_volume_principled.glsl
|
||||
shaders/material/gpu_shader_material_volume_scatter.glsl
|
||||
shaders/material/gpu_shader_material_voronoi.glsl
|
||||
shaders/material/gpu_shader_material_wireframe.glsl
|
||||
shaders/material/gpu_shader_material_world_normals.glsl
|
||||
|
||||
|
@ -793,8 +795,6 @@ if(WITH_GPU_BUILDTIME_SHADER_BUILDER)
|
|||
intern/gpu_shader_builder_stubs.cc
|
||||
${shader_create_info_list_file}
|
||||
)
|
||||
|
||||
setup_platform_linker_flags(shader_builder)
|
||||
target_link_libraries(shader_builder PUBLIC buildinfoobj)
|
||||
else()
|
||||
if(WIN32)
|
||||
|
@ -809,8 +809,9 @@ if(WITH_GPU_BUILDTIME_SHADER_BUILDER)
|
|||
${shader_create_info_list_file}
|
||||
${MANIFEST}
|
||||
)
|
||||
|
||||
endif()
|
||||
setup_platform_linker_flags(shader_builder)
|
||||
|
||||
target_link_libraries(shader_builder PUBLIC
|
||||
bf_gpu
|
||||
bf_intern_clog
|
||||
|
@ -848,6 +849,7 @@ if(WITH_GTESTS)
|
|||
tests/gpu_testing.cc
|
||||
|
||||
tests/buffer_texture_test.cc
|
||||
tests/compute_test.cc
|
||||
tests/framebuffer_test.cc
|
||||
tests/immediate_test.cc
|
||||
tests/index_buffer_test.cc
|
||||
|
|
|
@ -271,5 +271,36 @@ void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat * /*format*/,
|
|||
{
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Stubs of IMB_imbuf.h
|
||||
* \{ */
|
||||
struct ImBuf *IMB_ibImageFromMemory(const unsigned char * /*mem*/,
|
||||
size_t /*size*/,
|
||||
int /*flags*/,
|
||||
char /*colorspace*/[IM_MAX_SPACE],
|
||||
const char * /*descr*/)
|
||||
{
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct ImBuf *IMB_allocFromBuffer(const uint8_t * /*rect*/,
|
||||
const float * /*rectf*/,
|
||||
unsigned int /*w*/,
|
||||
unsigned int /*h*/,
|
||||
unsigned int /*channels*/)
|
||||
{
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IMB_saveiff(struct ImBuf * /*ibuf*/, const char * /*filepath*/, int /*flags*/)
|
||||
{
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
}
|
||||
|
|
|
@ -755,7 +755,8 @@ inline size_t to_bytesize(eGPUTextureFormat tex_format, eGPUDataFormat data_form
|
|||
* Standard component len calculation does not apply, as the texture formats contain multiple
|
||||
* channels, but associated data format contains several compacted components. */
|
||||
if ((tex_format == GPU_R11F_G11F_B10F && data_format == GPU_DATA_10_11_11_REV) ||
|
||||
(tex_format == GPU_RGB10_A2 && data_format == GPU_DATA_2_10_10_10_REV))
|
||||
((tex_format == GPU_RGB10_A2 || tex_format == GPU_RGB10_A2UI) &&
|
||||
data_format == GPU_DATA_2_10_10_10_REV))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
|
|
@ -3113,6 +3113,14 @@ std::string MSLGeneratorInterface::generate_msl_fragment_input_population()
|
|||
<< this->vertex_output_varyings[0].name << ";" << std::endl;
|
||||
}
|
||||
|
||||
/* Assign default gl_FragDepth.
|
||||
* If gl_FragDepth is used, it should default to the original depth value. Resolves #107159 where
|
||||
* overlay_wireframe_frag may not write to gl_FragDepth. */
|
||||
if (this->uses_gl_FragDepth) {
|
||||
out << "\t" << shader_stage_inst_name << ".gl_FragDepth = " << shader_stage_inst_name
|
||||
<< ".gl_FragCoord.z;" << std::endl;
|
||||
}
|
||||
|
||||
/* NOTE: We will only assign to the intersection of the vertex output and fragment input.
|
||||
* Fragment input represents varying variables which are declared (but are not necessarily
|
||||
* used). The Vertex out defines the set which is passed into the fragment shader, which
|
||||
|
|
|
@ -484,6 +484,7 @@ inline std::string tex_data_format_to_msl_type_str(eGPUDataFormat type)
|
|||
case GPU_DATA_UINT_24_8:
|
||||
return "uint"; /* Problematic type - but will match alignment. */
|
||||
case GPU_DATA_10_11_11_REV:
|
||||
case GPU_DATA_2_10_10_10_REV:
|
||||
return "float"; /* Problematic type - each component will be read as a float. */
|
||||
default:
|
||||
BLI_assert(false);
|
||||
|
@ -509,6 +510,7 @@ inline std::string tex_data_format_to_msl_texture_template_type(eGPUDataFormat t
|
|||
case GPU_DATA_UINT_24_8:
|
||||
return "uint"; /* Problematic type. */
|
||||
case GPU_DATA_10_11_11_REV:
|
||||
case GPU_DATA_2_10_10_10_REV:
|
||||
return "float"; /* Problematic type. */
|
||||
default:
|
||||
BLI_assert(false);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue