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:
Bastien Montagne 2016-06-27 15:59:01 +02:00
commit cbce7fef16
132 changed files with 2729 additions and 1235 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -89,6 +89,7 @@ ustring SocketType::type_name(Type type)
ustring("boolean"),
ustring("float"),
ustring("int"),
ustring("uint"),
ustring("color"),
ustring("vector"),
ustring("point"),

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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,

View File

@ -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 */

View File

@ -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__

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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) \

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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"));
}

View File

@ -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(

View File

@ -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;

View File

@ -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")

View File

@ -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")

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -49,9 +49,6 @@ set(INC
../../../intern/smoke/extern
../../../intern/atomic
../../../intern/libmv
# XXX - BAD LEVEL CALL WM_api.h
../windowmanager
)
set(INC_SYS

View File

@ -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;
}
/** \} */

View File

@ -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 */

View File

@ -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);

View File

@ -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(

View File

@ -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;

View File

@ -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 */

View File

@ -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)

View File

@ -95,8 +95,6 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "WM_api.h"
static SpinLock image_spin;
/* prototypes */

View File

@ -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 {

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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.
*/

View File

@ -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.
*

View File

@ -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.

View 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;

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 {

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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 */

View File

@ -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);

View File

@ -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) */

View File

@ -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);

View File

@ -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);

View File

@ -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.
*/

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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--) {

View File

@ -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 */

View File

@ -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",

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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__ */

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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 */
}

View File

@ -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 */

View File

@ -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);

View File

@ -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:
{

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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