Merge branch 'master' into blender2.8
Conflicts: source/blender/blenkernel/intern/pointcache.c source/blender/makesrna/intern/rna_main_api.c source/blender/makesrna/intern/rna_particle.c
This commit is contained in:
commit
cbce7fef16
|
@ -801,7 +801,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
|
|||
}
|
||||
|
||||
/* free derived mesh */
|
||||
b_data.meshes.remove(b_mesh);
|
||||
b_data.meshes.remove(b_mesh, false);
|
||||
}
|
||||
}
|
||||
mesh->geometry_flags = requested_geometry_flags;
|
||||
|
@ -1013,7 +1013,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
|
|||
sync_curves(mesh, b_mesh, b_ob, true, time_index);
|
||||
|
||||
/* free derived mesh */
|
||||
b_data.meshes.remove(b_mesh);
|
||||
b_data.meshes.remove(b_mesh, false);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -393,6 +393,9 @@ static ShaderNode *add_node(Scene *scene,
|
|||
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
|
||||
aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
|
||||
break;
|
||||
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
|
||||
aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID;
|
||||
break;
|
||||
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
|
||||
aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
|
||||
break;
|
||||
|
@ -439,6 +442,9 @@ static ShaderNode *add_node(Scene *scene,
|
|||
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
|
||||
glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
|
||||
break;
|
||||
case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
|
||||
glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
break;
|
||||
}
|
||||
node = glossy;
|
||||
}
|
||||
|
@ -455,6 +461,9 @@ static ShaderNode *add_node(Scene *scene,
|
|||
case BL::ShaderNodeBsdfGlass::distribution_GGX:
|
||||
glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
|
||||
break;
|
||||
case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
|
||||
glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
||||
break;
|
||||
}
|
||||
node = glass;
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ ustring SocketType::type_name(Type type)
|
|||
ustring("boolean"),
|
||||
ustring("float"),
|
||||
ustring("int"),
|
||||
ustring("uint"),
|
||||
ustring("color"),
|
||||
ustring("vector"),
|
||||
ustring("point"),
|
||||
|
|
|
@ -76,6 +76,8 @@ set(SRC_CLOSURE_HEADERS
|
|||
closure/bsdf_diffuse.h
|
||||
closure/bsdf_diffuse_ramp.h
|
||||
closure/bsdf_microfacet.h
|
||||
closure/bsdf_microfacet_multi.h
|
||||
closure/bsdf_microfacet_multi_impl.h
|
||||
closure/bsdf_oren_nayar.h
|
||||
closure/bsdf_phong_ramp.h
|
||||
closure/bsdf_reflection.h
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../closure/bsdf_phong_ramp.h"
|
||||
#include "../closure/bsdf_diffuse_ramp.h"
|
||||
#include "../closure/bsdf_microfacet.h"
|
||||
#include "../closure/bsdf_microfacet_multi.h"
|
||||
#include "../closure/bsdf_reflection.h"
|
||||
#include "../closure/bsdf_refraction.h"
|
||||
#include "../closure/bsdf_transparent.h"
|
||||
|
@ -35,7 +36,7 @@
|
|||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
|
||||
ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
|
||||
{
|
||||
int label;
|
||||
|
||||
|
@ -85,6 +86,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
|
|||
label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
|
||||
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
|
||||
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
|
||||
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state));
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
|
@ -130,7 +139,7 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
|
|||
return label;
|
||||
}
|
||||
|
||||
ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
|
||||
ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
|
||||
{
|
||||
float3 eval;
|
||||
|
||||
|
@ -172,6 +181,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
|
|||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
|
@ -234,6 +249,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
|
|||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state));
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
|
@ -286,6 +307,10 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
|
|||
|
||||
#ifdef __SVM__
|
||||
switch(sc->type) {
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
bsdf_microfacet_multi_ggx_blur(sc, roughness);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
|
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* Copyright 2011-2016 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */
|
||||
|
||||
/* === GGX Microfacet distribution functions === */
|
||||
|
||||
/* Isotropic GGX microfacet distribution */
|
||||
ccl_device_inline float D_ggx(float3 wm, float alpha)
|
||||
{
|
||||
wm.z *= wm.z;
|
||||
alpha *= alpha;
|
||||
float tmp = (1.0f - wm.z) + alpha * wm.z;
|
||||
return alpha / max(M_PI_F * tmp*tmp, 1e-7f);
|
||||
}
|
||||
|
||||
/* Anisotropic GGX microfacet distribution */
|
||||
ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha)
|
||||
{
|
||||
float slope_x = -wm.x/alpha.x;
|
||||
float slope_y = -wm.y/alpha.y;
|
||||
float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y;
|
||||
|
||||
return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f);
|
||||
}
|
||||
|
||||
/* Sample slope distribution (based on page 14 of the supplemental implementation). */
|
||||
ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU)
|
||||
{
|
||||
if(cosI > 0.9999f) {
|
||||
const float r = sqrtf(randU.x / (1.0f - randU.x));
|
||||
const float phi = M_2PI_F * randU.y;
|
||||
return make_float2(r*cosf(phi), r*sinf(phi));
|
||||
}
|
||||
|
||||
const float sinI = sqrtf(1.0f - cosI*cosI);
|
||||
const float tanI = sinI/cosI;
|
||||
const float projA = 0.5f * (cosI + 1.0f);
|
||||
if(projA < 0.0001f)
|
||||
return make_float2(0.0f, 0.0f);
|
||||
const float A = 2.0f*randU.x*projA / cosI - 1.0f;
|
||||
float tmp = A*A-1.0f;
|
||||
if(fabsf(tmp) < 1e-7f)
|
||||
return make_float2(0.0f, 0.0f);
|
||||
tmp = 1.0f / tmp;
|
||||
const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp);
|
||||
|
||||
const float slopeX2 = tanI*tmp + D;
|
||||
const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2;
|
||||
|
||||
float U2;
|
||||
if(randU.y >= 0.5f)
|
||||
U2 = 2.0f*(randU.y - 0.5f);
|
||||
else
|
||||
U2 = 2.0f*(0.5f - randU.y);
|
||||
const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f);
|
||||
const float slopeY = z * sqrtf(1.0f + slopeX*slopeX);
|
||||
|
||||
if(randU.y >= 0.5f)
|
||||
return make_float2(slopeX, slopeY);
|
||||
else
|
||||
return make_float2(slopeX, -slopeY);
|
||||
}
|
||||
|
||||
/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */
|
||||
ccl_device_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU)
|
||||
{
|
||||
const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z));
|
||||
const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU);
|
||||
|
||||
const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y));
|
||||
const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y);
|
||||
const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y);
|
||||
|
||||
kernel_assert(isfinite(slope_x));
|
||||
return normalize(make_float3(-slope_x, -slope_y, 1.0f));
|
||||
}
|
||||
|
||||
/* === Phase functions: Glossy, Diffuse and Glass === */
|
||||
|
||||
/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */
|
||||
ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm)
|
||||
{
|
||||
if(n && k)
|
||||
*weight *= fresnel_conductor(dot(wi, wm), *n, *k);
|
||||
|
||||
return -wi + 2.0f * wm * dot(wi, wm);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k)
|
||||
{
|
||||
if(w.z > 0.9999f)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
const float3 wh = normalize(wo - w);
|
||||
if(wh.z < 0.0f)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z;
|
||||
|
||||
const float dotW_WH = dot(-w, wh);
|
||||
if(dotW_WH < 0.0f)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH);
|
||||
if(alpha.x == alpha.y)
|
||||
phase *= D_ggx(wh, alpha.x);
|
||||
else
|
||||
phase *= D_ggx_aniso(wh, alpha);
|
||||
|
||||
if(n && k) {
|
||||
/* Apply conductive fresnel term. */
|
||||
return phase * fresnel_conductor(dotW_WH, *n, *k);
|
||||
}
|
||||
|
||||
return make_float3(phase, phase, phase);
|
||||
}
|
||||
|
||||
/* Phase function for rough lambertian diffuse surfaces. */
|
||||
ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv)
|
||||
{
|
||||
float3 tm, bm;
|
||||
make_orthonormals(wm, &tm, &bm);
|
||||
|
||||
float2 disk = concentric_sample_disk(randu, randv);
|
||||
return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm)
|
||||
{
|
||||
const float v = max(0.0f, dot(w, wm)) * M_1_PI_F;
|
||||
return make_float3(v, v, v);
|
||||
}
|
||||
|
||||
/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */
|
||||
ccl_device_inline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside)
|
||||
{
|
||||
float cosI = dot(wi, wm);
|
||||
float f = fresnel_dielectric_cos(cosI, eta);
|
||||
if(randV < f) {
|
||||
*outside = true;
|
||||
return -wi + 2.0f * wm * cosI;
|
||||
}
|
||||
*outside = false;
|
||||
float inv_eta = 1.0f/eta;
|
||||
float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta);
|
||||
return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta)
|
||||
{
|
||||
if(w.z > 0.9999f)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z;
|
||||
float v;
|
||||
if(wo_outside) {
|
||||
const float3 wh = normalize(wo - w);
|
||||
if(wh.z < 0.0f)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
const float dotW_WH = dot(-w, wh);
|
||||
v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH);
|
||||
}
|
||||
else {
|
||||
float3 wh = normalize(wo*eta - w);
|
||||
if(wh.z < 0.0f)
|
||||
wh = -wh;
|
||||
const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh);
|
||||
if(dotW_WH < 0.0f)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float temp = dotW_WH + eta*dotWO_WH;
|
||||
v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp);
|
||||
}
|
||||
|
||||
return make_float3(v, v, v);
|
||||
}
|
||||
|
||||
/* === Utility functions for the random walks === */
|
||||
|
||||
/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */
|
||||
ccl_device_inline float mf_lambda(const float3 w, const float2 alpha)
|
||||
{
|
||||
if(w.z > 0.9999f)
|
||||
return 0.0f;
|
||||
else if(w.z < -0.9999f)
|
||||
return -1.0f;
|
||||
|
||||
const float inv_wz2 = 1.0f / (w.z*w.z);
|
||||
const float2 wa = make_float2(w.x, w.y)*alpha;
|
||||
float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2);
|
||||
if(w.z <= 0.0f)
|
||||
v = -v;
|
||||
|
||||
return 0.5f*(v - 1.0f);
|
||||
}
|
||||
|
||||
/* Height distribution CDF (based on page 4 of the supplemental implementation). */
|
||||
ccl_device_inline float mf_invC1(const float h)
|
||||
{
|
||||
return 2.0f * saturate(h) - 1.0f;
|
||||
}
|
||||
|
||||
ccl_device_inline float mf_C1(const float h)
|
||||
{
|
||||
return saturate(0.5f * (h + 1.0f));
|
||||
}
|
||||
|
||||
/* Masking function (based on page 16 of the supplemental implementation). */
|
||||
ccl_device_inline float mf_G1(const float3 w, const float C1, const float lambda)
|
||||
{
|
||||
if(w.z > 0.9999f)
|
||||
return 1.0f;
|
||||
if(w.z < 1e-5f)
|
||||
return 0.0f;
|
||||
return powf(C1, lambda);
|
||||
}
|
||||
|
||||
/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */
|
||||
ccl_device_inline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U)
|
||||
{
|
||||
if(w.z > 0.9999f)
|
||||
return false;
|
||||
if(w.z < -0.9999f) {
|
||||
*C1 *= U;
|
||||
*h = mf_invC1(*C1);
|
||||
*G1 = mf_G1(w, *C1, *lambda);
|
||||
}
|
||||
else if(fabsf(w.z) >= 0.0001f) {
|
||||
if(U > 1.0f - *G1)
|
||||
return false;
|
||||
if(*lambda >= 0.0f) {
|
||||
*C1 = 1.0f;
|
||||
}
|
||||
else {
|
||||
*C1 *= powf(1.0f-U, -1.0f / *lambda);
|
||||
}
|
||||
*h = mf_invC1(*C1);
|
||||
*G1 = mf_G1(w, *C1, *lambda);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* === PDF approximations for the different phase functions. ===
|
||||
* As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */
|
||||
|
||||
/* Approximation for the albedo of the single-scattering GGX distribution,
|
||||
* the missing energy is then approximated as a diffuse reflection for the PDF. */
|
||||
ccl_device_inline float mf_ggx_albedo(float r)
|
||||
{
|
||||
float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f;
|
||||
albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f;
|
||||
return saturate(albedo);
|
||||
}
|
||||
|
||||
ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
|
||||
{
|
||||
return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z;
|
||||
}
|
||||
|
||||
ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
|
||||
{
|
||||
return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z;
|
||||
}
|
||||
|
||||
ccl_device_inline float mf_diffuse_pdf(const float3 wo)
|
||||
{
|
||||
return M_1_PI_F * wo.z;
|
||||
}
|
||||
|
||||
ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta)
|
||||
{
|
||||
float3 wh;
|
||||
float fresnel;
|
||||
if(wi.z*wo.z > 0.0f) {
|
||||
wh = normalize(wi + wo);
|
||||
fresnel = fresnel_dielectric_cos(dot(wi, wh), eta);
|
||||
}
|
||||
else {
|
||||
wh = normalize(wi + wo*eta);
|
||||
fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta);
|
||||
}
|
||||
if(wh.z < 0.0f)
|
||||
wh = -wh;
|
||||
float3 r_wi = (wi.z < 0.0f)? -wi: wi;
|
||||
return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z);
|
||||
}
|
||||
|
||||
/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */
|
||||
|
||||
#define MF_NAME_JOIN(x,y) x ## _ ## y
|
||||
#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y)
|
||||
#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION)
|
||||
|
||||
#define MF_PHASE_FUNCTION glass
|
||||
#define MF_MULTI_GLASS
|
||||
#include "bsdf_microfacet_multi_impl.h"
|
||||
|
||||
/* The diffuse phase function is not implemented as a node yet. */
|
||||
#if 0
|
||||
#define MF_PHASE_FUNCTION diffuse
|
||||
#define MF_MULTI_DIFFUSE
|
||||
#include "bsdf_microfacet_multi_impl.h"
|
||||
#endif
|
||||
|
||||
#define MF_PHASE_FUNCTION glossy
|
||||
#define MF_MULTI_GLOSSY
|
||||
#include "bsdf_microfacet_multi_impl.h"
|
||||
|
||||
ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness)
|
||||
{
|
||||
sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */
|
||||
sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
|
||||
}
|
||||
|
||||
/* === Closure implementations === */
|
||||
|
||||
/* Multiscattering GGX Glossy closure */
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc)
|
||||
{
|
||||
sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */
|
||||
sc->data1 = clamp(sc->data1, 1e-4f, 1.0f);
|
||||
sc->custom1 = saturate(sc->custom1); /* color */
|
||||
sc->custom2 = saturate(sc->custom2);
|
||||
sc->custom3 = saturate(sc->custom3);
|
||||
|
||||
sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
|
||||
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM;
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc)
|
||||
{
|
||||
#ifdef __KERNEL_OPENCL__
|
||||
if(all(sc->T == 0.0f))
|
||||
#else
|
||||
if(sc->T == make_float3(0.0f, 0.0f, 0.0f))
|
||||
#endif
|
||||
sc->T = make_float3(1.0f, 0.0f, 0.0f);
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(sc);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_setup(ShaderClosure *sc)
|
||||
{
|
||||
sc->data1 = sc->data0;
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(sc);
|
||||
}
|
||||
|
||||
ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
|
||||
*pdf = 0.0f;
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
|
||||
bool is_aniso = (sc->data0 != sc->data1);
|
||||
float3 X, Y, Z;
|
||||
Z = sc->N;
|
||||
if(is_aniso)
|
||||
make_orthonormals_tangent(Z, sc->T, &X, &Y);
|
||||
else
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
|
||||
float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
|
||||
|
||||
if(is_aniso)
|
||||
*pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1));
|
||||
else
|
||||
*pdf = mf_ggx_pdf(localI, localO, sc->data0);
|
||||
return mf_eval_glossy(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
|
||||
{
|
||||
bool is_aniso = (sc->data0 != sc->data1);
|
||||
float3 X, Y, Z;
|
||||
Z = sc->N;
|
||||
if(is_aniso)
|
||||
make_orthonormals_tangent(Z, sc->T, &X, &Y);
|
||||
else
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
|
||||
float3 localO;
|
||||
|
||||
*eval = mf_sample_glossy(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL);
|
||||
if(is_aniso)
|
||||
*pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1));
|
||||
else
|
||||
*pdf = mf_ggx_pdf(localI, localO, sc->data0);
|
||||
*eval *= *pdf;
|
||||
|
||||
*omega_in = X*localO.x + Y*localO.y + Z*localO.z;
|
||||
return LABEL_REFLECT|LABEL_GLOSSY;
|
||||
}
|
||||
|
||||
/* Multiscattering GGX Glass closure */
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ShaderClosure *sc)
|
||||
{
|
||||
sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */
|
||||
sc->data1 = sc->data0;
|
||||
sc->data2 = max(0.0f, sc->data2); /* ior */
|
||||
sc->custom1 = saturate(sc->custom1); /* color */
|
||||
sc->custom2 = saturate(sc->custom2);
|
||||
sc->custom3 = saturate(sc->custom3);
|
||||
|
||||
sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
||||
|
||||
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM;
|
||||
}
|
||||
|
||||
ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
|
||||
float3 X, Y, Z;
|
||||
Z = sc->N;
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
|
||||
float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
|
||||
|
||||
*pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2);
|
||||
return mf_eval_glass(localI, localO, false, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2);
|
||||
}
|
||||
|
||||
ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
|
||||
float3 X, Y, Z;
|
||||
Z = sc->N;
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
|
||||
float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
|
||||
|
||||
*pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2);
|
||||
return mf_eval_glass(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state)
|
||||
{
|
||||
float3 X, Y, Z;
|
||||
Z = sc->N;
|
||||
make_orthonormals(Z, &X, &Y);
|
||||
|
||||
float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
|
||||
float3 localO;
|
||||
|
||||
*eval = mf_sample_glass(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2);
|
||||
*pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2);
|
||||
*eval *= *pdf;
|
||||
|
||||
*omega_in = X*localO.x + Y*localO.y + Z*localO.z;
|
||||
if(localO.z*localI.z > 0.0f)
|
||||
return LABEL_REFLECT|LABEL_GLOSSY;
|
||||
else
|
||||
return LABEL_TRANSMIT|LABEL_GLOSSY;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Copyright 2011-2016 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Evaluate the BSDF from wi to wo.
|
||||
* Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF,
|
||||
* which is evaluated stochastically through a random walk. At each bounce (except for the first one),
|
||||
* the amount of reflection from here towards wo is evaluated before bouncing again.
|
||||
*
|
||||
* Because of the random walk, the evaluation is not deterministic, but its expected value is equal to
|
||||
* the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined
|
||||
* analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered
|
||||
* energy is used. In combination with MIS, that is enough to produce an unbiased result, although
|
||||
* the balance heuristic isn't necessarily optimal anymore.
|
||||
*/
|
||||
ccl_device float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint* lcg_state
|
||||
#ifdef MF_MULTI_GLASS
|
||||
, const float eta
|
||||
#elif defined(MF_MULTI_GLOSSY)
|
||||
, float3 *n, float3 *k
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */
|
||||
bool swapped = false;
|
||||
#ifdef MF_MULTI_GLASS
|
||||
if(wi.z*wo.z < 0.0f) {
|
||||
/* Glass transmission is a special case and requires the directions to change hemisphere. */
|
||||
if(-wo.z < wi.z) {
|
||||
swapped = true;
|
||||
float3 tmp = -wo;
|
||||
wo = -wi;
|
||||
wi = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(wo.z < wi.z) {
|
||||
swapped = true;
|
||||
float3 tmp = wo;
|
||||
wo = wi;
|
||||
wi = tmp;
|
||||
}
|
||||
|
||||
if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside))
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
const float2 alpha = make_float2(alpha_x, alpha_y);
|
||||
|
||||
float lambda_r = mf_lambda(-wi, alpha);
|
||||
float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha);
|
||||
|
||||
/* Analytically compute single scattering for lower noise. */
|
||||
float3 eval;
|
||||
#ifdef MF_MULTI_GLASS
|
||||
eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta);
|
||||
if(wo_outside)
|
||||
eval *= -lambda_r / (shadowing_lambda - lambda_r);
|
||||
else
|
||||
eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f);
|
||||
#elif defined(MF_MULTI_DIFFUSE)
|
||||
/* Diffuse has no special closed form for the single scattering bounce */
|
||||
eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
const float3 wh = normalize(wi+wo);
|
||||
const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda);
|
||||
float val = G2 * 0.25f / wi.z;
|
||||
if(alpha.x == alpha.y)
|
||||
val *= D_ggx(wh, alpha.x);
|
||||
else
|
||||
val *= D_ggx_aniso(wh, alpha);
|
||||
if(n && k) {
|
||||
eval = fresnel_conductor(dot(wh, wi), *n, *k) * val;
|
||||
}
|
||||
else {
|
||||
eval = make_float3(val, val, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
float3 wr = -wi;
|
||||
float hr = 1.0f;
|
||||
float C1_r = 1.0f;
|
||||
float G1_r = 0.0f;
|
||||
bool outside = true;
|
||||
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
for(int order = 0; order < 10; order++) {
|
||||
/* Sample microfacet height and normal */
|
||||
if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float(lcg_state)))
|
||||
break;
|
||||
float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float(lcg_state), lcg_step_float(lcg_state)));
|
||||
|
||||
#ifdef MF_MULTI_DIFFUSE
|
||||
if(order == 0) {
|
||||
/* Compute single-scattering for diffuse. */
|
||||
const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r);
|
||||
eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm);
|
||||
}
|
||||
#endif
|
||||
if(order > 0) {
|
||||
/* Evaluate amount of scattering towards wo on this microfacet. */
|
||||
float3 phase;
|
||||
#ifdef MF_MULTI_GLASS
|
||||
if(outside)
|
||||
phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta);
|
||||
else
|
||||
phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta);
|
||||
#elif defined(MF_MULTI_DIFFUSE)
|
||||
phase = mf_eval_phase_diffuse(wo, wm);
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput;
|
||||
#endif
|
||||
eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda);
|
||||
}
|
||||
if(order+1 < 10) {
|
||||
/* Bounce from the microfacet. */
|
||||
#ifdef MF_MULTI_GLASS
|
||||
bool next_outside;
|
||||
wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float(lcg_state), &next_outside);
|
||||
if(!next_outside) {
|
||||
outside = !outside;
|
||||
wr = -wr;
|
||||
hr = -hr;
|
||||
}
|
||||
#elif defined(MF_MULTI_DIFFUSE)
|
||||
wr = mf_sample_phase_diffuse(wm, lcg_step_float(lcg_state), lcg_step_float(lcg_state));
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
|
||||
#endif
|
||||
|
||||
lambda_r = mf_lambda(wr, alpha);
|
||||
|
||||
throughput *= color;
|
||||
|
||||
C1_r = mf_C1(hr);
|
||||
G1_r = mf_G1(wr, C1_r, lambda_r);
|
||||
}
|
||||
}
|
||||
|
||||
if(swapped)
|
||||
eval *= fabsf(wi.z / wo.z);
|
||||
return eval;
|
||||
}
|
||||
|
||||
/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk
|
||||
* escaped the surface in wo. The function returns the throughput between wi and wo.
|
||||
* Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal.
|
||||
*/
|
||||
ccl_device float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state
|
||||
#ifdef MF_MULTI_GLASS
|
||||
, const float eta
|
||||
#elif defined(MF_MULTI_GLOSSY)
|
||||
, float3 *n, float3 *k
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const float2 alpha = make_float2(alpha_x, alpha_y);
|
||||
|
||||
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||
float3 wr = -wi;
|
||||
float lambda_r = mf_lambda(wr, alpha);
|
||||
float hr = 1.0f;
|
||||
float C1_r = 1.0f;
|
||||
float G1_r = 0.0f;
|
||||
bool outside = true;
|
||||
|
||||
int order;
|
||||
for(order = 0; order < 10; order++) {
|
||||
/* Sample microfacet height. */
|
||||
if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float(lcg_state))) {
|
||||
/* The random walk has left the surface. */
|
||||
*wo = outside? wr: -wr;
|
||||
return throughput;
|
||||
}
|
||||
/* Sample microfacet normal. */
|
||||
float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float(lcg_state), lcg_step_float(lcg_state)));
|
||||
|
||||
/* First-bounce color is already accounted for in mix weight. */
|
||||
if(order > 0)
|
||||
throughput *= color;
|
||||
|
||||
/* Bounce from the microfacet. */
|
||||
#ifdef MF_MULTI_GLASS
|
||||
bool next_outside;
|
||||
wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float(lcg_state), &next_outside);
|
||||
if(!next_outside) {
|
||||
hr = -hr;
|
||||
wr = -wr;
|
||||
outside = !outside;
|
||||
}
|
||||
#elif defined(MF_MULTI_DIFFUSE)
|
||||
wr = mf_sample_phase_diffuse(wm, lcg_step_float(lcg_state), lcg_step_float(lcg_state));
|
||||
#else /* MF_MULTI_GLOSSY */
|
||||
wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
|
||||
#endif
|
||||
|
||||
/* Update random walk parameters. */
|
||||
lambda_r = mf_lambda(wr, alpha);
|
||||
G1_r = mf_G1(wr, C1_r, lambda_r);
|
||||
}
|
||||
*wo = make_float3(0.0f, 0.0f, 1.0f);
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
#undef MF_MULTI_GLASS
|
||||
#undef MF_MULTI_DIFFUSE
|
||||
#undef MF_MULTI_GLOSSY
|
||||
#undef MF_PHASE_FUNCTION
|
|
@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta)
|
|||
return 1.0f; // TIR(no refracted component)
|
||||
}
|
||||
|
||||
#if 0
|
||||
ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
|
||||
{
|
||||
float3 cosi2 = make_float3(cosi*cosi);
|
||||
float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi);
|
||||
float3 one = make_float3(1.0f, 1.0f, 1.0f);
|
||||
float3 tmp_f = eta * eta + k * k;
|
||||
float3 tmp = tmp_f * cosi2;
|
||||
|
@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k
|
|||
(tmp_f + (2.0f * eta * cosi) + cosi2);
|
||||
return(Rparl2 + Rperp2) * 0.5f;
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device float smooth_step(float edge0, float edge1, float x)
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
|
|||
|
||||
/* evaluate surface shader */
|
||||
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
|
||||
shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
|
||||
|
||||
/* TODO, disable the closures we won't need */
|
||||
|
||||
|
@ -220,6 +220,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg,
|
|||
|
||||
ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
RNG *rng,
|
||||
PathState *state,
|
||||
float3 direct,
|
||||
float3 indirect,
|
||||
|
@ -239,12 +240,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
|
|||
}
|
||||
else {
|
||||
/* surface color of the pass only */
|
||||
shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
|
||||
return kernel_bake_shader_bsdf(kg, sd, type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
|
||||
color = kernel_bake_shader_bsdf(kg, sd, type);
|
||||
}
|
||||
|
||||
|
@ -336,7 +337,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
|||
case SHADER_EVAL_NORMAL:
|
||||
{
|
||||
if((sd.flag & SD_HAS_BUMP)) {
|
||||
shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
|
||||
}
|
||||
|
||||
/* compression: normal = (2 * color) - 1 */
|
||||
|
@ -350,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
|||
}
|
||||
case SHADER_EVAL_EMISSION:
|
||||
{
|
||||
shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
|
||||
shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
|
||||
out = shader_emissive_eval(kg, &sd);
|
||||
break;
|
||||
}
|
||||
|
@ -403,6 +404,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
|||
{
|
||||
out = kernel_bake_evaluate_direct_indirect(kg,
|
||||
&sd,
|
||||
&rng,
|
||||
&state,
|
||||
L.direct_diffuse,
|
||||
L.indirect_diffuse,
|
||||
|
@ -414,6 +416,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
|||
{
|
||||
out = kernel_bake_evaluate_direct_indirect(kg,
|
||||
&sd,
|
||||
&rng,
|
||||
&state,
|
||||
L.direct_glossy,
|
||||
L.indirect_glossy,
|
||||
|
@ -425,6 +428,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
|||
{
|
||||
out = kernel_bake_evaluate_direct_indirect(kg,
|
||||
&sd,
|
||||
&rng,
|
||||
&state,
|
||||
L.direct_transmission,
|
||||
L.indirect_transmission,
|
||||
|
@ -437,6 +441,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
|
|||
#ifdef __SUBSURFACE__
|
||||
out = kernel_bake_evaluate_direct_indirect(kg,
|
||||
&sd,
|
||||
&rng,
|
||||
&state,
|
||||
L.direct_subsurface,
|
||||
L.indirect_subsurface,
|
||||
|
|
|
@ -57,7 +57,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
|
|||
/* no path flag, we're evaluating this for all closures. that's weak but
|
||||
* we'd have to do multiple evaluations otherwise */
|
||||
path_state_modify_bounce(state, true);
|
||||
shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
|
||||
shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
|
||||
path_state_modify_bounce(state, false);
|
||||
|
||||
/* evaluate emissive closure */
|
||||
|
|
|
@ -253,7 +253,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
|||
&isect,
|
||||
ray);
|
||||
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
|
||||
shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
|
||||
shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
|
||||
#ifdef __BRANCHED_PATH__
|
||||
shader_merge_closures(sd);
|
||||
#endif
|
||||
|
@ -791,7 +791,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
|
|||
/* setup shading */
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
|
||||
shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
|
||||
|
||||
/* holdout */
|
||||
#ifdef __HOLDOUT__
|
||||
|
|
|
@ -463,7 +463,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
|
|||
|
||||
/* setup shading */
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_merge_closures(&sd);
|
||||
|
||||
/* holdout */
|
||||
|
|
|
@ -232,14 +232,14 @@ ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG
|
|||
|
||||
/* Linear Congruential Generator */
|
||||
|
||||
ccl_device uint lcg_step_uint(uint *rng)
|
||||
ccl_device uint lcg_step_uint(ccl_addr_space uint *rng)
|
||||
{
|
||||
/* implicit mod 2^32 */
|
||||
*rng = (1103515245*(*rng) + 12345);
|
||||
return *rng;
|
||||
}
|
||||
|
||||
ccl_device float lcg_step_float(uint *rng)
|
||||
ccl_device float lcg_step_float(ccl_addr_space uint *rng)
|
||||
{
|
||||
/* implicit mod 2^32 */
|
||||
*rng = (1103515245*(*rng) + 12345);
|
||||
|
@ -309,7 +309,7 @@ ccl_device_inline void path_state_branch(PathState *state, int branch, int num_b
|
|||
state->num_samples = state->num_samples*num_branches;
|
||||
}
|
||||
|
||||
ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scramble)
|
||||
ccl_device_inline uint lcg_state_init(RNG *rng, const ccl_addr_space PathState *state, uint scramble)
|
||||
{
|
||||
return lcg_init(*rng + state->rng_offset + state->sample*scramble);
|
||||
}
|
||||
|
|
|
@ -468,6 +468,9 @@ ccl_device void shader_merge_closures(ShaderData *sd)
|
|||
continue;
|
||||
}
|
||||
|
||||
if((sd->flag & SD_BSDF_HAS_CUSTOM) && !(sci->custom1 == scj->custom1 && sci->custom2 == scj->custom2 && sci->custom3 == scj->custom3))
|
||||
continue;
|
||||
|
||||
sci->weight += scj->weight;
|
||||
sci->sample_weight += scj->sample_weight;
|
||||
|
||||
|
@ -488,7 +491,7 @@ ccl_device void shader_merge_closures(ShaderData *sd)
|
|||
|
||||
/* BSDF */
|
||||
|
||||
ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf,
|
||||
ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf,
|
||||
int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight)
|
||||
{
|
||||
/* this is the veach one-sample model with balance heuristic, some pdf
|
||||
|
@ -517,7 +520,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
|
|||
|
||||
#ifdef __BRANCHED_PATH__
|
||||
ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
|
||||
const ShaderData *sd,
|
||||
ShaderData *sd,
|
||||
const float3 omega_in,
|
||||
BsdfEval *result_eval,
|
||||
float light_pdf,
|
||||
|
@ -563,7 +566,7 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg,
|
|||
}
|
||||
}
|
||||
|
||||
ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
|
||||
ccl_device int shader_bsdf_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
float randu, float randv, BsdfEval *bsdf_eval,
|
||||
float3 *omega_in, differential3 *domega_in, float *pdf)
|
||||
{
|
||||
|
@ -620,7 +623,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
|
|||
return label;
|
||||
}
|
||||
|
||||
ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd,
|
||||
ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd,
|
||||
const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval,
|
||||
float3 *omega_in, differential3 *domega_in, float *pdf)
|
||||
{
|
||||
|
@ -824,7 +827,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
|
|||
|
||||
/* Surface Evaluation */
|
||||
|
||||
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
|
||||
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng,
|
||||
ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx)
|
||||
{
|
||||
ccl_fetch(sd, num_closure) = 0;
|
||||
|
@ -846,6 +849,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
|
|||
ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) {
|
||||
ccl_fetch(sd, lcg_state) = lcg_state_init(rng, state, 0xb4bc3953);
|
||||
}
|
||||
}
|
||||
|
||||
/* Background Evaluation */
|
||||
|
|
|
@ -117,7 +117,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd,
|
|||
/* attenuation from transparent surface */
|
||||
if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
|
||||
path_state_modify_bounce(state, true);
|
||||
shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
|
||||
shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
|
||||
path_state_modify_bounce(state, false);
|
||||
|
||||
throughput *= shader_bsdf_transparency(kg, shadow_sd);
|
||||
|
@ -252,7 +252,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
|
|||
/* attenuation from transparent surface */
|
||||
if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) {
|
||||
path_state_modify_bounce(state, true);
|
||||
shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
|
||||
shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
|
||||
path_state_modify_bounce(state, false);
|
||||
|
||||
throughput *= shader_bsdf_transparency(kg, shadow_sd);
|
||||
|
|
|
@ -198,7 +198,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg,
|
|||
|
||||
if(bump || texture_blur > 0.0f) {
|
||||
/* average color and normal at incoming point */
|
||||
shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
|
||||
shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
|
||||
float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL);
|
||||
|
||||
/* we simply divide out the average color and multiply with the average
|
||||
|
|
|
@ -679,31 +679,34 @@ typedef enum ShaderContext {
|
|||
|
||||
enum ShaderDataFlag {
|
||||
/* runtime flags */
|
||||
SD_BACKFACING = (1 << 0), /* backside of surface? */
|
||||
SD_EMISSION = (1 << 1), /* have emissive closure? */
|
||||
SD_BSDF = (1 << 2), /* have bsdf closure? */
|
||||
SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */
|
||||
SD_BSSRDF = (1 << 4), /* have bssrdf */
|
||||
SD_HOLDOUT = (1 << 5), /* have holdout closure? */
|
||||
SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */
|
||||
SD_SCATTER = (1 << 7), /* have volume phase closure? */
|
||||
SD_AO = (1 << 8), /* have ao closure? */
|
||||
SD_TRANSPARENT = (1 << 9), /* have transparent closure? */
|
||||
SD_BACKFACING = (1 << 0), /* backside of surface? */
|
||||
SD_EMISSION = (1 << 1), /* have emissive closure? */
|
||||
SD_BSDF = (1 << 2), /* have bsdf closure? */
|
||||
SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */
|
||||
SD_BSSRDF = (1 << 4), /* have bssrdf */
|
||||
SD_HOLDOUT = (1 << 5), /* have holdout closure? */
|
||||
SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */
|
||||
SD_SCATTER = (1 << 7), /* have volume phase closure? */
|
||||
SD_AO = (1 << 8), /* have ao closure? */
|
||||
SD_TRANSPARENT = (1 << 9), /* have transparent closure? */
|
||||
SD_BSDF_NEEDS_LCG = (1 << 10),
|
||||
SD_BSDF_HAS_CUSTOM = (1 << 11), /* are the custom variables relevant? */
|
||||
|
||||
SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF|
|
||||
SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO),
|
||||
SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO|
|
||||
SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM),
|
||||
|
||||
/* shader flags */
|
||||
SD_USE_MIS = (1 << 10), /* direct light sample */
|
||||
SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */
|
||||
SD_HAS_VOLUME = (1 << 12), /* has volume shader */
|
||||
SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */
|
||||
SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */
|
||||
SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */
|
||||
SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */
|
||||
SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */
|
||||
SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */
|
||||
SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */
|
||||
SD_USE_MIS = (1 << 12), /* direct light sample */
|
||||
SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */
|
||||
SD_HAS_VOLUME = (1 << 14), /* has volume shader */
|
||||
SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */
|
||||
SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */
|
||||
SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */
|
||||
SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */
|
||||
SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */
|
||||
SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */
|
||||
SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */
|
||||
|
||||
SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|
|
||||
SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME|
|
||||
|
@ -711,13 +714,13 @@ enum ShaderDataFlag {
|
|||
SD_VOLUME_CUBIC|SD_HAS_BUMP),
|
||||
|
||||
/* object flags */
|
||||
SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */
|
||||
SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */
|
||||
SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */
|
||||
SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */
|
||||
SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */
|
||||
SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */
|
||||
SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */
|
||||
SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */
|
||||
SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */
|
||||
SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */
|
||||
SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */
|
||||
SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */
|
||||
SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */
|
||||
SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */
|
||||
|
||||
SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
|
||||
SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
|
||||
|
@ -806,6 +809,9 @@ typedef ccl_addr_space struct ShaderData {
|
|||
int num_closure;
|
||||
float randb_closure;
|
||||
|
||||
/* LCG state for closures that require additional random numbers. */
|
||||
uint lcg_state;
|
||||
|
||||
/* ray start position, only set for backgrounds */
|
||||
float3 ray_P;
|
||||
differential3 ray_dP;
|
||||
|
|
|
@ -44,11 +44,13 @@
|
|||
#include "kernel_compat_cpu.h"
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_montecarlo.h"
|
||||
#include "kernel_random.h"
|
||||
|
||||
#include "closure/bsdf_util.h"
|
||||
#include "closure/bsdf_ashikhmin_velvet.h"
|
||||
#include "closure/bsdf_diffuse.h"
|
||||
#include "closure/bsdf_microfacet.h"
|
||||
#include "closure/bsdf_microfacet_multi.h"
|
||||
#include "closure/bsdf_oren_nayar.h"
|
||||
#include "closure/bsdf_reflection.h"
|
||||
#include "closure/bsdf_refraction.h"
|
||||
|
@ -205,6 +207,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
|
|||
bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare);
|
||||
register_closure(ss, "microfacet_ggx_refraction", id++,
|
||||
bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare);
|
||||
register_closure(ss, "microfacet_multi_ggx", id++,
|
||||
closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare);
|
||||
register_closure(ss, "microfacet_multi_ggx_glass", id++,
|
||||
closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare);
|
||||
register_closure(ss, "microfacet_multi_ggx_aniso", id++,
|
||||
closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare);
|
||||
register_closure(ss, "microfacet_beckmann", id++,
|
||||
bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare);
|
||||
register_closure(ss, "microfacet_beckmann_aniso", id++,
|
||||
|
@ -250,5 +258,127 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
|
|||
volume_absorption_params(), volume_absorption_prepare);
|
||||
}
|
||||
|
||||
/* Multiscattering GGX closures */
|
||||
|
||||
class MicrofacetMultiClosure : public CBSDFClosure {
|
||||
public:
|
||||
float3 color;
|
||||
|
||||
/* Technically, the MultiGGX Glass closure may also transmit.
|
||||
* However, since this is set statically and only used for caustic flags, this is probably as good as it gets. */
|
||||
MicrofacetMultiClosure() : CBSDFClosure(LABEL_GLOSSY|LABEL_REFLECT)
|
||||
{
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
sc.prim = NULL;
|
||||
sc.custom1 = color.x;
|
||||
sc.custom2 = color.y;
|
||||
sc.custom3 = color.z;
|
||||
}
|
||||
|
||||
void blur(float roughness)
|
||||
{
|
||||
}
|
||||
|
||||
float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const
|
||||
{
|
||||
pdf = 0.0f;
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const
|
||||
{
|
||||
pdf = 0.0f;
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
int sample(const float3 &Ng,
|
||||
const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy,
|
||||
float &pdf, float3 &eval) const
|
||||
{
|
||||
pdf = 0;
|
||||
return LABEL_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure {
|
||||
public:
|
||||
MicrofacetMultiGGXClosure() : MicrofacetMultiClosure() {}
|
||||
|
||||
void setup()
|
||||
{
|
||||
MicrofacetMultiClosure::setup();
|
||||
m_shaderdata_flag = bsdf_microfacet_multi_ggx_setup(&sc);
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam *closure_bsdf_microfacet_multi_ggx_params()
|
||||
{
|
||||
static ClosureParam params[] = {
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N),
|
||||
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0),
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
|
||||
CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
|
||||
};
|
||||
return params;
|
||||
}
|
||||
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure);
|
||||
|
||||
class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure {
|
||||
public:
|
||||
MicrofacetMultiGGXAnisoClosure() : MicrofacetMultiClosure() {}
|
||||
|
||||
void setup()
|
||||
{
|
||||
MicrofacetMultiClosure::setup();
|
||||
m_shaderdata_flag = bsdf_microfacet_multi_ggx_aniso_setup(&sc);
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params()
|
||||
{
|
||||
static ClosureParam params[] = {
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N),
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.T),
|
||||
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0),
|
||||
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data1),
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
|
||||
CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
|
||||
};
|
||||
return params;
|
||||
}
|
||||
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure);
|
||||
|
||||
class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure {
|
||||
public:
|
||||
MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {}
|
||||
|
||||
void setup()
|
||||
{
|
||||
MicrofacetMultiClosure::setup();
|
||||
m_shaderdata_flag = bsdf_microfacet_multi_ggx_glass_setup(&sc);
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params()
|
||||
{
|
||||
static ClosureParam params[] = {
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N),
|
||||
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0),
|
||||
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data2),
|
||||
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color),
|
||||
CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure)
|
||||
};
|
||||
return params;
|
||||
}
|
||||
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params();
|
|||
OSL::ClosureParam *closure_bssrdf_gaussian_params();
|
||||
OSL::ClosureParam *closure_bssrdf_burley_params();
|
||||
OSL::ClosureParam *closure_henyey_greenstein_volume_params();
|
||||
OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params();
|
||||
OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params();
|
||||
OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params();
|
||||
|
||||
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
|
||||
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
|
||||
|
@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
|
|||
void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data);
|
||||
void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data);
|
||||
void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data);
|
||||
void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data);
|
||||
void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data);
|
||||
void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data);
|
||||
|
||||
#define CCLOSURE_PREPARE(name, classname) \
|
||||
void name(RendererServices *, int id, void *data) \
|
||||
|
|
|
@ -177,6 +177,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
|
|||
case CClosurePrimitive::BSDF: {
|
||||
CBSDFClosure *bsdf = (CBSDFClosure *)prim;
|
||||
int scattering = bsdf->scattering();
|
||||
int shaderdata_flag = bsdf->shaderdata_flag();
|
||||
|
||||
/* caustic options */
|
||||
if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
|
||||
|
@ -201,11 +202,16 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
|
|||
sc.data1 = bsdf->sc.data1;
|
||||
sc.data2 = bsdf->sc.data2;
|
||||
sc.prim = bsdf->sc.prim;
|
||||
if(shaderdata_flag & SD_BSDF_HAS_CUSTOM) {
|
||||
sc.custom1 = bsdf->sc.custom1;
|
||||
sc.custom2 = bsdf->sc.custom2;
|
||||
sc.custom3 = bsdf->sc.custom3;
|
||||
}
|
||||
|
||||
/* add */
|
||||
if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
|
||||
sd->closure[sd->num_closure++] = sc;
|
||||
sd->flag |= bsdf->shaderdata_flag();
|
||||
sd->flag |= shaderdata_flag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ shader node_anisotropic_bsdf(
|
|||
BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV);
|
||||
else if (distribution == "GGX")
|
||||
BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV);
|
||||
else if (distribution == "Multiscatter GGX")
|
||||
BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color);
|
||||
else
|
||||
BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ shader node_glass_bsdf(
|
|||
else if (distribution == "beckmann")
|
||||
BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) +
|
||||
(1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta));
|
||||
else if (distribution == "Multiscatter GGX")
|
||||
BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color);
|
||||
else if (distribution == "GGX")
|
||||
BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) +
|
||||
(1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta));
|
||||
|
|
|
@ -30,6 +30,8 @@ shader node_glossy_bsdf(
|
|||
BSDF = Color * microfacet_beckmann(Normal, Roughness);
|
||||
else if (distribution == "GGX")
|
||||
BSDF = Color * microfacet_ggx(Normal, Roughness);
|
||||
else if (distribution == "Multiscatter GGX")
|
||||
BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color);
|
||||
else
|
||||
BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness);
|
||||
|
||||
|
|
|
@ -527,6 +527,9 @@ closure color transparent() BUILTIN;
|
|||
closure color microfacet_ggx(normal N, float ag) BUILTIN;
|
||||
closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN;
|
||||
closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN;
|
||||
closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN;
|
||||
closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN;
|
||||
closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN;
|
||||
closure color microfacet_beckmann(normal N, float ab) BUILTIN;
|
||||
closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN;
|
||||
closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN;
|
||||
|
|
|
@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval(
|
|||
isect,
|
||||
&ray);
|
||||
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
|
||||
shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
|
||||
shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,7 +186,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
|
|||
case CLOSURE_BSDF_REFLECTION_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: {
|
||||
#ifdef __CAUSTICS_TRICKS__
|
||||
if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
|
||||
break;
|
||||
|
@ -206,6 +207,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
|
|||
ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc);
|
||||
else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID)
|
||||
ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc);
|
||||
else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
|
||||
kernel_assert(stack_valid(data_node.z));
|
||||
float3 color = stack_load_float3(stack, data_node.z);
|
||||
sc->custom1 = color.x;
|
||||
sc->custom2 = color.y;
|
||||
sc->custom3 = color.z;
|
||||
ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(sc);
|
||||
}
|
||||
else
|
||||
ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc);
|
||||
}
|
||||
|
@ -307,8 +316,36 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
|
|||
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: {
|
||||
#ifdef __CAUSTICS_TRICKS__
|
||||
if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
|
||||
break;
|
||||
#endif
|
||||
ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
|
||||
|
||||
if(sc) {
|
||||
sc->N = N;
|
||||
|
||||
sc->data0 = param1;
|
||||
sc->data1 = param1;
|
||||
float eta = fmaxf(param2, 1e-5f);
|
||||
sc->data2 = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
|
||||
|
||||
kernel_assert(stack_valid(data_node.z));
|
||||
float3 color = stack_load_float3(stack, data_node.z);
|
||||
sc->custom1 = color.x;
|
||||
sc->custom2 = color.y;
|
||||
sc->custom3 = color.z;
|
||||
|
||||
/* setup bsdf */
|
||||
ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(sc);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID:
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: {
|
||||
#ifdef __CAUSTICS_TRICKS__
|
||||
if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
|
||||
|
@ -346,6 +383,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
|
|||
ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc);
|
||||
else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID)
|
||||
ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc);
|
||||
else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) {
|
||||
kernel_assert(stack_valid(data_node.w));
|
||||
float3 color = stack_load_float3(stack, data_node.w);
|
||||
sc->custom1 = color.x;
|
||||
sc->custom2 = color.y;
|
||||
sc->custom3 = color.z;
|
||||
ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(sc);
|
||||
}
|
||||
else
|
||||
ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc);
|
||||
}
|
||||
|
|
|
@ -396,8 +396,10 @@ typedef enum ClosureType {
|
|||
CLOSURE_BSDF_REFLECTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
|
||||
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID,
|
||||
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID,
|
||||
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
|
||||
|
@ -413,6 +415,7 @@ typedef enum ClosureType {
|
|||
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
|
||||
CLOSURE_BSDF_SHARP_GLASS_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
|
|
|
@ -1828,6 +1828,7 @@ NODE_DEFINE(AnisotropicBsdfNode)
|
|||
static NodeEnum distribution_enum;
|
||||
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
|
||||
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
|
||||
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID);
|
||||
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
|
||||
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
|
||||
|
||||
|
@ -1864,7 +1865,10 @@ void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
|
|||
{
|
||||
closure = distribution;
|
||||
|
||||
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
|
||||
if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID)
|
||||
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
|
||||
else
|
||||
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
|
||||
}
|
||||
|
||||
void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
|
||||
|
@ -1888,6 +1892,7 @@ NODE_DEFINE(GlossyBsdfNode)
|
|||
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
|
||||
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
|
||||
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
|
||||
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
|
||||
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
|
||||
SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
|
||||
|
||||
|
@ -1937,6 +1942,8 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler)
|
|||
|
||||
if(closure == CLOSURE_BSDF_REFLECTION_ID)
|
||||
BsdfNode::compile(compiler, NULL, NULL);
|
||||
else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
|
||||
BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color"));
|
||||
else
|
||||
BsdfNode::compile(compiler, input("Roughness"), NULL);
|
||||
}
|
||||
|
@ -1961,6 +1968,7 @@ NODE_DEFINE(GlassBsdfNode)
|
|||
distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
|
||||
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
|
||||
distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
||||
distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
||||
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
||||
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
|
||||
SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
|
||||
|
@ -2011,6 +2019,8 @@ void GlassBsdfNode::compile(SVMCompiler& compiler)
|
|||
|
||||
if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
|
||||
BsdfNode::compile(compiler, NULL, input("IOR"));
|
||||
else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
|
||||
else
|
||||
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
|
||||
}
|
||||
|
|
|
@ -545,6 +545,11 @@ ccl_device_inline float3 normalize(const float3 a)
|
|||
|
||||
#endif
|
||||
|
||||
ccl_device_inline float3 saturate3(float3 a)
|
||||
{
|
||||
return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
|
||||
}
|
||||
|
||||
ccl_device_inline float3 normalize_len(const float3 a, float *t)
|
||||
{
|
||||
*t = len(a);
|
||||
|
@ -1329,6 +1334,15 @@ ccl_device float safe_modulo(float a, float b)
|
|||
return (b != 0.0f)? fmodf(a, b): 0.0f;
|
||||
}
|
||||
|
||||
ccl_device_inline float beta(float x, float y)
|
||||
{
|
||||
#ifndef __KERNEL_OPENCL__
|
||||
return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y));
|
||||
#else
|
||||
return expf(lgamma(x) + lgamma(y) - lgamma(x+y));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Ray Intersection */
|
||||
|
||||
ccl_device bool ray_sphere_intersect(
|
||||
|
|
|
@ -260,7 +260,11 @@ string string_human_readable_size(size_t size)
|
|||
|
||||
string string_human_readable_number(size_t num)
|
||||
{
|
||||
/* add thousands separators */
|
||||
if(num == 0) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
/* Add thousands separators. */
|
||||
char buf[32];
|
||||
|
||||
char* p = buf+31;
|
||||
|
|
|
@ -96,25 +96,25 @@ class ConstraintButtonsPanel:
|
|||
def CHILD_OF(self, context, layout, con):
|
||||
self.target_template(layout, con)
|
||||
|
||||
split = layout.split()
|
||||
#split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Location:")
|
||||
col.prop(con, "use_location_x", text="X")
|
||||
col.prop(con, "use_location_y", text="Y")
|
||||
col.prop(con, "use_location_z", text="Z")
|
||||
#col = split.column()
|
||||
#col.label(text="Location:")
|
||||
#col.prop(con, "use_location_x", text="X")
|
||||
#col.prop(con, "use_location_y", text="Y")
|
||||
#col.prop(con, "use_location_z", text="Z")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Rotation:")
|
||||
col.prop(con, "use_rotation_x", text="X")
|
||||
col.prop(con, "use_rotation_y", text="Y")
|
||||
col.prop(con, "use_rotation_z", text="Z")
|
||||
#col = split.column()
|
||||
#col.label(text="Rotation:")
|
||||
#col.prop(con, "use_rotation_x", text="X")
|
||||
#col.prop(con, "use_rotation_y", text="Y")
|
||||
#col.prop(con, "use_rotation_z", text="Z")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Scale:")
|
||||
col.prop(con, "use_scale_x", text="X")
|
||||
col.prop(con, "use_scale_y", text="Y")
|
||||
col.prop(con, "use_scale_z", text="Z")
|
||||
#col = split.column()
|
||||
#col.label(text="Scale:")
|
||||
#col.prop(con, "use_scale_x", text="X")
|
||||
#col.prop(con, "use_scale_y", text="Y")
|
||||
#col.prop(con, "use_scale_z", text="Z")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("constraint.childof_set_inverse")
|
||||
|
|
|
@ -63,6 +63,9 @@ class GreasePencilDrawingToolsPanel:
|
|||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
is_3d_view = context.space_data.type == 'VIEW_3D'
|
||||
is_clip_editor = context.space_data.type == 'CLIP_EDITOR'
|
||||
|
||||
col = layout.column(align=True)
|
||||
|
||||
col.label(text="Draw:")
|
||||
|
@ -85,9 +88,9 @@ class GreasePencilDrawingToolsPanel:
|
|||
col.separator()
|
||||
col.label("Data Source:")
|
||||
row = col.row(align=True)
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
if is_3d_view:
|
||||
row.prop(context.tool_settings, "grease_pencil_source", expand=True)
|
||||
elif context.space_data.type == 'CLIP_EDITOR':
|
||||
elif is_clip_editor:
|
||||
row.prop(context.space_data, "grease_pencil_source", expand=True)
|
||||
|
||||
col.separator()
|
||||
|
@ -97,19 +100,19 @@ class GreasePencilDrawingToolsPanel:
|
|||
|
||||
gpd = context.gpencil_data
|
||||
|
||||
if gpd:
|
||||
if gpd and not is_3d_view:
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
|
||||
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
if is_3d_view:
|
||||
col.separator()
|
||||
col.separator()
|
||||
|
||||
col.label(text="Tools:")
|
||||
col.operator("gpencil.convert", text="Convert...")
|
||||
col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type")
|
||||
col.operator("view3d.ruler")
|
||||
|
||||
|
||||
|
@ -133,20 +136,23 @@ class GreasePencilStrokeEditPanel:
|
|||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(text="Select:")
|
||||
col = layout.column(align=True)
|
||||
col.operator("gpencil.select_all", text="Select All")
|
||||
col.operator("gpencil.select_border")
|
||||
col.operator("gpencil.select_circle")
|
||||
is_3d_view = context.space_data.type == 'VIEW_3D'
|
||||
|
||||
layout.separator()
|
||||
if not is_3d_view:
|
||||
layout.label(text="Select:")
|
||||
col = layout.column(align=True)
|
||||
col.operator("gpencil.select_all", text="Select All")
|
||||
col.operator("gpencil.select_border")
|
||||
col.operator("gpencil.select_circle")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.operator("gpencil.select_linked")
|
||||
col.operator("gpencil.select_more")
|
||||
col.operator("gpencil.select_less")
|
||||
layout.separator()
|
||||
|
||||
layout.separator()
|
||||
col = layout.column(align=True)
|
||||
col.operator("gpencil.select_linked")
|
||||
col.operator("gpencil.select_more")
|
||||
col.operator("gpencil.select_less")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.label(text="Edit:")
|
||||
row = layout.row(align=True)
|
||||
|
@ -160,12 +166,13 @@ class GreasePencilStrokeEditPanel:
|
|||
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.operator("transform.translate") # icon='MAN_TRANS'
|
||||
col.operator("transform.rotate") # icon='MAN_ROT'
|
||||
col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
|
||||
if not is_3d_view:
|
||||
col = layout.column(align=True)
|
||||
col.operator("transform.translate") # icon='MAN_TRANS'
|
||||
col.operator("transform.rotate") # icon='MAN_ROT'
|
||||
col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
|
||||
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.operator("transform.bend", text="Bend")
|
||||
|
|
|
@ -248,6 +248,8 @@ class DOPESHEET_MT_select(Menu):
|
|||
layout.operator("action.select_border").axis_range = False
|
||||
layout.operator("action.select_border", text="Border Axis Range").axis_range = True
|
||||
|
||||
layout.operator("action.select_circle")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS'
|
||||
layout.operator("action.select_column", text="Column on Current Frame").mode = 'CFRA'
|
||||
|
|
|
@ -154,6 +154,8 @@ class GRAPH_MT_select(Menu):
|
|||
props.axis_range = False
|
||||
props.include_handles = True
|
||||
|
||||
layout.operator("graph.select_circle")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS'
|
||||
layout.operator("graph.select_column", text="Column on Current Frame").mode = 'CFRA'
|
||||
|
|
|
@ -2526,7 +2526,7 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("gpencil.active_frame_delete")
|
||||
layout.operator("gpencil.active_frames_delete_all")
|
||||
|
||||
|
||||
# Edit Curve
|
||||
|
|
|
@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void);
|
|||
void BKE_blender_callback_test_break_set(void (*func)(void));
|
||||
int BKE_blender_test_break(void);
|
||||
|
||||
/* Blenders' own atexit (avoids leaking) */
|
||||
void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data);
|
||||
void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data);
|
||||
void BKE_blender_atexit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active);
|
|||
extern bool BKE_undo_save_file(const char *filename);
|
||||
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
|
||||
|
||||
extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -45,10 +45,14 @@
|
|||
#define DL_VERTS 7
|
||||
|
||||
/* dl->flag */
|
||||
#define DL_CYCL_U 1
|
||||
#define DL_CYCL_V 2
|
||||
#define DL_FRONT_CURVE 4
|
||||
#define DL_BACK_CURVE 8
|
||||
enum {
|
||||
/** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */
|
||||
DL_CYCL_U = (1 << 0),
|
||||
DL_CYCL_V = (1 << 1),
|
||||
|
||||
DL_FRONT_CURVE = (1 << 2),
|
||||
DL_BACK_CURVE = (1 << 3),
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
|
@ -70,7 +74,7 @@ typedef struct DispList {
|
|||
int charidx;
|
||||
int totindex; /* indexed array drawing surfaces */
|
||||
|
||||
unsigned int *bevelSplitFlag;
|
||||
unsigned int *bevel_split; /* BLI_bitmap */
|
||||
} DispList;
|
||||
|
||||
void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb);
|
||||
|
|
|
@ -40,7 +40,6 @@ struct MovieClipUser;
|
|||
struct MovieDistortion;
|
||||
|
||||
void BKE_movieclip_free(struct MovieClip *clip);
|
||||
void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
|
||||
|
||||
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
|
||||
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
|
||||
|
|
|
@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha
|
|||
const bool is_internal);
|
||||
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
|
||||
struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta);
|
||||
void BKE_text_unlink (struct Main *bmain, struct Text *text);
|
||||
void BKE_text_clear (struct Text *text);
|
||||
void BKE_text_write (struct Text *text, const char *str);
|
||||
int BKE_text_file_modified_check(struct Text *text);
|
||||
|
|
|
@ -49,9 +49,6 @@ set(INC
|
|||
../../../intern/smoke/extern
|
||||
../../../intern/atomic
|
||||
../../../intern/libmv
|
||||
|
||||
# XXX - BAD LEVEL CALL WM_api.h
|
||||
../windowmanager
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
|
|
@ -226,3 +226,56 @@ int BKE_blender_test_break(void)
|
|||
return (G.is_break == true);
|
||||
}
|
||||
|
||||
|
||||
/** \name Blender's AtExit
|
||||
*
|
||||
* \note Don't use MEM_mallocN so functions can be registered at any time.
|
||||
* \{ */
|
||||
|
||||
struct AtExitData {
|
||||
struct AtExitData *next;
|
||||
|
||||
void (*func)(void *user_data);
|
||||
void *user_data;
|
||||
} *g_atexit = NULL;
|
||||
|
||||
void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data)
|
||||
{
|
||||
struct AtExitData *ae = malloc(sizeof(*ae));
|
||||
ae->next = g_atexit;
|
||||
ae->func = func;
|
||||
ae->user_data = user_data;
|
||||
g_atexit = ae;
|
||||
}
|
||||
|
||||
void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data)
|
||||
{
|
||||
struct AtExitData *ae = g_atexit;
|
||||
struct AtExitData **ae_p = &g_atexit;
|
||||
|
||||
while (ae) {
|
||||
if ((ae->func == func) && (ae->user_data == user_data)) {
|
||||
*ae_p = ae->next;
|
||||
free(ae);
|
||||
return;
|
||||
}
|
||||
ae_p = &ae;
|
||||
ae = ae->next;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_blender_atexit(void)
|
||||
{
|
||||
struct AtExitData *ae = g_atexit, *ae_next;
|
||||
while (ae) {
|
||||
ae_next = ae->next;
|
||||
|
||||
ae->func(ae->user_data);
|
||||
|
||||
free(ae);
|
||||
ae = ae_next;
|
||||
}
|
||||
g_atexit = NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -66,9 +66,6 @@
|
|||
#include "BLO_readfile.h"
|
||||
#include "BLO_writefile.h"
|
||||
|
||||
#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Global Undo
|
||||
|
@ -87,6 +84,15 @@ typedef struct UndoElem {
|
|||
static ListBase undobase = {NULL, NULL};
|
||||
static UndoElem *curundo = NULL;
|
||||
|
||||
/**
|
||||
* Avoid bad-level call to #WM_jobs_kill_all_except()
|
||||
*/
|
||||
static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL;
|
||||
|
||||
void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C))
|
||||
{
|
||||
undo_wm_job_kill_callback = callback;
|
||||
}
|
||||
|
||||
static int read_undosave(bContext *C, UndoElem *uel)
|
||||
{
|
||||
|
@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
|
|||
int success = 0, fileflags;
|
||||
|
||||
/* This is needed so undoing/redoing doesn't crash with threaded previews going */
|
||||
WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
|
||||
undo_wm_job_kill_callback(C);
|
||||
|
||||
BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
|
||||
|
||||
|
|
|
@ -216,21 +216,6 @@ void BKE_brush_free(Brush *brush)
|
|||
BKE_previewimg_free(&(brush->preview));
|
||||
}
|
||||
|
||||
/**
|
||||
* \note Currently users don't remove brushes from the UI (as is done for scene, text... etc)
|
||||
* This is only used by RNA, which can remove brushes.
|
||||
*/
|
||||
void BKE_brush_unlink(Main *bmain, Brush *brush)
|
||||
{
|
||||
Brush *brush_iter;
|
||||
|
||||
for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) {
|
||||
if (brush_iter->toggle_brush == brush) {
|
||||
brush_iter->toggle_brush = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void extern_local_brush(Brush *brush)
|
||||
{
|
||||
id_lib_extern((ID *)brush->mtex.tex);
|
||||
|
|
|
@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts(
|
|||
/**
|
||||
* Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!).
|
||||
* \param vert_allocated if true, vert freeing will be done when freeing data.
|
||||
* \param mask if not null, true elements give which vert to add to BVH tree.
|
||||
* \param verts_mask if not null, true elements give which vert to add to BVH tree.
|
||||
* \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
|
||||
*/
|
||||
BVHTree *bvhtree_from_mesh_verts_ex(
|
||||
|
@ -804,7 +804,7 @@ BVHTree *bvhtree_from_mesh_faces(
|
|||
* Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!).
|
||||
* \param vert_allocated if true, vert freeing will be done when freeing data.
|
||||
* \param face_allocated if true, face freeing will be done when freeing data.
|
||||
* \param mask if not null, true elements give which faces to add to BVH tree.
|
||||
* \param faces_mask: if not null, true elements give which faces to add to BVH tree.
|
||||
* \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
|
||||
*/
|
||||
BVHTree *bvhtree_from_mesh_faces_ex(
|
||||
|
|
|
@ -61,8 +61,6 @@
|
|||
#include "GPU_shader.h"
|
||||
#include "GPU_basic_shader.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
@ -699,10 +697,10 @@ static void cdDM_drawMappedFaces(
|
|||
}
|
||||
|
||||
if ((orig != ORIGINDEX_NONE) && !is_hidden)
|
||||
WM_framebuffer_index_get(orig + 1, &selcol);
|
||||
GPU_select_index_get(orig + 1, &selcol);
|
||||
}
|
||||
else if (orig != ORIGINDEX_NONE)
|
||||
WM_framebuffer_index_get(orig + 1, &selcol);
|
||||
GPU_select_index_get(orig + 1, &selcol);
|
||||
|
||||
for (j = 0; j < mpoly->totloop; j++)
|
||||
fi_map[start_element++] = selcol;
|
||||
|
|
|
@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl)
|
|||
if (dl->verts) MEM_freeN(dl->verts);
|
||||
if (dl->nors) MEM_freeN(dl->nors);
|
||||
if (dl->index) MEM_freeN(dl->index);
|
||||
if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag);
|
||||
if (dl->bevel_split) MEM_freeN(dl->bevel_split);
|
||||
MEM_freeN(dl);
|
||||
}
|
||||
}
|
||||
|
@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb)
|
|||
dln->nors = MEM_dupallocN(dl->nors);
|
||||
dln->index = MEM_dupallocN(dl->index);
|
||||
|
||||
if (dl->bevelSplitFlag)
|
||||
dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag);
|
||||
if (dl->bevel_split) {
|
||||
dln->bevel_split = MEM_dupallocN(dl->bevel_split);
|
||||
}
|
||||
|
||||
dl = dl->next;
|
||||
}
|
||||
|
@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
|
|||
if (dlb->type == DL_POLY) {
|
||||
dl->flag |= DL_CYCL_U;
|
||||
}
|
||||
if ((bl->poly >= 0) && (steps != 2)) {
|
||||
if ((bl->poly >= 0) && (steps > 2)) {
|
||||
dl->flag |= DL_CYCL_V;
|
||||
}
|
||||
|
||||
|
@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
|
|||
/* CU_2D conflicts with R_NOPUNOFLIP */
|
||||
dl->rt = nu->flag & ~CU_2D;
|
||||
|
||||
dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5),
|
||||
"bevelSplitFlag");
|
||||
dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split");
|
||||
|
||||
/* for each point of poly make a bevel piece */
|
||||
bevp_first = bl->bevpoints;
|
||||
|
@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
|
|||
}
|
||||
|
||||
if (bevp->split_tag) {
|
||||
dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F);
|
||||
BLI_BITMAP_ENABLE(dl->bevel_split, a);
|
||||
}
|
||||
|
||||
/* rotate bevel piece and write in data */
|
||||
|
|
|
@ -123,7 +123,7 @@ static IDType *idtype_from_code(short idcode)
|
|||
/**
|
||||
* Return if the ID code is a valid ID code.
|
||||
*
|
||||
* \param code The code to check.
|
||||
* \param idcode: The code to check.
|
||||
* \return Boolean, 0 when invalid.
|
||||
*/
|
||||
bool BKE_idcode_is_valid(short idcode)
|
||||
|
@ -134,7 +134,7 @@ bool BKE_idcode_is_valid(short idcode)
|
|||
/**
|
||||
* Return non-zero when an ID type is linkable.
|
||||
*
|
||||
* \param code The code to check.
|
||||
* \param idcode: The code to check.
|
||||
* \return Boolean, 0 when non linkable.
|
||||
*/
|
||||
bool BKE_idcode_is_linkable(short idcode)
|
||||
|
@ -147,7 +147,7 @@ bool BKE_idcode_is_linkable(short idcode)
|
|||
/**
|
||||
* Convert an idcode into a name.
|
||||
*
|
||||
* \param code The code to convert.
|
||||
* \param idcode: The code to convert.
|
||||
* \return A static string representing the name of
|
||||
* the code.
|
||||
*/
|
||||
|
@ -258,7 +258,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
|
|||
/**
|
||||
* Convert an idcode into a name (plural).
|
||||
*
|
||||
* \param code The code to convert.
|
||||
* \param idcode: The code to convert.
|
||||
* \return A static string representing the name of
|
||||
* the code.
|
||||
*/
|
||||
|
@ -272,7 +272,7 @@ const char *BKE_idcode_to_name_plural(short idcode)
|
|||
/**
|
||||
* Convert an idcode into its translations' context.
|
||||
*
|
||||
* \param code The code to convert.
|
||||
* \param idcode: The code to convert.
|
||||
* \return A static string representing the i18n context of the code.
|
||||
*/
|
||||
const char *BKE_idcode_to_translation_context(short idcode)
|
||||
|
|
|
@ -95,8 +95,6 @@
|
|||
#include "DNA_screen_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
static SpinLock image_spin;
|
||||
|
||||
/* prototypes */
|
||||
|
|
|
@ -162,15 +162,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
|
|||
}
|
||||
|
||||
if (*id_p && (*id_p == old_id)) {
|
||||
const bool is_indirect = (id->lib != NULL);
|
||||
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
|
||||
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
|
||||
* on the other hand since they get reset to lib data on file open/reload it is indirect too...
|
||||
* Edit Mode is also a 'skip direct' case. */
|
||||
const bool is_obj = (GS(id->name) == ID_OB);
|
||||
const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
|
||||
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
|
||||
/* Note that indirect data from same file as processed ID is **not** considered indirect! */
|
||||
const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib));
|
||||
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
|
||||
const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
|
||||
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
|
||||
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
|
||||
|
@ -184,7 +183,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self),
|
|||
(is_obj_editmode && (((Object *)id)->data == *id_p)) ||
|
||||
(skip_indirect && (is_proxy || is_indirect)))
|
||||
{
|
||||
if (is_never_null || is_proxy || is_obj_editmode) {
|
||||
if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) {
|
||||
id_remap_data->skipped_direct++;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -427,12 +427,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
|
|||
}
|
||||
}
|
||||
|
||||
/* Note: unlinking is called when me->id.us is 0, question remains how
|
||||
* much unlinking of Library data in Mesh should be done... probably
|
||||
* we need a more generic method, like the expand() functions in
|
||||
* readfile.c */
|
||||
|
||||
|
||||
/** Free (or release) any data used by this mesh (does not free the mesh itself). */
|
||||
void BKE_mesh_free(Mesh *me)
|
||||
{
|
||||
|
|
|
@ -1491,73 +1491,6 @@ void BKE_movieclip_free(MovieClip *clip)
|
|||
BKE_tracking_free(&clip->tracking);
|
||||
}
|
||||
|
||||
void BKE_movieclip_unlink(Main *bmain, MovieClip *clip)
|
||||
{
|
||||
bScreen *scr;
|
||||
ScrArea *area;
|
||||
SpaceLink *sl;
|
||||
Scene *sce;
|
||||
Object *ob;
|
||||
|
||||
for (scr = bmain->screen.first; scr; scr = scr->id.next) {
|
||||
for (area = scr->areabase.first; area; area = area->next) {
|
||||
for (sl = area->spacedata.first; sl; sl = sl->next) {
|
||||
if (sl->spacetype == SPACE_CLIP) {
|
||||
SpaceClip *sc = (SpaceClip *) sl;
|
||||
|
||||
if (sc->clip == clip)
|
||||
sc->clip = NULL;
|
||||
}
|
||||
else if (sl->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *) sl;
|
||||
BGpic *bgpic;
|
||||
|
||||
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
|
||||
if (bgpic->clip == clip)
|
||||
bgpic->clip = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
|
||||
if (sce->clip == clip)
|
||||
sce->clip = NULL;
|
||||
}
|
||||
|
||||
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
bConstraint *con;
|
||||
|
||||
for (con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
|
||||
bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data;
|
||||
|
||||
if (data->clip == clip)
|
||||
data->clip = NULL;
|
||||
}
|
||||
else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
|
||||
bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data;
|
||||
|
||||
if (data->clip == clip)
|
||||
data->clip = NULL;
|
||||
}
|
||||
else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
|
||||
bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data;
|
||||
|
||||
if (data->clip == clip)
|
||||
data->clip = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_NODETREE(bmain, ntree, id) {
|
||||
BKE_node_tree_unlink_id((ID *)clip, ntree);
|
||||
} FOREACH_NODETREE_END
|
||||
|
||||
clip->id.us = 0;
|
||||
}
|
||||
|
||||
float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr)
|
||||
{
|
||||
return framenr - (float) clip->start_frame + 1.0f;
|
||||
|
|
|
@ -498,191 +498,6 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
|
|||
return tan;
|
||||
}
|
||||
|
||||
void BKE_text_unlink(Main *bmain, Text *text)
|
||||
{
|
||||
bScreen *scr;
|
||||
ScrArea *area;
|
||||
SpaceLink *sl;
|
||||
Object *ob;
|
||||
bController *cont;
|
||||
bActuator *act;
|
||||
bConstraint *con;
|
||||
bNodeTree *ntree;
|
||||
bNode *node;
|
||||
Material *mat;
|
||||
Lamp *la;
|
||||
Tex *te;
|
||||
World *wo;
|
||||
FreestyleLineStyle *linestyle;
|
||||
Scene *sce;
|
||||
SceneRenderLayer *srl;
|
||||
FreestyleModuleConfig *module;
|
||||
bool update;
|
||||
|
||||
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
/* game controllers */
|
||||
for (cont = ob->controllers.first; cont; cont = cont->next) {
|
||||
if (cont->type == CONT_PYTHON) {
|
||||
bPythonCont *pc;
|
||||
|
||||
pc = cont->data;
|
||||
if (pc->text == text) pc->text = NULL;
|
||||
}
|
||||
}
|
||||
/* game actuators */
|
||||
for (act = ob->actuators.first; act; act = act->next) {
|
||||
if (act->type == ACT_2DFILTER) {
|
||||
bTwoDFilterActuator *tfa;
|
||||
|
||||
tfa = act->data;
|
||||
if (tfa->text == text) tfa->text = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* pyconstraints */
|
||||
update = 0;
|
||||
|
||||
if (ob->type == OB_ARMATURE && ob->pose) {
|
||||
bPoseChannel *pchan;
|
||||
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
if (con->type == CONSTRAINT_TYPE_PYTHON) {
|
||||
bPythonConstraint *data = con->data;
|
||||
if (data->text == text) data->text = NULL;
|
||||
update = 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type == CONSTRAINT_TYPE_PYTHON) {
|
||||
bPythonConstraint *data = con->data;
|
||||
if (data->text == text) data->text = NULL;
|
||||
update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (update)
|
||||
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
||||
}
|
||||
|
||||
/* nodes */
|
||||
for (la = bmain->lamp.first; la; la = la->id.next) {
|
||||
ntree = la->nodetree;
|
||||
if (!ntree)
|
||||
continue;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == NODE_FRAME) {
|
||||
if ((Text *)node->id == text) {
|
||||
node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
|
||||
ntree = linestyle->nodetree;
|
||||
if (!ntree)
|
||||
continue;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == NODE_FRAME) {
|
||||
if ((Text *)node->id == text) {
|
||||
node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (mat = bmain->mat.first; mat; mat = mat->id.next) {
|
||||
ntree = mat->nodetree;
|
||||
if (!ntree)
|
||||
continue;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
|
||||
if ((Text *)node->id == text) {
|
||||
node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (te = bmain->tex.first; te; te = te->id.next) {
|
||||
ntree = te->nodetree;
|
||||
if (!ntree)
|
||||
continue;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == NODE_FRAME) {
|
||||
if ((Text *)node->id == text) {
|
||||
node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (wo = bmain->world.first; wo; wo = wo->id.next) {
|
||||
ntree = wo->nodetree;
|
||||
if (!ntree)
|
||||
continue;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == NODE_FRAME) {
|
||||
if ((Text *)node->id == text) {
|
||||
node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
|
||||
ntree = sce->nodetree;
|
||||
if (!ntree)
|
||||
continue;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == NODE_FRAME) {
|
||||
Text *ntext = (Text *)node->id;
|
||||
if (ntext == text) node->id = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Freestyle (while looping over the scene) */
|
||||
for (srl = sce->r.layers.first; srl; srl = srl->next) {
|
||||
for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
|
||||
if (module->script == text)
|
||||
module->script = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
|
||||
if ((Text *)node->id == text) {
|
||||
node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* text space */
|
||||
for (scr = bmain->screen.first; scr; scr = scr->id.next) {
|
||||
for (area = scr->areabase.first; area; area = area->next) {
|
||||
for (sl = area->spacedata.first; sl; sl = sl->next) {
|
||||
if (sl->spacetype == SPACE_TEXT) {
|
||||
SpaceText *st = (SpaceText *) sl;
|
||||
|
||||
if (st->text == text) {
|
||||
st->text = NULL;
|
||||
st->top = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text->id.us = 0;
|
||||
}
|
||||
|
||||
void BKE_text_clear(Text *text) /* called directly from rna */
|
||||
{
|
||||
int oldstate;
|
||||
|
|
|
@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
|
|||
#define BLI_array_findindex(arr, arr_len, p) \
|
||||
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
|
||||
|
||||
int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
|
||||
#define BLI_array_rfindindex(arr, arr_len, p) \
|
||||
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
|
||||
|
||||
void _bli_array_binary_and(
|
||||
void *arr, const void *arr_a, const void *arr_b,
|
||||
unsigned int arr_len, size_t arr_stride);
|
||||
|
|
|
@ -273,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
|
|||
/*********************************** Other ***********************************/
|
||||
|
||||
void print_m3(const char *str, float M[3][3]);
|
||||
void print_m4(const char *str, float M[3][4]);
|
||||
void print_m4(const char *str, float M[4][4]);
|
||||
|
||||
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
|
||||
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
|
||||
|
|
|
@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string(
|
|||
|
||||
/**
|
||||
* Deep-duplicate of a single direntry.
|
||||
*
|
||||
* \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
|
||||
*/
|
||||
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
|
||||
{
|
||||
|
@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
|
|||
|
||||
/**
|
||||
* Deep-duplicate of an array of direntries, including the array itself.
|
||||
*
|
||||
* \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
|
||||
*/
|
||||
void BLI_filelist_duplicate(
|
||||
struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries)
|
||||
|
|
|
@ -134,8 +134,22 @@ void _bli_array_permute(
|
|||
int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
|
||||
{
|
||||
const char *arr_step = (const char *)arr;
|
||||
unsigned int i;
|
||||
for (i = 0; i < arr_len; i++, arr_step += arr_stride) {
|
||||
for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) {
|
||||
if (memcmp(arr_step, p, arr_stride) == 0) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BLI_array_findindex that searches from the end of the list.
|
||||
*/
|
||||
int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
|
||||
{
|
||||
const char *arr_step = (const char *)arr + (arr_stride * arr_len);
|
||||
for (unsigned int i = arr_len; i-- != 0; ) {
|
||||
arr_step -= arr_stride;
|
||||
if (memcmp(arr_step, p, arr_stride) == 0) {
|
||||
return (int)i;
|
||||
}
|
||||
|
|
|
@ -2692,7 +2692,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v
|
|||
}
|
||||
|
||||
/**
|
||||
* \param r_vi The point \a p projected onto the triangle.
|
||||
* \param r_isect_co: The point \a p projected onto the triangle.
|
||||
* \return True when \a p is inside the triangle.
|
||||
* \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin.
|
||||
*/
|
||||
|
|
|
@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f
|
|||
/**
|
||||
* Remove redundant characters from \a path and optionally make absolute.
|
||||
*
|
||||
* \param relbase: The path this is relative to, or ignored when NULL.
|
||||
* \param relabase: The path this is relative to, or ignored when NULL.
|
||||
* \param path: Can be any input, and this function converts it to a regular full path.
|
||||
* Also removes garbage from directory paths, like `/../` or double slashes etc.
|
||||
*
|
||||
|
|
|
@ -1324,6 +1324,7 @@ bool BLO_has_bfile_extension(const char *str)
|
|||
*
|
||||
* \param path the full path to explode.
|
||||
* \param r_dir the string that'll contain path up to blend file itself ('library' path).
|
||||
* WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)!
|
||||
* \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
|
||||
* \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
|
||||
* \return true if path contains a blend file.
|
||||
|
|
|
@ -29,15 +29,22 @@
|
|||
*/
|
||||
|
||||
|
||||
/*
|
||||
* FILEFORMAT: IFF-style structure (but not IFF compatible!)
|
||||
/**
|
||||
*
|
||||
* FILE FORMAT
|
||||
* ===========
|
||||
*
|
||||
* IFF-style structure (but not IFF compatible!)
|
||||
*
|
||||
* start file:
|
||||
* <pre>
|
||||
* BLENDER_V100 12 bytes (versie 1.00)
|
||||
* V = big endian, v = little endian
|
||||
* _ = 4 byte pointer, - = 8 byte pointer
|
||||
* </pre>
|
||||
*
|
||||
* datablocks: also see struct BHead
|
||||
* datablocks: (also see struct #BHead).
|
||||
* <pre>
|
||||
* <bh.code> 4 chars
|
||||
* <bh.len> int, len data after BHead
|
||||
* <bh.old> void, old pointer
|
||||
|
@ -46,29 +53,32 @@
|
|||
* data
|
||||
* ...
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* Almost all data in Blender are structures. Each struct saved
|
||||
* gets a BHead header. With BHead the struct can be linked again
|
||||
* and compared with StructDNA .
|
||||
*
|
||||
*
|
||||
* WRITE
|
||||
* =====
|
||||
*
|
||||
* Preferred writing order: (not really a must, but why would you do it random?)
|
||||
* Any case: direct data is ALWAYS after the lib block
|
||||
*
|
||||
* (Local file data)
|
||||
* - for each LibBlock
|
||||
* - write LibBlock
|
||||
* - write associated direct data
|
||||
* - write LibBlock
|
||||
* - write associated direct data
|
||||
* (External file data)
|
||||
* - per library
|
||||
* - write library block
|
||||
* - per LibBlock
|
||||
* - write the ID of LibBlock
|
||||
* - write TEST (128x128, blend file preview, optional)
|
||||
* - write FileGlobal (some global vars)
|
||||
* - write SDNA
|
||||
* - write USER if filename is ~/X.XX/config/startup.blend
|
||||
* - write library block
|
||||
* - per LibBlock
|
||||
* - write the ID of LibBlock
|
||||
* - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional).
|
||||
* - write #GLOB (#FileGlobal struct) (some global vars).
|
||||
* - write #DNA1 (#SDNA struct)
|
||||
* - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -309,12 +319,6 @@ static WriteData *writedata_new(WriteWrap *ww)
|
|||
{
|
||||
WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
|
||||
|
||||
/* XXX, see note about this in readfile.c, remove
|
||||
* once we have an xp lock - zr
|
||||
*/
|
||||
|
||||
if (wd == NULL) return NULL;
|
||||
|
||||
wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
|
||||
|
||||
wd->ww = ww;
|
||||
|
|
|
@ -97,12 +97,22 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3])
|
||||
{
|
||||
float dir[3];
|
||||
sub_v3_v3v3(dir, v1, v2);
|
||||
mul_v2_m3v3(out, axis_mat, dir);
|
||||
normalize_v2(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists
|
||||
* when making changed to edge picking logic.
|
||||
*/
|
||||
static bool bm_face_split_edgenet_find_loop_pair(
|
||||
BMVert *v_init, const float face_normal[3],
|
||||
BMVert *v_init,
|
||||
const float face_normal[3], float face_normal_matrix[3][3],
|
||||
BMEdge *e_pair[2])
|
||||
{
|
||||
/* Always find one boundary edge (to determine winding)
|
||||
|
@ -142,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair(
|
|||
}
|
||||
e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
|
||||
|
||||
/* use to hold boundary OR wire edges */
|
||||
BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
|
||||
|
||||
/* attempt one boundary and one wire, or 2 boundary */
|
||||
if (edges_wire_len == 0) {
|
||||
if (edges_boundary_len >= 2) {
|
||||
if (edges_boundary_len > 1) {
|
||||
e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
|
||||
|
||||
if (edges_boundary_len > 2) {
|
||||
BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* one boundary and no wire */
|
||||
|
@ -154,28 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair(
|
|||
}
|
||||
else {
|
||||
e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
|
||||
|
||||
if (edges_wire_len > 1) {
|
||||
BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
|
||||
BMVert *v_next;
|
||||
float angle_best;
|
||||
|
||||
v_next = BM_edge_other_vert(e_pair[1], v_init);
|
||||
angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
|
||||
|
||||
BMEdge *e;
|
||||
while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
|
||||
float angle_test;
|
||||
v_next = BM_edge_other_vert(e, v_init);
|
||||
angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
|
||||
if (angle_test < angle_best) {
|
||||
angle_best = angle_test;
|
||||
e_pair[1] = e;
|
||||
}
|
||||
}
|
||||
BLI_SMALLSTACK_SWAP(edges_search, edges_wire);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we swapped above, search this list for the best edge */
|
||||
if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) {
|
||||
/* find the best edge in 'edge_list' to use for 'e_pair[1]' */
|
||||
const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
|
||||
const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init);
|
||||
|
||||
float dir_prev[2], dir_next[2];
|
||||
|
||||
normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co);
|
||||
normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co);
|
||||
float angle_best_cos = dot_v2v2(dir_next, dir_prev);
|
||||
|
||||
BMEdge *e;
|
||||
while ((e = BLI_SMALLSTACK_POP(edges_search))) {
|
||||
v_next = BM_edge_other_vert(e, v_init);
|
||||
float dir_test[2];
|
||||
|
||||
normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co);
|
||||
const float angle_test_cos = dot_v2v2(dir_prev, dir_test);
|
||||
|
||||
if (angle_test_cos > angle_best_cos) {
|
||||
angle_best_cos = angle_test_cos;
|
||||
e_pair[1] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* flip based on winding */
|
||||
l_walk = bm_edge_flagged_radial_first(e_pair[0]);
|
||||
|
@ -309,36 +335,40 @@ walk_nofork:
|
|||
BMEdge *e_next, *e_first;
|
||||
e_first = v->e;
|
||||
e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */
|
||||
do {
|
||||
BLI_assert(v->e != e_next);
|
||||
if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
|
||||
(bm_edge_flagged_radial_count(e_next) < 2))
|
||||
{
|
||||
BMVert *v_next;
|
||||
|
||||
v_next = BM_edge_other_vert(e_next, v);
|
||||
/* in rare cases there may be edges with a single connecting vertex */
|
||||
if (e_next != e_first) {
|
||||
do {
|
||||
if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
|
||||
(bm_edge_flagged_radial_count(e_next) < 2))
|
||||
{
|
||||
BMVert *v_next;
|
||||
|
||||
v_next = BM_edge_other_vert(e_next, v);
|
||||
BLI_assert(v->e != e_next);
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
/* indent and print */
|
||||
{
|
||||
BMVert *_v = v;
|
||||
do {
|
||||
printf(" ");
|
||||
} while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
|
||||
printf("vert %d -> %d (add=%d)\n",
|
||||
BM_elem_index_get(v), BM_elem_index_get(v_next),
|
||||
BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
|
||||
}
|
||||
/* indent and print */
|
||||
{
|
||||
BMVert *_v = v;
|
||||
do {
|
||||
printf(" ");
|
||||
} while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
|
||||
printf("vert %d -> %d (add=%d)\n",
|
||||
BM_elem_index_get(v), BM_elem_index_get(v_next),
|
||||
BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
|
||||
eo = STACK_PUSH_RET_PTR(edge_order);
|
||||
eo->v = v_next;
|
||||
if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
|
||||
eo = STACK_PUSH_RET_PTR(edge_order);
|
||||
eo->v = v_next;
|
||||
|
||||
v_next->e = e_next;
|
||||
v_next->e = e_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first);
|
||||
} while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first);
|
||||
}
|
||||
|
||||
#ifdef USE_FASTPATH_NOFORK
|
||||
if (STACK_SIZE(edge_order) == 1) {
|
||||
|
@ -388,7 +418,7 @@ finally:
|
|||
}
|
||||
|
||||
static bool bm_face_split_edgenet_find_loop(
|
||||
BMVert *v_init, const float face_normal[3],
|
||||
BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3],
|
||||
/* cache to avoid realloc every time */
|
||||
struct VertOrder *edge_order, const unsigned int edge_order_len,
|
||||
BMVert **r_face_verts, int *r_face_verts_len)
|
||||
|
@ -396,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop(
|
|||
BMEdge *e_pair[2];
|
||||
BMVert *v;
|
||||
|
||||
if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
|
||||
if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -491,12 +521,18 @@ bool BM_face_split_edgenet(
|
|||
BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
float face_normal_matrix[3][3];
|
||||
axis_dominant_v3_to_m3(face_normal_matrix, f->no);
|
||||
|
||||
|
||||
/* any vert can be used to begin with */
|
||||
STACK_PUSH(vert_queue, l_first->v);
|
||||
|
||||
while ((v = STACK_POP(vert_queue))) {
|
||||
if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
|
||||
if (bm_face_split_edgenet_find_loop(
|
||||
v, f->no, face_normal_matrix,
|
||||
edge_order, edge_order_len, face_verts, &face_verts_len))
|
||||
{
|
||||
BMFace *f_new;
|
||||
|
||||
f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
|
||||
|
|
|
@ -1292,7 +1292,8 @@ static bool bm_decim_edge_collapse(
|
|||
* \param factor face count multiplier [0 - 1]
|
||||
* \param vweights Optional array of vertex aligned weights [0 - 1],
|
||||
* a vertex group is the usual source for this.
|
||||
* \param axis: Axis of symmetry, -1 to disable mirror decimate.
|
||||
* \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
|
||||
* \param symmetry_eps: Threshold when matching mirror verts.
|
||||
*/
|
||||
void BM_mesh_decimate_collapse(
|
||||
BMesh *bm,
|
||||
|
|
|
@ -87,6 +87,18 @@
|
|||
|
||||
// #define USE_DUMP
|
||||
|
||||
/* use only for small arrays */
|
||||
BLI_INLINE bool array_contains_pointer(const void **arr, unsigned int arr_len, const void *item)
|
||||
{
|
||||
BLI_assert(arr_len < 3);
|
||||
for (unsigned int i = 0; i < arr_len; i++) {
|
||||
if (arr[i] == item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tri_v3_scale(
|
||||
float v1[3], float v2[3], float v3[3],
|
||||
const float t)
|
||||
|
@ -535,6 +547,7 @@ static void bm_isect_tri_tri(
|
|||
const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
|
||||
float f_a_nor[3];
|
||||
float f_b_nor[3];
|
||||
/* track vertices which have been added to 'iv_ls_a' & 'iv_ls_b' */
|
||||
int a_mask = 0;
|
||||
int b_mask = 0;
|
||||
unsigned int i;
|
||||
|
@ -556,6 +569,24 @@ static void bm_isect_tri_tri(
|
|||
STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
|
||||
STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
|
||||
|
||||
/* don't test, but we must be sure not to add doubles (assert instead). */
|
||||
#ifndef NDEBUG
|
||||
# define STACK_PUSH_NOTEST(arr, ele) \
|
||||
{ \
|
||||
BLI_assert(BLI_array_findindex(arr, STACK_SIZE(arr), &(ele)) == -1); \
|
||||
STACK_PUSH(arr, ele); \
|
||||
} ((void)0)
|
||||
#else
|
||||
# define STACK_PUSH_NOTEST STACK_PUSH
|
||||
#endif
|
||||
|
||||
/* warning, this seems like it might be inefficent,
|
||||
* however there will be <3 items in this case. */
|
||||
# define STACK_PUSH_TEST(arr, ele, arr_offset) \
|
||||
if (!array_contains_pointer((const void **)(&(arr)[arr_offset]), STACK_SIZE(arr) - (arr_offset), (void *)ele)) { \
|
||||
STACK_PUSH(arr, ele); \
|
||||
} ((void)0)
|
||||
|
||||
/* vert-vert
|
||||
* --------- */
|
||||
{
|
||||
|
@ -568,7 +599,7 @@ static void bm_isect_tri_tri(
|
|||
for (i_b = 0; i_b < 3; i_b++) {
|
||||
if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
|
||||
if (!((1 << i_a) & a_mask)) {
|
||||
STACK_PUSH(iv_ls_a, fv_a[i_a]);
|
||||
STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]);
|
||||
a_mask |= (1 << i_a);
|
||||
#ifdef USE_DUMP
|
||||
printf(" ('VERT-VERT-A') %d, %d),\n",
|
||||
|
@ -576,7 +607,7 @@ static void bm_isect_tri_tri(
|
|||
#endif
|
||||
}
|
||||
if (!((1 << i_b) & b_mask)) {
|
||||
STACK_PUSH(iv_ls_b, fv_b[i_b]);
|
||||
STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
|
||||
b_mask |= (1 << i_b);
|
||||
#ifdef USE_DUMP
|
||||
printf(" ('VERT-VERT-B') %d, %d),\n",
|
||||
|
@ -606,8 +637,8 @@ static void bm_isect_tri_tri(
|
|||
interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
|
||||
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
|
||||
BMEdge *e;
|
||||
STACK_PUSH(iv_ls_b, fv_a[i_a]);
|
||||
// STACK_PUSH(iv_ls_a, fv_a[i_a]);
|
||||
STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]);
|
||||
// STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]);
|
||||
a_mask |= (1 << i_a);
|
||||
e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
|
||||
#ifdef USE_DUMP
|
||||
|
@ -644,8 +675,8 @@ static void bm_isect_tri_tri(
|
|||
interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
|
||||
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
|
||||
BMEdge *e;
|
||||
STACK_PUSH(iv_ls_a, fv_b[i_b]);
|
||||
// STACK_PUSH(iv_ls_b, fv_b[i_b]);
|
||||
STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]);
|
||||
// STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
|
||||
b_mask |= (1 << i_b);
|
||||
e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
|
||||
#ifdef USE_DUMP
|
||||
|
@ -685,11 +716,8 @@ static void bm_isect_tri_tri(
|
|||
continue;
|
||||
if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
|
||||
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
|
||||
BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1);
|
||||
BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1);
|
||||
|
||||
STACK_PUSH(iv_ls_a, fv_a[i_a]);
|
||||
STACK_PUSH(iv_ls_b, fv_a[i_a]);
|
||||
STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]);
|
||||
STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]);
|
||||
a_mask |= (1 << i_a);
|
||||
#ifdef USE_DUMP
|
||||
printf(" 'VERT TRI-A',\n");
|
||||
|
@ -715,11 +743,8 @@ static void bm_isect_tri_tri(
|
|||
|
||||
if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
|
||||
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
|
||||
BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1);
|
||||
BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1);
|
||||
|
||||
STACK_PUSH(iv_ls_a, fv_b[i_b]);
|
||||
STACK_PUSH(iv_ls_b, fv_b[i_b]);
|
||||
STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]);
|
||||
STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
|
||||
b_mask |= (1 << i_b);
|
||||
#ifdef USE_DUMP
|
||||
printf(" 'VERT TRI-B',\n");
|
||||
|
@ -744,6 +769,17 @@ static void bm_isect_tri_tri(
|
|||
/* edge-tri & edge-edge
|
||||
* -------------------- */
|
||||
{
|
||||
/**
|
||||
* Note that its possible to add the same vertex multiple times
|
||||
* with near degenerate faces (or a large epsilon).
|
||||
*
|
||||
* For this reason we have #STACK_PUSH_TEST macro which only adds vertices that aren't already added.
|
||||
* Since we know none of the vertices from #bm_isect_edge_tri, the check can be offset.
|
||||
*/
|
||||
|
||||
const unsigned int iv_ls_a_offset = STACK_SIZE(iv_ls_a);
|
||||
const unsigned int iv_ls_b_offset = STACK_SIZE(iv_ls_b);
|
||||
|
||||
unsigned int i_e0;
|
||||
for (i_e0 = 0; i_e0 < 3; i_e0++) {
|
||||
unsigned int i_e1 = (i_e0 + 1) % 3;
|
||||
|
@ -753,10 +789,8 @@ static void bm_isect_tri_tri(
|
|||
continue;
|
||||
iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
|
||||
if (iv) {
|
||||
BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
|
||||
BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
|
||||
STACK_PUSH(iv_ls_a, iv);
|
||||
STACK_PUSH(iv_ls_b, iv);
|
||||
STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset);
|
||||
STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset);
|
||||
#ifdef USE_DUMP
|
||||
printf(" ('EDGE-TRI-A', %d),\n", side);
|
||||
#endif
|
||||
|
@ -771,10 +805,8 @@ static void bm_isect_tri_tri(
|
|||
continue;
|
||||
iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
|
||||
if (iv) {
|
||||
BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
|
||||
BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
|
||||
STACK_PUSH(iv_ls_a, iv);
|
||||
STACK_PUSH(iv_ls_b, iv);
|
||||
STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset);
|
||||
STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset);
|
||||
#ifdef USE_DUMP
|
||||
printf(" ('EDGE-TRI-B', %d),\n", side);
|
||||
#endif
|
||||
|
|
|
@ -158,7 +158,7 @@ static int add_driver_with_target(
|
|||
ReportList *UNUSED(reports),
|
||||
ID *dst_id, const char dst_path[], int dst_index,
|
||||
ID *src_id, const char src_path[], int src_index,
|
||||
PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
|
||||
PointerRNA *dst_ptr, PropertyRNA *dst_prop,
|
||||
PointerRNA *src_ptr, PropertyRNA *src_prop,
|
||||
short flag, int driver_type)
|
||||
{
|
||||
|
@ -207,11 +207,15 @@ static int add_driver_with_target(
|
|||
/* Create a driver variable for the target
|
||||
* - For transform properties, we want to automatically use "transform channel" instead
|
||||
* (The only issue is with quat rotations vs euler channels...)
|
||||
* - To avoid problems with transform properties depending on the final transform that they
|
||||
* control (thus creating pseudo-cycles - see T48734), we don't use transform channels
|
||||
* when both the source and destinaions are in same places.
|
||||
*/
|
||||
dvar = driver_add_new_variable(driver);
|
||||
|
||||
if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
|
||||
(STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
|
||||
(STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) &&
|
||||
(src_ptr->data != dst_ptr->data))
|
||||
{
|
||||
/* Transform Channel */
|
||||
DriverTarget *dtar;
|
||||
|
|
|
@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
|
|||
}
|
||||
|
||||
/**
|
||||
* only called from #ok_bezier_region_lasso
|
||||
* Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso
|
||||
*/
|
||||
static bool bezier_region_lasso_test(
|
||||
const struct KeyframeEdit_LassoData *data_lasso,
|
||||
bool keyframe_region_lasso_test(
|
||||
const KeyframeEdit_LassoData *data_lasso,
|
||||
const float xy[2])
|
||||
{
|
||||
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
|
||||
|
@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
|
|||
if (ked->data) {
|
||||
short ok = 0;
|
||||
|
||||
#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
|
||||
#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index])
|
||||
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
|
||||
#undef KEY_CHECK_OK
|
||||
|
||||
|
@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt)
|
||||
{
|
||||
/* check for lasso customdata (KeyframeEdit_LassoData) */
|
||||
if (ked->data) {
|
||||
KeyframeEdit_LassoData *data = ked->data;
|
||||
float pt[2];
|
||||
|
||||
/* late-binding remap of the x values (for summary channels) */
|
||||
/* XXX: Ideally we reset, but it should be fine just leaving it as-is
|
||||
* as the next channel will reset it properly, while the next summary-channel
|
||||
* curve will also reset by itself...
|
||||
*/
|
||||
if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
|
||||
data->rectf_scaled->xmin = ked->f1;
|
||||
data->rectf_scaled->xmax = ked->f2;
|
||||
}
|
||||
|
||||
/* only use the x-coordinate of the point; the y is the channel range... */
|
||||
pt[0] = bezt->vec[1][0];
|
||||
pt[1] = ked->channel_y;
|
||||
|
||||
if (keyframe_region_lasso_test(data, pt))
|
||||
return KEYFRAME_OK_KEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* only called from #ok_bezier_region_circle
|
||||
* Called from #ok_bezier_region_circle and #ok_bezier_channel_circle
|
||||
*/
|
||||
static bool bezier_region_circle_test(
|
||||
const struct KeyframeEdit_CircleData *data_circle,
|
||||
bool keyframe_region_circle_test(
|
||||
const KeyframeEdit_CircleData *data_circle,
|
||||
const float xy[2])
|
||||
{
|
||||
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
|
||||
|
@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
|
|||
if (ked->data) {
|
||||
short ok = 0;
|
||||
|
||||
#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
|
||||
#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index])
|
||||
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
|
||||
#undef KEY_CHECK_OK
|
||||
|
||||
|
@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
|
||||
{
|
||||
/* check for circle select customdata (KeyframeEdit_CircleData) */
|
||||
if (ked->data) {
|
||||
KeyframeEdit_CircleData *data = ked->data;
|
||||
float pt[2];
|
||||
|
||||
/* late-binding remap of the x values (for summary channels) */
|
||||
/* XXX: Ideally we reset, but it should be fine just leaving it as-is
|
||||
* as the next channel will reset it properly, while the next summary-channel
|
||||
* curve will also reset by itself...
|
||||
*/
|
||||
if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
|
||||
data->rectf_scaled->xmin = ked->f1;
|
||||
data->rectf_scaled->xmax = ked->f2;
|
||||
}
|
||||
|
||||
/* only use the x-coordinate of the point; the y is the channel range... */
|
||||
pt[0] = bezt->vec[1][0];
|
||||
pt[1] = ked->channel_y;
|
||||
|
||||
if (keyframe_region_circle_test(data, pt))
|
||||
return KEYFRAME_OK_KEY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
|
||||
{
|
||||
|
@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
|
|||
return ok_bezier_region_lasso;
|
||||
case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
|
||||
return ok_bezier_region_circle;
|
||||
case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */
|
||||
return ok_bezier_channel_lasso;
|
||||
case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
|
||||
return ok_bezier_channel_circle;
|
||||
default: /* nothing was ok */
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
|
|||
if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
|
||||
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
|
||||
}
|
||||
else if (RNA_property_subtype(prop), PROP_QUATERNION) {
|
||||
fcu->color_mode = FCURVE_COLOR_AUTO_YRGB;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert keyframe */
|
||||
|
|
|
@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short
|
|||
}
|
||||
}
|
||||
|
||||
/* select the frames in this layer that occur within the lasso/circle region specified */
|
||||
void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
|
||||
{
|
||||
bGPDframe *gpf;
|
||||
|
||||
if (gpl == NULL)
|
||||
return;
|
||||
|
||||
/* only select frames which are within the region */
|
||||
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
|
||||
/* construct a dummy point coordinate to do this testing with */
|
||||
float pt[2] = {0};
|
||||
|
||||
pt[0] = gpf->framenum;
|
||||
pt[1] = ked->channel_y;
|
||||
|
||||
/* check the necessary regions */
|
||||
if (tool == BEZT_OK_CHANNEL_LASSO) {
|
||||
/* Lasso */
|
||||
if (keyframe_region_lasso_test(ked->data, pt))
|
||||
gpframe_select(gpf, select_mode);
|
||||
}
|
||||
else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
|
||||
/* Circle */
|
||||
if (keyframe_region_circle_test(ked->data, pt))
|
||||
gpframe_select(gpf, select_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
/* Frame Editing Tools */
|
||||
|
||||
|
|
|
@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "Delete Active Frame";
|
||||
ot->idname = "GPENCIL_OT_active_frame_delete";
|
||||
ot->description = "Delete the active frame for the active Grease Pencil datablock";
|
||||
ot->description = "Delete the active frame for the active Grease Pencil Layer";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
|
@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot)
|
|||
ot->poll = gp_actframe_delete_poll;
|
||||
}
|
||||
|
||||
/* **************** Delete All Active Frames ****************** */
|
||||
|
||||
static int gp_actframe_delete_all_poll(bContext *C)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
|
||||
/* 1) There must be grease pencil data
|
||||
* 2) Hopefully some of the layers have stuff we can use
|
||||
*/
|
||||
return (gpd && gpd->layers.first);
|
||||
}
|
||||
|
||||
static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
bool success = false;
|
||||
|
||||
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
|
||||
{
|
||||
/* try to get the "active" frame - but only if it actually occurs on this frame */
|
||||
bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
|
||||
|
||||
if (gpf == NULL)
|
||||
continue;
|
||||
|
||||
/* delete it... */
|
||||
gpencil_layer_delframe(gpl, gpf);
|
||||
|
||||
/* we successfully modified something */
|
||||
success = true;
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* updates */
|
||||
if (success) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Delete All Active Frames";
|
||||
ot->idname = "GPENCIL_OT_active_frames_delete_all";
|
||||
ot->description = "Delete the active frame(s) of all editable Grease Pencil layers";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = gp_actframe_delete_all_exec;
|
||||
ot->poll = gp_actframe_delete_all_poll;
|
||||
}
|
||||
|
||||
/* ******************* Delete Operator ************************ */
|
||||
|
||||
typedef enum eGP_DeleteMode {
|
||||
|
|
|
@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
|
|||
void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
|
||||
|
||||
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
|
||||
|
||||
void GPENCIL_OT_convert(struct wmOperatorType *ot);
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
|
|||
|
||||
/* Delete Active Frame - For easier video tutorials/review sessions */
|
||||
/* NOTE: This works even when not in EditMode */
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY);
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
|
||||
}
|
||||
|
||||
/* ==================== */
|
||||
|
@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
|
|||
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
|
||||
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
|
||||
/* copy + paste */
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
|
||||
|
@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void)
|
|||
WM_operatortype_append(GPENCIL_OT_layer_isolate);
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
|
||||
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_convert);
|
||||
|
||||
|
|
|
@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result {
|
|||
typedef enum eGPencil_PaintFlags {
|
||||
GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
|
||||
GP_PAINTFLAG_STROKEADDED = (1 << 1),
|
||||
GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
|
||||
GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
|
||||
GP_PAINTFLAG_SELECTMASK = (1 << 3),
|
||||
} eGPencil_PaintFlags;
|
||||
|
||||
|
||||
|
@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
|
|||
BLI_freelinkN(&gpf->strokes, gps);
|
||||
}
|
||||
else if (gps->totpoints == 1) {
|
||||
gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
|
||||
|
||||
/* do boundbox check first */
|
||||
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
|
||||
/* only check if point is inside */
|
||||
if (len_v2v2_int(mval, pc1) <= radius) {
|
||||
/* free stroke */
|
||||
// XXX: pressure sensitive eraser should apply here too?
|
||||
MEM_freeN(gps->points);
|
||||
if (gps->triangles)
|
||||
MEM_freeN(gps->triangles);
|
||||
BLI_freelinkN(&gpf->strokes, gps);
|
||||
/* only process if it hasn't been masked out... */
|
||||
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
|
||||
gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
|
||||
|
||||
/* do boundbox check first */
|
||||
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
|
||||
/* only check if point is inside */
|
||||
if (len_v2v2_int(mval, pc1) <= radius) {
|
||||
/* free stroke */
|
||||
// XXX: pressure sensitive eraser should apply here too?
|
||||
MEM_freeN(gps->points);
|
||||
if (gps->triangles)
|
||||
MEM_freeN(gps->triangles);
|
||||
BLI_freelinkN(&gpf->strokes, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
|
|||
pt1 = gps->points + i;
|
||||
pt2 = gps->points + i + 1;
|
||||
|
||||
/* only process if it hasn't been masked out... */
|
||||
if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
|
||||
continue;
|
||||
|
||||
/* get coordinates of point in screenspace */
|
||||
gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
|
||||
gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
|
||||
|
||||
|
@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p)
|
|||
static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
|
||||
{
|
||||
Scene *scene = p->scene;
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
/* get active layer (or add a new one if non-existent) */
|
||||
p->gpl = gpencil_layer_getactive(p->gpd);
|
||||
|
@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
|
|||
/* Ensure this gets set... */
|
||||
p->gpf = p->gpl->actframe;
|
||||
|
||||
/* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
|
||||
* (though this is only available in editmode)
|
||||
*/
|
||||
if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
|
||||
if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
|
||||
p->flags |= GP_PAINTFLAG_SELECTMASK;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->gpf == NULL) {
|
||||
p->status = GP_STATUS_ERROR;
|
||||
//if (G.debug & G_DEBUG)
|
||||
|
@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
|
|||
}
|
||||
else {
|
||||
/* Drawing Modes - Add a new frame if needed on the active layer */
|
||||
ToolSettings *ts = p->scene->toolsettings;
|
||||
short add_frame_mode;
|
||||
|
||||
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
|
||||
|
|
|
@ -109,7 +109,7 @@ int ED_file_extension_icon(const char *path);
|
|||
|
||||
void ED_file_read_bookmarks(void);
|
||||
|
||||
void ED_file_change_dir(struct bContext *C, const bool checkdir);
|
||||
void ED_file_change_dir(struct bContext *C);
|
||||
|
||||
/* File menu stuff */
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ struct bGPDlayer;
|
|||
struct bGPDframe;
|
||||
struct bGPDstroke;
|
||||
struct bAnimContext;
|
||||
struct KeyframeEditData;
|
||||
struct PointerRNA;
|
||||
struct wmWindowManager;
|
||||
struct wmKeyConfig;
|
||||
|
@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
|
|||
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
|
||||
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
|
||||
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
|
||||
void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
|
||||
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
|
||||
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
|
||||
|
||||
|
|
|
@ -45,14 +45,21 @@ struct Scene;
|
|||
|
||||
/* bezt validation */
|
||||
typedef enum eEditKeyframes_Validate {
|
||||
/* Frame range */
|
||||
BEZT_OK_FRAME = 1,
|
||||
BEZT_OK_FRAMERANGE,
|
||||
/* Selection status */
|
||||
BEZT_OK_SELECTED,
|
||||
/* Values (y-val) only */
|
||||
BEZT_OK_VALUE,
|
||||
BEZT_OK_VALUERANGE,
|
||||
/* For graph editor keyframes (2D tests) */
|
||||
BEZT_OK_REGION,
|
||||
BEZT_OK_REGION_LASSO,
|
||||
BEZT_OK_REGION_CIRCLE,
|
||||
/* Only for keyframes a certain Dopesheet channel */
|
||||
BEZT_OK_CHANNEL_LASSO,
|
||||
BEZT_OK_CHANNEL_CIRCLE,
|
||||
} eEditKeyframes_Validate;
|
||||
|
||||
/* ------------ */
|
||||
|
@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror {
|
|||
} eEditKeyframes_Mirror;
|
||||
|
||||
/* use with BEZT_OK_REGION_LASSO */
|
||||
struct KeyframeEdit_LassoData {
|
||||
const rctf *rectf_scaled;
|
||||
typedef struct KeyframeEdit_LassoData {
|
||||
rctf *rectf_scaled;
|
||||
const rctf *rectf_view;
|
||||
const int (*mcords)[2];
|
||||
int mcords_tot;
|
||||
};
|
||||
} KeyframeEdit_LassoData;
|
||||
|
||||
/* use with BEZT_OK_REGION_CIRCLE */
|
||||
struct KeyframeEdit_CircleData {
|
||||
const rctf *rectf_scaled;
|
||||
typedef struct KeyframeEdit_CircleData {
|
||||
rctf *rectf_scaled;
|
||||
const rctf *rectf_view;
|
||||
float mval[2];
|
||||
float radius_squared;
|
||||
};
|
||||
} KeyframeEdit_CircleData;
|
||||
|
||||
|
||||
/* ************************************************ */
|
||||
|
@ -157,7 +164,8 @@ typedef struct KeyframeEditData {
|
|||
/* current iteration data */
|
||||
struct FCurve *fcu; /* F-Curve that is being iterated over */
|
||||
int curIndex; /* index of current keyframe being iterated over */
|
||||
|
||||
float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */
|
||||
|
||||
/* flags */
|
||||
eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
|
||||
eKeyframeIterFlags iterflags; /* settings for iteration process */
|
||||
|
@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt);
|
|||
*/
|
||||
void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt);
|
||||
|
||||
/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */
|
||||
/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */
|
||||
|
||||
bool keyframe_region_lasso_test(
|
||||
const KeyframeEdit_LassoData *data_lasso,
|
||||
const float xy[2]);
|
||||
|
||||
bool keyframe_region_circle_test(
|
||||
const KeyframeEdit_CircleData *data_circle,
|
||||
const float xy[2]);
|
||||
|
||||
|
||||
/* ************************************************ */
|
||||
/* Destructive Editing API (keyframes_general.c) */
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ struct bContext;
|
|||
struct wmKeyConfig;
|
||||
struct MaskLayer;
|
||||
struct MaskLayerShape;
|
||||
struct KeyframeEditData;
|
||||
|
||||
/* mask_edit.c */
|
||||
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
|
||||
|
@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
|
|||
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
|
||||
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
|
||||
void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
|
||||
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
|
||||
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
|
||||
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
|
||||
|
||||
|
|
|
@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list(
|
|||
|
||||
/* Helpers for Operators */
|
||||
uiBut *UI_context_active_but_get(const struct bContext *C);
|
||||
void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
|
||||
void UI_context_active_but_prop_get(
|
||||
const struct bContext *C,
|
||||
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
|
||||
void UI_context_active_but_prop_handle(struct bContext *C);
|
||||
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
|
||||
void UI_context_update_anim_flag(const struct bContext *C);
|
||||
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
|
||||
void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
|
||||
void UI_context_active_but_prop_get_filebrowser(
|
||||
const struct bContext *C,
|
||||
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo);
|
||||
void UI_context_active_but_prop_get_templateID(
|
||||
struct bContext *C,
|
||||
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
|
||||
|
||||
/* Styled text draw */
|
||||
void UI_fontstyle_set(const struct uiFontStyle *fs);
|
||||
|
|
|
@ -4323,7 +4323,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
|
|||
|
||||
|
||||
/**
|
||||
* \param sfunc, bfunc: both get it as \a arg.
|
||||
* \param search_func, bfunc: both get it as \a arg.
|
||||
* \param arg: user value,
|
||||
* \param active: when set, button opens with this item visible and selected.
|
||||
*/
|
||||
|
|
|
@ -8013,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C)
|
|||
}
|
||||
|
||||
/* helper function for insert keyframe, reset to default, etc operators */
|
||||
void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index)
|
||||
void UI_context_active_but_prop_get(
|
||||
const bContext *C,
|
||||
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
|
||||
{
|
||||
uiBut *activebut = ui_context_rna_button_active(C);
|
||||
|
||||
memset(ptr, 0, sizeof(*ptr));
|
||||
|
||||
if (activebut && activebut->rnapoin.data) {
|
||||
*ptr = activebut->rnapoin;
|
||||
*prop = activebut->rnaprop;
|
||||
*index = activebut->rnaindex;
|
||||
*r_ptr = activebut->rnapoin;
|
||||
*r_prop = activebut->rnaprop;
|
||||
*r_index = activebut->rnaindex;
|
||||
}
|
||||
else {
|
||||
*prop = NULL;
|
||||
*index = 0;
|
||||
memset(r_ptr, 0, sizeof(*r_ptr));
|
||||
*r_prop = NULL;
|
||||
*r_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9812,10 +9813,17 @@ static int ui_handle_menus_recursive(
|
|||
retval = ui_pie_handler(C, event, menu);
|
||||
}
|
||||
else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) {
|
||||
bool handled = false;
|
||||
|
||||
if (listbox) {
|
||||
retval = ui_handle_list_event(C, event, menu->region, listbox);
|
||||
int retval_test = ui_handle_list_event(C, event, menu->region, listbox);
|
||||
if (retval_test != WM_UI_HANDLER_CONTINUE) {
|
||||
retval = retval_test;
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
if (retval == WM_UI_HANDLER_CONTINUE) {
|
||||
|
||||
if (handled == false) {
|
||||
retval = ui_handle_menu_event(
|
||||
C, event, menu, level,
|
||||
is_parent_inside, is_parent_menu, is_floating);
|
||||
|
|
|
@ -231,15 +231,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
|
|||
/* This is for browsing and editing the ID-blocks used */
|
||||
|
||||
/* for new/open operators */
|
||||
void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
|
||||
void UI_context_active_but_prop_get_templateID(
|
||||
bContext *C,
|
||||
PointerRNA *r_ptr, PropertyRNA **r_prop)
|
||||
{
|
||||
TemplateID *template;
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
uiBlock *block;
|
||||
uiBut *but;
|
||||
|
||||
memset(ptr, 0, sizeof(*ptr));
|
||||
*prop = NULL;
|
||||
memset(r_ptr, 0, sizeof(*r_ptr));
|
||||
*r_prop = NULL;
|
||||
|
||||
if (!ar)
|
||||
return;
|
||||
|
@ -250,8 +252,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro
|
|||
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
|
||||
if (but->func_argN) {
|
||||
template = but->func_argN;
|
||||
*ptr = template->ptr;
|
||||
*prop = template->prop;
|
||||
*r_ptr = template->ptr;
|
||||
*r_prop = template->prop;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max,
|
|||
}
|
||||
}
|
||||
|
||||
/* select the frames in this layer that occur within the lasso/circle region specified */
|
||||
void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode)
|
||||
{
|
||||
MaskLayerShape *masklay_shape;
|
||||
|
||||
if (masklay == NULL)
|
||||
return;
|
||||
|
||||
/* only select frames which are within the region */
|
||||
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
|
||||
/* construct a dummy point coordinate to do this testing with */
|
||||
float pt[2] = {0};
|
||||
|
||||
pt[0] = masklay_shape->frame;
|
||||
pt[1] = ked->channel_y;
|
||||
|
||||
/* check the necessary regions */
|
||||
if (tool == BEZT_OK_CHANNEL_LASSO) {
|
||||
/* Lasso */
|
||||
if (keyframe_region_lasso_test(ked->data, pt))
|
||||
masklayshape_select(masklay_shape, select_mode);
|
||||
}
|
||||
else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
|
||||
/* Circle */
|
||||
if (keyframe_region_circle_test(ked->data, pt))
|
||||
masklayshape_select(masklay_shape, select_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
/* Frame Editing Tools */
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_buffers.h"
|
||||
|
||||
/* own include */
|
||||
|
@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
|
|||
if (ENDIAN_ORDER == B_ENDIAN) {
|
||||
IMB_convert_rgba_to_abgr(ibuf);
|
||||
}
|
||||
WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]);
|
||||
GPU_select_to_index_array(ibuf->rect, size[0] * size[1]);
|
||||
|
||||
a = size[0] * size[1];
|
||||
while (a--) {
|
||||
|
|
|
@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot)
|
|||
/************************ add constraint operators *********************/
|
||||
|
||||
/* get the Object and/or PoseChannel to use as target */
|
||||
static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add)
|
||||
static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
|
||||
{
|
||||
Object *obact = ED_object_active_context(C);
|
||||
bPoseChannel *pchanact = BKE_pose_channel_active(obact);
|
||||
short only_curve = 0, only_mesh = 0, only_ob = 0;
|
||||
short found = 0;
|
||||
bool only_curve = false, only_mesh = false, only_ob = false;
|
||||
bool found = false;
|
||||
|
||||
/* clear tar_ob and tar_pchan fields before use
|
||||
* - assume for now that both always exist...
|
||||
|
@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
|
|||
case CONSTRAINT_TYPE_ROTLIMIT:
|
||||
case CONSTRAINT_TYPE_SIZELIMIT:
|
||||
case CONSTRAINT_TYPE_SAMEVOL:
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* restricted target-type constraints -------------- */
|
||||
/* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */
|
||||
|
@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
|
|||
case CONSTRAINT_TYPE_CLAMPTO:
|
||||
case CONSTRAINT_TYPE_FOLLOWPATH:
|
||||
case CONSTRAINT_TYPE_SPLINEIK:
|
||||
only_curve = 1;
|
||||
only_ob = 1;
|
||||
add = 0;
|
||||
only_curve = true;
|
||||
only_ob = true;
|
||||
add = false;
|
||||
break;
|
||||
|
||||
/* mesh only? */
|
||||
case CONSTRAINT_TYPE_SHRINKWRAP:
|
||||
only_mesh = 1;
|
||||
only_ob = 1;
|
||||
add = 0;
|
||||
only_mesh = true;
|
||||
only_ob = true;
|
||||
add = false;
|
||||
break;
|
||||
|
||||
/* object only - add here is ok? */
|
||||
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
|
||||
only_ob = 1;
|
||||
only_ob = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if the active Object is Armature, and we can search for bones, do so... */
|
||||
if ((obact->type == OB_ARMATURE) && (only_ob == 0)) {
|
||||
if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
|
||||
/* search in list of selected Pose-Channels for target */
|
||||
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
|
||||
{
|
||||
|
@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
|
|||
if (pchan != pchanact) {
|
||||
*tar_ob = obact;
|
||||
*tar_pchan = pchan;
|
||||
found = 1;
|
||||
found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
|
|||
}
|
||||
|
||||
/* if not yet found, try selected Objects... */
|
||||
if (found == 0) {
|
||||
if (found == false) {
|
||||
/* search in selected objects context */
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
|
||||
{
|
||||
/* just use the first object we encounter (that isn't the active object)
|
||||
* and which fulfills the criteria for the object-target that we've got
|
||||
*/
|
||||
if ((ob != obact) &&
|
||||
((!only_curve) || (ob->type == OB_CURVE)) &&
|
||||
((!only_mesh) || (ob->type == OB_MESH)))
|
||||
{
|
||||
/* set target */
|
||||
*tar_ob = ob;
|
||||
found = 1;
|
||||
|
||||
/* perform some special operations on the target */
|
||||
if (only_curve) {
|
||||
/* Curve-Path option must be enabled for follow-path constraints to be able to work */
|
||||
Curve *cu = (Curve *)ob->data;
|
||||
cu->flag |= CU_PATH;
|
||||
if (ob != obact) {
|
||||
/* for armatures in pose mode, look inside the armature for the active bone
|
||||
* so that we set up cross-armature constraints with less effort
|
||||
*/
|
||||
if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) &&
|
||||
(!only_curve && !only_mesh))
|
||||
{
|
||||
/* just use the active bone, and assume that it is visible + usable */
|
||||
*tar_ob = ob;
|
||||
*tar_pchan = BKE_pose_channel_active(ob);
|
||||
found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (((!only_curve) || (ob->type == OB_CURVE)) &&
|
||||
((!only_mesh) || (ob->type == OB_MESH)))
|
||||
{
|
||||
/* set target */
|
||||
*tar_ob = ob;
|
||||
found = true;
|
||||
|
||||
/* perform some special operations on the target */
|
||||
if (only_curve) {
|
||||
/* Curve-Path option must be enabled for follow-path constraints to be able to work */
|
||||
Curve *cu = (Curve *)ob->data;
|
||||
cu->flag |= CU_PATH;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
|
||||
/* if still not found, add a new empty to act as a target (if allowed) */
|
||||
if ((found == 0) && (add)) {
|
||||
if ((found == false) && (add)) {
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Base *base = BASACT, *newbase = NULL;
|
||||
|
@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
|
|||
|
||||
/* make our new target the new object */
|
||||
*tar_ob = obt;
|
||||
found = 1;
|
||||
found = true;
|
||||
}
|
||||
|
||||
/* return whether there's any target */
|
||||
|
|
|
@ -436,7 +436,7 @@ typedef enum eObClearParentTypes {
|
|||
|
||||
EnumPropertyItem prop_clear_parent_types[] = {
|
||||
{CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
|
||||
"Completely clear the parenting relationship, including involved modifiers is any"},
|
||||
"Completely clear the parenting relationship, including involved modifiers if any"},
|
||||
{CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
|
||||
"As 'Clear Parent', but keep the current visual transformations of the object"},
|
||||
{CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
|
||||
|
|
|
@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s
|
|||
|
||||
void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
|
||||
void ACTION_OT_select_border(struct wmOperatorType *ot);
|
||||
void ACTION_OT_select_lasso(struct wmOperatorType *ot);
|
||||
void ACTION_OT_select_circle(struct wmOperatorType *ot);
|
||||
void ACTION_OT_select_column(struct wmOperatorType *ot);
|
||||
void ACTION_OT_select_linked(struct wmOperatorType *ot);
|
||||
void ACTION_OT_select_more(struct wmOperatorType *ot);
|
||||
|
|
|
@ -59,6 +59,8 @@ void action_operatortypes(void)
|
|||
WM_operatortype_append(ACTION_OT_clickselect);
|
||||
WM_operatortype_append(ACTION_OT_select_all_toggle);
|
||||
WM_operatortype_append(ACTION_OT_select_border);
|
||||
WM_operatortype_append(ACTION_OT_select_lasso);
|
||||
WM_operatortype_append(ACTION_OT_select_circle);
|
||||
WM_operatortype_append(ACTION_OT_select_column);
|
||||
WM_operatortype_append(ACTION_OT_select_linked);
|
||||
WM_operatortype_append(ACTION_OT_select_more);
|
||||
|
@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
|
|||
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "axis_range", true);
|
||||
|
||||
/* region select */
|
||||
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
|
||||
RNA_boolean_set(kmi->ptr, "deselect", false);
|
||||
kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "deselect", true);
|
||||
|
||||
WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
|
||||
|
||||
/* column select */
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dlrbTree.h"
|
||||
#include "BLI_lasso.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot)
|
|||
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
|
||||
}
|
||||
|
||||
/* ******************** Region Select Operators ***************************** */
|
||||
/* "Region Select" operators include the Lasso and Circle Select operators.
|
||||
* These two ended up being lumped together, as it was easier in the
|
||||
* original Graph Editor implmentation of these to do it this way.
|
||||
*/
|
||||
|
||||
static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
int filter;
|
||||
|
||||
KeyframeEditData ked;
|
||||
KeyframeEditFunc ok_cb, select_cb;
|
||||
View2D *v2d = &ac->ar->v2d;
|
||||
rctf rectf, scaled_rectf;
|
||||
float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
|
||||
|
||||
/* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
|
||||
UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
|
||||
|
||||
/* filter data */
|
||||
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
|
||||
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
||||
|
||||
/* get beztriple editing/validation funcs */
|
||||
select_cb = ANIM_editkeyframes_select(selectmode);
|
||||
ok_cb = ANIM_editkeyframes_ok(mode);
|
||||
|
||||
/* init editing data */
|
||||
memset(&ked, 0, sizeof(KeyframeEditData));
|
||||
if (mode == BEZT_OK_CHANNEL_LASSO) {
|
||||
KeyframeEdit_LassoData *data_lasso = data;
|
||||
data_lasso->rectf_scaled = &scaled_rectf;
|
||||
ked.data = data_lasso;
|
||||
}
|
||||
else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
|
||||
KeyframeEdit_CircleData *data_circle = data;
|
||||
data_circle->rectf_scaled = &scaled_rectf;
|
||||
ked.data = data;
|
||||
}
|
||||
else {
|
||||
ked.data = &scaled_rectf;
|
||||
}
|
||||
|
||||
/* loop over data, doing region select */
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
||||
|
||||
/* get new vertical minimum extent of channel */
|
||||
ymin = ymax - ACHANNEL_STEP;
|
||||
|
||||
/* compute midpoint of channel (used for testing if the key is in the region or not) */
|
||||
ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
|
||||
|
||||
/* if channel is mapped in NLA, apply correction
|
||||
* - Apply to the bounds being checked, not all the keyframe points,
|
||||
* to avoid having scaling everything
|
||||
* - Save result to the scaled_rect, which is all that these operators
|
||||
* will read from
|
||||
*/
|
||||
if (adt) {
|
||||
ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
|
||||
ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
|
||||
ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
|
||||
}
|
||||
else {
|
||||
ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
|
||||
ked.f1 = rectf.xmin;
|
||||
ked.f2 = rectf.xmax;
|
||||
}
|
||||
|
||||
/* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
|
||||
* NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these
|
||||
* with the properly remapped ked.f1/f2 values, when needed
|
||||
*/
|
||||
scaled_rectf.xmin = ked.f1;
|
||||
scaled_rectf.xmax = ked.f2;
|
||||
scaled_rectf.ymin = ymin;
|
||||
scaled_rectf.ymax = ymax;
|
||||
|
||||
/* perform vertical suitability check (if applicable) */
|
||||
if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
|
||||
!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
|
||||
{
|
||||
/* loop over data selecting */
|
||||
switch (ale->type) {
|
||||
case ANIMTYPE_GPDATABLOCK:
|
||||
{
|
||||
bGPdata *gpd = ale->data;
|
||||
bGPDlayer *gpl;
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GPLAYER:
|
||||
{
|
||||
ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_MASKDATABLOCK:
|
||||
{
|
||||
Mask *mask = ale->data;
|
||||
MaskLayer *masklay;
|
||||
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
|
||||
ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_MASKLAYER:
|
||||
{
|
||||
ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set minimum extent to be the maximum of the next channel */
|
||||
ymax = ymin;
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
/* ----------------------------------- */
|
||||
|
||||
static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
KeyframeEdit_LassoData data_lasso;
|
||||
rcti rect;
|
||||
rctf rect_fl;
|
||||
|
||||
short selectmode;
|
||||
bool extend;
|
||||
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
data_lasso.rectf_view = &rect_fl;
|
||||
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
|
||||
if (data_lasso.mcords == NULL)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
/* clear all selection if not extending selection */
|
||||
extend = RNA_boolean_get(op->ptr, "extend");
|
||||
if (!extend)
|
||||
deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
|
||||
|
||||
if (!RNA_boolean_get(op->ptr, "deselect"))
|
||||
selectmode = SELECT_ADD;
|
||||
else
|
||||
selectmode = SELECT_SUBTRACT;
|
||||
|
||||
/* get settings from operator */
|
||||
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
|
||||
BLI_rctf_rcti_copy(&rect_fl, &rect);
|
||||
|
||||
/* apply borderselect action */
|
||||
region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
|
||||
|
||||
MEM_freeN((void *)data_lasso.mcords);
|
||||
|
||||
/* send notifier that keyframe selection has changed */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void ACTION_OT_select_lasso(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Lasso Select";
|
||||
ot->description = "Select keyframe points using lasso selection";
|
||||
ot->idname = "ACTION_OT_select_lasso";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = WM_gesture_lasso_invoke;
|
||||
ot->modal = WM_gesture_lasso_modal;
|
||||
ot->exec = actkeys_lassoselect_exec;
|
||||
ot->poll = ED_operator_action_active;
|
||||
ot->cancel = WM_gesture_lasso_cancel;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
|
||||
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
|
||||
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
|
||||
}
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static int action_circle_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
|
||||
const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
|
||||
|
||||
KeyframeEdit_CircleData data = {0};
|
||||
rctf rect_fl;
|
||||
|
||||
float x = RNA_int_get(op->ptr, "x");
|
||||
float y = RNA_int_get(op->ptr, "y");
|
||||
float radius = RNA_int_get(op->ptr, "radius");
|
||||
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
data.mval[0] = x;
|
||||
data.mval[1] = y;
|
||||
data.radius_squared = radius * radius;
|
||||
data.rectf_view = &rect_fl;
|
||||
|
||||
rect_fl.xmin = x - radius;
|
||||
rect_fl.xmax = x + radius;
|
||||
rect_fl.ymin = y - radius;
|
||||
rect_fl.ymax = y + radius;
|
||||
|
||||
/* apply region select action */
|
||||
region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
|
||||
|
||||
/* send notifier that keyframe selection has changed */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void ACTION_OT_select_circle(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Circle Select";
|
||||
ot->description = "Select keyframe points using circle selection";
|
||||
ot->idname = "ACTION_OT_select_circle";
|
||||
|
||||
ot->invoke = WM_gesture_circle_invoke;
|
||||
ot->modal = WM_gesture_circle_modal;
|
||||
ot->exec = action_circle_select_exec;
|
||||
ot->poll = ED_operator_action_active;
|
||||
ot->cancel = WM_gesture_circle_cancel;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO;
|
||||
|
||||
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
|
||||
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
|
||||
RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
|
||||
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
|
||||
}
|
||||
|
||||
/* ******************** Column Select Operator **************************** */
|
||||
/* This operator works in one of four ways:
|
||||
* - 1) select all keyframes in the same frame as a selected one (KKEY)
|
||||
|
|
|
@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art);
|
|||
|
||||
/* file_utils.c */
|
||||
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
|
||||
bool file_is_dir(struct SpaceFile *sfile, const char *path);
|
||||
|
||||
#endif /* __FILE_INTERN_H__ */
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
|
|||
BLI_add_slash(params->dir);
|
||||
}
|
||||
|
||||
ED_file_change_dir(C, false);
|
||||
ED_file_change_dir(C);
|
||||
retval = FILE_SELECT_DIR;
|
||||
}
|
||||
}
|
||||
|
@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
|
|||
RNA_property_string_get(op->ptr, prop, entry);
|
||||
BLI_strncpy(params->dir, entry, sizeof(params->dir));
|
||||
BLI_cleanup_dir(G.main->name, params->dir);
|
||||
ED_file_change_dir(C, true);
|
||||
ED_file_change_dir(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
||||
}
|
||||
|
@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
|
|||
BLI_add_slash(sfile->params->dir);
|
||||
}
|
||||
|
||||
ED_file_change_dir(C, false);
|
||||
ED_file_change_dir(C);
|
||||
}
|
||||
/* opening file - sends events now, so things get handled on windowqueue level */
|
||||
else if (sfile->op) {
|
||||
|
@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
|
|||
if (sfile->params) {
|
||||
if (BLI_parent_dir(sfile->params->dir)) {
|
||||
BLI_cleanup_dir(G.main->name, sfile->params->dir);
|
||||
/* if not browsing in .blend file, we still want to check whether the path is a directory */
|
||||
if (sfile->params->type == FILE_LOADLIB) {
|
||||
char tdir[FILE_MAX];
|
||||
if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) {
|
||||
ED_file_change_dir(C, false);
|
||||
}
|
||||
else {
|
||||
ED_file_change_dir(C, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ED_file_change_dir(C, true);
|
||||
}
|
||||
ED_file_change_dir(C);
|
||||
if (sfile->params->recursion_level > 1) {
|
||||
/* Disable 'dirtree' recursion when going up in tree. */
|
||||
sfile->params->recursion_level = 0;
|
||||
|
@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
|
|||
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
|
||||
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
|
||||
|
||||
ED_file_change_dir(C, true);
|
||||
ED_file_change_dir(C);
|
||||
}
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
||||
|
||||
|
@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
|
|||
// update folders_prev so we can check for it in folderlist_clear_next()
|
||||
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
|
||||
|
||||
ED_file_change_dir(C, true);
|
||||
ED_file_change_dir(C);
|
||||
}
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
||||
|
||||
|
@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
|
|||
|
||||
if (RNA_boolean_get(op->ptr, "open")) {
|
||||
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
|
||||
ED_file_change_dir(C, true);
|
||||
ED_file_change_dir(C);
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
||||
|
@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
|
|||
file_expand_directory(C);
|
||||
|
||||
/* special case, user may have pasted a filepath into the directory */
|
||||
if (BLI_is_file(sfile->params->dir)) {
|
||||
char path[sizeof(sfile->params->dir)];
|
||||
BLI_strncpy(path, sfile->params->dir, sizeof(path));
|
||||
BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
|
||||
if (!file_is_dir(sfile, sfile->params->dir)) {
|
||||
char tdir[FILE_MAX_LIBEXTRA];
|
||||
char *group, *name;
|
||||
|
||||
if (BLI_is_file(sfile->params->dir)) {
|
||||
char path[sizeof(sfile->params->dir)];
|
||||
BLI_strncpy(path, sfile->params->dir, sizeof(path));
|
||||
BLI_split_dirfile(path, sfile->params->dir, sfile->params->file,
|
||||
sizeof(sfile->params->dir), sizeof(sfile->params->file));
|
||||
}
|
||||
else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
|
||||
if (group) {
|
||||
BLI_path_append(tdir, sizeof(tdir), group);
|
||||
}
|
||||
BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
|
||||
if (name) {
|
||||
BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
|
||||
}
|
||||
else {
|
||||
sfile->params->file[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_cleanup_dir(G.main->name, sfile->params->dir);
|
||||
|
||||
if (BLI_exists(sfile->params->dir)) {
|
||||
if (file_is_dir(sfile, sfile->params->dir)) {
|
||||
/* if directory exists, enter it immediately */
|
||||
ED_file_change_dir(C, true);
|
||||
ED_file_change_dir(C);
|
||||
|
||||
/* don't do for now because it selects entire text instead of
|
||||
* placing cursor at the end */
|
||||
|
@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
|
|||
#endif
|
||||
else {
|
||||
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
|
||||
char tdir[FILE_MAX_LIBEXTRA];
|
||||
|
||||
/* if not, ask to create it and enter if confirmed */
|
||||
wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
|
||||
PointerRNA ptr;
|
||||
WM_operator_properties_create_ptr(&ptr, ot);
|
||||
RNA_string_set(&ptr, "directory", sfile->params->dir);
|
||||
RNA_boolean_set(&ptr, "open", true);
|
||||
|
||||
if (lastdir)
|
||||
/* If we are 'inside' a blend library, we cannot do anything... */
|
||||
if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
|
||||
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
|
||||
}
|
||||
else {
|
||||
/* if not, ask to create it and enter if confirmed */
|
||||
wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
|
||||
PointerRNA ptr;
|
||||
WM_operator_properties_create_ptr(&ptr, ot);
|
||||
RNA_string_set(&ptr, "directory", sfile->params->dir);
|
||||
RNA_boolean_set(&ptr, "open", true);
|
||||
|
||||
if (lastdir)
|
||||
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
|
||||
WM_operator_properties_free(&ptr);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
|
||||
WM_operator_properties_free(&ptr);
|
||||
}
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
||||
|
@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
|
|||
BLI_filename_make_safe(sfile->params->file);
|
||||
|
||||
if (matches) {
|
||||
/* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */
|
||||
sfile->params->file[0] = '\0';
|
||||
/* replace the pattern (or filename that the user typed in, with the first selected file of the match */
|
||||
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
|
||||
|
||||
|
@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
|
|||
}
|
||||
|
||||
if (matches == 1) {
|
||||
|
||||
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
|
||||
|
||||
/* if directory, open it and empty filename field */
|
||||
if (BLI_is_dir(filepath)) {
|
||||
if (file_is_dir(sfile, filepath)) {
|
||||
BLI_cleanup_dir(G.main->name, filepath);
|
||||
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
|
||||
sfile->params->file[0] = '\0';
|
||||
ED_file_change_dir(C, true);
|
||||
ED_file_change_dir(C);
|
||||
UI_textbutton_activate_but(C, but);
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
||||
}
|
||||
else if (sfile->params->type == FILE_LOADLIB) {
|
||||
char tdir[FILE_MAX];
|
||||
BLI_add_slash(filepath);
|
||||
if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) {
|
||||
BLI_cleanup_dir(G.main->name, filepath);
|
||||
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
|
||||
sfile->params->file[0] = '\0';
|
||||
ED_file_change_dir(C, false);
|
||||
UI_textbutton_activate_but(C, but);
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (matches > 1) {
|
||||
file_draw_check(C);
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
*/
|
||||
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_fileops.h"
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
|
@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
|
|||
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
|
||||
ymax - layout->tile_h - layout->tile_border_y, ymax);
|
||||
}
|
||||
|
||||
/* Cannot directly use BLI_is_dir in libloading context... */
|
||||
bool file_is_dir(struct SpaceFile *sfile, const char *path)
|
||||
{
|
||||
if (sfile->params->type == FILE_LOADLIB) {
|
||||
char tdir[FILE_MAX_LIBEXTRA];
|
||||
char *name;
|
||||
if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
|
||||
/* .blend file itself and group are considered as directories, not final datablock names. */
|
||||
return name ? false : true;
|
||||
}
|
||||
}
|
||||
return BLI_is_dir(path);
|
||||
}
|
||||
|
|
|
@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root)
|
|||
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
|
||||
{
|
||||
bool is_filtered;
|
||||
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name;
|
||||
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
|
||||
|
||||
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
|
||||
|
||||
|
@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist)
|
|||
if (filelist->max_recursion) {
|
||||
/* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
|
||||
* root path is a blend file. */
|
||||
char dir[FILE_MAXDIR];
|
||||
char dir[FILE_MAX_LIBEXTRA];
|
||||
if (!filelist_islibrary(filelist, dir, NULL)) {
|
||||
filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
|
||||
}
|
||||
|
@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir
|
|||
|
||||
static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
|
||||
{
|
||||
char dir[FILE_MAXDIR];
|
||||
char dir[FILE_MAX_LIBEXTRA];
|
||||
if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
|
||||
/* if not a valid library, we need it to be a valid directory! */
|
||||
BLI_make_exist(r_dir);
|
||||
|
@ -2113,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
|
||||
bool filelist_islibrary(struct FileList *filelist, char *dir, char **group)
|
||||
{
|
||||
return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL);
|
||||
|
@ -2208,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
|
|||
FileListInternEntry *entry;
|
||||
LinkNode *ln, *names;
|
||||
int i, nnames, idcode = 0, nbr_entries = 0;
|
||||
char dir[FILE_MAX], *group;
|
||||
char dir[FILE_MAX_LIBEXTRA], *group;
|
||||
bool ok;
|
||||
|
||||
struct BlendHandle *libfiledata = NULL;
|
||||
|
|
|
@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar)
|
|||
return sfile->layout;
|
||||
}
|
||||
|
||||
void ED_file_change_dir(bContext *C, const bool checkdir)
|
||||
void ED_file_change_dir(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||
|
@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir)
|
|||
sfile->params->filter_search[0] = '\0';
|
||||
sfile->params->active_file = -1;
|
||||
|
||||
if (checkdir && !BLI_is_dir(sfile->params->dir)) {
|
||||
if (!file_is_dir(sfile, sfile->params->dir)) {
|
||||
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
|
||||
/* could return but just refresh the current dir */
|
||||
}
|
||||
|
|
|
@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
|
|||
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "axis_range", true);
|
||||
RNA_boolean_set(kmi->ptr, "include_handles", false);
|
||||
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
|
||||
RNA_boolean_set(kmi->ptr, "axis_range", false);
|
||||
RNA_boolean_set(kmi->ptr, "include_handles", true);
|
||||
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "axis_range", true);
|
||||
RNA_boolean_set(kmi->ptr, "include_handles", true);
|
||||
|
||||
|
||||
/* region select */
|
||||
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
|
||||
RNA_boolean_set(kmi->ptr, "deselect", false);
|
||||
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "deselect", true);
|
||||
|
||||
|
||||
WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
|
||||
|
||||
/* column select */
|
||||
|
|
|
@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
|
|||
* -> ALT-BKEY - depending on which axis of the region was larger...
|
||||
* -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE)
|
||||
* -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE)
|
||||
*
|
||||
* The selection backend is also reused for the Lasso and Circle select operators.
|
||||
*/
|
||||
|
||||
/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
|
||||
|
@ -245,12 +247,12 @@ static void borderselect_graphkeys(
|
|||
/* init editing data */
|
||||
memset(&ked, 0, sizeof(KeyframeEditData));
|
||||
if (mode == BEZT_OK_REGION_LASSO) {
|
||||
struct KeyframeEdit_LassoData *data_lasso = data;
|
||||
KeyframeEdit_LassoData *data_lasso = data;
|
||||
data_lasso->rectf_scaled = &scaled_rectf;
|
||||
ked.data = data_lasso;
|
||||
}
|
||||
else if (mode == BEZT_OK_REGION_CIRCLE) {
|
||||
struct KeyframeEdit_CircleData *data_circle = data;
|
||||
KeyframeEdit_CircleData *data_circle = data;
|
||||
data_circle->rectf_scaled = &scaled_rectf;
|
||||
ked.data = data;
|
||||
}
|
||||
|
@ -265,27 +267,27 @@ static void borderselect_graphkeys(
|
|||
}
|
||||
else
|
||||
mapping_flag = ANIM_UNITCONV_ONLYKEYS;
|
||||
|
||||
|
||||
mapping_flag |= ANIM_get_normalization_flags(ac);
|
||||
|
||||
|
||||
/* loop over data, doing border select */
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
float offset;
|
||||
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
|
||||
|
||||
|
||||
/* apply NLA mapping to all the keyframes, since it's easier than trying to
|
||||
* guess when a callback might use something different
|
||||
*/
|
||||
if (adt)
|
||||
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0);
|
||||
|
||||
|
||||
scaled_rectf.xmin = rectf.xmin;
|
||||
scaled_rectf.xmax = rectf.xmax;
|
||||
scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
|
||||
scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
|
||||
|
||||
|
||||
/* set horizontal range (if applicable)
|
||||
* NOTE: these values are only used for x-range and y-range but not region
|
||||
* (which uses ked.data, i.e. rectf)
|
||||
|
@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
|
|||
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
|
||||
}
|
||||
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
KeyframeEdit_LassoData data_lasso = {0};
|
||||
rcti rect;
|
||||
rctf rect_fl;
|
||||
|
||||
short selectmode;
|
||||
bool incl_handles;
|
||||
bool extend;
|
||||
|
||||
struct KeyframeEdit_LassoData data_lasso;
|
||||
|
||||
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
|
||||
data_lasso.rectf_view = &rect_fl;
|
||||
data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
|
||||
if (data_lasso.mcords == NULL)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
|
||||
/* clear all selection if not extending selection */
|
||||
extend = RNA_boolean_get(op->ptr, "extend");
|
||||
if (!extend)
|
||||
deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true);
|
||||
|
||||
|
||||
if (!RNA_boolean_get(op->ptr, "deselect"))
|
||||
selectmode = SELECT_ADD;
|
||||
else
|
||||
selectmode = SELECT_SUBTRACT;
|
||||
|
||||
if (ac.spacetype == SPACE_IPO) {
|
||||
|
||||
{
|
||||
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
|
||||
if (selectmode == SELECT_ADD) {
|
||||
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
|
||||
|
@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
|
|||
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
incl_handles = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* get settings from operator */
|
||||
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
|
||||
|
||||
BLI_rctf_rcti_copy(&rect_fl, &rect);
|
||||
|
||||
|
||||
/* apply borderselect action */
|
||||
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
|
||||
|
||||
|
||||
MEM_freeN((void *)data_lasso.mcords);
|
||||
|
||||
|
||||
|
||||
/* send notifier that keyframe selection has changed */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
|
||||
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
void GRAPH_OT_select_lasso(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Lasso Select";
|
||||
ot->description = "Select keyframe points using lasso selection";
|
||||
ot->idname = "GRAPH_OT_select_lasso";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = WM_gesture_lasso_invoke;
|
||||
ot->modal = WM_gesture_lasso_modal;
|
||||
ot->exec = graphkeys_lassoselect_exec;
|
||||
ot->poll = graphop_visible_keyframes_poll;
|
||||
ot->cancel = WM_gesture_lasso_cancel;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO;
|
||||
|
||||
|
||||
/* properties */
|
||||
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
|
||||
RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
|
||||
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
|
||||
}
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static int graph_circle_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
|
||||
short selectmode;
|
||||
bool incl_handles;
|
||||
const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
|
||||
bool incl_handles = false;
|
||||
|
||||
KeyframeEdit_CircleData data = {0};
|
||||
rctf rect_fl;
|
||||
struct KeyframeEdit_CircleData data;
|
||||
|
||||
float x = RNA_int_get(op->ptr, "x");
|
||||
float y = RNA_int_get(op->ptr, "y");
|
||||
float radius = RNA_int_get(op->ptr, "radius");
|
||||
|
@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
|
|||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
|
||||
data.mval[0] = x;
|
||||
data.mval[1] = y;
|
||||
data.radius_squared = radius * radius;
|
||||
data.rectf_view = &rect_fl;
|
||||
|
||||
if (gesture_mode == GESTURE_MODAL_SELECT)
|
||||
selectmode = SELECT_ADD;
|
||||
else
|
||||
selectmode = SELECT_SUBTRACT;
|
||||
|
||||
rect_fl.xmin = x - radius;
|
||||
rect_fl.xmax = x + radius;
|
||||
rect_fl.ymin = y - radius;
|
||||
rect_fl.ymax = y + radius;
|
||||
|
||||
if (ac.spacetype == SPACE_IPO) {
|
||||
{
|
||||
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
|
||||
if (selectmode == SELECT_ADD) {
|
||||
incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) ||
|
||||
|
@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
|
|||
incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
incl_handles = false;
|
||||
}
|
||||
|
||||
|
||||
/* apply borderselect action */
|
||||
borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
|
||||
|
||||
|
|
|
@ -611,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case FCURVE_COLOR_AUTO_YRGB:
|
||||
{
|
||||
/* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
|
||||
float *col = fcu->color;
|
||||
|
||||
switch (fcu->array_index) {
|
||||
case 1:
|
||||
UI_GetThemeColor3fv(TH_AXIS_X, col);
|
||||
break;
|
||||
case 2:
|
||||
UI_GetThemeColor3fv(TH_AXIS_Y, col);
|
||||
break;
|
||||
case 3:
|
||||
UI_GetThemeColor3fv(TH_AXIS_Z, col);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
{
|
||||
/* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
|
||||
float c1[3], c2[3];
|
||||
float h1[3], h2[3];
|
||||
float hresult[3];
|
||||
|
||||
/* - get colors (rgb) */
|
||||
UI_GetThemeColor3fv(TH_AXIS_X, c1);
|
||||
UI_GetThemeColor3fv(TH_AXIS_Y, c2);
|
||||
|
||||
/* - perform blending in HSV space (to keep brightness similar) */
|
||||
rgb_to_hsv_v(c1, h1);
|
||||
rgb_to_hsv_v(c2, h2);
|
||||
|
||||
interp_v3_v3v3(hresult, h1, h2, 0.5f);
|
||||
|
||||
/* - convert back to RGB for display */
|
||||
hsv_to_rgb_v(hresult, col);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* 'unknown' color - bluish so as to not conflict with handles */
|
||||
col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FCURVE_COLOR_AUTO_RAINBOW:
|
||||
default:
|
||||
{
|
||||
|
|
|
@ -399,13 +399,22 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
|
|||
ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"));
|
||||
|
||||
/* check for invalid states */
|
||||
if (soops == NULL)
|
||||
if (soops == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
|
||||
BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
|
||||
old_id->name, new_id->name);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (old_id->lib) {
|
||||
BKE_reportf(op->reports, RPT_WARNING,
|
||||
"Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped",
|
||||
old_id->name);
|
||||
}
|
||||
|
||||
BKE_libblock_remap(bmain, old_id, new_id,
|
||||
ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
|
||||
|
||||
|
|
|
@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op))
|
|||
}
|
||||
}
|
||||
|
||||
BKE_text_unlink(bmain, text);
|
||||
BKE_libblock_free(bmain, text);
|
||||
BKE_libblock_delete(bmain, text);
|
||||
|
||||
text_drawcache_tag_update(st, 1);
|
||||
WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL);
|
||||
|
|
|
@ -7032,7 +7032,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
|
|||
MVert *mv = &data->mvert[index];
|
||||
|
||||
if (!(mv->flag & ME_HIDE)) {
|
||||
WM_framebuffer_index_set(data->offset + index);
|
||||
GPU_select_index_set(data->offset + index);
|
||||
glVertex3fv(co);
|
||||
}
|
||||
}
|
||||
|
@ -7057,7 +7057,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
|
|||
BMVert *eve = BM_vert_at_index(data->bm, index);
|
||||
|
||||
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
|
||||
WM_framebuffer_index_set(data->offset + index);
|
||||
GPU_select_index_set(data->offset + index);
|
||||
glVertex3fv(co);
|
||||
}
|
||||
}
|
||||
|
@ -7076,7 +7076,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
|
|||
BMEdge *eed = BM_edge_at_index(data->bm, index);
|
||||
|
||||
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
|
||||
WM_framebuffer_index_set(data->offset + index);
|
||||
GPU_select_index_set(data->offset + index);
|
||||
return DM_DRAW_OPTION_NORMAL;
|
||||
}
|
||||
else {
|
||||
|
@ -7090,7 +7090,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
|
|||
}
|
||||
|
||||
/**
|
||||
* dont set #WM_framebuffer_index_set. just use to mask other
|
||||
* dont set #GPU_framebuffer_index_set. just use to mask other
|
||||
*/
|
||||
static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
|
||||
{
|
||||
|
@ -7109,7 +7109,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
|
|||
BMFace *efa = BM_face_at_index(userData, index);
|
||||
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
||||
WM_framebuffer_index_set(index + 1);
|
||||
GPU_select_index_set(index + 1);
|
||||
return DM_DRAW_OPTION_NORMAL;
|
||||
}
|
||||
else {
|
||||
|
@ -7122,7 +7122,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
|
|||
BMFace *efa = BM_face_at_index(userData, index);
|
||||
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
||||
WM_framebuffer_index_set(index + 1);
|
||||
GPU_select_index_set(index + 1);
|
||||
|
||||
glVertex3fv(cent);
|
||||
}
|
||||
|
@ -7153,7 +7153,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
|
|||
|
||||
static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
|
||||
{
|
||||
WM_framebuffer_index_set(index + 1);
|
||||
GPU_select_index_set(index + 1);
|
||||
return DM_DRAW_OPTION_NORMAL;
|
||||
}
|
||||
|
||||
|
@ -7162,7 +7162,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
|
|||
Mesh *me = userData;
|
||||
|
||||
if (!(me->mpoly[index].flag & ME_HIDE)) {
|
||||
WM_framebuffer_index_set(index + 1);
|
||||
GPU_select_index_set(index + 1);
|
||||
return DM_DRAW_OPTION_NORMAL;
|
||||
}
|
||||
else {
|
||||
|
@ -7170,7 +7170,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
|
|||
}
|
||||
}
|
||||
|
||||
/* must have called WM_framebuffer_index_set beforehand */
|
||||
/* must have called GPU_framebuffer_index_set beforehand */
|
||||
static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
|
||||
{
|
||||
Mesh *me = userData;
|
||||
|
|
|
@ -1483,7 +1483,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
|
|||
BLI_endian_switch_uint32(&col);
|
||||
}
|
||||
|
||||
return WM_framebuffer_to_index(col);
|
||||
return GPU_select_to_index(col);
|
||||
}
|
||||
|
||||
/* reads full rect, converts indices */
|
||||
|
@ -1516,7 +1516,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int
|
|||
IMB_convert_rgba_to_abgr(ibuf_clip);
|
||||
}
|
||||
|
||||
WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
|
||||
GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
|
||||
|
||||
if ((clip.xmin == xmin) &&
|
||||
(clip.xmax == xmax) &&
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue