Compare commits
38 Commits
node-group
...
blender-v3
Author | SHA1 | Date | |
---|---|---|---|
ef9ca44dee | |||
55485cb379 | |||
b9ced50094 | |||
48f0d5de54 | |||
c79d853e4d | |||
b64a80edd5 | |||
![]() |
75849c7796 | ||
e01b98cdb6 | |||
b87bcd3f8f | |||
![]() |
a1e7d96801 | ||
d4a6108ef2 | |||
c1537d4134 | |||
08fa18fb6e | |||
72260deac1 | |||
5d73850dd4 | |||
3dcd999267 | |||
fd3943dbd5 | |||
c2e7bf3953 | |||
6325174a75 | |||
0b706237b0 | |||
28e6a8414a | |||
![]() |
9992096c49 | ||
d6e75e2c23 | |||
7e5cb94748 | |||
e22f49c801 | |||
ef40604b87 | |||
d666c64f5d | |||
94e7e83cd9 | |||
389b086929 | |||
c4251110a9 | |||
a47d1ad9d5 | |||
![]() |
fa5164a8b2 | ||
08d687e8cd | |||
18ecaaf9cb | |||
fd70f9dfda | |||
28235df709 | |||
175bd38201 | |||
a95bf1ac01 |
@@ -367,13 +367,11 @@ static void attr_create_generic(Scene *scene,
|
||||
{
|
||||
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
|
||||
static const ustring u_velocity("velocity");
|
||||
|
||||
int attribute_index = 0;
|
||||
int render_color_index = b_mesh.attributes.render_color_index();
|
||||
const ustring default_color_name{b_mesh.attributes.default_color_name().c_str()};
|
||||
|
||||
for (BL::Attribute &b_attribute : b_mesh.attributes) {
|
||||
const ustring name{b_attribute.name().c_str()};
|
||||
const bool is_render_color = (attribute_index++ == render_color_index);
|
||||
const bool is_render_color = name == default_color_name;
|
||||
|
||||
if (need_motion && name == u_velocity) {
|
||||
attr_create_motion(mesh, b_attribute, motion_scale);
|
||||
|
@@ -578,11 +578,11 @@ ccl_device_inline
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
|
||||
eval = bsdf_microfacet_ggx_eval(sc, sd->I, omega_in, pdf);
|
||||
eval = bsdf_microfacet_ggx_eval(sc, sd->N, sd->I, omega_in, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
|
||||
eval = bsdf_microfacet_multi_ggx_eval(sc, sd->I, omega_in, pdf, &sd->lcg_state);
|
||||
eval = bsdf_microfacet_multi_ggx_eval(sc, sd->N, sd->I, omega_in, pdf, &sd->lcg_state);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
|
||||
@@ -590,10 +590,10 @@ ccl_device_inline
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
eval = bsdf_microfacet_beckmann_eval(sc, sd->I, omega_in, pdf);
|
||||
eval = bsdf_microfacet_beckmann_eval(sc, sd->N, sd->I, omega_in, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
|
||||
eval = bsdf_ashikhmin_shirley_eval(sc, sd->I, omega_in, pdf);
|
||||
eval = bsdf_ashikhmin_shirley_eval(sc, sd->N, sd->I, omega_in, pdf);
|
||||
break;
|
||||
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
|
||||
eval = bsdf_ashikhmin_velvet_eval(sc, sd->I, omega_in, pdf);
|
||||
|
@@ -40,11 +40,13 @@ ccl_device_inline float bsdf_ashikhmin_shirley_roughness_to_exponent(float rough
|
||||
}
|
||||
|
||||
ccl_device_forceinline Spectrum bsdf_ashikhmin_shirley_eval(ccl_private const ShaderClosure *sc,
|
||||
const float3 Ng,
|
||||
const float3 I,
|
||||
const float3 omega_in,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const float cosNgI = dot(Ng, omega_in);
|
||||
float3 N = bsdf->N;
|
||||
|
||||
float NdotI = dot(N, I); /* in Cycles/OSL convention I is omega_out */
|
||||
@@ -52,7 +54,8 @@ ccl_device_forceinline Spectrum bsdf_ashikhmin_shirley_eval(ccl_private const Sh
|
||||
|
||||
float out = 0.0f;
|
||||
|
||||
if (fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f || !(NdotI > 0.0f && NdotO > 0.0f)) {
|
||||
if ((cosNgI < 0.0f) || fmaxf(bsdf->alpha_x, bsdf->alpha_y) <= 1e-4f ||
|
||||
!(NdotI > 0.0f && NdotO > 0.0f)) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
@@ -210,7 +213,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(ccl_private const ShaderClosure *sc
|
||||
}
|
||||
else {
|
||||
/* leave the rest to eval */
|
||||
*eval = bsdf_ashikhmin_shirley_eval(sc, I, *omega_in, pdf);
|
||||
*eval = bsdf_ashikhmin_shirley_eval(sc, N, I, *omega_in, pdf);
|
||||
}
|
||||
|
||||
return label;
|
||||
|
@@ -517,27 +517,30 @@ ccl_device Spectrum bsdf_microfacet_ggx_eval_transmit(ccl_private const Microfac
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_microfacet_ggx_eval(ccl_private const ShaderClosure *sc,
|
||||
const float3 Ng,
|
||||
const float3 I,
|
||||
const float3 omega_in,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
|
||||
const float alpha_x = bsdf->alpha_x;
|
||||
const float alpha_y = bsdf->alpha_y;
|
||||
const bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
|
||||
const float3 N = bsdf->N;
|
||||
const float cosNO = dot(N, I);
|
||||
const float cosNI = dot(N, omega_in);
|
||||
const float cosNgI = dot(Ng, omega_in);
|
||||
|
||||
if (((cosNI < 0.0f) != m_refractive) || alpha_x * alpha_y <= 1e-7f) {
|
||||
if (((cosNgI < 0.0f) != m_refractive) || alpha_x * alpha_y <= 1e-7f) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
return (cosNI < 0.0f) ? bsdf_microfacet_ggx_eval_transmit(
|
||||
bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI) :
|
||||
bsdf_microfacet_ggx_eval_reflect(
|
||||
bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI);
|
||||
const float3 N = bsdf->N;
|
||||
const float cosNO = dot(N, I);
|
||||
const float cosNI = dot(N, omega_in);
|
||||
|
||||
return (cosNgI < 0.0f) ? bsdf_microfacet_ggx_eval_transmit(
|
||||
bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI) :
|
||||
bsdf_microfacet_ggx_eval_reflect(
|
||||
bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI);
|
||||
}
|
||||
|
||||
ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg,
|
||||
@@ -942,23 +945,26 @@ ccl_device Spectrum bsdf_microfacet_beckmann_eval_transmit(ccl_private const Mic
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_microfacet_beckmann_eval(ccl_private const ShaderClosure *sc,
|
||||
const float3 Ng,
|
||||
const float3 I,
|
||||
const float3 omega_in,
|
||||
ccl_private float *pdf)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
|
||||
const float alpha_x = bsdf->alpha_x;
|
||||
const float alpha_y = bsdf->alpha_y;
|
||||
const bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
|
||||
const float3 N = bsdf->N;
|
||||
const float cosNO = dot(N, I);
|
||||
const float cosNI = dot(N, omega_in);
|
||||
const float cosNgI = dot(Ng, omega_in);
|
||||
|
||||
if (((cosNI < 0.0f) != m_refractive) || alpha_x * alpha_y <= 1e-7f) {
|
||||
if (((cosNgI < 0.0f) != m_refractive) || alpha_x * alpha_y <= 1e-7f) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
const float3 N = bsdf->N;
|
||||
const float cosNO = dot(N, I);
|
||||
const float cosNI = dot(N, omega_in);
|
||||
|
||||
return (cosNI < 0.0f) ? bsdf_microfacet_beckmann_eval_transmit(
|
||||
bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI) :
|
||||
bsdf_microfacet_beckmann_eval_reflect(
|
||||
|
@@ -416,14 +416,16 @@ ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(ccl_private Microfacet
|
||||
}
|
||||
|
||||
ccl_device Spectrum bsdf_microfacet_multi_ggx_eval(ccl_private const ShaderClosure *sc,
|
||||
const float3 Ng,
|
||||
const float3 I,
|
||||
const float3 omega_in,
|
||||
ccl_private float *pdf,
|
||||
ccl_private uint *lcg_state)
|
||||
{
|
||||
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
|
||||
const float cosNgI = dot(Ng, omega_in);
|
||||
|
||||
if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
|
||||
if ((cosNgI < 0.0f) || bsdf->alpha_x * bsdf->alpha_y < 1e-7f) {
|
||||
*pdf = 0.0f;
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
@@ -386,6 +386,46 @@ void ConstantFolder::fold_mix_color(NodeMix type, bool clamp_factor, bool clamp)
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantFolder::fold_mix_float(bool clamp_factor, bool clamp) const
|
||||
{
|
||||
ShaderInput *fac_in = node->input("Factor");
|
||||
ShaderInput *float1_in = node->input("A");
|
||||
ShaderInput *float2_in = node->input("B");
|
||||
|
||||
float fac = clamp_factor ? saturatef(node->get_float(fac_in->socket_type)) :
|
||||
node->get_float(fac_in->socket_type);
|
||||
bool fac_is_zero = !fac_in->link && fac == 0.0f;
|
||||
bool fac_is_one = !fac_in->link && fac == 1.0f;
|
||||
|
||||
/* remove no-op node when factor is 0.0 */
|
||||
if (fac_is_zero) {
|
||||
if (try_bypass_or_make_constant(float1_in, clamp)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove useless mix floats nodes */
|
||||
if (float1_in->link && float2_in->link) {
|
||||
if (float1_in->link == float2_in->link) {
|
||||
try_bypass_or_make_constant(float1_in, clamp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!float1_in->link && !float2_in->link) {
|
||||
float value1 = node->get_float(float1_in->socket_type);
|
||||
float value2 = node->get_float(float2_in->socket_type);
|
||||
if (value1 == value2) {
|
||||
try_bypass_or_make_constant(float1_in, clamp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* remove no-op mix float node when factor is 1.0 */
|
||||
if (fac_is_one) {
|
||||
try_bypass_or_make_constant(float2_in, clamp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantFolder::fold_math(NodeMathType type) const
|
||||
{
|
||||
ShaderInput *value1_in = node->input("Value1");
|
||||
|
@@ -52,6 +52,7 @@ class ConstantFolder {
|
||||
/* Specific nodes. */
|
||||
void fold_mix(NodeMix type, bool clamp) const;
|
||||
void fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const;
|
||||
void fold_mix_float(bool clamp_factor, bool clamp) const;
|
||||
void fold_math(NodeMathType type) const;
|
||||
void fold_vector_math(NodeVectorMathType type) const;
|
||||
void fold_mapping(NodeMappingType type) const;
|
||||
|
@@ -5132,6 +5132,9 @@ void MixFloatNode::constant_fold(const ConstantFolder &folder)
|
||||
}
|
||||
folder.make_constant(a * (1 - fac) + b * fac);
|
||||
}
|
||||
else {
|
||||
folder.fold_mix_float(use_clamp, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mix Vector */
|
||||
@@ -5185,6 +5188,9 @@ void MixVectorNode::constant_fold(const ConstantFolder &folder)
|
||||
}
|
||||
folder.make_constant(a * (one_float3() - fac) + b * fac);
|
||||
}
|
||||
else {
|
||||
folder.fold_mix_color(NODE_MIX_BLEND, use_clamp, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mix Vector Non Uniform */
|
||||
|
@@ -254,7 +254,7 @@ class GHOST_IWindow {
|
||||
*/
|
||||
virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0;
|
||||
|
||||
virtual GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) = 0;
|
||||
virtual GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const = 0;
|
||||
|
||||
virtual void getCursorGrabState(GHOST_TGrabCursorMode &mode,
|
||||
GHOST_TAxisFlag &axis_flag,
|
||||
|
@@ -5826,8 +5826,36 @@ static GHOST_TSuccess getCursorPositionClientRelative_impl(
|
||||
int32_t &y)
|
||||
{
|
||||
const wl_fixed_t scale = win->scale();
|
||||
x = wl_fixed_to_int(scale * seat_state_pointer->xy[0]);
|
||||
y = wl_fixed_to_int(scale * seat_state_pointer->xy[1]);
|
||||
|
||||
if (win->getCursorGrabModeIsWarp()) {
|
||||
/* As the cursor is restored at the warped location,
|
||||
* apply warping when requesting the cursor location. */
|
||||
GHOST_Rect wrap_bounds{};
|
||||
if (win->getCursorGrabModeIsWarp()) {
|
||||
if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) {
|
||||
win->getClientBounds(wrap_bounds);
|
||||
}
|
||||
}
|
||||
int xy_wrap[2] = {
|
||||
seat_state_pointer->xy[0],
|
||||
seat_state_pointer->xy[1],
|
||||
};
|
||||
|
||||
GHOST_Rect wrap_bounds_scale;
|
||||
wrap_bounds_scale.m_l = wl_fixed_from_int(wrap_bounds.m_l) / scale;
|
||||
wrap_bounds_scale.m_t = wl_fixed_from_int(wrap_bounds.m_t) / scale;
|
||||
wrap_bounds_scale.m_r = wl_fixed_from_int(wrap_bounds.m_r) / scale;
|
||||
wrap_bounds_scale.m_b = wl_fixed_from_int(wrap_bounds.m_b) / scale;
|
||||
wrap_bounds_scale.wrapPoint(UNPACK2(xy_wrap), 0, win->getCursorGrabAxis());
|
||||
|
||||
x = wl_fixed_to_int(scale * xy_wrap[0]);
|
||||
y = wl_fixed_to_int(scale * xy_wrap[1]);
|
||||
}
|
||||
else {
|
||||
x = wl_fixed_to_int(scale * seat_state_pointer->xy[0]);
|
||||
y = wl_fixed_to_int(scale * seat_state_pointer->xy[1]);
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
|
@@ -1055,46 +1055,17 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
||||
int32_t x_new = x_screen;
|
||||
int32_t y_new = y_screen;
|
||||
int32_t x_accum, y_accum;
|
||||
GHOST_Rect bounds;
|
||||
|
||||
/* Warp within bounds. */
|
||||
{
|
||||
GHOST_Rect bounds;
|
||||
int32_t bounds_margin = 0;
|
||||
GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone;
|
||||
|
||||
if (window->getCursorGrabMode() == GHOST_kGrabHide) {
|
||||
window->getClientBounds(bounds);
|
||||
|
||||
/* WARNING(@campbellbarton): The current warping logic fails to warp on every event,
|
||||
* so the box needs to small enough not to let the cursor escape the window but large
|
||||
* enough that the cursor isn't being warped every time.
|
||||
* If this was not the case it would be less trouble to simply warp the cursor to the
|
||||
* center of the screen on every motion, see: D16558 (alternative fix for T102346). */
|
||||
const int32_t subregion_div = 4; /* One quarter of the region. */
|
||||
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
|
||||
const int32_t center[2] = {(bounds.m_l + bounds.m_r) / 2, (bounds.m_t + bounds.m_b) / 2};
|
||||
/* Shrink the box to prevent the cursor escaping. */
|
||||
bounds.m_l = center[0] - (size[0] / (subregion_div * 2));
|
||||
bounds.m_r = center[0] + (size[0] / (subregion_div * 2));
|
||||
bounds.m_t = center[1] - (size[1] / (subregion_div * 2));
|
||||
bounds.m_b = center[1] + (size[1] / (subregion_div * 2));
|
||||
bounds_margin = 0;
|
||||
bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY);
|
||||
}
|
||||
else {
|
||||
/* Fallback to window bounds. */
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
window->getClientBounds(bounds);
|
||||
}
|
||||
bounds_margin = 2;
|
||||
bounds_axis = window->getCursorGrabAxis();
|
||||
}
|
||||
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will
|
||||
* fail at the moment. Use inset in case the window is at screen bounds. */
|
||||
bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis);
|
||||
/* Fallback to window bounds. */
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
window->getClientBounds(bounds);
|
||||
}
|
||||
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will
|
||||
* fail at the moment. Use inset in case the window is at screen bounds. */
|
||||
bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis());
|
||||
|
||||
window->getCursorGrabAccum(x_accum, y_accum);
|
||||
if (x_new != x_screen || y_new != y_screen) {
|
||||
system->setCursorPosition(x_new, y_new); /* wrap */
|
||||
@@ -1195,16 +1166,16 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
|
||||
const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80;
|
||||
const bool alt_pressed = has_state && state[VK_MENU] & 0x80;
|
||||
|
||||
if (!key_down) {
|
||||
/* Pass. */
|
||||
}
|
||||
/* We can be here with !key_down if processing dead keys (diacritics). See T103119. */
|
||||
|
||||
/* No text with control key pressed (Alt can be used to insert special characters though!). */
|
||||
else if (ctrl_pressed && !alt_pressed) {
|
||||
if (ctrl_pressed && !alt_pressed) {
|
||||
/* Pass. */
|
||||
}
|
||||
/* Don't call #ToUnicodeEx on dead keys as it clears the buffer and so won't allow diacritical
|
||||
* composition. */
|
||||
else if (MapVirtualKeyW(vk, 2) != 0) {
|
||||
* composition. XXX: we are not checking return of MapVirtualKeyW for high bit set, which is
|
||||
* what is supposed to indicate dead keys. But this is working now so approach cautiously. */
|
||||
else if (MapVirtualKeyW(vk, MAPVK_VK_TO_CHAR) != 0) {
|
||||
wchar_t utf16[3] = {0};
|
||||
int r;
|
||||
/* TODO: #ToUnicodeEx can respond with up to 4 utf16 chars (only 2 here).
|
||||
@@ -1219,6 +1190,10 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
|
||||
utf8_char[0] = '\0';
|
||||
}
|
||||
}
|
||||
if (!key_down) {
|
||||
/* Clear or wm_event_add_ghostevent will warn of unexpected data on key up. */
|
||||
utf8_char[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
|
@@ -934,48 +934,17 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
int32_t x_new = xme.x_root;
|
||||
int32_t y_new = xme.y_root;
|
||||
int32_t x_accum, y_accum;
|
||||
GHOST_Rect bounds;
|
||||
|
||||
/* Warp within bounds. */
|
||||
{
|
||||
GHOST_Rect bounds;
|
||||
int32_t bounds_margin = 0;
|
||||
GHOST_TAxisFlag bounds_axis = GHOST_kAxisNone;
|
||||
|
||||
if (window->getCursorGrabMode() == GHOST_kGrabHide) {
|
||||
window->getClientBounds(bounds);
|
||||
|
||||
/* TODO(@campbellbarton): warp the cursor to `window->getCursorGrabInitPos`,
|
||||
* on every motion event, see: D16557 (alternative fix for T102346). */
|
||||
const int32_t subregion_div = 4; /* One quarter of the region. */
|
||||
const int32_t size[2] = {bounds.getWidth(), bounds.getHeight()};
|
||||
const int32_t center[2] = {
|
||||
(bounds.m_l + bounds.m_r) / 2,
|
||||
(bounds.m_t + bounds.m_b) / 2,
|
||||
};
|
||||
/* Shrink the box to prevent the cursor escaping. */
|
||||
bounds.m_l = center[0] - (size[0] / (subregion_div * 2));
|
||||
bounds.m_r = center[0] + (size[0] / (subregion_div * 2));
|
||||
bounds.m_t = center[1] - (size[1] / (subregion_div * 2));
|
||||
bounds.m_b = center[1] + (size[1] / (subregion_div * 2));
|
||||
bounds_margin = 0;
|
||||
bounds_axis = GHOST_TAxisFlag(GHOST_kAxisX | GHOST_kAxisY);
|
||||
}
|
||||
else {
|
||||
/* Fallback to window bounds. */
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
window->getClientBounds(bounds);
|
||||
}
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will
|
||||
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
|
||||
bounds_margin = 8;
|
||||
bounds_axis = window->getCursorGrabAxis();
|
||||
}
|
||||
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will
|
||||
* fail at the moment. Use inset in case the window is at screen bounds. */
|
||||
bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis);
|
||||
/* fallback to window bounds */
|
||||
if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
|
||||
window->getClientBounds(bounds);
|
||||
}
|
||||
|
||||
/* Could also clamp to screen bounds wrap with a window outside the view will
|
||||
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
|
||||
bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
|
||||
|
||||
window->getCursorGrabAccum(x_accum, y_accum);
|
||||
|
||||
if (x_new != xme.x_root || y_new != xme.y_root) {
|
||||
|
@@ -159,7 +159,7 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect &bounds)
|
||||
GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect &bounds) const
|
||||
{
|
||||
if (m_cursorGrab != GHOST_kGrabWrap) {
|
||||
return GHOST_kFailure;
|
||||
|
@@ -152,7 +152,7 @@ class GHOST_Window : public GHOST_IWindow {
|
||||
* Gets the cursor grab region, if unset the window is used.
|
||||
* reset when grab is disabled.
|
||||
*/
|
||||
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) override;
|
||||
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override;
|
||||
|
||||
void getCursorGrabState(GHOST_TGrabCursorMode &mode,
|
||||
GHOST_TAxisFlag &axis_flag,
|
||||
|
Submodule release/datafiles/locale updated: 4a581c54af...e398d3c496
Binary file not shown.
Before Width: | Height: | Size: 823 KiB After Width: | Height: | Size: 890 KiB |
Submodule release/scripts/addons updated: 0b0052bd53...7408fc7283
Submodule release/scripts/addons_contrib updated: 96143b1a8b...886ea86bd9
@@ -2137,9 +2137,6 @@ def km_node_editor(params):
|
||||
)),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
|
||||
("node.move_detach_links",
|
||||
{"type": 'D', "value": 'PRESS', "alt": True},
|
||||
{"properties": [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])]}),
|
||||
("node.move_detach_links_release",
|
||||
{"type": params.action_mouse, "value": 'CLICK_DRAG', "alt": True},
|
||||
{"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
|
||||
|
@@ -88,8 +88,16 @@ class CURVES_UL_attributes(UIList):
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for item in attributes:
|
||||
flags.append(0 if item.is_internal else self.bitflag_filter_item)
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
# Filtering internal attributes
|
||||
for idx, item in enumerate(attributes):
|
||||
flags[idx] = 0 if item.is_internal else flags[idx]
|
||||
|
||||
return flags, indices
|
||||
|
||||
|
@@ -535,8 +535,16 @@ class MESH_UL_attributes(UIList):
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for item in attributes:
|
||||
flags.append(0 if item.is_internal else self.bitflag_filter_item)
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
# Filtering internal attributes
|
||||
for idx, item in enumerate(attributes):
|
||||
flags[idx] = 0 if item.is_internal else flags[idx]
|
||||
|
||||
return flags, indices
|
||||
|
||||
@@ -624,20 +632,26 @@ class ColorAttributesListBase():
|
||||
}
|
||||
|
||||
def filter_items(self, _context, data, property):
|
||||
attrs = getattr(data, property)
|
||||
ret = []
|
||||
idxs = []
|
||||
attributes = getattr(data, property)
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for idx, item in enumerate(attrs):
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
for idx, item in enumerate(attributes):
|
||||
skip = (
|
||||
(item.domain not in {"POINT", "CORNER"}) or
|
||||
(item.data_type not in {"FLOAT_COLOR", "BYTE_COLOR"}) or
|
||||
item.is_internal
|
||||
)
|
||||
ret.append(0 if skip else self.bitflag_filter_item)
|
||||
idxs.append(idx)
|
||||
flags[idx] = 0 if skip else flags[idx]
|
||||
|
||||
return ret, idxs
|
||||
return flags, indices
|
||||
|
||||
|
||||
class MESH_UL_color_attributes(UIList, ColorAttributesListBase):
|
||||
|
@@ -70,8 +70,16 @@ class POINTCLOUD_UL_attributes(UIList):
|
||||
flags = []
|
||||
indices = [i for i in range(len(attributes))]
|
||||
|
||||
for item in attributes:
|
||||
flags.append(0 if item.is_internal else self.bitflag_filter_item)
|
||||
# Filtering by name
|
||||
if self.filter_name:
|
||||
flags = bpy.types.UI_UL_list.filter_items_by_name(
|
||||
self.filter_name, self.bitflag_filter_item, attributes, "name", reverse=self.use_filter_invert)
|
||||
if not flags:
|
||||
flags = [self.bitflag_filter_item] * len(attributes)
|
||||
|
||||
# Filtering internal attributes
|
||||
for idx, item in enumerate(attributes):
|
||||
flags[idx] = 0 if item.is_internal else flags[idx]
|
||||
|
||||
return flags, indices
|
||||
|
||||
|
@@ -19,9 +19,9 @@ extern "C" {
|
||||
/* Blender major and minor version. */
|
||||
#define BLENDER_VERSION 304
|
||||
/* Blender patch version for bugfix releases. */
|
||||
#define BLENDER_VERSION_PATCH 0
|
||||
#define BLENDER_VERSION_PATCH 1
|
||||
/** Blender release cycle stage: alpha/beta/rc/release. */
|
||||
#define BLENDER_VERSION_CYCLE rc
|
||||
#define BLENDER_VERSION_CYCLE release
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
|
@@ -1364,7 +1364,7 @@ void BKE_mesh_material_index_remove(Mesh *me, short index)
|
||||
}
|
||||
MutableVArraySpan<int> indices_span(material_indices.varray);
|
||||
for (const int i : indices_span.index_range()) {
|
||||
if (indices_span[i] > 0 && indices_span[i] > index) {
|
||||
if (indices_span[i] > 0 && indices_span[i] >= index) {
|
||||
indices_span[i]--;
|
||||
}
|
||||
}
|
||||
|
@@ -2323,6 +2323,10 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
|
||||
node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src);
|
||||
}
|
||||
|
||||
if (dst_tree) {
|
||||
BKE_ntree_update_tag_node_new(dst_tree, node_dst);
|
||||
}
|
||||
|
||||
/* Only call copy function when a copy is made for the main database, not
|
||||
* for cases like the dependency graph and localization. */
|
||||
if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) {
|
||||
@@ -2332,10 +2336,6 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
|
||||
node_dst->typeinfo->copyfunc_api(&ptr, &node_src);
|
||||
}
|
||||
|
||||
if (dst_tree) {
|
||||
BKE_ntree_update_tag_node_new(dst_tree, node_dst);
|
||||
}
|
||||
|
||||
/* Reset the declaration of the new node. */
|
||||
nodeDeclarationEnsure(dst_tree, node_dst);
|
||||
|
||||
|
@@ -214,4 +214,7 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
|
||||
void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
|
||||
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
|
||||
RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_Z, 1, "Z", SOCK_FLOAT);
|
||||
}
|
||||
}
|
||||
|
@@ -187,6 +187,13 @@ vec4 gpencil_vertex(vec4 viewport_size,
|
||||
is_squares = false;
|
||||
}
|
||||
|
||||
/* Endpoints, we discard the vertices. */
|
||||
if (!is_dot && ma2.x == -1) {
|
||||
/* We set the vertex at the camera origin to generate 0 fragments. */
|
||||
out_ndc = vec4(0.0, 0.0, -3e36, 0.0);
|
||||
return out_ndc;
|
||||
}
|
||||
|
||||
/* Avoid using a vertex attribute for quad positioning. */
|
||||
float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
|
||||
float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
|
||||
|
@@ -479,15 +479,20 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* create temp data for each layer */
|
||||
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, scene->r.cfra);
|
||||
if (gpf_prv == NULL) {
|
||||
continue;
|
||||
}
|
||||
bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, scene->r.cfra);
|
||||
if (gpf_next == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create temp data for each layer. */
|
||||
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
|
||||
|
||||
tgpil->gpl = gpl;
|
||||
bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, scene->r.cfra);
|
||||
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf, true);
|
||||
|
||||
gpf = gpencil_get_next_keyframe(gpl, scene->r.cfra);
|
||||
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf, true);
|
||||
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf_prv, true);
|
||||
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf_next, true);
|
||||
|
||||
BLI_addtail(&tgpi->ilayers, tgpil);
|
||||
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_sculpt.h"
|
||||
#include "ED_undo.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "bmesh_tools.h"
|
||||
@@ -287,6 +288,16 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
|
||||
params.add_boundary_loop = RNA_boolean_get(op->ptr, "add_boundary_loop");
|
||||
params.apply_shrinkwrap = RNA_boolean_get(op->ptr, "apply_shrinkwrap");
|
||||
params.add_solidify = RNA_boolean_get(op->ptr, "add_solidify");
|
||||
|
||||
/* Push an undo step prior to extraction.
|
||||
* Note: A second push happens after the operator due to
|
||||
* the OPTYPE_UNDO flag; having an initial undo step here
|
||||
* is just needed to preserve the active object pointer.
|
||||
*
|
||||
* Fixes T103261.
|
||||
*/
|
||||
ED_undo_push_op(C, op);
|
||||
|
||||
return geometry_extract_apply(C, op, geometry_extract_tag_masked_faces, ¶ms);
|
||||
}
|
||||
|
||||
|
@@ -3531,6 +3531,9 @@ void ED_region_info_draw_multiline(ARegion *region,
|
||||
/* background box */
|
||||
rcti rect = *ED_region_visible_rect(region);
|
||||
|
||||
/* Needed in case scripts leave the font size at an unexpected value, see: T102213. */
|
||||
BLF_size(fontid, style->widget.points * U.dpi_fac);
|
||||
|
||||
/* Box fill entire width or just around text. */
|
||||
if (!full_redraw) {
|
||||
const char **text = &text_array[0];
|
||||
|
@@ -4812,28 +4812,19 @@ bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
|
||||
int ED_screen_animation_play(bContext *C, int sync, int mode)
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_ensure_evaluated_depsgraph(C));
|
||||
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
/* stop playback now */
|
||||
ED_screen_animation_timer(C, 0, 0, 0);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
|
||||
Depsgraph *graph = BKE_scene_get_depsgraph(scene, view_layer);
|
||||
if (graph) {
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(graph);
|
||||
/* The audio handles are preserved throughout the dependency graph evaluation.
|
||||
* Checking for scene->playback_handle even for non-evaluated scene should be okay. */
|
||||
BKE_sound_stop_scene(scene_eval);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_sound_stop_scene(scene_eval);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
else {
|
||||
/* these settings are currently only available from a menu in the TimeLine */
|
||||
if (mode == 1) { /* XXX only play audio forwards!? */
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_ensure_evaluated_depsgraph(C));
|
||||
BKE_sound_play_scene(scene_eval);
|
||||
}
|
||||
|
||||
|
@@ -1345,6 +1345,11 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
|
||||
|
||||
static void sculpt_gesture_trim_begin(bContext *C, SculptGestureContext *sgcontext)
|
||||
{
|
||||
Object *object = sgcontext->vc.obact;
|
||||
SculptSession *ss = object->sculpt;
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
sculpt_gesture_trim_calculate_depth(sgcontext);
|
||||
sculpt_gesture_trim_geometry_generate(sgcontext);
|
||||
@@ -1369,9 +1374,9 @@ static void sculpt_gesture_trim_end(bContext *UNUSED(C), SculptGestureContext *s
|
||||
{
|
||||
Object *object = sgcontext->vc.obact;
|
||||
SculptSession *ss = object->sculpt;
|
||||
Mesh *mesh = (Mesh *)object->data;
|
||||
|
||||
ss->face_sets = CustomData_get_layer_named(
|
||||
&((Mesh *)object->data)->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
ss->face_sets = CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, ".sculpt_face_set");
|
||||
if (ss->face_sets) {
|
||||
/* Assign a new Face Set ID to the new faces created by the trim operation. */
|
||||
const int next_face_set_id = ED_sculpt_face_sets_find_next_available_id(object->data);
|
||||
|
@@ -587,6 +587,7 @@ typedef struct WPGradient_userData {
|
||||
Scene *scene;
|
||||
Mesh *me;
|
||||
MDeformVert *dvert;
|
||||
const bool *select_vert;
|
||||
Brush *brush;
|
||||
const float *sco_start; /* [2] */
|
||||
const float *sco_end; /* [2] */
|
||||
@@ -683,7 +684,7 @@ static void gradientVertInit__mapFunc(void *userData,
|
||||
WPGradient_userData *grad_data = userData;
|
||||
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
|
||||
|
||||
if (grad_data->use_select && !(grad_data->dvert[index].flag & SELECT)) {
|
||||
if (grad_data->use_select && (grad_data->select_vert && !grad_data->select_vert[index])) {
|
||||
copy_v2_fl(vs->sco, FLT_MAX);
|
||||
return;
|
||||
}
|
||||
@@ -811,6 +812,8 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
|
||||
data.scene = scene;
|
||||
data.me = ob->data;
|
||||
data.dvert = dverts;
|
||||
data.select_vert = (const bool *)CustomData_get_layer_named(
|
||||
&me->vdata, CD_PROP_BOOL, ".select_vert");
|
||||
data.sco_start = sco_start;
|
||||
data.sco_end = sco_end;
|
||||
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
|
||||
|
@@ -692,7 +692,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
||||
CustomData_get_layer(&mesh->edata, CD_CREASE));
|
||||
sculpt_face_sets_init_flood_fill(
|
||||
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
|
||||
return creases[edge] < threshold;
|
||||
return creases ? creases[edge] < threshold : true;
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -709,7 +709,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
||||
CustomData_get_layer(&mesh->edata, CD_BWEIGHT));
|
||||
sculpt_face_sets_init_flood_fill(
|
||||
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
|
||||
return bevel_weights ? bevel_weights[edge] / 255.0f < threshold : true;
|
||||
return bevel_weights ? bevel_weights[edge] < threshold : true;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@@ -317,7 +317,6 @@ static void filelist_readjob_main_assets(FileListReadJob *job_params,
|
||||
|
||||
/* helper, could probably go in BKE actually? */
|
||||
static int groupname_to_code(const char *group);
|
||||
static uint64_t groupname_to_filter_id(const char *group);
|
||||
|
||||
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
|
||||
static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry);
|
||||
@@ -745,7 +744,7 @@ static bool is_filtered_file(FileListInternEntry *file,
|
||||
}
|
||||
|
||||
static bool is_filtered_id_file_type(const FileListInternEntry *file,
|
||||
const char *id_group,
|
||||
const short id_code,
|
||||
const char *name,
|
||||
const FileListFilter *filter)
|
||||
{
|
||||
@@ -755,12 +754,12 @@ static bool is_filtered_id_file_type(const FileListInternEntry *file,
|
||||
|
||||
/* We only check for types if some type are enabled in filtering. */
|
||||
if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
|
||||
if (id_group) {
|
||||
if (id_code) {
|
||||
if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t filter_id = groupname_to_filter_id(id_group);
|
||||
const uint64_t filter_id = BKE_idtype_idcode_to_idfilter(id_code);
|
||||
if (!(filter_id & filter->filter_id)) {
|
||||
return false;
|
||||
}
|
||||
@@ -843,15 +842,11 @@ static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter)
|
||||
}
|
||||
|
||||
static bool is_filtered_lib_type(FileListInternEntry *file,
|
||||
const char *root,
|
||||
const char * /*root*/,
|
||||
FileListFilter *filter)
|
||||
{
|
||||
char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
|
||||
|
||||
BLI_path_join(path, sizeof(path), root, file->relpath);
|
||||
|
||||
if (BLO_library_path_explode(path, dir, &group, &name)) {
|
||||
return is_filtered_id_file_type(file, group, name, filter);
|
||||
if (file->typeflag & FILE_TYPE_BLENDERLIB) {
|
||||
return is_filtered_id_file_type(file, file->blentype, file->name, filter);
|
||||
}
|
||||
return is_filtered_file_type(file, filter);
|
||||
}
|
||||
@@ -873,7 +868,7 @@ static bool is_filtered_main_assets(FileListInternEntry *file,
|
||||
FileListFilter *filter)
|
||||
{
|
||||
/* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
|
||||
return is_filtered_id_file_type(file, file->relpath, file->name, filter) &&
|
||||
return is_filtered_id_file_type(file, file->blentype, file->name, filter) &&
|
||||
is_filtered_asset(file, filter);
|
||||
}
|
||||
|
||||
@@ -2859,13 +2854,6 @@ static int groupname_to_code(const char *group)
|
||||
return buf[0] ? BKE_idtype_idcode_from_name(buf) : 0;
|
||||
}
|
||||
|
||||
static uint64_t groupname_to_filter_id(const char *group)
|
||||
{
|
||||
int id_code = groupname_to_code(group);
|
||||
|
||||
return BKE_idtype_idcode_to_idfilter(id_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* From here, we are in 'Job Context',
|
||||
* i.e. have to be careful about sharing stuff between background working thread.
|
||||
|
@@ -55,6 +55,14 @@
|
||||
|
||||
#define USE_TABLET_SUPPORT
|
||||
|
||||
/**
|
||||
* Use alternative behavior when cursor warp is supported
|
||||
* to prevent the cursor escaping the window bounds, see: T102346.
|
||||
*
|
||||
* \note this is not needed if cursor positioning is not supported.
|
||||
*/
|
||||
#define USE_CURSOR_WARP_HACK
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Modal Key-map
|
||||
* \{ */
|
||||
@@ -221,6 +229,10 @@ typedef struct WalkInfo {
|
||||
bool need_rotation_keyframe;
|
||||
bool need_translation_keyframe;
|
||||
|
||||
#ifdef USE_CURSOR_WARP_HACK
|
||||
bool need_modal_cursor_warp_hack;
|
||||
#endif
|
||||
|
||||
/** Previous 2D mouse values. */
|
||||
int prev_mval[2];
|
||||
/** Initial mouse location. */
|
||||
@@ -579,6 +591,10 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int
|
||||
walk->need_rotation_keyframe = false;
|
||||
walk->need_translation_keyframe = false;
|
||||
|
||||
#ifdef USE_CURSOR_WARP_HACK
|
||||
walk->need_modal_cursor_warp_hack = false;
|
||||
#endif
|
||||
|
||||
walk->time_lastdraw = PIL_check_seconds_timer();
|
||||
|
||||
walk->draw_handle_pixel = ED_region_draw_cb_activate(
|
||||
@@ -594,7 +610,31 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int
|
||||
copy_v2_v2_int(walk->init_mval, mval);
|
||||
copy_v2_v2_int(walk->prev_mval, mval);
|
||||
|
||||
WM_cursor_grab_enable(win, 0, true, NULL);
|
||||
#ifdef USE_CURSOR_WARP_HACK
|
||||
if (WM_capabilities_flag() & WM_CAPABILITY_CURSOR_WARP) {
|
||||
int bounds[4];
|
||||
const rcti *rect = &walk->region->winrct;
|
||||
const int center[2] = {BLI_rcti_cent_x(rect), BLI_rcti_cent_y(rect)};
|
||||
const int size[2] = {BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)};
|
||||
const int div = 4; /* Where 2 is the region size. */
|
||||
|
||||
bounds[0] = center[0] - (size[0] / div); /* X-min. */
|
||||
bounds[1] = center[1] + (size[1] / div); /* Y-max. */
|
||||
bounds[2] = center[0] + (size[0] / div); /* X-max. */
|
||||
bounds[3] = center[1] - (size[1] / div); /* Y-min. */
|
||||
|
||||
WM_cursor_grab_enable(win, WM_CURSOR_WRAP_XY, false, bounds);
|
||||
|
||||
/* Important to hide afterwards (not part of grabbing),
|
||||
* since enabling cursor and hiding at the same time ignores bounds. */
|
||||
WM_cursor_modal_set(win, WM_CURSOR_NONE);
|
||||
walk->need_modal_cursor_warp_hack = true;
|
||||
}
|
||||
else
|
||||
#endif /* USE_CURSOR_WARP_HACK */
|
||||
{
|
||||
WM_cursor_grab_enable(win, 0, true, NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -643,7 +683,16 @@ static int walkEnd(bContext *C, WalkInfo *walk)
|
||||
}
|
||||
#endif
|
||||
|
||||
WM_cursor_grab_enable(win, 0, true, NULL);
|
||||
WM_cursor_grab_disable(win, NULL);
|
||||
|
||||
#ifdef USE_CURSOR_WARP_HACK
|
||||
if (walk->need_modal_cursor_warp_hack) {
|
||||
WM_cursor_warp(win,
|
||||
walk->region->winrct.xmin + walk->init_mval[0],
|
||||
walk->region->winrct.ymin + walk->init_mval[1]);
|
||||
WM_cursor_modal_restore(win);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (walk->state == WALK_CONFIRM) {
|
||||
MEM_freeN(walk);
|
||||
|
@@ -1029,8 +1029,9 @@ void ElementResize(const TransInfo *t,
|
||||
applyNumInput(&num_evil, values_final_evil);
|
||||
|
||||
float ratio = values_final_evil[0];
|
||||
*td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff;
|
||||
CLAMP_MIN(*td->val, 0.001f);
|
||||
float transformed_value = td->ival * fabs(ratio);
|
||||
*td->val = max_ff(interpf(transformed_value, td->ival, gps->runtime.multi_frame_falloff),
|
||||
0.001f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@@ -600,13 +600,21 @@ static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_
|
||||
return box_array;
|
||||
}
|
||||
|
||||
static bool island_has_pins(const Scene *scene, FaceIsland *island, const bool pin_unselected)
|
||||
static bool island_has_pins(const Scene *scene,
|
||||
FaceIsland *island,
|
||||
const UVPackIsland_Params *params)
|
||||
{
|
||||
const bool pin_unselected = params->pin_unselected;
|
||||
const bool only_selected_faces = params->only_selected_faces;
|
||||
BMLoop *l;
|
||||
BMIter iter;
|
||||
const int cd_loop_uv_offset = island->cd_loop_uv_offset;
|
||||
for (int i = 0; i < island->faces_len; i++) {
|
||||
BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) {
|
||||
BMFace *efa = island->faces[i];
|
||||
if (pin_unselected && only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
return true;
|
||||
}
|
||||
BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
|
||||
MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset));
|
||||
if (luv->flag & MLOOPUV_PINNED) {
|
||||
return true;
|
||||
@@ -679,7 +687,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
/* Remove from linked list and append to blender::Vector. */
|
||||
LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) {
|
||||
BLI_remlink(&island_list, island);
|
||||
if (params->ignore_pinned && island_has_pins(scene, island, params->pin_unselected)) {
|
||||
if (params->ignore_pinned && island_has_pins(scene, island, params)) {
|
||||
MEM_freeN(island->faces);
|
||||
MEM_freeN(island);
|
||||
continue;
|
||||
|
@@ -118,14 +118,12 @@ static void bakeModifier(Main *UNUSED(bmain),
|
||||
GpencilModifierData *md,
|
||||
Object *ob)
|
||||
{
|
||||
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
|
||||
ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
|
||||
GpencilModifierData *md_eval = BKE_gpencil_modifiers_findby_name(object_eval, md->name);
|
||||
|
||||
if (mmd->object == NULL) {
|
||||
return;
|
||||
}
|
||||
generic_bake_deform_stroke(depsgraph, md_eval, object_eval, true, deformStroke);
|
||||
generic_bake_deform_stroke(depsgraph, md, ob, true, deformStroke);
|
||||
}
|
||||
|
||||
static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
|
||||
|
@@ -113,7 +113,45 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob,
|
||||
zero_v3(r_mat[3]);
|
||||
}
|
||||
}
|
||||
static bool gpencil_data_selected_minmax(ArrayGpencilModifierData *mmd,
|
||||
Object *ob,
|
||||
float r_min[3],
|
||||
float r_max[3])
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
bool changed = false;
|
||||
|
||||
INIT_MINMAX(r_min, r_max);
|
||||
|
||||
if (gpd == NULL) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
|
||||
if (gpf != NULL) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
if (is_stroke_affected_by_modifier(ob,
|
||||
mmd->layername,
|
||||
mmd->material,
|
||||
mmd->pass_index,
|
||||
mmd->layer_pass,
|
||||
1,
|
||||
gpl,
|
||||
gps,
|
||||
mmd->flag & GP_ARRAY_INVERT_LAYER,
|
||||
mmd->flag & GP_ARRAY_INVERT_PASS,
|
||||
mmd->flag & GP_ARRAY_INVERT_LAYERPASS,
|
||||
mmd->flag & GP_ARRAY_INVERT_MATERIAL)) {
|
||||
changed |= BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
/* array modifier - generate geometry callback (for viewport/rendering) */
|
||||
static void generate_geometry(GpencilModifierData *md,
|
||||
Depsgraph *depsgraph,
|
||||
@@ -131,7 +169,7 @@ static void generate_geometry(GpencilModifierData *md,
|
||||
if (mmd->flag & GP_ARRAY_USE_RELATIVE) {
|
||||
float min[3];
|
||||
float max[3];
|
||||
if (BKE_gpencil_data_minmax(gpd, min, max)) {
|
||||
if (gpencil_data_selected_minmax(mmd, ob, min, max)) {
|
||||
sub_v3_v3v3(size, max, min);
|
||||
/* Need a minimum size (for flat drawings). */
|
||||
CLAMP3_MIN(size, 0.01f);
|
||||
|
@@ -177,7 +177,8 @@ void GpencilExporterPDF::export_gpencil_layers()
|
||||
/* Apply layer thickness change. */
|
||||
gps_duplicate->thickness += gpl->line_change;
|
||||
/* Apply object scale to thickness. */
|
||||
gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world);
|
||||
const float scalef = mat4_to_scale(ob->object_to_world);
|
||||
gps_duplicate->thickness = ceilf((float)gps_duplicate->thickness * scalef);
|
||||
CLAMP_MIN(gps_duplicate->thickness, 1.0f);
|
||||
/* Fill. */
|
||||
if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) {
|
||||
@@ -236,7 +237,9 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
|
||||
|
||||
if (is_stroke && !do_fill) {
|
||||
HPDF_Page_SetLineJoin(page_, HPDF_ROUND_JOIN);
|
||||
HPDF_Page_SetLineWidth(page_, MAX2((radius * 2.0f) - gpl->line_change, 1.0f));
|
||||
const float width = MAX2(
|
||||
MAX2(gps->thickness + gpl->line_change, (radius * 2.0f) + gpl->line_change), 1.0f);
|
||||
HPDF_Page_SetLineWidth(page_, width);
|
||||
}
|
||||
|
||||
/* Loop all points. */
|
||||
|
@@ -198,7 +198,8 @@ void GpencilExporterSVG::export_gpencil_layers()
|
||||
/* Apply layer thickness change. */
|
||||
gps_duplicate->thickness += gpl->line_change;
|
||||
/* Apply object scale to thickness. */
|
||||
gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world);
|
||||
const float scalef = mat4_to_scale(ob->object_to_world);
|
||||
gps_duplicate->thickness = ceilf((float)gps_duplicate->thickness * scalef);
|
||||
CLAMP_MIN(gps_duplicate->thickness, 1.0f);
|
||||
|
||||
const bool is_normalized = ((params_.flag & GP_EXPORT_NORM_THICKNESS) != 0) ||
|
||||
@@ -308,7 +309,9 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
|
||||
color_string_set(gpl, gps, node_gps, do_fill);
|
||||
|
||||
if (is_stroke && !do_fill) {
|
||||
node_gps.append_attribute("stroke-width").set_value((radius * 2.0f) - gpl->line_change);
|
||||
const float width = MAX2(
|
||||
MAX2(gps->thickness + gpl->line_change, (radius * 2.0f) + gpl->line_change), 1.0f);
|
||||
node_gps.append_attribute("stroke-width").set_value(width);
|
||||
}
|
||||
|
||||
std::string txt;
|
||||
|
@@ -651,6 +651,49 @@ static void rna_AttributeGroup_render_color_index_range(
|
||||
*softmin = *min;
|
||||
*softmax = *max;
|
||||
}
|
||||
|
||||
static void rna_AttributeGroup_default_color_name_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
const ID *id = ptr->owner_id;
|
||||
const CustomDataLayer *layer = BKE_id_attributes_render_color_get(id);
|
||||
if (!layer) {
|
||||
value[0] = '\0';
|
||||
return;
|
||||
}
|
||||
BLI_strncpy(value, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
|
||||
}
|
||||
|
||||
static int rna_AttributeGroup_default_color_name_length(PointerRNA *ptr)
|
||||
{
|
||||
const ID *id = ptr->owner_id;
|
||||
const CustomDataLayer *layer = BKE_id_attributes_render_color_get(id);
|
||||
if (!layer) {
|
||||
return 0;
|
||||
}
|
||||
return strlen(layer->name);
|
||||
}
|
||||
|
||||
static void rna_AttributeGroup_active_color_name_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
const ID *id = ptr->owner_id;
|
||||
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
|
||||
if (!layer) {
|
||||
value[0] = '\0';
|
||||
return;
|
||||
}
|
||||
BLI_strncpy(value, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
|
||||
}
|
||||
|
||||
static int rna_AttributeGroup_active_color_name_length(PointerRNA *ptr)
|
||||
{
|
||||
const ID *id = ptr->owner_id;
|
||||
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
|
||||
if (!layer) {
|
||||
return 0;
|
||||
}
|
||||
return strlen(layer->name);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void rna_def_attribute_float(BlenderRNA *brna)
|
||||
@@ -1110,6 +1153,29 @@ static void rna_def_attribute_group(BlenderRNA *brna)
|
||||
"rna_AttributeGroup_render_color_index_set",
|
||||
"rna_AttributeGroup_render_color_index_range");
|
||||
RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active_color");
|
||||
|
||||
prop = RNA_def_property(srna, "default_color_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_string_maxlength(prop, MAX_CUSTOMDATA_LAYER_NAME);
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_AttributeGroup_default_color_name_get",
|
||||
"rna_AttributeGroup_default_color_name_length",
|
||||
NULL);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Default Color Attribute",
|
||||
"The name of the default color attribute used as a fallback for rendering");
|
||||
|
||||
prop = RNA_def_property(srna, "active_color_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_string_maxlength(prop, MAX_CUSTOMDATA_LAYER_NAME);
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_AttributeGroup_active_color_name_get",
|
||||
"rna_AttributeGroup_active_color_name_length",
|
||||
NULL);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Active Color Attribute",
|
||||
"The name of the active color attribute for display and editing");
|
||||
}
|
||||
|
||||
void rna_def_attributes_common(StructRNA *srna)
|
||||
|
@@ -1052,6 +1052,7 @@ static void rna_def_tex_slot(BlenderRNA *brna)
|
||||
RNA_def_property_string_funcs(
|
||||
prop, "rna_TexPaintSlot_name_get", "rna_TexPaintSlot_name_length", NULL);
|
||||
RNA_def_property_ui_text(prop, "Name", "Name of the slot");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "icon_value", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
@@ -205,6 +205,10 @@ static bool rna_Object_holdout_get(Object *ob, bContext *C, PointerRNA *view_lay
|
||||
static bool rna_Object_indirect_only_get(Object *ob, bContext *C, PointerRNA *view_layer_ptr)
|
||||
{
|
||||
Base *base = find_view_layer_base_with_synced_ensure(ob, C, view_layer_ptr, NULL, NULL);
|
||||
if (!base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((base->flag & BASE_INDIRECT_ONLY) != 0);
|
||||
}
|
||||
|
||||
|
@@ -160,9 +160,11 @@ class LazyFunctionForMultiInput : public LazyFunction {
|
||||
BLI_assert(socket.is_multi_input());
|
||||
const bNodeTree &btree = socket.owner_tree();
|
||||
for (const bNodeLink *link : socket.directly_linked_links()) {
|
||||
if (!(link->is_muted() || nodeIsDanglingReroute(&btree, link->fromnode))) {
|
||||
inputs_.append({"Input", *base_type_});
|
||||
if (link->is_muted() || !link->fromsock->is_available() ||
|
||||
nodeIsDanglingReroute(&btree, link->fromnode)) {
|
||||
continue;
|
||||
}
|
||||
inputs_.append({"Input", *base_type_});
|
||||
}
|
||||
const CPPType *vector_type = get_vector_type(*base_type_);
|
||||
BLI_assert(vector_type != nullptr);
|
||||
@@ -1154,10 +1156,11 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
||||
if (multi_input_link == link) {
|
||||
break;
|
||||
}
|
||||
if (!(multi_input_link->is_muted() ||
|
||||
nodeIsDanglingReroute(&btree_, multi_input_link->fromnode))) {
|
||||
link_index++;
|
||||
if (multi_input_link->is_muted() || !multi_input_link->fromsock->is_available() ||
|
||||
nodeIsDanglingReroute(&btree_, multi_input_link->fromnode)) {
|
||||
continue;
|
||||
}
|
||||
link_index++;
|
||||
}
|
||||
if (to_bsocket.owner_node().is_muted()) {
|
||||
if (link_index == 0) {
|
||||
|
@@ -115,8 +115,8 @@ static const struct PyC_StringEnumItems pygpu_imagetype_items[] = {
|
||||
{int(ImageType::FLOAT_1D), "FLOAT_1D"},
|
||||
{int(ImageType::FLOAT_1D_ARRAY), "FLOAT_1D_ARRAY"},
|
||||
{int(ImageType::FLOAT_2D), "FLOAT_2D"},
|
||||
{int(ImageType::FLOAT_2D_ARRAY), "FLOAT"},
|
||||
{int(ImageType::FLOAT_3D), "FLOAT_2D_ARRAY"},
|
||||
{int(ImageType::FLOAT_2D_ARRAY), "FLOAT_2D_ARRAY"},
|
||||
{int(ImageType::FLOAT_3D), "FLOAT_3D"},
|
||||
{int(ImageType::FLOAT_CUBE), "FLOAT_CUBE"},
|
||||
{int(ImageType::FLOAT_CUBE_ARRAY), "FLOAT_CUBE_ARRAY"},
|
||||
{int(ImageType::INT_BUFFER), "INT_BUFFER"},
|
||||
|
@@ -1044,14 +1044,19 @@ bool RE_engine_render(Render *re, bool do_all)
|
||||
re->engine = engine;
|
||||
}
|
||||
|
||||
/* create render result */
|
||||
/* Create render result. Do this before acquiring lock, to avoid lock
|
||||
* inversion as this calls python to get the render passes, while python UI
|
||||
* code can also hold a lock on the render result. */
|
||||
const bool create_new_result = (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW));
|
||||
RenderResult *new_result = engine_render_create_result(re);
|
||||
|
||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||
if (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW)) {
|
||||
if (create_new_result) {
|
||||
if (re->result) {
|
||||
render_result_free(re->result);
|
||||
}
|
||||
|
||||
re->result = engine_render_create_result(re);
|
||||
re->result = new_result;
|
||||
}
|
||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||
|
||||
|
@@ -126,6 +126,15 @@ void WM_init_opengl(void);
|
||||
*/
|
||||
const char *WM_ghost_backend(void);
|
||||
|
||||
typedef enum eWM_CapabilitiesFlag {
|
||||
/** Ability to warp the cursor (set it's location). */
|
||||
WM_CAPABILITY_CURSOR_WARP = (1 << 0),
|
||||
/** Ability to access window positions & move them. */
|
||||
WM_CAPABILITY_WINDOW_POSITION = (1 << 1),
|
||||
} eWM_CapabilitiesFlag;
|
||||
|
||||
eWM_CapabilitiesFlag WM_capabilities_flag(void);
|
||||
|
||||
void WM_check(struct bContext *C);
|
||||
void WM_reinit_gizmomap_all(struct Main *bmain);
|
||||
|
||||
|
@@ -1643,6 +1643,23 @@ GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gp
|
||||
return GHOST_kDrawingContextTypeNone;
|
||||
}
|
||||
|
||||
eWM_CapabilitiesFlag WM_capabilities_flag(void)
|
||||
{
|
||||
static eWM_CapabilitiesFlag flag = -1;
|
||||
if (flag != -1) {
|
||||
return flag;
|
||||
}
|
||||
|
||||
flag = 0;
|
||||
if (GHOST_SupportsCursorWarp()) {
|
||||
flag |= WM_CAPABILITY_CURSOR_WARP;
|
||||
}
|
||||
if (GHOST_SupportsWindowPosition()) {
|
||||
flag |= WM_CAPABILITY_WINDOW_POSITION;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
Submodule source/tools updated: 9e33a8678a...dfa16042bf
Reference in New Issue
Block a user